WP RSS Aggregator - Version 4.17.7

Version Description

Download this release

Release Info

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

Code changes from version trunk to 4.17.7

Files changed (97) hide show
  1. CHANGELOG.md +0 -137
  2. css/admin-3.8.css +0 -0
  3. css/admin-editor.css +0 -0
  4. css/admin-styles.css +1262 -1307
  5. css/admin-tracking-styles.css +0 -0
  6. css/build/pagination.min.css +1 -1
  7. css/build/templates.min.css +1 -1
  8. css/colorbox.css +0 -0
  9. css/font-awesome.min.css +0 -0
  10. css/jquery-ui-smoothness.css +0 -1179
  11. css/templates/list/styles.css +0 -10
  12. fonts/FontAwesome.otf +0 -0
  13. fonts/fontawesome-webfont.eot +0 -0
  14. fonts/fontawesome-webfont.svg +0 -0
  15. fonts/fontawesome-webfont.ttf +0 -0
  16. fonts/fontawesome-webfont.woff +0 -0
  17. images/colorbox/border.png +0 -0
  18. images/colorbox/controls.png +0 -0
  19. images/colorbox/ie6/borderBottomCenter.png +0 -0
  20. images/colorbox/ie6/borderBottomLeft.png +0 -0
  21. images/colorbox/ie6/borderBottomRight.png +0 -0
  22. images/colorbox/ie6/borderMiddleLeft.png +0 -0
  23. images/colorbox/ie6/borderMiddleRight.png +0 -0
  24. images/colorbox/ie6/borderTopCenter.png +0 -0
  25. images/colorbox/ie6/borderTopLeft.png +0 -0
  26. images/colorbox/ie6/borderTopRight.png +0 -0
  27. images/colorbox/loading.gif +0 -0
  28. images/colorbox/loading_background.png +0 -0
  29. images/colorbox/overlay.png +0 -0
  30. images/facebook.png +0 -0
  31. images/icon-adminmenu16-sprite.png +0 -0
  32. images/icon-adminpage32.png +0 -0
  33. images/twitter.png +0 -0
  34. images/wpra-icon-transparent.png +0 -0
  35. includes/Aventura/Wprss/Core/Licensing/AjaxController.php +7 -7
  36. includes/Aventura/Wprss/Core/Licensing/Manager.php +8 -11
  37. includes/Aventura/Wprss/Core/Licensing/Settings.php +136 -188
  38. includes/Aventura/Wprss/Core/Model/AdminAjaxNotice/ServiceProvider.php +4 -13
  39. includes/Aventura/Wprss/Core/ServiceProvider.php +1 -1
  40. includes/OPML.php +1 -4
  41. includes/admin-activate.php +1 -2
  42. includes/admin-ajax-notice.php +50 -62
  43. includes/admin-display.php +590 -636
  44. includes/admin-editor.php +235 -230
  45. includes/admin-heartbeat.php +76 -59
  46. includes/admin-help-metaboxes.php +90 -137
  47. includes/admin-help-settings.php +195 -236
  48. includes/admin-help.php +1147 -1229
  49. includes/admin-intro-page.php +33 -31
  50. includes/admin-log.php +9 -9
  51. includes/admin-metaboxes.php +702 -786
  52. includes/admin-options-legacy.php +3 -3
  53. includes/admin-options.php +953 -991
  54. includes/admin-plugins.php +51 -55
  55. includes/admin-update-page.php +2 -2
  56. includes/admin.php +176 -212
  57. includes/black-friday-2021.php +0 -28
  58. includes/cpt-feeds.php +90 -113
  59. includes/cron-jobs.php +319 -397
  60. includes/fallback-mbstring.php +1 -1
  61. includes/feed-access.php +21 -49
  62. includes/feed-blacklist.php +14 -23
  63. includes/feed-importing-images.php +72 -170
  64. includes/feed-importing.php +912 -1047
  65. includes/feed-processing.php +744 -656
  66. includes/feed-states.php +93 -107
  67. includes/functions.php +1 -33
  68. includes/image-caching.php +0 -0
  69. includes/legacy-feed-display.php +489 -531
  70. includes/libraries/WordPress-Readme-Parser/ReadmeParser.php +0 -0
  71. includes/libraries/browser.php +0 -0
  72. includes/libraries/php-markdown/markdown.php +0 -0
  73. includes/licensing.php +0 -0
  74. includes/misc-functions.php +0 -60
  75. includes/multimedia.php +0 -60
  76. includes/opml-importer.php +32 -39
  77. includes/readme.php +0 -0
  78. includes/roles-capabilities.php +7 -45
  79. includes/scripts.php +252 -254
  80. includes/system-info.php +50 -36
  81. includes/templates-update.php +0 -15
  82. includes/update.php +5 -5
  83. js/admin-addon-ajax.js +1 -2
  84. js/admin-custom-bulk-actions.js +0 -0
  85. js/admin-custom.js +5 -4
  86. js/admin-help.js +0 -0
  87. js/admin-license-manager.js +0 -0
  88. js/admin-licensing.js +0 -0
  89. js/admin/tools/crons.js +1 -1
  90. js/admin/tools/logs.js +8 -0
  91. js/build/common.min.js +1 -1
  92. js/build/intro.min.js +1 -1
  93. js/build/pagination.min.js +1 -1
  94. js/build/plugins.min.js +1 -1
  95. js/build/templates.min.js +1 -1
  96. js/build/update.min.js +1 -1
  97. js/build/wpra-vendor.min.js +3 -4
CHANGELOG.md CHANGED
@@ -4,143 +4,6 @@ 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.22] - 2022-08-06
8
- ### Changed
9
- * YouTube embeds in the lightbox now begin playing automatically, if the browser allows it.
10
-
11
- ## [4.21.1] - 2022-07-20
12
- ### Fixed
13
- * An out-of-memory PHP error when importing items.
14
-
15
- ## [4.21] - 2022-07-13
16
- ### Change
17
- * Updated Twig to v1.42.2, to support PHP 8 or later.
18
- * Optimized feed item date processing when an item is being imported.
19
- * Permalink and GUID checks are now done across all feed sources when an item is being imported.
20
-
21
- ### Fixed
22
- * Various PHP 8 errors and deprecations compatibility.
23
- * The classic editor button was generating incorrect shortcodes.
24
-
25
- ## [4.20] - 2022-01-18
26
- ### Added
27
- * New option to use feed item GUIDs instead of permalinks to detect duplicate items.
28
-
29
- ### Changed
30
- * Small performance improvement when importing feed items.
31
-
32
- ### Fixed
33
- * A warning about `get_headers()` only working with URLs.
34
- * A warning about iteration over a non-array value.
35
- * An AJAX XSS vulnerability on the Feed Sources page. Thanks WPScan!
36
-
37
- ## [4.19.3] - 2021-11-24
38
- ### Fixed
39
- * An error during cron schedule filtering.
40
- * Not all image URLs in enclosure tags were being detected.
41
-
42
- ## [4.19.2] - 2021-10-28
43
- ### Changed
44
- * Cleaned up the code significantly.
45
- * Consistent permalink normalization between the preview and importing.
46
- * Some plugin strings were not internationalized.
47
- * Source information is extracted from feed items more reliably.
48
- * Audio links in feed items are detected more reliably.
49
- * Enclosure images in feed items are detected more reliably.
50
-
51
- ### Fixed
52
- * HTML entities caused unique title checks to always fail.
53
- * Some request data was not filtered and/or sanitized properly.
54
- * Some plugin-generated content was not properly escaped for use in HTML.
55
- * URLs added manually to the blacklist are now properly validated.
56
- * Feed sources and feed items restored from the trash become "draft" since WordPress 5.6.
57
-
58
- ## [4.19.1] - 2021-09-14
59
- ### Changed
60
- * More details are now logged when a fatal error occurs during an import.
61
- * Using local versions of images and stylesheets.
62
-
63
- ### Fixed
64
- * Importing would sometimes fail when trying to fetch the media:thumbnail image.
65
- * Some request data was not filtered and/or sanitized properly.
66
- * Some plugin-generated content was not properly escaped for use in HTML.
67
-
68
- ## [4.19] - 2021-07-06
69
- ### Added
70
- * Support for importing images from `<image>` tags.
71
-
72
- ### Changed
73
- * Exceptions thrown during an import and caught and logged.
74
-
75
- ## [4.18.2] - 2021-04-26
76
- ### Changed
77
- * Audio players no longer preload the audio file. Audio is now loaded only the play button is clicked.
78
-
79
- ### Fixed
80
- * Pagination would sometimes cause the page to scroll upwards.
81
- * Images were wrongly determined to be from Facebook and were being renamed incorrectly.
82
- * Invalid cron schedules no longer cause a fatal error.
83
- * The shortcode icon in the classic editor would sometimes not be shown.
84
-
85
- ## [4.18.1] - 2021-03-15
86
- ### Added
87
- * New filters to change the time limits during image downloads.
88
-
89
- ### Changed
90
- * Using a single store URL for addon license verification.
91
- * Increased the PHP execution time limits for image downloads.
92
-
93
- ### Fixed
94
- * Licenses for the Templates addon could not be verified.
95
-
96
- ## [4.18] - 2021-03-08
97
- ### Added
98
- * The total import time is now recorded in the debug log.
99
-
100
- ### Changed
101
- * Omitting dev files from the plugin, reducing its size.
102
- * Redesigned the "More Features" page.
103
- * Feed items link to the original article when shown without a template and in RSS feeds.
104
- * Allocating more PHP execution time for image downloads.
105
-
106
- ### Fixed
107
- * Images with HTML entities in the URL resulted in broken images and missing featured images.
108
- * The code that checks when a feed is saved no longer runs unnecessarily.
109
- * Fixed styling issues with the "Save" button in the Templates edit page.
110
- * The max title length option in the "Default" template was being applied in the "Feed Items" page.
111
-
112
- ## [4.17.10] - 2020-12-01
113
- ### Fixed
114
- * After updating the Templates add-on from v0.2, the add-on would be deactivated.
115
-
116
- ## [4.17.9] - 2020-11-25
117
- ### Changed
118
- * Auto image detection is now able to find the feed channel image.
119
- * SimplePie auto-discovery is turned off when the "Force feed" option is enabled.
120
- * The Feed Source post type is no longer public.
121
- * Meta box styling has been updated to match WordPress 5.3's updated styles.
122
-
123
- ### Fixed
124
- * Removed referer header from feed requests, fixed importing for some feeds.
125
- * Feeds that contain items without titles no longer only import just the first item.
126
- * Cron jobs are properly added/removed when the plugin is activated/deactivated, respectively.
127
- * Problems with the default template no longer trigger a fatal error.
128
-
129
- ## [4.17.8] - 2020-10-06
130
- ### Changed
131
- * Disabled SimplePie's HTML sanitization.
132
- * Updated jQuery code to be compatible with the upcoming update in WordPress.
133
- * Images without an extension can now be imported.
134
- * The image importing function now allows the image URL and local path to be changed via filters.
135
- * Changed how item importing is logged in the debugging log. The log now shows what hooks can reject an item.
136
-
137
- ### Fixed
138
- * WooCommerce Product type dropdown and accompanying options disappear while WP RSS Aggregator is active.
139
- * Addressed notices about `register_rest_route` being called incorrectly.
140
- * The "Validate feed" link did not work.
141
- * Sites on a multi-site network would see an error about a function not existing.
142
- * Errors would not be properly rendered for non-fatal notices and warnings.
143
-
144
  ## [4.17.7] - 2020-08-12
145
  ### Added
146
  * New HTML classes for pagination buttons.
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.7] - 2020-08-12
8
  ### Added
9
  * New HTML classes for pagination buttons.
css/admin-3.8.css CHANGED
File without changes
css/admin-editor.css CHANGED
File without changes
css/admin-styles.css CHANGED
@@ -1,1307 +1,1262 @@
1
- body.post-type-wprss_feed q {
2
- font-style: italic;
3
- }
4
- body.post-type-wprss_feed q:before {
5
- content: '"';
6
- }
7
- body.post-type-wprss_feed q:after {
8
- content: '"';
9
- }
10
-
11
- span.wp-rss-footer-text {
12
- font-style: italic;
13
- }
14
-
15
- .wprss-input {
16
- background: none repeat scroll 0 0 #EAF2FA;
17
- margin-bottom: 20px;
18
- padding-bottom: 10px;
19
- padding-left: 10px;
20
- padding-top: 10px;
21
- width: 600px;
22
- }
23
-
24
- .wprss-input p { line-height: 28px; }
25
-
26
- .wprss-input label {
27
- float: left;
28
- width: 95px !important;
29
- }
30
-
31
- .wprss-input input {
32
- height: 28px;
33
- margin-bottom: 0;
34
- padding: 0 0 0 5px;
35
- width: 400px;
36
- }
37
-
38
- .wprss-text-input {
39
- display: inline-block;
40
- width: 400px;
41
- max-width: 100%;
42
- }
43
-
44
- label.description {
45
- font-size: 13px;
46
- font-style: italic;
47
- }
48
-
49
- span.wprss-row-id {
50
- color: #8f8f8f;
51
- }
52
-
53
- #icon-wprss-aggregator {
54
- background: transparent url( '../images/icon-adminpage32.png' ) no-repeat !important;
55
- }
56
-
57
- body.post-type-wprss_feed #titlediv div.inside { display: none !important; }
58
-
59
- #misc-publishing-actions,
60
- #minor-publishing-actions { display: none; }
61
-
62
- div#force-feed-container {
63
- border-top: 1px solid #ddd;
64
- }
65
-
66
-
67
- /* FORM TABLES */
68
- .wprss-form-table th {
69
- width: 160px;
70
- max-width: 200px;
71
- padding: 10px;
72
- }
73
- .wprss-form-table th label {
74
- padding-top: 7px;
75
- }
76
- .wprss-form-table td {
77
- padding: 8px 10px;
78
- }
79
- .wprss-form-table td label {
80
- line-height: 15px;
81
- }
82
- @media screen and (max-width: 1025px) {
83
- .wprss-form-table th {
84
- display: block;
85
- padding: 0;
86
- }
87
- .wprss-form-table td {
88
- display: block;
89
- padding-left: 0;
90
- padding-right: 0;
91
- }
92
-
93
- .wprss-form-table td input[type="text"],
94
- .wprss-form-table td input[type="url"],
95
- .wprss-form-table td select {
96
- display: block;
97
- width: 100%;
98
- }
99
-
100
- .wprss-form-table td span.description {
101
- display: inline;
102
- }
103
-
104
- .wprss-form-table td input[type="checkbox"] + label {
105
- display: inline !important;
106
- }
107
-
108
- .wprss-form-table td input {
109
- line-height: normal;
110
- }
111
- }
112
-
113
-
114
-
115
- body.post-type-wprss_feed_item .add-new-h2,
116
- body.post-type-wprss_feed_item .tablenav select[name="m"],
117
- body.post-type-wprss_feed_item #post-query-submit
118
- { display: none; }
119
-
120
- body.post-type-wprss_feed_item a.row-title {
121
- cursor: default;
122
- font-weight: normal;
123
- color: #555;
124
- }
125
-
126
- #latest-news-cpac-settings li {
127
- list-style: none;
128
- line-height: 16px;
129
- }
130
-
131
- li.twitter a {
132
- background: transparent url('../images/twitter.png') no-repeat 0;
133
- padding-left: 20px;
134
- }
135
-
136
- li.facebook a {
137
- background: transparent url('../images/facebook.png') no-repeat 0;
138
- padding-left: 20px;
139
- }
140
-
141
- li.donate_link a:hover {
142
- color: darkGreen;
143
- }
144
-
145
- #preview_meta_box ul {
146
- list-style: disc;
147
- margin-left: 16px;
148
- }
149
-
150
- #preview_meta_box .invalid-feed-url {
151
- color: red;
152
- }
153
-
154
- #preview_meta_box .rss-date {
155
- color: #666;
156
-
157
- }
158
-
159
- /*.rss-aggregator_page_wprss-aggregator-settings .form-table th { width: 80px; }*/
160
-
161
-
162
- /* For excerpts and thumbnails admin screens
163
- .wprss_feed_page_wprss-aggregator-settings input,
164
- .wprss_feed_page_wprss-aggregator-settings input[type="checkbox"],
165
- .wprss_feed_page_wprss-aggregator-settings input[type="radio"] {
166
- margin-right: 8px;
167
- }
168
- */
169
-
170
- .wprss-license-status-text {
171
- margin-left: 8px;
172
- line-height: 27px;
173
- vertical-align: middle;
174
- }
175
-
176
- .wprss-license-icon-valid {
177
- color: green;
178
- }
179
-
180
- .wprss-license-icon-invalid,
181
- .wprss-license-icon-expired {
182
- color: #b71919;
183
- }
184
- .wprss-license-icon-inactive {
185
- color: #d19e5b;
186
- }
187
-
188
- input#default-thumbnail,
189
- input#wprss-et-license-key,
190
- input#wprss-c-license-key,
191
- input#wprss-kf-license-key,
192
- input#wprss-ftp-license-key {
193
- width: 300px;
194
- }
195
-
196
- input#thumbnails-height,
197
- input#thumbnails-width {
198
- /*width: 29px;*/
199
- }
200
-
201
-
202
- /* Red Button */
203
-
204
- .wp-core-ui .button-red {
205
- background: #BD2B2B;
206
- border-color: transparent;
207
- color: #fff;
208
- text-decoration: none;
209
- text-shadow: none;
210
- }
211
-
212
- .wp-core-ui .button-red.hover,
213
- .wp-core-ui .button-red:hover {
214
- color: #fff;
215
- border-color: transparent;
216
- background-color: #AC0F0F;
217
- }
218
-
219
- .wp-core-ui .button-red.focus,
220
- .wp-core-ui .button-red:focus {
221
- color: #fff;
222
- background-color: #AC0F0F;
223
- border-color: transparent;
224
- box-shadow: 0 0 0 1px #fff,0 0 0 3px #AC0F0F;
225
- }
226
-
227
- .wp-core-ui .button-red.active,
228
- .wp-core-ui .button-red:active {
229
- color: #fff;
230
- background-color: #A20909;
231
- border-color: transparent;
232
- }
233
-
234
- .wp-core-ui .button-red[disabled],
235
- .wp-core-ui .button-red:disabled,
236
- .wp-core-ui .button-red-disabled {
237
- color: #fba6a8 !important;
238
- background: #DD383A !important;
239
- box-shadow: 0 0 0 transparent !important;
240
- border-color: transparent !important;
241
- text-shadow: 0 0 0 transparent !important;
242
- }
243
-
244
- #wpra-system-info-textarea,
245
- #wprss-error-log-textarea {
246
- width: 800px;
247
- height: 400px;
248
- font-family: Menlo, Monaco, monospace;
249
- white-space: pre;
250
- overflow: auto;
251
- display: block;
252
- }
253
-
254
- #wpra-system-info-textarea {
255
- display: block;
256
- width: 100%;
257
- height: 600px;
258
- font-family: Menlo, Monaco, monospace;
259
- white-space: pre;
260
- overflow: auto;
261
- }
262
-
263
- .wprss-error-log-action {
264
- display: inline-block;
265
- }
266
-
267
- #wprss-clear-error-log-form {
268
- display: inline-block;
269
- }
270
- #wprss-clear-error-log-form,
271
- #wprss-clear-error-log-form > button {
272
- vertical-align: baseline;
273
- }
274
-
275
- form.wprss-error-log-action input[type="submit"]:active {
276
- vertical-align: baseline;
277
- }
278
- /* The debug log root element */
279
- div.wpra-log {
280
- display: block;
281
- position: relative;
282
- width: 100%;
283
- }
284
-
285
- /* The "Filters" label */
286
- div.wpra-log > p > strong:first-child {
287
- text-decoration: underline;
288
- margin-right: 10px;
289
- }
290
-
291
- /* The debug log filters separator */
292
- div.wpra-log .wpra-toggle-logs:not(:last-of-type)::after {
293
- content: ' | ';
294
- color: #3c3c3c;
295
- pointer-events: none;
296
- }
297
- /* The debug log filters */
298
- div.wpra-log .wpra-toggle-logs a {
299
- text-decoration: none;
300
- outline: none;
301
- box-shadow: 0 0 transparent;
302
- }
303
- /* The debug log filters when not selected */
304
- div.wpra-log .wpra-toggle-logs:not(.wpra-selected):not(.wpra-log-filter-disabled) a {
305
- color: #626262;
306
- }
307
- /* The debug log filters when selected */
308
- div.wpra-log .wpra-toggle-logs.wpra-selected:not(.wpra-log-filter-disabled) a {
309
- font-weight: bold;
310
- }
311
-
312
- /* The debug log "error" filter text color when there are errors */
313
- div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="error"]:not(.wpra-log-filter-disabled) a {
314
- color: #d40000;
315
- }
316
- /* The debug log "warning" filter text color when there are warnings */
317
- div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="warning"]:not(.wpra-log-filter-disabled) a {
318
- color: #d45500;
319
- }
320
- /* The debug log "notice" filter text color when there are notices */
321
- div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="notice"]:not(.wpra-log-filter-disabled) a {
322
- color: #d48a00;
323
- }
324
- /* The debug log "info" filter text color when there are info logs */
325
- div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="info"]:not(.wpra-log-filter-disabled) a {
326
- color: #009cd6;
327
- }
328
- /* The debug log "debug" filter text color when there are debug logs */
329
- div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="debug"]:not(.wpra-log-filter-disabled) a {
330
- color: #8242d4;
331
- }
332
-
333
- /* Disabled debug log filters */
334
- div.wpra-log .wpra-toggle-logs.wpra-log-filter-disabled a {
335
- color: #8b8b8b !important;
336
- font-style: italic;
337
- text-decoration: none;
338
- cursor: not-allowed;
339
- }
340
-
341
- /* The debug log */
342
- div.wpra-log-container {
343
- width: 100%;
344
- max-height: 600px;
345
- border: 1px solid #d1d1d1;
346
- padding: 5px;
347
- margin-bottom: 15px;
348
- overflow: auto;
349
- background: #222833;
350
- }
351
-
352
- /* The debug log & empty log notice */
353
- div.wpra-log-container,
354
- .notice.wpra-empty-log-notice {
355
- display: block;
356
- box-sizing: border-box;
357
- }
358
- .notice.wpra-empty-log-notice {
359
- width: 400px;
360
- }
361
-
362
- /* The log table */
363
- div.wpra-log-container > table {
364
- font-family: monospace;
365
- min-width: 100%;
366
- border: 0;
367
- border-collapse: collapse;
368
- }
369
- /* Log table: row formatting */
370
- div.wpra-log-container > table > tbody > tr {
371
- }
372
- /* Log table: cell formatting */
373
- div.wpra-log-container > table > tbody > tr > td {
374
- color: #cbcdda;
375
- vertical-align: baseline;
376
- padding: 4px 10px;
377
- border-bottom: 2px solid #222833;
378
- }
379
-
380
- /* Log table: row on hover */
381
- div.wpra-log-container > table > tbody > tr:hover {
382
- background: rgba(200, 200, 200, 0.1);
383
- }
384
-
385
- /* Log table: date and level cells do not wrap */
386
- div.wpra-log-container > table > tbody > tr > td.wpra-log-date,
387
- div.wpra-log-container > table > tbody > tr > td.wpra-log-level {
388
- white-space: nowrap;
389
- overflow: hidden;
390
- }
391
- div.wpra-log-container > table > tbody > tr > td.wpra-log-date {
392
- width: 150px;
393
- }
394
- div.wpra-log-container > table > tbody > tr > td.wpra-log-level {
395
- text-align: center;
396
- width: 60px;
397
- }
398
- div.wpra-log-container > table > tbody > tr > td.wpra-log-feed {
399
- width: 150px;
400
- }
401
-
402
- /* Log table: styling for DEBUG log messages */
403
- div.wpra-log-container > table > tbody > tr.wpra-log-debug > td:not(.wpra-log-date) {
404
- color: #b695e6;
405
- }
406
- /* Log table: styling for INFO log messages */
407
- div.wpra-log-container > table > tbody > tr.wpra-log-info > td:not(.wpra-log-date) {
408
- color: #38eaff;
409
- }
410
- /* Log table: styling for NOTICE log messages */
411
- div.wpra-log-container > table > tbody > tr.wpra-log-notice > td:not(.wpra-log-date) {
412
- color: #ffea00;
413
- }
414
- /* Log table: styling for WARNING log messages */
415
- div.wpra-log-container > table > tbody > tr.wpra-log-warning > td {
416
- color: #000;
417
- background-color: #ffea00;
418
- font-weight: bold;
419
- }
420
- /* Log table: styling for ERROR log messages */
421
- div.wpra-log-container > table > tbody > tr.wpra-log-error > td {
422
- color: white;
423
- background-color: #b90000;
424
- font-weight: bold;
425
- }
426
-
427
- @media screen and (min-width: 782px) {
428
- #custom_feed_title {
429
- width: 400px;
430
- }
431
- }
432
-
433
- /* Number Roller for Feed Source Limit */
434
- .wprss-number-roller {
435
- width: 80px;
436
- vertical-align: middle;
437
- }
438
- @media screen and (max-width: 782px) {
439
- .wprss-number-roller {
440
- width: 100px;
441
- }
442
- }
443
-
444
- /* Welcome Screen */
445
- .about-wrap ul {
446
- list-style: disc;
447
- padding-left: 30px;
448
- }
449
-
450
- /* Excerpts and Thumbnails */
451
-
452
- input#thumbnails-height,
453
- input#thumbnails-width {
454
- margin-right: 2px;
455
- }
456
-
457
- label[for=thumbnails-height],
458
- label[for=thumbnails-width] {
459
- margin-left: 8px;
460
- }
461
-
462
- .wp-list-table > thead > tr > th#thumbnail[scope="col"] {
463
- width: 95px;
464
- }
465
-
466
- select + label.description {
467
- margin-left: 8px;
468
- }
469
-
470
- input#title-limit {
471
- width: 100px;
472
- }
473
-
474
- .wprss-form-table th,
475
- .wprss-form-table tr,
476
- .wprss-form-table td {
477
- border: 0 transparent !important;
478
- }
479
-
480
- .wprss-indicator-green,
481
- .wprss-indicator-red,
482
- .wprss-indicator-grey {
483
- font-size: 1.6em;
484
- vertical-align: middle;
485
- margin-right: 10px;
486
- line-height: 30px;
487
- }
488
- .wprss-indicator-green {
489
- color: #009922;
490
- }
491
- .wprss-indicator-grey {
492
- color: #888;
493
- }
494
- .wprss-indicator-red {
495
- color: #EB442A;
496
- }
497
-
498
-
499
- .wprss-meta-slider {
500
- display: none;
501
- margin-top: 5px;
502
- }
503
-
504
- .wprss-slider-button {
505
- cursor: pointer;
506
- margin-right: 8px !important;
507
- }
508
-
509
- #wprss_activate_feed,
510
- #wprss_pause_feed {
511
- display: block;
512
- }
513
-
514
- .wprss-date-error {
515
- background: rgba( 245, 45, 45, 0.6 );
516
- }
517
-
518
- div.wprss-meta-side-setting {
519
- display: block;
520
- padding: 8px;
521
- border-bottom: 1px solid rgba(0,0,0,0.1);
522
- }
523
-
524
- div.wprss-meta-side-setting > p {
525
- margin: 2px 0;
526
- }
527
- div.wprss-meta-side-setting > p > label {
528
- vertical-align: baseline;
529
- }
530
- div.wprss-meta-side-setting a.wprss-slider-button {
531
- vertical-align: middle;
532
- }
533
-
534
- div.inside .wprss-meta-side-setting:last-child {
535
- border-bottom: 0 solid transparent;
536
- }
537
-
538
- input[type="checkbox"]#wprss-force-feed {
539
- margin-left: 10px;
540
- }
541
-
542
- /******************************
543
- * FEED SOURCES PAGE COLUMNS
544
- */
545
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th {
546
- text-align: left;
547
- overflow: hidden;
548
- }
549
- /* CHECKBOX */
550
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead td#cb {
551
- width: 30px !important;
552
- }
553
- /* STATE */
554
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state {
555
- width: 70px !important;
556
- }
557
- /* NAME */
558
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#title {
559
- width: auto;
560
- }
561
- /* NEXT UPDATE */
562
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#updates {
563
- width: 300px !important;
564
- }
565
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts td.column-updates p {
566
- margin-bottom: 0 !important;
567
- }
568
- /* FEED COUNT */
569
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#feed-count {
570
- width: 200px !important;
571
- }
572
- /* CATEGORIES */
573
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#category,
574
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#category {
575
- width: 130px !important;
576
- }
577
-
578
- /* FEED ITEM IMAGE */
579
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#image {
580
- width: 120px;
581
- }
582
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody img.wpra-item-ft-image {
583
- width: 100px;
584
- }
585
-
586
- @media screen and (max-width: 660px) {
587
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#id,
588
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-id,
589
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-id,
590
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state,
591
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-state,
592
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-state {
593
- display: none;
594
- }
595
- }
596
- @media only screen and (max-width: 782px) {
597
- /* WIDEN CHECKBOX COLUMN */
598
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead td#cb {
599
- width: 50px !important;
600
- }
601
-
602
- /* HIDE STATE COLUMN */
603
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state,
604
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-state,
605
- body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-state {
606
- display: none;
607
- padding: 8px 10px;
608
- }
609
-
610
- /* HIDE ITEM IMAGE COLUMN */
611
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#image,
612
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tfoot th.column-image,
613
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-image {
614
- display: none;
615
- }
616
-
617
- /* IMAGE IS LARGER IN RESPONSIVE MOBILE VIEW */
618
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody img.wpra-item-ft-image {
619
- width: 350px;
620
- }
621
-
622
- /* HIDE INLINE IMAGE COLUMN NAME IN RESPONSIVE MOBILE VIEW */
623
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-image::before {
624
- display: none;
625
- }
626
- }
627
-
628
- @media only screen and (max-width: 1200px) {
629
- /* HIDE ITEM PERMALINK COLUMN */
630
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#permalink,
631
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tfoot th.column-permalink,
632
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-permalink {
633
- display: none;
634
- }
635
- }
636
-
637
- /* For feed items */
638
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#publishdate {
639
- width: 150px;
640
- }
641
- body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#source {
642
- width: 200px;
643
- }
644
-
645
-
646
-
647
- i.wprss-feed-error-symbol {
648
- display: none;
649
- font-size: 1.2em;
650
- vertical-align: middle;
651
- color: rgb(200,0,0);
652
- margin-left: 8px;
653
- }
654
-
655
- i.wprss-updating-feed-icon {
656
- margin-left: 8px;
657
- display: none;
658
- }
659
-
660
- i.wprss-feed-error-symbol.wprss-show,
661
- i.wprss-updating-feed-icon.wprss-show {
662
- display: inline-block;
663
- }
664
-
665
- /* Log textarea styles */
666
- #wprss-log-textarea {
667
- width: 800px;
668
- height: 400px;
669
- font-family: Menlo, Monaco, monospace;
670
- background: none;
671
- white-space: pre-wrap;
672
- overflow: auto;
673
- display: block;
674
- background: rgb( 255, 245, 245 );
675
- }
676
-
677
-
678
-
679
- /*--------------------------------------------------------------------------
680
- *
681
- * Add-Ons
682
- *
683
- *-------------------------------------------------------------------------*/
684
-
685
- #add-ons {
686
- margin-bottom: 20px;
687
- }
688
-
689
- #add-ons .add-on-group {
690
- display: flex;
691
- flex-flow: row wrap;
692
- justify-content: flex-start;
693
- align-items: flex-start;
694
- }
695
-
696
- #add-ons .add-on-group:first-child {
697
- margin-top: 0;
698
- padding-top: 0;
699
- }
700
-
701
- #add-ons .add-on {
702
- display: inline-block;
703
- position: relative;
704
- flex: 0 0 220px;
705
- width: 220px;
706
- margin: 10px 20px 10px 0;
707
- background: #FFFFFF;
708
- border: 1px solid #E5E5E5;
709
- border-radius: 3px;
710
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
711
- box-sizing: border-box;
712
- min-height: 320px;
713
- overflow: hidden;
714
- }
715
-
716
- #add-ons .add-on h3 {
717
- margin: 0.5em 0 1.5em;
718
- }
719
-
720
- #add-ons .add-on h3 a {
721
- color: inherit;
722
- text-decoration: none;
723
- }
724
-
725
- #add-ons .add-on .inner {
726
- min-height: 170px;
727
- padding: 20px 15px;
728
- }
729
-
730
- #add-ons .add-on .footer {
731
- overflow: hidden;
732
- position: absolute;
733
- width: 100%;
734
- bottom: 0;
735
- padding: 15px 0;
736
- }
737
-
738
- #add-ons .add-on .footer .button {
739
- float: left;
740
- margin-left: 15px;
741
- }
742
-
743
- .add-on .corner-ribbon {
744
- position: absolute;
745
- top: 18px;
746
- right: -47px;
747
- font-size: 12px;
748
- width: 150px;
749
- padding: 2px 0;
750
- color: #fff;
751
- background: #333;
752
- text-align: center;
753
- transform: rotate(45deg);
754
- transform-origin: center center;
755
- }
756
-
757
- #add-ons .add-on.bundle-plan {
758
- border: 2px solid #ff792b;
759
- box-shadow: 0 0 25px -12px rgba(255, 121, 43, 0.6);
760
- }
761
-
762
- #add-ons .add-on.bundle-plan .corner-ribbon {
763
- background: #ff792b;
764
- }
765
-
766
- #add-ons .add-on.spotlight .corner-ribbon {
767
- background: #DD234B;
768
- }
769
-
770
- #add-ons .add-on.bundle-plan .footer,
771
- #add-ons .add-on.spotlight .footer {
772
- background: transparent;
773
- border-top: 0;
774
- }
775
-
776
-
777
- #add-ons .add-on-active .button-disabled:focus,
778
- #add-ons .add-on-active .button-disabled:active {
779
- background: #fafafa;
780
- }
781
-
782
- #add-ons .add-on-title {
783
- float: left;
784
- width: 100%;
785
- margin: 25px 0 25px;
786
- border-top: #F5F5F5 solid 1px;
787
- }
788
-
789
- /*== BLACKLIST */
790
- body.post-type-wprss_blacklist .add-new-h2,
791
- body.post-type-wprss_blacklist ul.subsubsub,
792
- body.post-type-wprss_blacklist .alignleft.actions {
793
- display: none;
794
- }
795
-
796
- body.post-type-wprss_blacklist .alignleft.actions.bulkactions {
797
- display: inline-block;
798
- }
799
-
800
- .wprss-header-small {
801
- color: #777;
802
- font-size: 0.7em;
803
- }
804
-
805
- /* Inline Help ============================================================== */
806
-
807
- .wprss-tooltip-handle,
808
- .wprss-tooltip-handle:hover,
809
- .wprss-tooltip-handle:focus {
810
- text-decoration: none;
811
- color: #aaaaaa;
812
- outline: none;
813
- }
814
-
815
- .wprss-tooltip-handle {
816
- margin-left: 5px;
817
- font-size: 15px;
818
- color: rgb(190, 190, 190);
819
- vertical-align: middle;
820
- }
821
-
822
- .wprss-tooltip-handle-side {
823
- float: right;
824
- }
825
-
826
- .wprss-tooltip-content {
827
- display: none;
828
- }
829
-
830
- .wprss-ui-tooltip {
831
- color: #444 !important;
832
- padding: 8px 10px !important;
833
- background: #fefefe !important;
834
- border: 1px solid #ccc !important;
835
- border-radius: 1px !important;
836
- font-family: "Open Sans", sans-serif !important;
837
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.17) !important;
838
- }
839
- .wprss-ui-tooltip p:first-child {
840
- margin-top: 0;
841
- }
842
- .wprss-ui-tooltip p:last-child {
843
- margin-bottom: 0;
844
- }
845
- .wprss-ui-tooltip p {
846
- margin: 8px 0;
847
- }
848
- .wprss-ui-tooltip p, code {
849
- font-size: 0.9em !important;
850
- }
851
- .wprss-ui-tooltip hr {
852
- margin: 0;
853
- }
854
-
855
- .wprss-section-tooltip-handle,
856
- .wprss-section-tooltip-handle:hover,
857
- .wprss-section-tooltip-handle:active,
858
- .wprss-section-tooltip-handle:visited,
859
- .wprss-section-tooltip-handle:link,
860
- .wprss-section-tooltip-handle:focus {
861
- color: #006799;
862
- margin-left: 5px;
863
- text-decoration: none;
864
- outline: none;
865
- cursor: help;
866
- font-size: 15px;
867
- }
868
-
869
- /* For non settings page screens */
870
- @media only screen and (max-width: 850px) {
871
-
872
- body:not(.wprss_feed_page_wprss-aggregator-settings) .wprss-tooltip-handle {
873
- color: #999;
874
- font-size: 1em;
875
- padding: 6px 10px;
876
- margin-left: 0;
877
- background: #e5e5e5;
878
- border-radius: 3px;
879
- vertical-align: middle;
880
- }
881
-
882
- body:not(.wprss_feed_page_wprss-aggregator-settings) select + .wprss-tooltip-handle,
883
- body:not(.wprss_feed_page_wprss-aggregator-settings) input[type="input"] + .wprss-tooltip-handle,
884
- body:not(.wprss_feed_page_wprss-aggregator-settings) input[type="password"] + .wprss-tooltip-handle {
885
- margin-top: 5px;
886
- }
887
-
888
- body:not(.wprss_feed_page_wprss-aggregator-settings) .wprss-tooltip-handle:after {
889
- content: 'Help';
890
- margin-left: 5px;
891
- font-family: 'Open Sans', sans-serif;
892
- }
893
-
894
- }
895
-
896
-
897
- /* For settings page screens */
898
- @media only screen and (max-width: 782px) {
899
-
900
- body.wprss_feed_page_wprss-aggregator-settings .wprss-tooltip-handle {
901
- color: #999;
902
- font-size: 1em;
903
- padding: 6px 10px;
904
- margin-left: 0;
905
- background: #e5e5e5;
906
- border-radius: 3px;
907
- vertical-align: middle;
908
- }
909
-
910
- body.wprss_feed_page_wprss-aggregator-settings select + .wprss-tooltip-handle,
911
- body.wprss_feed_page_wprss-aggregator-settings input[type="input"] + .wprss-tooltip-handle,
912
- body.wprss_feed_page_wprss-aggregator-settings input[type="password"] + .wprss-tooltip-handle {
913
- margin-top: 5px;
914
- }
915
-
916
- body.wprss_feed_page_wprss-aggregator-settings .wprss-tooltip-handle:after {
917
- content: 'Help';
918
- margin-left: 5px;
919
- font-family: 'Open Sans', sans-serif;
920
- }
921
-
922
- }
923
-
924
-
925
- @media only screen and (max-width: 1026px) {
926
- .wprss-tr-hr th {
927
- padding-top: 10px;
928
- }
929
- }
930
-
931
- .ajax-error,
932
- .ajax-error:hover,
933
- .ajax-error:visited,
934
- .ajax-error:link,
935
- .ajax-error:active {
936
- color: #a00;
937
- }
938
-
939
- /* Removes the "Add New" button for Feed Items */
940
- .post-type-wprss_feed_item .page-title-action {
941
- display: none
942
- }
943
-
944
- /* Changelog styles */
945
- .wpra-changelog-container h2 {
946
- font-size: 1.4em;
947
- }
948
- .wpra-changelog-container h3 {
949
- font-weight: normal;
950
- font-size: 1.2em;
951
- }
952
- .wpra-changelog-container ul {
953
- list-style: disc;
954
- list-style-position: inside;
955
- }
956
-
957
- .wpra_ft_image_option {
958
- margin-top: 10px;
959
- }
960
-
961
- #wpra_image_min_size_row {
962
- display: none;
963
- }
964
-
965
- /* Spacing between image width and height fields */
966
- #wpra_image_min_size_row > td > label {
967
- margin-right: 10px;
968
- }
969
-
970
- #wprss-feed-def-ft-image-preview {
971
- width: 220px;
972
- }
973
-
974
- #wprss-feed-def-ft-image-preview-hint {
975
- margin-bottom: 8px;
976
- }
977
-
978
-
979
- /*
980
- * The Feed Source List Table styles that mimic the plugins table
981
- */
982
-
983
- .post-type-wprss_feed table.wp-list-table.posts tbody tr th,
984
- .post-type-wprss_feed table.wp-list-table.posts tbody tr td
985
- {
986
- box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .1);
987
- }
988
-
989
- /* Feed updating/deleting animation in feed sources table */
990
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating,
991
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting {
992
- /*background-image: linear-gradient(-45deg, rgba(30, 30, 30, 0.05) 25%, transparent 0, transparent 50%, rgba(50, 50, 50, 0.05) 50%, rgba(30, 30, 30, 0.05) 75%, transparent 0, #0000);*/
993
- /*background-image: linear-gradient(*/
994
- /* -45deg, rgba(0, 0, 0, 0.9) 25%,*/
995
- /* transparent 0,*/
996
- /* transparent 50%,*/
997
- /* rgba(0, 0, 0, 0.9) 50%,*/
998
- /* rgba(0, 0, 0, 0.9) 75%,*/
999
- /* transparent 0, #0000*/
1000
- /*);*/
1001
- background-size: 80px 80px;
1002
- background-blend-mode: overlay;
1003
- }
1004
-
1005
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating > *,
1006
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting > * {
1007
- background: transparent !important;
1008
- }
1009
-
1010
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating {
1011
- animation: wpra-feed-updating-animation 1.3s linear infinite;
1012
- background-color: #e9f9ee;
1013
- }
1014
- .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting {
1015
- animation: wpra-feed-updating-animation 1s linear infinite;
1016
- background-color: #f8eaea;
1017
- }
1018
-
1019
- @keyframes wpra-feed-updating-animation {
1020
- 0% {
1021
- background-position: 0 0;
1022
- }
1023
- 50% {
1024
- background-position: 80px 80px;
1025
- }
1026
- 100% {
1027
- background-position: 160px 160px;
1028
- }
1029
- }
1030
-
1031
- /*
1032
- * Styles for the Feed Source List Table "State" column
1033
- */
1034
- div.wprss-feed-state-container,
1035
- div.wprss-feed-source-type
1036
- {
1037
- display: inline-block;
1038
- }
1039
-
1040
- /* the feed type icon */
1041
- div.wprss-feed-source-type {
1042
- float: right;
1043
- }
1044
- /* inactive color */
1045
- .post-type-wprss_feed table.wp-list-table tr div.wprss-feed-source-type {
1046
- color: #aaa;
1047
- }
1048
- /* active color */
1049
- .post-type-wprss_feed table.wp-list-table tr.active div.wprss-feed-source-type {
1050
- color: #ff792b;
1051
- }
1052
- /* youtube color */
1053
- .post-type-wprss_feed table.wp-list-table tr.active div.wprss-feed-source-type.wprss-feed-source-type-yt {
1054
- color: #ff0000;
1055
- }
1056
-
1057
- .post-type-wprss_feed table.wp-list-table tbody td.column-state {
1058
- padding-right: 0;
1059
- }
1060
-
1061
- .column-updates > p {
1062
- margin: 0 !important;
1063
- }
1064
- .post-type-wprss_feed table.wp-list-table.posts tbody tr .next-update-container {
1065
- font-weight: bold;
1066
- }
1067
- .post-type-wprss_feed table.wp-list-table.posts tbody tr:not(.active) .next-update-container {
1068
- display: none;
1069
- }
1070
-
1071
- /* The last update time in the feed sources page table */
1072
- .post-type-wprss_feed table.wp-list-table.posts .last-update-num-items-container {
1073
- color: #666;
1074
- font-style: italic;
1075
- font-size: 90%;
1076
- }
1077
-
1078
- /* The imported items link in the feed sources page - disabled when 0 items */
1079
- .post-type-wprss_feed table.wp-list-table.posts .items-imported-link.has-imported-items {
1080
- font-weight: bold;
1081
- line-height: 20px;
1082
- }
1083
- .post-type-wprss_feed table.wp-list-table.posts .items-imported-link:not(.has-imported-items) {
1084
- color: #777;
1085
- pointer-events: none;
1086
- }
1087
-
1088
- /* The delete items row action in the feed sources page - hidden when 0 items */
1089
- .post-type-wprss_feed table.wp-list-table.posts .row-actions .purge-posts:not(.has-imported-items) {
1090
- display: none;
1091
- }
1092
-
1093
- /* Styles for the disabled "Fetch" and "Delete" feed source row actions */
1094
- .post-type-wprss_feed table.wp-list-table.posts .row-actions a.wprss_fetch_items_ajax_action[disabled] {
1095
- color: #555;
1096
- }
1097
- .post-type-wprss_feed table.wp-list-table.posts .row-actions a.wprss_delete_items_ajax_action[disabled] {
1098
- color: #666;
1099
- }
1100
-
1101
- /* The feed updating/deleting spinner icon */
1102
- .post-type-wprss_feed table.wp-list-table.posts .column-feed-count .spinner {
1103
- float: none;
1104
- vertical-align: bottom;
1105
- }
1106
- .post-type-wprss_feed table.wp-list-table.posts tr.wpra-feed-is-updating .column-feed-count .spinner,
1107
- .post-type-wprss_feed table.wp-list-table.posts tr.wpra-feed-is-deleting .column-feed-count .spinner {
1108
- visibility: visible;
1109
- }
1110
-
1111
- /*
1112
- * TOGGLE SWITCH
1113
- */
1114
- .wprss-switch {
1115
- position: relative;
1116
- display: inline-block;
1117
- width: 34px;
1118
- height: 18px;
1119
- }
1120
- .wprss-switch input {
1121
- opacity: 0;
1122
- width: 0;
1123
- height: 0;
1124
- }
1125
- .wprss-switch-slider {
1126
- position: absolute;
1127
- cursor: pointer;
1128
- top: 0;
1129
- left: 0;
1130
- right: 0;
1131
- bottom: 0;
1132
- border-radius: 34px;
1133
- background-color: #ccc;
1134
- transition: .2s;
1135
- -webkit-transition: .2s;
1136
- }
1137
- .wprss-switch-slider:before {
1138
- position: absolute;
1139
- content: "";
1140
- width: 12px;
1141
- height: 12px;
1142
- left: 4px;
1143
- bottom: 3px;
1144
- border-radius: 50%;
1145
- background-color: white;
1146
- transition: .2s;
1147
- -webkit-transition: .2s;
1148
- }
1149
- input:checked + .wprss-switch-slider {
1150
- background-color: #0baa3c;
1151
- }
1152
- input:focus + .wprss-switch-slider {
1153
- box-shadow: 0 0 1px #2196F3;
1154
- }
1155
- input:checked + .wprss-switch-slider:before {
1156
- -webkit-transform: translateX(14px);
1157
- -ms-transform: translateX(14px);
1158
- transform: translateX(14px);
1159
- }
1160
-
1161
- .postbox .inside .wpra-feed-save-meta-box {
1162
- border-bottom: 1px solid #ccc;
1163
- padding: 10px;
1164
- margin: 0 -10px;
1165
- margin-top: -11px;
1166
- margin-bottom: 10px;
1167
- background: #fff;
1168
- }
1169
-
1170
- .postbox .inside .wpra-feed-save-meta-box label span {
1171
- font-weight: bold;
1172
- font-size: 14px;
1173
- }
1174
-
1175
- .postbox .inside .wpra-feed-save-meta-box input[type="text"] {
1176
- text-align: left !important;
1177
- }
1178
-
1179
- /* -- INLINE STYLES -- */
1180
-
1181
- form.wpra-inline-form {
1182
- display: inline-block;
1183
- }
1184
-
1185
- form.wpra-header-form {
1186
- display: inline-block;
1187
- margin: 0;
1188
- padding: 0;
1189
- border: 0;
1190
- }
1191
-
1192
- h1.wpra-inline-header,
1193
- h2.wpra-inline-header,
1194
- h3.wpra-inline-header,
1195
- h4.wpra-inline-header
1196
- {
1197
- display: inline-block;
1198
- margin-right: 5px;
1199
- }
1200
-
1201
- button.button.wpra-header-button {
1202
- position: relative;
1203
- vertical-align: baseline;
1204
- top: -1px;
1205
- }
1206
-
1207
- /* -- SLIDE BOX -- */
1208
-
1209
- div.wpra-slide-box {
1210
- display: none;
1211
- margin: 10px 0;
1212
- padding: 15px;
1213
- background: #fff;
1214
- border: 1px solid #ccc;
1215
- border-radius: 2px;
1216
- }
1217
-
1218
- div.wpra-slide-box.wpra-slide-box-open {
1219
- display: block;
1220
- }
1221
-
1222
- div.wpra-slide-box form {
1223
- display: block;
1224
- }
1225
-
1226
- div.wpra-slide-box h4 {
1227
- font-size: 16px;
1228
- margin: 0;
1229
- margin-bottom: 15px;
1230
- padding-bottom: 5px;
1231
- border-bottom: 1px solid #ddd;
1232
- }
1233
-
1234
- div.wpra-slide-box form label {
1235
- display: flex;
1236
- flex-direction: row;
1237
- align-items: center;
1238
- line-height: 1;
1239
- font-size: 1em;
1240
- margin: 5px 0;
1241
- }
1242
-
1243
- div.wpra-slide-box label > * {
1244
- flex-grow: 1;
1245
- }
1246
-
1247
- div.wpra-slide-box label > span {
1248
- display: inline-block;
1249
- flex-grow: 0;
1250
- width: 200px;
1251
- font-size: 1em;
1252
- }
1253
- div.wpra-slide-box label input[type="text"],
1254
- div.wpra-slide-box label input[type="number"],
1255
- div.wpra-slide-box label input[type="text"]
1256
- {
1257
- height: 28px;
1258
- min-height: 28px;
1259
- }
1260
-
1261
- div.wpra-slide-box div.wpra-submit-wrap {
1262
- margin-top: 10px;
1263
- }
1264
- div.wpra-slide-box div.wpra-submit-wrap.right {
1265
- text-align: right;
1266
- }
1267
-
1268
- div.wpra-slide-box div.wpra-submit-wrap > button {
1269
- text-align: center;
1270
- }
1271
-
1272
- /* -- ERROR LOG OPTIONS (SLIDE BOX) -- */
1273
-
1274
- #wprss-log-options-form input[name="logging_limit_days"] {
1275
- width: 80px;
1276
- }
1277
-
1278
- /* -- BLACKLIST TOOL -- */
1279
-
1280
- #wpra-add-blacklist-container form label span:first-child {
1281
- width: 120px;
1282
- }
1283
-
1284
- /* -- LOG TOOL -- */
1285
-
1286
- #wprss-error-log-options {
1287
- margin: 15px 0;
1288
- }
1289
-
1290
- #wprss-clear-error-log-form {
1291
- float: right;
1292
- position: relative;
1293
- top: -3px;
1294
- }
1295
-
1296
- .wpra-log-filters {
1297
- padding: 2px 0;
1298
- margin: 0;
1299
- }
1300
- p.wpra-logs-shown-msg {
1301
- margin: 5px 0;
1302
- }
1303
-
1304
- /* -- MISC -- */
1305
- .wpra-no-margin {
1306
- margin: 0;
1307
- }
1
+ body.post-type-wprss_feed q {
2
+ font-style: italic;
3
+ }
4
+ body.post-type-wprss_feed q:before {
5
+ content: '"';
6
+ }
7
+ body.post-type-wprss_feed q:after {
8
+ content: '"';
9
+ }
10
+
11
+ span.wp-rss-footer-text {
12
+ font-style: italic;
13
+ }
14
+
15
+ .wprss-input {
16
+ background: none repeat scroll 0 0 #EAF2FA;
17
+ margin-bottom: 20px;
18
+ padding-bottom: 10px;
19
+ padding-left: 10px;
20
+ padding-top: 10px;
21
+ width: 600px;
22
+ }
23
+
24
+ .wprss-input p { line-height: 28px; }
25
+
26
+ .wprss-input label {
27
+ float: left;
28
+ width: 95px !important;
29
+ }
30
+
31
+ .wprss-input input {
32
+ height: 28px;
33
+ margin-bottom: 0;
34
+ padding: 0 0 0 5px;
35
+ width: 400px;
36
+ }
37
+
38
+ .wprss-text-input {
39
+ display: inline-block;
40
+ width: 400px;
41
+ max-width: 100%;
42
+ }
43
+
44
+ label.description {
45
+ font-size: 13px;
46
+ font-style: italic;
47
+ }
48
+
49
+ span.wprss-row-id {
50
+ color: #8f8f8f;
51
+ }
52
+
53
+ #icon-wprss-aggregator {
54
+ background: transparent url( '../images/icon-adminpage32.png' ) no-repeat !important;
55
+ }
56
+
57
+ body.post-type-wprss_feed #titlediv div.inside { display: none !important; }
58
+
59
+ #misc-publishing-actions,
60
+ #minor-publishing-actions { display: none; }
61
+
62
+ div#force-feed-container {
63
+ border-top: 1px solid #ddd;
64
+ }
65
+
66
+
67
+ /* FORM TABLES */
68
+ .wprss-form-table th {
69
+ width: 135px;
70
+ max-width: 135px;
71
+ padding: 7px 10px 10px 0;
72
+ }
73
+ .wprss-form-table td {
74
+ padding: 7px 10px;
75
+ }
76
+ .wprss-form-table td label {
77
+ line-height: 15px;
78
+ }
79
+ @media screen and (max-width: 1025px) {
80
+ .wprss-form-table th {
81
+ display: block;
82
+ padding: 0;
83
+ }
84
+ .wprss-form-table td {
85
+ display: block;
86
+ padding-left: 0;
87
+ padding-right: 0;
88
+ }
89
+
90
+ .wprss-form-table td input[type="text"],
91
+ .wprss-form-table td input[type="url"],
92
+ .wprss-form-table td select {
93
+ display: block;
94
+ width: 100%;
95
+ }
96
+
97
+ .wprss-form-table td span.description {
98
+ display: inline;
99
+ }
100
+
101
+ .wprss-form-table td input[type="checkbox"] + label {
102
+ display: inline !important;
103
+ }
104
+
105
+ .wprss-form-table td input {
106
+ line-height: normal;
107
+ }
108
+ }
109
+
110
+
111
+
112
+ body.post-type-wprss_feed_item .add-new-h2,
113
+ body.post-type-wprss_feed_item .tablenav select[name="m"],
114
+ body.post-type-wprss_feed_item #post-query-submit
115
+ { display: none; }
116
+
117
+ body.post-type-wprss_feed_item a.row-title {
118
+ cursor: default;
119
+ font-weight: normal;
120
+ color: #555;
121
+ }
122
+
123
+ #latest-news-cpac-settings li {
124
+ list-style: none;
125
+ line-height: 16px;
126
+ }
127
+
128
+ li.twitter a {
129
+ background: transparent url('../images/twitter.png') no-repeat 0;
130
+ padding-left: 20px;
131
+ }
132
+
133
+ li.facebook a {
134
+ background: transparent url('../images/facebook.png') no-repeat 0;
135
+ padding-left: 20px;
136
+ }
137
+
138
+ li.donate_link a:hover {
139
+ color: darkGreen;
140
+ }
141
+
142
+ #preview_meta_box ul {
143
+ list-style: disc;
144
+ margin-left: 16px;
145
+ }
146
+
147
+ #preview_meta_box .invalid-feed-url {
148
+ color: red;
149
+ }
150
+
151
+ #preview_meta_box .rss-date {
152
+ color: #666;
153
+
154
+ }
155
+
156
+ /*.rss-aggregator_page_wprss-aggregator-settings .form-table th { width: 80px; }*/
157
+
158
+
159
+ /* For excerpts and thumbnails admin screens
160
+ .wprss_feed_page_wprss-aggregator-settings input,
161
+ .wprss_feed_page_wprss-aggregator-settings input[type="checkbox"],
162
+ .wprss_feed_page_wprss-aggregator-settings input[type="radio"] {
163
+ margin-right: 8px;
164
+ }
165
+ */
166
+
167
+ input#default-thumbnail,
168
+ input#wprss-et-license-key,
169
+ input#wprss-c-license-key,
170
+ input#wprss-kf-license-key,
171
+ input#wprss-ftp-license-key {
172
+ width: 300px;
173
+ }
174
+
175
+ input#thumbnails-height,
176
+ input#thumbnails-width {
177
+ /*width: 29px;*/
178
+ }
179
+
180
+
181
+ /* Red Button */
182
+
183
+ .wp-core-ui .button-red {
184
+ background: #BD2B2B;
185
+ border-color: transparent;
186
+ color: #fff;
187
+ text-decoration: none;
188
+ text-shadow: none;
189
+ }
190
+
191
+ .wp-core-ui .button-red.hover,
192
+ .wp-core-ui .button-red:hover {
193
+ color: #fff;
194
+ border-color: transparent;
195
+ background-color: #AC0F0F;
196
+ }
197
+
198
+ .wp-core-ui .button-red.focus,
199
+ .wp-core-ui .button-red:focus {
200
+ color: #fff;
201
+ background-color: #AC0F0F;
202
+ border-color: transparent;
203
+ box-shadow: 0 0 0 1px #fff,0 0 0 3px #AC0F0F;
204
+ }
205
+
206
+ .wp-core-ui .button-red.active,
207
+ .wp-core-ui .button-red:active {
208
+ color: #fff;
209
+ background-color: #A20909;
210
+ border-color: transparent;
211
+ }
212
+
213
+ .wp-core-ui .button-red[disabled],
214
+ .wp-core-ui .button-red:disabled,
215
+ .wp-core-ui .button-red-disabled {
216
+ color: #fba6a8 !important;
217
+ background: #DD383A !important;
218
+ box-shadow: 0 0 0 transparent !important;
219
+ border-color: transparent !important;
220
+ text-shadow: 0 0 0 transparent !important;
221
+ }
222
+
223
+ #wpra-system-info-textarea,
224
+ #wprss-error-log-textarea {
225
+ width: 800px;
226
+ height: 400px;
227
+ font-family: Menlo, Monaco, monospace;
228
+ white-space: pre;
229
+ overflow: auto;
230
+ display: block;
231
+ }
232
+
233
+ #wpra-system-info-textarea {
234
+ display: block;
235
+ width: 100%;
236
+ height: 600px;
237
+ font-family: Menlo, Monaco, monospace;
238
+ white-space: pre;
239
+ overflow: auto;
240
+ }
241
+
242
+ .wprss-error-log-action {
243
+ display: inline-block;
244
+ }
245
+
246
+ #wprss-clear-error-log-form {
247
+ display: inline-block;
248
+ }
249
+ #wprss-clear-error-log-form,
250
+ #wprss-clear-error-log-form > button {
251
+ vertical-align: baseline;
252
+ }
253
+
254
+ form.wprss-error-log-action input[type="submit"]:active {
255
+ vertical-align: baseline;
256
+ }
257
+ /* The debug log root element */
258
+ div.wpra-log {
259
+ display: block;
260
+ position: relative;
261
+ width: 100%;
262
+ }
263
+
264
+ /* The "Filters" label */
265
+ div.wpra-log > p > strong:first-child {
266
+ text-decoration: underline;
267
+ margin-right: 10px;
268
+ }
269
+
270
+ /* The debug log filters separator */
271
+ div.wpra-log .wpra-toggle-logs:not(:last-of-type)::after {
272
+ content: ' | ';
273
+ color: #3c3c3c;
274
+ pointer-events: none;
275
+ }
276
+ /* The debug log filters */
277
+ div.wpra-log .wpra-toggle-logs a {
278
+ text-decoration: none;
279
+ outline: none;
280
+ box-shadow: 0 0 transparent;
281
+ }
282
+ /* The debug log filters when not selected */
283
+ div.wpra-log .wpra-toggle-logs:not(.wpra-selected):not(.wpra-log-filter-disabled) a {
284
+ color: #626262;
285
+ }
286
+ /* The debug log filters when selected */
287
+ div.wpra-log .wpra-toggle-logs.wpra-selected:not(.wpra-log-filter-disabled) a {
288
+ font-weight: bold;
289
+ }
290
+
291
+ /* The debug log "error" filter text color when there are errors */
292
+ div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="error"]:not(.wpra-log-filter-disabled) a {
293
+ color: #d40000;
294
+ }
295
+ /* The debug log "warning" filter text color when there are warnings */
296
+ div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="warning"]:not(.wpra-log-filter-disabled) a {
297
+ color: #d45500;
298
+ }
299
+ /* The debug log "notice" filter text color when there are notices */
300
+ div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="notice"]:not(.wpra-log-filter-disabled) a {
301
+ color: #d48a00;
302
+ }
303
+ /* The debug log "info" filter text color when there are info logs */
304
+ div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="info"]:not(.wpra-log-filter-disabled) a {
305
+ color: #009cd6;
306
+ }
307
+ /* The debug log "debug" filter text color when there are debug logs */
308
+ div.wpra-log .wpra-toggle-logs.wpra-selected[data-level="debug"]:not(.wpra-log-filter-disabled) a {
309
+ color: #8242d4;
310
+ }
311
+
312
+ /* Disabled debug log filters */
313
+ div.wpra-log .wpra-toggle-logs.wpra-log-filter-disabled a {
314
+ color: #8b8b8b !important;
315
+ font-style: italic;
316
+ text-decoration: none;
317
+ cursor: not-allowed;
318
+ }
319
+
320
+ /* The debug log */
321
+ div.wpra-log-container {
322
+ width: 100%;
323
+ max-height: 600px;
324
+ border: 1px solid #d1d1d1;
325
+ padding: 5px;
326
+ margin-bottom: 15px;
327
+ overflow: auto;
328
+ background: #222833;
329
+ }
330
+
331
+ /* The debug log & empty log notice */
332
+ div.wpra-log-container,
333
+ .notice.wpra-empty-log-notice {
334
+ display: block;
335
+ box-sizing: border-box;
336
+ }
337
+ .notice.wpra-empty-log-notice {
338
+ width: 400px;
339
+ }
340
+
341
+ /* The log table */
342
+ div.wpra-log-container > table {
343
+ font-family: monospace;
344
+ min-width: 100%;
345
+ border: 0;
346
+ border-collapse: collapse;
347
+ }
348
+ /* Log table: row formatting */
349
+ div.wpra-log-container > table > tbody > tr {
350
+ }
351
+ /* Log table: cell formatting */
352
+ div.wpra-log-container > table > tbody > tr > td {
353
+ color: #cbcdda;
354
+ vertical-align: baseline;
355
+ padding: 4px 10px;
356
+ border-bottom: 2px solid #222833;
357
+ }
358
+
359
+ /* Log table: row on hover */
360
+ div.wpra-log-container > table > tbody > tr:hover {
361
+ background: rgba(200, 200, 200, 0.1);
362
+ }
363
+
364
+ /* Log table: date and level cells do not wrap */
365
+ div.wpra-log-container > table > tbody > tr > td.wpra-log-date,
366
+ div.wpra-log-container > table > tbody > tr > td.wpra-log-level {
367
+ white-space: nowrap;
368
+ overflow: hidden;
369
+ }
370
+ div.wpra-log-container > table > tbody > tr > td.wpra-log-date {
371
+ width: 150px;
372
+ }
373
+ div.wpra-log-container > table > tbody > tr > td.wpra-log-level {
374
+ text-align: center;
375
+ width: 60px;
376
+ }
377
+ div.wpra-log-container > table > tbody > tr > td.wpra-log-feed {
378
+ width: 150px;
379
+ }
380
+
381
+ /* Log table: styling for DEBUG log messages */
382
+ div.wpra-log-container > table > tbody > tr.wpra-log-debug > td:not(.wpra-log-date) {
383
+ color: #b695e6;
384
+ }
385
+ /* Log table: styling for INFO log messages */
386
+ div.wpra-log-container > table > tbody > tr.wpra-log-info > td:not(.wpra-log-date) {
387
+ color: #38eaff;
388
+ }
389
+ /* Log table: styling for NOTICE log messages */
390
+ div.wpra-log-container > table > tbody > tr.wpra-log-notice > td:not(.wpra-log-date) {
391
+ color: #ffea00;
392
+ }
393
+ /* Log table: styling for WARNING log messages */
394
+ div.wpra-log-container > table > tbody > tr.wpra-log-warning > td {
395
+ color: #000;
396
+ background-color: #ffea00;
397
+ font-weight: bold;
398
+ }
399
+ /* Log table: styling for ERROR log messages */
400
+ div.wpra-log-container > table > tbody > tr.wpra-log-error > td {
401
+ color: white;
402
+ background-color: #b90000;
403
+ font-weight: bold;
404
+ }
405
+
406
+ @media screen and (min-width: 782px) {
407
+ #custom_feed_title {
408
+ width: 400px;
409
+ }
410
+ }
411
+
412
+ /* Number Roller for Feed Source Limit */
413
+ .wprss-number-roller {
414
+ width: 80px;
415
+ vertical-align: middle;
416
+ }
417
+ @media screen and (max-width: 782px) {
418
+ .wprss-number-roller {
419
+ width: 100px;
420
+ }
421
+ }
422
+
423
+ /* Welcome Screen */
424
+ .about-wrap ul {
425
+ list-style: disc;
426
+ padding-left: 30px;
427
+ }
428
+
429
+ /* Excerpts and Thumbnails */
430
+
431
+ input#thumbnails-height,
432
+ input#thumbnails-width {
433
+ margin-right: 2px;
434
+ }
435
+
436
+ label[for=thumbnails-height],
437
+ label[for=thumbnails-width] {
438
+ margin-left: 8px;
439
+ }
440
+
441
+ .wp-list-table > thead > tr > th#thumbnail[scope="col"] {
442
+ width: 95px;
443
+ }
444
+
445
+ select + label.description {
446
+ margin-left: 8px;
447
+ }
448
+
449
+ input#title-limit {
450
+ width: 100px;
451
+ }
452
+
453
+ .wprss-form-table th,
454
+ .wprss-form-table tr,
455
+ .wprss-form-table td {
456
+ border: 0 transparent !important;
457
+ }
458
+
459
+ .wprss-indicator-green,
460
+ .wprss-indicator-red,
461
+ .wprss-indicator-grey {
462
+ font-size: 1.6em;
463
+ vertical-align: middle;
464
+ margin-right: 10px;
465
+ line-height: 30px;
466
+ }
467
+ .wprss-indicator-green {
468
+ color: #009922;
469
+ }
470
+ .wprss-indicator-grey {
471
+ color: #888;
472
+ }
473
+ .wprss-indicator-red {
474
+ color: #EB442A;
475
+ }
476
+
477
+
478
+ .wprss-meta-slider {
479
+ display: none;
480
+ margin-top: 5px;
481
+ }
482
+
483
+ .wprss-slider-button {
484
+ cursor: pointer;
485
+ margin-right: 8px !important;
486
+ }
487
+
488
+ #wprss_activate_feed,
489
+ #wprss_pause_feed {
490
+ display: block;
491
+ }
492
+
493
+ .wprss-date-error {
494
+ background: rgba( 245, 45, 45, 0.6 );
495
+ }
496
+
497
+ div.wprss-meta-side-setting {
498
+ display: block;
499
+ padding: 8px;
500
+ border-bottom: 1px solid rgba(0,0,0,0.1);
501
+ }
502
+
503
+ div.wprss-meta-side-setting > p {
504
+ margin: 2px 0;
505
+ }
506
+ div.wprss-meta-side-setting > p > label {
507
+ vertical-align: baseline;
508
+ }
509
+ div.wprss-meta-side-setting a.wprss-slider-button {
510
+ vertical-align: middle;
511
+ }
512
+
513
+ div.inside .wprss-meta-side-setting:last-child {
514
+ border-bottom: 0 solid transparent;
515
+ }
516
+
517
+ input[type="checkbox"]#wprss-force-feed {
518
+ margin-left: 10px;
519
+ }
520
+
521
+ /******************************
522
+ * FEED SOURCES PAGE COLUMNS
523
+ */
524
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th {
525
+ text-align: left;
526
+ overflow: hidden;
527
+ }
528
+ /* CHECKBOX */
529
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead td#cb {
530
+ width: 30px !important;
531
+ }
532
+ /* STATE */
533
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state {
534
+ width: 70px !important;
535
+ }
536
+ /* NAME */
537
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#title {
538
+ width: auto;
539
+ }
540
+ /* NEXT UPDATE */
541
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#updates {
542
+ width: 300px !important;
543
+ }
544
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts td.column-updates p {
545
+ margin-bottom: 0 !important;
546
+ }
547
+ /* FEED COUNT */
548
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#feed-count {
549
+ width: 200px !important;
550
+ }
551
+ /* CATEGORIES */
552
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#category,
553
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#category {
554
+ width: 130px !important;
555
+ }
556
+
557
+ /* FEED ITEM IMAGE */
558
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#image {
559
+ width: 120px;
560
+ }
561
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody img.wpra-item-ft-image {
562
+ width: 100px;
563
+ }
564
+
565
+ @media screen and (max-width: 660px) {
566
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#id,
567
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-id,
568
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-id,
569
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state,
570
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-state,
571
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-state {
572
+ display: none;
573
+ }
574
+ }
575
+ @media only screen and (max-width: 782px) {
576
+ /* WIDEN CHECKBOX COLUMN */
577
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead td#cb {
578
+ width: 50px !important;
579
+ }
580
+
581
+ /* HIDE STATE COLUMN */
582
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts thead th#state,
583
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tfoot th.column-state,
584
+ body.post-type-wprss_feed.edit-php table.wp-list-table.posts tbody td.column-state {
585
+ display: none;
586
+ padding: 8px 10px;
587
+ }
588
+
589
+ /* HIDE ITEM IMAGE COLUMN */
590
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#image,
591
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tfoot th.column-image,
592
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-image {
593
+ display: none;
594
+ }
595
+
596
+ /* IMAGE IS LARGER IN RESPONSIVE MOBILE VIEW */
597
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody img.wpra-item-ft-image {
598
+ width: 350px;
599
+ }
600
+
601
+ /* HIDE INLINE IMAGE COLUMN NAME IN RESPONSIVE MOBILE VIEW */
602
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-image::before {
603
+ display: none;
604
+ }
605
+ }
606
+
607
+ @media only screen and (max-width: 1200px) {
608
+ /* HIDE ITEM PERMALINK COLUMN */
609
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#permalink,
610
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tfoot th.column-permalink,
611
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts tbody td.column-permalink {
612
+ display: none;
613
+ }
614
+ }
615
+
616
+ /* For feed items */
617
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#publishdate {
618
+ width: 150px;
619
+ }
620
+ body.post-type-wprss_feed_item.edit-php table.wp-list-table.posts thead th#source {
621
+ width: 200px;
622
+ }
623
+
624
+
625
+
626
+ i.wprss-feed-error-symbol {
627
+ display: none;
628
+ font-size: 1.2em;
629
+ vertical-align: middle;
630
+ color: rgb(200,0,0);
631
+ margin-left: 8px;
632
+ }
633
+
634
+ i.wprss-updating-feed-icon {
635
+ margin-left: 8px;
636
+ display: none;
637
+ }
638
+
639
+ i.wprss-feed-error-symbol.wprss-show,
640
+ i.wprss-updating-feed-icon.wprss-show {
641
+ display: inline-block;
642
+ }
643
+
644
+ /* Log textarea styles */
645
+ #wprss-log-textarea {
646
+ width: 800px;
647
+ height: 400px;
648
+ font-family: Menlo, Monaco, monospace;
649
+ background: none;
650
+ white-space: pre-wrap;
651
+ overflow: auto;
652
+ display: block;
653
+ background: rgb( 255, 245, 245 );
654
+ }
655
+
656
+
657
+
658
+ /*--------------------------------------------------------------------------
659
+ *
660
+ * Add-Ons
661
+ *
662
+ *-------------------------------------------------------------------------*/
663
+
664
+ #add-ons {
665
+ margin-bottom: 20px;
666
+ }
667
+
668
+ #add-ons .add-on-group {
669
+ margin-top: 20px;
670
+ padding-top: 20px;
671
+ border-top: #F5F5F5 solid 1px;
672
+ }
673
+
674
+ #add-ons .add-on-group:first-child {
675
+ margin-top: 0;
676
+ padding-top: 0;
677
+ border-top: 0 none;
678
+ }
679
+
680
+ #add-ons .add-on {
681
+ float: left;
682
+ width: 220px;
683
+ margin: 10px 20px 10px 0;
684
+ background: #FFFFFF;
685
+ border: 1px solid #E5E5E5;
686
+ position: relative;
687
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
688
+ min-height: 320px;
689
+ }
690
+
691
+ #add-ons .add-on h3 {
692
+ margin-top: 0.5em;
693
+ }
694
+
695
+ #add-ons .add-on h3 a {
696
+ color: inherit;
697
+ text-decoration: none;
698
+ }
699
+
700
+ #add-ons .add-on .inner {
701
+ min-height: 170px;
702
+ padding: 15px;
703
+ }
704
+
705
+ #add-ons .add-on .footer {
706
+ background: #F5F5F5;
707
+ border-top: 1px solid #E1E1E1;
708
+ overflow: hidden;
709
+ position: absolute;
710
+ width: 100%;
711
+ bottom: 0;
712
+ padding-top: 15px;
713
+ height: 45px;
714
+ }
715
+
716
+ #add-ons .add-on .footer .button {
717
+ float: left;
718
+ margin-left: 15px;
719
+ }
720
+
721
+ #add-ons .add-on-active .button-disabled:focus,
722
+ #add-ons .add-on-active .button-disabled:active {
723
+ background: #fafafa;
724
+ }
725
+
726
+ #add-ons .add-on-title {
727
+ float: left;
728
+ width: 100%;
729
+ margin: 25px 0 25px;
730
+ border-top: #F5F5F5 solid 1px;
731
+ }
732
+
733
+
734
+ /*== BLACKLIST */
735
+ body.post-type-wprss_blacklist .add-new-h2,
736
+ body.post-type-wprss_blacklist ul.subsubsub,
737
+ body.post-type-wprss_blacklist .alignleft.actions {
738
+ display: none;
739
+ }
740
+
741
+ body.post-type-wprss_blacklist .alignleft.actions.bulkactions {
742
+ display: inline-block;
743
+ }
744
+
745
+ .wprss-header-small {
746
+ color: #777;
747
+ font-size: 0.7em;
748
+ }
749
+
750
+ /* Inline Help ============================================================== */
751
+
752
+ .wprss-tooltip-handle,
753
+ .wprss-tooltip-handle:hover,
754
+ .wprss-tooltip-handle:focus {
755
+ text-decoration: none;
756
+ color: #aaaaaa;
757
+ outline: none;
758
+ }
759
+
760
+ .wprss-tooltip-handle {
761
+ margin-left: 5px;
762
+ font-size: 15px;
763
+ color: rgb(190, 190, 190);
764
+ vertical-align: middle;
765
+ }
766
+
767
+ .wprss-tooltip-handle-side {
768
+ float: right;
769
+ }
770
+
771
+ .wprss-tooltip-content {
772
+ display: none;
773
+ }
774
+
775
+ .wprss-ui-tooltip {
776
+ color: #444 !important;
777
+ padding: 8px 10px !important;
778
+ background: #fefefe !important;
779
+ border: 1px solid #ccc !important;
780
+ border-radius: 1px !important;
781
+ font-family: "Open Sans", sans-serif !important;
782
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.17) !important;
783
+ }
784
+ .wprss-ui-tooltip p:first-child {
785
+ margin-top: 0;
786
+ }
787
+ .wprss-ui-tooltip p:last-child {
788
+ margin-bottom: 0;
789
+ }
790
+ .wprss-ui-tooltip p {
791
+ margin: 8px 0;
792
+ }
793
+ .wprss-ui-tooltip p, code {
794
+ font-size: 0.9em !important;
795
+ }
796
+ .wprss-ui-tooltip hr {
797
+ margin: 0;
798
+ }
799
+
800
+ .wprss-section-tooltip-handle,
801
+ .wprss-section-tooltip-handle:hover,
802
+ .wprss-section-tooltip-handle:active,
803
+ .wprss-section-tooltip-handle:visited,
804
+ .wprss-section-tooltip-handle:link,
805
+ .wprss-section-tooltip-handle:focus {
806
+ color: #006799;
807
+ margin-left: 5px;
808
+ text-decoration: none;
809
+ outline: none;
810
+ cursor: help;
811
+ font-size: 15px;
812
+ }
813
+
814
+ /* For non settings page screens */
815
+ @media only screen and (max-width: 850px) {
816
+
817
+ body:not(.wprss_feed_page_wprss-aggregator-settings)
818
+ .wprss-tooltip-handle {
819
+ color: #999;
820
+ font-size: 1em;
821
+ padding: 6px 10px;
822
+ margin-left: 0;
823
+ background: #e5e5e5;
824
+ border-radius: 3px;
825
+ vertical-align: middle;
826
+ }
827
+
828
+ body:not(.wprss_feed_page_wprss-aggregator-settings)
829
+ select + .wprss-tooltip-handle,
830
+ body:not(.wprss_feed_page_wprss-aggregator-settings)
831
+ input[type="input"] + .wprss-tooltip-handle,
832
+ body:not(.wprss_feed_page_wprss-aggregator-settings)
833
+ input[type="password"] + .wprss-tooltip-handle {
834
+ margin-top: 5px;
835
+ }
836
+
837
+ body:not(.wprss_feed_page_wprss-aggregator-settings)
838
+ .wprss-tooltip-handle:after {
839
+ content: 'Help';
840
+ margin-left: 5px;
841
+ font-family: 'Open Sans', sans-serif;
842
+ }
843
+
844
+ }
845
+
846
+
847
+ /* For settings page screens */
848
+ @media only screen and (max-width: 782px) {
849
+
850
+ body.wprss_feed_page_wprss-aggregator-settings
851
+ .wprss-tooltip-handle {
852
+ color: #999;
853
+ font-size: 1em;
854
+ padding: 6px 10px;
855
+ margin-left: 0;
856
+ background: #e5e5e5;
857
+ border-radius: 3px;
858
+ vertical-align: middle;
859
+ }
860
+
861
+ body.wprss_feed_page_wprss-aggregator-settings
862
+ select + .wprss-tooltip-handle,
863
+ body.wprss_feed_page_wprss-aggregator-settings
864
+ input[type="input"] + .wprss-tooltip-handle,
865
+ body.wprss_feed_page_wprss-aggregator-settings
866
+ input[type="password"] + .wprss-tooltip-handle {
867
+ margin-top: 5px;
868
+ }
869
+
870
+ body.wprss_feed_page_wprss-aggregator-settings
871
+ .wprss-tooltip-handle:after {
872
+ content: 'Help';
873
+ margin-left: 5px;
874
+ font-family: 'Open Sans', sans-serif;
875
+ }
876
+
877
+ }
878
+
879
+
880
+ @media only screen and (max-width: 1026px) {
881
+ .wprss-tr-hr th {
882
+ padding-top: 10px;
883
+ }
884
+ }
885
+
886
+ .ajax-error,
887
+ .ajax-error:hover,
888
+ .ajax-error:visited,
889
+ .ajax-error:link,
890
+ .ajax-error:active {
891
+ color: #a00;
892
+ }
893
+
894
+ /* Removes the "Add New" button for Feed Items */
895
+ .post-type-wprss_feed_item .page-title-action {
896
+ display: none
897
+ }
898
+
899
+ /* Changelog styles */
900
+ .wpra-changelog-container h2 {
901
+ font-size: 1.4em;
902
+ }
903
+ .wpra-changelog-container h3 {
904
+ font-weight: normal;
905
+ font-size: 1.2em;
906
+ }
907
+ .wpra-changelog-container ul {
908
+ list-style: disc;
909
+ list-style-position: inside;
910
+ }
911
+
912
+ .wpra_ft_image_option {
913
+ margin-top: 10px;
914
+ }
915
+
916
+ #wpra_image_min_size_row {
917
+ display: none;
918
+ }
919
+
920
+ /* Spacing between image width and height fields */
921
+ #wpra_image_min_size_row > td > label {
922
+ margin-right: 10px;
923
+ }
924
+
925
+ #wprss-feed-def-ft-image-preview {
926
+ width: 220px;
927
+ }
928
+
929
+ #wprss-feed-def-ft-image-preview-hint {
930
+ margin-bottom: 8px;
931
+ }
932
+
933
+
934
+ /*
935
+ * The Feed Source List Table styles that mimic the plugins table
936
+ */
937
+
938
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr th,
939
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr td
940
+ {
941
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .1);
942
+ }
943
+
944
+ /* Feed updating/deleting animation in feed sources table */
945
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating,
946
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting {
947
+ /*background-image: linear-gradient(-45deg, rgba(30, 30, 30, 0.05) 25%, transparent 0, transparent 50%, rgba(50, 50, 50, 0.05) 50%, rgba(30, 30, 30, 0.05) 75%, transparent 0, #0000);*/
948
+ /*background-image: linear-gradient(*/
949
+ /* -45deg, rgba(0, 0, 0, 0.9) 25%,*/
950
+ /* transparent 0,*/
951
+ /* transparent 50%,*/
952
+ /* rgba(0, 0, 0, 0.9) 50%,*/
953
+ /* rgba(0, 0, 0, 0.9) 75%,*/
954
+ /* transparent 0, #0000*/
955
+ /*);*/
956
+ background-size: 80px 80px;
957
+ background-blend-mode: overlay;
958
+ }
959
+
960
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating > *,
961
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting > * {
962
+ background: transparent !important;
963
+ }
964
+
965
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-updating {
966
+ animation: wpra-feed-updating-animation 1.3s linear infinite;
967
+ background-color: #e9f9ee;
968
+ }
969
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr.wpra-feed-is-deleting {
970
+ animation: wpra-feed-updating-animation 1s linear infinite;
971
+ background-color: #f8eaea;
972
+ }
973
+
974
+ @keyframes wpra-feed-updating-animation {
975
+ 0% {
976
+ background-position: 0 0;
977
+ }
978
+ 50% {
979
+ background-position: 80px 80px;
980
+ }
981
+ 100% {
982
+ background-position: 160px 160px;
983
+ }
984
+ }
985
+
986
+ /*
987
+ * Styles for the Feed Source List Table "State" column
988
+ */
989
+ div.wprss-feed-state-container,
990
+ div.wprss-feed-source-type
991
+ {
992
+ display: inline-block;
993
+ }
994
+
995
+ /* the feed type icon */
996
+ div.wprss-feed-source-type {
997
+ float: right;
998
+ }
999
+ /* inactive color */
1000
+ .post-type-wprss_feed table.wp-list-table tr div.wprss-feed-source-type {
1001
+ color: #aaa;
1002
+ }
1003
+ /* active color */
1004
+ .post-type-wprss_feed table.wp-list-table tr.active div.wprss-feed-source-type {
1005
+ color: #ff792b;
1006
+ }
1007
+ /* youtube color */
1008
+ .post-type-wprss_feed table.wp-list-table tr.active div.wprss-feed-source-type.wprss-feed-source-type-yt {
1009
+ color: #ff0000;
1010
+ }
1011
+
1012
+ .post-type-wprss_feed table.wp-list-table tbody td.column-state {
1013
+ padding-right: 0;
1014
+ }
1015
+
1016
+ .column-updates > p {
1017
+ margin: 0 !important;
1018
+ }
1019
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr .next-update-container {
1020
+ font-weight: bold;
1021
+ }
1022
+ .post-type-wprss_feed table.wp-list-table.posts tbody tr:not(.active) .next-update-container {
1023
+ display: none;
1024
+ }
1025
+
1026
+ /* The last update time in the feed sources page table */
1027
+ .post-type-wprss_feed table.wp-list-table.posts .last-update-num-items-container {
1028
+ color: #666;
1029
+ font-style: italic;
1030
+ font-size: 90%;
1031
+ }
1032
+
1033
+ /* The imported items link in the feed sources page - disabled when 0 items */
1034
+ .post-type-wprss_feed table.wp-list-table.posts .items-imported-link.has-imported-items {
1035
+ font-weight: bold;
1036
+ line-height: 20px;
1037
+ }
1038
+ .post-type-wprss_feed table.wp-list-table.posts .items-imported-link:not(.has-imported-items) {
1039
+ color: #777;
1040
+ pointer-events: none;
1041
+ }
1042
+
1043
+ /* The delete items row action in the feed sources page - hidden when 0 items */
1044
+ .post-type-wprss_feed table.wp-list-table.posts .row-actions .purge-posts:not(.has-imported-items) {
1045
+ display: none;
1046
+ }
1047
+
1048
+ /* Styles for the disabled "Fetch" and "Delete" feed source row actions */
1049
+ .post-type-wprss_feed table.wp-list-table.posts .row-actions a.wprss_fetch_items_ajax_action[disabled] {
1050
+ color: #555;
1051
+ }
1052
+ .post-type-wprss_feed table.wp-list-table.posts .row-actions a.wprss_delete_items_ajax_action[disabled] {
1053
+ color: #666;
1054
+ }
1055
+
1056
+ /* The feed updating/deleting spinner icon */
1057
+ .post-type-wprss_feed table.wp-list-table.posts .column-feed-count .spinner {
1058
+ float: none;
1059
+ vertical-align: bottom;
1060
+ }
1061
+ .post-type-wprss_feed table.wp-list-table.posts tr.wpra-feed-is-updating .column-feed-count .spinner,
1062
+ .post-type-wprss_feed table.wp-list-table.posts tr.wpra-feed-is-deleting .column-feed-count .spinner {
1063
+ visibility: visible;
1064
+ }
1065
+
1066
+ /*
1067
+ * TOGGLE SWITCH
1068
+ */
1069
+ .wprss-switch {
1070
+ position: relative;
1071
+ display: inline-block;
1072
+ width: 34px;
1073
+ height: 18px;
1074
+ }
1075
+ .wprss-switch input {
1076
+ opacity: 0;
1077
+ width: 0;
1078
+ height: 0;
1079
+ }
1080
+ .wprss-switch-slider {
1081
+ position: absolute;
1082
+ cursor: pointer;
1083
+ top: 0;
1084
+ left: 0;
1085
+ right: 0;
1086
+ bottom: 0;
1087
+ border-radius: 34px;
1088
+ background-color: #ccc;
1089
+ transition: .2s;
1090
+ -webkit-transition: .2s;
1091
+ }
1092
+ .wprss-switch-slider:before {
1093
+ position: absolute;
1094
+ content: "";
1095
+ width: 12px;
1096
+ height: 12px;
1097
+ left: 4px;
1098
+ bottom: 3px;
1099
+ border-radius: 50%;
1100
+ background-color: white;
1101
+ transition: .2s;
1102
+ -webkit-transition: .2s;
1103
+ }
1104
+ input:checked + .wprss-switch-slider {
1105
+ background-color: #0baa3c;
1106
+ }
1107
+ input:focus + .wprss-switch-slider {
1108
+ box-shadow: 0 0 1px #2196F3;
1109
+ }
1110
+ input:checked + .wprss-switch-slider:before {
1111
+ -webkit-transform: translateX(14px);
1112
+ -ms-transform: translateX(14px);
1113
+ transform: translateX(14px);
1114
+ }
1115
+
1116
+ .postbox .inside .wpra-feed-save-meta-box {
1117
+ border-bottom: 1px solid #ccc;
1118
+ padding: 10px;
1119
+ margin: 0 -10px;
1120
+ margin-top: -11px;
1121
+ margin-bottom: 10px;
1122
+ background: #fff;
1123
+ }
1124
+
1125
+ .postbox .inside .wpra-feed-save-meta-box label span {
1126
+ font-weight: bold;
1127
+ font-size: 14px;
1128
+ }
1129
+
1130
+ .postbox .inside .wpra-feed-save-meta-box input[type="text"] {
1131
+ text-align: left !important;
1132
+ }
1133
+
1134
+ /* -- INLINE STYLES -- */
1135
+
1136
+ form.wpra-inline-form {
1137
+ display: inline-block;
1138
+ }
1139
+
1140
+ form.wpra-header-form {
1141
+ display: inline-block;
1142
+ margin: 0;
1143
+ padding: 0;
1144
+ border: 0;
1145
+ }
1146
+
1147
+ h1.wpra-inline-header,
1148
+ h2.wpra-inline-header,
1149
+ h3.wpra-inline-header,
1150
+ h4.wpra-inline-header
1151
+ {
1152
+ display: inline-block;
1153
+ margin-right: 5px;
1154
+ }
1155
+
1156
+ button.button.wpra-header-button {
1157
+ position: relative;
1158
+ vertical-align: baseline;
1159
+ top: -1px;
1160
+ }
1161
+
1162
+ /* -- SLIDE BOX -- */
1163
+
1164
+ div.wpra-slide-box {
1165
+ display: none;
1166
+ margin: 10px 0;
1167
+ padding: 15px;
1168
+ background: #fff;
1169
+ border: 1px solid #ccc;
1170
+ border-radius: 2px;
1171
+ }
1172
+
1173
+ div.wpra-slide-box.wpra-slide-box-open {
1174
+ display: block;
1175
+ }
1176
+
1177
+ div.wpra-slide-box form {
1178
+ display: block;
1179
+ }
1180
+
1181
+ div.wpra-slide-box h4 {
1182
+ font-size: 16px;
1183
+ margin: 0;
1184
+ margin-bottom: 15px;
1185
+ padding-bottom: 5px;
1186
+ border-bottom: 1px solid #ddd;
1187
+ }
1188
+
1189
+ div.wpra-slide-box form label {
1190
+ display: flex;
1191
+ flex-direction: row;
1192
+ align-items: center;
1193
+ line-height: 1;
1194
+ font-size: 1em;
1195
+ margin: 5px 0;
1196
+ }
1197
+
1198
+ div.wpra-slide-box label > * {
1199
+ flex-grow: 1;
1200
+ }
1201
+
1202
+ div.wpra-slide-box label > span {
1203
+ display: inline-block;
1204
+ flex-grow: 0;
1205
+ width: 200px;
1206
+ font-size: 1em;
1207
+ }
1208
+ div.wpra-slide-box label input[type="text"],
1209
+ div.wpra-slide-box label input[type="number"],
1210
+ div.wpra-slide-box label input[type="text"]
1211
+ {
1212
+ height: 28px;
1213
+ min-height: 28px;
1214
+ }
1215
+
1216
+ div.wpra-slide-box div.wpra-submit-wrap {
1217
+ margin-top: 10px;
1218
+ }
1219
+ div.wpra-slide-box div.wpra-submit-wrap.right {
1220
+ text-align: right;
1221
+ }
1222
+
1223
+ div.wpra-slide-box div.wpra-submit-wrap > button {
1224
+ text-align: center;
1225
+ }
1226
+
1227
+ /* -- ERROR LOG OPTIONS (SLIDE BOX) -- */
1228
+
1229
+ #wprss-log-options-form input[name="logging_limit_days"] {
1230
+ width: 80px;
1231
+ }
1232
+
1233
+ /* -- BLACKLIST TOOL -- */
1234
+
1235
+ #wpra-add-blacklist-container form label span:first-child {
1236
+ width: 120px;
1237
+ }
1238
+
1239
+ /* -- LOG TOOL -- */
1240
+
1241
+ #wprss-error-log-options {
1242
+ margin: 15px 0;
1243
+ }
1244
+
1245
+ #wprss-clear-error-log-form {
1246
+ float: right;
1247
+ position: relative;
1248
+ top: -3px;
1249
+ }
1250
+
1251
+ .wpra-log-filters {
1252
+ padding: 2px 0;
1253
+ margin: 0;
1254
+ }
1255
+ p.wpra-logs-shown-msg {
1256
+ margin: 5px 0;
1257
+ }
1258
+
1259
+ /* -- MISC -- */
1260
+ .wpra-no-margin {
1261
+ margin: 0;
1262
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/admin-tracking-styles.css CHANGED
File without changes
css/build/pagination.min.css CHANGED
@@ -1 +1 @@
1
- .wpra-loading{animation:pulse 1s infinite ease-in-out;pointer-events:none}.nav-links a{cursor:pointer}@keyframes pulse{0%{opacity:.25}50%{opacity:.6}to{opacity:.25}}
1
+ .wpra-loading{animation:pulse 1s infinite ease-in-out;pointer-events:none}@keyframes pulse{0%{opacity:.25}50%{opacity:.6}to{opacity:.25}}
css/build/templates.min.css CHANGED
@@ -1 +1 @@
1
- .mobile-collapsed{display:inherit}.mobile-only{display:none!important}@media (max-width:782px){.mobile-only{display:inherit!important}.mobile-collapsed{display:none!important}}.wpra-bottom-panel{position:sticky;bottom:0;z-index:9;background-color:#fffce9;padding:1rem;border:1px solid #e5e5e5;box-shadow:0 1px 1px rgba(0,0,0,.04)}.wpra-bottom-panel__title{font-size:1rem;font-weight:500;padding-bottom:8px}a.disabled{color:#9c9c9c;pointer-events:none}[v-cloak] .vcloak--visible{display:block}[v-cloak] .vcloak--hidden{display:none}.vcloak--visible{min-height:60px;display:none}.loading-container{min-height:5rem;position:relative}.loading-container:before{display:block;content:"";position:absolute;left:calc(50% - 20px);top:calc(50% - 20px);box-sizing:border-box;height:40px;width:40px;border:0 solid #d0d0d0;border-radius:50%;box-shadow:inset 0 -12px 0 16px #d0d0d0;animation:rotate 1s infinite linear;z-index:3}.loading-container:after{display:block;content:"";position:absolute;z-index:2;background-color:hsla(0,0%,95%,.5);width:100%;height:100%;left:0;top:0}.loading-container--white:after{background-color:#fff}.loading-button{pointer-events:none;position:relative}.loading-button:before{display:block;content:"";position:absolute;left:calc(50% - 8px);top:calc(50% - 8px);box-sizing:border-box;height:16px;width:16px;border:0 solid #aaa;border-radius:50%;box-shadow:inset 0 -4px 0 6px #aaa;animation:rotate 1s infinite linear;z-index:3}.loading-button:after{display:block;content:"";position:absolute;z-index:2;background-color:inherit;width:100%;height:100%;left:0;top:0}.button-default.loading-button:before{box-shadow:inset 0 -4px 0 6px #6f6f6f}.loading-inline{display:inline-block;pointer-events:none;position:relative}.loading-inline:before{display:block;content:"";position:absolute;left:calc(50% + 1px);top:calc(50% - 11px);box-sizing:border-box;height:14px;width:14px;border:0 solid #d0d0d0;border-radius:50%;box-shadow:inset 0 -3px 0 5px #d0d0d0;animation:rotate 1s infinite linear;z-index:3}.loading-inline:after{display:block;content:"";position:absolute;z-index:2;background-color:inherit;width:100%;height:100%;left:0;top:0}@keyframes rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.table-loading{position:relative}.table-loading .table-loader-wrap{position:absolute;width:100%;height:100%;z-index:9}.table-loading .table-loader-wrap .table-loader-center{position:absolute;top:50%;transform:translateY(-50%);width:100%}.table-loading .tablenav,.table-loading .wp-list-table{opacity:.4}.table-loader{font-size:10px;margin:50px auto;text-indent:-9999em;width:11em;height:11em;border-radius:50%;background:#fff;background:-moz-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-webkit-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-o-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-ms-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:linear-gradient(90deg,#fff 10%,hsla(0,0%,100%,0) 42%);position:relative;-webkit-animation:tableLoading 1s infinite linear;animation:tableLoading 1s infinite linear;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.table-loader:before{width:50%;height:50%;background:#fff;border-radius:100% 0 0 0}.table-loader:after,.table-loader:before{position:absolute;top:0;left:0;content:""}.table-loader:after{background:#f4f4f4;width:75%;height:75%;border-radius:50%;margin:auto;bottom:0;right:0}@-webkit-keyframes tableLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes tableLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.toasted-container.top-center{top:44px!important}.toasted{background:#23282d!important;color:#e5e5e5!important;font-size:inherit!important;font-weight:inherit!important;justify-content:start!important;border-left:none!important}.toasted.error .dashicons{color:#ff7781}.toasted .dashicons{margin-right:12px;margin-left:-8px;display:inline-block;opacity:.65}.flex-row{display:flex}.flex-col{box-sizing:border-box;padding:0 10px;flex:1 1 0}.flex-col:first-child{padding-left:0}.flex-col:last-child{padding-right:0}.wpra-postbox .hndle{cursor:unset!important}.wpra-shortcode-copy{font-size:13px;background-color:#fff;margin-left:auto;padding:9px 14px;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);border-left:4px solid #0085ba;display:flex;align-items:center}@media (max-width:782px){.wpra-shortcode-copy{display:block}}.wpra-shortcode-copy__icon{padding-left:16px}@media (max-width:782px){.wpra-shortcode-copy__icon{padding-left:0;margin-top:1rem}}.page-title{display:flex;align-items:center;padding:9px 0 4px}@media (max-width:782px){.page-title{display:block}}.page-title a:focus{text-decoration:none}.page-title h1{margin-left:6px;padding:0}.back-button{opacity:.75;text-decoration:none;font-size:20px;display:flex;align-items:center;padding-right:10px;margin-right:4px;border-right:1px solid #b4b4b4}@media (max-width:782px){.back-button{border-right:none;margin-bottom:.5rem}}.back-button .dashicons{margin-right:8px}.tippy-tooltip.light-theme{font-size:13px!important;font-family:unset!important;text-align:left!important}.tippy-tooltip.light-theme hr{border:none;height:1px;background-color:#efefef}.form-input{display:flex;margin:.75rem 0}.form-input--disabled{pointer-events:none}.form-input--disabled .form-input__label :not(.disable-ignored){opacity:.5;user-select:none}.form-input .disable-ignored{opacity:1}.form-input--vertical{flex-direction:column}.form-input--vertical .form-input__label{padding-right:0;padding-bottom:4px;flex-basis:100%}@media (max-width:782px){.form-input{flex-direction:column}.form-input .form-input__label{padding-right:0;padding-bottom:4px;flex-basis:100%}}.form-input:last-child{margin-bottom:0}.form-input__tip{cursor:pointer;display:inline-block;margin-left:4px;opacity:.25;vertical-align:middle}.form-input__tip:hover{opacity:.85}.form-input__tip .dashicons{font-size:18px}.form-input__label{padding-right:12px;flex-basis:260px}.form-input__label-description{padding-top:2px;padding-right:10px;line-height:1.65;opacity:.6;font-size:12px}.form-input__label-description a{pointer-events:auto!important}.form-input__field{flex-grow:1}.form-input__field input:not([type=checkbox]),.form-input__field select,.form-input__field textarea{width:100%;max-width:325px}.built-in{background:#f1f1f1}.built-in [type=checkbox]{display:none}.wpra-preview-link{vertical-align:middle}.wpra-preview-link span.dashicons{opacity:.75;font-size:16px;vertical-align:middle}.wpra-no-cb .column-cb input[type=checkbox]{display:none}@media (max-width:782px){.column.name small{display:block}}@media (max-width:782px){.inside .wpra-preview-link{float:none}}@media (max-width:782px){.wpra-postbox-container{display:flex;flex-direction:column}.wpra-postbox-container .wpra-postbox-last{order:100}}
1
+ .mobile-collapsed{display:inherit}.mobile-only{display:none!important}@media (max-width:782px){.mobile-only{display:inherit!important}.mobile-collapsed{display:none!important}}.wpra-bottom-panel{position:sticky;bottom:0;z-index:9;background-color:#fffce9;padding:1rem;border:1px solid #e5e5e5;box-shadow:0 1px 1px rgba(0,0,0,.04)}.wpra-bottom-panel__title{font-size:1rem;font-weight:500;padding-bottom:8px}a.disabled{color:#9c9c9c;pointer-events:none}[v-cloak] .vcloak--visible{display:block}[v-cloak] .vcloak--hidden{display:none}.vcloak--visible{min-height:60px;display:none}.loading-container{min-height:5rem;position:relative}.loading-container:before{display:block;content:"";position:absolute;left:calc(50% - 20px);top:calc(50% - 20px);box-sizing:border-box;height:40px;width:40px;border:0 solid #d0d0d0;border-radius:50%;box-shadow:inset 0 -12px 0 16px #d0d0d0;animation:rotate 1s infinite linear;z-index:3}.loading-container:after{display:block;content:"";position:absolute;z-index:2;background-color:hsla(0,0%,95%,.5);width:100%;height:100%;left:0;top:0}.loading-container--white:after{background-color:#fff}.loading-button{pointer-events:none;position:relative}.loading-button:before{display:block;content:"";position:absolute;left:calc(50% - 8px);top:calc(50% - 8px);box-sizing:border-box;height:16px;width:16px;border:0 solid #fff;border-radius:50%;box-shadow:inset 0 -4px 0 6px #fff;animation:rotate 1s infinite linear;z-index:3}.loading-button:after{display:block;content:"";position:absolute;z-index:2;background-color:inherit;width:100%;height:100%;left:0;top:0}.button-default.loading-button:before{box-shadow:inset 0 -4px 0 6px #6f6f6f}.loading-inline{display:inline-block;pointer-events:none;position:relative}.loading-inline:before{display:block;content:"";position:absolute;left:calc(50% + 1px);top:calc(50% - 11px);box-sizing:border-box;height:14px;width:14px;border:0 solid #d0d0d0;border-radius:50%;box-shadow:inset 0 -3px 0 5px #d0d0d0;animation:rotate 1s infinite linear;z-index:3}.loading-inline:after{display:block;content:"";position:absolute;z-index:2;background-color:inherit;width:100%;height:100%;left:0;top:0}@keyframes rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.table-loading{position:relative}.table-loading .table-loader-wrap{position:absolute;width:100%;height:100%;z-index:9}.table-loading .table-loader-wrap .table-loader-center{position:absolute;top:50%;transform:translateY(-50%);width:100%}.table-loading .tablenav,.table-loading .wp-list-table{opacity:.4}.table-loader{font-size:10px;margin:50px auto;text-indent:-9999em;width:11em;height:11em;border-radius:50%;background:#fff;background:-moz-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-webkit-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-o-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:-ms-linear-gradient(left,#fff 10%,hsla(0,0%,100%,0) 42%);background:linear-gradient(90deg,#fff 10%,hsla(0,0%,100%,0) 42%);position:relative;-webkit-animation:tableLoading 1s infinite linear;animation:tableLoading 1s infinite linear;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}.table-loader:before{width:50%;height:50%;background:#fff;border-radius:100% 0 0 0}.table-loader:after,.table-loader:before{position:absolute;top:0;left:0;content:""}.table-loader:after{background:#f4f4f4;width:75%;height:75%;border-radius:50%;margin:auto;bottom:0;right:0}@-webkit-keyframes tableLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes tableLoading{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.toasted-container.top-center{top:44px!important}.toasted{background:#23282d!important;color:#e5e5e5!important;font-size:inherit!important;font-weight:inherit!important;justify-content:start!important;border-left:none!important}.toasted.error .dashicons{color:#ff7781}.toasted .dashicons{margin-right:12px;margin-left:-8px;display:inline-block;opacity:.65}.flex-row{display:flex}.flex-col{box-sizing:border-box;padding:0 10px;flex:1 1 0}.flex-col:first-child{padding-left:0}.flex-col:last-child{padding-right:0}.wpra-postbox .hndle{cursor:unset!important}.wpra-shortcode-copy{font-size:13px;background-color:#fff;margin-left:auto;padding:9px 14px;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);border-left:4px solid #0085ba;display:flex;align-items:center}@media (max-width:782px){.wpra-shortcode-copy{display:block}}.wpra-shortcode-copy__icon{padding-left:16px}@media (max-width:782px){.wpra-shortcode-copy__icon{padding-left:0;margin-top:1rem}}.page-title{display:flex;align-items:center;padding:9px 0 4px}@media (max-width:782px){.page-title{display:block}}.page-title a:focus{text-decoration:none}.page-title h1{margin-left:6px;padding:0}.back-button{opacity:.75;text-decoration:none;font-size:20px;display:flex;align-items:center;padding-right:10px;margin-right:4px;border-right:1px solid #b4b4b4}@media (max-width:782px){.back-button{border-right:none;margin-bottom:.5rem}}.back-button .dashicons{margin-right:8px}.tippy-tooltip.light-theme{font-size:13px!important;font-family:unset!important;text-align:left!important}.tippy-tooltip.light-theme hr{border:none;height:1px;background-color:#efefef}.form-input{display:flex;margin:.75rem 0}.form-input--disabled{pointer-events:none}.form-input--disabled .form-input__label :not(.disable-ignored){opacity:.5;user-select:none}.form-input .disable-ignored{opacity:1}.form-input--vertical{flex-direction:column}.form-input--vertical .form-input__label{padding-right:0;padding-bottom:4px;flex-basis:100%}@media (max-width:782px){.form-input{flex-direction:column}.form-input .form-input__label{padding-right:0;padding-bottom:4px;flex-basis:100%}}.form-input:last-child{margin-bottom:0}.form-input__tip{cursor:pointer;display:inline-block;margin-left:4px;opacity:.25;vertical-align:middle}.form-input__tip:hover{opacity:.85}.form-input__tip .dashicons{font-size:18px}.form-input__label{padding-right:12px;flex-basis:260px}.form-input__label-description{padding-top:2px;padding-right:10px;line-height:1.65;opacity:.6;font-size:12px}.form-input__label-description a{pointer-events:auto!important}.form-input__field{flex-grow:1}.form-input__field input:not([type=checkbox]),.form-input__field select,.form-input__field textarea{width:100%;max-width:325px}.built-in{background:#f1f1f1}.built-in [type=checkbox]{display:none}.wpra-preview-link{vertical-align:middle}.wpra-preview-link span.dashicons{opacity:.75;font-size:16px;vertical-align:middle}.wpra-no-cb .column-cb input[type=checkbox]{display:none}@media (max-width:782px){.column.name small{display:block}}@media (max-width:782px){.inside .wpra-preview-link{float:none}}@media (max-width:782px){.wpra-postbox-container{display:flex;flex-direction:column}.wpra-postbox-container .wpra-postbox-last{order:100}}
css/colorbox.css CHANGED
File without changes
css/font-awesome.min.css CHANGED
File without changes
css/jquery-ui-smoothness.css DELETED
@@ -1,1179 +0,0 @@
1
- /*! jQuery UI - v1.10.4 - 2014-01-17
2
- * http://jqueryui.com
3
- * Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css
4
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
5
- * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
6
-
7
- /* Layout helpers
8
- ----------------------------------*/
9
- .ui-helper-hidden {
10
- display: none;
11
- }
12
- .ui-helper-hidden-accessible {
13
- border: 0;
14
- clip: rect(0 0 0 0);
15
- height: 1px;
16
- margin: -1px;
17
- overflow: hidden;
18
- padding: 0;
19
- position: absolute;
20
- width: 1px;
21
- }
22
- .ui-helper-reset {
23
- margin: 0;
24
- padding: 0;
25
- border: 0;
26
- outline: 0;
27
- line-height: 1.3;
28
- text-decoration: none;
29
- font-size: 100%;
30
- list-style: none;
31
- }
32
- .ui-helper-clearfix:before,
33
- .ui-helper-clearfix:after {
34
- content: "";
35
- display: table;
36
- border-collapse: collapse;
37
- }
38
- .ui-helper-clearfix:after {
39
- clear: both;
40
- }
41
- .ui-helper-clearfix {
42
- min-height: 0; /* support: IE7 */
43
- }
44
- .ui-helper-zfix {
45
- width: 100%;
46
- height: 100%;
47
- top: 0;
48
- left: 0;
49
- position: absolute;
50
- opacity: 0;
51
- filter:Alpha(Opacity=0);
52
- }
53
-
54
- .ui-front {
55
- z-index: 100;
56
- }
57
-
58
-
59
- /* Interaction Cues
60
- ----------------------------------*/
61
- .ui-state-disabled {
62
- cursor: default !important;
63
- }
64
-
65
-
66
- /* Icons
67
- ----------------------------------*/
68
-
69
- /* states and images */
70
- .ui-icon {
71
- display: block;
72
- text-indent: -99999px;
73
- overflow: hidden;
74
- background-repeat: no-repeat;
75
- }
76
-
77
-
78
- /* Misc visuals
79
- ----------------------------------*/
80
-
81
- /* Overlays */
82
- .ui-widget-overlay {
83
- position: fixed;
84
- top: 0;
85
- left: 0;
86
- width: 100%;
87
- height: 100%;
88
- }
89
- .ui-accordion .ui-accordion-header {
90
- display: block;
91
- cursor: pointer;
92
- position: relative;
93
- margin-top: 2px;
94
- padding: .5em .5em .5em .7em;
95
- min-height: 0; /* support: IE7 */
96
- }
97
- .ui-accordion .ui-accordion-icons {
98
- padding-left: 2.2em;
99
- }
100
- .ui-accordion .ui-accordion-noicons {
101
- padding-left: .7em;
102
- }
103
- .ui-accordion .ui-accordion-icons .ui-accordion-icons {
104
- padding-left: 2.2em;
105
- }
106
- .ui-accordion .ui-accordion-header .ui-accordion-header-icon {
107
- position: absolute;
108
- left: .5em;
109
- top: 50%;
110
- margin-top: -8px;
111
- }
112
- .ui-accordion .ui-accordion-content {
113
- padding: 1em 2.2em;
114
- border-top: 0;
115
- overflow: auto;
116
- }
117
- .ui-autocomplete {
118
- position: absolute;
119
- top: 0;
120
- left: 0;
121
- cursor: default;
122
- }
123
- .ui-button {
124
- display: inline-block;
125
- position: relative;
126
- padding: 0;
127
- line-height: normal;
128
- margin-right: .1em;
129
- cursor: pointer;
130
- vertical-align: middle;
131
- text-align: center;
132
- overflow: visible; /* removes extra width in IE */
133
- }
134
- .ui-button,
135
- .ui-button:link,
136
- .ui-button:visited,
137
- .ui-button:hover,
138
- .ui-button:active {
139
- text-decoration: none;
140
- }
141
- /* to make room for the icon, a width needs to be set here */
142
- .ui-button-icon-only {
143
- width: 2.2em;
144
- }
145
- /* button elements seem to need a little more width */
146
- button.ui-button-icon-only {
147
- width: 2.4em;
148
- }
149
- .ui-button-icons-only {
150
- width: 3.4em;
151
- }
152
- button.ui-button-icons-only {
153
- width: 3.7em;
154
- }
155
-
156
- /* button text element */
157
- .ui-button .ui-button-text {
158
- display: block;
159
- line-height: normal;
160
- }
161
- .ui-button-text-only .ui-button-text {
162
- padding: .4em 1em;
163
- }
164
- .ui-button-icon-only .ui-button-text,
165
- .ui-button-icons-only .ui-button-text {
166
- padding: .4em;
167
- text-indent: -9999999px;
168
- }
169
- .ui-button-text-icon-primary .ui-button-text,
170
- .ui-button-text-icons .ui-button-text {
171
- padding: .4em 1em .4em 2.1em;
172
- }
173
- .ui-button-text-icon-secondary .ui-button-text,
174
- .ui-button-text-icons .ui-button-text {
175
- padding: .4em 2.1em .4em 1em;
176
- }
177
- .ui-button-text-icons .ui-button-text {
178
- padding-left: 2.1em;
179
- padding-right: 2.1em;
180
- }
181
- /* no icon support for input elements, provide padding by default */
182
- input.ui-button {
183
- padding: .4em 1em;
184
- }
185
-
186
- /* button icon element(s) */
187
- .ui-button-icon-only .ui-icon,
188
- .ui-button-text-icon-primary .ui-icon,
189
- .ui-button-text-icon-secondary .ui-icon,
190
- .ui-button-text-icons .ui-icon,
191
- .ui-button-icons-only .ui-icon {
192
- position: absolute;
193
- top: 50%;
194
- margin-top: -8px;
195
- }
196
- .ui-button-icon-only .ui-icon {
197
- left: 50%;
198
- margin-left: -8px;
199
- }
200
- .ui-button-text-icon-primary .ui-button-icon-primary,
201
- .ui-button-text-icons .ui-button-icon-primary,
202
- .ui-button-icons-only .ui-button-icon-primary {
203
- left: .5em;
204
- }
205
- .ui-button-text-icon-secondary .ui-button-icon-secondary,
206
- .ui-button-text-icons .ui-button-icon-secondary,
207
- .ui-button-icons-only .ui-button-icon-secondary {
208
- right: .5em;
209
- }
210
-
211
- /* button sets */
212
- .ui-buttonset {
213
- margin-right: 7px;
214
- }
215
- .ui-buttonset .ui-button {
216
- margin-left: 0;
217
- margin-right: -.3em;
218
- }
219
-
220
- /* workarounds */
221
- /* reset extra padding in Firefox, see h5bp.com/l */
222
- input.ui-button::-moz-focus-inner,
223
- button.ui-button::-moz-focus-inner {
224
- border: 0;
225
- padding: 0;
226
- }
227
- .ui-datepicker {
228
- width: 17em;
229
- padding: .2em .2em 0;
230
- display: none;
231
- }
232
- .ui-datepicker .ui-datepicker-header {
233
- position: relative;
234
- padding: .2em 0;
235
- }
236
- .ui-datepicker .ui-datepicker-prev,
237
- .ui-datepicker .ui-datepicker-next {
238
- position: absolute;
239
- top: 2px;
240
- width: 1.8em;
241
- height: 1.8em;
242
- }
243
- .ui-datepicker .ui-datepicker-prev-hover,
244
- .ui-datepicker .ui-datepicker-next-hover {
245
- top: 1px;
246
- }
247
- .ui-datepicker .ui-datepicker-prev {
248
- left: 2px;
249
- }
250
- .ui-datepicker .ui-datepicker-next {
251
- right: 2px;
252
- }
253
- .ui-datepicker .ui-datepicker-prev-hover {
254
- left: 1px;
255
- }
256
- .ui-datepicker .ui-datepicker-next-hover {
257
- right: 1px;
258
- }
259
- .ui-datepicker .ui-datepicker-prev span,
260
- .ui-datepicker .ui-datepicker-next span {
261
- display: block;
262
- position: absolute;
263
- left: 50%;
264
- margin-left: -8px;
265
- top: 50%;
266
- margin-top: -8px;
267
- }
268
- .ui-datepicker .ui-datepicker-title {
269
- margin: 0 2.3em;
270
- line-height: 1.8em;
271
- text-align: center;
272
- }
273
- .ui-datepicker .ui-datepicker-title select {
274
- font-size: 1em;
275
- margin: 1px 0;
276
- }
277
- .ui-datepicker select.ui-datepicker-month,
278
- .ui-datepicker select.ui-datepicker-year {
279
- width: 49%;
280
- }
281
- .ui-datepicker table {
282
- width: 100%;
283
- font-size: .9em;
284
- border-collapse: collapse;
285
- margin: 0 0 .4em;
286
- }
287
- .ui-datepicker th {
288
- padding: .7em .3em;
289
- text-align: center;
290
- font-weight: bold;
291
- border: 0;
292
- }
293
- .ui-datepicker td {
294
- border: 0;
295
- padding: 1px;
296
- }
297
- .ui-datepicker td span,
298
- .ui-datepicker td a {
299
- display: block;
300
- padding: .2em;
301
- text-align: right;
302
- text-decoration: none;
303
- }
304
- .ui-datepicker .ui-datepicker-buttonpane {
305
- background-image: none;
306
- margin: .7em 0 0 0;
307
- padding: 0 .2em;
308
- border-left: 0;
309
- border-right: 0;
310
- border-bottom: 0;
311
- }
312
- .ui-datepicker .ui-datepicker-buttonpane button {
313
- float: right;
314
- margin: .5em .2em .4em;
315
- cursor: pointer;
316
- padding: .2em .6em .3em .6em;
317
- width: auto;
318
- overflow: visible;
319
- }
320
- .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
321
- float: left;
322
- }
323
-
324
- /* with multiple calendars */
325
- .ui-datepicker.ui-datepicker-multi {
326
- width: auto;
327
- }
328
- .ui-datepicker-multi .ui-datepicker-group {
329
- float: left;
330
- }
331
- .ui-datepicker-multi .ui-datepicker-group table {
332
- width: 95%;
333
- margin: 0 auto .4em;
334
- }
335
- .ui-datepicker-multi-2 .ui-datepicker-group {
336
- width: 50%;
337
- }
338
- .ui-datepicker-multi-3 .ui-datepicker-group {
339
- width: 33.3%;
340
- }
341
- .ui-datepicker-multi-4 .ui-datepicker-group {
342
- width: 25%;
343
- }
344
- .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
345
- .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
346
- border-left-width: 0;
347
- }
348
- .ui-datepicker-multi .ui-datepicker-buttonpane {
349
- clear: left;
350
- }
351
- .ui-datepicker-row-break {
352
- clear: both;
353
- width: 100%;
354
- font-size: 0;
355
- }
356
-
357
- /* RTL support */
358
- .ui-datepicker-rtl {
359
- direction: rtl;
360
- }
361
- .ui-datepicker-rtl .ui-datepicker-prev {
362
- right: 2px;
363
- left: auto;
364
- }
365
- .ui-datepicker-rtl .ui-datepicker-next {
366
- left: 2px;
367
- right: auto;
368
- }
369
- .ui-datepicker-rtl .ui-datepicker-prev:hover {
370
- right: 1px;
371
- left: auto;
372
- }
373
- .ui-datepicker-rtl .ui-datepicker-next:hover {
374
- left: 1px;
375
- right: auto;
376
- }
377
- .ui-datepicker-rtl .ui-datepicker-buttonpane {
378
- clear: right;
379
- }
380
- .ui-datepicker-rtl .ui-datepicker-buttonpane button {
381
- float: left;
382
- }
383
- .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
384
- .ui-datepicker-rtl .ui-datepicker-group {
385
- float: right;
386
- }
387
- .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
388
- .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
389
- border-right-width: 0;
390
- border-left-width: 1px;
391
- }
392
- .ui-dialog {
393
- overflow: hidden;
394
- position: absolute;
395
- top: 0;
396
- left: 0;
397
- padding: .2em;
398
- outline: 0;
399
- }
400
- .ui-dialog .ui-dialog-titlebar {
401
- padding: .4em 1em;
402
- position: relative;
403
- }
404
- .ui-dialog .ui-dialog-title {
405
- float: left;
406
- margin: .1em 0;
407
- white-space: nowrap;
408
- width: 90%;
409
- overflow: hidden;
410
- text-overflow: ellipsis;
411
- }
412
- .ui-dialog .ui-dialog-titlebar-close {
413
- position: absolute;
414
- right: .3em;
415
- top: 50%;
416
- width: 20px;
417
- margin: -10px 0 0 0;
418
- padding: 1px;
419
- height: 20px;
420
- }
421
- .ui-dialog .ui-dialog-content {
422
- position: relative;
423
- border: 0;
424
- padding: .5em 1em;
425
- background: none;
426
- overflow: auto;
427
- }
428
- .ui-dialog .ui-dialog-buttonpane {
429
- text-align: left;
430
- border-width: 1px 0 0 0;
431
- background-image: none;
432
- margin-top: .5em;
433
- padding: .3em 1em .5em .4em;
434
- }
435
- .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
436
- float: right;
437
- }
438
- .ui-dialog .ui-dialog-buttonpane button {
439
- margin: .5em .4em .5em 0;
440
- cursor: pointer;
441
- }
442
- .ui-dialog .ui-resizable-se {
443
- width: 12px;
444
- height: 12px;
445
- right: -5px;
446
- bottom: -5px;
447
- background-position: 16px 16px;
448
- }
449
- .ui-draggable .ui-dialog-titlebar {
450
- cursor: move;
451
- }
452
- .ui-menu {
453
- list-style: none;
454
- padding: 2px;
455
- margin: 0;
456
- display: block;
457
- outline: none;
458
- }
459
- .ui-menu .ui-menu {
460
- margin-top: -3px;
461
- position: absolute;
462
- }
463
- .ui-menu .ui-menu-item {
464
- margin: 0;
465
- padding: 0;
466
- width: 100%;
467
- /* support: IE10, see #8844 */
468
- list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
469
- }
470
- .ui-menu .ui-menu-divider {
471
- margin: 5px -2px 5px -2px;
472
- height: 0;
473
- font-size: 0;
474
- line-height: 0;
475
- border-width: 1px 0 0 0;
476
- }
477
- .ui-menu .ui-menu-item a {
478
- text-decoration: none;
479
- display: block;
480
- padding: 2px .4em;
481
- line-height: 1.5;
482
- min-height: 0; /* support: IE7 */
483
- font-weight: normal;
484
- }
485
- .ui-menu .ui-menu-item a.ui-state-focus,
486
- .ui-menu .ui-menu-item a.ui-state-active {
487
- font-weight: normal;
488
- margin: -1px;
489
- }
490
-
491
- .ui-menu .ui-state-disabled {
492
- font-weight: normal;
493
- margin: .4em 0 .2em;
494
- line-height: 1.5;
495
- }
496
- .ui-menu .ui-state-disabled a {
497
- cursor: default;
498
- }
499
-
500
- /* icon support */
501
- .ui-menu-icons {
502
- position: relative;
503
- }
504
- .ui-menu-icons .ui-menu-item a {
505
- position: relative;
506
- padding-left: 2em;
507
- }
508
-
509
- /* left-aligned */
510
- .ui-menu .ui-icon {
511
- position: absolute;
512
- top: .2em;
513
- left: .2em;
514
- }
515
-
516
- /* right-aligned */
517
- .ui-menu .ui-menu-icon {
518
- position: static;
519
- float: right;
520
- }
521
- .ui-progressbar {
522
- height: 2em;
523
- text-align: left;
524
- overflow: hidden;
525
- }
526
- .ui-progressbar .ui-progressbar-value {
527
- margin: -1px;
528
- height: 100%;
529
- }
530
- .ui-progressbar .ui-progressbar-overlay {
531
- background: url("images/animated-overlay.gif");
532
- height: 100%;
533
- filter: alpha(opacity=25);
534
- opacity: 0.25;
535
- }
536
- .ui-progressbar-indeterminate .ui-progressbar-value {
537
- background-image: none;
538
- }
539
- .ui-resizable {
540
- position: relative;
541
- }
542
- .ui-resizable-handle {
543
- position: absolute;
544
- font-size: 0.1px;
545
- display: block;
546
- }
547
- .ui-resizable-disabled .ui-resizable-handle,
548
- .ui-resizable-autohide .ui-resizable-handle {
549
- display: none;
550
- }
551
- .ui-resizable-n {
552
- cursor: n-resize;
553
- height: 7px;
554
- width: 100%;
555
- top: -5px;
556
- left: 0;
557
- }
558
- .ui-resizable-s {
559
- cursor: s-resize;
560
- height: 7px;
561
- width: 100%;
562
- bottom: -5px;
563
- left: 0;
564
- }
565
- .ui-resizable-e {
566
- cursor: e-resize;
567
- width: 7px;
568
- right: -5px;
569
- top: 0;
570
- height: 100%;
571
- }
572
- .ui-resizable-w {
573
- cursor: w-resize;
574
- width: 7px;
575
- left: -5px;
576
- top: 0;
577
- height: 100%;
578
- }
579
- .ui-resizable-se {
580
- cursor: se-resize;
581
- width: 12px;
582
- height: 12px;
583
- right: 1px;
584
- bottom: 1px;
585
- }
586
- .ui-resizable-sw {
587
- cursor: sw-resize;
588
- width: 9px;
589
- height: 9px;
590
- left: -5px;
591
- bottom: -5px;
592
- }
593
- .ui-resizable-nw {
594
- cursor: nw-resize;
595
- width: 9px;
596
- height: 9px;
597
- left: -5px;
598
- top: -5px;
599
- }
600
- .ui-resizable-ne {
601
- cursor: ne-resize;
602
- width: 9px;
603
- height: 9px;
604
- right: -5px;
605
- top: -5px;
606
- }
607
- .ui-selectable-helper {
608
- position: absolute;
609
- z-index: 100;
610
- border: 1px dotted black;
611
- }
612
- .ui-slider {
613
- position: relative;
614
- text-align: left;
615
- }
616
- .ui-slider .ui-slider-handle {
617
- position: absolute;
618
- z-index: 2;
619
- width: 1.2em;
620
- height: 1.2em;
621
- cursor: default;
622
- }
623
- .ui-slider .ui-slider-range {
624
- position: absolute;
625
- z-index: 1;
626
- font-size: .7em;
627
- display: block;
628
- border: 0;
629
- background-position: 0 0;
630
- }
631
-
632
- /* For IE8 - See #6727 */
633
- .ui-slider.ui-state-disabled .ui-slider-handle,
634
- .ui-slider.ui-state-disabled .ui-slider-range {
635
- filter: inherit;
636
- }
637
-
638
- .ui-slider-horizontal {
639
- height: .8em;
640
- }
641
- .ui-slider-horizontal .ui-slider-handle {
642
- top: -.3em;
643
- margin-left: -.6em;
644
- }
645
- .ui-slider-horizontal .ui-slider-range {
646
- top: 0;
647
- height: 100%;
648
- }
649
- .ui-slider-horizontal .ui-slider-range-min {
650
- left: 0;
651
- }
652
- .ui-slider-horizontal .ui-slider-range-max {
653
- right: 0;
654
- }
655
-
656
- .ui-slider-vertical {
657
- width: .8em;
658
- height: 100px;
659
- }
660
- .ui-slider-vertical .ui-slider-handle {
661
- left: -.3em;
662
- margin-left: 0;
663
- margin-bottom: -.6em;
664
- }
665
- .ui-slider-vertical .ui-slider-range {
666
- left: 0;
667
- width: 100%;
668
- }
669
- .ui-slider-vertical .ui-slider-range-min {
670
- bottom: 0;
671
- }
672
- .ui-slider-vertical .ui-slider-range-max {
673
- top: 0;
674
- }
675
- .ui-spinner {
676
- position: relative;
677
- display: inline-block;
678
- overflow: hidden;
679
- padding: 0;
680
- vertical-align: middle;
681
- }
682
- .ui-spinner-input {
683
- border: none;
684
- background: none;
685
- color: inherit;
686
- padding: 0;
687
- margin: .2em 0;
688
- vertical-align: middle;
689
- margin-left: .4em;
690
- margin-right: 22px;
691
- }
692
- .ui-spinner-button {
693
- width: 16px;
694
- height: 50%;
695
- font-size: .5em;
696
- padding: 0;
697
- margin: 0;
698
- text-align: center;
699
- position: absolute;
700
- cursor: default;
701
- display: block;
702
- overflow: hidden;
703
- right: 0;
704
- }
705
- /* more specificity required here to override default borders */
706
- .ui-spinner a.ui-spinner-button {
707
- border-top: none;
708
- border-bottom: none;
709
- border-right: none;
710
- }
711
- /* vertically center icon */
712
- .ui-spinner .ui-icon {
713
- position: absolute;
714
- margin-top: -8px;
715
- top: 50%;
716
- left: 0;
717
- }
718
- .ui-spinner-up {
719
- top: 0;
720
- }
721
- .ui-spinner-down {
722
- bottom: 0;
723
- }
724
-
725
- /* TR overrides */
726
- .ui-spinner .ui-icon-triangle-1-s {
727
- /* need to fix icons sprite */
728
- background-position: -65px -16px;
729
- }
730
- .ui-tabs {
731
- position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
732
- padding: .2em;
733
- }
734
- .ui-tabs .ui-tabs-nav {
735
- margin: 0;
736
- padding: .2em .2em 0;
737
- }
738
- .ui-tabs .ui-tabs-nav li {
739
- list-style: none;
740
- float: left;
741
- position: relative;
742
- top: 0;
743
- margin: 1px .2em 0 0;
744
- border-bottom-width: 0;
745
- padding: 0;
746
- white-space: nowrap;
747
- }
748
- .ui-tabs .ui-tabs-nav .ui-tabs-anchor {
749
- float: left;
750
- padding: .5em 1em;
751
- text-decoration: none;
752
- }
753
- .ui-tabs .ui-tabs-nav li.ui-tabs-active {
754
- margin-bottom: -1px;
755
- padding-bottom: 1px;
756
- }
757
- .ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
758
- .ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
759
- .ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
760
- cursor: text;
761
- }
762
- .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
763
- cursor: pointer;
764
- }
765
- .ui-tabs .ui-tabs-panel {
766
- display: block;
767
- border-width: 0;
768
- padding: 1em 1.4em;
769
- background: none;
770
- }
771
- .ui-tooltip {
772
- padding: 8px;
773
- position: absolute;
774
- z-index: 9999;
775
- max-width: 300px;
776
- -webkit-box-shadow: 0 0 5px #aaa;
777
- box-shadow: 0 0 5px #aaa;
778
- /* Custom by WPRA: */ opacity: 1 !important;
779
- }
780
- body .ui-tooltip {
781
- border-width: 2px;
782
- }
783
-
784
- /* Component containers
785
- ----------------------------------*/
786
- .ui-widget {
787
- font-family: Verdana,Arial,sans-serif;
788
- font-size: 1.1em;
789
- }
790
- .ui-widget .ui-widget {
791
- font-size: 1em;
792
- }
793
- .ui-widget input,
794
- .ui-widget select,
795
- .ui-widget textarea,
796
- .ui-widget button {
797
- font-family: Verdana,Arial,sans-serif;
798
- font-size: 1em;
799
- }
800
- .ui-widget-content {
801
- border: 1px solid #aaaaaa;
802
- background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;
803
- color: #222222;
804
- }
805
- .ui-widget-content a {
806
- color: #222222;
807
- }
808
- .ui-widget-header {
809
- border: 1px solid #aaaaaa;
810
- background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;
811
- color: #222222;
812
- font-weight: bold;
813
- }
814
- .ui-widget-header a {
815
- color: #222222;
816
- }
817
-
818
- /* Interaction states
819
- ----------------------------------*/
820
- .ui-state-default,
821
- .ui-widget-content .ui-state-default,
822
- .ui-widget-header .ui-state-default {
823
- border: 1px solid #d3d3d3;
824
- background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;
825
- font-weight: normal;
826
- color: #555555;
827
- }
828
- .ui-state-default a,
829
- .ui-state-default a:link,
830
- .ui-state-default a:visited {
831
- color: #555555;
832
- text-decoration: none;
833
- }
834
- .ui-state-hover,
835
- .ui-widget-content .ui-state-hover,
836
- .ui-widget-header .ui-state-hover,
837
- .ui-state-focus,
838
- .ui-widget-content .ui-state-focus,
839
- .ui-widget-header .ui-state-focus {
840
- border: 1px solid #999999;
841
- background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;
842
- font-weight: normal;
843
- color: #212121;
844
- }
845
- .ui-state-hover a,
846
- .ui-state-hover a:hover,
847
- .ui-state-hover a:link,
848
- .ui-state-hover a:visited,
849
- .ui-state-focus a,
850
- .ui-state-focus a:hover,
851
- .ui-state-focus a:link,
852
- .ui-state-focus a:visited {
853
- color: #212121;
854
- text-decoration: none;
855
- }
856
- .ui-state-active,
857
- .ui-widget-content .ui-state-active,
858
- .ui-widget-header .ui-state-active {
859
- border: 1px solid #aaaaaa;
860
- background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;
861
- font-weight: normal;
862
- color: #212121;
863
- }
864
- .ui-state-active a,
865
- .ui-state-active a:link,
866
- .ui-state-active a:visited {
867
- color: #212121;
868
- text-decoration: none;
869
- }
870
-
871
- /* Interaction Cues
872
- ----------------------------------*/
873
- .ui-state-highlight,
874
- .ui-widget-content .ui-state-highlight,
875
- .ui-widget-header .ui-state-highlight {
876
- border: 1px solid #fcefa1;
877
- background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;
878
- color: #363636;
879
- }
880
- .ui-state-highlight a,
881
- .ui-widget-content .ui-state-highlight a,
882
- .ui-widget-header .ui-state-highlight a {
883
- color: #363636;
884
- }
885
- .ui-state-error,
886
- .ui-widget-content .ui-state-error,
887
- .ui-widget-header .ui-state-error {
888
- border: 1px solid #cd0a0a;
889
- background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;
890
- color: #cd0a0a;
891
- }
892
- .ui-state-error a,
893
- .ui-widget-content .ui-state-error a,
894
- .ui-widget-header .ui-state-error a {
895
- color: #cd0a0a;
896
- }
897
- .ui-state-error-text,
898
- .ui-widget-content .ui-state-error-text,
899
- .ui-widget-header .ui-state-error-text {
900
- color: #cd0a0a;
901
- }
902
- .ui-priority-primary,
903
- .ui-widget-content .ui-priority-primary,
904
- .ui-widget-header .ui-priority-primary {
905
- font-weight: bold;
906
- }
907
- .ui-priority-secondary,
908
- .ui-widget-content .ui-priority-secondary,
909
- .ui-widget-header .ui-priority-secondary {
910
- opacity: .7;
911
- filter:Alpha(Opacity=70);
912
- font-weight: normal;
913
- }
914
- .ui-state-disabled,
915
- .ui-widget-content .ui-state-disabled,
916
- .ui-widget-header .ui-state-disabled {
917
- opacity: .35;
918
- filter:Alpha(Opacity=35);
919
- background-image: none;
920
- }
921
- .ui-state-disabled .ui-icon {
922
- filter:Alpha(Opacity=35); /* For IE8 - See #6059 */
923
- }
924
-
925
- /* Icons
926
- ----------------------------------*/
927
-
928
- /* states and images */
929
- .ui-icon {
930
- width: 16px;
931
- height: 16px;
932
- }
933
- .ui-icon,
934
- .ui-widget-content .ui-icon {
935
- background-image: url(images/ui-icons_222222_256x240.png);
936
- }
937
- .ui-widget-header .ui-icon {
938
- background-image: url(images/ui-icons_222222_256x240.png);
939
- }
940
- .ui-state-default .ui-icon {
941
- background-image: url(images/ui-icons_888888_256x240.png);
942
- }
943
- .ui-state-hover .ui-icon,
944
- .ui-state-focus .ui-icon {
945
- background-image: url(images/ui-icons_454545_256x240.png);
946
- }
947
- .ui-state-active .ui-icon {
948
- background-image: url(images/ui-icons_454545_256x240.png);
949
- }
950
- .ui-state-highlight .ui-icon {
951
- background-image: url(images/ui-icons_2e83ff_256x240.png);
952
- }
953
- .ui-state-error .ui-icon,
954
- .ui-state-error-text .ui-icon {
955
- background-image: url(images/ui-icons_cd0a0a_256x240.png);
956
- }
957
-
958
- /* positioning */
959
- .ui-icon-blank { background-position: 16px 16px; }
960
- .ui-icon-carat-1-n { background-position: 0 0; }
961
- .ui-icon-carat-1-ne { background-position: -16px 0; }
962
- .ui-icon-carat-1-e { background-position: -32px 0; }
963
- .ui-icon-carat-1-se { background-position: -48px 0; }
964
- .ui-icon-carat-1-s { background-position: -64px 0; }
965
- .ui-icon-carat-1-sw { background-position: -80px 0; }
966
- .ui-icon-carat-1-w { background-position: -96px 0; }
967
- .ui-icon-carat-1-nw { background-position: -112px 0; }
968
- .ui-icon-carat-2-n-s { background-position: -128px 0; }
969
- .ui-icon-carat-2-e-w { background-position: -144px 0; }
970
- .ui-icon-triangle-1-n { background-position: 0 -16px; }
971
- .ui-icon-triangle-1-ne { background-position: -16px -16px; }
972
- .ui-icon-triangle-1-e { background-position: -32px -16px; }
973
- .ui-icon-triangle-1-se { background-position: -48px -16px; }
974
- .ui-icon-triangle-1-s { background-position: -64px -16px; }
975
- .ui-icon-triangle-1-sw { background-position: -80px -16px; }
976
- .ui-icon-triangle-1-w { background-position: -96px -16px; }
977
- .ui-icon-triangle-1-nw { background-position: -112px -16px; }
978
- .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
979
- .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
980
- .ui-icon-arrow-1-n { background-position: 0 -32px; }
981
- .ui-icon-arrow-1-ne { background-position: -16px -32px; }
982
- .ui-icon-arrow-1-e { background-position: -32px -32px; }
983
- .ui-icon-arrow-1-se { background-position: -48px -32px; }
984
- .ui-icon-arrow-1-s { background-position: -64px -32px; }
985
- .ui-icon-arrow-1-sw { background-position: -80px -32px; }
986
- .ui-icon-arrow-1-w { background-position: -96px -32px; }
987
- .ui-icon-arrow-1-nw { background-position: -112px -32px; }
988
- .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
989
- .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
990
- .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
991
- .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
992
- .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
993
- .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
994
- .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
995
- .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
996
- .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
997
- .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
998
- .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
999
- .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
1000
- .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
1001
- .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
1002
- .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
1003
- .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
1004
- .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
1005
- .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
1006
- .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
1007
- .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
1008
- .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
1009
- .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
1010
- .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
1011
- .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
1012
- .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
1013
- .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
1014
- .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
1015
- .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
1016
- .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
1017
- .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
1018
- .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
1019
- .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
1020
- .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
1021
- .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
1022
- .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
1023
- .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
1024
- .ui-icon-arrow-4 { background-position: 0 -80px; }
1025
- .ui-icon-arrow-4-diag { background-position: -16px -80px; }
1026
- .ui-icon-extlink { background-position: -32px -80px; }
1027
- .ui-icon-newwin { background-position: -48px -80px; }
1028
- .ui-icon-refresh { background-position: -64px -80px; }
1029
- .ui-icon-shuffle { background-position: -80px -80px; }
1030
- .ui-icon-transfer-e-w { background-position: -96px -80px; }
1031
- .ui-icon-transferthick-e-w { background-position: -112px -80px; }
1032
- .ui-icon-folder-collapsed { background-position: 0 -96px; }
1033
- .ui-icon-folder-open { background-position: -16px -96px; }
1034
- .ui-icon-document { background-position: -32px -96px; }
1035
- .ui-icon-document-b { background-position: -48px -96px; }
1036
- .ui-icon-note { background-position: -64px -96px; }
1037
- .ui-icon-mail-closed { background-position: -80px -96px; }
1038
- .ui-icon-mail-open { background-position: -96px -96px; }
1039
- .ui-icon-suitcase { background-position: -112px -96px; }
1040
- .ui-icon-comment { background-position: -128px -96px; }
1041
- .ui-icon-person { background-position: -144px -96px; }
1042
- .ui-icon-print { background-position: -160px -96px; }
1043
- .ui-icon-trash { background-position: -176px -96px; }
1044
- .ui-icon-locked { background-position: -192px -96px; }
1045
- .ui-icon-unlocked { background-position: -208px -96px; }
1046
- .ui-icon-bookmark { background-position: -224px -96px; }
1047
- .ui-icon-tag { background-position: -240px -96px; }
1048
- .ui-icon-home { background-position: 0 -112px; }
1049
- .ui-icon-flag { background-position: -16px -112px; }
1050
- .ui-icon-calendar { background-position: -32px -112px; }
1051
- .ui-icon-cart { background-position: -48px -112px; }
1052
- .ui-icon-pencil { background-position: -64px -112px; }
1053
- .ui-icon-clock { background-position: -80px -112px; }
1054
- .ui-icon-disk { background-position: -96px -112px; }
1055
- .ui-icon-calculator { background-position: -112px -112px; }
1056
- .ui-icon-zoomin { background-position: -128px -112px; }
1057
- .ui-icon-zoomout { background-position: -144px -112px; }
1058
- .ui-icon-search { background-position: -160px -112px; }
1059
- .ui-icon-wrench { background-position: -176px -112px; }
1060
- .ui-icon-gear { background-position: -192px -112px; }
1061
- .ui-icon-heart { background-position: -208px -112px; }
1062
- .ui-icon-star { background-position: -224px -112px; }
1063
- .ui-icon-link { background-position: -240px -112px; }
1064
- .ui-icon-cancel { background-position: 0 -128px; }
1065
- .ui-icon-plus { background-position: -16px -128px; }
1066
- .ui-icon-plusthick { background-position: -32px -128px; }
1067
- .ui-icon-minus { background-position: -48px -128px; }
1068
- .ui-icon-minusthick { background-position: -64px -128px; }
1069
- .ui-icon-close { background-position: -80px -128px; }
1070
- .ui-icon-closethick { background-position: -96px -128px; }
1071
- .ui-icon-key { background-position: -112px -128px; }
1072
- .ui-icon-lightbulb { background-position: -128px -128px; }
1073
- .ui-icon-scissors { background-position: -144px -128px; }
1074
- .ui-icon-clipboard { background-position: -160px -128px; }
1075
- .ui-icon-copy { background-position: -176px -128px; }
1076
- .ui-icon-contact { background-position: -192px -128px; }
1077
- .ui-icon-image { background-position: -208px -128px; }
1078
- .ui-icon-video { background-position: -224px -128px; }
1079
- .ui-icon-script { background-position: -240px -128px; }
1080
- .ui-icon-alert { background-position: 0 -144px; }
1081
- .ui-icon-info { background-position: -16px -144px; }
1082
- .ui-icon-notice { background-position: -32px -144px; }
1083
- .ui-icon-help { background-position: -48px -144px; }
1084
- .ui-icon-check { background-position: -64px -144px; }
1085
- .ui-icon-bullet { background-position: -80px -144px; }
1086
- .ui-icon-radio-on { background-position: -96px -144px; }
1087
- .ui-icon-radio-off { background-position: -112px -144px; }
1088
- .ui-icon-pin-w { background-position: -128px -144px; }
1089
- .ui-icon-pin-s { background-position: -144px -144px; }
1090
- .ui-icon-play { background-position: 0 -160px; }
1091
- .ui-icon-pause { background-position: -16px -160px; }
1092
- .ui-icon-seek-next { background-position: -32px -160px; }
1093
- .ui-icon-seek-prev { background-position: -48px -160px; }
1094
- .ui-icon-seek-end { background-position: -64px -160px; }
1095
- .ui-icon-seek-start { background-position: -80px -160px; }
1096
- /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
1097
- .ui-icon-seek-first { background-position: -80px -160px; }
1098
- .ui-icon-stop { background-position: -96px -160px; }
1099
- .ui-icon-eject { background-position: -112px -160px; }
1100
- .ui-icon-volume-off { background-position: -128px -160px; }
1101
- .ui-icon-volume-on { background-position: -144px -160px; }
1102
- .ui-icon-power { background-position: 0 -176px; }
1103
- .ui-icon-signal-diag { background-position: -16px -176px; }
1104
- .ui-icon-signal { background-position: -32px -176px; }
1105
- .ui-icon-battery-0 { background-position: -48px -176px; }
1106
- .ui-icon-battery-1 { background-position: -64px -176px; }
1107
- .ui-icon-battery-2 { background-position: -80px -176px; }
1108
- .ui-icon-battery-3 { background-position: -96px -176px; }
1109
- .ui-icon-circle-plus { background-position: 0 -192px; }
1110
- .ui-icon-circle-minus { background-position: -16px -192px; }
1111
- .ui-icon-circle-close { background-position: -32px -192px; }
1112
- .ui-icon-circle-triangle-e { background-position: -48px -192px; }
1113
- .ui-icon-circle-triangle-s { background-position: -64px -192px; }
1114
- .ui-icon-circle-triangle-w { background-position: -80px -192px; }
1115
- .ui-icon-circle-triangle-n { background-position: -96px -192px; }
1116
- .ui-icon-circle-arrow-e { background-position: -112px -192px; }
1117
- .ui-icon-circle-arrow-s { background-position: -128px -192px; }
1118
- .ui-icon-circle-arrow-w { background-position: -144px -192px; }
1119
- .ui-icon-circle-arrow-n { background-position: -160px -192px; }
1120
- .ui-icon-circle-zoomin { background-position: -176px -192px; }
1121
- .ui-icon-circle-zoomout { background-position: -192px -192px; }
1122
- .ui-icon-circle-check { background-position: -208px -192px; }
1123
- .ui-icon-circlesmall-plus { background-position: 0 -208px; }
1124
- .ui-icon-circlesmall-minus { background-position: -16px -208px; }
1125
- .ui-icon-circlesmall-close { background-position: -32px -208px; }
1126
- .ui-icon-squaresmall-plus { background-position: -48px -208px; }
1127
- .ui-icon-squaresmall-minus { background-position: -64px -208px; }
1128
- .ui-icon-squaresmall-close { background-position: -80px -208px; }
1129
- .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
1130
- .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
1131
- .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
1132
- .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
1133
- .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
1134
- .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
1135
-
1136
-
1137
- /* Misc visuals
1138
- ----------------------------------*/
1139
-
1140
- /* Corner radius */
1141
- .ui-corner-all,
1142
- .ui-corner-top,
1143
- .ui-corner-left,
1144
- .ui-corner-tl {
1145
- border-top-left-radius: 4px;
1146
- }
1147
- .ui-corner-all,
1148
- .ui-corner-top,
1149
- .ui-corner-right,
1150
- .ui-corner-tr {
1151
- border-top-right-radius: 4px;
1152
- }
1153
- .ui-corner-all,
1154
- .ui-corner-bottom,
1155
- .ui-corner-left,
1156
- .ui-corner-bl {
1157
- border-bottom-left-radius: 4px;
1158
- }
1159
- .ui-corner-all,
1160
- .ui-corner-bottom,
1161
- .ui-corner-right,
1162
- .ui-corner-br {
1163
- border-bottom-right-radius: 4px;
1164
- }
1165
-
1166
- /* Overlays */
1167
- .ui-widget-overlay {
1168
- background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
1169
- opacity: .3;
1170
- filter: Alpha(Opacity=30);
1171
- }
1172
- .ui-widget-shadow {
1173
- margin: -8px 0 0 -8px;
1174
- padding: 8px;
1175
- background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
1176
- opacity: .3;
1177
- filter: Alpha(Opacity=30);
1178
- border-radius: 8px;
1179
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/templates/list/styles.css CHANGED
@@ -27,16 +27,6 @@ div.wpra-list-template .wpra-item-list > li.wpra-item > div.wprss-feed-meta > sp
27
  list-style: decimal;
28
  }
29
 
30
- /* Audio player */
31
- .wpra-feed-audio {
32
- display: block;
33
- margin: 0 5px;
34
- }
35
-
36
- .wpra-feed-audio audio {
37
- width: 100%;
38
- }
39
-
40
  /**
41
  * Old styles
42
  */
27
  list-style: decimal;
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
30
  /**
31
  * Old styles
32
  */
fonts/FontAwesome.otf CHANGED
File without changes
fonts/fontawesome-webfont.eot CHANGED
File without changes
fonts/fontawesome-webfont.svg CHANGED
File without changes
fonts/fontawesome-webfont.ttf CHANGED
File without changes
fonts/fontawesome-webfont.woff CHANGED
File without changes
images/colorbox/border.png CHANGED
File without changes
images/colorbox/controls.png CHANGED
File without changes
images/colorbox/ie6/borderBottomCenter.png CHANGED
File without changes
images/colorbox/ie6/borderBottomLeft.png CHANGED
File without changes
images/colorbox/ie6/borderBottomRight.png CHANGED
File without changes
images/colorbox/ie6/borderMiddleLeft.png CHANGED
File without changes
images/colorbox/ie6/borderMiddleRight.png CHANGED
File without changes
images/colorbox/ie6/borderTopCenter.png CHANGED
File without changes
images/colorbox/ie6/borderTopLeft.png CHANGED
File without changes
images/colorbox/ie6/borderTopRight.png CHANGED
File without changes
images/colorbox/loading.gif CHANGED
File without changes
images/colorbox/loading_background.png CHANGED
File without changes
images/colorbox/overlay.png CHANGED
File without changes
images/facebook.png CHANGED
File without changes
images/icon-adminmenu16-sprite.png CHANGED
File without changes
images/icon-adminpage32.png CHANGED
File without changes
images/twitter.png CHANGED
File without changes
images/wpra-icon-transparent.png DELETED
Binary file
includes/Aventura/Wprss/Core/Licensing/AjaxController.php CHANGED
@@ -90,18 +90,18 @@ class AjaxController {
90
  $licenseKey = empty( $_GET['license'] )? null : sanitize_text_field( $_GET['license'] );
91
 
92
  // If no nonce, stop
93
- if ( $nonce === null ) $this->_sendErrorResponse( __( 'No nonce', 'wprss' ), $addon );
94
  // Generate the nonce id
95
  $nonce_id = sprintf( 'wprss_%s_license_nonce', $addon );
96
  // Verify the nonce. If verification fails, stop
97
  if ( ! wp_verify_nonce( $nonce, $nonce_id ) ) {
98
- $this->_sendErrorResponse( __( 'Bad nonce', 'wprss' ), $addon );
99
  }
100
 
101
  // Check addon, event and license
102
- if ( $addon === null ) $this->_sendErrorResponse( __( 'No addon ID', 'wprss' ) );
103
- if ( $event === null ) $this->_sendErrorResponse( __( 'No event specified', 'wprss' ), $addon );
104
- if ( $licenseKey === null ) $this->_sendErrorResponse( __( 'No license', 'wprss' ), $addon );
105
 
106
  $settings = $this->getSettingsController();
107
  $manager = $this->getManager();
@@ -127,7 +127,7 @@ class AjaxController {
127
  $eventMethod = sprintf( self::AJAX_MANAGE_LICENSE_METHOD_PATTERN, $event );
128
  // check if the event is handle-able
129
  if ( ! method_exists( $this, $eventMethod ) ) {
130
- $this->_sendErrorResponse( __( 'Invalid event specified', 'wprss' ), $addon);
131
  }
132
 
133
  // Call the appropriate handler method
@@ -153,7 +153,7 @@ class AjaxController {
153
  public function handleAjaxFetchLicense() {
154
  // If not addon ID in the request, stop
155
  if ( empty( $_GET['addon']) )
156
- $this->_sendErrorResponse( __( 'No addon ID', 'wprss' ) );
157
  // Get and sanitize the addon ID
158
  $addon = sanitize_text_field( $_GET['addon'] );
159
  // Get the license information from EDD
90
  $licenseKey = empty( $_GET['license'] )? null : sanitize_text_field( $_GET['license'] );
91
 
92
  // If no nonce, stop
93
+ if ( $nonce === null ) $this->_sendErrorResponse( __( 'No nonce', WPRSS_TEXT_DOMAIN ), $addon );
94
  // Generate the nonce id
95
  $nonce_id = sprintf( 'wprss_%s_license_nonce', $addon );
96
  // Verify the nonce. If verification fails, stop
97
  if ( ! wp_verify_nonce( $nonce, $nonce_id ) ) {
98
+ $this->_sendErrorResponse( __( 'Bad nonce', WPRSS_TEXT_DOMAIN ), $addon );
99
  }
100
 
101
  // Check addon, event and license
102
+ if ( $addon === null ) $this->_sendErrorResponse( __( 'No addon ID', WPRSS_TEXT_DOMAIN ) );
103
+ if ( $event === null ) $this->_sendErrorResponse( __( 'No event specified', WPRSS_TEXT_DOMAIN ), $addon );
104
+ if ( $licenseKey === null ) $this->_sendErrorResponse( __( 'No license', WPRSS_TEXT_DOMAIN ), $addon );
105
 
106
  $settings = $this->getSettingsController();
107
  $manager = $this->getManager();
127
  $eventMethod = sprintf( self::AJAX_MANAGE_LICENSE_METHOD_PATTERN, $event );
128
  // check if the event is handle-able
129
  if ( ! method_exists( $this, $eventMethod ) ) {
130
+ $this->_sendErrorResponse( __( 'Invalid event specified', WPRSS_TEXT_DOMAIN ), $addon);
131
  }
132
 
133
  // Call the appropriate handler method
153
  public function handleAjaxFetchLicense() {
154
  // If not addon ID in the request, stop
155
  if ( empty( $_GET['addon']) )
156
+ $this->_sendErrorResponse( __( 'No addon ID', WPRSS_TEXT_DOMAIN ) );
157
  // Get and sanitize the addon ID
158
  $addon = sanitize_text_field( $_GET['addon'] );
159
  // Get the license information from EDD
includes/Aventura/Wprss/Core/Licensing/Manager.php CHANGED
@@ -476,30 +476,27 @@ class Manager {
476
 
477
  // Prepare constants names
478
  $itemNameConstant = sprintf( 'WPRSS_%s_SL_ITEM_NAME', $addonUid );
 
479
 
480
  // Check for existence of constants
481
- if ( !defined($itemNameConstant) ) {
482
  return null;
483
  }
484
 
485
  // Get constant values
486
  $itemName = constant( $itemNameConstant );
 
487
  // Correct item name for lifetime variants
488
  $itemName = ($isLifetime)
489
  ? sprintf(static::LIFETIME_ITEM_NAME_PATTERN, $itemName)
490
  : $itemName;
491
 
492
- $requestData = [
493
- 'edd_action' => $action,
494
- 'license' => $license,
495
- 'item_name' => $itemName,
496
- ];
497
-
498
- $storeUrl = apply_filters('wpra/licensing/store_url', WPRSS_SL_STORE_URL, $addonId, $action, $license);
499
- $requestData = apply_filters('wpra/licensing/request', $requestData, $addonId, $action, $license);
500
-
501
  try {
502
- $licenseData = $this->api($storeUrl, $requestData);
 
 
 
 
503
  }
504
  catch ( RequestException $e ) {
505
  wprss_log( sprintf( 'Could not retrieve licensing data from "%1$s": %2$s', $storeUrl, $e->getMessage() ), __FUNCTION__, WPRSS_LOG_LEVEL_WARNING );
476
 
477
  // Prepare constants names
478
  $itemNameConstant = sprintf( 'WPRSS_%s_SL_ITEM_NAME', $addonUid );
479
+ $storeUrlConstant = sprintf( 'WPRSS_%s_SL_STORE_URL', $addonUid );
480
 
481
  // Check for existence of constants
482
+ if ( !defined($itemNameConstant) || !defined($storeUrlConstant) ) {
483
  return null;
484
  }
485
 
486
  // Get constant values
487
  $itemName = constant( $itemNameConstant );
488
+ $storeUrl = constant( $storeUrlConstant );
489
  // Correct item name for lifetime variants
490
  $itemName = ($isLifetime)
491
  ? sprintf(static::LIFETIME_ITEM_NAME_PATTERN, $itemName)
492
  : $itemName;
493
 
 
 
 
 
 
 
 
 
 
494
  try {
495
+ $licenseData = $this->api($storeUrl, $requestData = array(
496
+ 'edd_action' => $action,
497
+ 'license' => $license,
498
+ 'item_name' => $itemName,
499
+ ));
500
  }
501
  catch ( RequestException $e ) {
502
  wprss_log( sprintf( 'Could not retrieve licensing data from "%1$s": %2$s', $storeUrl, $e->getMessage() ), __FUNCTION__, WPRSS_LOG_LEVEL_WARNING );
includes/Aventura/Wprss/Core/Licensing/Settings.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
  namespace Aventura\Wprss\Core\Licensing;
4
- use WPRSS_MBString;
 
5
 
6
  /**
7
  * The licensing settings class.
@@ -76,35 +77,26 @@ class Settings {
76
 
77
  foreach ( $this->getManager()->getAddons() as $_addonId => $_addonName ) {
78
  $_year = date('Y');
79
- $emptyLicenseNotice = $factory->make(
80
- sprintf('%saddon_empty_license', WPRSS_NOTICE_SERVICE_ID_PREFIX),
81
- [
82
- 'addon_id' => $_addonId,
83
- 'addon_name' => $_addonName,
84
- 'settings' => $this
85
- ]
86
- );
87
  $noticesComponent->addNotice($emptyLicenseNotice);
88
 
89
- $inactiveLicenseNotice = $factory->make(
90
- sprintf('%saddon_inactive_license', WPRSS_NOTICE_SERVICE_ID_PREFIX),
91
- [
92
- 'addon_id' => $_addonId,
93
- 'addon_name' => $_addonName,
94
- 'settings' => $this
95
- ]
96
- );
97
  $noticesComponent->addNotice($inactiveLicenseNotice);
98
 
99
- $expiringLicenseNotice = $factory->make(
100
- sprintf('%saddon_expiring_license', WPRSS_NOTICE_SERVICE_ID_PREFIX),
101
- [
102
- 'addon_id' => $_addonId,
103
- 'addon_name' => $_addonName,
104
- 'settings' => $this,
105
- 'year' => $_year
106
- ]
107
- );
108
  $noticesComponent->addNotice($expiringLicenseNotice);
109
  }
110
 
@@ -149,7 +141,6 @@ class Settings {
149
  return false;
150
  }
151
  $license = $this->getManager()->getLicense( $args['addon'] );
152
-
153
  return $license !== null && strlen( $license->getKey() ) > 0 && ! $license->isValid();
154
  }
155
 
@@ -164,14 +155,12 @@ class Settings {
164
  return false;
165
  }
166
 
167
- if (!isset($args['addon'])) {
168
- return false;
169
- }
170
-
171
- $manager = $this->getManager();
172
- $license = $manager->getLicense($args['addon']);
173
-
174
- return $license && $license->isValid() && $manager->isLicenseExpiring($args['addon']);
175
  }
176
 
177
 
@@ -180,31 +169,31 @@ class Settings {
180
  */
181
  public function registerSettings() {
182
  // Iterate all addon IDs and register a settings section with 2 fields for each.
183
- foreach ($this->getManager()->getAddons() as $_addonId => $_addonName) {
184
  // Settings Section
185
  add_settings_section(
186
- sprintf('wprss_settings_%s_licenses_section', $_addonId),
187
- sprintf('%s %s', $_addonName, __('License', 'wprss')),
188
  '__return_empty_string',
189
  'wprss_settings_license_keys'
190
  );
191
  // License key field
192
  add_settings_field(
193
- sprintf('wprss_settings_%s_license', $_addonId),
194
- __('License key', 'wprss'),
195
- [$this, 'renderLicenseKeyField'],
196
  'wprss_settings_license_keys',
197
- sprintf('wprss_settings_%s_licenses_section', $_addonId),
198
- [$_addonId]
199
  );
200
  // Activate license button
201
  add_settings_field(
202
- sprintf('wprss_settings_%s_activate_license', $_addonId),
203
- __('Activate license', 'wprss'),
204
- [$this, 'renderActivateLicenseButton'],
205
  'wprss_settings_license_keys',
206
- sprintf('wprss_settings_%s_licenses_section', $_addonId),
207
- [$_addonId]
208
  );
209
  }
210
 
@@ -217,30 +206,20 @@ class Settings {
217
  * @since 4.4.5
218
  */
219
  public function renderLicenseKeyField( $args ) {
220
- if (count($args) < 1) {
221
- return;
222
- }
223
  // Addon ID is the first arg
224
  $addonId = $args[0];
225
  // Get the addon's license
226
  $license = $this->getManager()->getLicense( $addonId );
227
  // Mask it - if the license exists
228
- $displayedKey = $license !== null
229
- ? self::obfuscateLicenseKey( $license->getKey() )
230
- : '';
231
-
232
- printf(
233
- '<input id="wprss-%s-license-key" name="wprss_settings_license_keys[%s_license_key]" class="wprss-license-input" type="text" value="%s" style="width: 300px;" />',
234
- esc_attr($addonId),
235
- esc_attr($addonId),
236
- esc_attr($displayedKey)
237
- );
238
-
239
- printf(
240
- '<label class="description" for="wprss-%s-license-key">%s</label>',
241
- esc_attr($addonId),
242
- __('Enter your license key', 'wprss')
243
- );
244
  }
245
 
246
 
@@ -289,15 +268,18 @@ class Settings {
289
 
290
  /**
291
  * Invalidates the key if it is obfuscated, causing the saved version to be used.
292
- * This meant that the new key will not be saved, as it is considered then to be unchanged.
293
  *
294
  * @since 4.6.10
295
  * @param bool $is_valid Indicates whether the key is currently considered to be valid.
296
  * @param string $key The license key in question
297
- * @return bool Whether or not the key is still to be considered valid.
298
  */
299
  public function validateLicenseKeyForSave( $is_valid, $key ) {
300
- return !$this->isLicenseKeyObfuscated($key) && $is_valid;
 
 
 
301
  }
302
 
303
  /**
@@ -315,127 +297,93 @@ class Settings {
315
  if ( $status === 'item_name_mismatch' ) $status = 'invalid';
316
 
317
  $valid = $status == 'valid';
318
- $btnText = $valid
319
- ? __('Deactivate license', 'wprss')
320
- : __('Activate license');
321
  $btnName = "wprss_{$addonId}_license_" . ( $valid? 'deactivate' : 'activate' );
322
  $btnClass = "button-" . ( $valid ? 'deactivate' : 'activate' ) . "-license";
323
- wp_nonce_field( "wprss_{$addonId}_license_nonce", "wprss_{$addonId}_license_nonce", false );
324
-
325
- $icon = '';
326
- if ( $status === 'valid' ) {
327
- $icon = '<i class="fa fa-check"></i>';
328
- } elseif( $status === 'invalid' || $status === 'expired' ) {
329
- $icon = '<i class="fa fa-times"></i>';
330
- } elseif( $status === 'inactive' ) {
331
- $icon = '<i class="fa fa-warning"></i>';
332
- }
333
-
334
- printf(
335
- '<input type="button" class="%s button-process-license button-secondary" name="%s" value="%s" />',
336
- esc_attr($btnClass),
337
- esc_attr($btnName),
338
- esc_attr($btnText)
339
- );
340
-
341
- printf(
342
- '<span class="wprss-license-status-text">
343
- <strong>%s</strong>
344
- <span class="wprss-license-icon-%s">%s</span>
345
- </span>',
346
- __('Status', 'wprss'),
347
- esc_attr($status),
348
- $icon
349
- );
350
-
351
- $license = $manager->getLicense($addonId);
352
- $licenseValid = $license !== null && $license->isValid();
353
- $licenseKey = $license !== null ? $license->getKey() : null;
354
-
355
- if ($licenseValid && !empty($licenseKey)) {
356
- if (!is_object($data)) {
357
- printf(
358
- '<p><small>%s</small></p>',
359
- __(
360
- 'Failed to get license information. This is a temporary problem. Check your internet connection and try again later.',
361
- 'wprss'
362
- )
363
- );
364
- } else {
365
- $currentActivations = $data->site_count;
366
- $activationsLeft = $data->activations_left;
367
- $activationsLimit = $data->license_limit;
368
- $expires = $data->expires;
369
- $expiresSpace = strpos($expires, ' ');
370
- // if expiry has space, get only first word
371
- $expires = ($expiresSpace !== false)
372
- ? substr($expires, 0, $expiresSpace)
373
- : $expires;
374
- $expires = trim($expires);
375
- // change lifetime expiry to never
376
- $expires = ($expires === Manager::EXPIRATION_LIFETIME)
377
- ? __('never', 'wprss')
378
- : $expires;
379
-
380
- if (!empty($data->payment_id) && !empty($data->license_limit)) {
381
- echo '<p><small>';
382
-
383
- if ($status !== 'valid' && $activationsLeft === 0) {
384
- $accountUrl = sprintf(
385
- 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=%s',
386
- urlencode($data->payment_id)
387
- );
388
- printf(
389
- '<a href="%s">%s</a>',
390
- esc_attr($accountUrl),
391
- __(
392
- 'No activations left. Click here to manage the sites you\'ve activated licenses on.',
393
- 'wprss'
394
- )
395
- );
396
-
397
- echo '<br/>';
398
- }
399
-
400
- if (!empty($expires) && $expires !== 'never' && strtotime($expires) < strtotime("+2 weeks")) {
401
- $renewalUrl = sprintf(
402
- '%s/checkout/?edd_license_key=%s',
403
- WPRSS_SL_STORE_URL,
404
- urlencode($licenseKey)
405
- );
406
-
407
- printf(
408
- '<a href="%s">%s</a><br/>',
409
- esc_attr($renewalUrl),
410
- __('Renew your license to continue receiving updates and support.', 'wprss')
411
- );
412
-
413
- echo '<br/>';
414
- }
415
-
416
- printf('<strong>%s</strong> ', __('Activations:', 'wprss'));
417
- printf(
418
- '%s/%s (%s)',
419
- $currentActivations,
420
- $activationsLimit,
421
- sprintf(_x('%s left', 'Number of license activations remaining', 'wprss'), $activationsLeft)
422
- );
423
-
424
- echo '<br/>';
425
-
426
- if (!empty($expires)) {
427
- printf('<strong>%s</strong> ', __('Expires:', 'wprss'));
428
- printf('<code>%s</code>', esc_html($expires));
429
- echo '<br/>';
430
- }
431
-
432
- printf('<strong>%s</strong> ', __('Registered to:', 'wprss'));
433
- printf('%s (<code>%s</code>)', $data->customer_name, $data->customer_email);
434
-
435
- echo '</small></p>';
436
- }
437
  }
438
- }
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
440
 
441
  /**
1
  <?php
2
 
3
  namespace Aventura\Wprss\Core\Licensing;
4
+ use \Aventura\Wprss\Core\Licensing\License\Status;
5
+ use \WPRSS_MBString;
6
 
7
  /**
8
  * The licensing settings class.
77
 
78
  foreach ( $this->getManager()->getAddons() as $_addonId => $_addonName ) {
79
  $_year = date('Y');
80
+ $emptyLicenseNotice = $factory->make(sprintf('%saddon_empty_license', WPRSS_NOTICE_SERVICE_ID_PREFIX), array(
81
+ 'addon_id' => $_addonId,
82
+ 'addon_name' => $_addonName,
83
+ 'settings' => $this
84
+ ));
 
 
 
85
  $noticesComponent->addNotice($emptyLicenseNotice);
86
 
87
+ $inactiveLicenseNotice = $factory->make(sprintf('%saddon_inactive_license', WPRSS_NOTICE_SERVICE_ID_PREFIX), array(
88
+ 'addon_id' => $_addonId,
89
+ 'addon_name' => $_addonName,
90
+ 'settings' => $this
91
+ ));
 
 
 
92
  $noticesComponent->addNotice($inactiveLicenseNotice);
93
 
94
+ $expiringLicenseNotice = $factory->make(sprintf('%saddon_expiring_license', WPRSS_NOTICE_SERVICE_ID_PREFIX), array(
95
+ 'addon_id' => $_addonId,
96
+ 'addon_name' => $_addonName,
97
+ 'settings' => $this,
98
+ 'year' => $_year
99
+ ));
 
 
 
100
  $noticesComponent->addNotice($expiringLicenseNotice);
101
  }
102
 
141
  return false;
142
  }
143
  $license = $this->getManager()->getLicense( $args['addon'] );
 
144
  return $license !== null && strlen( $license->getKey() ) > 0 && ! $license->isValid();
145
  }
146
 
155
  return false;
156
  }
157
 
158
+ if ( ! isset( $args['addon'] ) ) return false;
159
+ $manager = $this->getManager();
160
+ if ( !($license = $manager->getLicense( $args['addon'] )) ) {
161
+ return false;
162
+ }
163
+ return $license->isValid() && $manager->isLicenseExpiring($args['addon']);
 
 
164
  }
165
 
166
 
169
  */
170
  public function registerSettings() {
171
  // Iterate all addon IDs and register a settings section with 2 fields for each.
172
+ foreach( $this->getManager()->getAddons() as $_addonId => $_addonName ) {
173
  // Settings Section
174
  add_settings_section(
175
+ sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
176
+ sprintf( '%s %s', $_addonName, __( 'License', WPRSS_TEXT_DOMAIN ) ),
177
  '__return_empty_string',
178
  'wprss_settings_license_keys'
179
  );
180
  // License key field
181
  add_settings_field(
182
+ sprintf( 'wprss_settings_%s_license', $_addonId ),
183
+ __( 'License key', WPRSS_TEXT_DOMAIN ),
184
+ array( $this, 'renderLicenseKeyField' ),
185
  'wprss_settings_license_keys',
186
+ sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
187
+ array( $_addonId )
188
  );
189
  // Activate license button
190
  add_settings_field(
191
+ sprintf( 'wprss_settings_%s_activate_license', $_addonId ),
192
+ __( 'Activate license', WPRSS_TEXT_DOMAIN ),
193
+ array( $this, 'renderActivateLicenseButton' ),
194
  'wprss_settings_license_keys',
195
+ sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
196
+ array( $_addonId )
197
  );
198
  }
199
 
206
  * @since 4.4.5
207
  */
208
  public function renderLicenseKeyField( $args ) {
209
+ if ( count( $args ) < 1 ) return;
 
 
210
  // Addon ID is the first arg
211
  $addonId = $args[0];
212
  // Get the addon's license
213
  $license = $this->getManager()->getLicense( $addonId );
214
  // Mask it - if the license exists
215
+ $displayedKey = is_null( $license )? '' : self::obfuscateLicenseKey( $license->getKey() );
216
+ // Render the markup ?>
217
+ <input id="wprss-<?php echo $addonId ?>-license-key" name="wprss_settings_license_keys[<?php echo $addonId ?>_license_key]"
218
+ class="wprss-license-input" type="text" value="<?php echo esc_attr( $displayedKey ) ?>" style="width: 300px;"
219
+ />
220
+ <label class="description" for="wprss-<?php echo $addonId ?>-license-key">
221
+ <?php _e( 'Enter your license key', WPRSS_TEXT_DOMAIN ) ?>
222
+ </label><?php
 
 
 
 
 
 
 
 
223
  }
224
 
225
 
268
 
269
  /**
270
  * Invalidates the key if it is obfuscated, causing the saved version to be used.
271
+ * This meanst that the new key will not be saved, as it is considered then to be unchanged.
272
  *
273
  * @since 4.6.10
274
  * @param bool $is_valid Indicates whether the key is currently considered to be valid.
275
  * @param string $key The license key in question
276
+ * @return Whether or not the key is still to be considered valid.
277
  */
278
  public function validateLicenseKeyForSave( $is_valid, $key ) {
279
+ if ( $this->isLicenseKeyObfuscated( $key ) )
280
+ return false;
281
+
282
+ return $is_valid;
283
  }
284
 
285
  /**
297
  if ( $status === 'item_name_mismatch' ) $status = 'invalid';
298
 
299
  $valid = $status == 'valid';
300
+ $btnText = $valid ? 'Deactivate license' : 'Activate license';
 
 
301
  $btnName = "wprss_{$addonId}_license_" . ( $valid? 'deactivate' : 'activate' );
302
  $btnClass = "button-" . ( $valid ? 'deactivate' : 'activate' ) . "-license";
303
+ wp_nonce_field( "wprss_{$addonId}_license_nonce", "wprss_{$addonId}_license_nonce", false ); ?>
304
+
305
+ <input type="button" class="<?php echo $btnClass; ?> button-process-license button-secondary" name="<?php echo $btnName; ?>" value="<?php _e( $btnText, WPRSS_TEXT_DOMAIN ); ?>" />
306
+ <span id="wprss-<?php echo $addonId; ?>-license-status-text">
307
+ <strong><?php _e('Status', WPRSS_TEXT_DOMAIN); ?>:
308
+ <span class="wprss-<?php echo $addonId; ?>-license-<?php echo $status; ?>">
309
+ <?php _e( ucfirst($status), WPRSS_TEXT_DOMAIN ); ?>
310
+ <?php if ( $status === 'valid' ) : ?>
311
+ <i class="fa fa-check"></i>
312
+ <?php elseif( $status === 'invalid' || $status === 'expired' ): ?>
313
+ <i class="fa fa-times"></i>
314
+ <?php elseif( $status === 'inactive' ): ?>
315
+ <i class="fa fa-warning"></i>
316
+ <?php endif; ?>
317
+ </strong>
318
+ </span>
319
+ </span>
320
+
321
+ <p>
322
+ <?php
323
+ $license = $manager->getLicense( $addonId );
324
+ if ( $license !== null && !$license->isInvalid() && ($licenseKey = $license->getKey()) && !empty( $licenseKey ) ) :
325
+ if ( is_object( $data ) ) :
326
+ $currentActivations = $data->site_count;
327
+ $activationsLeft = $data->activations_left;
328
+ $activationsLimit = $data->license_limit;
329
+ $expires = $data->expires;
330
+ $expiresSpace = strpos($expires, ' ');
331
+ // if expiry has space, get only first word
332
+ $expires = ( $expiresSpace !== false ) ? substr( $expires, 0, $expiresSpace ) : $expires;
333
+ $expires = trim($expires);
334
+ // change lifetime expiry to never
335
+ $expires = ($expires === Manager::EXPIRATION_LIFETIME) ? __('never', WPRSS_TEXT_DOMAIN) : $expires;
336
+
337
+ // If the license key is garbage, don't show any of the data.
338
+ if ( !empty($data->payment_id) && !empty($data->license_limit ) ) :
339
+ ?>
340
+ <small>
341
+ <?php if ( $status !== 'valid' && $activationsLeft === 0 ) : ?>
342
+ <?php $accountUrl = 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=' . $data->payment_id; ?>
343
+ <a href="<?php echo $accountUrl; ?>"><?php _e("No activations left. Click here to manage the sites you've activated licenses on.", WPRSS_TEXT_DOMAIN); ?></a>
344
+ <br/>
345
+ <?php endif; ?>
346
+ <?php if ( !empty($expires) && $expires !== 'never' && strtotime($expires) < strtotime("+2 weeks") ) : ?>
347
+ <?php $renewalUrl = esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $licenseKey); ?>
348
+ <a href="<?php echo $renewalUrl; ?>"><?php _e('Renew your license to continue receiving updates and support.', WPRSS_TEXT_DOMAIN); ?></a>
349
+ <br/>
350
+ <?php endif; ?>
351
+ <strong><?php _e('Activations', WPRSS_TEXT_DOMAIN); ?>:</strong>
352
+ <?php echo $currentActivations.'/'.$activationsLimit; ?> (<?php echo $activationsLeft; ?> left)
353
+ <br/>
354
+ <?php if ( !empty($expires) ) : ?>
355
+ <strong><?php _e('Expires', WPRSS_TEXT_DOMAIN); ?>:</strong>
356
+ <code><?php echo $expires; ?></code>
357
+ <br/>
358
+ <?php endif; ?>
359
+ <strong><?php _e('Registered to', WPRSS_TEXT_DOMAIN); ?>:</strong>
360
+ <?php echo $data->customer_name; ?> (<code><?php echo $data->customer_email; ?></code>)
361
+ </small>
362
+ <?php endif; ?>
363
+ <?php else: ?>
364
+ <small><?php _e('Failed to get license information. This is a temporary problem. Check your internet connection and try again later.', WPRSS_TEXT_DOMAIN); ?></small>
365
+ <?php endif; ?>
366
+ <?php endif;
367
+ ?>
368
+ </p>
369
+
370
+ <style type="text/css">
371
+ .wprss-<?php echo $addonId; ?>-license-valid {
372
+ color: green;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  }
374
+ .wprss-<?php echo $addonId; ?>-license-invalid, .wprss-<?php echo $addonId; ?>-license-expired {
375
+ color: #b71919;
376
+ }
377
+ .wprss-<?php echo $addonId; ?>-license-inactive {
378
+ color: #d19e5b;
379
+ }
380
+ #wprss-<?php echo $addonId; ?>-license-status-text {
381
+ margin-left: 8px;
382
+ line-height: 27px;
383
+ vertical-align: middle;
384
+ }
385
+ </style>
386
+ <?php
387
  }
388
 
389
  /**
includes/Aventura/Wprss/Core/Model/AdminAjaxNotice/ServiceProvider.php CHANGED
@@ -68,7 +68,7 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
68
  $config = $this->_normalizeConfig($config, array(
69
  'setting_code' => 'wprss_admin_notices',
70
  'id_prefix' => 'wprss_',
71
- 'text_domain' => 'wprss'
72
  ));
73
  // Initialize collection
74
  $controller = new \WPRSS_Admin_Notices($config);
@@ -424,10 +424,7 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
424
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
425
  return $me->_autoParagraph(
426
  sprintf(
427
- __(
428
- 'Remember to <a href="%1$s">enter your license key</a> for the <strong>WP RSS Aggregator - %2$s</strong> add-on to benefit from updates and support.',
429
- 'wprss'
430
- ),
431
  esc_attr( admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ),
432
  $addonName
433
  )
@@ -471,10 +468,7 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
471
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
472
  return $me->_autoParagraph(
473
  sprintf(
474
- __(
475
- 'The license key for the <strong>WP RSS Aggregator - %2$s</strong> add-on is saved but not activated. In order to benefit from updates and support, it must be <a href="%1$s">activated</a>.',
476
- 'wprss'
477
- ),
478
  esc_attr( admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ),
479
  $addonName
480
  )
@@ -521,10 +515,7 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
521
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
522
  return $me->_autoParagraph(
523
  sprintf(
524
- __(
525
- 'The license for the <strong>WP RSS Aggregator - %2$s</strong> add-on is about to expire. <a href="%1$s">Please renew it</a> to keep receiving updates and benefit from support.',
526
- 'wprss'
527
- ),
528
  esc_attr( 'https://docs.wprssaggregator.com/renewing-your-license/' ),
529
  $addonName
530
  )
68
  $config = $this->_normalizeConfig($config, array(
69
  'setting_code' => 'wprss_admin_notices',
70
  'id_prefix' => 'wprss_',
71
+ 'text_domain' => \WPRSS_TEXT_DOMAIN
72
  ));
73
  // Initialize collection
74
  $controller = new \WPRSS_Admin_Notices($config);
424
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
425
  return $me->_autoParagraph(
426
  sprintf(
427
+ __( 'Remember to <a href="%1$s">enter your license key</a> for the <strong>WP RSS Aggregator - %2$s</strong> add-on to benefit from updates and support.', WPRSS_TEXT_DOMAIN ),
 
 
 
428
  esc_attr( admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ),
429
  $addonName
430
  )
468
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
469
  return $me->_autoParagraph(
470
  sprintf(
471
+ __( 'The license key for the <strong>WP RSS Aggregator - %2$s</strong> add-on is saved but not activated. In order to benefit from updates and support, it must be <a href="%1$s">activated</a>.', WPRSS_TEXT_DOMAIN ),
 
 
 
472
  esc_attr( admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ),
473
  $addonName
474
  )
515
  'content' => new CallbackBlock(array(), function() use ($addonName, &$me) {
516
  return $me->_autoParagraph(
517
  sprintf(
518
+ __( 'The license for the <strong>WP RSS Aggregator - %2$s</strong> add-on is about to expire. <a href="%1$s">Please renew it</a> to keep receiving updates and benefit from support.', WPRSS_TEXT_DOMAIN ),
 
 
 
519
  esc_attr( 'https://docs.wprssaggregator.com/renewing-your-license/' ),
520
  $addonName
521
  )
includes/Aventura/Wprss/Core/ServiceProvider.php CHANGED
@@ -192,7 +192,7 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
192
  */
193
  public function _createTranslator(ContainerInterface $c, $p = null, $config = null)
194
  {
195
- $textDomain = 'wprss';
196
  $helper = $c->get($this->_p('admin_helper'));
197
  /* @var $helper \Aventura\Wprss\Core\Component\AdminHelper */
198
  $command = $helper->createCommand(array(
192
  */
193
  public function _createTranslator(ContainerInterface $c, $p = null, $config = null)
194
  {
195
+ $textDomain = \WPRSS_TEXT_DOMAIN;
196
  $helper = $c->get($this->_p('admin_helper'));
197
  /* @var $helper \Aventura\Wprss\Core\Component\AdminHelper */
198
  $command = $helper->createCommand(array(
includes/OPML.php CHANGED
@@ -39,10 +39,7 @@ class WPRSS_OPML {
39
 
40
  } catch (Exception $e) {
41
  // If an exception is caught. Throw an error message
42
- throw new Exception(
43
- __('An error occurred: The file might not be a valid OPML file or is corrupt. ', 'wprss'),
44
- 1
45
- );
46
  }
47
  }
48
 
39
 
40
  } catch (Exception $e) {
41
  // If an exception is caught. Throw an error message
42
+ throw new Exception( __( 'An error occurred: The file might not be a valid OPML file or is corrupt. ', WPRSS_TEXT_DOMAIN ), 1);
 
 
 
43
  }
44
  }
45
 
includes/admin-activate.php CHANGED
@@ -22,8 +22,7 @@ add_action('admin_init', function () {
22
  delete_transient('_wprss_activation_redirect');
23
 
24
  // Continue only if activating from a non-network site and not bulk activating plugins
25
- $bulkActivate = filter_input(INPUT_GET, 'activate-multi');
26
- if (is_network_admin() || $bulkActivate) {
27
  return;
28
  }
29
 
22
  delete_transient('_wprss_activation_redirect');
23
 
24
  // Continue only if activating from a non-network site and not bulk activating plugins
25
+ if (is_network_admin() || isset($_GET['activate-multi'])) {
 
26
  return;
27
  }
28
 
includes/admin-ajax-notice.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
- use Aventura\Wprss\Core\Model\AdminAjaxNotice\NoticeInterface;
4
  use Aventura\Wprss\Core\Model\AdminAjaxNotice\ServiceProvider;
5
  use Dhii\Di\WritableContainerInterface;
 
6
 
7
  define ('WPRSS_NOTICE_SERVICE_ID_PREFIX', WPRSS_SERVICE_ID_PREFIX . 'notice.');
8
 
@@ -58,35 +58,53 @@ define ('WPRSS_NOTICE_SERVICE_ID_PREFIX', WPRSS_SERVICE_ID_PREFIX . 'notice.');
58
  * @since 3.4.2
59
  */
60
  function wprss_dismiss_addon_notice() {
61
- check_admin_referer('wprss_admin_addon_ajax');
62
- $addon = isset($_POST['addon'])? $_POST['addon'] : null;
63
- if ($addon === null) {
64
  echo 'false';
65
- die;
66
  }
67
- $addon = strip_tags($addon);
68
- $notice = isset($_POST['notice'])? $_POST['notice'] : null;
69
- if ($notice === null) {
70
  echo 'false';
71
- die;
72
  }
73
 
74
  $notices = wprss_check_addon_notice_option();
75
- if (isset($notices[$addon])) {
76
  $notices[$addon] = array();
77
  }
78
- if (isset($notices[$addon][$addon])) {
79
  $notices[$addon][$notice] = '1';
80
  }
81
  update_option( 'wprss_addon_notices', $notices );
82
  echo 'true';
83
 
84
- die;
85
  }
86
 
87
  add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
88
 
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  /**
91
  * Responsible for tracking and outputting admin notices
92
  *
@@ -1058,49 +1076,22 @@ class WPRSS_Admin_Notices {
1058
 
1059
  ob_start();
1060
  $notice = apply_filters( $this->prefix( 'admin_notice_render_before' ), $notice, $this );
1061
-
1062
- $noticeId = esc_attr($notice['id']);
1063
- $content = $notice['content'];
1064
-
1065
- $type = $notice['notice_type'];
1066
- $baseClass = $this->get_notice_base_class();
1067
- $elemClass = $notice['notice_element_class'];
1068
- $dismissMode = $notice['dismiss_mode'];
1069
- $fullClass = esc_attr("{$type} {$elemClass} {$baseClass} dismiss-mode-{$dismissMode}");
1070
-
1071
- $nonce = $notice['nonce'];
1072
- $nonceId = esc_attr($notice['nonce_element_id']);
1073
- $nonceElemClass = $notice['nonce_element_class'];
1074
- $nonceBaseClass = $this->get_nonce_base_class();
1075
- $nonceFullClass = esc_attr("hidden {$nonceElemClass} {$nonceBaseClass}");
1076
  ?>
1077
 
1078
- <div id="<?= $noticeId ?>" class="<?= $fullClass ?>">
1079
  <div class="notice-inside">
1080
- <?= $content ?>
1081
  </div>
1082
- <?php if ($dismissMode !== NoticeInterface::DISMISS_MODE_NONE):
1083
- $btnId = esc_attr($notice['btn_close_id']);
1084
- $btnContent = $notice['btn_close_content'];
1085
- $btnElemClass = $notice['btn_close_class'];
1086
- $btnBaseClass = $this->get_btn_close_base_class();
1087
- $btnFullClass = esc_attr("{$btnBaseClass} {$btnElemClass}");
1088
- ?>
1089
- <a href="javascript:void(0);" id="<?= $btnId ?>" style="float:right;" class="<?= $btnFullClass ?>">
1090
- <?= $btnContent ?>
1091
- </a>
1092
- <?php endif ?>
1093
- <span id="<?= $nonceId ?>" class="<?= $nonceFullClass ?>">
1094
- <?= $helper->resolveValue($nonce) ?>
1095
- </span>
1096
  </div>
1097
-
1098
  <?php
 
 
1099
 
1100
- do_action($this->prefix('admin_notice_render_after'), $notice, $this);
1101
- $output = ob_get_clean();
1102
-
1103
- return apply_filters($this->prefix('admin_notice_rendered'), $output, $notice, $this);
1104
  }
1105
 
1106
 
@@ -1120,9 +1111,9 @@ class WPRSS_Admin_Notices {
1120
 
1121
  $notice_id = $notice;
1122
  if ( is_null( $notice ) )
1123
- throw new Exception('Could not hide notice: Notice ID must be specified');
1124
  if ( is_null( $nonce ) )
1125
- throw new Exception('Could not hide notice: nonce must be specified');
1126
  if ( !($notice = $this->get_notices( $notice ) ) )
1127
  throw new Exception( sprintf( 'Could not hide notice: No notice found for ID "%1$s"', $notice_id ) );
1128
 
@@ -1224,22 +1215,19 @@ add_action( sprintf( 'wp_ajax_%1$s', wprss_admin_notice_get_action_code() ), 'wp
1224
  * @since 4.7.4
1225
  */
1226
  function wprss_admin_notice_hide() {
1227
- $notice_id = isset($_REQUEST['notice_id']) ? $_REQUEST['notice_id'] : null;
1228
- $notice_id = filter_var($notice_id, FILTER_SANITIZE_STRING);
1229
-
1230
- $nonce = isset($_REQUEST['nonce']) ? $_REQUEST['nonce'] : null;
1231
- $nonce = filter_var($nonce, FILTER_SANITIZE_STRING);
1232
 
1233
  try {
1234
- wprss_admin_notice_get_collection()->hide_notice($notice_id, $nonce);
1235
- } catch (Exception $e) {
1236
- // Failure
1237
- echo $e->getMessage();
1238
- exit();
1239
- }
1240
 
1241
  // Success
1242
- exit('1');
1243
  }
1244
 
1245
 
1
  <?php
2
 
 
3
  use Aventura\Wprss\Core\Model\AdminAjaxNotice\ServiceProvider;
4
  use Dhii\Di\WritableContainerInterface;
5
+ use Aventura\Wprss\Core\Model\AdminAjaxNotice\NoticeInterface;
6
 
7
  define ('WPRSS_NOTICE_SERVICE_ID_PREFIX', WPRSS_SERVICE_ID_PREFIX . 'notice.');
8
 
58
  * @since 3.4.2
59
  */
60
  function wprss_dismiss_addon_notice() {
61
+ $addon = ( isset( $_POST['addon'] ) === TRUE )? $_POST['addon'] : null;
62
+ if ( $addon === null ) {
 
63
  echo 'false';
64
+ die();
65
  }
66
+ $notice = ( isset( $_POST['notice'] ) === TRUE )? $_POST['notice'] : null;
67
+ if ( $notice === null ){
 
68
  echo 'false';
69
+ die();
70
  }
71
 
72
  $notices = wprss_check_addon_notice_option();
73
+ if ( isset( $notices[$addon] ) === FALSE ) {
74
  $notices[$addon] = array();
75
  }
76
+ if ( isset( $notices[$addon][$addon] ) === FALSE ) {
77
  $notices[$addon][$notice] = '1';
78
  }
79
  update_option( 'wprss_addon_notices', $notices );
80
  echo 'true';
81
 
82
+ die();
83
  }
84
 
85
  add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
86
 
87
 
88
+
89
+
90
+ /**
91
+ * AJAX action for the tracking pointer
92
+ *
93
+ * @since 3.6
94
+ */
95
+ function wprss_tracking_ajax_opt() {
96
+ if ( isset( $_POST['opted'] ) ){
97
+ $opted = $_POST['opted'];
98
+ $settings = get_option( 'wprss_settings_general' );
99
+ $settings['tracking'] = $opted;
100
+ update_option( 'wprss_settings_general', $settings );
101
+ }
102
+ die();
103
+ }
104
+
105
+ add_action( 'wp_ajax_wprss_tracking_ajax_opt', 'wprss_tracking_ajax_opt' );
106
+
107
+
108
  /**
109
  * Responsible for tracking and outputting admin notices
110
  *
1076
 
1077
  ob_start();
1078
  $notice = apply_filters( $this->prefix( 'admin_notice_render_before' ), $notice, $this );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1079
  ?>
1080
 
1081
+ <div id="<?php echo $notice['id'] ?>" class="<?php echo $notice['notice_type'] ?> <?php echo $notice['notice_element_class'] ?> <?php echo $this->get_notice_base_class() ?> dismiss-mode-<?php echo $notice['dismiss_mode'] ?>">
1082
  <div class="notice-inside">
1083
+ <?php echo $notice['content'] ?>
1084
  </div>
1085
+ <?php if ($notice['dismiss_mode'] !== NoticeInterface::DISMISS_MODE_NONE): ?>
1086
+ <a href="javascript:;" id="<?php echo $notice['btn_close_id'] ?>" style="float:right;" class="<?php echo $this->get_btn_close_base_class() ?> <?php echo $notice['btn_close_class'] ?>"><?php echo $notice['btn_close_content'] ?></a>
1087
+ <?php endif ?>
1088
+ <span id="<?php echo $notice['nonce_element_id'] ?>" class="hidden <?php echo $notice['nonce_element_class'] ?> <?php echo $this->get_nonce_base_class() ?>"><?php echo $helper->resolveValue($notice['nonce']) ?></span>
 
 
 
 
 
 
 
 
 
 
1089
  </div>
 
1090
  <?php
1091
+ do_action( $this->prefix( 'admin_notice_render_after' ), $notice, $this );
1092
+ $output = ob_get_clean();
1093
 
1094
+ return apply_filters( $this->prefix( 'admin_notice_rendered' ), $output, $notice, $this );
 
 
 
1095
  }
1096
 
1097
 
1111
 
1112
  $notice_id = $notice;
1113
  if ( is_null( $notice ) )
1114
+ throw new Exception( sprintf( 'Could not hide notice: Notice ID must be specified' ) );
1115
  if ( is_null( $nonce ) )
1116
+ throw new Exception( sprintf( 'Could not hide notice: nonce must be specified' ) );
1117
  if ( !($notice = $this->get_notices( $notice ) ) )
1118
  throw new Exception( sprintf( 'Could not hide notice: No notice found for ID "%1$s"', $notice_id ) );
1119
 
1215
  * @since 4.7.4
1216
  */
1217
  function wprss_admin_notice_hide() {
1218
+ $notice_id = isset( $_REQUEST['notice_id'] ) ? $_REQUEST['notice_id'] : null;
1219
+ $nonce = isset( $_REQUEST['nonce'] ) ? $_REQUEST['nonce'] : null;
 
 
 
1220
 
1221
  try {
1222
+ wprss_admin_notice_get_collection()->hide_notice( $notice_id, $nonce );
1223
+ } catch (Exception $e) {
1224
+ // Failure
1225
+ echo $e->getMessage();
1226
+ exit();
1227
+ }
1228
 
1229
  // Success
1230
+ exit( '1' );
1231
  }
1232
 
1233
 
includes/admin-display.php CHANGED
@@ -1,70 +1,75 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- // Adds the "active" class to the feed source list table rows, for active feed sources
4
- add_filter('post_class', function ($classes, $class, $postId) {
5
- $post = get_post($postId);
6
 
7
- if ($post->post_type !== 'wprss_feed') {
8
  return $classes;
9
- }
10
 
11
- if (wprss_is_feed_source_active($postId)) {
12
- $classes[] = 'active';
13
- }
 
 
 
 
 
14
 
15
- return $classes;
16
- }, 10, 3);
17
-
18
- add_filter('manage_wprss_feed_posts_columns', 'wprss_set_feed_custom_columns', 20, 1);
19
- /**
20
- * Set up the custom columns for the wprss_feed list
21
- *
22
- * @since 2.0
23
- */
24
- function wprss_set_feed_custom_columns($columns)
25
- {
26
- $isTrashPage = filter_input(INPUT_GET, 'post_status') === 'trash';
27
-
28
- $columns = [
29
- 'cb' => '<input type="checkbox" />',
30
- ];
31
-
32
- if (!$isTrashPage) {
33
- $columns['state'] = __('State', 'wprss');
34
- }
35
 
36
- $columns['title'] = __('Name', 'wprss');
37
 
38
- $columns = apply_filters('wprss_set_feed_custom_columns', $columns);
 
 
 
39
 
40
- if (!$isTrashPage) {
41
- $columns['updates'] = __('Updates', 'wprss');
42
- $columns['feed-count'] = __(apply_filters('wprss_feed_items_count_column', 'Imported items'), 'wprss');
43
  }
44
 
45
- return apply_filters('wprss_feed_columns', $columns);
46
- }
47
-
48
- add_action("manage_wprss_feed_posts_custom_column", "wprss_show_custom_columns", 10, 2);
49
- /**
50
- * Show up the custom columns for the wprss_feed list
51
- *
52
- * @since 2.0
53
- */
54
- function wprss_show_custom_columns($column, $post_id)
55
- {
56
- switch ($column) {
57
  case 'state':
58
  $switch_title = __('Activate or pause auto importing for this feed', 'wprss');
59
  ?>
60
- <div class="wprss-feed-state-container" title="<?= esc_attr($switch_title); ?>">
61
  <label class="wprss-switch">
62
- <input
63
- type="checkbox"
64
- class="wprss-toggle-feed-state"
65
- autocomplete="off"
66
- value="<?= esc_attr($post_id); ?>"
67
- <?php checked(true, wprss_is_feed_source_active($post_id)) ?>
68
  />
69
  <span class="wprss-switch-slider"></span>
70
  </label>
@@ -82,68 +87,56 @@ function wprss_show_custom_columns($column, $post_id)
82
  }
83
  ?>
84
 
85
- <div
86
- class="wprss-feed-source-type wprss-feed-source-type-<?= esc_attr($feed_type) ?>"
87
- title="<?= esc_attr($icon_title) ?>"
88
  >
89
- <span class="dashicons dashicons-<?= esc_attr($feed_icon) ?>"></span>
90
  </div>
91
  <?php
92
 
93
- break;
94
 
95
  case 'updates':
96
  // Get the update interval
97
- $update_interval = get_post_meta($post_id, 'wprss_update_interval', true);
98
  // Get the last updated and next update data
99
- $last_update = get_post_meta($post_id, 'wprss_last_update', true);
100
- $last_update_items = get_post_meta($post_id, 'wprss_last_update_items', true);
101
- $next_update = wprss_get_next_feed_source_update($post_id);
102
 
103
  // If using the global interval, get the timestamp of the next global update
104
- if ($update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '') {
105
- $next_update = wp_next_scheduled('wprss_fetch_all_feeds_hook', []);
106
  }
107
 
108
- // Update the meta field
109
- if (wprss_is_feed_source_active($post_id)) {
110
- $next_update_text = $next_update === false
111
- ? __('None', 'wprss')
112
- : human_time_diff($next_update, time());
113
- } else {
114
- $next_update_text = __('...', 'wprss');
115
- }
116
- update_post_meta($post_id, 'wprss_next_update', $next_update_text);
117
 
118
- $timeAgo = empty($last_update)
119
- ? ''
120
- : human_time_diff($last_update, time());
121
  ?>
122
 
123
  <p class="next-update-container">
124
- <?= __('Next update in', 'wprss') ?>
125
  <code class="next-update">
126
- <?= esc_html($next_update_text); ?>
127
  </code>
128
  </p>
129
 
130
- <p
131
- class="last-update-container"
132
- style="display: <?php echo empty($timeAgo) ? 'none' : 'inline-block'; ?>">
133
  <span class="last-update-num-items-container">
134
- <?= _x('Updated', 'Example: "Updated 2 days ago"', 'wprss'); ?>
135
  <span class="last-update-time-container">
136
- <code class="last-update-time">
137
- <?php printf(__('%1$s ago', 'wprss'), $timeAgo) ?>
138
- </code>
139
  </span>
140
- (
141
- <span class="last-update-num-items">
142
- <?= esc_html($last_update_items) ?>
143
- </span>
144
-
145
- <?= _x('items', 'Example: "15 new"', 'wprss'); ?>
146
- )
147
  </span>
148
  </p>
149
 
@@ -151,646 +144,607 @@ function wprss_show_custom_columns($column, $post_id)
151
  break;
152
 
153
  case 'feed-count':
154
- $items = wprss_get_feed_items_for_source($post_id);
155
  $has_items_class = ($items->post_count > 0) ? 'has-imported-items' : '';
156
 
157
- $errors = get_post_meta($post_id, 'wprss_error_last_import', true);
158
- $errorShowClass = ($errors !== '') ? 'wprss-show' : '';
159
- $default_msg = __(
160
- "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.",
161
- 'wprss'
162
- );
163
- $msg = strlen($errors) > 0
164
- ? $errors
165
- : $default_msg;
166
-
167
  $errorIcon = sprintf(
168
  '<i title="%1$s" class="fa fa-warning fa-fw wprss-feed-error-symbol %2$s"></i>',
169
  esc_attr($msg),
170
- esc_attr($errorShowClass)
171
  );
172
 
173
- $view_items_url = admin_url('edit.php?post_type=wprss_feed_item&wprss_feed=' . $post_id);
174
- $view_items_url = apply_filters('wprss_view_feed_items_row_action_link', $view_items_url, $post_id);
175
  ?>
176
- <a
177
- href="<?= esc_attr($view_items_url); ?>"
178
- class="items-imported-link <?= esc_attr($has_items_class); ?>"
179
- title="<?= esc_attr(__('View the imported items for this feed source', 'wprss')); ?>"
180
- >
181
- <span class="items-imported">
182
- <?= esc_attr($items->post_count) ?>
183
- </span>
184
- <?= __('items', 'wprss') ?>
185
- </a>
186
  <div class="spinner"></div>
187
 
188
- <?= $errorIcon ?>
189
-
190
- <div class="row-actions">
191
- <span class="fetch">
192
- <a
193
- href="javascript:void(0);"
194
- class="wprss_fetch_items_ajax_action"
195
- pid="<?= esc_attr($post_id); ?>"
196
- purl="<?= esc_attr(admin_url('admin-ajax.php')); ?>">
197
- <?= esc_html(__('Fetch', 'wprss')); ?>
198
- </a>
199
- </span>
200
- <span class="purge-posts trash <?= esc_attr($has_items_class) ?>">
201
  |
202
- <a
203
- href="javascript:void(0);"
204
- class="wprss_delete_items_ajax_action"
205
- pid="<?= esc_attr($post_id); ?>"
206
- purl="<?= esc_attr(admin_url('admin-ajax.php')); ?>">
207
- <?= esc_html(__('Delete items', 'wprss')) ?>
208
  </a>
209
  </span>
210
- </div>
211
- <?php
212
 
213
- // Set meta field for items imported
214
- update_post_meta($post_id, 'wprss_items_imported', $items->post_count);
215
 
216
  break;
217
- }
218
- }
219
-
220
- add_filter("manage_edit-wprss_feed_sortable_columns", "wprss_feed_sortable_columns");
221
- /**
222
- * Make the custom columns sortable for wprss_feed post type
223
- *
224
- * @since 2.0
225
- */
226
- function wprss_feed_sortable_columns()
227
- {
228
- $sortable_columns = [
229
- // meta column id => sort by value used in query
230
- 'state' => 'state',
231
- 'title' => 'title',
232
- 'updates' => 'updates',
233
- 'feed-count' => 'feed-count',
234
- ];
235
-
236
- return apply_filters('wprss_feed_sortable_columns', $sortable_columns);
237
- }
238
-
239
- add_action('pre_get_posts', 'wprss_feed_source_order');
240
- /**
241
- * Change order of feed sources to alphabetical ascending according to feed name
242
- *
243
- * @since 2.2
244
- */
245
- function wprss_feed_source_order($query)
246
- {
247
- // Check if the query is being processed in WP Admin, is the main query, and is targeted
248
- // for the wprss_feed CPT. If not, stop
249
- if (!is_admin() || !$query->is_main_query() || $query->get('post_type') !== 'wprss_feed') {
250
- return;
251
  }
252
 
253
- // Get the sorting query args
254
- $order = strtoupper($query->get('order'));
255
- $orderby = $query->get('orderby');
256
 
257
- // If order is not specified, default to ascending
258
- if ($order !== 'ASC' && $order !== 'DESC') {
259
- $order = 'ASC';
 
 
 
 
 
 
 
 
 
 
 
 
260
  }
261
 
262
- $query->set('order', $order);
263
 
264
- // If not explicitly sorting or sorting by title, sort by title
265
- if (!$orderby || $orderby === 'title') {
266
- $query->set('orderby', 'title');
267
- }
 
 
 
 
 
 
 
 
268
 
269
- // Check what we are sorting by
270
- switch ($orderby) {
271
- case 'state':
272
- $query->set('meta_key', 'wprss_state');
273
- $query->set('orderby', 'meta_value');
274
- break;
275
 
276
- case 'updates':
277
- $query->set('meta_key', 'wprss_next_update');
278
- $query->set('orderby', 'meta_value');
 
279
 
280
- break;
281
- case 'feed-count':
282
- $query->set('meta_key', 'wprss_items_imported');
283
- $query->set('orderby', 'meta_value_num');
284
 
285
- break;
286
- }
287
- }
288
-
289
- add_filter('manage_wprss_feed_item_posts_columns', 'wprss_set_feed_item_custom_columns', 20, 1);
290
- /**
291
- * Set up the custom columns for the wprss_feed source list
292
- *
293
- * @since 2.0
294
- */
295
- function wprss_set_feed_item_custom_columns($columns)
296
- {
297
- return apply_filters('wprss_set_feed_item_custom_columns', [
298
- 'cb' => '<input type="checkbox" />',
299
- 'title' => __('Name', 'wprss'),
300
- 'permalink' => __('Permalink', 'wprss'),
301
- 'publishdate' => __('Date published', 'wprss'),
302
- 'source' => __('Source', 'wprss'),
303
- ]);
304
- }
305
-
306
- add_action("manage_wprss_feed_item_posts_custom_column", "wprss_show_feed_item_custom_columns", 10, 2);
307
- /**
308
- * Show up the custom columns for the wprss_feed list
309
- *
310
- * @since 2.0
311
- */
312
- function wprss_show_feed_item_custom_columns($column, $post_id)
313
- {
314
- switch ($column) {
315
- case "permalink":
316
- $url = get_post_meta($post_id, 'wprss_item_permalink', true);
317
- printf(
318
- '<a href="%s">%s</a>',
319
- esc_attr($url),
320
- esc_html($url)
321
- );
322
- break;
323
 
324
- case "publishdate":
325
- $item_date = get_the_time('U', get_the_ID());
326
- $item_date = ($item_date === '') ? date('U') : $item_date;
327
- $publishdate = date('Y-m-d H:i:s', $item_date);
328
- echo $publishdate;
329
- break;
330
 
331
- case "source":
332
- $query = new WP_Query();
 
333
 
334
- $feedId = get_post_meta($post_id, 'wprss_feed_id', true);
335
- $feedName = get_the_title($feedId);
336
- $feedEditLink = get_edit_post_link($feedId);
 
337
 
338
- printf(
339
- '<a href="%s">%s</a>',
340
- $feedEditLink,
341
- $feedName
342
- );
343
 
344
- break;
345
- }
346
- }
347
-
348
- add_filter("manage_edit-wprss_feed_item_sortable_columns", "wprss_feed_item_sortable_columns");
349
- /**
350
- * Make the custom columns sortable
351
- *
352
- * @since 2.0
353
- */
354
- function wprss_feed_item_sortable_columns()
355
- {
356
- return apply_filters('wprss_feed_item_sortable_columns', [
357
- 'publishdate' => 'publishdate',
358
- 'source' => 'source',
359
- ]);
360
- }
361
-
362
- add_action('pre_get_posts', 'wprss_feed_item_orderby');
363
- /**
364
- * Change ordering of posts on wprss_feed_item screen
365
- *
366
- * @since 2.0
367
- */
368
- function wprss_feed_item_orderby($query)
369
- {
370
- if (!is_admin()) {
371
- return;
372
  }
373
 
374
- $post_type = $query->get('post_type');
375
-
376
- // If we're on the feed listing admin page
377
- if ($post_type == 'wprss_feed_item') {
378
- // Set general orderby to date the feed item was published
379
- $query->set('orderby', 'publishdate');
380
- // If user clicks on the reorder link, implement reordering
381
- $orderby = $query->get('orderby');
382
- if ('publishdate' == $orderby) {
383
- $query->set('order', 'DESC');
384
- $query->set('orderby', 'date');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  }
386
  }
387
- }
388
-
389
- add_filter('post_updated_messages', 'wprss_feed_updated_messages');
390
- /**
391
- * Change default notification message when new feed is added or updated
392
- *
393
- * @since 2.0
394
- */
395
- function wprss_feed_updated_messages($messages)
396
- {
397
- global $post, $post_ID;
398
-
399
- $messages['wprss_feed'] = [
400
- 0 => '', // Unused. Messages start at index 1.
401
- 1 => __('Feed source updated. ', 'wprss'),
402
- 2 => __('Custom field updated.', 'wprss'),
403
- 3 => __('Custom field deleted.', 'wprss'),
404
- 4 => __('Feed source updated.', 'wprss'),
405
- 5 => '',
406
- 6 => __('Feed source saved.', 'wprss'),
407
- 7 => __('Feed source saved.', 'wprss'),
408
- 8 => __('Feed source submitted.', 'wprss'),
409
- 9 => '',
410
- 10 => __('Feed source updated.', 'wprss'),
411
- ];
412
-
413
- return apply_filters('wprss_feed_updated_messages', $messages);
414
- }
415
-
416
- add_filter('post_row_actions', 'wprss_remove_row_actions', 10, 2);
417
- /**
418
- * Remove actions row for imported feed items, we don't want them to be editable or viewable
419
- *
420
- * @since 2.0
421
- */
422
- function wprss_remove_row_actions($actions, $post)
423
- {
424
- if (get_post_type($post) === 'wprss_feed_item') {
425
- if (!wpra_is_dev_mode()) {
426
- unset($actions['edit']);
427
  }
428
- unset($actions['view']);
429
- unset($actions['inline hide-if-no-js']);
430
- } elseif (get_post_type($post) === 'wprss_feed') {
431
- $actions = array_reverse($actions);
432
- $actions['id'] = sprintf(
433
- '<span class="wprss-row-id">%s</span>',
434
- sprintf(__('ID: %1$s', 'wprss'), $post->ID)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  );
436
- $actions = array_reverse($actions);
437
 
438
- unset($actions['view']);
439
- unset($actions['inline hide-if-no-js']);
440
  }
441
 
442
- return apply_filters('wprss_remove_row_actions', $actions);
443
- }
444
-
445
- add_action('wprss_delete_feed_items_from_source_hook', 'wprss_delete_feed_items_of_feed_source', 10, 1);
446
- /**
447
- * Deletes the feed items of the feed source identified by the given ID.
448
- *
449
- * @since 3.5
450
- *
451
- * @param int $source_id The ID of the feed source
452
- */
453
- function wprss_delete_feed_items_of_feed_source($source_id)
454
- {
455
- wprss_delete_feed_items($source_id);
456
-
457
- update_post_meta($source_id, 'wprss_feed_is_deleting_items', '');
458
- }
459
-
460
- /**
461
- * Shows a notification that tells the user that feed items for a particular source are being deleted
462
- *
463
- * @since 3.5
464
- */
465
- function wprss_notify_about_deleting_source_feed_items()
466
- {
467
- $message = apply_filters(
468
- 'wprss_notify_about_deleting_source_feed_items_message',
469
- __('The feed items for this feed source are being deleted in the background.', 'wprss')
470
- );
471
-
472
- printf('<div class="updated"><p>%s</p></div>', $message);
473
- }
474
-
475
- add_action('wp_ajax_wprss_fetch_items_row_action', 'wprss_fetch_feeds_action_hook');
476
- /**
477
- * The AJAX function for the 'Fetch Feed Items' row action on the
478
- * 'All Feed Sources' page.
479
- *
480
- * @since 3.3
481
- */
482
- function wprss_fetch_feeds_action_hook()
483
- {
484
- $response = wprss()->createAjaxResponse();
485
- $wprss = wprss();
486
- $feedIdKey = 'feed_source_id';
487
-
488
- try {
489
- if (!current_user_can('edit_feed_sources')) {
490
- throw new Exception(__('Could not schedule fetch for feed source: user must have sufficient privileges.'));
491
- }
492
 
493
- // Verify admin referer
494
- if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
495
- throw new Exception(__('Could not schedule fetch for feed source: nonce is invalid.', 'wprss'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  }
 
 
 
 
497
 
498
- $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);
499
- if (!$id) {
500
- throw new Exception($wprss->__('Could not schedule fetch: feed source ID is invalid or was not specified'));
501
  }
502
- $response->setAjaxData($feedIdKey, $id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
 
504
 
505
- update_post_meta($id, 'wprss_force_next_fetch', '1');
 
 
 
 
 
 
 
 
506
 
507
- // Prepare the schedule args
508
- $schedule_args = [strval($id)];
509
 
510
- // Get the current schedule - do nothing if not scheduled
511
- $next_scheduled = wp_next_scheduled('wprss_fetch_single_feed_hook', $schedule_args);
512
- if ($next_scheduled !== false) {
513
- // If scheduled, unschedule it
514
- wp_unschedule_event($next_scheduled, 'wprss_fetch_single_feed_hook', $schedule_args);
 
 
 
 
 
 
 
 
 
 
 
 
 
515
 
516
- // Get the interval option for the feed source
517
- $interval = get_post_meta($id, 'wprss_update_interval', true);
518
- // if the feed source uses its own interval
519
- if ($interval !== '' && $interval !== wprss_get_default_feed_source_update_interval()) {
520
- // Add meta in feed source. This is used to notify the source that it needs to reschedule it
521
- update_post_meta($id, 'wprss_reschedule_event', $next_scheduled);
522
  }
523
- }
524
 
525
- // Schedule the event for 5 seconds from now
526
- $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
527
- $success = wp_schedule_single_event(time() + $offset, 'wprss_fetch_single_feed_hook', $schedule_args);
528
- if (!$success) {
529
- throw new Exception(__('Failed to schedule cron', 'wprss'));
530
- }
531
- wprss_flag_feed_as_updating($id);
532
- } catch (Exception $e) {
533
- $response = wprss()->createAjaxErrorResponse($e);
534
- if (isset($id)) {
535
- $response->setAjaxData($feedIdKey, $id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  }
 
 
 
537
  echo $response->getBody();
538
  exit();
539
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
 
541
- $response->setAjaxData('message', $wprss->__(['Fetch for feed source #%1$s successfully scheduled', $id]));
542
- $response->setAjaxData('success', $success);
543
- echo $response->getBody();
544
- exit();
545
- }
546
-
547
- add_action('wp_ajax_wprss_delete_items_row_action', 'wprss_delete_items_ajax_action_hook');
548
- /**
549
- * The AJAX function for the 'Delete Items' row action on the 'All Feed Sources' page.
550
- *
551
- * @since 4.14
552
- */
553
- function wprss_delete_items_ajax_action_hook()
554
- {
555
- $kFeedSourceId = 'feed_source_id';
556
- $response = wprss()->createAjaxResponse();
557
- $wprss = wprss();
558
- try {
559
- $id = filter_input(INPUT_POST, 'id');
560
- if (empty($id)) {
561
- throw new Exception($wprss->__('Source ID was not specified'));
562
- }
563
 
564
- $response->setAjaxData($kFeedSourceId, $id);
 
 
565
 
566
- if (!current_user_can('edit_feed_sources')) {
567
- throw new Exception($wprss->__(['User must have sufficient privileges', $id]));
568
- }
 
569
 
570
- // Verify admin referer
571
- if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
572
- throw new Exception($wprss->__(['Nonce has expired - Please refresh the page.', $id]));
 
 
 
 
 
 
 
 
 
 
 
 
573
  }
574
 
575
- // Schedule a job that runs this function with the source id parameter
576
- $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
577
- $success = wp_schedule_single_event(time() + $offset, 'wprss_delete_feed_items_from_source_hook', [$id]);
578
- if (!$success) {
579
- throw new Exception(__('Failed to schedule cron', 'wprss'));
580
- }
581
- // Mark feed as deleting its items
582
- update_post_meta($id, 'wprss_feed_is_deleting_items', time());
583
- } catch (Exception $e) {
584
- $response = wprss()->createAjaxErrorResponse($e);
585
- if (isset($id)) {
586
- $response->setAjaxData($kFeedSourceId, $id);
587
- }
588
  echo $response->getBody();
589
  exit();
590
  }
591
 
592
- $response->setAjaxData('message', $wprss->__(['Items are being deleted', $id]));
593
- $response->setAjaxData('success', $success);
594
- echo $response->getBody();
595
- exit();
596
- }
597
-
598
- add_action('wp_ajax_wprss_toggle_feed_state', 'wprss_ajax_toggle_feed_state');
599
- /**
600
- * The AJAX function for toggling a feed's state from the 'All Feed Sources' page.
601
- *
602
- * @since 4.14
603
- */
604
- function wprss_ajax_toggle_feed_state()
605
- {
606
- $kFeedSourceId = 'feed_source_id';
607
- $response = wprss()->createAjaxResponse();
608
- $wprss = wprss();
609
- try {
610
- $id = filter_input(INPUT_POST, 'id', FILTER_DEFAULT);
611
- if (empty($id)) {
612
- throw new Exception($wprss->__('Source ID was not specified'));
613
- }
614
 
615
- $response->setAjaxData($kFeedSourceId, $id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
 
617
- if (!current_user_can('edit_feed_sources')) {
618
- throw new Exception($wprss->__(['User must have sufficient privileges', $id]));
619
- }
620
 
621
- // Verify admin referer
622
- if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
623
- throw new Exception($wprss->__(['Nonce has expired - Please refresh the page.', $id]));
624
- }
625
 
626
- $active = wprss_is_feed_source_active($id);
 
 
 
627
 
628
- if ($active) {
629
- wprss_pause_feed_source($id);
630
- } else {
631
- wprss_activate_feed_source($id);
632
- }
633
 
634
- $response->setAjaxData('active', !$active);
635
- } catch (Exception $e) {
636
- $response = wprss()->createAjaxErrorResponse($e);
637
- if (isset($id)) {
638
- $response->setAjaxData($kFeedSourceId, $id);
 
 
 
 
 
 
 
 
 
639
  }
 
 
640
  echo $response->getBody();
641
  exit();
642
  }
643
 
644
- $response->setAjaxData('message', $wprss->__(['Feed state changed successfully', $id]));
645
- echo $response->getBody();
646
- exit();
647
- }
 
 
 
648
 
649
- add_action('manage_posts_extra_tablenav', function ($which) {
650
- $screen = get_current_screen();
651
- $postType = $screen->post_type;
652
- // Only add on feed source list
653
- if ($postType !== 'wprss_feed') {
654
- return;
655
- }
 
656
 
657
- $nonceEl = new \Aventura\Wprss\Core\Block\Html\Span([
658
- 'data-value' => wp_create_nonce('wprss_feed_source_action'),
659
- 'id' => 'wprss_feed_source_action_nonce',
660
- 'class' => 'hidden',
661
- ]);
662
-
663
- echo (string) $nonceEl;
664
- });
665
-
666
- add_filter('bulk_actions-edit-wprss_feed_item', 'wprss_custom_feed_item_bulk_actions');
667
- /**
668
- * Allow filtering bulk actions for feed items
669
- *
670
- * @since 2.0
671
- */
672
- function wprss_custom_feed_item_bulk_actions($actions)
673
- {
674
- if (!wpra_is_dev_mode()) {
675
- unset($actions['edit']);
676
- }
677
 
678
- return apply_filters('wprss_custom_feed_item_bulk_actions', $actions);
679
- }
680
-
681
- add_action('admin_footer-edit.php', 'wprss_remove_a_from_feed_title');
682
- /**
683
- * Remove hyperlink from imported feed titles in list posts screen
684
- *
685
- * @since 2.0
686
- */
687
- function wprss_remove_a_from_feed_title()
688
- {
689
- if ('edit-wprss_feed_item' !== get_current_screen()->id) {
690
- return;
691
- }
692
 
693
- ?>
694
- <script type="text/javascript">
695
- jQuery('table.wp-list-table a.row-title').contents().unwrap();
696
- </script>
697
- <?php
698
- }
699
-
700
- add_action('wp_before_admin_bar_render', 'wprss_modify_admin_bar');
701
- /**
702
- * Removes the old "View Source" menu item from the admin bar and adds a new
703
- * "View items" menu bar item, that opens a new tab, showing the items imported
704
- * from that feed source.
705
- *
706
- * Only shown on the wprss_feed edit page.
707
- *
708
- * @since 4.2
709
- */
710
- function wprss_modify_admin_bar()
711
- {
712
- if (!is_admin()) {
713
- return;
714
  }
715
 
716
- $screen = get_current_screen();
717
- $action = filter_input(INPUT_GET, 'action');
718
- $action = strtolower($action);
719
 
720
- if (empty($screen) || $screen->base !== 'post' || $screen->post_type !== 'wprss_feed' || $action !== 'edit') {
 
 
 
 
 
 
 
721
  return;
 
 
 
 
 
 
722
  }
723
 
724
- global $wp_admin_bar;
725
- // Remove the old 'View Source' menu item
726
- $wp_admin_bar->remove_node('view');
727
-
728
- // Prepare the view items link and text
729
- $view_items_link = apply_filters(
730
- 'wprss_view_feed_items_row_action_link',
731
- admin_url('edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID()),
732
- get_the_ID()
733
- );
734
- $view_items_text = apply_filters('wprss_view_feed_items_row_action_text', __('View Items', 'wprss'));
735
-
736
- // Prepare the link target
737
- $link_target = 'wprss-view-items-' . get_the_ID();
738
-
739
- // Add the new menu item
740
- $wp_admin_bar->add_node([
741
- 'href' => $view_items_link,
742
- 'id' => 'view',
743
- 'title' => $view_items_text,
744
- 'meta' => [
745
- 'target' => $link_target,
746
- ],
747
- ]);
748
- }
749
-
750
- if (is_admin()) {
751
  /**
752
- * Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
753
- * The queried items are then filtered down to the items imported by the feed source with
754
- * the ID given in the wprss_feed GET parameter.
 
 
755
  *
756
  * @since 4.2
757
  */
758
- add_filter('pre_get_posts', function ($query) {
759
- // Get the ID from the GET param
760
- $id = filter_input(INPUT_GET, 'wprss_feed', FILTER_VALIDATE_INT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
 
762
- // Make sure we are in the admin area, filtering the main query, and the GET param is present
763
- if (!is_admin() || !$query->is_main_query() || empty($id)) {
764
- return $query;
765
- }
766
 
767
- // Bail if the ID does not correspond to a WPRA feed source
768
- $feed = get_post($id);
769
- if ($feed instanceof WP_Post && $feed->post_type !== 'wprss_feed') {
770
- return $query;
771
- }
772
 
773
- // Get the existing meta query
774
- $mq = $query->get('meta_query');
775
- // Add a meta query if one is not yet set
776
- if (!is_array($mq)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
777
  // initialize it
778
- $mq = ['relation' => 'AND'];
779
- }
780
- // Add the custom meta query
781
- $mq[] = apply_filters(
 
 
782
  'wprss_view_feed_items_meta_query',
783
- [
784
- 'key' => 'wprss_feed_id',
785
- 'value' => $id,
786
- 'compare' => '=',
787
- ],
788
  $id
789
- );
790
- // Set the new meta query
791
- $query->set('meta_query', $mq);
792
-
793
  // Return the query
794
  return $query;
795
- });
796
- }
1
  <?php
2
+ /**
3
+ * Functions for the admin section, columns and row actions
4
+ *
5
+ * @package WP RSS Aggregator
6
+ */
7
+
8
+ // Adds the "active" class to the feed source list table rows, for active feed sources
9
+ add_filter( 'post_class', function( $classes, $class, $postId ) {
10
+ $post = get_post($postId);
11
+
12
+ if ($post->post_type !== 'wprss_feed') {
13
+ return $classes;
14
+ }
15
 
16
+ if (wprss_is_feed_source_active($postId)) {
17
+ $classes[] = 'active';
18
+ }
19
 
 
20
  return $classes;
21
+ }, 10, 3 );
22
 
23
+ add_filter( 'manage_wprss_feed_posts_columns', 'wprss_set_feed_custom_columns', 20, 1 );
24
+ /**
25
+ * Set up the custom columns for the wprss_feed list
26
+ *
27
+ * @since 2.0
28
+ */
29
+ function wprss_set_feed_custom_columns( $columns ) {
30
+ $isTrashPage = filter_input(INPUT_GET, 'post_status') === 'trash';
31
 
32
+ $columns = array(
33
+ 'cb' => '<input type="checkbox" />',
34
+ );
35
+
36
+
37
+ if (!$isTrashPage) {
38
+ $columns['state'] = __( 'State', WPRSS_TEXT_DOMAIN );
39
+ }
40
+
41
+ $columns['title'] = __( 'Name', WPRSS_TEXT_DOMAIN );
 
 
 
 
 
 
 
 
 
 
42
 
43
+ $columns = apply_filters( 'wprss_set_feed_custom_columns', $columns );
44
 
45
+ if (!$isTrashPage) {
46
+ $columns['updates'] = __( 'Updates', WPRSS_TEXT_DOMAIN );
47
+ $columns['feed-count'] = __( apply_filters( 'wprss_feed_items_count_column', 'Imported items' ), WPRSS_TEXT_DOMAIN );
48
+ }
49
 
50
+ return apply_filters( 'wprss_feed_columns', $columns );
 
 
51
  }
52
 
53
+
54
+ add_action( "manage_wprss_feed_posts_custom_column", "wprss_show_custom_columns", 10, 2 );
55
+ /**
56
+ * Show up the custom columns for the wprss_feed list
57
+ *
58
+ * @since 2.0
59
+ */
60
+ function wprss_show_custom_columns( $column, $post_id ) {
61
+
62
+ switch ( $column ) {
 
 
63
  case 'state':
64
  $switch_title = __('Activate or pause auto importing for this feed', 'wprss');
65
  ?>
66
+ <div class="wprss-feed-state-container" title="<?php echo esc_attr($switch_title); ?>">
67
  <label class="wprss-switch">
68
+ <input type="checkbox"
69
+ class="wprss-toggle-feed-state"
70
+ autocomplete="off"
71
+ value="<?php echo esc_attr($post_id); ?>"
72
+ <?php checked(true, wprss_is_feed_source_active($post_id)) ?>
 
73
  />
74
  <span class="wprss-switch-slider"></span>
75
  </label>
87
  }
88
  ?>
89
 
90
+ <div class="wprss-feed-source-type wprss-feed-source-type-<?php echo $feed_type ?>"
91
+ title="<?php echo esc_attr($icon_title) ?>"
 
92
  >
93
+ <span class="dashicons dashicons-<?php echo $feed_icon ?>"></span>
94
  </div>
95
  <?php
96
 
97
+ break;
98
 
99
  case 'updates':
100
  // Get the update interval
101
+ $update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
102
  // Get the last updated and next update data
103
+ $last_update = get_post_meta( $post_id, 'wprss_last_update', TRUE );
104
+ $last_update_items = get_post_meta( $post_id, 'wprss_last_update_items', TRUE );
105
+ $next_update = wprss_get_next_feed_source_update( $post_id );
106
 
107
  // If using the global interval, get the timestamp of the next global update
108
+ if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
109
+ $next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
110
  }
111
 
112
+ // Update the meta field
113
+ if ( wprss_is_feed_source_active( $post_id ) ) {
114
+ $next_update_text = $next_update === FALSE ? __( 'None', WPRSS_TEXT_DOMAIN ) : human_time_diff( $next_update, time() );
115
+ } else {
116
+ $next_update_text = __( '...', 'wprss' );
117
+ }
118
+ update_post_meta( $post_id, 'wprss_next_update', $next_update_text );
 
 
119
 
120
+ $timeago = empty($last_update) ? '' : human_time_diff( $last_update, time() );
 
 
121
  ?>
122
 
123
  <p class="next-update-container">
124
+ <?php _e( 'Next update in', WPRSS_TEXT_DOMAIN ) ?>
125
  <code class="next-update">
126
+ <?php echo $next_update_text; ?>
127
  </code>
128
  </p>
129
 
130
+ <p class="last-update-container"
131
+ style="display: <?php echo empty($timeago) ? 'none' : 'inline-block'; ?>">
 
132
  <span class="last-update-num-items-container">
133
+ <?php echo _x( 'Updated', 'Example: "Updated 2 days ago"', 'wprss' ); ?>
134
  <span class="last-update-time-container">
135
+ <code class="last-update-time"><?php printf(__('%1$s ago', 'wprss'), $timeago) ?></code>
 
 
136
  </span>
137
+ (<span class="last-update-num-items"><?php echo
138
+ $last_update_items ?></span>
139
+ <?php echo _x('items', 'Example: "15 new"', 'wprss'); ?>)
 
 
 
 
140
  </span>
141
  </p>
142
 
144
  break;
145
 
146
  case 'feed-count':
147
+ $items = wprss_get_feed_items_for_source( $post_id );
148
  $has_items_class = ($items->post_count > 0) ? 'has-imported-items' : '';
149
 
150
+ $errors = get_post_meta( $post_id, 'wprss_error_last_import', true );
151
+ $errorShowClass = ( $errors !== '' )? 'wprss-show' : '';
152
+ $default_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.", WPRSS_TEXT_DOMAIN );
153
+ $msg = strlen( $errors ) > 0 ? $errors : $default_msg;
 
 
 
 
 
 
154
  $errorIcon = sprintf(
155
  '<i title="%1$s" class="fa fa-warning fa-fw wprss-feed-error-symbol %2$s"></i>',
156
  esc_attr($msg),
157
+ $errorShowClass
158
  );
159
 
160
+ $view_items_url = admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . $post_id );
161
+ $view_items_url = apply_filters( 'wprss_view_feed_items_row_action_link', $view_items_url, $post_id );
162
  ?>
163
+ <a href="<?php echo esc_attr($view_items_url); ?>"
164
+ class="items-imported-link <?php echo $has_items_class; ?>"
165
+ title="<?php echo esc_attr(__('View the imported items for this feed source', 'wprss')); ?>"
166
+ >
167
+ <span class="items-imported"><?php echo $items->post_count ?></span>
168
+ <?php _e('items', 'wprss') ?>
169
+ </a>
 
 
 
170
  <div class="spinner"></div>
171
 
172
+ <?php echo $errorIcon; ?>
173
+
174
+ <div class="row-actions">
175
+ <span class="fetch">
176
+ <a href="javascript:;"
177
+ class="wprss_fetch_items_ajax_action"
178
+ pid="<?php echo esc_attr ($post_id); ?>"
179
+ purl="<?php echo admin_url('admin-ajax.php'); ?>">
180
+ <?php _e('Fetch', 'wprss'); ?>
181
+ </a>
182
+ </span>
183
+ <span class="purge-posts trash <?php echo $has_items_class; ?>">
 
184
  |
185
+ <a href="javascript:;"
186
+ class="wprss_delete_items_ajax_action"
187
+ pid="<?php echo esc_attr ($post_id); ?>"
188
+ purl="<?php echo admin_url('admin-ajax.php'); ?>">
189
+ <?php _e('Delete items', 'wprss'); ?>
 
190
  </a>
191
  </span>
192
+ </div>
193
+ <?php
194
 
195
+ // Set meta field for items imported
196
+ update_post_meta( $post_id, 'wprss_items_imported', $items->post_count );
197
 
198
  break;
199
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  }
201
 
 
 
 
202
 
203
+ add_filter( "manage_edit-wprss_feed_sortable_columns", "wprss_feed_sortable_columns" );
204
+ /**
205
+ * Make the custom columns sortable for wprss_feed post type
206
+ *
207
+ * @since 2.0
208
+ */
209
+ function wprss_feed_sortable_columns() {
210
+ $sortable_columns = array(
211
+ // meta column id => sortby value used in query
212
+ 'state' => 'state',
213
+ 'title' => 'title',
214
+ 'updates' => 'updates',
215
+ 'feed-count' => 'feed-count'
216
+ );
217
+ return apply_filters( 'wprss_feed_sortable_columns', $sortable_columns );
218
  }
219
 
 
220
 
221
+ add_action( 'pre_get_posts', 'wprss_feed_source_order' );
222
+ /**
223
+ * Change order of feed sources to alphabetical ascending according to feed name
224
+ *
225
+ * @since 2.2
226
+ */
227
+ function wprss_feed_source_order( $query ) {
228
+ // Check if the query is being processed in WP Admin, is the main query, and is targetted
229
+ // for the wprss_feed CPT. If not, stop
230
+ if ( !is_admin() || !$query->is_main_query() || $query->get('post_type') !== 'wprss_feed' ) {
231
+ return;
232
+ }
233
 
234
+ // Get the sorting query args
235
+ $order = strtoupper($query->get('order'));
236
+ $orderby = $query->get('orderby');
 
 
 
237
 
238
+ // If order is not specified, default to ascending
239
+ if ($order !== 'ASC' && $order !== 'DESC') {
240
+ $order = 'ASC';
241
+ }
242
 
243
+ $query->set('order', $order);
 
 
 
244
 
245
+ // If not explicitly sorting or sorting by title, sort by title
246
+ if (!$orderby || $orderby === 'title') {
247
+ $query->set('orderby', 'title');
248
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
250
+ // Check what we are sorting by
251
+ switch ( $orderby ) {
252
+ case 'state':
253
+ $query->set('meta_key', 'wprss_state');
254
+ $query->set('orderby', 'meta_value');
255
+ break;
256
 
257
+ case 'updates':
258
+ $query->set('meta_key', 'wprss_next_update');
259
+ $query->set('orderby', 'meta_value');
260
 
261
+ break;
262
+ case 'feed-count':
263
+ $query->set('meta_key', 'wprss_items_imported');
264
+ $query->set('orderby', 'meta_value_num');
265
 
266
+ break;
267
+ }
268
+ }
 
 
269
 
270
+
271
+ add_filter( 'manage_wprss_feed_item_posts_columns', 'wprss_set_feed_item_custom_columns', 20, 1 );
272
+ /**
273
+ * Set up the custom columns for the wprss_feed source list
274
+ *
275
+ * @since 2.0
276
+ */
277
+ function wprss_set_feed_item_custom_columns( $columns ) {
278
+
279
+ $columns = array (
280
+ 'cb' => '<input type="checkbox" />',
281
+ 'title' => __( 'Name', WPRSS_TEXT_DOMAIN ),
282
+ 'permalink' => __( 'Permalink', WPRSS_TEXT_DOMAIN ),
283
+ 'publishdate' => __( 'Date published', WPRSS_TEXT_DOMAIN ),
284
+ 'source' => __( 'Source', WPRSS_TEXT_DOMAIN )
285
+ );
286
+ return apply_filters( 'wprss_set_feed_item_custom_columns', $columns );
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
 
289
+
290
+ add_action( "manage_wprss_feed_item_posts_custom_column", "wprss_show_feed_item_custom_columns", 10, 2 );
291
+ /**
292
+ * Show up the custom columns for the wprss_feed list
293
+ *
294
+ * @since 2.0
295
+ */
296
+ function wprss_show_feed_item_custom_columns( $column, $post_id ) {
297
+
298
+ switch ( $column ) {
299
+ case "permalink":
300
+ $url = get_post_meta( $post_id, 'wprss_item_permalink', true);
301
+ echo '<a href="' . $url . '">' . $url. '</a>';
302
+ break;
303
+
304
+ case "publishdate":
305
+ $item_date = get_the_time( 'U', get_the_ID() );
306
+ $item_date = ( $item_date === '' )? date('U') : $item_date;
307
+ $publishdate = date( 'Y-m-d H:i:s', $item_date ) ;
308
+ echo $publishdate;
309
+ break;
310
+
311
+ case "source":
312
+ $query = new WP_Query();
313
+ $source = '<a href="' . get_edit_post_link( get_post_meta( $post_id, 'wprss_feed_id', true ) ) . '">' . get_the_title( get_post_meta( $post_id, 'wprss_feed_id', true ) ) . '</a>';
314
+ echo $source;
315
+ break;
316
  }
317
  }
318
+
319
+
320
+ add_filter( "manage_edit-wprss_feed_item_sortable_columns", "wprss_feed_item_sortable_columns" );
321
+ /**
322
+ * Make the custom columns sortable
323
+ *
324
+ * @since 2.0
325
+ */
326
+ function wprss_feed_item_sortable_columns() {
327
+ $sortable_columns = array(
328
+ // meta column id => sortby value used in query
329
+ 'publishdate' => 'publishdate',
330
+ 'source' => 'source'
331
+ );
332
+ return apply_filters( 'wprss_feed_item_sortable_columns', $sortable_columns );
333
+ }
334
+
335
+
336
+ add_action( 'pre_get_posts', 'wprss_feed_item_orderby' );
337
+ /**
338
+ * Change ordering of posts on wprss_feed_item screen
339
+ *
340
+ * @since 2.0
341
+ */
342
+ function wprss_feed_item_orderby( $query ) {
343
+ if( ! is_admin() )
344
+ return;
345
+
346
+ $post_type = $query->get('post_type');
347
+
348
+ // If we're on the feed listing admin page
349
+ if ( $post_type == 'wprss_feed_item') {
350
+ // Set general orderby to date the feed item was published
351
+ $query->set('orderby','publishdate');
352
+ // If user clicks on the reorder link, implement reordering
353
+ $orderby = $query->get( 'orderby');
354
+ if( 'publishdate' == $orderby ) {
355
+ $query->set( 'order', 'DESC' );
356
+ $query->set( 'orderby', 'date' );
357
+ }
358
  }
359
+ }
360
+
361
+
362
+ add_filter( 'post_updated_messages', 'wprss_feed_updated_messages' );
363
+ /**
364
+ * Change default notification message when new feed is added or updated
365
+ *
366
+ * @since 2.0
367
+ */
368
+ function wprss_feed_updated_messages( $messages ) {
369
+ global $post, $post_ID;
370
+
371
+ $messages[ 'wprss_feed' ] = array(
372
+ 0 => '', // Unused. Messages start at index 1.
373
+ 1 => __( 'Feed source updated. ', WPRSS_TEXT_DOMAIN ),
374
+ 2 => __( 'Custom field updated.', WPRSS_TEXT_DOMAIN ),
375
+ 3 => __( 'Custom field deleted.', WPRSS_TEXT_DOMAIN ),
376
+ 4 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN ),
377
+ 5 => '',
378
+ 6 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
379
+ 7 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
380
+ 8 => __( 'Feed source submitted.', WPRSS_TEXT_DOMAIN ),
381
+ 9 => '',
382
+ 10 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN )
383
  );
 
384
 
385
+ return apply_filters( 'wprss_feed_updated_messages', $messages );
 
386
  }
387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
+ add_filter( 'post_row_actions', 'wprss_remove_row_actions', 10, 2 );
390
+ /**
391
+ * Remove actions row for imported feed items, we don't want them to be editable or viewable
392
+ *
393
+ * @since 2.0
394
+ */
395
+ function wprss_remove_row_actions( $actions, $post )
396
+ {
397
+
398
+ $page = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
399
+ if ( get_post_type($post) === 'wprss_feed_item' ) {
400
+ if (!wpra_is_dev_mode()) {
401
+ unset($actions['edit']);
402
+ }
403
+ unset( $actions[ 'view' ] );
404
+ //unset( $actions[ 'trash' ] );
405
+ unset( $actions[ 'inline hide-if-no-js' ] );
406
  }
407
+ elseif ( get_post_type($post) === 'wprss_feed' ) {
408
+ $actions = array_reverse( $actions );
409
+ $actions['id'] = '<span class="wprss-row-id">' . sprintf( __( 'ID: %1$s', WPRSS_TEXT_DOMAIN ), $post->ID ) . '</span>';
410
+ $actions = array_reverse( $actions );
411
 
412
+ unset( $actions[ 'view'] );
413
+ unset( $actions[ 'inline hide-if-no-js'] );
 
414
  }
415
+ return apply_filters( 'wprss_remove_row_actions', $actions );
416
+ }
417
+
418
+
419
+
420
+ add_action( 'wprss_delete_feed_items_from_source_hook', 'wprss_delete_feed_items_of_feed_source', 10 , 1 );
421
+ /**
422
+ * Deletes the feed items of the feed source identified by the given ID.
423
+ *
424
+ * @since 3.5
425
+ * @param int $source_id The ID of the feed source
426
+ */
427
+ function wprss_delete_feed_items_of_feed_source($source_id) {
428
+ wprss_delete_feed_items($source_id);
429
+
430
+ update_post_meta($source_id, 'wprss_feed_is_deleting_items', '');
431
+ }
432
 
433
 
434
+ /**
435
+ * Shows a notification that tells the user that feed items for a particular source are being deleted
436
+ *
437
+ * @since 3.5
438
+ */
439
+ function wprss_notify_about_deleting_source_feed_items() {
440
+ $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_TEXT_DOMAIN );
441
+ echo '<div class="updated"><p>' . $message . '</p></div>';
442
+ }
443
 
 
 
444
 
445
+ add_action( 'wp_ajax_wprss_fetch_items_row_action', 'wprss_fetch_feeds_action_hook' );
446
+ /**
447
+ * The AJAX function for the 'Fetch Feed Items' row action on the
448
+ * 'All Feed Sources' page.
449
+ *
450
+ * @since 3.3
451
+ */
452
+ function wprss_fetch_feeds_action_hook() {
453
+ $response = wprss()->createAjaxResponse();
454
+ $wprss = wprss();
455
+ $kFeedSourceId = 'feed_source_id';
456
+ try {
457
+ $kId = 'id';
458
+ if (!isset( $_POST[$kId] ) || empty( $_POST[$kId] )) {
459
+ throw new Exception($wprss->__('Could not schedule fetch: source ID must be specified'));
460
+ }
461
+ $id = $_POST['id'];
462
+ $response->setAjaxData($kFeedSourceId, $id);
463
 
464
+ if (!current_user_can('edit_feed_sources')) {
465
+ throw new Exception($wprss->__(array('Could not schedule fetch for source #%1$s: user must have sufficient privileges', $id)));
 
 
 
 
466
  }
 
467
 
468
+ // Verify admin referer
469
+ if (!wprss_verify_nonce( 'wprss_feed_source_action', 'wprss_admin_ajax_nonce' )) {
470
+ throw new Exception($wprss->__(array('Could not schedule fetch for source #%1$s: nonce is expired', $id)));
471
+ }
472
+
473
+ update_post_meta( $id, 'wprss_force_next_fetch', '1' );
474
+
475
+ // Prepare the schedule args
476
+ $schedule_args = array( strval( $id ) );
477
+
478
+ // Get the current schedule - do nothing if not scheduled
479
+ $next_scheduled = wp_next_scheduled( 'wprss_fetch_single_feed_hook', $schedule_args );
480
+ if ( $next_scheduled !== FALSE ) {
481
+ // If scheduled, unschedule it
482
+ wp_unschedule_event( $next_scheduled, 'wprss_fetch_single_feed_hook', $schedule_args );
483
+
484
+ // Get the interval option for the feed source
485
+ $interval = get_post_meta( $id, 'wprss_update_interval', TRUE );
486
+ // if the feed source uses its own interval
487
+ if ( $interval !== '' && $interval !== wprss_get_default_feed_source_update_interval() ) {
488
+ // Add meta in feed source. This is used to notify the source that it needs to reschedule it
489
+ update_post_meta( $id, 'wprss_reschedule_event', $next_scheduled );
490
+ }
491
+ }
492
+
493
+ // Schedule the event for 5 seconds from now
494
+ $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
495
+ $success = wp_schedule_single_event( time() + $offset, 'wprss_fetch_single_feed_hook', $schedule_args );
496
+ if (!$success) {
497
+ throw new Exception(__('Failed to schedule cron', 'wprss'));
498
+ }
499
+ wprss_flag_feed_as_updating( $id );
500
+ } catch (Exception $e) {
501
+ $response = wprss()->createAjaxErrorResponse($e);
502
+ if (isset($id)) {
503
+ $response->setAjaxData($kFeedSourceId, $id);
504
+ }
505
+ echo $response->getBody();
506
+ exit();
507
  }
508
+
509
+ $response->setAjaxData('message', $wprss->__(array('Fetch for feed source #%1$s successfully scheduled', $id)));
510
+ $response->setAjaxData('success', $success);
511
  echo $response->getBody();
512
  exit();
513
  }
514
+
515
+ add_action( 'wp_ajax_wprss_delete_items_row_action', 'wprss_delete_items_ajax_action_hook' );
516
+ /**
517
+ * The AJAX function for the 'Delete Items' row action on the 'All Feed Sources' page.
518
+ *
519
+ * @since 4.14
520
+ */
521
+ function wprss_delete_items_ajax_action_hook() {
522
+ $kFeedSourceId = 'feed_source_id';
523
+ $response = wprss()->createAjaxResponse();
524
+ $wprss = wprss();
525
+ try {
526
+ $id = filter_input(INPUT_POST, 'id', FILTER_DEFAULT);
527
+ if (empty($id)) {
528
+ throw new Exception($wprss->__('Source ID was not specified'));
529
+ }
530
 
531
+ $response->setAjaxData($kFeedSourceId, $id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
 
533
+ if (!current_user_can('edit_feed_sources')) {
534
+ throw new Exception($wprss->__(array('User must have sufficient privileges', $id)));
535
+ }
536
 
537
+ // Verify admin referer
538
+ if (!wprss_verify_nonce( 'wprss_feed_source_action', 'wprss_admin_ajax_nonce' )) {
539
+ throw new Exception($wprss->__(array('Nonce has expired - Please refresh the page.', $id)));
540
+ }
541
 
542
+ // Schedule a job that runs this function with the source id parameter
543
+ $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
544
+ $success = wp_schedule_single_event( time() + $offset, 'wprss_delete_feed_items_from_source_hook', array( $id ) );
545
+ if (!$success) {
546
+ throw new Exception(__('Failed to schedule cron', 'wprss'));
547
+ }
548
+ // Mark feed as deleting its items
549
+ update_post_meta( $id, 'wprss_feed_is_deleting_items', time() );
550
+ } catch (Exception $e) {
551
+ $response = wprss()->createAjaxErrorResponse($e);
552
+ if (isset($id)) {
553
+ $response->setAjaxData($kFeedSourceId, $id);
554
+ }
555
+ echo $response->getBody();
556
+ exit();
557
  }
558
 
559
+ $response->setAjaxData('message', $wprss->__(array('Items are being deleted', $id)));
560
+ $response->setAjaxData('success', $success);
 
 
 
 
 
 
 
 
 
 
 
561
  echo $response->getBody();
562
  exit();
563
  }
564
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
565
 
566
+ add_action( 'wp_ajax_wprss_toggle_feed_state', 'wprss_ajax_toggle_feed_state' );
567
+ /**
568
+ * The AJAX function for toggling a feed's state from the 'All Feed Sources' page.
569
+ *
570
+ * @since 4.14
571
+ */
572
+ function wprss_ajax_toggle_feed_state() {
573
+ $kFeedSourceId = 'feed_source_id';
574
+ $response = wprss()->createAjaxResponse();
575
+ $wprss = wprss();
576
+ try {
577
+ $id = filter_input(INPUT_POST, 'id', FILTER_DEFAULT);
578
+ if (empty($id)) {
579
+ throw new Exception($wprss->__('Source ID was not specified'));
580
+ }
581
 
582
+ $response->setAjaxData($kFeedSourceId, $id);
 
 
583
 
584
+ if (!current_user_can('edit_feed_sources')) {
585
+ throw new Exception($wprss->__(array('User must have sufficient privileges', $id)));
586
+ }
 
587
 
588
+ // Verify admin referer
589
+ if (!wprss_verify_nonce( 'wprss_feed_source_action', 'wprss_admin_ajax_nonce' )) {
590
+ throw new Exception($wprss->__(array('Nonce has expired - Please refresh the page.', $id)));
591
+ }
592
 
593
+ $active = wprss_is_feed_source_active( $id );
 
 
 
 
594
 
595
+ if ( $active ) {
596
+ wprss_pause_feed_source( $id );
597
+ } else {
598
+ wprss_activate_feed_source( $id );
599
+ }
600
+
601
+ $response->setAjaxData('active', !$active);
602
+ } catch (Exception $e) {
603
+ $response = wprss()->createAjaxErrorResponse($e);
604
+ if (isset($id)) {
605
+ $response->setAjaxData($kFeedSourceId, $id);
606
+ }
607
+ echo $response->getBody();
608
+ exit();
609
  }
610
+
611
+ $response->setAjaxData('message', $wprss->__(array('Feed state changed successfully', $id)));
612
  echo $response->getBody();
613
  exit();
614
  }
615
 
616
+ add_action('manage_posts_extra_tablenav', function($which) {
617
+ $screen = get_current_screen();
618
+ $postType = $screen->post_type;
619
+ // Only add on feed source list
620
+ if ($postType !== 'wprss_feed') {
621
+ return;
622
+ }
623
 
624
+ $nonceEl = new \Aventura\Wprss\Core\Block\Html\Span(array(
625
+ 'data-value' => wp_create_nonce('wprss_feed_source_action'),
626
+ 'id' => 'wprss_feed_source_action_nonce',
627
+ 'class' => 'hidden'
628
+ ));
629
+ echo (string) $nonceEl;
630
+ // wp_nonce_field('wprss_feed_source_action', 'wprss_feed_source_action_nonce', false);
631
+ });
632
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
 
634
+ add_filter( 'bulk_actions-edit-wprss_feed_item', 'wprss_custom_feed_item_bulk_actions' );
635
+ /**
636
+ * Allow filtering bulk actions for feed items
637
+ *
638
+ * @since 2.0
639
+ */
640
+ function wprss_custom_feed_item_bulk_actions( $actions ) {
641
+ if (!wpra_is_dev_mode()) {
642
+ unset($actions['edit']);
643
+ }
 
 
 
 
644
 
645
+ return apply_filters( 'wprss_custom_feed_item_bulk_actions', $actions );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
  }
647
 
 
 
 
648
 
649
+ add_action( 'admin_footer-edit.php', 'wprss_remove_a_from_feed_title' );
650
+ /**
651
+ * Remove hyperlink from imported feed titles in list posts screen
652
+ *
653
+ * @since 2.0
654
+ */
655
+ function wprss_remove_a_from_feed_title() {
656
+ if ( 'edit-wprss_feed_item' !== get_current_screen()->id )
657
  return;
658
+ ?>
659
+
660
+ <script type="text/javascript">
661
+ jQuery('table.wp-list-table a.row-title').contents().unwrap();
662
+ </script>
663
+ <?php
664
  }
665
 
666
+
667
+ add_action( 'wp_before_admin_bar_render', 'wprss_modify_admin_bar' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  /**
669
+ * Removes the old "View Source" menu item from the admin bar and adds a new
670
+ * "View items" menu bar item, that opens a new tab, showing the items imported
671
+ * from that feed source.
672
+ *
673
+ * Only shown on the wprss_feed edit page.
674
  *
675
  * @since 4.2
676
  */
677
+ function wprss_modify_admin_bar() {
678
+ global $wp_admin_bar;
679
+ if ( !is_admin() ) return;
680
+ $screen = get_current_screen();
681
+ // Check if we are in the wprss_feed edit page
682
+ if ( $screen->base == 'post' && $screen->post_type == 'wprss_feed' && !empty( $_GET['action'] ) && $_GET['action'] == 'edit' ) {
683
+ // Remove the old 'View Source' menu item
684
+ $wp_admin_bar->remove_node( 'view' );
685
+
686
+ // Prepare the view items link and text
687
+ $view_items_link = apply_filters(
688
+ 'wprss_view_feed_items_row_action_link',
689
+ admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID() ),
690
+ get_the_ID()
691
+ );
692
+ $view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', 'View Items' );
693
+
694
+ // Prepare the link target
695
+ $link_target = 'wprss-view-items-' . get_the_ID();
696
+
697
+ // Add the new menu item
698
+ $wp_admin_bar->add_node( array(
699
+ 'href' => $view_items_link,
700
+ 'id' => 'view',
701
+ 'title' => __( $view_items_text, WPRSS_TEXT_DOMAIN ),
702
+ 'meta' => array(
703
+ 'target' => $link_target
704
+ )
705
+ ));
706
+ }
707
+ }
708
+
709
 
 
 
 
 
710
 
 
 
 
 
 
711
 
712
+ if ( is_admin() ){
713
+ add_filter('pre_get_posts', 'wprss_view_feed_items_query');
714
+ /**
715
+ * Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
716
+ * The queried items are then filtered down to the items imported by the feed source with
717
+ * the ID given in the wprss_feed GET parameter.
718
+ *
719
+ * @since 4.2
720
+ */
721
+ function wprss_view_feed_items_query( $query ) {
722
+ if ( is_admin() && $query->is_main_query() && !empty($_GET['wprss_feed']) ) {
723
+ // Get the ID from the GET param
724
+ $id = $_GET['wprss_feed'];
725
+ // Get the existing meta query
726
+ $mq = $query->get('meta_query');
727
+ // If the meta query is not yet set
728
+ if ( !is_array($mq) ) {
729
  // initialize it
730
+ $mq = array(
731
+ 'relation' => 'AND',
732
+ );
733
+ }
734
+ // Add the custom meta query
735
+ $mq[] = apply_filters(
736
  'wprss_view_feed_items_meta_query',
737
+ array(
738
+ 'key' => 'wprss_feed_id',
739
+ 'value' => $id,
740
+ 'compare' => '='
741
+ ),
742
  $id
743
+ );
744
+ // Set the new meta query
745
+ $query->set('meta_query', $mq);
746
+ }
747
  // Return the query
748
  return $query;
749
+ }
750
+ }
includes/admin-editor.php CHANGED
@@ -1,231 +1,236 @@
1
  <?php
2
-
3
- /**
4
- * This file contains code related to the custom button added to Wordpress' TinyMCE editor.
5
- *
6
- * @since 3.5
7
- */
8
-
9
- /**
10
- * Adds the WPRSS button to WordPress' editor
11
- *
12
- * @since 3.5
13
- */
14
- add_action('admin_init', function () {
15
- if (current_user_can('edit_posts') && current_user_can('edit_pages') && get_user_option('rich_editing') == 'true') {
16
- /**
17
- * Adds the button action JS file to TinyMCE's plugin list
18
- *
19
- * @since 3.5
20
- * @todo add filter to skip showing the editor button
21
- */
22
- add_filter('mce_external_plugins', function ($plugin_array) {
23
- // add filter here
24
- $plugin_array['wprss'] = WPRSS_JS . 'editor.js';
25
- return $plugin_array;
26
- }, 0);
27
-
28
- /**
29
- * Adds a separator and the wprss button to the buttons array.
30
- *
31
- * @since 3.5
32
- */
33
- add_filter('mce_buttons', function ($buttons) {
34
- $buttons[] = "|";
35
- $buttons[] = "wprss";
36
-
37
- return $buttons;
38
- }, 0);
39
- }
40
- });
41
-
42
- /**
43
- * Intercepts TinyMCE's version check and increments its version by 3.
44
- *
45
- * This is a hack used to work around TinyMCE's caching, that might prevent the
46
- * new wprss button from appearing on the editor.
47
- *
48
- * @since 3.5
49
- */
50
- add_filter('tiny_mce_version', function ($ver) {
51
- $ver += 3;
52
- return $ver;
53
- });
54
-
55
- add_action('wp_ajax_wprss_editor_dialog', 'wprss_return_dialog_contents');
56
- /**
57
- * Renders the TinyMCE button dialog contents.
58
- */
59
- function wprss_return_dialog_contents()
60
- {
61
- $templates_collection = wpra_get('feeds/templates/collection');
62
- $templates_options = [];
63
- foreach ($templates_collection as $template) {
64
- $template_name = $template['name'];
65
- $template_slug = ($template['type'] === '__built_in')
66
- ? ''
67
- : $template['slug'];
68
-
69
- $templates_options[$template_slug] = $template_name;
70
- }
71
- $templates_select = wprss_settings_render_select(
72
- 'wprss-dialog-templates',
73
- '',
74
- $templates_options,
75
- '',
76
- ['class' => 'widefat']
77
- );
78
-
79
- $feed_sources = get_posts([
80
- 'post_type' => 'wprss_feed',
81
- 'post_status' => 'publish',
82
- 'posts_per_page' => -1,
83
- 'no_found_rows' => true,
84
- ]);
85
- $feed_sources_by_id = [];
86
- $feed_sources_by_slug = [];
87
- foreach ($feed_sources as $source) {
88
- $feed_sources_by_id[$source->ID] = $source->post_title;
89
- $feed_sources_by_slug[$source->post_name] = $source->post_title;
90
- }
91
- $feed_sources_select = wprss_settings_render_select(
92
- 'wprss-dialog-feed-source-list',
93
- '',
94
- $feed_sources_by_slug,
95
- '',
96
- ['multiple' => 'multiple', 'class' => 'widefat']
97
- );
98
- $feed_sources_exclude_select = wprss_settings_render_select(
99
- 'wprss-dialog-exclude-list',
100
- '',
101
- $feed_sources_by_id,
102
- '',
103
- ['multiple' => 'multiple', 'class' => 'widefat']
104
- );
105
-
106
- $feed_sources_both_select = sprintf(
107
- '<p>%s</p>',
108
- __('To select more than one feed source, click and drag with your mouse pointer or click individual feed sources while holding down the Ctrl (Windows) or Command (Mac) key.',
109
- 'wprss')
110
- );
111
- $feed_sources_select .= $feed_sources_both_select;
112
- $feed_sources_exclude_select .= $feed_sources_both_select;
113
-
114
- ?>
115
- <table cellspacing="20">
116
- <tbody>
117
- <tr>
118
- <td id="wprss-dialog-templates-label">
119
- <label for="wprss-dialog-templates">
120
- <?php _e('Template', 'wprss') ?>
121
- </label>
122
- </td>
123
- <td>
124
- <?php echo $templates_select; ?>
125
- </td>
126
- </tr>
127
- <tr>
128
- <td id="wprss-dialog-all-sources-label">
129
- <?php _e('Sources', 'wprss') ?>
130
- </td>
131
- <td>
132
- <input id="wprss-dialog-all-sources" type="checkbox" checked>
133
- <label for="wprss-dialog-all-sources">
134
- <?php _e('All feed sources', 'wprss') ?>
135
- </label>
136
- </td>
137
- </tr>
138
-
139
- <tr id="wprss-dialog-exclude-row">
140
- <td id="wprss-dialog-exclude-label">
141
- <label id="wprss-dialog-exclude-list-label" for="wprss-dialog-exclude-list">
142
- <?php _e('Exclude', 'wprss') ?>
143
- </label>
144
- </td>
145
- <td>
146
- <div id="wprss-dialog-excludes-container">
147
- <p><?php _e('You may choose to exclude some feed sources:', 'wprss') ?></p>
148
- <?php echo $feed_sources_exclude_select; ?>
149
- </div>
150
-
151
- <div id="wprss-dialog-sources-container" style="display:none">
152
- <p><?php _e('Choose which feed sources to show:', 'wprss') ?></p>
153
- <?php echo $feed_sources_select; ?>
154
- </div>
155
-
156
- <script type="text/javascript">
157
- jQuery('#wprss-dialog-all-sources').click(function () {
158
- if (jQuery(this).is(':checked')) {
159
- jQuery('#wprss-dialog-sources-container').hide();
160
- jQuery('#wprss-dialog-excludes-container').show();
161
- jQuery('#wprss-dialog-exclude-list-label').show();
162
- } else {
163
- jQuery('#wprss-dialog-sources-container').show();
164
- jQuery('#wprss-dialog-excludes-container').hide();
165
- jQuery('#wprss-dialog-exclude-list-label').hide();
166
- }
167
- });
168
- jQuery('#wprss-dialog-submit').click(wprss_dialog_submit);
169
- </script>
170
- </td>
171
- </tr>
172
-
173
- <tr>
174
- <td><?php _e('Number of items', 'wprss') ?></td>
175
- <td>
176
- <input
177
- id="wprss-dialog-feed-limit"
178
- type="number"
179
- class="wprss-number-roller widefat"
180
- placeholder="<?php _e('Use template setting', 'wprss') ?>"
181
- min="0"
182
- />
183
- </td>
184
- </tr>
185
-
186
- <tr>
187
- <td><?php _e('Pagination', 'wprss') ?></td>
188
- <td>
189
- <label>
190
- <select id="wprss-dialog-pagination">
191
- <option value=""><?php _e('Use template setting', 'wprss') ?></option>
192
- <option value="on"><?php _e('Enabled', 'wprss') ?></option>
193
- <option value="off"><?php _e('Disabled', 'wprss') ?></option>
194
- </select>
195
- <br />
196
- <span>
197
- <?php _e('Choose whether to show or hide pagination controls', 'wprss') ?>
198
- </span>
199
- </label>
200
- </td>
201
- </tr>
202
-
203
- <tr>
204
- <td><?php _e('Starting page', 'wprss') ?></td>
205
- <td>
206
- <input
207
- id="wprss-dialog-start-page"
208
- type="number"
209
- class="wprss-number-roller widefat"
210
- placeholder="<?php _e('Use template setting', 'wprss') ?>"
211
- min="1"
212
- />
213
- </td>
214
- </tr>
215
-
216
- <?php do_action('wprss_return_dialog_contents'); ?>
217
-
218
- <tr>
219
- <td></td>
220
- <td>
221
- <button id="wprss-dialog-submit">
222
- <?php _e('Add shortcode', 'wprss') ?>
223
- </button>
224
- </td>
225
- </tr>
226
-
227
- </tbody>
228
- </table>
229
- <?php
230
- die();
231
- }
 
 
 
 
 
1
  <?php
2
+ /**
3
+ * This file contains code related to the custom button added to Wordpress' TinyMCE editor.
4
+ *
5
+ * @since 3.5
6
+ */
7
+
8
+
9
+
10
+ add_action( 'admin_init', 'wprss_add_editor_button' );
11
+ /**
12
+ * Adds the WPRSS button to WordPress' editor
13
+ *
14
+ * @since 3.5
15
+ */
16
+ function wprss_add_editor_button() {
17
+ if ( ! current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) )
18
+ return;
19
+ if ( get_user_option( 'rich_editing' ) == 'true') {
20
+ add_filter( 'mce_external_plugins', 'wprss_register_tinymce_plugin' );
21
+ add_filter( 'mce_buttons', 'wprss_register_tinymce_button' );
22
+ }
23
+ }
24
+
25
+
26
+ /**
27
+ * Adds a separator and the wprss button to the buttons array.
28
+ *
29
+ * @since 3.5
30
+ */
31
+ function wprss_register_tinymce_button( $buttons ) {
32
+ array_push( $buttons, "|", "wprss" );
33
+ return $buttons;
34
+ }
35
+
36
+
37
+ /**
38
+ * Adds the button action JS file to TinyMCE's plugin list
39
+ *
40
+ * @todo add filter to skip showing the editor button
41
+ * @since 3.5
42
+ */
43
+ function wprss_register_tinymce_plugin($plugin_array) {
44
+ // add filter here
45
+ $plugin_array['wprss'] = WPRSS_JS . 'editor.js';
46
+ return $plugin_array;
47
+ }
48
+
49
+
50
+ add_filter( 'tiny_mce_version', 'wprss_tinymce_version');
51
+ /**
52
+ * Intercepts TinyMCE's version check and increments its version by 3.
53
+ *
54
+ * This is a hack used to work around TinyMCE's caching, that might prevent the
55
+ * new wprss button from appearing on the editor.
56
+ *
57
+ * @since 3.5
58
+ */
59
+ function wprss_tinymce_version($ver) {
60
+ $ver += 3;
61
+ return $ver;
62
+ }
63
+
64
+
65
+
66
+
67
+
68
+
69
+ add_action( 'wp_ajax_wprss_editor_dialog', 'wprss_return_dialog_contents' );
70
+ /**
71
+ * Renders the TinyMCE button dialog contents.
72
+ */
73
+ function wprss_return_dialog_contents() {
74
+ $templates_collection = wpra_get('feeds/templates/collection');
75
+ $templates_options = [];
76
+ foreach ($templates_collection as $template) {
77
+ $template_name = $template['name'];
78
+ $template_slug = ($template['type'] === '__built_in')
79
+ ? ''
80
+ : $template['slug'];
81
+
82
+ $templates_options[$template_slug] = $template_name;
83
+ }
84
+ $templates_select = wprss_settings_render_select(
85
+ 'wprss-dialog-templates',
86
+ '',
87
+ $templates_options,
88
+ '',
89
+ ['class' => 'widefat']
90
+ );
91
+
92
+ $feed_sources = get_posts( array(
93
+ 'post_type' => 'wprss_feed',
94
+ 'post_status' => 'publish',
95
+ 'posts_per_page' => -1,
96
+ 'no_found_rows' => true
97
+ ));
98
+ $feed_sources_names = [];
99
+ foreach ( $feed_sources as $source ) {
100
+ $feed_sources_names[$source->ID] = $source->post_title;
101
+ }
102
+ $feed_sources_select = wprss_settings_render_select(
103
+ 'wprss-dialog-feed-source-list',
104
+ '',
105
+ $feed_sources_names,
106
+ '',
107
+ ['multiple' => 'multiple', 'class' => 'widefat']
108
+ );
109
+ $feed_sources_exclude_select = wprss_settings_render_select(
110
+ 'wprss-dialog-exclude-list',
111
+ '',
112
+ $feed_sources_names,
113
+ '',
114
+ ['multiple' => 'multiple', 'class' => 'widefat']
115
+ );
116
+
117
+ $feed_sources_both_select = '<p>' . __( 'To select more than one feed source, click and drag with your mouse pointer or click individual feed sources while holding down the Ctrl (Windows) or Command (Mac) key.' , WPRSS_TEXT_DOMAIN ) . '</p>';
118
+ $feed_sources_select .= $feed_sources_both_select;
119
+ $feed_sources_exclude_select .= $feed_sources_both_select;
120
+
121
+ ?>
122
+ <table cellspacing="20">
123
+ <tbody>
124
+ <tr>
125
+ <td id="wprss-dialog-templates-label">
126
+ <label for="wprss-dialog-templates">
127
+ <?php _e( 'Template', WPRSS_TEXT_DOMAIN ) ?>
128
+ </label>
129
+ </td>
130
+ <td>
131
+ <?php echo $templates_select; ?>
132
+ </td>
133
+ </tr>
134
+ <tr>
135
+ <td id="wprss-dialog-all-sources-label">
136
+ <?php _e( 'Sources', WPRSS_TEXT_DOMAIN ) ?>
137
+ </td>
138
+ <td>
139
+ <input id="wprss-dialog-all-sources" type="checkbox" checked>
140
+ <label for="wprss-dialog-all-sources">
141
+ <?php _e( 'All feed sources', WPRSS_TEXT_DOMAIN ) ?>
142
+ </label>
143
+ </td>
144
+ </tr>
145
+
146
+ <tr id="wprss-dialog-exclude-row">
147
+ <td id="wprss-dialog-exclude-label">
148
+ <label id="wprss-dialog-exclude-list-label" for="wprss-dialog-exclude-list">
149
+ <?php _e( 'Exclude', WPRSS_TEXT_DOMAIN ) ?>
150
+ </label>
151
+ </td>
152
+ <td>
153
+ <div id="wprss-dialog-excludes-container">
154
+ <p><?php _e( 'You may choose to exclude some feed sources:', WPRSS_TEXT_DOMAIN ) ?></p>
155
+ <?php echo $feed_sources_exclude_select; ?>
156
+ </div>
157
+
158
+ <div id="wprss-dialog-sources-container" style="display:none">
159
+ <p><?php _e( 'Choose which feed sources to show:', WPRSS_TEXT_DOMAIN ) ?></p>
160
+ <?php echo $feed_sources_select; ?>
161
+ </div>
162
+
163
+ <script type="text/javascript">
164
+ jQuery('#wprss-dialog-all-sources').click( function(){
165
+ if ( jQuery(this).is(':checked') ) {
166
+ jQuery( '#wprss-dialog-sources-container' ).hide();
167
+ jQuery( '#wprss-dialog-excludes-container' ).show();
168
+ jQuery( '#wprss-dialog-exclude-list-label' ).show();
169
+ } else {
170
+ jQuery( '#wprss-dialog-sources-container' ).show();
171
+ jQuery( '#wprss-dialog-excludes-container' ).hide();
172
+ jQuery( '#wprss-dialog-exclude-list-label' ).hide();
173
+ }
174
+ });
175
+ jQuery('#wprss-dialog-submit').click( wprss_dialog_submit );
176
+ </script>
177
+ </td>
178
+ </tr>
179
+
180
+ <tr>
181
+ <td><?php _e( 'Number of items', WPRSS_TEXT_DOMAIN ) ?></td>
182
+ <td>
183
+ <input id="wprss-dialog-feed-limit"
184
+ type="number"
185
+ class="wprss-number-roller widefat"
186
+ placeholder="<?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?>"
187
+ min="0"
188
+ />
189
+ </td>
190
+ </tr>
191
+
192
+ <tr>
193
+ <td><?php _e( 'Pagination', WPRSS_TEXT_DOMAIN ) ?></td>
194
+ <td>
195
+ <label>
196
+ <select id="wprss-dialog-pagination">
197
+ <option value=""><?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?></option>
198
+ <option value="on"><?php _e( 'Enabled', WPRSS_TEXT_DOMAIN ) ?></option>
199
+ <option value="off"><?php _e( 'Disabled', WPRSS_TEXT_DOMAIN ) ?></option>
200
+ </select>
201
+ <br/>
202
+ <span>
203
+ <?php _e( 'Choose whether to show or hide pagination controls', WPRSS_TEXT_DOMAIN ) ?>
204
+ </span>
205
+ </label>
206
+ </td>
207
+ </tr>
208
+
209
+ <tr>
210
+ <td><?php _e( 'Starting page', WPRSS_TEXT_DOMAIN ) ?></td>
211
+ <td>
212
+ <input id="wprss-dialog-start-page"
213
+ type="number"
214
+ class="wprss-number-roller widefat"
215
+ placeholder="<?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?>"
216
+ min="1"
217
+ />
218
+ </td>
219
+ </tr>
220
+
221
+ <?php do_action( 'wprss_return_dialog_contents' ); ?>
222
+
223
+ <tr>
224
+ <td></td>
225
+ <td>
226
+ <button id="wprss-dialog-submit">
227
+ <?php _e( 'Add shortcode', WPRSS_TEXT_DOMAIN ) ?>
228
+ </button>
229
+ </td>
230
+ </tr>
231
+
232
+ </tbody>
233
+ </table>
234
+ <?php
235
+ die();
236
+ }
includes/admin-heartbeat.php CHANGED
@@ -1,71 +1,88 @@
1
  <?php
2
 
3
- add_action('wp_ajax_wprss_feed_source_table_ajax', function () {
4
- $response = [];
 
 
 
 
 
 
5
 
6
- if (!current_user_can('edit_feed_sources') || empty($_POST['wprss_heartbeat'])) {
7
- return [];
8
- }
9
 
10
- $request = isset($_POST['wprss_heartbeat']) ? $_POST['wprss_heartbeat'] : null;
11
- if (!is_array($request)) {
12
- return [];
13
- }
14
 
15
- $action = isset($request['action']) ? $request['action'] : '';
16
- $action = filter_var($action, FILTER_SANITIZE_STRING);
 
 
 
 
 
 
 
 
 
 
17
 
18
- $params = isset($request['params']) ? $request['params'] : '';
19
- $params = filter_var($params, FILTER_VALIDATE_INT, FILTER_REQUIRE_ARRAY);
 
 
 
 
 
20
 
21
- switch ($action) {
22
- case 'feed_sources':
23
- {
24
- $feeds = [];
 
25
 
26
- foreach ($params as $feedId) {
27
- $nextFetch = wprss_get_next_feed_source_update($feedId, false);
28
- $isFetching = wprss_is_feed_source_updating($feedId);
29
- $isDeleting = wprss_is_feed_source_deleting($feedId);
30
- $fetchesSoon = $nextFetch !== false && $nextFetch < 2 && $nextFetch > 0;
31
- $isActive = wprss_is_feed_source_active($feedId);
32
- $numItems = wprss_get_feed_items_for_source($feedId)->post_count;
33
- $lastUpdateTime = get_post_meta($feedId, 'wprss_last_update', true);
34
- $lastUpdateItems = get_post_meta($feedId, 'wprss_last_update_items', true);
35
- $errors = get_post_meta($feedId, 'wprss_error_last_import', true);
 
 
 
 
 
 
 
36
 
37
- if ($nextFetch === false) {
38
- $nextFetchText = __('None', 'wprss');
39
- } elseif ($isActive) {
40
- $nextFetchText = $fetchesSoon
41
- ? _x('now', 'Next update: now', 'wprss')
42
- : human_time_diff($nextFetch, time());
43
- } else {
44
- $nextFetchText = __('...', 'wprss');
45
- }
46
 
47
- $feeds[$feedId] = [
48
- 'active' => $isActive,
49
- 'fetching' => $isFetching || $fetchesSoon,
50
- 'deleting' => $isDeleting,
51
- 'items' => $numItems,
52
- 'next-update' => $nextFetchText,
53
- 'last-update' => empty($lastUpdateTime) ? '' : human_time_diff($lastUpdateTime, time()),
54
- 'last-update-imported' => $lastUpdateItems,
55
- 'errors' => $errors,
56
- ];
57
 
58
- update_post_meta($feedId, 'wprss_items_imported', $numItems);
59
- update_post_meta($feedId, 'wprss_next_update', $nextFetchText);
60
- }
61
 
62
- $response = [
63
- 'wprss_feed_sources_data' => $feeds,
64
- ];
65
- break;
66
- }
67
- }
68
-
69
- echo json_encode($response);
70
- die;
71
- });
 
1
  <?php
2
 
3
+ add_action( 'wp_ajax_wprss_feed_source_table_ajax', 'wprss_feed_source_updates');
4
+ /**
5
+ *
6
+ */
7
+ function wprss_feed_source_updates() {
8
+ $response = array();
9
+
10
+ if ( ! current_user_can( 'edit_feed_sources' ) ) return $response;
11
 
12
+ if ( empty($_POST['wprss_heartbeat']) ) return $response;
 
 
13
 
14
+ // Get the wprss heartbeat data and extract the data
15
+ $wprss_heartbeat = $_POST['wprss_heartbeat'];
16
+ $action = $wprss_heartbeat['action'];
17
+ $params = $wprss_heartbeat['params'];
18
 
19
+ // Perform the action specified by the heartbeat data
20
+ switch( $action ) {
21
+ /* FEED SOURCE UPDATING STATUS
22
+ * Used to determine whether or not to show the updating icon in the feed source table.
23
+ */
24
+ case 'feed_sources':
25
+ // Prepare array of IDs for feed sources currently updating
26
+ $feed_sources_data = array();
27
+ // Iterate all feed sources
28
+ foreach ( $params as $feed_id ) {
29
+ $feed_sources_data[$feed_id] = array();
30
+ $feed_source_data = &$feed_sources_data[$feed_id];
31
 
32
+ // Check if the feed source is updating
33
+ $next_fetch = wprss_get_next_feed_source_update($feed_id);
34
+ $fetches_soon = $next_fetch !== false && $next_fetch < 2 && $next_fetch > 0;
35
+ $is_fetching = wprss_is_feed_source_updating($feed_id);
36
+ $is_deleting = wprss_is_feed_source_deleting($feed_id);
37
+ $feed_source_data['fetching'] = $fetches_soon || $is_fetching;
38
+ $feed_source_data['deleting'] = $is_deleting;
39
 
40
+ // Add the number of imported items
41
+ $items = wprss_get_feed_items_for_source( $feed_id );
42
+ $feed_source_data['items'] = $items->post_count;
43
+ // Update the meta field
44
+ update_post_meta( $feed_id, 'wprss_items_imported', $items->post_count );
45
 
46
+ // Add the next update time
47
+ $next_update = wprss_get_next_feed_source_update( $feed_id );
48
+ $update_interval = get_post_meta( $feed_id, 'wprss_update_interval', TRUE );
49
+ // If using the global interval, get the timestamp of the next global update
50
+ if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
51
+ $next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
52
+ }
53
+ // Set the text appropriately
54
+ if ( ! wprss_is_feed_source_active( $feed_id ) ) {
55
+ $feed_source_data['next-update'] = __( '...', 'wprss' );
56
+ }
57
+ elseif( $next_update === FALSE ) {
58
+ $feed_source_data['next-update'] = __( 'None', 'wprss' );
59
+ wprss_activate_feed_source( $feed_id );
60
+ }
61
+ else {
62
+ $time_diff = absint($next_update - time());
63
 
64
+ $feed_source_data['next-update'] = ($time_diff > 1)
65
+ ? human_time_diff( $next_update, time() )
66
+ : _x('now', 'Next update: now', 'wprss');
67
+ }
68
+ // Update the meta field
69
+ update_post_meta( $feed_id, 'wprss_next_update', $feed_source_data['next-update'] );
 
 
 
70
 
71
+ // Add the last update information
72
+ $last_update = get_post_meta( $feed_id, 'wprss_last_update', TRUE );
73
+ $last_update_items = get_post_meta( $feed_id, 'wprss_last_update_items', TRUE );
 
 
 
 
 
 
 
74
 
75
+ $feed_source_data['last-update'] = ( $last_update === '' )? '' : human_time_diff( $last_update, time() );
76
+ $feed_source_data['last-update-imported'] = $last_update_items;
 
77
 
78
+ // Add any error info
79
+ $errors = get_post_meta( $feed_id, 'wprss_error_last_import', true );
80
+ $feed_source_data['errors'] = $errors;
81
+ }
82
+ // Send back all the IDs
83
+ $response['wprss_feed_sources_data'] = $feed_sources_data;
84
+ break;
85
+ }
86
+ // Return the response
87
+ die( json_encode($response) );
88
+ }
includes/admin-help-metaboxes.php CHANGED
@@ -1,139 +1,92 @@
1
  <?php
2
 
3
- add_action('plugins_loaded', function () {
4
- if (!class_exists('WPRSS_Help')) {
5
- return;
6
- }
7
-
8
- $help = WPRSS_Help::get_instance();;
9
-
10
- // Feed source setting fields
11
- $prefix = 'field_';
12
- $tooltips = [
13
- /* -----------------------------
14
- * Feed Source Details Metabox
15
- * -----------------------------
16
- */
17
- // Feed Source URL
18
- 'wprss_url' => __(
19
- "The URL of the feed source. In most cases, the URL of the site will also work, but for best results we recommend trying to find the URL of the RSS feed." .
20
- "\n\n" .
21
- "Also include the <code>http://</code> or <code>https://</code> prefix in the URL.",
22
- 'wprss'
23
- ),
24
- // Feed limit
25
- 'wprss_limit' => __(
26
- 'The maximum number of imported items from this feed to keep stored.' .
27
- "\n\n" .
28
- 'When new items are imported and the limit is exceeded, the oldest feed items will be deleted to make room for new ones.' .
29
- "\n\n" .
30
- 'If you already have items imported from this feed source, setting this option now may delete some of your items, in order to comply with the limit.',
31
- 'wprss'
32
- ),
33
- // Link to Enclosure
34
- 'wprss_enclosure' => __(
35
- 'Tick this box to make imported items link to their enclosure, rather than to the original article.' .
36
- "\n\n" .
37
- 'Enclosures are typically links to attachments, such as images, audio, videos, documents or flash content.' .
38
- "\n\n" .
39
- 'If you are not sure, leave this option unticked.',
40
- 'wprss'
41
- ),
42
-
43
- 'wprss_unique_titles' => __(
44
- 'Whether to allow multiple feed items to have the same title. When checked, if a feed item has the same title as a previously-imported feed item, it will not be imported.' .
45
- "\n\n" .
46
- 'This can be useful in cases where permalinks change, or where multiple permalinks refer to the same item.',
47
- 'wprss'
48
- ),
49
-
50
- 'wprss_source_link' => __(
51
- 'Enable this option to link the feed source name to the RSS feed\'s source site.' .
52
- "\n\n" .
53
- 'Selecting "Default" will cause the value chosen in the general Source Display Settings to be used.' .
54
- "\n\n" .
55
- 'This option only applies when using the shortcode to output feed items.',
56
- 'wprss'
57
- ),
58
-
59
- 'wprss_use_guids' => __(
60
- 'Enable this option to identify duplicate feed items by their GUIDs, rather than by their permalink.' .
61
- "\n\n" .
62
- 'This can be useful when the feed items share the same permalink, and so not all feed items would get imported.',
63
- 'wprss'
64
- ),
65
-
66
- 'wprss_import_source' => __(
67
- 'Tick this box to get the site name and URL from the RSS feed, for each item individually.' .
68
- "\n\n" .
69
- 'This option is useful when importing from aggregated RSS feeds that have items from different sources.' .
70
- "\n\n" .
71
- 'If the RSS feed does not provide source information for its items, the name and URL that you have given for the feed source will be used instead.',
72
- 'wprss'
73
- ),
74
-
75
- /* -------------------------
76
- * Feed Processing Metabox
77
- * -------------------------
78
- */
79
- // Feed State
80
- 'wprss_state' => __(
81
- 'State of the feed, active or paused.' .
82
- "\n\n" .
83
- 'If active, the feed source will fetch items periodically, according to the settings below.' .
84
- "\n\n" .
85
- 'If paused, the feed source will not fetch feed items periodically.',
86
- 'wprss'
87
- ),
88
-
89
- // Activate Feed: [date]
90
- 'wprss_activate_feed' => __(
91
- 'You can set a time, in UTC, in the future when the feed source will become active, if it is paused.' .
92
- "\n\n" .
93
- 'Leave blank to activate immediately.',
94
- 'wprss'
95
- ),
96
-
97
- // Pause Feed: [date]
98
- 'wprss_pause_feed' => __(
99
- 'You can set a time, in UTC, in the future when the feed source will become paused, if it is active.' .
100
- "\n\n" .
101
- 'Leave blank to never pause.',
102
- 'wprss'
103
- ),
104
-
105
- // Update Interval
106
- 'wprss_update_interval' => __(
107
- 'How frequently the feed source should check for new items and fetch if needed.' .
108
- "\n\n" .
109
- 'If left as <em>Default</em>, the interval in the global settings is used.',
110
- 'wprss'
111
- ),
112
-
113
- // Delete items older than: [date]
114
- 'wprss_age_limit' => __(
115
- 'The maximum age allowed for feed items. Very useful if you are only concerned with, say, last week\'s news.' .
116
- "\n\n" .
117
- 'Items already imported will be deleted if they eventually exceed this age limit.' .
118
- "\n\n" .
119
- 'Also, items in the RSS feed that are already older than this age will not be imported at all.' .
120
- "\n\n" .
121
- 'Leave empty to use the <em>Limit feed items by age</em> option in the general settings.',
122
- 'wprss'
123
- ),
124
-
125
- /* ----------------------
126
- * Feed Preview Metabox
127
- * ----------------------
128
- */
129
- // Force Feed
130
- 'wprss_force_feed' => __(
131
- 'Use this option if you are seeing an <q>Invalid feed URL</q> error in the Feed Preview above, but you are sure that the URL is correct.' .
132
- "\n\n" .
133
- 'Note, however, that this will disable auto-discovery, meaning that the given URL must be an RSS feed URL. Using the site\'s URL will not work.',
134
- 'wprss'
135
- ),
136
- ];
137
-
138
- $help->add_tooltips($tooltips, $prefix);
139
- }, 11);
1
  <?php
2
 
3
+ add_action( 'plugins_loaded', 'wprss_metaboxes_add_tooltips', 11 );
4
+ function wprss_metaboxes_add_tooltips() {
5
+
6
+ if( class_exists('WPRSS_Help') ) {
7
+ $help = WPRSS_Help::get_instance();
8
+
9
+ // Feed source setting fields
10
+ $prefix = 'field_';
11
+ $tooltips = array(
12
+ /* -----------------------------
13
+ * Feed Source Details Metabox
14
+ * -----------------------------
15
+ */
16
+ // Feed Source URL
17
+ 'wprss_url' => __('The URL of the feed source. In most cases, the URL of the site will also work, but for best results we recommend trying to find the URL of the RSS feed.
18
+
19
+ ' . 'Also include the <code>http://</code> or <code>https://</code> prefix in the URL.', WPRSS_TEXT_DOMAIN),
20
+ // Feed limit
21
+ 'wprss_limit' => __('The maximum number of imported items from this feed to keep stored.
22
+
23
+ '. 'When new items are imported and the limit is exceeded, the oldest feed items will be deleted to make room for new ones.
24
+
25
+ '. 'If you already have items imported from this feed source, setting this option now may delete some of your items, in order to comply with the limit.', WPRSS_TEXT_DOMAIN),
26
+ // Link to Enclosure
27
+ 'wprss_enclosure' => __('Tick this box to make imported items link to their enclosure, rather than to the original article.
28
+
29
+ '. 'Enclosures are typically links to attachments, such as images, audio, videos, documents or flash content.
30
+
31
+ '. 'If you are not sure, leave this option unticked', WPRSS_TEXT_DOMAIN),
32
+
33
+ 'wprss_unique_titles' => __('Whether to allow multiple feed items to have the same title. When checked, if a feed item has the same title as a previously-imported feed item, it will not be imported.
34
+
35
+ '. 'This can be useful in cases where permalinks change, or where multiple permalinks refer to the same item.', WPRSS_TEXT_DOMAIN),
36
+
37
+ 'wprss_source_link' => __('Enable this option to link the feed source name to the RSS feed\'s source site.
38
+
39
+ ' . 'Selecting "Default" will cause the value chosen in the general Source Display Settings to be used.
40
+
41
+ ' . 'This option only applies when using the shortcode to output feed items.', WPRSS_TEXT_DOMAIN),
42
+
43
+ 'wprss_import_source' => __('Tick this box to get the site name and URL from the RSS feed, for each item individually.
44
+
45
+ ' . 'This option is useful when importing from aggregated RSS feeds that have items from different sources.
46
+
47
+ ' . 'If the RSS feed does not provide source information for its items, the name and URL that you have given for the feed source will be used instead.'
48
+ , 'wprss'),
49
+
50
+ /* -------------------------
51
+ * Feed Processing Metabox
52
+ * -------------------------
53
+ */
54
+ // Feed State
55
+ 'wprss_state' => __('State of the feed, active or paused.
56
+
57
+ '. 'If active, the feed source will fetch items periodically, according to the settings below.
58
+
59
+ '. 'If paused, the feed source will not fetch feed items periodically.', WPRSS_TEXT_DOMAIN),
60
+ // Activate Feed: [date]
61
+ 'wprss_activate_feed' => __('You can set a time, in UTC, in the future when the feed source will become active, if it is paused.
62
+
63
+ '. 'Leave blank to activate immediately.', WPRSS_TEXT_DOMAIN),
64
+ // Pause Feed: [date]
65
+ 'wprss_pause_feed' => __('You can set a time, in UTC, in the future when the feed source will become paused, if it is active.
66
+
67
+ '. 'Leave blank to never pause.', WPRSS_TEXT_DOMAIN),
68
+ // Update Interval
69
+ 'wprss_update_interval' => __('How frequently the feed source should check for new items and fetch if needed.
70
+
71
+ '. 'If left as <em>Default</em>, the interval in the global settings is used.', WPRSS_TEXT_DOMAIN),
72
+ // Delete items older than: [date]
73
+ 'wprss_age_limit' => __('The maximum age allowed for feed items. Very useful if you are only concerned with, say, last week\'s news.
74
+
75
+ '. 'Items already imported will be deleted if they eventually exceed this age limit.
76
+
77
+ '. 'Also, items in the RSS feed that are already older than this age will not be imported at all.
78
+
79
+ '. 'Leave empty to use the <em>Limit feed items by age</em> option in the general settings.', WPRSS_TEXT_DOMAIN),
80
+
81
+ /* ----------------------
82
+ * Feed Preview Metabox
83
+ * ----------------------
84
+ */
85
+ // Force Feed
86
+ 'wprss_force_feed' => __('Use this option if you are seeing an <q>Invalid feed URL</q> error in the Feed Preview above, but you are sure that the URL is correct.
87
+
88
+ '. 'Note, however, that this will disable auto-discovery, meaning that the given URL must be an RSS feed URL. Using the site\'s URL will not work.', WPRSS_TEXT_DOMAIN)
89
+ );
90
+ $help->add_tooltips( $tooltips, $prefix );
91
+ }
92
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin-help-settings.php CHANGED
@@ -1,238 +1,197 @@
1
  <?php
2
 
3
- add_action('plugins_loaded', function () {
4
- if (!class_exists('WPRSS_Help')) {
5
- return;
6
- }
7
-
8
- $help = WPRSS_Help::get_instance();
9
-
10
- // Feed source setting fields
11
- $prefix = 'setting-';
12
- $tooltips = [
13
- /* -----------------
14
- * General Section
15
- * -----------------
16
- */
17
- // Limit feed items by age
18
- 'limit-feed-items-by-age' => __(
19
- 'The maximum age allowed for feed items.' .
20
- "\n<hr/>\n\n" .
21
- 'Items already imported will be deleted if they eventually exceed this age limit.' .
22
- "\n\n" .
23
- 'Also, items in the RSS feed that are already older than this age will not be imported at all.' .
24
- "\n<hr/>\n\n" .
25
- '<em>Leave empty for no limit.</em>',
26
- 'wprss'
27
- ),
28
- // Limit feed items per feed
29
- 'limit-feed-items-imported' => __(
30
- 'The maximum number of imported items to keep stored, for feed sources that do not have their own limit.' .
31
- "\n<hr/>\n\n" .
32
- 'When new items are imported and the limit for a feed source is exceeded, the oldest feed items for that feed source will be deleted to make room for the new ones.' .
33
- "\n\n" .
34
- 'If you already have items imported from this feed source, setting this option now may delete some of your items, in order to comply with the limit.' .
35
- "\n<hr/>\n\n" .
36
- '<em>Use 0 or leave empty for no limit.</em>',
37
- 'wprss'
38
- ),
39
- // Limit feed items per import
40
- 'limit_feed_items_per_import' => __(
41
- 'The maximum amount of items to process per import.' .
42
- "\n<hr/>\n\n" .
43
- 'Will not process more than this amount of items every time the feed source updates, regardless of other settings.' .
44
- "\n\n" .
45
- 'The frequency of updates is determined by the feed processing interval.' .
46
- "\n<hr/>\n\n" .
47
- '<em>Leave empty for no limit.</em>',
48
- 'wprss'
49
- ),
50
- // Feed items import order
51
- 'feed_items_import_order' => __(
52
- 'The order in which feed items will be imported.' .
53
- "\n<hr />\n\n" .
54
- '<strong>Latest items first</strong> will import the most recent items in the feed first.' .
55
- "\n" .
56
- '<strong>Oldest items first</strong> will import the oldest items in the feed first.' .
57
- "\n" .
58
- '<strong>Original feed order</strong> only works well on PHP7 or later.' .
59
- "\n\n" .
60
- 'This setting is very useful in combination with the per-import limit.' .
61
- "\n<hr />\n\n" .
62
- 'Default: <em>Latest items first</em>',
63
- 'wprss'
64
- ),
65
- // Schedule future items
66
- 'schedule_future_items' => __(
67
- 'If ticked, items with future dates will be scheduled to be published later. Leave unticked to always publish items immediately.' .
68
- "\n<hr/>\n\n" .
69
- 'Default: <em>Off</em>',
70
- 'wprss'
71
- ),
72
- // Feed processing interval
73
- 'cron-interval' => __(
74
- 'How frequently should the feed sources (that do not have their own update interval) check for updates and fetch items accordingly.' .
75
- "\n\n" .
76
- 'It is recommended to not have more than 20 feed sources that use this global update interval. Having too many feed sources updating precisely at the same time can cause the WP Cron System to crash.',
77
- 'wprss'),
78
- // Unique titles only
79
- 'unique-titles' => __(
80
- 'Whether to allow multiple feed items to have the same title. When checked, if a feed item has the same title as a previously-imported feed item from any feed source, it will not be imported.' .
81
- "\n\n" .
82
- 'This can be useful in cases where permalinks change, or where multiple permalinks refer to the same item.' .
83
- "\n\n" .
84
- 'Since this feature requires checking every post title, WordPress installs with a significant amount of posts may notice a slight slowdown of the post import process.',
85
- 'wprss'
86
- ),
87
- // Custom Feed URL
88
- 'custom-feed-url' => __(
89
- 'The URL of the custom feed, located at <code>https://yoursite.com/[custom feed url]</code>.' .
90
- "\n<hr/>\n\n" .
91
-
92
- 'WP RSS Aggregator allows you to create a custom RSS feed, that contains all of your imported feed items. This setting allows you to change the URL of this custom feed.' .
93
- "\n\n<hr/>\n\n" .
94
- '<strong>Note:</strong> You may be required to refresh you Permalinks after you change this setting, by going to <em>Settings <i class="fa fa-angle-right"></i> Permalinks</e> and clicking <em>Save</em>.',
95
- 'wprss'
96
- ),
97
- // Custom Feed Title
98
- 'custom-feed-title' => __(
99
- 'The title of the custom feed.' .
100
- "\n\n" .
101
- 'This title will be included in the RSS source of the custom feed, in a <code>&lt;title&gt;</code> tag.',
102
- 'wprss'
103
- ),
104
- // Custom Feed Limit
105
- 'custom-feed-limit' => __('The maximum number of feed items in the custom feed.', 'wprss'),
106
-
107
- /* --------------------------
108
- * General Display Settings
109
- * --------------------------
110
- */
111
- // Link titles
112
- 'link-enable' => __('Check this box to make the feed item titles link to the original article.', 'wprss'),
113
- // Title Maximum length
114
- 'title-limit' => __(
115
- 'Set the maximum number of characters to show for feed item titles.' .
116
- "\n<hr/>\n\n" .
117
- '<em>Leave empty for no limit.</em>',
118
- 'wprss'
119
- ),
120
- // Show Authors
121
- 'authors-enable' => __('Check this box to show the author for each feed item, if it is available.', 'wprss'),
122
- // Video Links
123
- 'video-links' => __(
124
- 'For feed items from YouTube, Vimeo or Dailymotion, you can choose whether you want to have the items link to the original page link, or a link to the embedded video player only.',
125
- 'wprss'
126
- ),
127
- // Pagination Type
128
- 'pagination' => __(
129
- 'The type of pagination to use when showing feed items on multiple pages.' .
130
- "\n\n" .
131
- 'The first shows two links, "Older" and "Newer", which allow you to navigate through the pages.' .
132
- "\n\n" .
133
- 'The second shows links for all the pages, together with links for the next and previous pages.',
134
- 'wprss'
135
- ),
136
- // Feed Limit
137
- 'feed-limit' => __(
138
- 'The maximum number of feed items to display when using the shortcode.' .
139
- "\n\n" .
140
- 'This enables pagination if set to a number smaller than the number of items to be displayed.',
141
- 'wprss'
142
- ),
143
- // Open Links Behaviour
144
- 'open-dd' => __(
145
- 'Choose how you want links to be opened. This applies to the feed item title and the source link.',
146
- 'wprss'
147
- ),
148
- // Set links as no follow
149
- 'follow-dd' => __(
150
- 'Enable this option to set all links displayed as "NoFollow".' .
151
- "\n<hr/>\n\n" .
152
- '"Nofollow" provides a way to tell search engines to <em>not</em> follow certain links, such as links to feed items in this case.',
153
- 'wprss'
154
- ),
155
-
156
- /* -------------------------
157
- * Source Display Settings
158
- * -------------------------
159
- */ // Source Enabled
160
- 'source-enable' => __('Enable this option to show the feed source name for each feed item.', 'wprss'),
161
- // Text preceding source
162
- 'text-preceding-source' => __(
163
- 'Enter the text that you want to show before the source name. A space is automatically added between this text and the feed source name.',
164
- 'wprss'
165
- ),
166
- // Source Link
167
- 'source-link' => __('Enable this option to link the feed source name to the RSS feed\'s source site.', 'wprss'),
168
-
169
- /* -------------------------
170
- * Date Display Settings
171
- * -------------------------
172
- */ // Source Enabled
173
- 'date-enable' => __('Enable this to show the feed item\'s date.', 'wprss'),
174
- // Text preceding date
175
- 'text-preceding-date' => __(
176
- 'Enter the text that you want to show before the feed item date. A space is automatically added between this text and the date.',
177
- 'wprss'
178
- ),
179
- // Date Format
180
- 'date-format' => __('The format to use for the feed item dates, as a PHP date format.', 'wprss'),
181
- // Time Ago Format Enable
182
- 'time-ago-format-enable' => __(
183
- 'Enable this option to show the elapsed time from the feed item\'s date and time to the present time.' .
184
- "\n" .
185
- '<em>Eg. 2 hours ago</em>',
186
- 'wprss'
187
- ),
188
-
189
- /* --------
190
- * Styles
191
- * --------
192
- */
193
- // Styles Disable
194
- 'styles-disable' => __(
195
- 'Check this box to disable all plugin styles used for displaying feed items.' .
196
- "\n\n" .
197
- 'This will allow you to provide your own custom CSS styles for displaying the feed items.',
198
- 'wprss'
199
- ),
200
-
201
- /*
202
- * -------
203
- * Other
204
- * -------
205
- */
206
- // Certificate Path
207
- 'certificate-path' => __(
208
- 'Path to the file containing one or more certificates.' .
209
- "\n\n" .
210
- 'These will be used to verify certificates over secure connection, such as when fetching a remote resource over HTTPS.' .
211
- "\n\n" .
212
- 'Relative path will be relative to the WordPress root.' .
213
- "\n\n" .
214
- '<strong>Default:</strong> path to certificate file bundled with WordPress.',
215
- 'wprss'
216
- ),
217
-
218
- /** @since 4.8.2 */
219
- 'feed_request_useragent' => __(
220
- 'The user agent string that WP RSS Aggregator uses for feed requests.' .
221
- "\n\n" .
222
- 'You should leave this blank. Only change it if you know what you\'re doing.' .
223
- "\n<hr/>\n\n" .
224
- '<strong>Important:</strong> Do not use this option to circumvent any security mechanisms that an RSS feed server may have put in place. Servers reserve the right to block you or WP RSS Aggregator.' .
225
- "\n\n" .
226
- 'Attempting to bypass such blocks may result in legal action being taken against you. WP RSS Aggregator will not be held liable for misuse of this setting.',
227
- 'wprss'
228
- ),
229
- ];
230
-
231
- $help->add_tooltips($tooltips, $prefix);
232
-
233
- // Feed source specific
234
- $prefix = 'field_';
235
- $help->add_tooltips([
236
- WPRSS_Feed_Access::SETTING_KEY_FEED_REQUEST_USERAGENT => $tooltips['feed_request_useragent'],
237
- ], $prefix);
238
- }, 11);
1
  <?php
2
 
3
+ add_action( 'plugins_loaded', 'wprss_settings_add_tooltips', 11 );
4
+ function wprss_settings_add_tooltips() {
5
+ if( class_exists('WPRSS_Help') ) {
6
+ $wprss = wprss();
7
+ $help = WPRSS_Help::get_instance();
8
+
9
+ // Feed source setting fields
10
+ $prefix = 'setting-';
11
+ $tooltips = array(
12
+ /* -----------------
13
+ * General Section
14
+ * -----------------
15
+ */ // Limit feed items by age
16
+ 'limit-feed-items-by-age' => __( 'The maximum age allowed for feed items.
17
+ '. '<hr/>
18
+
19
+ '. 'Items already imported will be deleted if they eventually exceed this age limit.
20
+
21
+ '. 'Also, items in the RSS feed that are already older than this age will not be imported at all.
22
+ '. '<hr/>
23
+
24
+ '. '<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
25
+ // Limit feed items per feed
26
+ 'limit-feed-items-imported' => __('The maximum number of imported items to keep stored, for feed sources that do not have their own limit.
27
+ '. '<hr/>
28
+
29
+ '. 'When new items are imported and the limit for a feed source is exceeded, the oldest feed items for that feed source will be deleted to make room for the new ones.
30
+
31
+ '. 'If you already have items imported from this feed source, setting this option now may delete some of your items, in order to comply with the limit.
32
+ '. '<hr/>
33
+
34
+ '. '<em>Use 0 or leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
35
+ // Limit feed items per import
36
+ 'limit_feed_items_per_import' => __('The maximum amount of items to process per import.
37
+ '. '<hr />
38
+
39
+ '. 'Will not process more than this amount of items every time the feed source updates, regardless of other settings.
40
+ '. 'The frequency of updates is determined by the feed processing interval.
41
+ '. '<hr />
42
+
43
+ '. '<em>Leave empty for no limit.</em>',
44
+ WPRSS_TEXT_DOMAIN),
45
+ // Feed items import order
46
+ 'feed_items_import_order' => __('The order in which feed items will be imported.
47
+ '. '<hr />
48
+
49
+ '. '<strong>Latest items first</strong> will import the most recent items in the feed first.
50
+ '. '<strong>Oldest items first</strong> will import the oldest items in the feed first.
51
+ '. '<strong>Original feed order</strong> only works well on PHP7 or later.
52
+ '. '
53
+ '. 'This setting is very useful in combination with the per-import limit.
54
+ '. '<hr />
55
+
56
+ '. 'Default: <em>Latest items first</em>',
57
+ WPRSS_TEXT_DOMAIN),
58
+ // Schedule future items
59
+ 'schedule_future_items' => __('If ticked, items with future dates will be scheduled to be published later. Leave unticked to always publish items immediately.
60
+ <hr/>
61
+ Default: <em>Off</em>',
62
+ 'wprss'),
63
+ // Feed processing interval
64
+ 'cron-interval' => __('How frequently should the feed sources (that do not have their own update interval) check for updates and fetch items accordingly.
65
+
66
+ '. 'It is recommended to not have more than 20 feed sources that use this global update interval. Having too many feed sources updating precisely at the same time can cause the WP Cron System to crash.', WPRSS_TEXT_DOMAIN),
67
+ // Unique titles only
68
+ 'unique-titles' => __('Whether to allow multiple feed items to have the same title. When checked, if a feed item has the same title as a previously-imported feed item from any feed source, it will not be imported.
69
+
70
+ '. 'This can be useful in cases where permalinks change, or where multiple permalinks refer to the same item.
71
+
72
+ '. 'Since this feature requires checking every post title, WordPress installs with a significant amount of posts may notice a slight slowdown of the post import process.', WPRSS_TEXT_DOMAIN),
73
+ // Custom Feed URL
74
+ 'custom-feed-url' => __('The URL of the custom feed, located at <code>https://yoursite.com/[custom feed url]</code>.
75
+ '. '<hr/>
76
+
77
+ '. 'WP RSS Aggregator allows you to create a custom RSS feed, that contains all of your imported feed items. This setting allows you to change the URL of this custom feed.
78
+
79
+ '. '<hr/>
80
+
81
+ '. '<strong>Note:</strong> You may be required to refresh you Permalinks after you change this setting, by going to <em>Settings <i class="fa fa-angle-right"></i> Permalinks</e> and clicking <em>Save</em>.', WPRSS_TEXT_DOMAIN),
82
+ // Custom Feed Title
83
+ 'custom-feed-title' => __('The title of the custom feed.
84
+
85
+ '. 'This title will be included in the RSS source of the custom feed, in a <code>&lt;title&gt;</code> tag.', WPRSS_TEXT_DOMAIN),
86
+ // Custom Feed Limit
87
+ 'custom-feed-limit' => __('The maximum number of feed items in the custom feed.', WPRSS_TEXT_DOMAIN),
88
+
89
+ /* --------------------------
90
+ * General Display Settings
91
+ * --------------------------
92
+ */ // Link titles
93
+ 'link-enable' => __('Check this box to make the feed item titles link to the original article.', WPRSS_TEXT_DOMAIN),
94
+ // Title Maximum length
95
+ 'title-limit' => __('Set the maximum number of characters to show for feed item titles.
96
+ '. '<hr/>
97
+
98
+ '. '<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
99
+ // Show Authors
100
+ 'authors-enable' => __('Check this box to show the author for each feed item, if it is available.', WPRSS_TEXT_DOMAIN),
101
+ // Video Links
102
+ 'video-links' => __('For feed items from YouTube, Vimeo or Dailymotion, you can choose whether you want to have the items link to the original page link, or a link to the embedded video player only.', WPRSS_TEXT_DOMAIN),
103
+ // Pagination Type
104
+ 'pagination' => __('The type of pagination to use when showing feed items on multiple pages.
105
+
106
+ '. 'The first shows two links, "Older" and "Newer", which allow you to navigate through the pages.
107
+
108
+ '. 'The second shows links for all the pages, together with links for the next and previous pages.', WPRSS_TEXT_DOMAIN),
109
+ // Feed Limit
110
+ 'feed-limit' => __('The maximum number of feed items to display when using the shortcode.
111
+
112
+ '. 'This enables pagination if set to a number smaller than the number of items to be displayed.', WPRSS_TEXT_DOMAIN),
113
+ // Open Links Behaviour
114
+ 'open-dd' => __('Choose how you want links to be opened. This applies to the feed item title and the source link.', WPRSS_TEXT_DOMAIN),
115
+ // Set links as no follow
116
+ 'follow-dd' => __('Enable this option to set all links displayed as "NoFollow".
117
+ '. '<hr/>
118
+
119
+ '. '"Nofollow" provides a way to tell search engines to <em>not</em> follow certain links, such as links to feed items in this case.', WPRSS_TEXT_DOMAIN),
120
+
121
+ /* -------------------------
122
+ * Source Display Settings
123
+ * -------------------------
124
+ */ // Source Enabled
125
+ 'source-enable' => __('Enable this option to show the feed source name for each feed item.', WPRSS_TEXT_DOMAIN),
126
+ // Text preceding source
127
+ 'text-preceding-source' => __('Enter the text that you want to show before the source name. A space is automatically added between this text and the feed source name.', WPRSS_TEXT_DOMAIN),
128
+ // Source Link
129
+ 'source-link' => __('Enable this option to link the feed source name to the RSS feed\'s source site.', WPRSS_TEXT_DOMAIN),
130
+
131
+ /* -------------------------
132
+ * Date Display Settings
133
+ * -------------------------
134
+ */ // Source Enabled
135
+ 'date-enable' => __('Enable this to show the feed item\'s date.', WPRSS_TEXT_DOMAIN),
136
+ // Text preceding date
137
+ 'text-preceding-date' => __('Enter the text that you want to show before the feed item date. A space is automatically added between this text and the date.', WPRSS_TEXT_DOMAIN),
138
+ // Date Format
139
+ 'date-format' => __('The format to use for the feed item dates, as a PHP date format.', WPRSS_TEXT_DOMAIN),
140
+ // Time Ago Format Enable
141
+ 'time-ago-format-enable' => __('Enable this option to show the elapsed time from the feed item\'s date and time to the present time.
142
+ '. '<em>Eg. 2 hours ago</em>', WPRSS_TEXT_DOMAIN),
143
+
144
+ /* --------
145
+ * Styles
146
+ * --------
147
+ */ // Styles Disable
148
+ 'styles-disable' => __('Check this box to disable all plugin styles used for displaying feed items.
149
+
150
+ '. 'This will allow you to provide your own custom CSS styles for displaying the feed items.', WPRSS_TEXT_DOMAIN),
151
+
152
+ /*
153
+ * -------
154
+ * Other
155
+ * -------
156
+ */ // Certificate Path
157
+ 'certificate-path' => __( 'Path to the file containing one or more certificates.
158
+
159
+ '. 'These will be used to verify certificates over secure connection, such as when fetching a remote resource over HTTPS.
160
+
161
+ '. 'Relative path will be relative to the WordPress root.
162
+
163
+ '. '<strong>Default:</strong> path to certificate file bundled with WordPress.', WPRSS_TEXT_DOMAIN ),
164
+
165
+ /** @since 4.8.2 */
166
+ 'feed_request_useragent' => __( 'The string to be used as the useragent for feed requests.
167
+
168
+ '. 'If non-empty, this exact string will be sent with every request made by WP RSS Aggregator for a feed source XML document.
169
+
170
+ '. 'Some servers react in unexpected ways to the default value. In such cases, try changing this to something else.
171
+
172
+ '. 'The default value is the useragent that the Chrome Browser uses.'),
173
+ 'feed_cache_enabled' => __( 'Tick this box to enable caching for a small performance gain.
174
+
175
+ '. 'When enabled, websites may ignore the plugin if their RSS feed did not change. So we suggest testing it out first to ensure that your RSS feeds work well with this option enabled.
176
+
177
+ '. 'If you encounter problems or weird behavior, we suggest turning this option off.',
178
+ 'wprss')
179
+ );
180
+ $help->add_tooltips( $tooltips, $prefix );
181
+
182
+ // Feed source specific
183
+ $prefix = 'field_';
184
+ $help->add_tooltips(array(
185
+ WPRSS_Feed_Access::SETTING_KEY_FEED_REQUEST_USERAGENT => $wprss->__( array('The string to be used as the useragent for feed requests.
186
+
187
+ '. 'If non-empty, this exact string will be sent with every request made by %1$s for a feed source XML document.
188
+
189
+ '. 'Leave this empty to inherit the general setting.
190
+
191
+ '. 'Some servers react in unexpected ways to the default value. In such cases, try changing this to something else.
192
+
193
+ '. 'The default value is the useragent that the Chrome browser uses.',
194
+ $wprss->getName()))
195
+ ), $prefix);
196
+ }
197
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin-help.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
- use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
4
 
5
- /**
6
  * Checks if the HS becaon is enabled or not.
7
  *
8
  * @since 4.12.1
@@ -13,90 +13,86 @@ use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
13
  return (int) get_option('wprss_hs_beacon_enabled', 1) === 1;
14
  }
15
 
16
- /**
17
- * Build the Help page
18
- *
19
- * @since 4.2
20
- */
21
- function wprss_help_page_display() {
22
- ?>
23
 
24
- <div class="wrap">
25
- <h2><?php _e( 'Help & Support', 'wprss' ); ?></h2>
26
  <?php do_action('wpra/help_page/after_title') ?>
27
- <h3><?php _e( 'Knowledge Base', 'wprss' ) ?></h3>
28
- <?php
29
- printf(
30
- wpautop(
31
- __( 'In the <a href="%s">WP RSS Aggregator knowledge base</a> you will find comprehensive details and tutorials on how to use the core plugin and all the add-ons.
32
-
33
- There are also some videos to help you make a quick start to setting up and enjoying this plugin.',
34
- 'wprss'
35
- )
36
- ),
37
- esc_attr('https://kb.wprssaggregator.com/')
38
- );
39
- ?>
40
- <h3><?php _e( 'Frequently Asked Questions (FAQ)', 'wprss' ) ?></h3>
41
- <?php
42
- printf(
43
- wpautop(
44
- __(
45
- 'If after going through the knowledge base you still have questions, please take a look at the <a href="%s">FAQ section</a>. We set this up purposely to answer the most commonly asked questions from our users.',
46
- 'wprss'
47
- )
48
- ),
49
- esc_attr('https://kb.wprssaggregator.com/category/359-faqs')
50
- )
51
- ?>
52
-
53
- <?php
54
- if ( wprss_licensing_get_manager()->licenseWithStatusExists( License_Status::VALID ) ) {
55
- wprss_premium_help_display();
56
- } else {
57
- wprss_free_help_display();
58
- }
59
- ?>
60
- <h3><?= __('Built-in Help Beacon', 'wprss') ?></h3>
61
  <form method="POST">
62
  <p>
63
- <?= __('The help beacon is an interactive button that appears on the bottom-right section of WP RSS Aggregator admin pages.', 'wprss'); ?>
64
- <?= __('It provides access to our extensive knowledge base where you can find the answers to the most commonly asked questions.', 'wprss'); ?>
65
  </p>
66
  <p>
67
- <?= __('The beacon only works on WP RSS Aggregator admin pages and does not track your mouse clicks and/or keyboard input.', 'wprss'); ?>
68
  </p>
69
-
70
  <?php if (wprss_is_help_beacon_enabled()): ?>
71
- <p><?= __('The support beacon is currently <b>enabled</b>.', 'wprss'); ?></p>
72
  <button type="submit" name="wprss_hs_beacon_enabled" value="0" class="button button-secondary">
73
- <?= __('Disable support beacon', 'wprss'); ?>
74
  </button>
75
  <?php else: ?>
76
- <p>
77
- <?= __('By enabling the help beacon, you are consenting to this data collection.', 'wprss'); ?>
78
- </p>
79
  <button type="submit" name="wprss_hs_beacon_enabled" value="1" class="button button-primary">
80
- <?= __('Enable support beacon', 'wprss'); ?>
81
  </button>
82
  <?php endif; ?>
83
 
84
  <?php wp_nonce_field('wprss_hs_beacon_enabled'); ?>
85
  </form>
86
- </div>
87
- <?php
88
  do_action('wpra/help_page/bottom');
89
- }
90
 
91
- // Handler to update the HS beacon enabled option
92
- add_action('init', function () {
93
- if (!is_admin()) {
94
- return;
95
  }
96
 
97
- $enabled = filter_input(INPUT_POST, 'wprss_hs_beacon_enabled', FILTER_VALIDATE_INT);
98
 
99
- if ($enabled !== null) {
100
  check_admin_referer('wprss_hs_beacon_enabled');
101
  update_option('wprss_hs_beacon_enabled', $enabled);
102
  }
@@ -108,301 +104,254 @@ use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
108
  * @since 4.11.3
109
  */
110
  function wprss_premium_help_display() {
111
- printf('<h3>%s</h3>', __('Premium Support', 'wprss'));
112
  printf(
113
  __(
114
  'Contact us <a href="%s" target="%s=">here</a> for pre-sales and premium support.',
115
- 'wprss'
116
  ),
117
- esc_attr("https://www.wprssaggregator.com/contact/"),
118
- esc_attr("wpra-premium-contact-us-form")
119
  );
120
  }
121
 
122
- /**
123
- * Print the premium help section with inline support form.
124
- *
125
- * (Currently unused)
126
- *
127
- * @since 4.7
128
- */
129
- function wprss_premium_help_support_form() {
130
- // Addon and license object, both detected in the below algorithm that searches for a
131
- // premium addon that is activated with a valid license
132
- $addon = null;
133
- $license = null;
134
- // Get license statuses option
135
- $statuses = get_option( 'wprss_settings_license_statuses', array() );
136
- // Iterate all statuses
137
- foreach ( $statuses as $_key => $_value ) {
138
- // If not a license status key, continue to next
139
- $_keyPos = strpos($_key, '_license_status');
140
- if ( $_keyPos === FALSE ) {
141
- continue;
142
- }
143
-
144
- // If the status is not valid, continue to next
145
- if ($_value !== 'valid') {
146
- continue;
147
- }
148
-
149
- // Get the addon ID
150
- $_addonId = substr( $_key, 0, $_keyPos );
151
- // Get the license
152
- $_license = wprss_licensing_get_manager()->checkLicense( $_addonId, 'ALL' );
153
- // If the license is not null
154
- if ($_license !== null) {
155
- // Save its details
156
- $addon = $_addonId;
157
- $license = $_license;
158
- // And stop iterating
159
- break;
160
- }
161
- }
162
-
163
- // If we didn't find an add-on with a valid license, show the free help text.
164
- if ( $addon === null || $license === null ) {
165
- wprss_free_help_display();
166
- return;
167
- }
168
-
169
- // Get the full license info so we can prefill the name and email
170
- $customer_name = is_object($license) ? esc_attr($license->customer_name) : '';
171
- $customer_email = is_object($license) ? esc_attr($license->customer_email) : '';
172
-
173
- echo '<h3>' . __('Email Support', 'wprss') . '</h3>';
174
- echo wpautop(__("If you still can't find an answer to your query after reading the documentation and going through the FAQ, just fill out the support request form below. We'll be happy to help you out.", 'wprss'));
175
-
176
- ?>
177
-
178
- <form method="post">
179
- <table>
180
- <tr>
181
- <td><strong><?= __('From: ', 'wprss'); ?></strong></td>
182
- <td>
183
- <input
184
- type='text'
185
- name='support-name'
186
- value="<?= $customer_name ?>"
187
- placeholder='<?= __('Name', 'wprss'); ?>'
188
- style='width:100%;'
189
- />
190
- </td>
191
- <td>
192
- <input
193
- type='text'
194
- name='support-email'
195
- value="<?= $customer_email ?>"
196
- placeholder='<?= __('Email', 'wprss'); ?>'
197
- style='width:100%;'
198
- />
199
- </td>
200
- </tr>
201
- <tr>
202
- <td colspan="3" style="text-align:right;">
203
- <small><?php _e('Replies will be sent to this email address.'); ?></small>
204
- </td>
205
- </tr>
206
- <tr>
207
- <td colspan="3">
208
- <input
209
- type='text'
210
- name='support-subject'
211
- placeholder='<?= __('Subject', 'wprss'); ?>'
212
- style='width:100%;'>
213
- </td>
214
- </tr>
215
- <tr>
216
- <td colspan="3">
217
- <textarea
218
- name='support-message'
219
- rows='10'
220
- cols='80'
221
- placeholder='<?= __('Message', 'wprss'); ?>'></textarea>
222
- </td>
223
- </tr>
224
- <tr>
225
- <td colspan="3">
226
- <strong><?= __('Attachments', 'wprss') ?>: </strong>
227
- </td>
228
- </tr>
229
- <tr>
230
- <td colspan="3"><input type='checkbox' name='support-include-log' value='checked' checked>
231
- <?= __('WP RSS Aggregator log file', 'wprss') ?>
232
- </td>
233
- </tr>
234
- <tr>
235
- <td colspan="3"><input type='checkbox' name='support-include-sys' value='checked' checked>
236
- <?= __('WordPress debugging information', 'wprss'); ?>
237
- </td>
238
- </tr>
239
- </table>
240
- </form>
241
-
242
- <div style='line-height:2.3em; margin-top:10px;'>
243
- <button id='send-message-btn' class='button button-primary'>
244
- <?= __('Send Message', 'wprss'); ?>
245
- </button>
246
- <div id='support-error'></div>
247
- </div>
248
-
249
- <?php
250
- }
251
-
252
- /**
253
- * Print the free help section with link to forums.
254
- *
255
- * @since 4.7
256
- */
257
- function wprss_free_help_display() {
258
- echo '<h3>' . __( 'Support Forums', 'wprss' ) . '</h3>';
259
- printf(
260
- wpautop(
261
- __( 'Users of the free version of WP RSS Aggregator can ask questions on the <a href="%s">support forum</a>.', 'wprss' )
262
- ),
263
- 'https://wordpress.org/support/plugin/wp-rss-aggregator'
264
- );
265
- }
266
-
267
-
268
- add_action( 'wp_ajax_wprss_ajax_send_premium_support', 'wprss_ajax_send_premium_support' );
269
- /**
270
- * Handles the AJAX request to send the support form. Returns a JSON status.
271
- *
272
- * @since 4.7
273
- */
274
- function wprss_ajax_send_premium_support() {
275
- $ret = array();
276
-
277
- // Validate the form fields that were submitted and send any errors.
278
- $error = wprss_validate_support_request();
279
- if ($error !== FALSE) {
280
- $ret['error'] = $error;
281
- echo json_encode($ret);
282
- die();
283
- }
284
-
285
- // Create the email content.
286
- $subject = sanitize_text_field($_GET['support-subject']);
287
- $message = wprss_create_support_message();
288
- $headers = wprss_create_support_headers();
289
-
290
- // Send the email.
291
- $sent = wp_mail( "support@wprssaggregator.com", $subject, $message, $headers );
292
-
293
- // NB, the retval is a best-guess about email sending. According to the WP Codex it
294
- // doesn't mean the user received the email, it "only means that the method used
295
- // was able to process the request without any errors."
296
- if ($sent === FALSE) {
297
- $ret['error'] = sprintf(
298
- __(
299
- 'There was an error sending the form. Please use the <a href="%s" target="_blank">contact form on our site.</a>',
300
- 'wprss'
301
- ),
302
- esc_attr('https://www.wprssaggregator.com/contact/')
303
- );
304
- $ret['message'] = $message;
305
- } else {
306
- $ret['status'] = 'OK';
307
- }
308
-
309
- echo json_encode($ret);
310
- die();
311
- }
312
-
313
-
314
- /**
315
- * Ensures that all support form fields have been filled out. Returns TRUE
316
- *
317
- * @since 4.7
318
- * @return FALSE when all fields are valid, or a string containing an error they aren't.
319
- */
320
- function wprss_validate_support_request() {
321
- $fields = [
322
- 'support-name',
323
- 'support-email',
324
- 'support-subject',
325
- 'support-message'
326
- ];
327
-
328
- // Ensure that each required field is present and filled out.
329
- foreach ($fields as $field) {
330
- $value = filter_input(INPUT_GET, $field);
331
- if (empty($value)) {
332
- $fieldName = explode('-', $field)[1];
333
- $fieldName = ucfirst($fieldName);
334
-
335
- return sprintf(
336
- __('Please fill out all the fields in the form, including the <strong>%s</strong> field.', 'wprss'),
337
- $fieldName
338
- );
339
- }
340
- }
341
-
342
- // Ensure the email is of a valid format.
343
- $email = filter_input(INPUT_GET, 'support-email');
344
- if (!is_email($email)) {
345
- return __('Please enter a valid email address.', 'wprss');
346
- }
347
-
348
- return false;
349
- }
350
-
351
-
352
- /**
353
- * Creates and returns the support request email's message body.
354
- *
355
- * @since 4.7
356
- */
357
- function wprss_create_support_message() {
358
- // Get the WP RSS Aggregator log.
359
- $log = 'Customer did not send log';
360
- if ($_GET['support-include-log'] === 'true') {
361
- $log = wprss_get_log();
362
- }
363
-
364
- // Get the system information.
365
- $sys_info = 'Customer did not send system information';
366
- if ($_GET['support-include-sys'] === 'true') {
367
- ob_start();
368
- wprss_print_system_info();
369
- $sys_info = ob_get_contents();
370
- ob_end_clean();
371
- }
372
-
373
- // Get the license keys.
374
- $keys = json_encode(get_option('wprss_settings_license_keys', []), JSON_PRETTY_PRINT);
375
-
376
- // Get the message they entered.
377
- $message = sanitize_text_field($_GET['support-message']);
378
-
379
- // Remove any generated system data that may be present from previous form submission attempts.
380
- $idx = strpos($message, "----------------------------------------------");
381
- if ($idx !== FALSE) {
382
- $message = substr($message, 0, $idx);
383
- }
384
-
385
- // Append the generated system data.
386
- $message .= "\n\n----------------------------------------------\n";
387
- $message .= "\nLicense Information:\n" . $keys;
388
- $message .= "\n\n\nError Log:\n" . $log;
389
- $message .= "\n\n\nSystem Information:\n" . $sys_info . "\n";
390
-
391
- return apply_filters('wprss_support_message', $message);
392
- }
393
-
394
-
395
- /**
396
- * Creates and returns the support request email's headers.
397
- *
398
- * @since 4.7
399
- */
400
- function wprss_create_support_headers() {
401
- $headers = "From: no-reply@wprssaggregator.com\r\n";
402
- $headers .= "Reply-to: " . sanitize_text_field($_GET['support-name']) . " <" . sanitize_email($_GET['support-email']) . ">\r\n";
403
-
404
- return apply_filters('wprss_support_headers', $headers);
405
- }
406
 
407
 
408
  /**
@@ -439,892 +388,861 @@ use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
439
  * 1. The absolute path to the core plugin directory
440
  */
441
  class WPRSS_Help {
442
- static $_instance;
443
-
444
- protected $_options;
445
-
446
- protected $_enqueued_tooltip_content = [];
447
-
448
- protected $_tooltips = [];
449
-
450
- const OPTION_NAME = 'wprss_settings_help';
451
- const CODE_PREFIX = 'wprss_help_';
452
- const OVERRIDE_DEFAULT_PREFIX = '!';
453
- const HASHING_DELIMETER = '|';
454
- const OPTIONS_FILTER_SUFFIX = '_options';
455
- const TOOLTIP_DATA_KEY_ID = 'id';
456
- const TOOLTIP_DATA_KEY_TEXT = 'text';
457
- const TOOLTIP_DATA_KEY_OPTIONS = 'options';
458
-
459
- /**
460
- * Retrieve the singleton instance
461
- *
462
- * @return WPRSS_Help
463
- */
464
- public static function get_instance()
465
- {
466
- if (is_null(self::$_instance)) {
467
- $class_name = __CLASS__; // Late static bindings not allowed
468
- self::$_instance = new $class_name();
469
- }
470
-
471
- return self::$_instance;
472
- }
473
-
474
- /**
475
- * @since 4.10
476
- */
477
- public static function init()
478
- {
479
- if (static::get_instance()->_isEnqueueScripts()) {
480
- add_action('admin_enqueue_scripts', [self::get_instance(), '_admin_enqueue_scripts']);
481
- add_action('admin_footer', [self::get_instance(), '_admin_footer']);
482
- }
483
- }
484
-
485
- /**
486
- * Determines if the admin scripts should get enqueued.
487
- *
488
- * @since 4.10
489
- *
490
- * @return bool True if admin scripts should be enqueued; false otherwise.
491
- */
492
- protected function _isEnqueueScripts()
493
- {
494
- return $this->_isWprssPage();
495
- }
496
-
497
- /**
498
- * Determines if the current page is related to WPRSS.
499
- *
500
- * @since 4.10
501
- *
502
- * @return bool True if the current page is related to WPRSS; false otherwise.
503
- */
504
- protected function _isWprssPage()
505
- {
506
- return wprss_is_wprss_page();
507
- }
508
-
509
-
510
- /**
511
- * Filters used:
512
- *
513
- * - `wprss_help_default_options`
514
- *
515
- * @param array $options Options that will overwrite defaults.
516
- */
517
- public function __construct( $options = array() ) {
518
- $defaults = apply_filters( 'wprss_help_default_options', array(
519
- 'tooltip_id_prefix' => 'wprss-tooltip-',
520
- 'tooltip_handle_text' => '',
521
- 'tooltip_handle_class' => 'wprss-tooltip-handle', // Used in logic to identify handle elements
522
- 'tooltip_handle_class_extra' => 'fa fa-question-circle', // Not used in logic
523
- 'tooltip_content_class' => 'wprss-tooltip-content',
524
- 'tooltip_class' => 'wprss-ui-tooltip', // Overrides default jQuery UI class
525
- 'is_enqueue_tooltip_content' => '0',
526
- 'tooltip_handle_template' => '%1$s/help-tooltip-handle.php',
527
- 'tooltip_content_template' => '%1$s/help-tooltip-content.php',
528
- 'admin_footer_js_template' => '%1$s/help-footer-js.php',
529
- 'tooltip_not_found_handle_html' => '',
530
- 'text_domain' => 'wprss'
531
- ));
532
- $db_options = $this->get_options_db();
533
- $this->_set_options( $this->array_merge_recursive_distinct( $db_options, $defaults ) );
534
-
535
- $this->_construct();
536
- }
537
-
538
-
539
- /**
540
- * Used for parameter-less extension of constructor logic
541
- */
542
- protected function _construct() {
543
-
544
- }
545
-
546
-
547
- /**
548
- * Return an option value, or the whole array of internal options.
549
- * These options are a product of the defaults, the database, and anything
550
- * set later on, applied on top of each other and overwriting in that order.
551
- *
552
- * @param null|string $key The key of the option to return.
553
- * @param null|mixed $default What to return if options with the specified key not found.
554
- * @return array|mixed|null The option value, or an array of options.
555
- */
556
- public function get_options($key = null, $default = null)
557
- {
558
- $options = $this->_options;
559
-
560
- if (is_null($key)) {
561
- return $options;
562
- }
563
-
564
- if (is_array($key)) {
565
- return $this->array_merge_recursive_distinct($options, $key);
566
- }
567
-
568
- return isset($options[$key]) ? $options[$key] : $default;
569
- }
570
-
571
- /**
572
- * Set the value of an internal option or options.
573
- * Existing options will be overwritten. New options will be added.
574
- * Database options will not be modified.
575
- *
576
- * @param string|array $key The key of the option to set, or an array of options.
577
- * @param null|mixed $value The value of the option to set.
578
- *
579
- * @return WPRSS_Help This instance.
580
- */
581
- public function set_options($key, $value = null)
582
- {
583
- if (is_array($key)) {
584
- foreach ($key as $_key => $_value) {
585
- $this->_set_options($_key, $_value);
586
- }
587
-
588
- return $this;
589
- }
590
-
591
- $this->_set_options($key, $value);
592
- }
593
-
594
- /**
595
- * Set an option value, or all options.
596
- * In latter case completely overrides the whole options array.
597
- *
598
- * @param string|array $key The key of the option to set, or the whole options array.
599
- * @param null|mixed $value Value of the option to set.
600
- *
601
- * @return WPRSS_Help This instance.
602
- */
603
- protected function _set_options($key, $value = null)
604
- {
605
- if (is_array($key)) {
606
- $this->_options = $key;
607
- return $this;
608
- }
609
-
610
- $this->_options[$key] = $value;
611
- return $this;
612
- }
613
-
614
-
615
- /**
616
- * Returns a WPRSS_Help option or options from the database.
617
- *
618
- * @param string $key The key of the option to return.
619
- * @param null|mixed $default What to return if option identified by $key is not found.
620
- * @return null|array|mixed The options or option value.
621
- */
622
- public function get_options_db($key = null, $default = null)
623
- {
624
- $options = (array) get_option(self::OPTION_NAME, []);
625
-
626
- if (is_null($key)) {
627
- return $options;
628
- }
629
-
630
- return isset($options[$key]) ? $options[$key] : $default;
631
- }
632
-
633
- /**
634
- * Get content of a template.
635
- *
636
- * Filters used
637
- *
638
- * - `wprss_help_template_path`
639
- * - `wprss_help_template_vars`
640
- *
641
- * @param string $path Full path to the template
642
- * @param array $vars This will be passed to the template
643
- */
644
- public function get_template($path, $vars = [])
645
- {
646
- $vars = (array) $vars;
647
-
648
- // Entry points
649
- $path = apply_filters('wprss_help_template_path', $path, $vars);
650
- $vars = apply_filters('wprss_help_template_vars', $vars, $path);
651
-
652
- ob_start();
653
- include($path);
654
- $content = ob_get_contents();
655
- ob_end_clean();
656
-
657
- return $content;
658
- }
659
-
660
- /**
661
- * This is called during the `admin_enqueue_scripts` action, and will
662
- * enqueue scripts needed for the backend.
663
- *
664
- * Filters used:
665
- *
666
- * - `wprss_help_admin_scripts`
667
- *
668
- * @return WPRSS_Help This instance.
669
- */
670
- public function _admin_enqueue_scripts()
671
- {
672
- if (!wprss_is_wprss_page()) {
673
- return $this;
674
- }
675
-
676
- $scripts = $this->apply_filters('admin_scripts', [
677
- 'jquery-ui-tooltip' => [],
678
- ]);
679
-
680
- foreach ($scripts as $_handle => $_args) {
681
- // Allows numeric array with handles as values
682
- if (is_numeric($_handle)) {
683
- $_handle = $_args;
684
- }
685
-
686
- // Allows specifying null as value to simply enqueue handle
687
- if (empty($_args)) {
688
- $_args = [];
689
- }
690
-
691
- array_unshift($_args, $_handle);
692
- call_user_func_array('wp_enqueue_script', $_args);
693
- }
694
-
695
- return $this;
696
- }
697
-
698
- public function _admin_footer()
699
- {
700
- $html = $this->get_enqueued_tooltip_content_html() . "\n" . $this->get_admin_footer_js_html();
701
-
702
- // This should not be escaped!
703
- echo $this->apply_filters('admin_footer', $html);
704
- }
705
-
706
- public function is_overrides_default_prefix($string)
707
- {
708
- return strpos($string, self::OVERRIDE_DEFAULT_PREFIX) === 0;
709
- }
710
-
711
- /**
712
- * Hashes all the given values into a single hash.
713
- * Accepts an infinite number of parameters, all of which will be first
714
- * glued together by a separator, then hashed.
715
- * Non-scalar values will be serialized.
716
- *
717
- * @param mixed $value The value to hash.
718
- * @param mixed $argN Other values to hash.
719
- *
720
- * @return string The hash.
721
- */
722
- public function get_hash($value)
723
- {
724
- $args = func_get_args();
725
- $glue = self::HASHING_DELIMETER;
726
-
727
- $blob = '';
728
- foreach ($args as $_arg) {
729
- $blob .= is_scalar($_arg) ? $_arg : serialize($_arg);
730
- $blob .= $glue;
731
- }
732
-
733
- $blob = substr($blob, 0, -1);
734
-
735
- return sha1($blob);
736
- }
737
-
738
- /**
739
- * Get the class code prefix, or the specified prefixed with it.
740
- *
741
- * @param string $string A string to prefix.
742
- *
743
- * @return string The code prefix or the prefixed string.
744
- */
745
- public function get_code_prefix($string = '')
746
- {
747
- return self::CODE_PREFIX . (string) $string;
748
- }
749
-
750
- /**
751
- * Optionally prefix a string with the class code prefix, unless it
752
- * contains the "!" character in the very beginning, in which case it will
753
- * simply be removed.
754
- *
755
- * @param string $string The string to consider for prefixing.
756
- *
757
- * @return string The prefixed or clean string.
758
- */
759
- public function prefix($string)
760
- {
761
- return $this->is_overrides_default_prefix($string)
762
- ? substr($string, 1)
763
- : $this->get_code_prefix($string);
764
- }
765
-
766
- /**
767
- * Applies filters, but prefixes the filter name with 'wprss_help_',
768
- * unless '!' is specified as the first character of the filter.
769
- *
770
- * @param string $filter_name Name or "tag" of the filter.
771
- * @param mixed $subject The value to apply filters to.
772
- * @param mixed $argN ,.. Additional filter arguments
773
- *
774
- * @return mixed Result of filtering
775
- */
776
- public function apply_filters($filter_name, $subject, $argN = null)
777
- {
778
- $args = func_get_args();
779
- $args[0] = $this->prefix($filter_name);
780
-
781
- return call_user_func_array('apply_filters', $args);
782
- }
783
-
784
- /**
785
- * Applies a filters with the specified name to the options that were
786
- * applied on top of defaults.
787
- * The name will be prefixed with the class prefix 'wprss_help_', and
788
- * suffixed with '_options'.
789
- *
790
- * @param string $filter_name Name of the filter to apply to the options
791
- * @param array $options The options to filter
792
- * @param mixed $filter_argN ,.. Other filter arguments to be passed to filter
793
- */
794
- public function apply_options_filters($filter_name, $options = [], $filter_argN = null)
795
- {
796
- $args = func_get_args();
797
-
798
- // Adding suffix to filter name
799
- $args[0] = $filter_name . self::OPTIONS_FILTER_SUFFIX;
800
-
801
- // Applying default options
802
- $args[1] = $this->get_options($options);
803
-
804
- // Entry point. Order of args is already correct.
805
- return call_user_func_array([$this, 'apply_filters'], $args);
806
- }
807
-
808
- /**
809
- * Parses the tooltip handle template path for placeholders.
810
- *
811
- * Filters used:
812
- *
813
- * - `wprss_help_admin_footer_js_html_template`
814
- *
815
- * @param null|string $path Optional path to parse and retrieve. Default: value of the 'admin_footer_js_template'
816
- * option.
817
- *
818
- * @return string Path to the template.
819
- */
820
- public function get_admin_footer_js_html_template($path = null)
821
- {
822
- // Default is from options
823
- if (is_null($path)) {
824
- $path = $this->get_options('admin_footer_js_template');
825
- }
826
-
827
- // Entry point
828
- $path = $this->apply_filters('admin_footer_js_html_template', $path);
829
-
830
- return $this->parse_path($path);
831
- }
832
-
833
- /**
834
- * Get the HTML of the JavaScript for the footer in Admin Panel.
835
- *
836
- * Filters used:
837
- *
838
- * - `wprss_help_admin_footer_js_html`
839
- *
840
- * @param array $options Any additional options to be used with defaults.
841
- *
842
- * @return string The HTML.
843
- */
844
- public function get_admin_footer_js_html($options = [])
845
- {
846
- $options = $this->apply_options_filters('admin_footer_js_html', $options);
847
-
848
- $templatePath = $this->get_admin_footer_js_html_template($options['admin_footer_js_template']);
849
-
850
- return $this->get_template($templatePath, $options);
851
- }
852
-
853
- /**
854
- * Parses the tooltip handle template path for placeholders.
855
- *
856
- * Filters used:
857
- *
858
- * - `wprss_help_tooltip_handle_html_template`
859
- *
860
- * @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template'
861
- * option.
862
- *
863
- * @return string Path to the template.
864
- */
865
- public function get_tooltip_handle_html_template($path = null)
866
- {
867
- // Default is from options
868
- if (is_null($path)) {
869
- $path = $this->get_options('tooltip_handle_template');
870
- }
871
-
872
- // Entry point
873
- $path = $this->apply_filters('tooltip_handle_html_template', $path);
874
-
875
- return $this->parse_path($path);
876
- }
877
-
878
- /**
879
- * Get the HTML of the tooltip handle.
880
- *
881
- * Filters used:
882
- *
883
- * - `wprss_help_tooltip_handle_html_options`
884
- *
885
- * @param string $text Content of the tooltip text.
886
- * @param string $id ID of the tooltip.
887
- * @param array $options Any additional options to be used with defaults.
888
- *
889
- * @return string The HTML.
890
- */
891
- public function get_tooltip_handle_html($text, $id, $options = [])
892
- {
893
- $options = $this->apply_options_filters('tooltip_handle_html', $options, $text, $id);
894
-
895
- // Add template variables
896
- $options['tooltip_id'] = $id;
897
- $options['tooltip_text'] = $text;
898
-
899
- $templatePath = $this->get_tooltip_handle_html_template($options['tooltip_handle_template']);
900
-
901
- return $this->get_template($templatePath, $options);
902
- }
903
-
904
- /**
905
- * Parses the tooltip content template path for placeholders.
906
- *
907
- * Filters used:
908
- *
909
- * - `wprss_help_tooltip_content_html_template`
910
- *
911
- * @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template'
912
- * option.
913
- *
914
- * @return string Path to the template.
915
- */
916
- public function get_tooltip_content_html_template($path = null)
917
- {
918
- // Default is from options
919
- if (is_null($path)) {
920
- $path = $this->get_options('tooltip_content_template');
921
- }
922
-
923
- // Entry point
924
- $path = $this->apply_filters('tooltip_content_html_template', $path);
925
-
926
- return $this->parse_path($path);
927
- }
928
-
929
- /**
930
- * Get the HTML of the tooltip content.
931
- *
932
- * Filters used:
933
- *
934
- * - `wprss_help_tooltip_content_html_options`
935
- *
936
- * @param string $text Content of the tooltip text.
937
- * @param string $id ID of the tooltip.
938
- * @param array $options Any additional options to be used with defaults.
939
- *
940
- * @return string The HTML.
941
- */
942
- public function get_tooltip_content_html($text, $id, $options = [])
943
- {
944
- $options = $this->apply_options_filters('tooltip_content_html', $options, $text, $id);
945
-
946
- // Add template variables
947
- $options['tooltip_id'] = $id;
948
- $options['tooltip_text'] = $text;
949
-
950
- $templatePath = $this->get_tooltip_content_html_template($options['tooltip_content_template']);
951
-
952
- return $this->get_template($templatePath, $options);
953
- }
954
-
955
- /**
956
- * Add tooltip and get tooltip HTML.
957
- * If $text is null, just get the HTML of tooltip with specified ID.
958
- * The `is_enqueue_tooltip_content` option determines whether to enqueue
959
- * the content, instead of outputting it after the handle.
960
- *
961
- * @param string $id ID for this tooltip
962
- * @param string|null $text Text of this tooltip. If null, tooltip will not be added, but only retrieved.
963
- * @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
964
- * @return string The tooltip handle and, optionally, content.
965
- */
966
- public function tooltip($id, $text = null, $options = [])
967
- {
968
- $this->add_tooltip($id, $text, $options);
969
- return $this->do_tooltip($id);
970
- }
971
-
972
- /**
973
- * Add tooltips in a batch, with optionally prefixed ID.
974
- *
975
- * @param array $tooltips An array where key is tooltip ID and value is tooltip text.
976
- * @param string $prefix A prefix to add to all tooltip IDs.
977
- * @param array $options Arra of options for all the tooltips to add.
978
- *
979
- * @return \WPRSS_Help
980
- */
981
- public function add_tooltips($tooltips, $prefix = null, $options = [])
982
- {
983
- $prefix = (string) $prefix;
984
- if (!is_array($options)) $options = [];
985
-
986
- foreach ($tooltips as $_id => $_text) {
987
- $this->add_tooltip($prefix . $_id, $_text, $options);
988
- }
989
-
990
- return $this;
991
- }
992
-
993
- /**
994
- * Add a tooltip for later display.
995
- * Text and options will be replaced by existing text and options, if they
996
- * are empty, and a tooltip with the same ID is already registered.
997
- *
998
- * @param string $id The ID of this tooltip
999
- * @param string $text Text for this tooltip
1000
- * @param array $options Options for this tooltip.
1001
- *
1002
- * @return WPRSS_Help This instance.
1003
- */
1004
- public function add_tooltip($id, $text = null, $options = [])
1005
- {
1006
- if ($tooltip = $this->get_tooltip($id)) {
1007
- if (is_null($text)) {
1008
- $text = isset($tooltip[self::TOOLTIP_DATA_KEY_TEXT])
1009
- ? $tooltip[self::TOOLTIP_DATA_KEY_TEXT]
1010
- : $text;
1011
- }
1012
 
1013
- if (empty($options)) {
1014
- $options = isset($tooltip[self::TOOLTIP_DATA_KEY_OPTIONS])
1015
- ? $tooltip[self::TOOLTIP_DATA_KEY_OPTIONS]
1016
- : $options;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
  }
 
 
 
 
 
 
 
 
 
 
 
 
1018
  }
1019
 
1020
- $this->set_tooltip($id, $text, $options);
1021
-
1022
- return $this;
1023
- }
1024
-
1025
- /**
1026
- * Set a tooltip, existing or not.
1027
- *
1028
- * @param string $id The ID of this tooltip
1029
- * @param string $text Text for this tooltip
1030
- * @param array $options Options for this tooltip.
1031
- *
1032
- * @return WPRSS_Help This instance.
1033
- */
1034
- public function set_tooltip($id, $text = null, $options = [])
1035
- {
1036
- $this->_tooltips[$id] = [
1037
- self::TOOLTIP_DATA_KEY_ID => $id,
1038
- self::TOOLTIP_DATA_KEY_TEXT => $text,
1039
- self::TOOLTIP_DATA_KEY_OPTIONS => $options,
1040
- ];
1041
-
1042
- return $this;
1043
- }
1044
-
1045
- /**
1046
- * Retrieve one tooltip, or an array containing all tooltips.
1047
- *
1048
- * @param string|null $id The ID of the tooltip to retrieve.
1049
- * @param mixed|null $default What to return if tooltip with specified ID not found.
1050
- *
1051
- * @return array An array that contains the following indexes: 'id', 'text', 'options'. See {@link add_tooltip()}
1052
- * for details.
1053
- */
1054
- public function get_tooltip($id = null, $default = null)
1055
- {
1056
- if (is_null($id)) {
1057
- return $this->_tooltips;
1058
  }
1059
 
1060
- return $this->has_tooltip($id)
1061
- ? $this->_tooltips[$id]
1062
- : $default;
1063
- }
1064
 
1065
- /**
1066
- * Check whether a tooltip with the specified ID exists.
1067
- *
1068
- * @param string $id ID of the tooltip to check for.
1069
- *
1070
- * @return boolean True if a tooltip with the specified ID exists; false otherwise.
1071
- */
1072
- public function has_tooltip($id)
1073
- {
1074
- return isset($this->_tooltips[$id]);
1075
- }
1076
-
1077
- /**
1078
- * Get registered tooltip HTML.
1079
- *
1080
- * Filters used:
1081
- *
1082
- * - `wprss_help_tooltip_options` - Filters options used for tooltip
1083
- *
1084
- * @param string $id ID for this tooltip
1085
- * @param string $text Text of this tooltip
1086
- * @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to
1087
- * be enqueued
1088
- *
1089
- * @return string The tooltip handle and, optionally, content.
1090
- */
1091
- public function do_tooltip($id)
1092
- {
1093
- $options = $this->get_options();
1094
- $tooltip = $this->get_tooltip($id);
1095
-
1096
- $text = !empty($tooltip[self::TOOLTIP_DATA_KEY_TEXT])
1097
- ? $tooltip[self::TOOLTIP_DATA_KEY_TEXT]
1098
- : null;
1099
-
1100
- if (!$tooltip || empty($text)) {
1101
- return isset($options['tooltip_not_found_handle_html'])
1102
- ? $options['tooltip_not_found_handle_html']
1103
- : null;
1104
- }
1105
-
1106
- $options = isset($tooltip[self::TOOLTIP_DATA_KEY_OPTIONS])
1107
- ? $tooltip[self::TOOLTIP_DATA_KEY_OPTIONS]
1108
- : null;
1109
-
1110
- if (!is_array($options)) {
1111
- $options = ['is_enqueue_tooltip_content' => $options];
1112
- }
1113
-
1114
- // Entry point
1115
- $options = $this->apply_options_filters('tooltip', $options, $id, $text);
1116
-
1117
- // Get handle HTML
1118
- $output = $this->get_tooltip_handle_html($text, $id, $options);
1119
-
1120
- if ($this->evaluate_boolean($options['is_enqueue_tooltip_content'])) {
1121
- $this->enqueue_tooltip_content($text, $id, $options);
1122
- } else {
1123
- $output .= $this->get_tooltip_content_html($text, $id, $options);
1124
- }
1125
-
1126
- return $output;
1127
- }
1128
-
1129
- /**
1130
- * Enqueue tooltip content to be displayed in another part of the page.
1131
- *
1132
- * @param string $text The text of the tooltip content to enqueue.
1133
- * @param string $id ID of the tooltip, the content of which to enqueue.
1134
- * @param array $options This tooltip's options.
1135
- *
1136
- * @return \WP_Error|\WPRSS_Help This instance, or error if enqueue method is invalid.
1137
- */
1138
- public function enqueue_tooltip_content($text, $id, $options = [])
1139
- {
1140
- $queue_method = $this->apply_filters('enqueue_tooltip_content_method', [$this, '_enqueue_tooltip_content'],
1141
- $options, $id, $text);
1142
-
1143
- // "Error handling" WP style
1144
- if (!is_callable($queue_method)) {
1145
- $code = $this->prefix('invalid_queue_method');
1146
- $msg = __('Could not enqueue tooltip content: the queue method is not a valid callable.', 'wprss');
1147
-
1148
- return new WP_Error($code, $msg, [
1149
- 'queue_method' => $queue_method,
1150
- 'text' => $text,
1151
- 'id' => $id,
1152
- 'options' => $options,
1153
- ]);
1154
- }
1155
-
1156
- call_user_func_array($queue_method, [$text, $id, $options]);
1157
-
1158
- return $this;
1159
- }
1160
-
1161
- public function _enqueue_tooltip_content($text, $id, $options = [])
1162
- {
1163
- $hash = $this->get_hash($text, $id, $options);
1164
- $this->_enqueued_tooltip_content[$hash] = [
1165
- self::TOOLTIP_DATA_KEY_TEXT => $text,
1166
- self::TOOLTIP_DATA_KEY_ID => $id,
1167
- self::TOOLTIP_DATA_KEY_OPTIONS => $options,
1168
- ];
1169
-
1170
- return $this;
1171
- }
1172
-
1173
- public function get_enqueued_tooltip_content()
1174
- {
1175
- return $this->_enqueued_tooltip_content;
1176
- }
1177
-
1178
- public function get_enqueued_tooltip_content_html()
1179
- {
1180
- $output = '';
1181
- foreach ($this->get_enqueued_tooltip_content() as $_vars) {
1182
- $options = is_array($_vars[self::TOOLTIP_DATA_KEY_OPTIONS])
1183
- ? $_vars[self::TOOLTIP_DATA_KEY_OPTIONS]
1184
- : [];
1185
-
1186
- $output = $this->get_tooltip_content_html(
1187
- $_vars[self::TOOLTIP_DATA_KEY_ID],
1188
- $_vars[self::TOOLTIP_DATA_KEY_ID],
1189
- $options
1190
- );
1191
- }
1192
-
1193
- // This should not be escaped!
1194
- echo $output;
1195
- }
1196
-
1197
- /**
1198
- * Check whether or not the given value is false.
1199
- * False values are all {@link empty()} values, and also strings 'false' and 'no'.
1200
- *
1201
- * @param mixed $value The value to check.
1202
- * @return boolean Whether or not the value is considered to be false.
1203
- */
1204
- public function evaluate_boolean( $value ) {
1205
- return filter_var($value, FILTER_VALIDATE_BOOLEAN);
1206
- }
1207
-
1208
- /**
1209
- * Merge two arrays in an intuitive way.
1210
- * Input arrays remain unchanged.
1211
- *
1212
- * @see http://php.net/manual/en/function.array-merge-recursive.php#92195
1213
- *
1214
- * @param array $array1 The array to merge.
1215
- * @param array $array2 The array to merge into.
1216
- *
1217
- * @return array The merged array.
1218
- */
1219
- public function array_merge_recursive_distinct(array &$array1, array &$array2)
1220
- {
1221
- $merged = $array1;
1222
-
1223
- foreach ($array2 as $key => &$value) {
1224
- if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
1225
- $merged[$key] = $this->array_merge_recursive_distinct($merged[$key], $value);
1226
- } else {
1227
- $merged[$key] = $value;
1228
  }
1229
- }
1230
-
1231
- return $merged;
1232
- }
1233
-
1234
- /**
1235
- * Converts an array to a numeric array.
1236
- * If $map is empty, assumes that the array keys are already in order.
1237
- * If $map is a number, assumes it's the amount of elements to return.
1238
- * If $map is an array, assumes it is the map of intended numeric indexes to their value in the input array.
1239
- *
1240
- * @param array $array The array to convert to a numeric array
1241
- * @param false|null|array $map The map of the array indexes, or number of array elements to slice, or nothing.
1242
- *
1243
- * @return array The resulting numeric array.
1244
- */
1245
- public function array_to_numeric($array, $map = null)
1246
- {
1247
- $result = [];
1248
-
1249
- // If map is not an array, assume it's an indicator
1250
- if (!is_array($map)) {
1251
- $array = array_values($array);
1252
- }
1253
 
1254
- // If map is empty, assume keys are in order
1255
- if (empty($map)) {
1256
- return $array;
1257
- }
1258
-
1259
- // If map is a number, assume it's the amount of elements to return
1260
- if (is_numeric($map)) {
1261
- $map = intval($map);
1262
- return array_slice($array, 0, $map);
1263
- }
1264
-
1265
- foreach ($map as $_idx => $_key) {
1266
- $result[$_idx] = $array[$_key];
1267
- }
1268
-
1269
- return $result;
1270
- }
1271
-
1272
- /**
1273
- * Parses the template and replaces placeholders with their values.
1274
- * This function uses {@see sprintf()} to format the template string using
1275
- * the values provided in $data.
1276
- * It is also possible for $data to be an associative array of key-value pairs.
1277
- * To achieve the same result, a map can be provided, mapping data keys to
1278
- * their placeholder positions.
1279
- * If no map is provided,
1280
- *
1281
- * @param string $string The template string.
1282
- * @param array $data The key-value pairs of template data.
1283
- * @param false|null|array $map {@see array_to_numeric()} The template value map.
1284
- *
1285
- * @return string The parsed and modified template.
1286
- */
1287
- public function parse_template($string, $data, $map = null)
1288
- {
1289
- $data = $this->array_to_numeric($data, $map);
1290
- array_unshift($data, $string);
1291
- return call_user_func_array('sprintf', $data);
1292
- }
1293
-
1294
- /**
1295
- * Parses a path template specifically with WPRSS_Help path placeholders.
1296
- *
1297
- * Filters used (in order):
1298
- *
1299
- * 1. `parse_path_data_default`;
1300
- * 2. `parse_path_data`;
1301
- * 3. `parse_path_map`;
1302
- * 4. `parse_path_path`.
1303
- *
1304
- * @see WPRSS_Help::parse_template()
1305
- *
1306
- * @param string $path The path to parse.
1307
- * @param null|array $data Any additional data. Will be merged with defaults.
1308
- * @param null|array $map The map for parsing.
1309
- *
1310
- * @return string The path with placeholders replaced
1311
- */
1312
- public function parse_path($path, $data = null, $map = null)
1313
- {
1314
- if (is_null($data)) {
1315
- $data = [];
1316
- }
1317
-
1318
- $defaults = $this->apply_filters('parse_path_data_default', [
1319
- 'wprss_templates_dir' => wprss_get_templates_dir(),
1320
- ]);
1321
- $data = $this->array_merge_recursive_distinct($data, $defaults);
1322
- $data = $this->apply_filters('parse_path_data', $data, $path, $map);
1323
- $map = $this->apply_filters('parse_path_map', $map, $data, $path);
1324
- $path = $this->apply_filters('parse_path_path', $path, $data, $map);
1325
-
1326
- return $this->parse_template($path, $data, $map);
1327
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1328
  }
1329
 
1330
  WPRSS_Help::init();
1
  <?php
2
 
3
+ use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
4
 
5
+ /**
6
  * Checks if the HS becaon is enabled or not.
7
  *
8
  * @since 4.12.1
13
  return (int) get_option('wprss_hs_beacon_enabled', 1) === 1;
14
  }
15
 
16
+ /**
17
+ * Build the Help page
18
+ *
19
+ * @since 4.2
20
+ */
21
+ function wprss_help_page_display() {
22
+ ?>
23
 
24
+ <div class="wrap">
25
+ <h2><?php _e( 'Help & Support', WPRSS_TEXT_DOMAIN ); ?></h2>
26
  <?php do_action('wpra/help_page/after_title') ?>
27
+ <h3><?php _e( 'Knowledge Base', WPRSS_TEXT_DOMAIN ) ?></h3>
28
+ <?php
29
+ printf(
30
+ wpautop(
31
+ __( 'In the <a href="%s">WP RSS Aggregator knowledge base</a> you will find comprehensive details and tutorials on how to use the core plugin and all the add-ons.
32
+
33
+ There are also some videos to help you make a quick start to setting up and enjoying this plugin.',
34
+ WPRSS_TEXT_DOMAIN
35
+ )
36
+ ),
37
+ 'https://kb.wprssaggregator.com/'
38
+ );
39
+ ?>
40
+ <h3><?php _e( 'Frequently Asked Questions (FAQ)', WPRSS_TEXT_DOMAIN ) ?></h3>
41
+ <?php
42
+ printf(
43
+ wpautop(
44
+ __( 'If after going through the knowledge base you still have questions, please take a look at the <a href="%s">FAQ section</a>. We set this up purposely to answer the most commonly asked questions from our users.',
45
+ WPRSS_TEXT_DOMAIN
46
+ )
47
+ ),
48
+ 'https://kb.wprssaggregator.com/category/359-faqs'
49
+ )
50
+ ?>
51
+
52
+ <?php
53
+ if ( wprss_licensing_get_manager()->licenseWithStatusExists( License_Status::VALID ) ) {
54
+ wprss_premium_help_display();
55
+ } else {
56
+ wprss_free_help_display();
57
+ }
58
+ ?>
59
+ <h3><?php _e( 'Built-in Help Beacon', WPRSS_TEXT_DOMAIN ) ?></h3>
 
60
  <form method="POST">
61
  <p>
62
+ <?php _e('The help beacon is an interactive button that appears on the bottom-right section of WP RSS Aggregator admin pages.', WPRSS_TEXT_DOMAIN); ?>
63
+ <?php _e('It provides access to our extensive knowledge base where you can find the answers to the most commonly asked questions.', WPRSS_TEXT_DOMAIN); ?>
64
  </p>
65
  <p>
66
+ <?php _e('The beacon only works on WP RSS Aggregator admin pages and does not track your mouse clicks and/or keyboard input.', WPRSS_TEXT_DOMAIN); ?>
67
  </p>
 
68
  <?php if (wprss_is_help_beacon_enabled()): ?>
69
+ <p><?php _e('The support beacon is currently <b>enabled</b>.', WPRSS_TEXT_DOMAIN); ?></p>
70
  <button type="submit" name="wprss_hs_beacon_enabled" value="0" class="button button-secondary">
71
+ <?php _e('Disable support beacon', WPRSS_TEXT_DOMAIN); ?>
72
  </button>
73
  <?php else: ?>
74
+ <p><?php _e('By enabling the help beacon, you are consenting to this data collection.', WPRSS_TEXT_DOMAIN); ?></p>
 
 
75
  <button type="submit" name="wprss_hs_beacon_enabled" value="1" class="button button-primary">
76
+ <?php _e('Enable support beacon', WPRSS_TEXT_DOMAIN); ?>
77
  </button>
78
  <?php endif; ?>
79
 
80
  <?php wp_nonce_field('wprss_hs_beacon_enabled'); ?>
81
  </form>
82
+ </div>
83
+ <?php
84
  do_action('wpra/help_page/bottom');
85
+ }
86
 
87
+ // Handler to update the HS beacon enabled option
88
+ add_action('init', function () {
89
+ if (!is_admin()) {
90
+ return;
91
  }
92
 
93
+ $enabled = filter_input(INPUT_POST, 'wprss_hs_beacon_enabled', FILTER_VALIDATE_INT);
94
 
95
+ if ($enabled !== null) {
96
  check_admin_referer('wprss_hs_beacon_enabled');
97
  update_option('wprss_hs_beacon_enabled', $enabled);
98
  }
104
  * @since 4.11.3
105
  */
106
  function wprss_premium_help_display() {
107
+ printf('<h3>%s</h3>', __( 'Premium Support', WPRSS_TEXT_DOMAIN ));
108
  printf(
109
  __(
110
  'Contact us <a href="%s" target="%s=">here</a> for pre-sales and premium support.',
111
+ WPRSS_TEXT_DOMAIN
112
  ),
113
+ "https://www.wprssaggregator.com/contact/",
114
+ "wpra-premium-contact-us-form"
115
  );
116
  }
117
 
118
+ /**
119
+ * Print the premium help section with inline support form.
120
+ *
121
+ * (Currently unused)
122
+ *
123
+ * @since 4.7
124
+ */
125
+ function wprss_premium_help_support_form() {
126
+ // Addon and license object, both detected in the below algorithm that searches for a
127
+ // premium addon that is activated with a valid license
128
+ $addon = null;
129
+ $license = null;
130
+ // Get license statuses option
131
+ $statuses = get_option( 'wprss_settings_license_statuses', array() );
132
+ // Iterate all statuses
133
+ foreach ( $statuses as $_key => $_value ) {
134
+ // If not a license status key, continue to next
135
+ $_keyPos = strpos($_key, '_license_status');
136
+ if ( $_keyPos === FALSE ) {
137
+ continue;
138
+ }
139
+ // If the status is not valid, contine to next
140
+ if ($_value !== 'valid') {
141
+ continue;
142
+ }
143
+ // Get the addon ID
144
+ $_addonId = substr( $_key, 0, $_keyPos );
145
+ // Get the license
146
+ $_license = wprss_licensing_get_manager()->checkLicense( $_addonId, 'ALL' );
147
+ // If the license is not null
148
+ if ($_license !== null) {
149
+ // Save its details
150
+ $addon = $_addonId;
151
+ $license = $_license;
152
+ // And stop iterating
153
+ break;
154
+ }
155
+ }
156
+
157
+ // If we didn't find an add-on with a valid license, show the free help text.
158
+ if ( $addon === null || $license === null ) {
159
+ wprss_free_help_display();
160
+ return;
161
+ }
162
+
163
+ // Get the full license info so we can prefill the name and email
164
+ $customer_name = is_object($license) ? $license->customer_name : '';
165
+ $customer_email = is_object($license) ? $license->customer_email : '';
166
+
167
+ echo '<h3>' . __( 'Email Support', WPRSS_TEXT_DOMAIN ) . '</h3>';
168
+ echo wpautop( __( "If you still can't find an answer to your query after reading the documentation and going through the FAQ, just fill out the support request form below. We'll be happy to help you out.", WPRSS_TEXT_DOMAIN ) );
169
+
170
+ ?>
171
+
172
+ <form method="post">
173
+ <table>
174
+ <tr>
175
+ <td><strong><?php _e('From: ', WPRSS_TEXT_DOMAIN); ?></strong></td>
176
+ <td><input type='text' name='support-name' value="<?php echo esc_attr($customer_name); ?>" placeholder='<?php echo esc_attr('Name', WPRSS_TEXT_DOMAIN); ?>' style='width:100%;'></td>
177
+ <td><input type='text' name='support-email' value="<?php echo esc_attr($customer_email); ?>" placeholder='<?php echo esc_attr('Email', WPRSS_TEXT_DOMAIN); ?>' style='width:100%;'></td>
178
+ </tr>
179
+ <tr>
180
+ <td colspan="3" style="text-align:right;"><small><?php _e('Replies will be sent to this email address.'); ?></small></td>
181
+ </tr>
182
+ <tr>
183
+ <td colspan="3"><input type='text' name='support-subject' placeholder='<?php echo esc_attr('Subject', WPRSS_TEXT_DOMAIN); ?>' style='width:100%;'></td>
184
+ </tr>
185
+ <tr>
186
+ <td colspan="3"><textarea name='support-message' rows='10' cols='80' placeholder='<?php echo esc_attr('Message', WPRSS_TEXT_DOMAIN); ?>'></textarea></td>
187
+ </tr>
188
+ <tr>
189
+ <td colspan="3"><strong><?php _e('Attachments', WPRSS_TEXT_DOMAIN);?>: </strong></td>
190
+ </tr>
191
+ <tr>
192
+ <td colspan="3"><input type='checkbox' name='support-include-log' value='checked' checked><?php _e('WP RSS Aggregator log file', WPRSS_TEXT_DOMAIN); ?></td>
193
+ </tr>
194
+ <tr>
195
+ <td colspan="3"><input type='checkbox' name='support-include-sys' value='checked' checked><?php _e('WordPress debugging information', WPRSS_TEXT_DOMAIN); ?></td>
196
+ </tr>
197
+ </table>
198
+ </form>
199
+ <div style='line-height:2.3em; margin-top:10px;'>
200
+ <button id='send-message-btn' class='button button-primary'><?php _e('Send Message', WPRSS_TEXT_DOMAIN); ?></button>
201
+ <div id='support-error'></div>
202
+ </div>
203
+
204
+ <?php
205
+ }
206
+
207
+ /**
208
+ * Print the free help section with link to forums.
209
+ *
210
+ * @since 4.7
211
+ */
212
+ function wprss_free_help_display() {
213
+ echo '<h3>' . __( 'Support Forums', WPRSS_TEXT_DOMAIN ) . '</h3>';
214
+ printf(
215
+ wpautop(
216
+ __( 'Users of the free version of WP RSS Aggregator can ask questions on the <a href="%s">support forum</a>.', WPRSS_TEXT_DOMAIN )
217
+ ),
218
+ 'https://wordpress.org/support/plugin/wp-rss-aggregator'
219
+ );
220
+ }
221
+
222
+
223
+ add_action( 'wp_ajax_wprss_ajax_send_premium_support', 'wprss_ajax_send_premium_support' );
224
+ /**
225
+ * Handles the AJAX request to send the support form. Returns a JSON status.
226
+ *
227
+ * @since 4.7
228
+ */
229
+ function wprss_ajax_send_premium_support() {
230
+ $ret = array();
231
+
232
+ // Validate the form fields that were submitted and send any errors.
233
+ $error = wprss_validate_support_request();
234
+ if ($error !== FALSE) {
235
+ $ret['error'] = $error;
236
+ echo json_encode($ret);
237
+ die();
238
+ }
239
+
240
+ // Create the email content.
241
+ $subject = sanitize_text_field($_GET['support-subject']);
242
+ $message = wprss_create_support_message();
243
+ $headers = wprss_create_support_headers();
244
+
245
+ // Send the email.
246
+ $sent = wp_mail( "support@wprssaggregator.com", $subject, $message, $headers );
247
+
248
+ // NB, the retval is a best-guess about email sending. According to the WP Codex it
249
+ // doesn't mean the user received the email, it "only means that the method used
250
+ // was able to process the request without any errors."
251
+ if ($sent === FALSE) {
252
+ $ret['error'] = sprintf(__('There was an error sending the form. Please use the <a href="%s" target="_blank">contact form on our site.</a>'), esc_attr('https://www.wprssaggregator.com/contact/'));
253
+ $ret['message'] = $message;
254
+ } else {
255
+ $ret['status'] = 'OK';
256
+ }
257
+
258
+ echo json_encode($ret);
259
+ die();
260
+ }
261
+
262
+
263
+ /**
264
+ * Ensures that all support form fields have been filled out. Returns TRUE
265
+ *
266
+ * @since 4.7
267
+ * @return FALSE when all fields are valid, or a string containing an error they aren't.
268
+ */
269
+ function wprss_validate_support_request() {
270
+ $fields = array(
271
+ 'support-name',
272
+ 'support-email',
273
+ 'support-subject',
274
+ 'support-message'
275
+ );
276
+
277
+ // Ensure that each required field is present and filled out.
278
+ foreach ($fields as $field) {
279
+ if (!isset($_GET[$field]) || $_GET[$field] === "") {
280
+
281
+ return sprintf(
282
+ __('Please fill out all the fields in the form, including the <strong>%s</strong> field.', WPRSS_TEXT_DOMAIN),
283
+ ucfirst(substr($field, strpos($field, '-') + 1))
284
+ );
285
+ }
286
+ }
287
+
288
+ // Ensure the email is of a valid format.
289
+ if (is_email($_GET['support-email']) === FALSE) {
290
+ return __('Please enter a valid email address.', WPRSS_TEXT_DOMAIN);
291
+ }
292
+
293
+ return FALSE;
294
+ }
295
+
296
+
297
+ /**
298
+ * Creates and returns the support request email's message body.
299
+ *
300
+ * @since 4.7
301
+ */
302
+ function wprss_create_support_message() {
303
+ // Get the WP RSS Aggregator log.
304
+ $log = 'Customer did not send log';
305
+ if ($_GET['support-include-log'] === 'true') {
306
+ $log = wprss_get_log();
307
+ }
308
+
309
+ // Get the system information.
310
+ $sys_info = 'Customer did not send system information';
311
+ if ($_GET['support-include-sys'] === 'true') {
312
+ ob_start();
313
+ wprss_print_system_info();
314
+ $sys_info = ob_get_contents();
315
+ ob_end_clean();
316
+ }
317
+
318
+ // Get the license keys.
319
+ $keys = json_encode( get_option( 'wprss_settings_license_keys', array() ), JSON_PRETTY_PRINT );
320
+
321
+ // Get the message they entered.
322
+ $message = sanitize_text_field($_GET['support-message']);
323
+
324
+ // Remove any generated system data that may be present from previous form submission attempts.
325
+ $idx = strpos($message, "----------------------------------------------");
326
+ if ($idx !== FALSE) {
327
+ $message = substr($message, 0, $idx);
328
+ }
329
+
330
+ // Append the generated system data.
331
+ $message .= "\n\n----------------------------------------------\n";
332
+ $message .= "\nLicense Information:\n" . $keys;
333
+ $message .= "\n\n\nError Log:\n" . $log;
334
+ $message .= "\n\n\nSystem Information:\n" . $sys_info . "\n";
335
+
336
+ $message = apply_filters( 'wprss_support_message', $message );
337
+
338
+ return $message;
339
+ }
340
+
341
+
342
+ /**
343
+ * Creates and returns the support request email's headers.
344
+ *
345
+ * @since 4.7
346
+ */
347
+ function wprss_create_support_headers() {
348
+ $headers = "From: no-reply@wprssaggregator.com\r\n";
349
+ $headers .= "Reply-to: " . sanitize_text_field($_GET['support-name']) . " <" . sanitize_email($_GET['support-email']) . ">\r\n";
350
+
351
+ $headers = apply_filters( 'wprss_support_headers', $headers );
352
+
353
+ return $headers;
354
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
 
357
  /**
388
  * 1. The absolute path to the core plugin directory
389
  */
390
  class WPRSS_Help {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
 
392
+ static $_instance;
393
+
394
+ protected $_options;
395
+ protected $_enqueued_tooltip_content = array();
396
+ protected $_tooltips = array();
397
+
398
+ const OPTION_NAME = 'wprss_settings_help';
399
+ const CODE_PREFIX = 'wprss_help_';
400
+ const OVERRIDE_DEFAULT_PREFIX = '!';
401
+ const TEXT_DOMAIN = WPRSS_TEXT_DOMAIN;
402
+ const HASHING_CONCATENATOR = '|';
403
+ const OPTIONS_FILTER_SUFFIX = '_options';
404
+
405
+ const TOOLTIP_DATA_KEY_ID = 'id';
406
+ const TOOLTIP_DATA_KEY_TEXT = 'text';
407
+ const TOOLTIP_DATA_KEY_OPTIONS = 'options';
408
+
409
+ /**
410
+ * Retrieve the singleton instance
411
+ *
412
+ * @return WPRSS_Help
413
+ */
414
+ public static function get_instance() {
415
+ if ( is_null( self::$_instance ) ) {
416
+ $class_name = __CLASS__; // Late static bindings not allowed
417
+ self::$_instance = new $class_name();
418
+ }
419
+
420
+ return self::$_instance;
421
+ }
422
+
423
+ /**
424
+ * @since 4.10
425
+ */
426
+ public static function init()
427
+ {
428
+ if (static::get_instance()->_isEnqueueScripts()) {
429
+ add_action( 'admin_enqueue_scripts', array( self::get_instance(), '_admin_enqueue_scripts' ) );
430
+ add_action( 'admin_footer', array( self::get_instance(), '_admin_footer' ) );
431
  }
432
+ }
433
+
434
+ /**
435
+ * Determines if the admin scripts should get enqueued.
436
+ *
437
+ * @since 4.10
438
+ *
439
+ * @return bool True if admin scripts should be enqueued; false otherwise.
440
+ */
441
+ protected function _isEnqueueScripts()
442
+ {
443
+ return $this->_isWprssPage();
444
  }
445
 
446
+ /**
447
+ * Determines if the current page is related to WPRSS.
448
+ *
449
+ * @since 4.10
450
+ *
451
+ * @return bool True if the current page is related to WPRSS; false otherwise.
452
+ */
453
+ protected function _isWprssPage()
454
+ {
455
+ return wprss_is_wprss_page();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  }
457
 
 
 
 
 
458
 
459
+ /**
460
+ * Filters used:
461
+ *
462
+ * - `wprss_help_default_options`
463
+ *
464
+ * @param array $options Options that will overwrite defaults.
465
+ */
466
+ public function __construct( $options = array() ) {
467
+ $defaults = apply_filters( 'wprss_help_default_options', array(
468
+ 'tooltip_id_prefix' => 'wprss-tooltip-',
469
+ 'tooltip_handle_text' => '',
470
+ 'tooltip_handle_class' => 'wprss-tooltip-handle', // Used in logic to identify handle elements
471
+ 'tooltip_handle_class_extra' => 'fa fa-question-circle', // Not used in logic
472
+ 'tooltip_content_class' => 'wprss-tooltip-content',
473
+ 'tooltip_class' => 'wprss-ui-tooltip', // Overrides default jQuery UI class
474
+ 'is_enqueue_tooltip_content' => '0',
475
+ 'tooltip_handle_template' => '%1$s/help-tooltip-handle.php',
476
+ 'tooltip_content_template' => '%1$s/help-tooltip-content.php',
477
+ 'admin_footer_js_template' => '%1$s/help-footer-js.php',
478
+ 'tooltip_not_found_handle_html' => '',
479
+ 'text_domain' => self::TEXT_DOMAIN
480
+ ));
481
+ $db_options = $this->get_options_db();
482
+ $this->_set_options( $this->array_merge_recursive_distinct( $db_options, $defaults ) );
483
+
484
+ $this->_construct();
485
+ }
486
+
487
+
488
+ /**
489
+ * Used for parameter-less extension of constructor logic
490
+ */
491
+ protected function _construct() {
492
+
493
+ }
494
+
495
+
496
+ /**
497
+ * Return an option value, or the whole array of internal options.
498
+ * These options are a product of the defaults, the database, and anything
499
+ * set later on, applied on top of eachother and overwriting in that order.
500
+ *
501
+ * @param null|string $key The key of the option to return.
502
+ * @param null|mixed $default What to return if options with the specified key not found.
503
+ * @return array|mixed|null The option value, or an array of options.
504
+ */
505
+ public function get_options( $key = null, $default = null ) {
506
+ $options = $this->_options;
507
+
508
+ if ( is_null( $key ) ) {
509
+ return $options;
510
+ }
511
+
512
+ if( is_array( $key ) ) {
513
+ return $this->array_merge_recursive_distinct( $options, $key );
514
+ }
515
+
516
+ return isset( $options[ $key ] ) ? $options[ $key ] : $default;
517
+ }
518
+
519
+
520
+ /**
521
+ * Set the value of an internal option or options.
522
+ * Existing options will be overwritten. New options will be added.
523
+ * Database options will not be modified.
524
+ *
525
+ * @param string|array $key The key of the option to set, or an array of options.
526
+ * @param null|mixed $value The value of the option to set.
527
+ * @return WPRSS_Help This instance.
528
+ */
529
+ public function set_options( $key, $value = null ) {
530
+ if ( is_array( $key ) ) {
531
+ foreach ( $key as $_key => $_value ) {
532
+ $this->_set_options( $_key, $_value );
533
+ }
534
+
535
+ return $this;
536
+ }
537
+
538
+ $this->_set_options( $key, $value );
539
+ }
540
+
541
+
542
+ /**
543
+ * Set an option value, or all options.
544
+ * In latter case completely overrides the whole options array.
545
+ *
546
+ * @param string|array $key The key of the option to set, or the whole options array.
547
+ * @param null|mixed $value Value of the option to set.
548
+ * @return WPRSS_Help This instance.
549
+ */
550
+ protected function _set_options( $key, $value = null ) {
551
+ if ( is_array( $key ) ) {
552
+ $this->_options = $key;
553
+ return $this;
554
+ }
555
+
556
+ $this->_options[ $key ] = $value;
557
+ return $this;
558
+ }
559
+
560
+
561
+ /**
562
+ * Returns a WPRSS_Help option or options from the database.
563
+ *
564
+ * @param string $key The key of the option to return.
565
+ * @param null|mixed $default What to return if option identified by $key is not found.
566
+ * @return null|array|mixed The options or option value.
567
+ */
568
+ public function get_options_db( $key = null, $default = null ) {
569
+ $options = (array) get_option( self::OPTION_NAME, array() );
570
+
571
+ if ( is_null( $key ) ) {
572
+ return $options;
573
+ }
574
+
575
+ return isset( $options[ $key ] ) ? $options[ $key ] : $default;
576
+ }
577
+
578
+
579
+ /**
580
+ * Get content of a template.
581
+ *
582
+ * Filters used
583
+ *
584
+ * - `wprss_help_template_path`
585
+ * - `wprss_help_template_vars`
586
+ *
587
+ * @param string $path Full path to the template
588
+ * @param array $vars This will be passed to the template
589
+ */
590
+ public function get_template( $path, $vars = array() ) {
591
+ $vars = (array) $vars;
592
+
593
+ // Entry points
594
+ $path = apply_filters( 'wprss_help_template_path', $path, $vars );
595
+ $vars = apply_filters( 'wprss_help_template_vars', $vars, $path );
596
+
597
+ ob_start();
598
+ include($path);
599
+ $content = ob_get_contents();
600
+ ob_end_clean();
601
+
602
+ return $content;
603
+ }
604
+
605
+
606
+ /**
607
+ * This is called during the `admin_enqueue_scripts` action, and will
608
+ * enqueue scripts needed for the backend.
609
+ *
610
+ * Filters used:
611
+ *
612
+ * - `wprss_help_admin_scripts`
613
+ *
614
+ * @return WPRSS_Help This instance.
615
+ */
616
+ public function _admin_enqueue_scripts()
617
+ {
618
+ if (!wprss_is_wprss_page()) {
619
+ return $this;
 
 
620
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
 
622
+ $scripts = $this->apply_filters( 'admin_scripts', array(
623
+ 'jquery-ui-tooltip' => array()
624
+ ));
625
+
626
+ foreach ( $scripts as $_handle => $_args ) {
627
+ // Allows numeric array with handles as values
628
+ if ( is_numeric( $_handle ) ) {
629
+ $_handle = $_args;
630
+ }
631
+
632
+ // Allows specifying null as value to simply enqueue handle
633
+ if ( empty( $_args ) ){
634
+ $_args = array();
635
+ }
636
+
637
+ array_unshift( $_args, $_handle );
638
+ call_user_func_array( 'wp_enqueue_script', $_args );
639
+ }
640
+
641
+ return $this;
642
+ }
643
+
644
+
645
+ public function _admin_footer() {
646
+ $html = '';
647
+ $html .= $this->get_enqueued_tooltip_content_html() . "\n";
648
+ $html .= $this->get_admin_footer_js_html();
649
+ $html = $this->apply_filters( 'admin_footer', $html );
650
+
651
+ echo $html;
652
+ }
653
+
654
+
655
+ public function is_overrides_default_prefix( $string ) {
656
+ return strpos( $string, self::OVERRIDE_DEFAULT_PREFIX ) === 0;
657
+ }
658
+
659
+
660
+ /**
661
+ * @return string This class's text domain
662
+ */
663
+ public function get_text_domain() {
664
+ return self::TEXT_DOMAIN;
665
+ }
666
+
667
+ /**
668
+ * Format this string, replacing placeholders with values, and translate it
669
+ * in the class's text domain.
670
+ *
671
+ * @see sprintf()
672
+ * @param string $string The string to translate.
673
+ * @param mixed $argN,.. Additional arguments.
674
+ */
675
+ public function __( $string, $argN = null ) {
676
+ $args = func_get_args();
677
+ $args[0] = $string = __( $string, $this->get_text_domain() );
678
+
679
+ $string = call_user_func_array( 'sprintf', $args );
680
+
681
+ return $string;
682
+ }
683
+
684
+ /**
685
+ * Hashes all the given values into a single hash.
686
+ * Accepts an infinite number of parameters, all of which will be first
687
+ * glued together by a separator, then hashed.
688
+ * Non-scalar values will be serialized.
689
+ *
690
+ * @param mixed $value The value to hash.
691
+ * @param mixed $argN Other values to hash.
692
+ * @return string The hash.
693
+ */
694
+ public function get_hash( $value ) {
695
+ $args = func_get_args();
696
+ $glue = self::HASHING_CONCATENATOR;
697
+
698
+ $blob = '';
699
+ foreach ( $args as $_idx => $_arg ) {
700
+ $blob .= is_scalar( $_arg ) ? $_arg : serialize( $_arg );
701
+ $blob .= $glue;
702
+ }
703
+
704
+ $blob = substr( $blob, 0, -1 );
705
+
706
+ return sha1( $blob );
707
+ }
708
+
709
+ /**
710
+ * Get the class code prefix, or the specified prefixed with it.
711
+ *
712
+ * @param string $string A string to prefix.
713
+ * @return string The code prefix or the prefixed string.
714
+ */
715
+ public function get_code_prefix( $string = '' ) {
716
+ return self::CODE_PREFIX . (string)$string;
717
+ }
718
+
719
+ /**
720
+ * Optionally prefix a string with the class code prefix, unless it
721
+ * contains the "!" character in the very beginning, in which case it will
722
+ * simply be removed.
723
+ *
724
+ * @param string $string The string to consider for prefixing.
725
+ * @return string The prefixed or clean string.
726
+ */
727
+ public function prefix( $string ) {
728
+ return $this->is_overrides_default_prefix( $string )
729
+ ? substr( $string, 1 )
730
+ : $this->get_code_prefix( $string );
731
+ }
732
+
733
+ /**
734
+ * Applies filters, but prefixes the filter name with 'wprss_help_',
735
+ * unless '!' is specified as the first character of the filter.
736
+ *
737
+ * @param string $filter_name Name or "tag" of the filter.
738
+ * @param mixed $subject The value to apply filters to.
739
+ * @param mixed $argN,.. Additional filter arguments
740
+ * @return mixed Result of filtering
741
+ */
742
+ public function apply_filters( $filter_name, $subject, $argN = null ) {
743
+ $args = func_get_args();
744
+
745
+ $args[0] = $filter_name = $this->prefix( $filter_name );
746
+
747
+ return call_user_func_array( 'apply_filters', $args );
748
+ }
749
+
750
+
751
+ /**
752
+ * Applies a filters with the specified name to the options that were
753
+ * applied on top of defaults.
754
+ * The name will be prefixed with the class prefix 'wprss_help_', and
755
+ * suffixed with '_options'.
756
+ *
757
+ * @param string $filter_name Name of the filter to apply to the options
758
+ * @param array $options The options to filter
759
+ * @param mixed $filter_argN,.. Other filter arguments to be passed to filter
760
+ */
761
+ public function apply_options_filters( $filter_name, $options = array(), $filter_argN = null ) {
762
+ $args = func_get_args();
763
+
764
+ // Adding sufix
765
+ $args[0] = $filter_name .= self::OPTIONS_FILTER_SUFFIX;
766
+
767
+ // Applying defaults
768
+ $args[1] = $options = $this->get_options( $options );
769
+
770
+ // Entry point. Order of args is already correct.
771
+ $options = call_user_func_array( array( $this, 'apply_filters' ), $args );
772
+
773
+ return $options;
774
+ }
775
+
776
+
777
+ /**
778
+ * Parses the tooltip handle template path for placeholders.
779
+ *
780
+ * Filters used:
781
+ *
782
+ * - `wprss_help_admin_footer_js_html_template`
783
+ *
784
+ * @param null|string $path Optional path to parse and retrieve. Default: value of the 'admin_footer_js_template' option.
785
+ * @return string Path to the template.
786
+ */
787
+ public function get_admin_footer_js_html_template( $path = null ) {
788
+ // Default is from options
789
+ if ( is_null( $path ) ) {
790
+ $path = $this->get_options( 'admin_footer_js_template' );
791
+ }
792
+
793
+ // Entry point
794
+ $path = $this->apply_filters( 'admin_footer_js_html_template', $path );
795
+
796
+ return $this->parse_path( $path );
797
+ }
798
+
799
+
800
+ /**
801
+ * Get the HTML of the JavaScript for the footer in Admin Panel.
802
+ *
803
+ * Filters used:
804
+ *
805
+ * - `wprss_help_admin_footer_js_html`
806
+ *
807
+ * @param array $options Any additional options to be used with defaults.
808
+ * @return string The HTML.
809
+ */
810
+ public function get_admin_footer_js_html( $options = array() ) {
811
+ $options = $this->apply_options_filters( 'admin_footer_js_html', $options);
812
+
813
+ $templatePath = $this->get_admin_footer_js_html_template( $options['admin_footer_js_template'] );
814
+
815
+ return $this->get_template($templatePath, $options);
816
+ }
817
+
818
+
819
+ /**
820
+ * Parses the tooltip handle template path for placeholders.
821
+ *
822
+ * Filters used:
823
+ *
824
+ * - `wprss_help_tooltip_handle_html_template`
825
+ *
826
+ * @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
827
+ * @return string Path to the template.
828
+ */
829
+ public function get_tooltip_handle_html_template( $path = null ) {
830
+ // Default is from options
831
+ if ( is_null( $path ) ) {
832
+ $path = $this->get_options( 'tooltip_handle_template' );
833
+ }
834
+
835
+ // Entry point
836
+ $path = $this->apply_filters( 'tooltip_handle_html_template', $path );
837
+
838
+ return $this->parse_path( $path );
839
+ }
840
+
841
+
842
+ /**
843
+ * Get the HTML of the tooltip handle.
844
+ *
845
+ * Filters used:
846
+ *
847
+ * - `wprss_help_tooltip_handle_html_options`
848
+ *
849
+ * @param string $text Content of the tooltip text.
850
+ * @param string $id ID of the tooltip.
851
+ * @param array $options Any additional options to be used with defaults.
852
+ * @return string The HTML.
853
+ */
854
+ public function get_tooltip_handle_html( $text, $id, $options = array() ) {
855
+ $options = $this->apply_options_filters( 'tooltip_handle_html', $options, $text, $id);
856
+
857
+ // Add template varialbes
858
+ $options['tooltip_id'] = $id;
859
+ $options['tooltip_text'] = $text;
860
+
861
+ $templatePath = $this->get_tooltip_handle_html_template( $options['tooltip_handle_template'] );
862
+
863
+ return $this->get_template($templatePath, $options);
864
+ }
865
+
866
+
867
+ /**
868
+ * Parses the tooltip content template path for placeholders.
869
+ *
870
+ * Filters used:
871
+ *
872
+ * - `wprss_help_tooltip_content_html_template`
873
+ *
874
+ * @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
875
+ * @return string Path to the template.
876
+ */
877
+ public function get_tooltip_content_html_template( $path = null ) {
878
+ // Default is from options
879
+ if ( is_null( $path ) ) {
880
+ $path = $this->get_options( 'tooltip_content_template' );
881
+ }
882
+
883
+ // Entry point
884
+ $path = $this->apply_filters( 'tooltip_content_html_template', $path );
885
+
886
+ return $this->parse_path( $path );
887
+ }
888
+
889
+
890
+ /**
891
+ * Get the HTML of the tooltip content.
892
+ *
893
+ * Filters used:
894
+ *
895
+ * - `wprss_help_tooltip_content_html_options`
896
+ *
897
+ * @param string $text Content of the tooltip text.
898
+ * @param string $id ID of the tooltip.
899
+ * @param array $options Any additional options to be used with defaults.
900
+ * @return string The HTML.
901
+ */
902
+ public function get_tooltip_content_html( $text, $id, $options = array() ) {
903
+ $options = $this->apply_options_filters( 'tooltip_content_html', $options, $text, $id );
904
+
905
+ // Add template varialbes
906
+ $options['tooltip_id'] = $id;
907
+ $options['tooltip_text'] = $text;
908
+
909
+ $templatePath = $this->get_tooltip_content_html_template( $options['tooltip_content_template'] );
910
+
911
+ return $this->get_template( $templatePath, $options );
912
+ }
913
+
914
+
915
+ /**
916
+ * Add tooltip and get tooltip HTML.
917
+ * If $text is null, just get the HTML of tooltip with specified ID.
918
+ * The `is_enqueue_tooltip_content` option determines whether to enqueue
919
+ * the content, instead of outputting it after the handle.
920
+ *
921
+ * @param string $id ID for this tooltip
922
+ * @param string|null $text Text of this tooltip. If null, tooltip will not be added, but only retrieved.
923
+ * @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
924
+ * @return string The tooltip handle and, optionally, content.
925
+ */
926
+ public function tooltip( $id, $text = null, $options = array() ) {
927
+ $this->add_tooltip( $id, $text, $options );
928
+ return $this->do_tooltip( $id );
929
+ }
930
+
931
+
932
+ /**
933
+ * Add tooltips in a batch, with optionally prefixed ID.
934
+ *
935
+ * @param array $tooltips An array where key is tooltip ID and value is tooltip text.
936
+ * @param string $prefix A prefix to add to all tooltip IDs.
937
+ * @param array $options Arra of options for all the tooltips to add.
938
+ * @return \WPRSS_Help
939
+ */
940
+ public function add_tooltips( $tooltips, $prefix = null, $options = array() ) {
941
+ $prefix = (string) $prefix;
942
+ if ( !is_array($options) ) $options = array();
943
+
944
+ foreach ( $tooltips as $_id => $_text ) {
945
+ $this->add_tooltip( $prefix . $_id, $_text, $options );
946
+ }
947
+
948
+ return $this;
949
+ }
950
+
951
+
952
+ /**
953
+ * Add a tooltip for later display.
954
+ * Text and options will be replaced by existing text and options, if they
955
+ * are empty, and a tooltip with the same ID is already registered.
956
+ *
957
+ * @param string $id The ID of this tooltip
958
+ * @param string $text Text for this tooltip
959
+ * @param array $options Options for this tooltip.
960
+ * @return WPRSS_Help This instance.
961
+ */
962
+ public function add_tooltip( $id, $text = null, $options = array() ) {
963
+ if ( $tooltip = $this->get_tooltip( $id ) ) {
964
+ if ( is_null( $text ) ) $text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : $text;
965
+ if ( empty( $options ) ) $options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : $options;
966
+ }
967
+
968
+ $this->set_tooltip( $id, $text, $options );
969
+
970
+ return $this;
971
+ }
972
+
973
+
974
+ /**
975
+ * Set a tooltip, existing or not.
976
+ *
977
+ * @param string $id The ID of this tooltip
978
+ * @param string $text Text for this tooltip
979
+ * @param array $options Options for this tooltip.
980
+ * @return WPRSS_Help This instance.
981
+ */
982
+ public function set_tooltip( $id, $text = null, $options = array() ) {
983
+ $this->_tooltips[ $id ] = array(
984
+ self::TOOLTIP_DATA_KEY_ID => $id,
985
+ self::TOOLTIP_DATA_KEY_TEXT => $text,
986
+ self::TOOLTIP_DATA_KEY_OPTIONS => $options
987
+ );
988
+
989
+ return $this;
990
+ }
991
+
992
+
993
+ /**
994
+ * Retrieve one tooltip, or an array containing all tooltips.
995
+ *
996
+ * @param string|null $id The ID of the tooltip to retrieve.
997
+ * @param mixed|null $default What to return if tooltip with specified ID not found.
998
+ * @return array An array that contains the following indexes: 'id', 'text', 'options'. See {@link add_tooltip()} for details.
999
+ */
1000
+ public function get_tooltip( $id = null, $default = null ) {
1001
+ if ( is_null( $id ) ) {
1002
+ return $this->_tooltips;
1003
+ }
1004
+
1005
+ return $this->has_tooltip( $id ) ? $this->_tooltips[ $id ] : $default;
1006
+ }
1007
+
1008
+
1009
+ /**
1010
+ * Check whether a tooltip with the specified ID exists.
1011
+ *
1012
+ * @param string $id ID of the tooltip to check for.
1013
+ * @return boolean True if a tooltip with the specified ID exists; false otherwise.
1014
+ */
1015
+ public function has_tooltip( $id ) {
1016
+ return isset( $this->_tooltips[ $id ] );
1017
+ }
1018
+
1019
+ /**
1020
+ * Get registered tooltip HTML.
1021
+ *
1022
+ * Filters used:
1023
+ *
1024
+ * - `wprss_help_tooltip_options` - Filters options used for tooltip
1025
+ *
1026
+ * @param string $id ID for this tooltip
1027
+ * @param string $text Text of this tooltip
1028
+ * @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
1029
+ * @return string The tooltip handle and, optionally, content.
1030
+ */
1031
+ public function do_tooltip( $id ) {
1032
+ $options = $this->get_options();
1033
+
1034
+ if ( !($tooltip = $this->get_tooltip( $id )) || !isset($tooltip[ self::TOOLTIP_DATA_KEY_TEXT ]) || !$tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) {
1035
+ return isset( $options['tooltip_not_found_handle_html'] )
1036
+ ? $options['tooltip_not_found_handle_html']
1037
+ : null;
1038
+ }
1039
+
1040
+ $options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : null;
1041
+ $text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : null;
1042
+
1043
+ if ( !is_array( $options ) ) {
1044
+ $options = array( 'is_enqueue_tooltip_content' => $options );
1045
+ }
1046
+
1047
+ // Entry point
1048
+ $options = $this->apply_options_filters( 'tooltip', $options, $id, $text );
1049
+
1050
+ // Get handle HTML
1051
+ $output = $this->get_tooltip_handle_html( $text, $id, $options );
1052
+
1053
+ if ( $this->evaluate_boolean( $options['is_enqueue_tooltip_content'] ) ) {
1054
+ $this->enqueue_tooltip_content($text, $id, $options);
1055
+ }
1056
+ else {
1057
+ $output .= $this->get_tooltip_content_html( $text, $id, $options );
1058
+ }
1059
+
1060
+ return $output;
1061
+ }
1062
+
1063
+
1064
+ /**
1065
+ * Enqueue tooltip content to be displayed in another part of the page.
1066
+ *
1067
+ * @param string $text The text of the tooltip content to enqueue.
1068
+ * @param string $id ID of the tooltip, the content of which to enqueue.
1069
+ * @param array $options This tooltip's options.
1070
+ * @return \WP_Error|\WPRSS_Help This instance, or error if enqueue method is invalid.
1071
+ */
1072
+ public function enqueue_tooltip_content( $text, $id, $options = array() ) {
1073
+ $queue_method = $this->apply_filters( 'enqueue_tooltip_content_method', array( $this, '_enqueue_tooltip_content' ), $options, $id, $text );
1074
+
1075
+ // "Error handling" WP style
1076
+ if ( !is_callable( $queue_method ) ) {
1077
+ return new WP_Error( $this->prefix( 'invalid_queue_method' ), $this->__( 'Could not enqueue tooltip content: the queue method is not a valid callable.' ), array(
1078
+ 'queue_method' => $queue_method,
1079
+ 'text' => $text,
1080
+ 'id' => $id,
1081
+ 'options' => $options
1082
+ ));
1083
+ }
1084
+
1085
+ call_user_func_array( $queue_method, array( $text, $id, $options ) );
1086
+
1087
+ return $this;
1088
+ }
1089
+
1090
+
1091
+ public function _enqueue_tooltip_content( $text, $id, $options = array() ) {
1092
+ $hash = $this->get_hash( $text, $id, $options );
1093
+ $this->_enqueued_tooltip_content[ $hash ] = array(
1094
+ self::TOOLTIP_DATA_KEY_TEXT => $text,
1095
+ self::TOOLTIP_DATA_KEY_ID => $id,
1096
+ self::TOOLTIP_DATA_KEY_OPTIONS => $options
1097
+ );
1098
+
1099
+ return $this;
1100
+ }
1101
+
1102
+
1103
+ public function get_enqueued_tooltip_content() {
1104
+ return $this->_enqueued_tooltip_content;
1105
+ }
1106
+
1107
+
1108
+ public function get_enqueued_tooltip_content_html() {
1109
+ $output = '';
1110
+ foreach ( $this->get_enqueued_tooltip_content() as $_hash => $_vars ) {
1111
+ $options = is_array( $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] : array();
1112
+ $output = $this->get_tooltip_content_html( $_vars[ self::TOOLTIP_DATA_KEY_ID ], $_vars[ self::TOOLTIP_DATA_KEY_ID ], $options );
1113
+ }
1114
+
1115
+ echo $output;
1116
+ }
1117
+
1118
+
1119
+ /**
1120
+ * Check whether or not the given value is false.
1121
+ * False values are all {@link empty()} values, and also strings 'false' and 'no'.
1122
+ *
1123
+ * @param mixed $value The value to check.
1124
+ * @return boolean Whether or not the value is considered to be false.
1125
+ */
1126
+ public function evaluate_boolean( $value ) {
1127
+ return (empty( $value ) || strtolower( $value ) === 'false' || strtolower( $value ) === 'no')
1128
+ ? false
1129
+ : true;
1130
+ }
1131
+
1132
+
1133
+ /**
1134
+ * Merge two arrays in an intuitive way.
1135
+ * Input arrays remain unchanged.
1136
+ *
1137
+ * @see http://php.net/manual/en/function.array-merge-recursive.php#92195
1138
+ * @param array $array1 The array to merge.
1139
+ * @param array $array2 The array to merge into.
1140
+ * @return array The merged array.
1141
+ */
1142
+ public function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
1143
+ $merged = $array1;
1144
+
1145
+ foreach ( $array2 as $key => &$value ) {
1146
+ if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
1147
+ $merged[ $key ] = $this->array_merge_recursive_distinct( $merged[ $key ], $value );
1148
+ } else {
1149
+ $merged[ $key ] = $value;
1150
+ }
1151
+ }
1152
+
1153
+ return $merged;
1154
+ }
1155
+
1156
+
1157
+ /**
1158
+ * Converts an array to a numeric array.
1159
+ * If $map is empty, assumes that the array keys are already in order.
1160
+ * If $map is a number, assumes it's the amount of elements to return.
1161
+ * If $map is an array, assumes it is the map of intended numeric indexes to their value in the input array.
1162
+ *
1163
+ * @param array $array The array to convert to a numeric array
1164
+ * @param false|null|array $map The map of the array indexes, or number of array elements to slice, or nothing.
1165
+ * @return array The resulting numeric array.
1166
+ */
1167
+ public function array_to_numeric( $array, $map = null ) {
1168
+ $result = array();
1169
+
1170
+ // If map is not an array, assume it's an indicator
1171
+ if ( !is_array( $map ) ) {
1172
+ $array = array_values( $array );
1173
+ }
1174
+
1175
+ // If map is empty, assume keys are in order
1176
+ if ( empty( $map ) ) {
1177
+ return $array;
1178
+ }
1179
+
1180
+ // If map is a number, assume it's the amount of elements to return
1181
+ if ( is_numeric( $map ) ) {
1182
+ $map = intval( $map );
1183
+ return array_slice( $array, 0, $map );
1184
+ }
1185
+
1186
+ foreach( $map as $_idx => $_key ) {
1187
+ $result[ $_idx ] = $array[ $_key ];
1188
+ }
1189
+
1190
+ return $result;
1191
+ }
1192
+
1193
+
1194
+ /**
1195
+ * Parses the template and replaces placeholders with their values.
1196
+ * This function uses {@see sprintf()} to format the template string using
1197
+ * the values provided in $data.
1198
+ * It is also possible for $data to be an associative array of key-value pairs.
1199
+ * To achieve the same result, a map can be provided, mapping data keys to
1200
+ * their placeholder positions.
1201
+ * If no map is provided,
1202
+ *
1203
+ * @param string $string The template string.
1204
+ * @param array $data The key-value pairs of template data.
1205
+ * @param false|null|array $map {@see array_to_numeric()} The template value map.
1206
+ * @return string The parsed and modified template.
1207
+ */
1208
+ public function parse_template( $string, $data, $map = null ) {
1209
+ $data = $this->array_to_numeric( $data, $map );
1210
+ array_unshift( $data, $string );
1211
+ return call_user_func_array( 'sprintf', $data );
1212
+ }
1213
+
1214
+
1215
+ /**
1216
+ * Parses a path template specifically with WPRSS_Help path placeholders.
1217
+ *
1218
+ * Filters used (in order):
1219
+ *
1220
+ * 1. `parse_path_data_default`;
1221
+ * 2. `parse_path_data`;
1222
+ * 3. `parse_path_map`;
1223
+ * 4. `parse_path_path`.
1224
+ *
1225
+ * @see WPRSS_Help::parse_template()
1226
+ * @param string $path The path to parse.
1227
+ * @param null|array $data Any additional data. Will be merged with defaults.
1228
+ * @param null|array $map The map for parsing.
1229
+ * @return string The path with placeholders replaced
1230
+ */
1231
+ public function parse_path( $path, $data = null, $map = null ) {
1232
+ if( is_null( $data ) ) {
1233
+ $data = array();
1234
+ }
1235
+
1236
+ $defaults = $this->apply_filters( 'parse_path_data_default', array(
1237
+ 'wprss_templates_dir' => wprss_get_templates_dir()
1238
+ ));
1239
+ $data = $this->array_merge_recursive_distinct( $data, $defaults );
1240
+ $data = $this->apply_filters( 'parse_path_data', $data, $path, $map );
1241
+ $map = $this->apply_filters( 'parse_path_map', $map, $data, $path );
1242
+ $path = $this->apply_filters( 'parse_path_path', $path, $data, $map );
1243
+
1244
+ return $this->parse_template( $path, $data, $map );
1245
+ }
1246
  }
1247
 
1248
  WPRSS_Help::init();
includes/admin-intro-page.php CHANGED
@@ -4,18 +4,18 @@ if (!defined('ABSPATH')) {
4
  die;
5
  }
6
 
7
- const WPRSS_INTRO_PAGE_SLUG = 'wpra-intro';
8
- const WPRSS_FIRST_ACTIVATION_OPTION = 'wprss_first_activation_time';
9
- const WPRSS_DB_VERSION_OPTION = 'wprss_db_version';
10
- const WPRSS_INTRO_DID_INTRO_OPTION = 'wprss_did_intro';
11
- const WPRSS_INTRO_FEED_ID_OPTION = 'wprss_intro_feed_id';
12
- const WPRSS_INTRO_FEED_LIMIT = 20;
13
- const WPRSS_INTRO_STEP_OPTION = 'wprss_intro_step';
14
- const WPRSS_INTRO_NONCE_NAME = 'wprss_intro_nonce';
15
- const WPRSS_INTRO_STEP_POST_PARAM = 'wprss_intro_step';
16
- const WPRSS_INTRO_FEED_URL_PARAM = 'wprss_intro_feed_url';
17
- const WPRSS_INTRO_SHORTCODE_PAGE_OPTION = 'wprss_intro_shortcode_page';
18
- const WPRSS_INTRO_SHORTCODE_PAGE_PREVIEW_PARAM = 'wprss_preview_shortcode_page';
19
 
20
  /**
21
  * Registers the introduction page.
@@ -37,6 +37,10 @@ add_action('admin_menu', function () {
37
  * Renders the intro page.
38
  *
39
  * @since 4.12
 
 
 
 
40
  */
41
  function wprss_render_intro_page()
42
  {
@@ -68,9 +72,6 @@ function wprss_render_intro_page()
68
  echo wprss_render_template('admin/intro-page.twig', array(
69
  'title' => 'Welcome to WP RSS Aggregator 👋',
70
  'subtitle' => 'Follow these introductory steps to get started with WP RSS Aggregator.',
71
- 'path' => array(
72
- 'images' => WPRSS_IMG,
73
- ),
74
  ));
75
  }
76
 
@@ -91,7 +92,7 @@ add_action('wp_ajax_wprss_set_intro_step', function () {
91
 
92
  if ($step === null) {
93
  wprss_ajax_error_response(
94
- sprintf(__('Missing intro step param "%s"', 'wprss'), WPRSS_INTRO_STEP_POST_PARAM)
95
  );
96
  }
97
 
@@ -118,12 +119,12 @@ add_action('wp_ajax_wprss_create_intro_feed', function () {
118
 
119
  if ($url === null) {
120
  wprss_ajax_error_response(
121
- __('Missing feed URL parameter', 'wprss')
122
  );
123
  }
124
  if ($url === false) {
125
  wprss_ajax_error_response(
126
- __('The given feed URL is invalid', 'wprss')
127
  );
128
  }
129
 
@@ -133,7 +134,7 @@ add_action('wp_ajax_wprss_create_intro_feed', function () {
133
  $data = array(
134
  'feed_items' => $items,
135
  );
136
- wprss_set_intro_done();
137
  wprss_ajax_success_response($data);
138
  } catch (Exception $e) {
139
  wprss_ajax_error_response($e->getMessage(), 500);
@@ -218,7 +219,7 @@ function wprss_preview_feed_items($url, $max = 10)
218
 
219
  add_action('wprss_create_intro_feed_source', 'wprss_create_intro_feed_source');
220
  /**
221
- * Creates the feed source for the on-boarding introduction process.
222
  *
223
  * @since 4.12
224
  *
@@ -231,7 +232,7 @@ add_action('wprss_create_intro_feed_source', 'wprss_create_intro_feed_source');
231
  function wprss_create_intro_feed_source($url)
232
  {
233
  $feedId = get_option(WPRSS_INTRO_FEED_ID_OPTION, 0);
234
- $feed = get_post($feedId);
235
 
236
  if ($feed === null || $feed->post_status != 'publish') {
237
  $newId = wprss_create_feed_source_with_url($url);
@@ -242,15 +243,15 @@ function wprss_create_intro_feed_source($url)
242
  }
243
 
244
  // Update the existing feed source with a new generated name and new URL
245
- wp_update_post([
246
  'ID' => $feedId,
247
  'post_title' => wprss_feed_source_name_from_url($url),
248
  'post_status' => 'publish',
249
- 'meta_input' => [
250
  'wprss_url' => $url,
251
  'wprss_limit' => WPRSS_INTRO_FEED_LIMIT
252
- ]
253
- ]);
254
 
255
  // Re-import the items for this feed
256
  wprss_delete_feed_items($feedId);
@@ -273,11 +274,11 @@ function wprss_create_intro_feed_source($url)
273
  function wprss_create_feed_source_with_url($url)
274
  {
275
  $name = wprss_feed_source_name_from_url($url);
276
- $result = wprss_import_feed_sources_array([$url => $name]);
277
 
278
  if (empty($result)) {
279
  throw new Exception(
280
- sprintf(__('Failed to import the feed source "%s" with URL "%s"', 'wprss'), $name, $url)
281
  );
282
  }
283
 
@@ -302,7 +303,7 @@ function wprss_create_feed_source_with_url($url)
302
  function wprss_import_feed_sources_array($array)
303
  {
304
  /* @var $importer Aventura\Wprss\Core\Component\BulkSourceImport */
305
- $importer = wprss_wp_container()->get(WPRSS_SERVICE_ID_PREFIX . 'array_source_importer');
306
 
307
  return $importer->import($array);
308
  }
@@ -329,8 +330,9 @@ function wprss_feed_source_name_from_url($url)
329
  }
330
 
331
  $name = parse_url($url, PHP_URL_HOST);
 
332
 
333
- return ($name === null) ? $url : $name;
334
  }
335
 
336
  /**
@@ -370,7 +372,7 @@ function wprss_get_intro_shortcode_page()
370
  function wprss_create_shortcode_page($title = null, $status = 'draft')
371
  {
372
  $title = ($title === null)
373
- ? _x('Feeds', 'default name of shortcode page', 'wprss')
374
  : $title;
375
 
376
  $id = wp_insert_post(array(
@@ -445,7 +447,7 @@ function wprss_should_do_intro_page()
445
  */
446
  function wprss_set_intro_done($done = true)
447
  {
448
- update_option(WPRSS_INTRO_DID_INTRO_OPTION, $done ? '1' : '0', false);
449
  }
450
 
451
  /**
4
  die;
5
  }
6
 
7
+ define('WPRSS_INTRO_PAGE_SLUG', 'wpra-intro');
8
+ define('WPRSS_FIRST_ACTIVATION_OPTION', 'wprss_first_activation_time');
9
+ define('WPRSS_DB_VERSION_OPTION', 'wprss_db_version');
10
+ define('WPRSS_INTRO_DID_INTRO_OPTION', 'wprss_did_intro');
11
+ define('WPRSS_INTRO_FEED_ID_OPTION', 'wprss_intro_feed_id');
12
+ define('WPRSS_INTRO_FEED_LIMIT', 20);
13
+ define('WPRSS_INTRO_STEP_OPTION', 'wprss_intro_step');
14
+ define('WPRSS_INTRO_NONCE_NAME', 'wprss_intro_nonce');
15
+ define('WPRSS_INTRO_STEP_POST_PARAM', 'wprss_intro_step');
16
+ define('WPRSS_INTRO_FEED_URL_PARAM', 'wprss_intro_feed_url');
17
+ define('WPRSS_INTRO_SHORTCODE_PAGE_OPTION', 'wprss_intro_shortcode_page');
18
+ define('WPRSS_INTRO_SHORTCODE_PAGE_PREVIEW_PARAM', 'wprss_preview_shortcode_page');
19
 
20
  /**
21
  * Registers the introduction page.
37
  * Renders the intro page.
38
  *
39
  * @since 4.12
40
+ *
41
+ * @throws Twig_Error_Loader
42
+ * @throws Twig_Error_Runtime
43
+ * @throws Twig_Error_Syntax
44
  */
45
  function wprss_render_intro_page()
46
  {
72
  echo wprss_render_template('admin/intro-page.twig', array(
73
  'title' => 'Welcome to WP RSS Aggregator 👋',
74
  'subtitle' => 'Follow these introductory steps to get started with WP RSS Aggregator.',
 
 
 
75
  ));
76
  }
77
 
92
 
93
  if ($step === null) {
94
  wprss_ajax_error_response(
95
+ sprintf(__('Missing intro step param "%s"', WPRSS_TEXT_DOMAIN), WPRSS_INTRO_STEP_POST_PARAM)
96
  );
97
  }
98
 
119
 
120
  if ($url === null) {
121
  wprss_ajax_error_response(
122
+ __('Missing feed URL parameter', WPRSS_TEXT_DOMAIN)
123
  );
124
  }
125
  if ($url === false) {
126
  wprss_ajax_error_response(
127
+ __('The given feed URL is invalid', WPRSS_TEXT_DOMAIN)
128
  );
129
  }
130
 
134
  $data = array(
135
  'feed_items' => $items,
136
  );
137
+ wprss_set_intro_done(true);
138
  wprss_ajax_success_response($data);
139
  } catch (Exception $e) {
140
  wprss_ajax_error_response($e->getMessage(), 500);
219
 
220
  add_action('wprss_create_intro_feed_source', 'wprss_create_intro_feed_source');
221
  /**
222
+ * Creates the feed source for the onboarding introduction process.
223
  *
224
  * @since 4.12
225
  *
232
  function wprss_create_intro_feed_source($url)
233
  {
234
  $feedId = get_option(WPRSS_INTRO_FEED_ID_OPTION, 0);
235
+ $feed = get_post($feedId, OBJECT);
236
 
237
  if ($feed === null || $feed->post_status != 'publish') {
238
  $newId = wprss_create_feed_source_with_url($url);
243
  }
244
 
245
  // Update the existing feed source with a new generated name and new URL
246
+ wp_update_post(array(
247
  'ID' => $feedId,
248
  'post_title' => wprss_feed_source_name_from_url($url),
249
  'post_status' => 'publish',
250
+ 'meta_input' => array(
251
  'wprss_url' => $url,
252
  'wprss_limit' => WPRSS_INTRO_FEED_LIMIT
253
+ )
254
+ ));
255
 
256
  // Re-import the items for this feed
257
  wprss_delete_feed_items($feedId);
274
  function wprss_create_feed_source_with_url($url)
275
  {
276
  $name = wprss_feed_source_name_from_url($url);
277
+ $result = wprss_import_feed_sources_array(array($url => $name));
278
 
279
  if (empty($result)) {
280
  throw new Exception(
281
+ sprintf(__('Failed to import the feed source "%s" with URL "%s"', WPRSS_TEXT_DOMAIN), $name, $url)
282
  );
283
  }
284
 
303
  function wprss_import_feed_sources_array($array)
304
  {
305
  /* @var $importer Aventura\Wprss\Core\Component\BulkSourceImport */
306
+ $importer = wprss_wp_container()->get(\WPRSS_SERVICE_ID_PREFIX . 'array_source_importer');
307
 
308
  return $importer->import($array);
309
  }
330
  }
331
 
332
  $name = parse_url($url, PHP_URL_HOST);
333
+ $name = ($name === null) ? $url : $name;
334
 
335
+ return $name;
336
  }
337
 
338
  /**
372
  function wprss_create_shortcode_page($title = null, $status = 'draft')
373
  {
374
  $title = ($title === null)
375
+ ? _x('Feeds', 'default name of shortcode page', WPRSS_TEXT_DOMAIN)
376
  : $title;
377
 
378
  $id = wp_insert_post(array(
447
  */
448
  function wprss_set_intro_done($done = true)
449
  {
450
+ update_option(WPRSS_INTRO_DID_INTRO_OPTION, '1', false);
451
  }
452
 
453
  /**
includes/admin-log.php CHANGED
@@ -6,15 +6,15 @@ use RebelCode\Wpra\Core\Logger\ClearableLoggerInterface;
6
  use RebelCode\Wpra\Core\Logger\FeedLoggerInterface;
7
  use RebelCode\Wpra\Core\Logger\LogReaderInterface;
8
 
9
- const WPRSS_OPTION_CODE_LOG_LEVEL = 'log_level';
10
- const WPRSS_LOG_LEVEL_SYSTEM = LogLevel::DEBUG;
11
- const WPRSS_LOG_LEVEL_INFO = LogLevel::INFO;
12
- const WPRSS_LOG_LEVEL_NOTICE = LogLevel::NOTICE;
13
- const WPRSS_LOG_LEVEL_WARNING = LogLevel::WARNING;
14
- const WPRSS_LOG_LEVEL_ERROR = LogLevel::ERROR;
15
-
16
- const WPRSS_LOG_LEVEL_NONE = WPRSS_LOG_LEVEL_INFO;
17
- const WPRSS_LOG_LEVEL_DEFAULT = WPRSS_LOG_LEVEL_NONE;
18
 
19
  /**
20
  * Returns the logger.
6
  use RebelCode\Wpra\Core\Logger\FeedLoggerInterface;
7
  use RebelCode\Wpra\Core\Logger\LogReaderInterface;
8
 
9
+ define('WPRSS_OPTION_CODE_LOG_LEVEL', 'log_level');
10
+ define('WPRSS_LOG_LEVEL_SYSTEM', LogLevel::DEBUG);
11
+ define('WPRSS_LOG_LEVEL_INFO', LogLevel::INFO);
12
+ define('WPRSS_LOG_LEVEL_NOTICE', LogLevel::NOTICE);
13
+ define('WPRSS_LOG_LEVEL_WARNING', LogLevel::WARNING);
14
+ define('WPRSS_LOG_LEVEL_ERROR', LogLevel::ERROR);
15
+
16
+ define('WPRSS_LOG_LEVEL_NONE', WPRSS_LOG_LEVEL_INFO);
17
+ define('WPRSS_LOG_LEVEL_DEFAULT', WPRSS_LOG_LEVEL_NONE);
18
 
19
  /**
20
  * Returns the logger.
includes/admin-metaboxes.php CHANGED
@@ -1,855 +1,771 @@
1
  <?php
2
 
3
- add_action('add_meta_boxes', function () {
4
- // Remove some plugin's meta boxes because they're not relevant to the wprss_feed post type.
5
- $post_type = 'wprss_feed';
6
- remove_meta_box('wpseo_meta', $post_type, 'normal'); // WP SEO Yoast
7
- remove_meta_box('ta-reviews-post-meta-box', $post_type, 'normal'); // Author hReview
8
- remove_meta_box('wpdf_editor_section', $post_type, 'advanced'); // ImageInject
9
-
10
- // Remove the default WordPress Publish box, because we will be using custom ones
11
- remove_meta_box('submitdiv', 'wprss_feed', 'side');
12
- // Custom Publish box
13
- add_meta_box(
14
- 'submitdiv',
15
- __('Save Feed Source', 'wprss'),
16
- 'post_submit_meta_box',
17
- 'wprss_feed',
18
- 'side',
19
- 'high'
20
- );
21
- });
22
-
23
- /**
24
- * Set up the input boxes for the wprss_feed post type
25
- *
26
- * @since 2.0
27
- */
28
- add_action('add_meta_boxes', function () {
29
- global $wprss_meta_fields;
30
-
31
- add_meta_box(
32
- 'preview_meta_box',
33
- __('Feed Preview', 'wprss'),
34
- 'wprss_preview_meta_box_callback',
35
- 'wprss_feed',
36
- 'side',
37
- 'high'
38
- );
39
-
40
- add_meta_box(
41
- 'wprss-feed-processing-meta',
42
- __('Feed Processing', 'wprss'),
43
- 'wprss_feed_processing_meta_box_callback',
44
- 'wprss_feed',
45
- 'side',
46
- 'high'
47
- );
48
-
49
- if (!defined('WPRSS_FTP_VERSION') && !defined('WPRSS_ET_VERSION') && !defined('WPRSS_C_VERSION')) {
50
  add_meta_box(
51
- 'wprss-like-meta',
52
- __('Share The Love', 'wprss'),
53
- 'wprss_like_meta_box_callback',
54
  'wprss_feed',
55
  'side',
56
- 'low'
57
  );
58
- }
59
 
60
- add_meta_box(
61
- 'custom_meta_box',
62
- __('Feed Source Details', 'wprss'),
63
- 'wprss_show_meta_box_callback',
64
- 'wprss_feed',
65
- 'normal',
66
- 'high'
67
- );
68
- }, 99);
69
-
70
- /**
71
- * Set up fields for the meta box for the wprss_feed post type
72
- *
73
- * @since 2.0
74
- */
75
- function wprss_get_custom_fields()
76
- {
77
- $prefix = 'wprss_';
78
-
79
- // Field Array
80
- $wprss_meta_fields['url'] = [
81
- 'label' => __('URL', 'wprss'),
82
- 'id' => $prefix . 'url',
83
- 'type' => 'url',
84
- 'after' => 'wprss_after_url',
85
- 'placeholder' => 'https://',
86
- ];
87
-
88
- $wprss_meta_fields['limit'] = [
89
- 'label' => __('Limit', 'wprss'),
90
- 'id' => $prefix . 'limit',
91
- 'type' => 'number',
92
- ];
93
-
94
- $wprss_meta_fields['unique_titles'] = [
95
- 'label' => __('Unique titles only', 'wprss'),
96
- 'id' => $prefix . 'unique_titles',
97
- 'type' => 'select',
98
- 'options' => [
99
- ['value' => '', 'label' => __('Default', 'wprss')],
100
- ['value' => '1', 'label' => __('Yes', 'wprss')],
101
- ['value' => '0', 'label' => __('No', 'wprss')],
102
- ],
103
- ];
104
-
105
- $wprss_meta_fields['enclosure'] = [
106
- 'label' => __('Link to enclosure', 'wprss'),
107
- 'id' => $prefix . 'enclosure',
108
- 'type' => 'checkbox',
109
- ];
110
-
111
- if (wprss_is_et_active()) {
112
- $wprss_meta_fields['source_link'] = [
113
- 'label' => __('Link source', 'wprss'),
114
- 'id' => $prefix . 'source_link',
115
- 'type' => 'boolean_fallback',
116
- ];
117
- }
118
 
119
- $wprss_meta_fields['import_source'] = [
120
- 'label' => __('Use source info', 'wprss'),
121
- 'id' => $prefix . 'import_source',
122
- 'type' => 'checkbox',
123
- ];
124
-
125
- $wprss_meta_fields['use_guids'] = [
126
- 'label' => __('Use GUIDs', 'wprss'),
127
- 'id' => $prefix . 'use_guids',
128
- 'type' => 'checkbox',
129
- ];
130
-
131
- // for extensibility, allows more meta fields to be added
132
- return apply_filters('wprss_fields', $wprss_meta_fields);
133
- }
134
-
135
- /**
136
- * Set up the meta box for the wprss_feed post type
137
- *
138
- * @since 2.0
139
- */
140
- function wprss_show_meta_box_callback()
141
- {
142
- global $post;
143
- $meta_fields = wprss_get_custom_fields();
144
- $field_tooltip_id_prefix = 'field_';
145
- $help = WPRSS_Help::get_instance();
146
-
147
- // Use nonce for verification
148
- wp_nonce_field('wpra_feed_source', 'wprss_meta_box_nonce');
149
-
150
- // Fix for WordPress SEO JS issue
151
- echo '<input type="hidden" id="content" value="" />';
152
-
153
- // Begin form table
154
- echo '<table class="form-table wprss-form-table">';
155
-
156
- foreach ($meta_fields as $field) {
157
- $meta = get_post_meta($post->ID, $field['id'], true);
158
-
159
- // Add default placeholder value
160
- $field = wp_parse_args($field, [
161
- 'desc' => '',
162
- 'placeholder' => '',
163
- 'type' => 'text',
164
- ]);
165
-
166
- $fieldId = $field['id'];
167
- $fieldLabel = $field['label'];
168
- $fieldType = $field['type'];
169
- $fieldDesc = $field['desc'];
170
- $placeholder = isset($field['placeholder']) ? trim($field['placeholder']) : '';
171
-
172
- $tooltip = isset($field['tooltip']) ? trim($field['tooltip']) : null;
173
- $tooltip_id = isset($field['id']) ? $field_tooltip_id_prefix . $field['id'] : uniqid($field_tooltip_id_prefix);
174
-
175
- // Begin row
176
- echo '<tr>';
177
-
178
- // Label
179
- printf('<th><label for="%s">%s</label></th>', esc_attr($fieldId), esc_html($fieldLabel));
180
-
181
- // Begin field
182
- echo '<td>';
183
-
184
- if (isset($field['before']) && !empty($field['before'])) {
185
- call_user_func($field['before']);
186
- }
187
-
188
- switch ($fieldType) {
189
- // text/url
190
- case 'url':
191
- case 'text':
192
- {
193
- printf(
194
- '<input id="%1$s" type="%2$s" name="%1$s" value="%3$s" placeholder="%4$s" class="wprss-text-input />"',
195
- esc_attr($fieldId),
196
- esc_attr($fieldType),
197
- esc_attr($meta),
198
- esc_attr($placeholder)
199
- );
200
 
201
- echo $help->tooltip($tooltip_id, $tooltip);
202
- echo wprss_render_option_desc($fieldDesc, $fieldId);
203
- break;
204
- }
 
 
 
 
205
 
206
- // textarea
207
- case 'textarea':
208
- {
209
- printf(
210
- '<textarea id="%1$s" name="%1$s" cols="60" rows="4">%2$s</textarea>',
211
- esc_attr($fieldId),
212
- esc_textarea($meta)
213
- );
 
 
214
 
215
- echo $help->tooltip($tooltip_id, $tooltip);
216
- echo wprss_render_option_desc($fieldDesc, $fieldId);
217
- break;
218
- }
 
 
 
 
219
 
220
- // checkbox
221
- case 'checkbox2':
222
- case 'checkbox':
223
- {
224
- $trueValue = $fieldType === 'checkbox' ? 'true' : '1';
225
- $falseValue = $fieldType === 'checkbox' ? 'false' : '0';
226
-
227
- printf('<input type="hidden" name="%s" value="%s" />', esc_attr($fieldId), esc_attr($falseValue));
228
- printf(
229
- '<input type="checkbox" name="%1$s" id="%1$s" value="%2$s" %3$s />',
230
- esc_attr($fieldId),
231
- esc_attr($trueValue),
232
- checked($meta, $trueValue, false)
233
- );
234
 
235
- echo $help->tooltip($tooltip_id, $tooltip);
236
- echo wprss_render_option_desc($fieldDesc, $fieldId);
237
- break;
238
- }
239
 
240
- // select
241
- case 'select':
242
- printf('<select name="%1$s" id="%1$s">', esc_attr($fieldId));
243
-
244
- foreach ($field['options'] as $option) {
245
- printf(
246
- '<option %1$s value="%2$s">%3$s</option>',
247
- selected($option['value'], $meta, false),
248
- esc_attr($option['value']),
249
- esc_html($option['label'])
250
- );
251
- }
252
 
253
- echo '</select>';
254
 
255
- echo $help->tooltip($tooltip_id, $tooltip);
256
- echo wprss_render_option_desc($fieldDesc, $fieldId);
257
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- // A select with "On" and "Off" values, and a special option to fall back to General setting
260
- case 'boolean_fallback':
261
- {
262
- $options = wprss_settings_get_feed_source_boolean_options();
263
- if ($meta === '') {
264
- $meta = -1;
265
- }
266
- echo wprss_settings_render_select($field['id'], $field['id'], $options, $meta);
267
- echo $help->tooltip($tooltip_id, $tooltip);
268
- break;
269
- }
270
 
271
- // number
272
- case 'number':
273
- {
274
- printf(
275
- '<input id="%1$s" name="%1$s" class="wprss-number-roller" type="number" min="0" value="%2$s" placeholder="%3$s" />',
276
- esc_attr($fieldId),
277
- esc_attr($meta),
278
- __('Default', 'wprss')
279
- );
 
280
 
281
- echo $help->tooltip($tooltip_id, $tooltip);
282
- echo wprss_render_option_desc($fieldDesc, $fieldId);
283
- break;
284
- }
285
- }
286
 
287
- if (isset($field['after']) && !empty($field['after'])) {
288
- call_user_func($field['after']);
 
 
 
 
289
  }
290
 
291
- // End field
292
- echo '</td>';
 
 
 
293
 
294
- // End row
295
- echo '</tr>';
296
  }
297
 
298
- echo '</table>';
299
- }
300
 
301
- /** @deprecated There shouldn't be any options that still use a description. All help text was moved to tooltips. */
302
- function wprss_render_option_desc($desc, $id)
303
- {
304
- if (strlen($desc) === 0) {
305
- return '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  }
307
 
308
- ob_start();
309
- ?>
310
- <br />
311
- <label for="<?= esc_attr($id) ?>">
312
- <span class="description">
313
- <?= esc_html($desc) ?>
314
- </span>
315
- </label>
316
- <?php
317
- return ob_get_clean();
318
- }
319
-
320
- /**
321
- * Renders content after the URL field
322
- *
323
- * @since 3.9.5
324
- */
325
- function wprss_after_url()
326
- {
327
- ?>
328
- <i
329
- id="wprss-url-spinner"
330
- class="fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon"
331
- title="<?= __('Updating feed source', 'wprss') ?>">
332
- </i>
333
-
334
- <div id="wprss-url-error" style="color:red"></div>
335
-
336
- <a href="#" id="validate-feed-link" class="wprss-after-url-link">
337
- Validate feed
338
- </a>
339
-
340
- <span> | </span>
341
-
342
- <a
343
- href="https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed"
344
- class="wprss-after-url-link"
345
- target="_blank"
346
- >
347
- <?= __('How to find an RSS feed', 'wprss') ?>
348
- </a>
349
-
350
- <script type="text/javascript">
351
- (function ($) {
352
- // When the DOM is ready
353
- $(document).ready(function () {
354
- // Move the link immediately after the url text field, and add the click event handler
355
- $('#validate-feed-link').on('click', function (e) {
356
- // Get the url and proceed only if the url is not empty
357
- var url = $('#wprss_url').val();
358
- if (url.trim().length > 0) {
359
- // Encode the url and generate the full url to the w3 feed validator
360
- var encodedUrl = encodeURIComponent(url);
361
- var fullURL = 'https://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
362
- // Open the window / tab
363
- window.open(fullURL, 'wprss-feed-validator');
364
- }
365
- // Suppress the default link click behaviour
366
- e.preventDefault();
367
- e.stopPropagation();
368
- return false;
369
- });
370
- });
371
- })(jQuery);
372
- </script>
373
- <?php
374
- }
375
-
376
- /**
377
- * Save the custom fields
378
- *
379
- * @since 2.0
380
- */
381
- add_action('save_post', function ($post_id, $post) {
382
- $meta_fields = wprss_get_custom_fields();
383
-
384
- /* Verify the nonce before proceeding. */
385
- if (!isset($_POST['wprss_meta_box_nonce']) ||
386
- !wp_verify_nonce($_POST['wprss_meta_box_nonce'], 'wpra_feed_source')) {
387
- return;
388
- }
389
-
390
- /* Get the post type object. */
391
- $post_type = get_post_type_object($post->post_type);
392
 
393
- /* Check if the current user has permission to edit the post. */
394
- if (!current_user_can($post_type->cap->edit_post, $post_id)) {
395
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  }
397
 
398
- /** Bail out if running an autosave, ajax or a cron */
399
- if (
400
- (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) ||
401
- (defined('DOING_AJAX') && DOING_AJAX) ||
402
- (defined('DOING_CRON') && DOING_CRON)
403
- ) {
404
- return;
405
- }
406
 
407
- $postType = class_exists('WPRSS_FTP_Meta')
408
- ? WPRSS_FTP_Meta::get_instance()->get($post_id, 'post_type')
409
- : 'wprss_feed_item';
410
 
411
- if ($postType === 'wprss_feed_item' && isset($_POST['wpra_feed_def_ft_image'])) {
412
- $def_ft_image_id = $_POST['wpra_feed_def_ft_image'];
 
 
 
 
 
 
413
 
414
- if (empty($def_ft_image_id)) {
415
- // Does not actually delete the image
416
- delete_post_thumbnail($post_id);
417
- } else {
418
- set_post_thumbnail($post_id, $def_ft_image_id);
419
  }
420
- }
421
-
422
- // Change the limit, if it is zero, to an empty string
423
- if (isset($_POST['wprss_limit']) && strval($_POST['wprss_limit']) == '0') {
424
- $_POST['wprss_limit'] = '';
425
- }
426
 
427
- // loop through fields and save the data
428
- foreach ($meta_fields as $field) {
429
- $old = get_post_meta($post_id, $field['id'], true);
430
- $new = trim($_POST[$field['id']]);
431
- if ($new !== $old || empty($old)) {
432
- update_post_meta($post_id, $field['id'], $new);
433
- } elseif (empty($new) && !empty($old)) {
434
- delete_post_meta($post_id, $field['id'], $old);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  }
436
- } // end foreach
437
-
438
- $force_feed = filter_input(INPUT_POST, 'wprss_force_feed', FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false';
439
-
440
- $state = filter_input(INPUT_POST, 'wprss_state', FILTER_SANITIZE_STRING);
441
- $state = strtolower(trim($state)) === 'paused' ? 'paused' : 'active';
442
-
443
- $activate = filter_input(INPUT_POST, 'wprss_activate_feed', FILTER_SANITIZE_STRING);
444
- $activate = $activate ? : '';
445
-
446
- $pause = filter_input(INPUT_POST, 'wprss_pause_feed', FILTER_SANITIZE_STRING);
447
- $pause = $pause ? : '';
448
-
449
- $age_limit = filter_input(INPUT_POST, 'wprss_age_limit', FILTER_VALIDATE_INT);
450
- $age_limit = (is_int($age_limit) && $age_limit > 0) ? (string) $age_limit : '';
451
 
452
- $age_unit = filter_input(INPUT_POST, 'wprss_age_unit', FILTER_SANITIZE_STRING);
453
- $age_unit = $age_unit ? strtolower($age_unit) : '';
454
- $age_unit = in_array($age_unit, wprss_age_limit_units()) ? $age_unit : '';
 
455
 
456
- $update_interval = filter_input(INPUT_POST, 'wprss_update_interval', FILTER_SANITIZE_STRING);
457
- $update_interval = $update_interval ? $update_interval : wprss_get_default_feed_source_update_interval();
458
- $old_update_interval = get_post_meta($post_id, 'wprss_update_interval', true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
- // Update the feed source meta
461
- update_post_meta($post_id, 'wprss_force_feed', $force_feed);
462
- update_post_meta($post_id, 'wprss_activate_feed', $activate);
463
- update_post_meta($post_id, 'wprss_pause_feed', $pause);
464
- update_post_meta($post_id, 'wprss_age_limit', $age_limit);
465
- update_post_meta($post_id, 'wprss_age_unit', $age_unit);
466
- update_post_meta($post_id, 'wprss_update_interval', $update_interval);
467
 
468
- // Check if the state or the update interval has changed
469
- if (get_post_meta($post_id, 'wprss_state', true) !== $state || $old_update_interval !== $update_interval) {
470
- // Pause the feed source, and if it is active, re-activate it.
471
- // This should update the feed's scheduling
472
- wprss_pause_feed_source($post_id);
473
- if ($state === 'active') {
474
- wprss_activate_feed_source($post_id);
475
  }
476
  }
477
 
478
- // Update the schedules
479
- wprss_update_feed_processing_schedules($post_id);
480
 
481
- // If the feed source uses the global updating system, update the feed on publish
482
- if ($update_interval === wprss_get_default_feed_source_update_interval()) {
483
- wp_schedule_single_event(time(), 'wprss_fetch_single_feed_hook', [$post_id]);
484
- }
485
- }, 10, 2);
486
-
487
- /**
488
- * Generate a preview of the latest 5 posts from the feed source being added/edited
489
- *
490
- * @since 2.0
491
- */
492
- function wprss_preview_meta_box_callback()
493
- {
494
- global $post;
495
- $feed_url = get_post_meta($post->ID, 'wprss_url', true);
496
-
497
- echo '<div id="feed-preview-container">';
498
-
499
- if (empty($feed_url)) {
500
- echo '<p>' . __('No feed URL defined yet', 'wprss') . '</p>';
501
- } else {
502
- $feed = wprss_fetch_feed($feed_url, $post->ID);
503
-
504
- // Check if failed to fetch the feed
505
- if (is_wp_error($feed)) {
506
- // Log the error
507
- wprss_log_obj('Failed to preview feed.', $feed->get_error_message(), null, WPRSS_LOG_LEVEL_INFO);
508
- printf(
509
- '<span class="invalid-feed-url">%s</span>',
510
- __('<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', 'wprss')
511
- );
512
-
513
- echo wpautop(
514
- sprintf(
515
- __(
516
- 'Not sure where to find the RSS feed on a website? <a target="_blank" href="%1$s">Click here</a> for a visual guide.',
517
- 'wprss'
518
- ),
519
- 'https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed'
520
- )
521
- );
522
- } else {
523
- ob_start();
524
- // Figure out how many total items there are
525
- $total = @$feed->get_item_quantity();
526
- // Get the number of items again, but limit it to 5.
527
- $maxItems = $feed->get_item_quantity(5);
528
-
529
- // Build an array of all the items, starting with element 0 (first element).
530
- $items = $feed->get_items(0, $maxItems);
531
- ob_clean();
532
- ?>
533
- <h4>
534
- <?php
535
- printf(
536
- __('Latest %1$s feed items out of %2$s available from %3$s'),
537
- $maxItems,
538
- $total,
539
- get_the_title()
540
- )
541
  ?>
542
- </h4>
543
- <ul>
544
- <?php
545
- foreach ($items as $item) {
546
- $date = $item->get_date('U');
547
- $has_date = !!$date;
548
-
549
- // Get human readable date
550
- $item_date = ($has_date)
551
- ? human_time_diff($date, current_time('timestamp')) . ' ' . __('ago', 'wprss')
552
- : sprintf('<em>[%s]</em>', esc_html(__('No Date', 'wprss')));
553
-
554
- printf(
555
- '<li>%s<div class="rss-date"><small>%s</small></div></li>',
556
- esc_html($item->get_title()),
557
- $item_date
558
- );
 
 
 
 
 
 
 
 
559
  }
560
  ?>
561
- </ul>
562
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
  }
564
- }
 
 
 
565
 
566
- echo '</div>';
567
- echo '<div id="force-feed-container">';
568
-
569
- wprss_render_force_feed_option($post->ID, true);
570
-
571
- echo '</div>';
572
- }
573
-
574
- /**
575
- * Renders the Force Feed option for the Feed Preview.
576
- *
577
- * @since 4.6.12
578
- *
579
- * @param bool $echo (Optional) If set to true, the function will immediately echo the option,
580
- * rather than return a string of the option's markup. Default: False.
581
- * @param int|string $feed_source_id (Optional) The ID of the feed source for the option will be rendered. If not given
582
- * or its value is null, the option will not be checked.
583
- *
584
- * @return string|null A string containing the HTML for the rendered option if $echo is set to false,
585
- * or null if $echo is set to true.
586
- */
587
- function wprss_render_force_feed_option($feed_source_id = null, $echo = false)
588
- {
589
- if (!$echo) {
590
- ob_start();
591
  }
592
 
593
- $force_feed = $feed_source_id !== null
594
- ? get_post_meta($feed_source_id, 'wprss_force_feed', true)
595
- : '';
596
-
597
- echo '<p>';
598
- echo '<label for="wprss-force-feed">' . __('Force the feed', 'wprss') . '</label>';
599
- echo '<input type="hidden" name="wprss_force_feed" value="false" />';
600
-
601
- printf(
602
- '<input type="checkbox" name="wprss_force_feed" id="wprss-force-feed" value="true" %s />',
603
- checked($force_feed, 'true', false)
604
- );
605
-
606
- echo WPRSS_Help::get_instance()->tooltip('field_wprss_force_feed');
607
- echo '</p>';
608
-
609
- return $echo ? null : ob_get_clean();
610
- }
611
-
612
- /**
613
- * Renders the Feed Processing metabox
614
- *
615
- * @since 3.7
616
- */
617
- function wprss_feed_processing_meta_box_callback()
618
- {
619
- global $post;
620
-
621
- // Get the post meta
622
- $state = get_post_meta($post->ID, 'wprss_state', true);
623
- $activate = get_post_meta($post->ID, 'wprss_activate_feed', true);
624
- $pause = get_post_meta($post->ID, 'wprss_pause_feed', true);
625
- $update_interval = get_post_meta($post->ID, 'wprss_update_interval', true);
626
- $update_time = get_post_meta($post->ID, 'wprss_update_time', true);
627
-
628
- $age_limit = get_post_meta($post->ID, 'wprss_age_limit', true);
629
- $age_unit = get_post_meta($post->ID, 'wprss_age_unit', true);
630
-
631
- // Set default strings for activate and pause times
632
- $default_activate = 'immediately';
633
- $default_pause = 'never';
634
-
635
- // Prepare the states
636
- $states = [
637
- 'active' => __('Active', 'wprss'),
638
- 'paused' => __('Paused', 'wprss'),
639
- ];
640
-
641
- // Prepare the schedules
642
- $default_interval = __('Default', 'wprss');
643
- $wprss_schedules = apply_filters('wprss_schedules', wprss_get_schedules());
644
- $default_interval_key = wprss_get_default_feed_source_update_interval();
645
- $schedules = array_merge(
646
- [
647
- $default_interval_key => [
648
- 'display' => $default_interval,
649
- 'interval' => $default_interval,
650
- ],
651
- ],
652
- $wprss_schedules
653
- );
654
-
655
- // Inline help
656
- $help = WPRSS_Help::get_instance();
657
- $help_options = [
658
- 'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-side',
659
- ];
660
-
661
- ?>
662
-
663
- <div class="wprss-meta-side-setting">
664
- <label for="wprss_state">Feed state:</label>
665
- <select id="wprss_state" name="wprss_state">
666
- <?php foreach ($states as $value => $label) : ?>
667
- <option value="<?= esc_attr($value) ?>" <?php selected($state, $value) ?> >
668
- <?= esc_html($label) ?>
669
- </option>
670
- <?php endforeach; ?>
671
- </select>
672
- <?= $help->tooltip('field_wprss_state', null, $help_options) ?>
673
- </div>
674
-
675
- <div class="wprss-meta-side-setting">
676
  <p>
677
- <label for="">Activate feed: </label>
678
- <strong id="wprss-activate-feed-viewer">
679
- <?= empty($activate) ? $default_activate : esc_attr($activate) ?>
680
- </strong>
681
- <a href="#">Edit</a>
682
- <?= $help->tooltip('field_wprss_activate_feed', null, $help_options) ?>
683
  </p>
684
- <div
685
- class="wprss-meta-slider"
686
- data-collapse-viewer="wprss-activate-feed-viewer"
687
- data-default-value="<?php echo $default_activate; ?>">
688
- <input
689
- id="wprss_activate_feed"
690
- class="wprss-datetimepicker-from-today"
691
- name="wprss_activate_feed"
692
- value="<?= esc_attr($activate) ?>"
693
- />
694
- <span class="description">
695
- Current UTC time is:
696
- <br />
697
- <code>
698
- <?= date('d/m/Y H:i:s', current_time('timestamp', 1)) ?>
699
- </code>
700
- </span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  </div>
702
- </div>
703
 
704
- <div class="wprss-meta-side-setting">
705
- <p>
706
- <label for="">Pause feed: </label>
707
- <strong id="wprss-pause-feed-viewer">
708
- <?= empty($pause) ? $default_pause : $pause ?>
709
- </strong>
710
- <a href="#">Edit</a>
711
- <?= $help->tooltip('field_wprss_pause_feed', null, $help_options) ?>
712
- </p>
713
- <div
714
- class="wprss-meta-slider"
715
- data-collapse-viewer="wprss-pause-feed-viewer"
716
- data-default-value="<?= esc_attr($default_pause) ?>">
717
- <input
718
- id="wprss_pause_feed"
719
- class="wprss-datetimepicker-from-today"
720
- name="wprss_pause_feed"
721
- value="<?= esc_attr($pause) ?>"
722
- />
723
- <span class="description">
724
- Current UTC time is:
725
- <br />
726
- <code>
727
- <?= date('d/m/Y H:i:s', current_time('timestamp', 1)) ?>
728
- </code>
729
- </span>
730
  </div>
731
- </div>
732
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
 
734
- <div class="wprss-meta-side-setting">
735
- <p>
736
- <label for="">Update interval: </label>
737
- <strong id="wprss-feed-update-interval-viewer">
738
- <?php
739
- if ($update_interval === '' || $update_interval === wprss_get_default_feed_source_update_interval()) {
740
- echo $default_interval;
741
- } else {
742
- echo wprss_interval($schedules[$update_interval]['interval']);
743
- }
744
- ?>
745
- </strong>
746
- <a href="#">Edit</a>
747
- <?= $help->tooltip('field_wprss_update_interval', null, $help_options) ?>
748
- </p>
749
- <div
750
- class="wprss-meta-slider"
751
- data-collapse-viewer="wprss-feed-update-interval-viewer"
752
- data-default-value="<?= esc_attr($default_interval) ?>">
753
- <select id="feed-update-interval" name="wprss_update_interval">
754
- <?php foreach ($schedules as $value => $schedule) : ?>
755
  <?php
756
- $text = ($value === wprss_get_default_feed_source_update_interval())
757
- ? $default_interval
758
- : wprss_interval($schedule['interval']);
 
 
 
759
  ?>
760
- <option value="<?= esc_attr($value) ?>" <?php selected($update_interval, $value) ?>>
761
- <?= esc_html($text) ?>
762
- </option>
 
 
 
 
 
 
763
  <?php endforeach; ?>
764
- </select>
765
- <label>
766
- <input type="time" name="wpra_feed[update_time]" value="<?= esc_attr($update_time) ?>">
767
- </label>
 
768
  </div>
769
- </div>
770
 
771
 
772
- <div class="wprss-meta-side-setting">
773
- <p>
774
- <label id="wprss-age-limit-feed-label" for="" data-when-empty="Limit items by age:">
775
- <?= __('Limit items by age:', 'wprss'); ?>
776
- </label>
777
- <strong id="wprss-age-limit-feed-viewer">
778
- <?= __('Default', 'wprss'); ?>
779
- </strong>
780
- <a href="#">Edit</a>
781
- <?php echo $help->tooltip('field_wprss_age_limit', null, $help_options) ?>
782
- </p>
783
- <div
784
- class="wprss-meta-slider"
785
- data-collapse-viewer="wprss-age-limit-feed-viewer"
786
- data-label="#wprss-age-limit-feed-label"
787
- data-default-value=""
788
- data-empty-controller="#limit-feed-items-age"
789
- data-hybrid="#limit-feed-items-age, #limit-feed-items-age-unit">
790
- <input
791
- id="limit-feed-items-age"
792
- name="wprss_age_limit"
793
- type="number"
794
- min="0"
795
- class="wprss-number-roller"
796
- placeholder="No limit"
797
- value="<?= esc_attr($age_limit) ?>" />
798
-
799
- <select id="limit-feed-items-age-unit" name="wprss_age_unit">
800
- <?php foreach (wprss_age_limit_units() as $unit) : ?>
801
- <option value="<?= esc_attr($unit) ?>" <?php selected($age_unit, $unit) ?> >
802
- <?= esc_html($unit) ?>
803
- </option>
804
  <?php endforeach; ?>
805
- </select>
 
806
  </div>
807
- </div>
808
-
809
-
810
- <?php
811
- }
812
-
813
- /**
814
- * Generate Like this plugin meta box
815
- *
816
- * @since 2.0
817
- *
818
- */
819
- function wprss_like_meta_box_callback()
820
- {
821
- printf(
822
- '<ul><li><a href="%s" target="_blank">%s</a></li></ul>',
823
- 'https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?rate=5#postform',
824
- __('Give it a 5 star rating on WordPress.org', 'wprss')
825
- );
826
-
827
- do_action('wpra_share_the_love_metabox');
828
- }
829
-
830
- /**
831
- * Remove meta boxes from add feed source screen that tend to appear for all post types.
832
- *
833
- * @since 2.0
834
- */
835
- add_action('add_meta_boxes', function () {
836
- if ('wprss_feed' !== get_current_screen()->id) {
837
- return;
 
 
 
 
 
 
 
 
838
  }
839
 
840
- //remove_meta_box( 'wpseo_meta', 'wprss_feed' ,'normal' );
841
- remove_meta_box('postpsp', 'wprss_feed', 'normal');
842
- remove_meta_box('su_postmeta', 'wprss_feed', 'normal');
843
- remove_meta_box('woothemes-settings', 'wprss_feed', 'normal');
844
- remove_meta_box('wpcf-post-relationship', 'wprss_feed', 'normal');
845
- remove_meta_box('wpar_plugin_meta_box ', 'wprss_feed', 'normal');
846
- remove_meta_box('sharing_meta', 'wprss_feed', 'advanced');
847
- remove_meta_box('content-permissions-meta-box', 'wprss_feed', 'advanced');
848
- remove_meta_box('theme-layouts-post-meta-box', 'wprss_feed', 'side');
849
- remove_meta_box('post-stylesheets', 'wprss_feed', 'side');
850
- remove_meta_box('hybrid-core-post-template', 'wprss_feed', 'side');
851
- remove_meta_box('wpcf-marketing', 'wprss_feed', 'side');
852
- remove_meta_box('trackbacksdiv22', 'wprss_feed', 'advanced');
853
- remove_meta_box('aiosp', 'wprss_feed', 'advanced');
854
- remove_action('post_submitbox_start', 'fpp_post_submitbox_start_action');
855
- }, 100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
+ add_action( 'add_meta_boxes', function () {
4
+ // Remove some plugin's metaboxes because they're not relevant to the wprss_feed post type.
5
+ wprss_remove_unrelated_meta_boxes();
6
+
7
+ // Remove the default WordPress Publish box, because we will be using custom ones
8
+ remove_meta_box( 'submitdiv', 'wprss_feed', 'side' );
9
+ // Custom Publish box
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  add_meta_box(
11
+ 'submitdiv',
12
+ __( 'Save Feed Source', WPRSS_TEXT_DOMAIN ),
13
+ 'post_submit_meta_box',
14
  'wprss_feed',
15
  'side',
16
+ 'high'
17
  );
18
+ });
19
 
20
+ add_action( 'add_meta_boxes', 'wprss_add_meta_boxes', 99);
21
+ /**
22
+ * Set up the input boxes for the wprss_feed post type
23
+ *
24
+ * @since 2.0
25
+ */
26
+ function wprss_add_meta_boxes() {
27
+ global $wprss_meta_fields;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ add_meta_box(
30
+ 'preview_meta_box',
31
+ __( 'Feed Preview', WPRSS_TEXT_DOMAIN ),
32
+ 'wprss_preview_meta_box_callback',
33
+ 'wprss_feed',
34
+ 'side',
35
+ 'high'
36
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ add_meta_box(
39
+ 'wprss-feed-processing-meta',
40
+ __( 'Feed Processing', WPRSS_TEXT_DOMAIN ),
41
+ 'wprss_feed_processing_meta_box_callback',
42
+ 'wprss_feed',
43
+ 'side',
44
+ 'high'
45
+ );
46
 
47
+ if ( !defined('WPRSS_FTP_VERSION') && !defined('WPRSS_ET_VERSION') && !defined('WPRSS_C_VERSION') ) {
48
+ add_meta_box(
49
+ 'wprss-like-meta',
50
+ __( 'Share The Love', WPRSS_TEXT_DOMAIN ),
51
+ 'wprss_like_meta_box_callback',
52
+ 'wprss_feed',
53
+ 'side',
54
+ 'low'
55
+ );
56
+ }
57
 
58
+ add_meta_box(
59
+ 'custom_meta_box',
60
+ __( 'Feed Source Details', WPRSS_TEXT_DOMAIN ),
61
+ 'wprss_show_meta_box_callback',
62
+ 'wprss_feed',
63
+ 'normal',
64
+ 'high'
65
+ );
66
 
67
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
 
 
 
 
69
 
70
+ /**
71
+ * Removes some other plugin's metaboxes because they're not relevant to the wprss_feed post type.
72
+ *
73
+ * @since 4.7
74
+ */
75
+ function wprss_remove_unrelated_meta_boxes() {
76
+ $post_type = 'wprss_feed';
77
+ remove_meta_box( 'wpseo_meta', $post_type, 'normal'); // WP SEO Yoast
78
+ remove_meta_box( 'ta-reviews-post-meta-box', $post_type, 'normal'); // Author hReview
79
+ remove_meta_box( 'wpdf_editor_section', $post_type, 'advanced'); // ImageInject
80
+ }
 
81
 
 
82
 
83
+ /**
84
+ * Set up fields for the meta box for the wprss_feed post type
85
+ *
86
+ * @since 2.0
87
+ */
88
+ function wprss_get_custom_fields() {
89
+ $prefix = 'wprss_';
90
+
91
+ // Field Array
92
+ $wprss_meta_fields[ 'url' ] = array(
93
+ 'label' => __( 'URL', WPRSS_TEXT_DOMAIN ),
94
+ 'id' => $prefix .'url',
95
+ 'type' => 'url',
96
+ 'after' => 'wprss_after_url',
97
+ 'placeholder' => 'https://'
98
+ );
99
 
100
+ $wprss_meta_fields[ 'limit' ] = array(
101
+ 'label' => __( 'Limit', WPRSS_TEXT_DOMAIN ),
102
+ 'id' => $prefix . 'limit',
103
+ 'type' => 'number'
104
+ );
 
 
 
 
 
 
105
 
106
+ $wprss_meta_fields[ 'unique_titles' ] = array(
107
+ 'label' => __( 'Unique titles only', WPRSS_TEXT_DOMAIN ),
108
+ 'id' => $prefix . 'unique_titles',
109
+ 'type' => 'select',
110
+ 'options' => [
111
+ ['value' => '', 'label' => 'Default'],
112
+ ['value' => '1', 'label' => 'Yes'],
113
+ ['value' => '0', 'label' => 'No'],
114
+ ]
115
+ );
116
 
117
+ $wprss_meta_fields[ 'enclosure' ] = array(
118
+ 'label' => __( 'Link to enclosure', WPRSS_TEXT_DOMAIN ),
119
+ 'id' => $prefix . 'enclosure',
120
+ 'type' => 'checkbox'
121
+ );
122
 
123
+ if (wprss_is_et_active()) {
124
+ $wprss_meta_fields[ 'source_link' ] = array(
125
+ 'label' => __( 'Link source', WPRSS_TEXT_DOMAIN ),
126
+ 'id' => $prefix . 'source_link',
127
+ 'type' => 'boolean_fallback'
128
+ );
129
  }
130
 
131
+ $wprss_meta_fields[ 'import_source' ] = array(
132
+ 'label' => __( 'Use source info', WPRSS_TEXT_DOMAIN ),
133
+ 'id' => $prefix . 'import_source',
134
+ 'type' => 'checkbox',
135
+ );
136
 
137
+ // for extensibility, allows more meta fields to be added
138
+ return apply_filters( 'wprss_fields', $wprss_meta_fields );
139
  }
140
 
 
 
141
 
142
+ /**
143
+ * Set up the meta box for the wprss_feed post type
144
+ *
145
+ * @since 2.0
146
+ */
147
+ function wprss_show_meta_box_callback() {
148
+ global $post;
149
+ $meta_fields = wprss_get_custom_fields();
150
+ $field_tooltip_id_prefix = 'field_';
151
+ $help = WPRSS_Help::get_instance();
152
+
153
+ // Use nonce for verification
154
+ wp_nonce_field( 'wpra_feed_source', 'wprss_meta_box_nonce' );
155
+
156
+ // Fix for WordpRess SEO JS issue
157
+ ?><input type="hidden" id="content" value="" /><?php
158
+
159
+ // Begin the field table and loop
160
+ ?><table class="form-table wprss-form-table"><?php
161
+
162
+ foreach ( $meta_fields as $field ) {
163
+ // get value of this field if it exists for this post
164
+ $meta = get_post_meta( $post->ID, $field['id'], true );
165
+ // begin a table row with
166
+ ?><tr>
167
+ <th><label for="<?php echo $field['id'] ?>"><?php echo $field['label'] /* Should be already translated */ ?></label></th>
168
+ <td><?php
169
+
170
+ if ( isset( $field['before'] ) && !empty( $field['before'] ) ) {
171
+ call_user_func( $field['before'] );
172
+ }
173
+
174
+ // Add default placeholder value
175
+ $field = wp_parse_args( $field, array(
176
+ 'desc' => '',
177
+ 'placeholder' => '',
178
+ 'type' => 'text'
179
+ ) );
180
+
181
+ $tooltip = isset( $field['tooltip'] ) ? trim( $field['tooltip'] ) : null;
182
+ $tooltip_id = isset( $field['id'] ) ? $field_tooltip_id_prefix . $field['id'] : uniqid( $field_tooltip_id_prefix );
183
+
184
+ $field_description = __( $field['desc'], WPRSS_TEXT_DOMAIN );
185
+
186
+ /*
187
+ * So, here's how tooltips work here.
188
+ * Tooltip output will be attempted in any case.
189
+ * If 'tooltip' index is not defined, or is null, then
190
+ * a registered tooltip will be attempted. If that is
191
+ * not found, default value will be output. This value
192
+ * is by default an empty string, but can be altered
193
+ * by the `tooltip_not_found_handle_html` option of `WPRSS_Help`.
194
+ */
195
+
196
+ switch( $field['type'] ) {
197
+
198
+ // text/url
199
+ case 'url':
200
+ case 'text':
201
+ ?><input type="<?php echo $field['type'] ?>" name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" value="<?php echo esc_attr( $meta ) ?>" placeholder="<?php _e( $field['placeholder'], WPRSS_TEXT_DOMAIN ) ?>" class="wprss-text-input"/><?php
202
+ echo $help->tooltip( $tooltip_id, $tooltip );
203
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
204
+ ?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php _e( $field['desc'], WPRSS_TEXT_DOMAIN ) ?></span></label><?php
205
+ }
206
+ break;
207
+
208
+ // textarea
209
+ case 'textarea':
210
+ ?><textarea name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" cols="60" rows="4"><?php echo esc_attr( $meta ) ?></textarea><?php
211
+ echo $help->tooltip( $tooltip_id, $tooltip );
212
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
213
+ ?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
214
+ }
215
+ break;
216
+
217
+ // checkbox
218
+ case 'checkbox':
219
+ ?>
220
+ <input type="hidden" name="<?php echo $field['id'] ?>" value="false" />
221
+ <input type="checkbox" name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" value="true" <?php checked( $meta, 'true' ) ?> />
222
+ <?php
223
+ echo $help->tooltip( $tooltip_id, $tooltip );
224
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
225
+ ?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
226
+ }
227
+ break;
228
+
229
+ // improved checkbox
230
+ case 'checkbox2':
231
+ ?>
232
+ <input type="hidden" name="<?php echo $field['id'] ?>" value="0" />
233
+ <input type="checkbox"
234
+ id="<?php echo $field['id'] ?>"
235
+ name="<?php echo $field['id'] ?>"
236
+ value="1"
237
+ <?php checked( $meta, '1' ) ?>
238
+ />
239
+ <?php
240
+ echo $help->tooltip( $tooltip_id, $tooltip );
241
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
242
+ ?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
243
+ }
244
+ break;
245
+
246
+ // select
247
+ case 'select':
248
+ ?><select name="<?php echo $field['id'] ?>" id="<?php $field['id'] ?>"><?php
249
+ foreach ($field['options'] as $option) {
250
+ ?><option<?php if ( $meta == $option['value'] ): ?> selected="selected"<?php endif ?> value="<?php echo $option['value'] ?>"><?php echo $option['label'] ?></option><?php
251
+ }
252
+
253
+ ?></select><?php
254
+ echo $help->tooltip( $tooltip_id, $tooltip );
255
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
256
+ ?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
257
+ }
258
+ break;
259
+
260
+ // A select with "On" and "Off" values, and a special option to fall back to General setting
261
+ case 'boolean_fallback':
262
+ $options = wprss_settings_get_feed_source_boolean_options();
263
+ if ($meta === '') {
264
+ $meta = -1;
265
+ }
266
+ echo wprss_settings_render_select($field['id'], $field['id'], $options, $meta);
267
+ echo $help->tooltip( $tooltip_id, $tooltip );
268
+ break;
269
+
270
+ // number
271
+ case 'number':
272
+ ?><input class="wprss-number-roller" type="number" placeholder="<?php _e( 'Default', WPRSS_TEXT_DOMAIN ) ?>" min="0" name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" value="<?php echo esc_attr( $meta ) ?>" /><?php
273
+ echo $help->tooltip( $tooltip_id, $tooltip );
274
+ if ( strlen( trim( $field['desc'] ) ) > 0 ) {
275
+ ?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
276
+ }
277
+ break;
278
+
279
+ } //end switch
280
+
281
+ if ( isset( $field['after'] ) && !empty( $field['after'] ) ) {
282
+ call_user_func( $field['after'] );
283
+ }
284
+
285
+ ?></td></tr><?php
286
+ } // end foreach
287
+ ?></table><?php
288
  }
289
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
+ /**
292
+ * Renders content after the URL field
293
+ *
294
+ * @since 3.9.5
295
+ */
296
+ function wprss_after_url() {
297
+ ?>
298
+ <i id="wprss-url-spinner" class="fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon" title="<?php _e( 'Updating feed source', WPRSS_TEXT_DOMAIN ) ?>"></i>
299
+ <div id="wprss-url-error" style="color:red"></div>
300
+ <a href="#" id="validate-feed-link" class="wprss-after-url-link">Validate feed</a>
301
+ <span> | </span>
302
+ <a href="https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed"
303
+ class="wprss-after-url-link"
304
+ target="_blank">
305
+ <?= __('How to find an RSS feed', 'wprss') ?>
306
+ </a>
307
+ <script type="text/javascript">
308
+ <script type="text/javascript">
309
+ (function($){
310
+ // When the DOM is ready
311
+ $(document).ready( function(){
312
+ // Move the link immediately after the url text field, and add the click event handler
313
+ $('#validate-feed-link').click(function(e){
314
+ // Get the url and proceed only if the url is not empty
315
+ var url = $('#wprss_url').val();
316
+ if ( url.trim().length > 0 ) {
317
+ // Encode the url and generate the full url to the w3 feed validator
318
+ var encodedUrl = encodeURIComponent( url );
319
+ var fullURL = 'https://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
320
+ // Open the window / tab
321
+ window.open( fullURL, 'wprss-feed-validator' );
322
+ }
323
+ // Suppress the default link click behaviour
324
+ e.preventDefault();
325
+ e.stopPropagation();
326
+ return false;
327
+ });
328
+ });
329
+ })(jQuery);
330
+ </script>
331
+ <?php
332
  }
333
 
 
 
 
 
 
 
 
 
334
 
 
 
 
335
 
336
+ add_action( 'save_post', 'wprss_save_custom_fields', 10, 2 );
337
+ /**
338
+ * Save the custom fields
339
+ *
340
+ * @since 2.0
341
+ */
342
+ function wprss_save_custom_fields( $post_id, $post ) {
343
+ $meta_fields = wprss_get_custom_fields();
344
 
345
+ /* Verify the nonce before proceeding. */
346
+ if ( !isset( $_POST['wprss_meta_box_nonce'] ) ||
347
+ !wp_verify_nonce( $_POST['wprss_meta_box_nonce'], 'wpra_feed_source' ) ) {
348
+ return $post_id;
 
349
  }
 
 
 
 
 
 
350
 
351
+ /* Get the post type object. */
352
+ $post_type = get_post_type_object( $post->post_type );
353
+
354
+ /* Check if the current user has permission to edit the post. */
355
+ if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
356
+ return $post_id;
357
+
358
+ /* // Stop WP from clearing custom fields on autosave - maybe not needed
359
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
360
+ return;
361
+
362
+ // Prevent quick edit from clearing custom fields - maybe not needed
363
+ if (defined('DOING_AJAX') && DOING_AJAX)
364
+ return; */
365
+
366
+ /** Bail out if running an autosave, ajax or a cron */
367
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
368
+ return;
369
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
370
+ return;
371
+ if ( defined( 'DOING_CRON' ) && DOING_CRON )
372
+ return;
373
+
374
+ $postType = class_exists('WPRSS_FTP_Meta')
375
+ ? WPRSS_FTP_Meta::get_instance()->get($post_id, 'post_type')
376
+ : 'wprss_feed_item';
377
+
378
+ if ($postType === 'wprss_feed_item' && isset($_POST['wpra_feed_def_ft_image']) ) {
379
+ $def_ft_image_id = $_POST['wpra_feed_def_ft_image'];
380
+
381
+ if (empty($def_ft_image_id)) {
382
+ // Does not actually delete the image
383
+ delete_post_thumbnail( $post_id );
384
+ } else {
385
+ set_post_thumbnail( $post_id, $def_ft_image_id );
386
+ }
387
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
+ // Change the limit, if it is zero, to an empty string
390
+ if ( isset( $_POST['wprss_limit'] ) && strval( $_POST['wprss_limit'] ) == '0' ) {
391
+ $_POST['wprss_limit'] = '';
392
+ }
393
 
394
+ // loop through fields and save the data
395
+ foreach ( $meta_fields as $field ) {
396
+ $old = get_post_meta( $post_id, $field[ 'id' ], true );
397
+ $new = trim( $_POST[ $field[ 'id' ] ] );
398
+ if ( $new !== $old || empty($old) ) {
399
+ update_post_meta( $post_id, $field[ 'id' ], $new );
400
+ } elseif ( empty($new) && !empty($old) ) {
401
+ delete_post_meta( $post_id, $field[ 'id' ], $old );
402
+ }
403
+ } // end foreach
404
+
405
+ $force_feed = ( isset( $_POST['wprss_force_feed'] ) )? $_POST['wprss_force_feed'] : 'false';
406
+ $state = ( isset( $_POST['wprss_state'] ) )? $_POST['wprss_state'] : 'active';
407
+ $activate = ( isset( $_POST['wprss_activate_feed'] ) )? stripslashes( $_POST['wprss_activate_feed'] ) : '';
408
+ $pause = ( isset( $_POST['wprss_pause_feed'] ) )? stripslashes( $_POST['wprss_pause_feed'] ) : '';
409
+ $age_limit = ( isset( $_POST['wprss_age_limit'] ) )? stripslashes( $_POST['wprss_age_limit'] ) : '';
410
+ $age_unit = ( isset( $_POST['wprss_age_unit'] ) )? stripslashes( $_POST['wprss_age_unit'] ) : '';
411
+ $update_interval = ( isset( $_POST['wprss_update_interval'] ) )? stripslashes( $_POST['wprss_update_interval'] ) : wprss_get_default_feed_source_update_interval();
412
+ $old_update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
413
+
414
+ // Update the feed source meta
415
+ update_post_meta( $post_id, 'wprss_force_feed', $force_feed );
416
+ update_post_meta( $post_id, 'wprss_activate_feed', $activate );
417
+ update_post_meta( $post_id, 'wprss_pause_feed', $pause );
418
+ update_post_meta( $post_id, 'wprss_age_limit', $age_limit );
419
+ update_post_meta( $post_id, 'wprss_age_unit', $age_unit );
420
+ update_post_meta( $post_id, 'wprss_update_interval', $update_interval );
421
+
422
+ // Check if the state or the update interval has changed
423
+ if ( get_post_meta( $post_id, 'wprss_state', TRUE ) !== $state || $old_update_interval !== $update_interval ) {
424
+ // Pause the feed source, and if it is active, re-activate it.
425
+ // This should update the feed's scheduling
426
+ wprss_pause_feed_source( $post_id );
427
+ if ( $state === 'active' )
428
+ wprss_activate_feed_source( $post_id );
429
+ }
430
 
431
+ // Update the schedules
432
+ wprss_update_feed_processing_schedules( $post_id );
 
 
 
 
 
433
 
434
+ // If the feed source uses the global updating system, update the feed on publish
435
+ if ( $update_interval === wprss_get_default_feed_source_update_interval() ) {
436
+ wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
 
 
 
 
437
  }
438
  }
439
 
 
 
440
 
441
+ /**
442
+ * Generate a preview of the latest 5 posts from the feed source being added/edited
443
+ *
444
+ * @since 2.0
445
+ */
446
+ function wprss_preview_meta_box_callback() {
447
+ global $post;
448
+ $feed_url = get_post_meta( $post->ID, 'wprss_url', true );
449
+
450
+ $help = WPRSS_Help::get_instance();
451
+ /* @var $help WPRSS_Help */
452
+
453
+ echo '<div id="feed-preview-container">';
454
+
455
+ if ( ! empty( $feed_url ) ) {
456
+ $feed = wprss_fetch_feed( $feed_url, $post->ID );
457
+ if ( ! is_wp_error( $feed ) ) {
458
+ ob_start();
459
+ // Figure out how many total items there are
460
+ $total = @$feed->get_item_quantity();
461
+ // Get the number of items again, but limit it to 5.
462
+ $maxitems = $feed->get_item_quantity(5);
463
+
464
+ // Build an array of all the items, starting with element 0 (first element).
465
+ $items = $feed->get_items( 0, $maxitems );
466
+ ob_clean();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  ?>
468
+ <h4><?php echo sprintf( __( 'Latest %1$s feed items out of %2$s available from %3$s' ), $maxitems, $total, get_the_title() ) ?></h4>
469
+ <ul>
470
+ <?php
471
+ foreach ( $items as $item ) {
472
+ $date = $item->get_date( 'U' );
473
+ $has_date = $date ? true : false;
474
+
475
+ // Get human date
476
+ if ( $has_date ) {
477
+ $item_date = human_time_diff( $date, current_time('timestamp')).' '.__( 'ago', 'wprss' );
478
+ } else {
479
+ $item_date = '<em>[' . __( 'No Date', WPRSS_TEXT_DOMAIN ) . ']</em>';
480
+ }
481
+
482
+ // Start displaying item content within a <li> tag
483
+ echo '<li>';
484
+ // create item link
485
+ //echo '<a href="'.esc_url( $item->get_permalink() ).'" title="'.$item_date.'">';
486
+ // Get item title
487
+ echo esc_html( $item->get_title() );
488
+ //echo '</a>';
489
+ // Display date
490
+ echo ' <div class="rss-date"><small>'.$item_date.'</small></div>';
491
+ // End <li> tag
492
+ echo '</li>';
493
  }
494
  ?>
495
+ </ul>
496
+ <?php
497
+ }
498
+ else {
499
+ ?>
500
+ <span class="invalid-feed-url">
501
+ <?php _e( '<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', WPRSS_TEXT_DOMAIN ) ?>
502
+ <?php wprss_log_obj( 'Failed to preview feed.', $feed->get_error_message(), NULL, WPRSS_LOG_LEVEL_INFO ); ?>
503
+ </span>
504
+ <?php
505
+ echo wpautop(
506
+ sprintf(
507
+ __('Not sure where to find the RSS feed on a website? <a target="_blank" href="%1$s">Click here</a> for a visual guide.', 'wprss'),
508
+ 'https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed'
509
+ )
510
+ );
511
+ }
512
+
513
  }
514
+ else {
515
+ echo '<p>' . __( 'No feed URL defined yet', WPRSS_TEXT_DOMAIN ) . '</p>';
516
+ }
517
+ echo '</div>';
518
 
519
+ echo '<div id="force-feed-container">';
520
+ wprss_render_force_feed_option( $post->ID, TRUE );
521
+ echo '</div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
  }
523
 
524
+
525
+ /**
526
+ * Renders the Force Feed option for the Feed Preview.
527
+ *
528
+ * @param int|string $feed_source_id (Optional) The ID of the feed source for the option will be rendered. If not given or
529
+ * its value is null, the option will not be checked.
530
+ * @param bool $echo (Optional) If set to true, the function will immediately echo the option,
531
+ * rather than return a string of the option's markup. Default: False.
532
+ * @return string|null A string containing the HTML for the rendered option if $echo is set to false,
533
+ * or null if $echo is set to true.
534
+ * @since 4.6.12
535
+ */
536
+ function wprss_render_force_feed_option( $feed_source_id = NULL, $echo = FALSE ) {
537
+ if ( ! $echo ) ob_start();
538
+ $force_feed = $feed_source_id === NULL ? '' : get_post_meta( $feed_source_id, 'wprss_force_feed', TRUE ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  <p>
540
+ <label for="wprss-force-feed"><?php _e('Force the feed') ?></label>
541
+ <input type="hidden" name="wprss_force_feed" value="false" />
542
+ <input type="checkbox" name="wprss_force_feed" id="wprss-force-feed" value="true" <?php echo checked( $force_feed, 'true' ); ?> />
543
+ <?php echo WPRSS_Help::get_instance()->tooltip( 'field_wprss_force_feed' ) ?>
 
 
544
  </p>
545
+ <?php
546
+ if ( ! $echo ) return ob_get_clean();
547
+ return NULL;
548
+ }
549
+
550
+
551
+ /**
552
+ * Renders the Feed Processing metabox
553
+ *
554
+ * @since 3.7
555
+ */
556
+ function wprss_feed_processing_meta_box_callback() {
557
+ global $post;
558
+ // Get the post meta
559
+ $state = get_post_meta( $post->ID, 'wprss_state', TRUE );
560
+ $activate = get_post_meta( $post->ID, 'wprss_activate_feed', TRUE );
561
+ $pause = get_post_meta( $post->ID, 'wprss_pause_feed', TRUE );
562
+ $update_interval = get_post_meta( $post->ID, 'wprss_update_interval', TRUE );
563
+ $update_time = get_post_meta( $post->ID, 'wprss_update_time', TRUE );
564
+
565
+ $age_limit = get_post_meta( $post->ID, 'wprss_age_limit', true );
566
+ $age_unit = get_post_meta( $post->ID, 'wprss_age_unit', true );
567
+
568
+ // Set default strings for activate and pause times
569
+ $default_activate = 'immediately';
570
+ $default_pause = 'never';
571
+
572
+ // Prepare the states
573
+ $states = array(
574
+ 'active' => __( 'Active', WPRSS_TEXT_DOMAIN ),
575
+ 'paused' => __( 'Paused', WPRSS_TEXT_DOMAIN ),
576
+ );
577
+
578
+ // Prepare the schedules
579
+ $default_interval = __( 'Default', WPRSS_TEXT_DOMAIN );
580
+ $wprss_schedules = apply_filters( 'wprss_schedules', wprss_get_schedules() );
581
+ $default_interval_key = wprss_get_default_feed_source_update_interval();
582
+ $schedules = array_merge(
583
+ array(
584
+ $default_interval_key => array(
585
+ 'display' => $default_interval,
586
+ 'interval' => $default_interval,
587
+ ),
588
+ ),
589
+ $wprss_schedules
590
+ );
591
+
592
+ // Inline help
593
+ $help = WPRSS_Help::get_instance();
594
+ $help_options = array('tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-side');
595
+
596
+ ?>
597
+
598
+ <div class="wprss-meta-side-setting">
599
+ <label for="wprss_state">Feed state:</label>
600
+ <select id="wprss_state" name="wprss_state">
601
+ <?php foreach( $states as $value => $label ) : ?>
602
+ <option value="<?php echo $value; ?>" <?php selected( $state, $value ) ?> ><?php echo $label; ?></option>
603
+ <?php endforeach; ?>
604
+ </select>
605
+ <?php echo $help->tooltip( 'field_wprss_state', null, $help_options ) ?>
606
  </div>
 
607
 
608
+ <div class="wprss-meta-side-setting">
609
+ <p>
610
+ <label for="">Activate feed: </label>
611
+ <strong id="wprss-activate-feed-viewer"><?php echo ( ( $activate !== '' )? $activate : $default_activate ); ?></strong>
612
+ <a href="#">Edit</a>
613
+ <?php echo $help->tooltip( 'field_wprss_activate_feed', null, $help_options ) ?>
614
+ </p>
615
+ <div class="wprss-meta-slider" data-collapse-viewer="wprss-activate-feed-viewer" data-default-value="<?php echo $default_activate; ?>">
616
+ <input id="wprss_activate_feed" class="wprss-datetimepicker-from-today" name="wprss_activate_feed" value="<?php echo $activate; ?>" />
617
+ <span class="description">
618
+ Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
619
+ </span>
620
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  </div>
 
622
 
623
+ <div class="wprss-meta-side-setting">
624
+ <p>
625
+ <label for="">Pause feed: </label>
626
+ <strong id="wprss-pause-feed-viewer"><?php echo ( ( $pause !== '' )? $pause : $default_pause ); ?></strong>
627
+ <a href="#">Edit</a>
628
+ <?php echo $help->tooltip( 'field_wprss_pause_feed', null, $help_options ) ?>
629
+ </p>
630
+ <div class="wprss-meta-slider" data-collapse-viewer="wprss-pause-feed-viewer" data-default-value="<?php echo $default_pause; ?>">
631
+ <input id="wprss_pause_feed" class="wprss-datetimepicker-from-today" name="wprss_pause_feed" value="<?php echo $pause; ?>" />
632
+ <span class="description">
633
+ Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
634
+ </span>
635
+ </div>
636
+ </div>
637
 
638
+
639
+ <div class="wprss-meta-side-setting">
640
+ <p>
641
+ <label for="">Update interval: </label>
642
+ <strong id="wprss-feed-update-interval-viewer">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  <?php
644
+ if ( $update_interval === '' || $update_interval === wprss_get_default_feed_source_update_interval() ) {
645
+ echo $default_interval;
646
+ }
647
+ else {
648
+ echo wprss_interval( $schedules[$update_interval]['interval'] );
649
+ }
650
  ?>
651
+ </strong>
652
+ <a href="#">Edit</a>
653
+ <?php echo $help->tooltip( 'field_wprss_update_interval', null, $help_options ) ?>
654
+ </p>
655
+ <div class="wprss-meta-slider" data-collapse-viewer="wprss-feed-update-interval-viewer" data-default-value="<?php echo $default_interval; ?>">
656
+ <select id="feed-update-interval" name="wprss_update_interval">
657
+ <?php foreach ( $schedules as $value => $schedule ) : ?>
658
+ <?php $text = ( $value === wprss_get_default_feed_source_update_interval() )? $default_interval : wprss_interval( $schedule['interval'] ); ?>
659
+ <option value="<?php echo $value; ?>" <?php selected( $update_interval, $value ); ?> ><?php echo $text; ?></option>
660
  <?php endforeach; ?>
661
+ </select>
662
+ <label>
663
+ <input type="time" name="wpra_feed[update_time]" value="<?php echo esc_attr($update_time); ?>">
664
+ </label>
665
+ </div>
666
  </div>
 
667
 
668
 
669
+ <div class="wprss-meta-side-setting">
670
+ <p>
671
+ <label id="wprss-age-limit-feed-label" for="" data-when-empty="Limit items by age:">
672
+ <?php _e( 'Limit items by age:', 'wprss' ); ?>
673
+ </label>
674
+ <strong id="wprss-age-limit-feed-viewer">
675
+ <?php _e( 'Default', WPRSS_TEXT_DOMAIN ); ?>
676
+ </strong>
677
+ <a href="#">Edit</a>
678
+ <?php echo $help->tooltip( 'field_wprss_age_limit', null, $help_options ) ?>
679
+ </p>
680
+ <div class="wprss-meta-slider" data-collapse-viewer="wprss-age-limit-feed-viewer" data-label="#wprss-age-limit-feed-label" data-default-value="" data-empty-controller="#limit-feed-items-age" data-hybrid="#limit-feed-items-age, #limit-feed-items-age-unit">
681
+ <input id="limit-feed-items-age" name="wprss_age_limit" type="number" min="0" class="wprss-number-roller" placeholder="No limit" value="<?php echo $age_limit; ?>" />
682
+
683
+ <select id="limit-feed-items-age-unit" name="wprss_age_unit">
684
+ <?php foreach ( wprss_age_limit_units() as $unit ) : ?>
685
+ <option value="<?php echo $unit; ?>" <?php selected( $age_unit, $unit ); ?> ><?php echo $unit; ?></option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
  <?php endforeach; ?>
687
+ </select>
688
+ </div>
689
  </div>
690
+
691
+
692
+ <?php
693
+ }
694
+
695
+
696
+
697
+ /**
698
+ * Generate Help meta box
699
+ *
700
+ * @since 2.0
701
+ *
702
+ */
703
+ function wprss_help_meta_box_callback() {
704
+ echo '<p><a href="https://www.wprssaggregator.com/documentation/">View the documentation</p>';
705
+ echo '<p><strong>';
706
+ _e( 'Need help?', WPRSS_TEXT_DOMAIN );
707
+ echo '</strong> <a target="_blank" href="https://wordpress.org/support/plugin/wp-rss-aggregator">';
708
+ _e( 'Check out the support forum', WPRSS_TEXT_DOMAIN );
709
+ echo '</a></p>';
710
+ echo '</strong> <a target="_blank" href="https://www.wprssaggregator.com/feature-requests/">';
711
+ _e( 'Suggest a new feature', WPRSS_TEXT_DOMAIN );
712
+ echo '</a></p>';
713
+ }
714
+
715
+ /**
716
+ * Generate Like this plugin meta box
717
+ *
718
+ * @since 2.0
719
+ *
720
+ */
721
+ function wprss_like_meta_box_callback()
722
+ {
723
+ ?>
724
+ <ul>
725
+ <li><a href="https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?rate=5#postform" target="_blank"><?php _e( 'Give it a 5 star rating on WordPress.org', WPRSS_TEXT_DOMAIN ) ?></a></li>
726
+ </ul>
727
+ <?php
728
+ do_action('wpra_share_the_love_metabox');
729
  }
730
 
731
+
732
+ /**
733
+ * Generate Follow us plugin meta box
734
+ *
735
+ * @since 2.0
736
+ *
737
+ */
738
+ function wprss_follow_meta_box_callback() {
739
+ ?>
740
+ <ul>
741
+ <li class="twitter"><a href="https://twitter.com/wpmayor"><?php _e( 'Follow WP Mayor on Twitter.', WPRSS_TEXT_DOMAIN ) ?></a></li>
742
+ <li class="facebook"><a href="https://www.facebook.com/wpmayor"><?php _e( 'Like WP Mayor on Facebook.', WPRSS_TEXT_DOMAIN ) ?></a></li>
743
+ </ul>
744
+ <?php }
745
+
746
+
747
+ add_action( 'add_meta_boxes', 'wprss_remove_meta_boxes', 100 );
748
+ /**
749
+ * Remove unneeded meta boxes from add feed source screen
750
+ *
751
+ * @since 2.0
752
+ */
753
+ function wprss_remove_meta_boxes() {
754
+ if ( 'wprss_feed' !== get_current_screen()->id ) return;
755
+ // Remove meta boxes of other plugins that tend to appear on all posts
756
+ //remove_meta_box( 'wpseo_meta', 'wprss_feed' ,'normal' );
757
+ remove_meta_box( 'postpsp', 'wprss_feed' ,'normal' );
758
+ remove_meta_box( 'su_postmeta', 'wprss_feed' ,'normal' );
759
+ remove_meta_box( 'woothemes-settings', 'wprss_feed' ,'normal' );
760
+ remove_meta_box( 'wpcf-post-relationship', 'wprss_feed' ,'normal' );
761
+ remove_meta_box( 'wpar_plugin_meta_box ', 'wprss_feed' ,'normal' );
762
+ remove_meta_box( 'sharing_meta', 'wprss_feed' ,'advanced' );
763
+ remove_meta_box( 'content-permissions-meta-box', 'wprss_feed' ,'advanced' );
764
+ remove_meta_box( 'theme-layouts-post-meta-box', 'wprss_feed' ,'side' );
765
+ remove_meta_box( 'post-stylesheets', 'wprss_feed' ,'side' );
766
+ remove_meta_box( 'hybrid-core-post-template', 'wprss_feed' ,'side' );
767
+ remove_meta_box( 'wpcf-marketing', 'wprss_feed' ,'side' );
768
+ remove_meta_box( 'trackbacksdiv22', 'wprss_feed' ,'advanced' );
769
+ remove_meta_box( 'aiosp', 'wprss_feed' ,'advanced' );
770
+ remove_action( 'post_submitbox_start', 'fpp_post_submitbox_start_action' );
771
+ }
includes/admin-options-legacy.php CHANGED
@@ -221,7 +221,7 @@ function wprss_setting_video_links_callback($field)
221
 
222
  printf(
223
  '<p><span class="description">%s</span></p>',
224
- esc_html(__('This will not affect already imported feed items.', 'wprss'))
225
  );
226
  }
227
 
@@ -417,8 +417,8 @@ function wprss_setting_date_format_callback($field)
417
 
418
  printf(
419
  '<p><a href="%s">%s</a></p>',
420
- esc_attr('https://codex.wordpress.org/Formatting_Date_and_Time'),
421
- esc_html(__('PHP Date Format Reference', 'wprss'))
422
  );
423
  }
424
 
221
 
222
  printf(
223
  '<p><span class="description">%s</span></p>',
224
+ __('This will not affect already imported feed items.', 'wprss')
225
  );
226
  }
227
 
417
 
418
  printf(
419
  '<p><a href="%s">%s</a></p>',
420
+ 'https://codex.wordpress.org/Formatting_Date_and_Time',
421
+ __('PHP Date Format Reference', 'wprss')
422
  );
423
  }
424
 
includes/admin-options.php CHANGED
@@ -1,1073 +1,1035 @@
1
- <?php
2
-
3
- /**
4
- * Returns the given general setting option value form the database, or the default value if it is not found.
5
- *
6
- * @since 3.7.1
7
- *
8
- * @param bool $not_empty If true, the default value will be returned if the option exists but is empty.
9
- * @param string $option_name The name of the option to get
10
- *
11
- * @return mixed
12
- */
13
- function wprss_get_general_setting($option_name, $not_empty = false)
14
- {
15
- $options = get_option('wprss_settings_general', []);
16
- $defaults = wprss_get_default_settings_general();
17
-
18
- $value = isset($options[$option_name])
19
- ? $options[$option_name]
20
- : $defaults[$option_name];
21
-
22
- return ($not_empty && empty($value))
23
- ? $defaults[$option_name]
24
- : $value;
25
- }
26
-
27
- function wprss_get_settings_tabs()
28
- {
29
- $tabs = [
30
- [
31
- 'label' => __('General', 'wprss'),
32
- 'slug' => 'general_settings',
33
- ],
34
- [
35
- 'label' => __('Custom Feed', 'wprss'),
36
- 'slug' => 'custom_feed_settings',
37
- ],
38
- ];
39
-
40
- $tabs = apply_filters('wprss_options_tabs', $tabs);
41
-
42
- $tabs[] = [
43
- 'label' => __('Advanced', 'wprss'),
44
- 'slug' => 'advanced_settings',
45
- ];
46
-
47
- if (count(wprss_get_addons()) > 0 && is_main_site()) {
48
- $tabs[] = [
49
- 'label' => __('Licenses', 'wprss'),
50
- 'slug' => 'licenses_settings',
51
- ];
52
  }
53
 
54
- return $tabs;
55
- }
56
-
57
- /**
58
- * Build the plugin settings page, used to save general settings like whether a link should be follow or no follow
59
- *
60
- * @since 1.1
61
- */
62
- function wprss_settings_page_display()
63
- {
64
- echo '<div class="wrap">';
65
- echo '<div id="wpra-settings-app"></div>';
66
- printf('<h2>%s</h2>', __('WP RSS Aggregator Settings', 'wprss'));
67
-
68
- // Any errors that happened during saving
69
- settings_errors();
70
-
71
- $active_tab = isset($_GET['tab'])
72
- ? $_GET['tab']
73
- : 'general_settings';
74
-
75
- $tabs = wprss_get_settings_tabs();
76
-
77
- echo '<h2 class="nav-tab-wrapper">';
78
- foreach ($tabs as $tab_property) {
79
- $tabSlug = $tab_property['slug'];
80
- $tabLabel = $tab_property['label'];
81
- $tabUrl = '?post_type=wprss_feed&page=wprss-aggregator-settings&tab=' . urlencode($tabSlug);
82
- $activeClass = $active_tab == $tabSlug ? 'nav-tab-active' : '';
83
-
84
- printf(
85
- '<a href="%s" class="nav-tab %s">%s</a>',
86
- $tabUrl,
87
- $activeClass,
88
- $tabLabel
89
- );
90
- }
91
- echo '</h2>';
92
 
93
- // Begin form
94
- echo '<form action="options.php" method="post">';
 
95
 
96
- switch ($active_tab) {
97
- case 'general_settings':
98
- {
99
- settings_fields('wprss_settings_general');
100
- do_settings_sections('wprss_settings_general');
101
- break;
102
- }
103
- case 'custom_feed_settings':
104
- {
105
- settings_fields('wprss_settings_custom_feed');
106
- do_settings_sections('wprss_settings_custom_feed');
107
- break;
108
- }
109
- case 'advanced_settings':
110
- {
111
- settings_fields('wprss_settings_advanced');
112
- do_settings_sections('wprss_settings_advanced');
113
- break;
114
- }
115
- case 'licenses_settings':
116
- {
117
- if (!is_main_site()) {
118
- printf(
119
- '<p><strong>%s</strong></p>',
120
- __('You do not have access to this page', 'wprss')
121
- );
122
 
123
- return;
124
- }
125
 
126
- settings_fields('wprss_settings_license_keys');
127
- do_settings_sections('wprss_settings_license_keys');
128
- break;
129
- }
130
- default:
131
- {
132
- do_action('wprss_add_settings_fields_sections', $active_tab);
133
- break;
134
- }
135
- }
136
 
137
- submit_button(__('Save Settings', 'wprss'));
138
 
139
- echo '</form>';
140
- echo '</div>';
141
- }
 
 
 
 
 
 
 
142
 
143
- function wprss_settings_fields_array()
144
- {
145
- // Define the settings per section
146
- $settings = apply_filters('wprss_settings_array', [
147
- 'import' => [
148
- 'cron-interval' => [
149
- 'label' => __('Update interval', 'wprss'),
150
- 'callback' => 'wprss_setting_cron_interval_callback',
151
- ],
152
- 'unique-titles' => [
153
- 'label' => __('Unique titles only', 'wprss'),
154
- 'callback' => 'wprss_setting_unique_titles',
155
- ],
156
- 'feed_items_import_order' => [
157
- 'label' => __('Import order', 'wprss'),
158
- 'callback' => 'wprss_setting_feed_items_import_order_callback',
159
- ],
160
- 'limit-feed-items-by-age' => [
161
- 'label' => __('Limit items by age', 'wprss'),
162
- 'callback' => 'wprss_setting_limit_feed_items_age_callback',
163
- ],
164
- 'limit-feed-items-imported' => [
165
- 'label' => __('Limit feed items stored per feed', 'wprss'),
166
- 'callback' => 'wprss_setting_limit_feed_items_imported_callback',
167
- ],
168
- 'limit-feed-items-db' => [
169
- 'label' => __('Limit feed items stored', 'wprss'),
170
- 'callback' => 'wprss_setting_limit_feed_items_callback',
171
- ],
172
- 'limit_feed_items_per_import' => [
173
- 'label' => __('Limit feed items per import', 'wprss'),
174
- 'callback' => 'wprss_setting_limit_feed_items_per_import_callback',
175
- ],
176
- 'schedule_future_items' => [
177
- 'label' => __('Schedule future items', 'wprss'),
178
- 'callback' => 'wprss_setting_schedule_future_items_callback',
179
- ],
180
- ],
181
 
182
- 'custom_feed' => [
183
- 'custom-feed-url' => [
184
- 'label' => __('Custom feed URL', 'wprss'),
185
- 'callback' => 'wprss_settings_custom_feed_url_callback',
186
- ],
187
- 'custom-feed-title' => [
188
- 'label' => __('Custom feed title', 'wprss'),
189
- 'callback' => 'wprss_settings_custom_feed_title_callback',
190
- ],
191
- 'custom-feed-limit' => [
192
- 'label' => __('Custom feed limit', 'wprss'),
193
- 'callback' => 'wprss_settings_custom_feed_limit_callback',
194
- ],
195
- ],
196
- ]);
197
 
198
- if (apply_filters('wprss_use_fixed_feed_limit', false) === false) {
199
- unset($settings['import']['limit-feed-items-db']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  }
201
 
202
- $settings['styles'] = [
203
- 'styles-disable' => [
204
- 'label' => __('Disable styles', 'wprss'),
205
- 'callback' => 'wprss_setting_styles_disable_callback',
206
- ],
207
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
- if (apply_filters('wprss_use_fixed_feed_limit', false) === false) {
210
- unset($settings['general']['limit-feed-items-db']);
211
  }
212
 
213
- return $settings;
214
- }
215
-
216
- add_action('admin_init', 'wprss_admin_init');
217
- /**
218
- * Register and define options and settings
219
- *
220
- * @since 2.0
221
- *
222
- * Note: In the future might change to
223
- * the way EDD builds the settings pages, cleaner method.
224
- */
225
- function wprss_admin_init()
226
- {
227
- $fields = wprss_settings_fields_array();
228
-
229
- // page => sections -> fields
230
- $settings = [
231
- 'general' => [
232
- 'sections' => apply_filters(
233
- 'wprss_settings_sections_array',
234
- [
235
- 'import' => [
236
- 'title' => __('Import Settings', 'wprss'),
237
- 'fields' => $fields['import'],
 
 
 
 
 
 
 
238
  ],
239
- ]
240
- ),
241
- 'option' => 'wprss_settings_general',
242
- 'callback' => 'wprss_settings_general_validate',
243
- ],
244
- 'custom_feed' => [
245
- 'sections' => [
246
- 'custom_feed' => [
247
- 'title' => __('Custom RSS Feed', 'wprss'),
248
- 'fields' => $fields['custom_feed'],
249
  ],
 
 
250
  ],
251
- 'option' => 'wprss_settings_general',
252
- 'callback' => 'wprss_settings_general_validate',
253
- ],
254
- 'advanced' => [
255
- 'sections' => [
256
- 'advanced' => [
257
- 'title' => __('Advanced Settings', 'wprss'),
258
- 'fields' => $fields['advanced'],
259
- ],
260
- 'styles' => [
261
- 'title' => __('Styles', 'wprss'),
262
- 'fields' => $fields['styles'],
263
  ],
 
 
264
  ],
265
- 'option' => 'wprss_settings_general',
266
- 'callback' => 'wprss_settings_general_validate',
267
- ],
268
- 'license_keys' => [
269
- 'sections' => [],
270
- 'option' => 'wprss_settings_license_keys',
271
- 'callback' => 'wprss_settings_license_keys_validate',
272
- ],
273
- ];
274
-
275
- $setting_field_id_prefix = 'wprss-settings-';
276
-
277
- foreach ($settings as $pageKey => $page) {
278
- $groupId = "wprss_settings_${pageKey}";
279
-
280
- register_setting(
281
- $groupId,
282
- $page['option'],
283
- $page['callback']
284
- );
285
 
286
- foreach ($page['sections'] as $sectionKey => $section) {
287
- $sectionId = "wprss_settings_${sectionKey}_section";
288
 
289
- add_settings_section(
290
- $sectionId,
291
- $section['title'],
292
- "wprss_settings_${sectionKey}_callback",
293
- $groupId
 
 
294
  );
295
 
296
- foreach ($section['fields'] as $fieldId => $field) {
297
- /**
298
- * This will be passed to the field callback as the only argument
299
- *
300
- * @see http://codex.wordpress.org/Function_Reference/add_settings_field#Parameters
301
- */
302
- $callback_args = [
303
- 'field_id' => $fieldId,
304
- 'field_id_prefix' => $setting_field_id_prefix,
305
- 'section_id' => $sectionKey,
306
- 'field_label' => isset($field['label']) ? $field['label'] : null,
307
- 'tooltip' => isset($field['tooltip']) ? $field['tooltip'] : null,
308
- ];
309
-
310
- add_settings_field(
311
- $setting_field_id_prefix . $fieldId,
312
- $field['label'],
313
- $field['callback'],
314
- $groupId,
315
  $sectionId,
316
- $callback_args
 
 
317
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  }
319
  }
 
 
320
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
- do_action('wprss_admin_init');
323
- }
324
-
325
- /**
326
- * Returns the HTML of a tooltip handle.
327
- *
328
- * Filters used:
329
- * - `wprss_settings_inline_help_default_options` - The default options for "Settings" page's tooltips
330
- * - `wprss_settings_inline_help_id_prefix` - The prefix for all tooltip IDs for the "Settings" page.
331
- *
332
- * @param string $id The ID of the tooltip
333
- * @param string|null $text Text for this tooltip, if any.
334
- * @param array $options Any options for this setting.
335
- *
336
- * @return string Tooltip handle HTML. See {@link WPRSS_Help::tooltip()}.
337
- */
338
- function wprss_settings_inline_help($id, $text = null, $options = [])
339
- {
340
- $help = WPRSS_Help::get_instance();
341
-
342
- // Default options, entry point
343
- $defaults = apply_filters('wprss_settings_inline_help_default_options', [
344
- 'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-setting',
345
- ]);
346
-
347
- $options = $help->array_merge_recursive_distinct($defaults, $options);
348
-
349
- // ID Prefix
350
- $id = apply_filters('wprss_settings_inline_help_id_prefix', 'setting-') . $id;
351
-
352
- return $help->tooltip($id, $text, $options);
353
- }
354
-
355
- function wprss_settings_field_name_prefix($string = '')
356
- {
357
- $string = (string) $string;
358
- $prefix = apply_filters('wprss_settings_field_name_prefix', 'wprss_settings_', $string);
359
-
360
- return $prefix . $string;
361
- }
362
-
363
- /**
364
- * Generates a uniform setting field name for use in HTML.
365
- * The parts used are the ID of the field, the section it is in, and an optional prefix.
366
- * All parts are optional, but, if they appear, they shall appear in this order: $prefix, $section, $id.
367
- *
368
- * If only the section is not specified, the $id will be simply prefixed by $prefix.
369
- * If either the $id or the $section are empty (but not both), $prefix will be stripped of known separators.
370
- * Empty parts will be excluded.
371
- *
372
- * @param string $id ID of the field.
373
- * @param string|null $section Name of the section, to which this field belongs.
374
- * @param string|null $prefix The string to prefix the name with; appears first. If boolean false, no prefix will be
375
- * applied. Default: return value of {@link wprss_settings_field_name_prefix()}.
376
- *
377
- * @return string Name of the settings field, namespaced and optionally prefixed.
378
- */
379
- function wprss_settings_field_name($id = null, $section = null, $prefix = null)
380
- {
381
- if ($prefix !== false) {
382
- $prefix = $prefix !== null
383
- ? $prefix
384
- : wprss_settings_field_name_prefix();
385
- } else {
386
- $prefix = '';
387
  }
388
 
389
- $section = (string) $section;
 
 
 
 
 
 
 
390
 
391
- $format = '';
392
- if (!strlen($section) xor !strlen($id)) {
393
- $prefix = trim($prefix, "\t\n\r _-:");
 
 
 
 
394
  }
395
- if (strlen($prefix)) {
396
- $format .= '%3$s';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  }
398
- if (strlen($section)) {
399
- $format .= '%2$s';
 
 
 
 
 
 
 
 
 
 
400
  }
401
- if (strlen($id)) {
402
- $format .= (!strlen($section) ? '%1$s' : '[%1$s]');
 
 
 
 
 
 
 
 
 
403
  }
404
 
405
- return apply_filters('wprss_settings_field_name', sprintf($format, $id, $section, $prefix), $id, $section, $prefix);
406
- }
407
-
408
- /**
409
- * General settings section header
410
- *
411
- * @since 3.0
412
- */
413
- function wprss_settings_import_callback()
414
- {
415
- echo wpautop(__('Configure how WP RSS Aggregator imports RSS feed items.', 'wprss'));
416
- }
417
-
418
- /**
419
- * Custom feed settings section header
420
- *
421
- * @since 4.13
422
- */
423
- function wprss_settings_custom_feed_callback()
424
- {
425
- echo wpautop(__('WP RSS Aggregator creates a custom RSS feed on your site that includes all of your imported items. Use the below options to set it up.',
426
- 'wprss'));
427
- }
428
-
429
- /**
430
- * Advanced settings section header
431
- *
432
- * @since 4.13
433
- */
434
- function wprss_settings_advanced_callback()
435
- {
436
- echo wpautop(__('Only change these options if you know what you are doing!', 'wprss'));
437
- }
438
-
439
- /**
440
- * General settings styles section header
441
- *
442
- * @since 3.0
443
- */
444
- function wprss_settings_styles_callback()
445
- {
446
- echo wpautop(__('If you would like to disable all styles used in this plugin, tick the checkbox.', 'wprss'));
447
- }
448
-
449
- /**
450
- * Limit number of feed items stored by their age
451
- *
452
- * @since 3.0
453
- */
454
- function wprss_setting_limit_feed_items_age_callback($field)
455
- {
456
- $limit_feed_items_age = wprss_get_general_setting('limit_feed_items_age');
457
- $limit_feed_items_age_unit = wprss_get_general_setting('limit_feed_items_age_unit');
458
- $units = wprss_age_limit_units();
459
-
460
- printf(
461
- '<input id="%s" name="wprss_settings_general[limit_feed_items_age]" type="number" min="0" class="wprss-number-roller" placeholder="%s" value="%s" />',
462
- esc_attr($field['field_id']),
463
- __('No limit', 'wprss'),
464
- esc_attr($limit_feed_items_age)
465
- );
466
-
467
- echo '<select id="limit-feed-items-age-unit" name="wprss_settings_general[limit_feed_items_age_unit]">';
468
- foreach ($units as $unit) {
469
- printf(
470
- '<option value="%s" %s>%s</option>',
471
- esc_attr($unit),
472
- selected($limit_feed_items_age_unit, $unit, false),
473
- esc_html($unit)
474
- );
475
  }
476
- echo '</select>';
477
-
478
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
479
- }
480
-
481
- /**
482
- * Limit number of feed items stored
483
- *
484
- * @since 3.0
485
- */
486
- function wprss_setting_limit_feed_items_callback($field)
487
- {
488
- $limit_feed_items_db = wprss_get_general_setting('limit_feed_items_db');
489
-
490
- printf(
491
- '<input type="text" id="%s" name="%s" value="%s" />',
492
- esc_attr($field['field_id']),
493
- 'wprss_settings_general[limit_feed_items_db]',
494
- esc_attr($limit_feed_items_db)
495
- );
496
-
497
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
498
- }
499
-
500
- /**
501
- * Limit number of feed items imported per feed
502
- *
503
- * @since 3.1
504
- */
505
- function wprss_setting_limit_feed_items_imported_callback($field)
506
- {
507
- $limit_feed_items_imported = wprss_get_general_setting('limit_feed_items_imported');
508
-
509
- printf(
510
- '<input type="text" id="%s" name="%s" value="%s" placeholder="%s" />',
511
- esc_attr($field['field_id']),
512
- 'wprss_settings_general[limit_feed_items_imported]',
513
- esc_attr($limit_feed_items_imported),
514
- __('No Limit', 'wprss')
515
- );
516
-
517
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
518
- }
519
-
520
- /**
521
- * Gets a sorted (according to interval) list of the cron schedules
522
- *
523
- * @since 3.0
524
- */
525
- function wprss_get_schedules()
526
- {
527
- $schedules = wp_get_schedules();
528
-
529
- uasort($schedules, function ($a, $b) {
530
- return $a['interval'] - $b['interval'];
531
- });
532
-
533
- return $schedules;
534
- }
535
-
536
- /**
537
- * Cron interval dropdown callback
538
- *
539
- * @since 3.0
540
- */
541
- function wprss_setting_cron_interval_callback($field)
542
- {
543
- $current = wprss_get_general_setting('cron_interval');
544
- $schedules = wprss_get_schedules();
545
-
546
- // Set the allowed Cron schedules, we don't want any intervals that can lead to issues with server load
547
- $wprss_schedules = apply_filters(
548
- 'wprss_schedules',
549
- ['fifteen_min', 'thirty_min', 'hourly', 'two_hours', 'twicedaily', 'daily']
550
- );
551
-
552
- printf(
553
- '<select id="%s" name="%s">',
554
- esc_attr($field['field_id']),
555
- 'wprss_settings_general[cron_interval]'
556
- );
557
-
558
- foreach ($schedules as $schedule_name => $schedule_data) {
559
- if (!in_array($schedule_name, $wprss_schedules)) {
560
- continue;
561
- }
562
 
563
- printf(
564
- '<option value="%s" %s>%s (%s)</option>',
565
- esc_attr($schedule_name),
566
- selected($current, $schedule_name, false),
567
- esc_html($schedule_data['display']),
568
- wprss_interval($schedule_data['interval'])
569
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  }
571
 
572
- echo '</select>';
573
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
574
- }
575
-
576
- /**
577
- * Unique titles only checkbox callback
578
- *
579
- * @since 4.7
580
- */
581
- function wprss_setting_unique_titles($field)
582
- {
583
- $unique_titles = wprss_get_general_setting('unique_titles');
584
-
585
- echo wprss_options_render_checkbox($field['field_id'], 'unique_titles', $unique_titles);
586
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
587
- }
588
-
589
- /**
590
- * Sets the custom feed URL
591
- *
592
- * @since 3.3
593
- */
594
- function wprss_settings_custom_feed_url_callback($field)
595
- {
596
- $siteUrl = trailingslashit(get_site_url());
597
- $custom_feed_url = wprss_get_general_setting('custom_feed_url');
598
- $fullUrl = $siteUrl . $custom_feed_url;
599
-
600
- printf('<code>%s</code>', $siteUrl);
601
- printf(
602
- '<input type="text" id="%s" name="%s" value="%s" />',
603
- esc_attr($field['field_id']),
604
- 'wprss_settings_general[custom_feed_url]',
605
- esc_attr($custom_feed_url)
606
- );
607
-
608
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
609
-
610
- echo '<p style="font-style: normal">';
611
- printf(
612
- '<a href="%s" target="_blank">%s</a>',
613
- esc_attr($fullUrl),
614
- __('Open custom feed', 'wprss')
615
- );
616
- echo '</p>';
617
- }
618
-
619
- /**
620
- * Sets the custom feed title
621
- *
622
- * @since 4.1.2
623
- */
624
- function wprss_settings_custom_feed_title_callback($field)
625
- {
626
- $custom_feed_title = wprss_get_general_setting('custom_feed_title');
627
-
628
- printf(
629
- '<input type="text" id="%s" name="%s" value="%s" />',
630
- esc_attr($field['field_id']),
631
- 'wprss_settings_general[custom_feed_title]',
632
- esc_attr($custom_feed_title)
633
- );
634
-
635
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
636
- }
637
-
638
- /**
639
- * Sets the custom feed limit
640
- *
641
- * @since 3.3
642
- */
643
- function wprss_settings_custom_feed_limit_callback($field)
644
- {
645
- $custom_feed_limit = wprss_get_general_setting('custom_feed_limit');
646
-
647
- printf(
648
- '<input type="number" id="%s" name="%s" value="%s" placeholder="%s" class="wprss-number-roller" min="0" />',
649
- esc_attr($field['field_id']),
650
- 'wprss_settings_general[custom_feed_limit]',
651
- esc_attr($custom_feed_limit),
652
- __('Default', 'wprss')
653
- );
654
-
655
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
656
- }
657
-
658
- /**
659
- * Disable styles
660
- *
661
- * @since 3.0
662
- */
663
- function wprss_setting_styles_disable_callback($field)
664
- {
665
- $styles_disable = wprss_get_general_setting('styles_disable');
666
-
667
- echo wprss_options_render_checkbox($field['field_id'], 'styles_disable', $styles_disable);
668
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
669
- }
670
-
671
- /**
672
- * Renders the `limit_feed_items_per_import` setting.
673
- *
674
- * @since 4.11.2
675
- *
676
- * @param array $field Field data.
677
- */
678
- function wprss_setting_limit_feed_items_per_import_callback($field)
679
- {
680
- $id = $field['field_id'];
681
- $mainOptionName = 'wprss_settings_general';
682
- $value = wprss_get_general_setting($id);
683
-
684
- echo \Aventura\Wprss\Core\Model\SettingsAbstract::getTextHtml($value, [
685
- 'id' => $id,
686
- 'name' => \Aventura\Wprss\Core\Model\SettingsAbstract::getNameHtml([$mainOptionName, $id]),
687
- 'placeholder' => __('No Limit', 'wprss'),
688
- ]);
689
-
690
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
691
- }
692
-
693
- /**
694
- * Renders the `limit_feed_items_per_import` setting.
695
- *
696
- * @since 4.17
697
- *
698
- * @param array $field Field data.
699
- */
700
- function wprss_setting_schedule_future_items_callback($field)
701
- {
702
- $id = $field['field_id'];
703
- $value = wprss_get_general_setting($id);
704
-
705
- echo wprss_options_render_checkbox($field['field_id'], 'schedule_future_items', $value);
706
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
707
- }
708
-
709
- /**
710
- * Renders the `feed_items_import_order` setting.
711
- *
712
- * @since 4.11.2
713
- *
714
- * @param array $field Field data.
715
- */
716
- function wprss_setting_feed_items_import_order_callback($field)
717
- {
718
- $id = $field['field_id'];
719
- $mainOptionName = 'wprss_settings_general';
720
- $value = wprss_get_general_setting($id);
721
- $items = [
722
- 'latest' => __('Latest items first', 'wprss'),
723
- 'oldest' => __('Oldest items first', 'wprss'),
724
- '' => __('Original feed order', 'wprss'),
725
- ];
726
-
727
- printf(
728
- '<select id="%s" name="%s">',
729
- esc_attr($id),
730
- esc_attr(\Aventura\Wprss\Core\Model\SettingsAbstract::getNameHtml([$mainOptionName, $id]))
731
- );
732
-
733
- foreach ($items as $_value => $_label) {
734
- printf(
735
- '<option value="%s" %s>%s</option>',
736
- esc_attr($_value),
737
- selected($value, $_value, false),
738
- esc_html($_label)
739
- );
740
  }
741
 
742
- echo '</select>';
743
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
744
- }
745
-
746
- /**
747
- * Gets options that should go in a dropdown which represents a
748
- * feed-source-specific boolean setting.
749
- *
750
- * @since 4.10
751
- * @return array An array with options.
752
- */
753
- function wprss_settings_get_feed_source_boolean_options()
754
- {
755
- return [
756
- 1 => __('On', 'wprss'),
757
- 0 => __('Off', 'wprss'),
758
- -1 => __('Default', 'wprss'),
759
- ];
760
- }
761
-
762
- /**
763
- * Renders a <select> HTML tag from its parameters.
764
- *
765
- * @since 4.10
766
- * @return string The HTML of a <select> tag.
767
- */
768
- function wprss_settings_render_select($id, $name, $items, $selected = null, $attributes = [])
769
- {
770
- ob_start();
771
- $attributes = array_merge($attributes, [
772
- 'id' => $id,
773
- 'name' => $name,
774
- ]);
775
-
776
- array_walk($attributes, function (&$v, $k) {
777
- $v = sprintf('%1$s="%2$s"', $k, esc_attr($v));
778
- });
779
- $attrString = implode(' ', $attributes);
780
-
781
- $html = sprintf('<select %s>', $attrString);
782
-
783
- foreach ($items as $_key => $_item) {
784
- $_key = (string) $_key;
785
- $_item = (string) $_item;
786
-
787
- $html .= sprintf(
788
- '<option value="%s" %s>%s</option>',
789
- esc_attr($_key),
790
- selected($selected, $_key, false),
791
- esc_html($_item)
792
- );
793
  }
794
 
795
- $html .= '</select>';
796
-
797
- return $html;
798
- }
799
-
800
- /**
801
- * Renders an <input> HTML tag from its parameters.
802
- *
803
- * @since 4.13
804
- * @return string The HTML of an <input> tag.
805
- */
806
- function wprss_settings_render_input($id, $name, $value, $type = 'text', $attributes = [])
807
- {
808
- $attributes = array_merge($attributes, [
809
- 'id' => $id,
810
- 'name' => $name,
811
- 'type' => $type,
812
- 'value' => esc_attr($value),
813
- ]);
814
-
815
- $attributePairs = $attributes;
816
-
817
- array_walk($attributePairs, function (&$v, $k) {
818
- $v = sprintf('%1$s="%2$s"', $k, $v);
819
- });
820
-
821
- $attributesString = implode(' ', $attributePairs);
822
-
823
- return sprintf('<input %s />', $attributesString);
824
- }
825
-
826
- /**
827
- * Renders an <input> checkbox HTML tag from its parameters.
828
- *
829
- * @since 4.13
830
- * @return string The HTML of an <input> checkbox tag.
831
- */
832
- function wprss_settings_render_checkbox($id, $name, $value, $checked = false)
833
- {
834
- $attributes = [];
835
-
836
- if ($checked) {
837
- $attributes['checked'] = '';
838
  }
839
 
840
- return wprss_settings_render_input($id, $name, $value, 'checkbox', $attributes);
841
- }
842
-
843
- /**
844
- * Pretty-prints the difference in two times.
845
- *
846
- * @since 3.0
847
- *
848
- * @param time $older_date
849
- * @param time $newer_date
850
- *
851
- * @return string The pretty time_since value
852
- * @link http://wordpress.org/extend/plugins/wp-crontrol/
853
- */
854
- function wprss_time_since($older_date, $newer_date)
855
- {
856
- return wprss_interval($newer_date - $older_date);
857
- }
858
-
859
- /**
860
- * Calculates difference between times
861
- *
862
- * Taken from the WP-Crontrol plugin
863
- *
864
- * @link http://wordpress.org/extend/plugins/wp-crontrol/
865
- * @since 3.0
866
- *
867
- */
868
- function wprss_interval($since)
869
- {
870
- if ($since === wprss_get_default_feed_source_update_interval()) {
871
- return __('Default', 'wprss');
872
  }
873
- // array of time period chunks
874
- $chunks = [
875
- [60 * 60 * 24 * 365, _n_noop('%s year', '%s years', 'crontrol')],
876
- [60 * 60 * 24 * 30, _n_noop('%s month', '%s months', 'crontrol')],
877
- [60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'crontrol')],
878
- [60 * 60 * 24, _n_noop('%s day', '%s days', 'crontrol')],
879
- [60 * 60, _n_noop('%s hour', '%s hours', 'crontrol')],
880
- [60, _n_noop('%s minute', '%s minutes', 'crontrol')],
881
- [1, _n_noop('%s second', '%s seconds', 'crontrol')],
882
- ];
883
-
884
- if ($since <= 0) {
885
- return __('now', 'wprss');
886
  }
887
 
888
- // we only want to output two chunks of time here, eg:
889
- // x years, xx months
890
- // x days, xx hours
891
- // so there's only two bits of calculation below:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
 
893
- // step one: the first chunk
894
- for ($i = 0, $j = count($chunks); $i < $j; $i++) {
895
- $seconds = $chunks[$i][0];
896
- $name = $chunks[$i][1];
 
 
 
 
 
 
 
 
 
 
 
897
 
898
- // finding the biggest chunk (if the chunk fits, break)
899
- if (($count = floor($since / $seconds)) != 0) {
900
- break;
901
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
902
  }
903
 
904
- // set output var
905
- $output = sprintf(_n($name[0], $name[1], $count, 'wprss'), $count);
906
 
907
- // step two: the second chunk
908
- if ($i + 1 < $j) {
909
- $seconds2 = $chunks[$i + 1][0];
910
- $name2 = $chunks[$i + 1][1];
911
 
912
- if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {
913
- // add to output var
914
- $output .= ' ' . sprintf(_n($name2[0], $name2[1], $count2, 'wprss'), $count2);
915
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
916
  }
917
 
918
- return $output;
919
- }
920
-
921
- /**
922
- * Validate inputs from the general settings page
923
- *
924
- * @since 3.0
925
- */
926
- function wprss_settings_general_validate($input)
927
- {
928
- $current_cron_interval = wprss_get_general_setting('cron_interval');
929
-
930
- // Create our array for storing the validated options
931
- $output = get_option('wprss_settings_general', []);
932
-
933
- // Loop through each of the incoming options
934
- foreach ($input as $key => $value) {
935
- // Check to see if the current option has a value. If so, process it.
936
- if (!isset($value)) {
937
- continue;
938
- }
939
 
940
- // Strip all HTML and PHP tags and properly handle quoted strings
941
- $output[$key] = strip_tags(stripslashes($value));
 
 
 
 
 
 
 
 
 
 
 
 
942
  }
943
 
944
- if (isset($input['styles_disable'])) {
945
- $output['styles_disable'] = (int) $input['styles_disable'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946
  }
947
 
948
- if (isset($input['unique_titles'])) {
949
- $output['unique_titles'] = $input['unique_titles'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
950
  }
951
 
952
- if (isset($input['cron_interval']) && $input['cron_interval'] != $current_cron_interval) {
953
- wp_clear_scheduled_hook('wprss_fetch_all_feeds_hook');
954
- wp_schedule_event(time(), $input['cron_interval'], 'wprss_fetch_all_feeds_hook');
 
 
 
 
 
 
 
 
 
 
 
 
955
  }
956
 
957
- // Return the array processing any additional functions filtered by this action
958
- return apply_filters('wprss_settings_general_validate', $output, $input);
959
- }
960
-
961
- /**
962
- * Validates the licenses settings
963
- *
964
- * @since 3.8
965
- */
966
- function wprss_settings_license_keys_validate($input)
967
- {
968
- // Get the current licenses option
969
- $licenses = get_option('wprss_settings_license_keys');
970
- // If no licenses have been defined yet, create an empty array
971
- if (!is_array($licenses)) {
972
- $licenses = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
973
  }
974
- // For each entry in the received input
975
- foreach ($input as $addon => $license_code) {
976
- $addon_code = explode('_', $addon);
977
- $addon_code = isset($addon_code[0]) ? $addon_code[0] : null;
978
- // Only save if the entry does not exist OR the code is different
979
- if (array_key_exists($addon, $licenses) && $license_code === $licenses[$addon]) {
980
- continue;
 
 
 
 
 
 
981
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
982
 
983
- $is_valid = apply_filters('wprss_settings_license_key_is_valid', true, $license_code);
984
 
985
- if ($addon_code) {
986
- $is_valid = apply_filters("wprss_settings_license_key_{$addon_code}_is_valid", $is_valid, $license_code);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
987
  }
988
 
989
- if (!$is_valid) {
990
- continue;
991
  }
 
 
992
 
993
- // Save it to the licenses option
994
- $licenses[$addon] = $license_code;
 
 
 
 
 
 
995
  }
996
- wprss_check_license_statuses();
997
- // Return the new licenses
998
- return $licenses;
999
- }
1000
-
1001
- add_action('wprss_check_license_statuses', 'wprss_check_license_statuses');
1002
- /**
1003
- * Checks the license statuses
1004
- *
1005
- * @since 3.8.1
1006
- */
1007
- function wprss_check_license_statuses()
1008
- {
1009
- $license_statuses = get_option('wprss_settings_license_statuses', []);
1010
-
1011
- if (count($license_statuses) === 0) return;
1012
-
1013
- $found_inactive = false;
1014
- foreach ($license_statuses as $addon => $status) {
1015
- if ($status !== 'active') {
1016
- $found_inactive = true;
1017
- break;
1018
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1019
  }
1020
 
1021
- if ($found_inactive) {
1022
- set_transient('wprss_notify_inactive_licenses', 1, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1023
  }
1024
- }
1025
-
1026
- /**
1027
- * Returns the units used for the limit by age option.
1028
- *
1029
- * @since 3.8
1030
- */
1031
- function wprss_age_limit_units()
1032
- {
1033
- return apply_filters(
1034
- 'wprss_age_limit_units',
1035
- [
1036
- __('days', 'wprss'),
1037
- __('weeks', 'wprss'),
1038
- __('months', 'wprss'),
1039
- __('years', 'wprss'),
1040
- ]
1041
- );
1042
- }
1043
-
1044
- /**
1045
- * Renders a checkbox with a hidden field for the default value (when unchecked).
1046
- *
1047
- * @param string $id
1048
- * @param string $name
1049
- * @param string $value
1050
- * @param string $checked_value
1051
- * @param string $default_value
1052
- *
1053
- * @return string
1054
- */
1055
- function wprss_options_render_checkbox($id, $name, $value, $checked_value = '1', $default_value = '0')
1056
- {
1057
- $name = sprintf('wprss_settings_general[%s]', $name);
1058
-
1059
- $result = sprintf(
1060
- '<input type="hidden" name="%s" value="%s" />',
1061
- esc_attr($name),
1062
- esc_attr($default_value)
1063
- );
1064
- $result .= sprintf(
1065
- '<input type="checkbox" id="%s" name="%s" value="%s" %s />',
1066
- esc_attr($id),
1067
- esc_attr($name),
1068
- esc_attr($checked_value),
1069
- checked($checked_value, $value, false)
1070
- );
1071
-
1072
- return $result;
1073
- }
1
+ <?php
2
+ /**
3
+ * Plugin settings related functions
4
+ *
5
+ * Note: Wording of options and settings is confusing, due to the plugin originally only having
6
+ * an 'options' page to enter feed sources, and now needing two screens, one for feed sources and one for
7
+ * general settings. Might implement something cleaner in the future.
8
+ *
9
+ * @package WP PRSS Aggregator
10
+ */
11
+
12
+
13
+
14
+ /**
15
+ * Returns the given general setting option value form the database, or the default value if it is not found.
16
+ *
17
+ * @param string $option_name The name of the option to get
18
+ * @param bool $not_empty If true, the default value will be returned if the option exists but is empty.
19
+ * @return mixed
20
+ * @since 3.7.1
21
+ */
22
+ function wprss_get_general_setting( $option_name, $not_empty = false ) {
23
+ $options = get_option( 'wprss_settings_general', array() );
24
+ $defaults = wprss_get_default_settings_general();
25
+
26
+ $value = isset($options[$option_name])
27
+ ? $options[$option_name]
28
+ : $defaults[$option_name];
29
+
30
+ return ($not_empty && empty($value))
31
+ ? $defaults[$option_name]
32
+ : $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
+ /**
36
+ * Build the plugin settings page, used to save general settings like whether a link should be follow or no follow
37
+ * @since 1.1
38
+ */
39
+ function wprss_settings_page_display() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ ?>
42
+ <div class="wrap">
43
+ <div id="wpra-settings-app"></div>
44
 
45
+ <h2><?php _e( 'WP RSS Aggregator Settings', WPRSS_TEXT_DOMAIN ); ?></h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
+ <?php settings_errors(); ?>
 
48
 
49
+ <?php $active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general_settings'; ?>
 
 
 
 
 
 
 
 
 
50
 
51
+ <?php
52
 
53
+ $tabs = array(
54
+ array(
55
+ 'label' => __( 'General', WPRSS_TEXT_DOMAIN ),
56
+ 'slug' => 'general_settings',
57
+ ),
58
+ array(
59
+ 'label' => __( 'Custom Feed', WPRSS_TEXT_DOMAIN ),
60
+ 'slug' => 'custom_feed_settings',
61
+ ),
62
+ );
63
 
64
+ $tabs = apply_filters( 'wprss_options_tabs', $tabs );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ $tabs[] = array(
67
+ 'label' => __( 'Advanced', WPRSS_TEXT_DOMAIN ),
68
+ 'slug' => 'advanced_settings',
69
+ );
 
 
 
 
 
 
 
 
 
 
 
70
 
71
+ if (count(wprss_get_addons()) > 0 && is_main_site()) {
72
+ $tabs[] = array(
73
+ 'label' => __( 'Licenses', WPRSS_TEXT_DOMAIN ),
74
+ 'slug' => 'licenses_settings'
75
+ );
76
+ }
77
+
78
+ $show_tabs = ( count( $tabs ) > 1 ) || apply_filters( 'wprss_show_settings_tabs_condition', FALSE );
79
+
80
+ if ( $show_tabs ) { ?>
81
+ <h2 class="nav-tab-wrapper">
82
+ <?php
83
+ foreach ( $tabs as $tab => $tab_property ) { ?>
84
+ <a href="?post_type=wprss_feed&page=wprss-aggregator-settings&tab=<?php echo esc_attr( $tab_property['slug'] ); ?>"
85
+ class="nav-tab <?php echo $active_tab == $tab_property['slug'] ? 'nav-tab-active' : ''; ?>"><?php echo esc_html( $tab_property['label'] ); ?></a>
86
+ <?php } ?>
87
+ <?php } ?>
88
+ </h2>
89
+
90
+ <form action="options.php" method="post">
91
+
92
+ <?php
93
+
94
+ if ( $active_tab === 'general_settings' ) {
95
+ settings_fields( 'wprss_settings_general' );
96
+ do_settings_sections( 'wprss_settings_general' );
97
+ }
98
+ elseif ( $active_tab === 'advanced_settings' ) {
99
+ settings_fields( 'wprss_settings_advanced' );
100
+ do_settings_sections( 'wprss_settings_advanced' );
101
+ }
102
+ elseif ( $active_tab === 'custom_feed_settings' ) {
103
+ settings_fields( 'wprss_settings_custom_feed' );
104
+ do_settings_sections( 'wprss_settings_custom_feed' );
105
+ }
106
+ elseif ( $show_tabs ) {
107
+
108
+ if ( $active_tab === 'licenses_settings') {
109
+
110
+ if (!is_main_site()) {
111
+ printf(
112
+ '<p><strong>%s</strong></p>',
113
+ __('You do not have access to this page', 'wprss')
114
+ );
115
+
116
+ return;
117
+ }
118
+
119
+ settings_fields( 'wprss_settings_license_keys' );
120
+ do_settings_sections( 'wprss_settings_license_keys' );
121
+ }
122
+
123
+ do_action( 'wprss_add_settings_fields_sections', $active_tab );
124
+ }
125
+
126
+ submit_button( __( 'Save Settings', WPRSS_TEXT_DOMAIN ) );
127
+
128
+ ?>
129
+ </form>
130
+ </div>
131
+ <?php
132
  }
133
 
134
+ function wprss_settings_fields_array()
135
+ {
136
+ // Define the settings per section
137
+ $settings = apply_filters(
138
+ 'wprss_settings_array',
139
+ array(
140
+ 'import' => array(
141
+ 'cron-interval' => array(
142
+ 'label' => __( 'Update interval', 'wprss' ),
143
+ 'callback' => 'wprss_setting_cron_interval_callback'
144
+ ),
145
+ 'unique-titles' => array(
146
+ 'label' => __( 'Unique titles only', 'wprss'),
147
+ 'callback' => 'wprss_setting_unique_titles'
148
+ ),
149
+ 'feed_items_import_order' => array(
150
+ 'label' => __( 'Import order', 'wprss' ),
151
+ 'callback' => 'wprss_setting_feed_items_import_order_callback'
152
+ ),
153
+ 'limit-feed-items-by-age' => array(
154
+ 'label' => __( 'Limit items by age', 'wprss' ),
155
+ 'callback' => 'wprss_setting_limit_feed_items_age_callback'
156
+ ),
157
+ 'limit-feed-items-imported' => array(
158
+ 'label' => __( 'Limit feed items stored per feed', 'wprss' ),
159
+ 'callback' => 'wprss_setting_limit_feed_items_imported_callback'
160
+ ),
161
+ 'limit-feed-items-db' => array(
162
+ 'label' => __( 'Limit feed items stored', 'wprss' ),
163
+ 'callback' => 'wprss_setting_limit_feed_items_callback'
164
+ ),
165
+ 'limit_feed_items_per_import' => array(
166
+ 'label' => __( 'Limit feed items per import', 'wprss' ),
167
+ 'callback' => 'wprss_setting_limit_feed_items_per_import_callback'
168
+ ),
169
+ 'schedule_future_items' => array(
170
+ 'label' => __( 'Schedule future items', 'wprss' ),
171
+ 'callback' => 'wprss_setting_schedule_future_items_callback'
172
+ ),
173
+ ),
174
+
175
+ 'custom_feed' => array(
176
+ 'custom-feed-url' => array(
177
+ 'label' => __( 'Custom feed URL', 'wprss' ),
178
+ 'callback' => 'wprss_settings_custom_feed_url_callback'
179
+ ),
180
+ 'custom-feed-title' => array(
181
+ 'label' => __( 'Custom feed title', 'wprss' ),
182
+ 'callback' => 'wprss_settings_custom_feed_title_callback'
183
+ ),
184
+ 'custom-feed-limit' => array(
185
+ 'label' => __( 'Custom feed limit', 'wprss' ),
186
+ 'callback' => 'wprss_settings_custom_feed_limit_callback'
187
+ ),
188
+ ),
189
+ )
190
+ );
191
+
192
+ if ( apply_filters( 'wprss_use_fixed_feed_limit', false ) === false ) {
193
+ unset( $settings['import']['limit-feed-items-db'] );
194
+ }
195
+
196
+ $settings['styles'] = array(
197
+ 'styles-disable' => array(
198
+ 'label' => __( 'Disable styles', 'wprss' ),
199
+ 'callback' => 'wprss_setting_styles_disable_callback'
200
+ )
201
+ );
202
+
203
+ if ( apply_filters( 'wprss_use_fixed_feed_limit', false ) === false ) {
204
+ unset( $settings['general']['limit-feed-items-db'] );
205
+ }
206
 
207
+ return $settings;
 
208
  }
209
 
210
+
211
+ add_action( 'admin_init', 'wprss_admin_init' );
212
+ /**
213
+ * Register and define options and settings
214
+ * @since 2.0
215
+ *
216
+ * Note: In the future might change to
217
+ * the way EDD builds the settings pages, cleaner method.
218
+ */
219
+ function wprss_admin_init() {
220
+ $fields = wprss_settings_fields_array();
221
+
222
+ // page => sections -> fields
223
+ $settings = [
224
+ 'general' => [
225
+ 'sections' => apply_filters(
226
+ 'wprss_settings_sections_array',
227
+ [
228
+ 'import' => [
229
+ 'title' => __( 'Import Settings', 'wprss' ),
230
+ 'fields' => $fields['import'],
231
+ ],
232
+ ]
233
+ ),
234
+ 'option' => 'wprss_settings_general',
235
+ 'callback' => 'wprss_settings_general_validate',
236
+ ],
237
+ 'custom_feed' => [
238
+ 'sections' => [
239
+ 'custom_feed' => [
240
+ 'title' => __('Custom RSS Feed', 'wprss'),
241
+ 'fields' => $fields['custom_feed'],
242
  ],
 
 
 
 
 
 
 
 
 
 
243
  ],
244
+ 'option' => 'wprss_settings_general',
245
+ 'callback' => 'wprss_settings_general_validate',
246
  ],
247
+ 'advanced' => [
248
+ 'sections' => [
249
+ 'advanced' => [
250
+ 'title' => __('Advanced Settings', 'wprss'),
251
+ 'fields' => $fields['advanced'],
252
+ ],
253
+ 'styles' => [
254
+ 'title' => __('Styles', 'wprss'),
255
+ 'fields' => $fields['styles'],
256
+ ],
 
 
257
  ],
258
+ 'option' => 'wprss_settings_general',
259
+ 'callback' => 'wprss_settings_general_validate',
260
  ],
261
+ 'license_keys' => [
262
+ 'sections' => [],
263
+ 'option' => 'wprss_settings_license_keys',
264
+ 'callback' => 'wprss_settings_license_keys_validate',
265
+ ],
266
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
+ $setting_field_id_prefix = 'wprss-settings-';
 
269
 
270
+ foreach ($settings as $pageKey => $page) {
271
+ $groupId = "wprss_settings_${pageKey}";
272
+
273
+ register_setting(
274
+ $groupId,
275
+ $page['option'],
276
+ $page['callback']
277
  );
278
 
279
+ foreach ($page['sections'] as $sectionKey => $section) {
280
+ $sectionId = "wprss_settings_${sectionKey}_section";
281
+
282
+ add_settings_section(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  $sectionId,
284
+ $section['title'],
285
+ "wprss_settings_${sectionKey}_callback",
286
+ $groupId
287
  );
288
+
289
+ foreach ($section['fields'] as $fieldId => $field) {
290
+ /**
291
+ * This will be passed to the field callback as the only argument
292
+ * @see http://codex.wordpress.org/Function_Reference/add_settings_field#Parameters
293
+ */
294
+ $callback_args = array(
295
+ 'field_id' => $fieldId,
296
+ 'field_id_prefix' => $setting_field_id_prefix,
297
+ 'section_id' => $sectionKey,
298
+ 'field_label' => isset( $field['label'] ) ? $field['label'] : null,
299
+ 'tooltip' => isset( $field['tooltip'] ) ? $field['tooltip'] : null
300
+ );
301
+
302
+ add_settings_field(
303
+ $setting_field_id_prefix . $fieldId,
304
+ $field['label'],
305
+ $field['callback'],
306
+ $groupId,
307
+ $sectionId,
308
+ $callback_args
309
+ );
310
+ }
311
  }
312
  }
313
+
314
+ do_action( 'wprss_admin_init' );
315
  }
316
+
317
+
318
+ /**
319
+ * Returns the HTML of a tooltip handle.
320
+ *
321
+ * Filters used:
322
+ * - `wprss_settings_inline_help_default_options` - The default options for "Settings" page's tooltips
323
+ * - `wprss_settings_inline_help_id_prefix` - The prefix for all tooltip IDs for the "Settings" page.
324
+ *
325
+ * @param string $id The ID of the tooltip
326
+ * @param string|null $text Text for this tooltip, if any.
327
+ * @param array $options Any options for this setting.
328
+ * @return string Tooltip handle HTML. See {@link WPRSS_Help::tooltip()}.
329
+ */
330
+ function wprss_settings_inline_help( $id, $text = null, $options = array() ) {
331
+ $help = WPRSS_Help::get_instance();
332
+
333
+ // Default options, entry point
334
+ $defaults = apply_filters( 'wprss_settings_inline_help_default_options', array(
335
+ 'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-setting'
336
+ ));
337
+
338
+ $options = $help->array_merge_recursive_distinct( $defaults, $options );
339
+
340
+ // ID Prefix
341
+ $id = apply_filters( 'wprss_settings_inline_help_id_prefix', 'setting-' ) . $id;
342
+
343
+ return $help->tooltip( $id, $text, $options );
344
+ }
345
+
346
+
347
+ /**
348
+ *
349
+ * @param type $string
350
+ * @return type
351
+ */
352
+ function wprss_settings_field_name_prefix( $string = '' ) {
353
+ $string = (string) $string;
354
+ $prefix = apply_filters( 'wprss_settings_field_name_prefix', 'wprss_settings_', $string );
355
+ return $prefix . $string;
356
+ }
357
+
358
+
359
+ /**
360
+ * Generates a uniform setting field name for use in HTML.
361
+ * The parts used are the ID of the field, the section it is in, and an optional prefix.
362
+ * All parts are optional, but, if they appear, they shall appear in this order: $prefix, $section, $id.
363
+ *
364
+ * If only the section is not specified, the $id will be simply prefixed by $prefix.
365
+ * If either the $id or the $section are empty (but not both), $prefix will be stripped of known separators.
366
+ * Empty parts will be excluded.
367
+ *
368
+ * @param string $id ID of the field.
369
+ * @param string|null $section Name of the section, to which this field belongs.
370
+ * @param string|null $prefix The string to prefix the name with; appears first. If boolean false, no prefix will be applied. Default: return value of {@link wprss_settings_field_name_prefix()}.
371
+ * @return string Name of the settings field, namespaced and optionally prefixed.
372
+ */
373
+ function wprss_settings_field_name( $id = null, $section = null, $prefix = null ) {
374
+ if( $prefix !== false ) $prefix = is_null( $prefix ) ? wprss_settings_field_name_prefix() : $prefix;
375
+ else $prefix = '';
376
+
377
+ $section = (string) $section;
378
+
379
+ $format = '';
380
+ if( !strlen( $section ) xor !strlen($id) ) $prefix = trim ( $prefix, "\t\n\r _-:" );
381
+ if( strlen( $prefix ) ) $format .= '%3$s';
382
+ if( strlen( $section ) ) $format .= '%2$s';
383
+ if( strlen( $id ) ) $format .= ( !strlen( $section ) ? '%1$s' : '[%1$s]' );
384
+
385
+ return apply_filters( 'wprss_settings_field_name', sprintf( $format, $id, $section, $prefix ), $id, $section, $prefix );
386
+ }
387
+
388
+
389
+ /**
390
+ * General settings section header
391
+ *
392
+ * @since 3.0
393
+ */
394
+ function wprss_settings_import_callback() {
395
+ echo wpautop( __( 'Configure how WP RSS Aggregator imports RSS feed items.', 'wprss' ) );
396
+ }
397
+
398
 
399
+ /**
400
+ * Custom feed settings section header
401
+ *
402
+ * @since 4.13
403
+ */
404
+ function wprss_settings_custom_feed_callback() {
405
+ echo wpautop( __( 'WP RSS Aggregator creates a custom RSS feed on your site that includes all of your imported items. Use the below options to set it up.', 'wprss' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
407
 
408
+ /**
409
+ * Advanced settings section header
410
+ *
411
+ * @since 4.13
412
+ */
413
+ function wprss_settings_advanced_callback() {
414
+ echo wpautop( __( 'Only change these options if you know what you are doing!', WPRSS_TEXT_DOMAIN ) );
415
+ }
416
 
417
+ /**
418
+ * General settings styles section header
419
+ *
420
+ * @since 3.0
421
+ */
422
+ function wprss_settings_styles_callback() {
423
+ echo wpautop( __( 'If you would like to disable all styles used in this plugin, tick the checkbox.', WPRSS_TEXT_DOMAIN ) );
424
  }
425
+
426
+
427
+
428
+ /**
429
+ * Limit number of feed items stored by their age
430
+ * @since 3.0
431
+ */
432
+ function wprss_setting_limit_feed_items_age_callback( $field ) {
433
+ $limit_feed_items_age = wprss_get_general_setting( 'limit_feed_items_age' );
434
+ $limit_feed_items_age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
435
+ $units = wprss_age_limit_units();
436
+ // echo wprss_settings_field_name( $field_info['field_id'], $field_info['section_id'], $field_info['field_name_prefix'] )
437
+ ?>
438
+
439
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_age]" type="number" min="0"
440
+ class="wprss-number-roller" placeholder="<?php _e( 'No limit', WPRSS_TEXT_DOMAIN ) ?>" value="<?php echo $limit_feed_items_age; ?>" />
441
+
442
+ <select id="limit-feed-items-age-unit" name="wprss_settings_general[limit_feed_items_age_unit]">
443
+ <?php foreach ( $units as $unit ) : ?>
444
+ <option value="<?php echo $unit ?>" <?php selected( $limit_feed_items_age_unit, $unit ) ?> ><?php _e( $unit, WPRSS_TEXT_DOMAIN ) ?></option>
445
+ <?php endforeach ?>
446
+ </select>
447
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
448
+
449
+ <br/>
450
+ <?php
451
  }
452
+
453
+
454
+
455
+ /**
456
+ * Limit number of feed items stored
457
+ * @since 3.0
458
+ */
459
+ function wprss_setting_limit_feed_items_callback( $field ) {
460
+ $limit_feed_items_db = wprss_get_general_setting( 'limit_feed_items_db' );
461
+ ?>
462
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_db]" type="text" value="<?php echo $limit_feed_items_db ?>" />
463
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
464
  }
465
+
466
+
467
+ /**
468
+ * Limit number of feed items imported per feed
469
+ * @since 3.1
470
+ */
471
+ function wprss_setting_limit_feed_items_imported_callback( $field ) {
472
+ $limit_feed_items_imported = wprss_get_general_setting( 'limit_feed_items_imported' );
473
+ ?>
474
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_imported]" type="text" value="<?php echo $limit_feed_items_imported ?>" placeholder="<?php _e( 'No Limit', WPRSS_TEXT_DOMAIN ) ?>" />
475
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
476
  }
477
 
478
+
479
+ /**
480
+ * Gets a sorted (according to interval) list of the cron schedules
481
+ * @since 3.0
482
+ */
483
+ function wprss_get_schedules() {
484
+ $schedules = wp_get_schedules();
485
+ uasort( $schedules, function($a, $b) {
486
+ return $a['interval'] - $b['interval'];
487
+ } );
488
+ return $schedules;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
 
491
+
492
+ /**
493
+ * Cron interval dropdown callback
494
+ * @since 3.0
495
+ */
496
+ function wprss_setting_cron_interval_callback( $field ) {
497
+ $current = wprss_get_general_setting('cron_interval');
498
+
499
+ $schedules = wprss_get_schedules();
500
+ // Set the allowed Cron schedules, we don't want any intervals that can lead to issues with server load
501
+ $wprss_schedules = apply_filters(
502
+ 'wprss_schedules',
503
+ array( 'fifteen_min', 'thirty_min', 'hourly', 'two_hours', 'twicedaily', 'daily' )
504
+ );
505
+ ?>
506
+ <select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[cron_interval]">
507
+ <?php
508
+ foreach( $schedules as $schedule_name => $schedule_data ):
509
+ if ( in_array( $schedule_name, $wprss_schedules ) ): ?>
510
+ <option value="<?php echo $schedule_name ?>" <?php selected( $current, $schedule_name ) ?> >
511
+ <?php echo $schedule_data['display'] ?> (<?php echo wprss_interval( $schedule_data['interval'] ) ?>)
512
+ </option>
513
+ <?php endif ?>
514
+ <?php endforeach ?>
515
+ </select>
516
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?><?php
517
  }
518
 
519
+
520
+ /**
521
+ * Unique titles only checkbox callback
522
+ * @since 4.7
523
+ */
524
+ function wprss_setting_unique_titles( $field ) {
525
+ $unique_titles = wprss_get_general_setting( 'unique_titles' );
526
+
527
+ echo wprss_options_render_checkbox( $field['field_id'], 'unique_titles', $unique_titles );
528
+ echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  }
530
 
531
+
532
+ /**
533
+ * Sets the custom feed URL
534
+ * @since 3.3
535
+ */
536
+ function wprss_settings_custom_feed_url_callback( $field ) {
537
+ $siteUrl = trailingslashit(get_site_url());
538
+ $custom_feed_url = wprss_get_general_setting( 'custom_feed_url' );
539
+ $fullUrl = $siteUrl . $custom_feed_url;
540
+ ?>
541
+ <code><?= $siteUrl ?></code>
542
+ <input id="<?php echo $field['field_id'] ?>"
543
+ name="wprss_settings_general[custom_feed_url]"
544
+ type="text"
545
+ value="<?php echo $custom_feed_url ?>" />
546
+
547
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ); ?>
548
+
549
+ <p style="font-style: normal">
550
+ <a href="<?php echo esc_attr($fullUrl); ?>" target="_blank">
551
+ <?php _e('Open custom feed', 'wprss') ?>
552
+ </a>
553
+ </p>
554
+ <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  }
556
 
557
+ /**
558
+ * Sets the custom feed title
559
+ * @since 4.1.2
560
+ */
561
+ function wprss_settings_custom_feed_title_callback( $field ) {
562
+ $custom_feed_title = wprss_get_general_setting( 'custom_feed_title' );
563
+ ?>
564
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_title]" type="text" value="<?php echo $custom_feed_title ?>" />
565
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  }
567
 
568
+ /**
569
+ * Sets the custom feed limit
570
+ * @since 3.3
571
+ */
572
+ function wprss_settings_custom_feed_limit_callback( $field ) {
573
+ $custom_feed_limit = wprss_get_general_setting( 'custom_feed_limit' );
574
+ ?>
575
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_limit]" placeholder="<?php _e( 'Default', WPRSS_TEXT_DOMAIN ) ?>" min="0" class="wprss-number-roller" type="number" value="<?php echo $custom_feed_limit ?>" />
576
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  }
578
+
579
+ /**
580
+ * Disable styles
581
+ * @since 3.0
582
+ */
583
+ function wprss_setting_styles_disable_callback( $field ) {
584
+ $styles_disable = wprss_get_general_setting( 'styles_disable' );
585
+ echo wprss_options_render_checkbox( $field['field_id'], 'styles_disable', $styles_disable );
586
+ echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
587
  }
588
 
589
+ /**
590
+ * Renders the `limit_feed_items_per_import` setting.
591
+ *
592
+ * @since 4.11.2
593
+ *
594
+ * @param array $field Field data.
595
+ */
596
+ function wprss_setting_limit_feed_items_per_import_callback($field)
597
+ {
598
+ $id = $field['field_id'];
599
+ $mainOptionName = 'wprss_settings_general';
600
+ $value = wprss_get_general_setting($id);
601
+ echo \Aventura\Wprss\Core\Model\SettingsAbstract::getTextHtml($value, array(
602
+ 'id' => $id,
603
+ 'name' => \Aventura\Wprss\Core\Model\SettingsAbstract::getNameHtml(array($mainOptionName, $id)),
604
+ 'placeholder' => __( 'No Limit', WPRSS_TEXT_DOMAIN )
605
+ ));
606
+ ?>
607
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
608
+ }
609
 
610
+ /**
611
+ * Renders the `limit_feed_items_per_import` setting.
612
+ *
613
+ * @since 4.17
614
+ *
615
+ * @param array $field Field data.
616
+ */
617
+ function wprss_setting_schedule_future_items_callback($field)
618
+ {
619
+ $id = $field['field_id'];
620
+ $value = wprss_get_general_setting($id);
621
+
622
+ echo wprss_options_render_checkbox( $field['field_id'], 'schedule_future_items', $value );
623
+ echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
624
+ }
625
 
626
+ /**
627
+ * Renders the `feed_items_import_order` setting.
628
+ *
629
+ * @since 4.11.2
630
+ *
631
+ * @param array $field Field data.
632
+ */
633
+ function wprss_setting_feed_items_import_order_callback($field)
634
+ {
635
+ $id = $field['field_id'];
636
+ $mainOptionName = 'wprss_settings_general';
637
+ $value = wprss_get_general_setting($id);
638
+ $items = array(
639
+ 'latest' => __('Latest items first', WPRSS_TEXT_DOMAIN),
640
+ 'oldest' => __('Oldest items first', WPRSS_TEXT_DOMAIN),
641
+ '' => __('Original feed order', WPRSS_TEXT_DOMAIN),
642
+ );
643
+ ?>
644
+ <select id="<?php echo $id ?>" name="<?php echo \Aventura\Wprss\Core\Model\SettingsAbstract::getNameHtml(array($mainOptionName, $id)) ?>">
645
+ <?php
646
+ foreach( $items as $_value => $_label ): ?>
647
+ <option value="<?php echo esc_attr($_value) ?>" <?php selected( $value, $_value ) ?> >
648
+ <?php echo esc_html($_label) ?>
649
+ </option>
650
+ <?php endforeach ?>
651
+ </select>
652
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
653
  }
654
 
 
 
655
 
 
 
 
 
656
 
657
+ /**
658
+ * Secure Reset section
659
+ *
660
+ * @since 3.7.1
661
+ */
662
+ function wprss_settings_secure_reset_code_callback( $args ) {
663
+ $reset_code = get_option( 'wprss_secure_reset_code', '' );
664
+ ?>
665
+ <input id="wprss-secure-reset-code" name="wprss_secure_reset_code" type="input" value="<?php echo $reset_code; ?>" />
666
+ <button type="button" role="button" id="wprss-secure-reset-generate"><?php _e( 'Generate Random Code', WPRSS_TEXT_DOMAIN ) ?></button>
667
+
668
+ <br/>
669
+
670
+ <label class="description" for="wprss-secure-reset-code">
671
+ <?php _e( 'Enter the code to use to securely reset the plugin and deactivate it. Be sure to save this code somewhere safe.', WPRSS_TEXT_DOMAIN ) ?><br/>
672
+ </label>
673
+
674
+ <br/>
675
+
676
+ <p>
677
+ <?php _e( 'Leave this empty to disable the secure reset function.<br/>
678
+ You use this code by adding any of the following to any URL on your site.', WPRSS_TEXT_DOMAIN ) ?>
679
+ <ol>
680
+ <li>"?wprss_action=reset&wprss_security_code=&lt;your_code&gt;" - <b><?php _e( 'Resets your WP RSS Aggregator settings', WPRSS_TEXT_DOMAIN ) ?></b></li>
681
+ <li>"?wprss_action=deactivate&wprss_security_code=&lt;your_code&gt;" - <b><?php _e( 'Deactivates WP RSS Aggregator', WPRSS_TEXT_DOMAIN ) ?></b></li>
682
+ <li>"?wprss_action=reset_and_deactivate&wprss_security_code=&lt;your_code&gt;" - <b><?php _e( 'Does both of the above', WPRSS_TEXT_DOMAIN ) ?></b></li>
683
+ </ol>
684
+ </p>
685
+ <p class="description">
686
+ <?php _e( 'Use the above actions only when absolutely necessary, or when instructed to by support staff.', WPRSS_TEXT_DOMAIN ) ?>
687
+ </p>
688
+ <?php
689
  }
690
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
691
 
692
+ /**
693
+ * Gets options that should go in a dropdown which represents a
694
+ * feed-source-specific boolean setting.
695
+ *
696
+ * @since 4.10
697
+ * @return array An array with options.
698
+ */
699
+ function wprss_settings_get_feed_source_boolean_options()
700
+ {
701
+ return array(
702
+ 1 => __('On', WPRSS_TEXT_DOMAIN),
703
+ 0 => __('Off', WPRSS_TEXT_DOMAIN),
704
+ -1 => __('Default', WPRSS_TEXT_DOMAIN),
705
+ );
706
  }
707
 
708
+ /**
709
+ * Renders a <select> HTML tag from its parameters.
710
+ *
711
+ * @since 4.10
712
+ * @return string The HTML of a <select> tag.
713
+ */
714
+ function wprss_settings_render_select($id, $name, $items, $selected = null, $attributes = [])
715
+ {
716
+ ob_start();
717
+ $attributes = array_merge($attributes, [
718
+ 'id' => $id,
719
+ 'name' => $name,
720
+ ]);
721
+
722
+ $attributePairs = $attributes;
723
+ array_walk($attributePairs, function (&$v, $k) {
724
+ $v = sprintf('%1$s="%2$s"', $k, $v);
725
+ });
726
+ $attributesString = implode(' ', $attributePairs);
727
+ ?>
728
+ <select <?php echo $attributesString ?>>
729
+ <?php
730
+ foreach ($items as $_key => $_item) {
731
+ $_key = (string) $_key;
732
+ $_item = (string) $_item;
733
+ $isSelected = $selected == $_key;
734
+ ?>
735
+ <option value="<?php echo $_key ?>"<?php if ($isSelected): ?> selected="selected"<?php endif ?>><?php echo htmlspecialchars($_item) ?></option><?php
736
+ }
737
+ ?>
738
+ </select>
739
+ <?php
740
+ $html = ob_get_clean();
741
+
742
+ return $html;
743
  }
744
 
745
+ /**
746
+ * Renders an <input> HTML tag from its parameters.
747
+ *
748
+ * @since 4.13
749
+ * @return string The HTML of an <input> tag.
750
+ */
751
+ function wprss_settings_render_input($id, $name, $value, $type ='text', $attributes = [])
752
+ {
753
+ $attributes = array_merge($attributes, [
754
+ 'id' => $id,
755
+ 'name' => $name,
756
+ 'type' => $type,
757
+ 'value' => esc_attr($value)
758
+ ]);
759
+
760
+ $attributePairs = $attributes;
761
+
762
+ array_walk($attributePairs, function (&$v, $k) {
763
+ $v = sprintf('%1$s="%2$s"', $k, $v);
764
+ });
765
+
766
+ $attributesString = implode(' ', $attributePairs);
767
+
768
+ return sprintf('<input %s />', $attributesString);
769
  }
770
 
771
+ /**
772
+ * Renders an <input> checkbox HTML tag from its parameters.
773
+ *
774
+ * @since 4.13
775
+ * @return string The HTML of an <input> checkbox tag.
776
+ */
777
+ function wprss_settings_render_checkbox($id, $name, $value, $checked = false)
778
+ {
779
+ $attributes = [];
780
+
781
+ if ($checked) {
782
+ $attributes['checked'] = '';
783
+ }
784
+
785
+ return wprss_settings_render_input($id, $name, $value, 'checkbox', $attributes);
786
  }
787
 
788
+ /**
789
+ * Pretty-prints the difference in two times.
790
+ *
791
+ * @since 3.0
792
+ * @param time $older_date
793
+ * @param time $newer_date
794
+ * @return string The pretty time_since value
795
+ * @link http://wordpress.org/extend/plugins/wp-crontrol/
796
+ */
797
+ function wprss_time_since( $older_date, $newer_date ) {
798
+ return wprss_interval( $newer_date - $older_date );
799
+ }
800
+
801
+ /**
802
+ * Calculates difference between times
803
+ *
804
+ * Taken from the WP-Crontrol plugin
805
+ * @link http://wordpress.org/extend/plugins/wp-crontrol/
806
+ * @since 3.0
807
+ *
808
+ */
809
+ function wprss_interval( $since ) {
810
+ if ( $since === wprss_get_default_feed_source_update_interval() ) {
811
+ return __( 'Default', WPRSS_TEXT_DOMAIN );
812
+ }
813
+ // array of time period chunks
814
+ $chunks = array(
815
+ array(60 * 60 * 24 * 365 , _n_noop('%s year', '%s years', 'crontrol')),
816
+ array(60 * 60 * 24 * 30 , _n_noop('%s month', '%s months', 'crontrol')),
817
+ array(60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'crontrol')),
818
+ array(60 * 60 * 24 , _n_noop('%s day', '%s days', 'crontrol')),
819
+ array(60 * 60 , _n_noop('%s hour', '%s hours', 'crontrol')),
820
+ array(60 , _n_noop('%s minute', '%s minutes', 'crontrol')),
821
+ array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
822
+ );
823
+
824
+
825
+ if( $since <= 0 ) {
826
+ return __( 'now', WPRSS_TEXT_DOMAIN );
827
+ }
828
+
829
+ // we only want to output two chunks of time here, eg:
830
+ // x years, xx months
831
+ // x days, xx hours
832
+ // so there's only two bits of calculation below:
833
+
834
+ // step one: the first chunk
835
+ for ($i = 0, $j = count($chunks); $i < $j; $i++)
836
+ {
837
+ $seconds = $chunks[$i][0];
838
+ $name = $chunks[$i][1];
839
+
840
+ // finding the biggest chunk (if the chunk fits, break)
841
+ if (($count = floor($since / $seconds)) != 0)
842
+ {
843
+ break;
844
+ }
845
+ }
846
+
847
+ // set output var
848
+ $output = sprintf(_n($name[0], $name[1], $count, WPRSS_TEXT_DOMAIN), $count);
849
+
850
+ // step two: the second chunk
851
+ if ($i + 1 < $j)
852
+ {
853
+ $seconds2 = $chunks[$i + 1][0];
854
+ $name2 = $chunks[$i + 1][1];
855
+
856
+ if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
857
+ {
858
+ // add to output var
859
+ $output .= ' '.sprintf(_n($name2[0], $name2[1], $count2, WPRSS_TEXT_DOMAIN), $count2);
860
+ }
861
+ }
862
+
863
+ return $output;
864
+ }
865
+
866
+
867
+ /**
868
+ * Validate inputs from the general settings page
869
+ * @since 3.0
870
+ */
871
+ function wprss_settings_general_validate( $input ) {
872
+ $current_cron_interval = wprss_get_general_setting( 'cron_interval');
873
+
874
+ // Create our array for storing the validated options
875
+ $output = get_option('wprss_settings_general', []);
876
+
877
+ // Loop through each of the incoming options
878
+ foreach ($input as $key => $value) {
879
+ // Check to see if the current option has a value. If so, process it.
880
+ if (!isset($input[$key])) {
881
+ continue;
882
+ }
883
+
884
+ // Strip all HTML and PHP tags and properly handle quoted strings
885
+ $output[$key] = strip_tags(stripslashes($input[$key]));
886
+ }
887
+
888
+ if ( isset($input['styles_disable']) ) {
889
+ $output['styles_disable'] = (int) $input['styles_disable'];
890
+ }
891
+
892
+ if ( isset($input['unique_titles']) ) {
893
+ $output['unique_titles'] = $input['unique_titles'];
894
+ }
895
+
896
+ if ( isset($input['cron_interval']) && $input['cron_interval'] != $current_cron_interval ) {
897
+ wp_clear_scheduled_hook( 'wprss_fetch_all_feeds_hook' );
898
+ wp_schedule_event( time(), $input['cron_interval'], 'wprss_fetch_all_feeds_hook' );
899
+ }
900
+
901
+ // Return the array processing any additional functions filtered by this action
902
+ return apply_filters( 'wprss_settings_general_validate', $output, $input );
903
  }
904
+
905
+
906
+ /**
907
+ * Validates the licenses settings
908
+ *
909
+ * @since 3.8
910
+ */
911
+ function wprss_settings_license_keys_validate( $input ) {
912
+ // Get the current licenses option
913
+ $licenses = get_option( 'wprss_settings_license_keys' );
914
+ // If no licenses have been defined yet, create an empty array
915
+ if ( !is_array( $licenses ) ) {
916
+ $licenses = array();
917
  }
918
+ // For each entry in the received input
919
+ foreach ( $input as $addon => $license_code ) {
920
+ $addon_code = explode( '_', $addon );
921
+ $addon_code = isset( $addon_code[0] ) ? $addon_code[0] : null;
922
+ // Only save if the entry does not exist OR the code is different
923
+ if ( array_key_exists( $addon, $licenses ) && $license_code === $licenses[ $addon ] )
924
+ continue;
925
+
926
+ $is_valid = apply_filters( 'wprss_settings_license_key_is_valid', true, $license_code );
927
+ if( $addon_code )
928
+ $is_valid = apply_filters( "wprss_settings_license_key_{$addon_code}_is_valid", $is_valid, $license_code );
929
+ if( !$is_valid ) continue;
930
+
931
+ // Save it to the licenses option
932
+ $licenses[ $addon ] = $license_code;
933
+ }
934
+ wprss_check_license_statuses();
935
+ // Return the new licenses
936
+ return $licenses;
937
+ }
938
 
 
939
 
940
+
941
+ add_action( 'wprss_check_license_statuses', 'wprss_check_license_statuses' );
942
+ /**
943
+ * Checks the license statuses
944
+ *
945
+ * @since 3.8.1
946
+ */
947
+ function wprss_check_license_statuses() {
948
+ $license_statuses = get_option( 'wprss_settings_license_statuses', array() );
949
+
950
+ if ( count( $license_statuses ) === 0 ) return;
951
+
952
+ $found_inactive = FALSE;
953
+ foreach ( $license_statuses as $addon => $status ) {
954
+ if ( $status !== 'active' ) {
955
+ $found_inactive = TRUE;
956
+ break;
957
+ }
958
  }
959
 
960
+ if ( $found_inactive ) {
961
+ set_transient( 'wprss_notify_inactive_licenses', 1, 0 );
962
  }
963
+ }
964
+
965
 
966
+
967
+ /**
968
+ * Validates the wprss_secure_reset_code option
969
+ *
970
+ * @since 3.7.1
971
+ */
972
+ function wprss_secure_reset_code_validate( $input ) {
973
+ return $input;
974
  }
975
+
976
+
977
+
978
+ /**
979
+ * Validates the presstrends setting
980
+ *
981
+ * @since 3.6
982
+ */
983
+ function wprss_tracking_validate ( $input ) {
984
+ $output = $input;
985
+ if ( ! isset( $input['wprss_tracking'] ) ) {
986
+ $output['wprss_tracking'] = 0;
 
 
 
 
 
 
 
 
 
 
987
  }
988
+ return $output;
989
+ }
990
+
991
+
992
+
993
+ /**
994
+ * Returns the units used for the limit by age option.
995
+ *
996
+ * @since 3.8
997
+ */
998
+ function wprss_age_limit_units() {
999
+ return apply_filters(
1000
+ 'wprss_age_limit_units',
1001
+ array(
1002
+ 'days',
1003
+ 'weeks',
1004
+ 'months',
1005
+ 'years'
1006
+ )
1007
+ );
1008
  }
1009
 
1010
+ /**
1011
+ * Renders a checkbox with a hidden field for the default value (when unchecked).
1012
+ *
1013
+ * @param string $id
1014
+ * @param string $name
1015
+ * @param string $value
1016
+ * @param string $checked_value
1017
+ * @param string $default_value
1018
+ *
1019
+ * @return string
1020
+ */
1021
+ function wprss_options_render_checkbox($id, $name, $value, $checked_value = '1', $default_value = '0') {
1022
+ $nameAttr = esc_attr(sprintf('wprss_settings_general[%s]', $name));
1023
+ ob_start();
1024
+
1025
+ ?>
1026
+ <input type="hidden" name="<?= $nameAttr; ?>" value="<?= esc_attr($default_value) ?>"/>
1027
+ <input type="checkbox"
1028
+ id="<?= $id ?>"
1029
+ name="<?= $nameAttr ?>"
1030
+ value="<?= esc_attr($checked_value) ?>"
1031
+ <?= checked( $checked_value, $value, false ) ?> />
1032
+ <?php
1033
+
1034
+ return ob_get_clean();
1035
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/admin-plugins.php CHANGED
@@ -24,98 +24,94 @@ add_action('admin_init', function () {
24
  $addons = wprss_find_installed_addon_names();
25
  $addons = array_fill_keys($addons, 1);
26
 
27
- wp_localize_script('wpra-plugins', 'WrpaDisablePoll', [
28
  'image' => WPRSS_IMG,
29
  'url' => 'https://hooks.zapier.com/hooks/catch/305784/puf5uf/',
30
  'audience' => 50, // how many people should see the disable poll (in percents)
31
- 'model' => [
32
  'reason' => 'Other',
33
  'follow_up' => null,
34
  'date' => date('j M Y'),
35
  'addons' => $addons,
36
- ],
37
- 'form' => [
38
- [
39
  'label' => '',
40
  'type' => 'radio',
41
  'name' => 'reason',
42
  'options' =>
43
- [
44
- [
45
  'value' => 'I no longer need the plugin',
46
- 'label' => __('I no longer need the plugin', 'wprss'),
47
- ],
48
- [
49
  'value' => 'I found a better alternative',
50
- 'label' => __('I found a better alternative', 'wprss'),
51
- ],
52
- [
53
  'value' => 'I couldn\'t get the plugin to work',
54
- 'label' => __('I couldn\'t get the plugin to work', 'wprss'),
55
- ],
56
- [
57
  'value' => 'I\'m temporarily deactivating the plugin, but I\'ll be back',
58
- 'label' => __('I\'m temporarily deactivating the plugin, but I\'ll be back', 'wprss'),
59
- ],
60
- [
61
  'value' => 'I have a WP RSS Aggregator add-on',
62
- 'label' => __('I have a WP RSS Aggregator add-on', 'wprss'),
63
- ],
64
- [
65
  'value' => 'Other',
66
- 'label' => __('Other', 'wprss'),
67
- ],
68
- ],
69
- ],
70
- [
71
- 'label' => __('Would you mind sharing its name?', 'wprss'),
72
  'type' => 'textarea',
73
  'name' => 'follow_up',
74
  'condition' =>
75
- [
76
  'field' => 'reason',
77
  'operator' => '=',
78
  'value' => 'I found a better alternative',
79
- ],
80
- ],
81
- [
82
  'type' => 'content',
83
- 'label' => __(
84
- 'Have you <a target="_blank" href="https://wordpress.org/support/plugin/wp-rss-aggregator/">contacted our support team</a> or checked out our <a href="https://kb.wprssaggregator.com/" target="_blank">Knowledge Base</a>?',
85
- 'wprss'
86
- ),
87
  'condition' =>
88
- [
89
  'field' => 'reason',
90
  'operator' => '=',
91
- 'value' => __('I couldn\'t get the plugin to work', 'wprss'),
92
- ],
93
- ],
94
- [
95
  'type' => 'content',
96
  'className' => 'error',
97
- 'label' => __('This core plugin is required for all our premium add-ons. Please don\'t deactivate it if you currently have premium add-ons installed and activated.',
98
- 'wprss'),
99
  'condition' =>
100
- [
101
  'field' => 'reason',
102
  'operator' => '=',
103
- 'value' => __('I have a WP RSS Aggregator add-on', 'wprss'),
104
- ],
105
- ],
106
- [
107
- 'label' => __('Please share your reason...', 'wprss'),
108
  'type' => 'textarea',
109
  'name' => 'follow_up',
110
  'condition' =>
111
- [
112
  'field' => 'reason',
113
  'operator' => '=',
114
- 'value' => __('Other', 'wprss'),
115
- ],
116
- ],
117
- ],
118
- ]);
119
 
120
  echo '<div id="wpra-plugins-app"></div>';
121
  });
24
  $addons = wprss_find_installed_addon_names();
25
  $addons = array_fill_keys($addons, 1);
26
 
27
+ wp_localize_script('wpra-plugins', 'WrpaDisablePoll', array(
28
  'image' => WPRSS_IMG,
29
  'url' => 'https://hooks.zapier.com/hooks/catch/305784/puf5uf/',
30
  'audience' => 50, // how many people should see the disable poll (in percents)
31
+ 'model' => array(
32
  'reason' => 'Other',
33
  'follow_up' => null,
34
  'date' => date('j M Y'),
35
  'addons' => $addons,
36
+ ),
37
+ 'form' => array(
38
+ array(
39
  'label' => '',
40
  'type' => 'radio',
41
  'name' => 'reason',
42
  'options' =>
43
+ array(
44
+ array(
45
  'value' => 'I no longer need the plugin',
46
+ 'label' => __('I no longer need the plugin', WPRSS_TEXT_DOMAIN),
47
+ ),
48
+ array(
49
  'value' => 'I found a better alternative',
50
+ 'label' => __('I found a better alternative', WPRSS_TEXT_DOMAIN),
51
+ ),
52
+ array(
53
  'value' => 'I couldn\'t get the plugin to work',
54
+ 'label' => __('I couldn\'t get the plugin to work', WPRSS_TEXT_DOMAIN),
55
+ ),
56
+ array(
57
  'value' => 'I\'m temporarily deactivating the plugin, but I\'ll be back',
58
+ 'label' => __('I\'m temporarily deactivating the plugin, but I\'ll be back', WPRSS_TEXT_DOMAIN),
59
+ ),
60
+ array(
61
  'value' => 'I have a WP RSS Aggregator add-on',
62
+ 'label' => __('I have a WP RSS Aggregator add-on', WPRSS_TEXT_DOMAIN),
63
+ ),
64
+ array(
65
  'value' => 'Other',
66
+ 'label' => __('Other', WPRSS_TEXT_DOMAIN),
67
+ ),
68
+ ),
69
+ ),
70
+ array(
71
+ 'label' => __('Would you mind sharing its name?', WPRSS_TEXT_DOMAIN),
72
  'type' => 'textarea',
73
  'name' => 'follow_up',
74
  'condition' =>
75
+ array(
76
  'field' => 'reason',
77
  'operator' => '=',
78
  'value' => 'I found a better alternative',
79
+ ),
80
+ ),
81
+ array(
82
  'type' => 'content',
83
+ 'label' => __('Have you <a target="_blank" href="https://wordpress.org/support/plugin/wp-rss-aggregator/">contacted our support team</a> or checked out our <a href="https://kb.wprssaggregator.com/" target="_blank">Knowledge Base</a>?', WPRSS_TEXT_DOMAIN),
 
 
 
84
  'condition' =>
85
+ array(
86
  'field' => 'reason',
87
  'operator' => '=',
88
+ 'value' => 'I couldn\'t get the plugin to work',
89
+ ),
90
+ ),
91
+ array(
92
  'type' => 'content',
93
  'className' => 'error',
94
+ 'label' => __('This core plugin is required for all our premium add-ons. Please don\'t deactivate it if you currently have premium add-ons installed and activated.', WPRSS_TEXT_DOMAIN),
 
95
  'condition' =>
96
+ array(
97
  'field' => 'reason',
98
  'operator' => '=',
99
+ 'value' => 'I have a WP RSS Aggregator add-on',
100
+ ),
101
+ ),
102
+ array(
103
+ 'label' => __('Please share your reason...', WPRSS_TEXT_DOMAIN),
104
  'type' => 'textarea',
105
  'name' => 'follow_up',
106
  'condition' =>
107
+ array(
108
  'field' => 'reason',
109
  'operator' => '=',
110
+ 'value' => 'Other',
111
+ ),
112
+ ),
113
+ )
114
+ ));
115
 
116
  echo '<div id="wpra-plugins-app"></div>';
117
  });
includes/admin-update-page.php CHANGED
@@ -11,8 +11,8 @@ define('WPRSS_UPDATE_PAGE_PREV_VERSION_OPTION', 'wprss_prev_update_page_version'
11
  add_action('admin_menu', function () {
12
  add_submenu_page(
13
  null,
14
- __('Thank you for updating WP RSS Aggregator', 'wprss'),
15
- __('Thank you for updating WP RSS Aggregator', 'wprss'),
16
  'manage_options',
17
  WPRSS_UPDATE_PAGE_SLUG,
18
  'wprss_render_update_page'
11
  add_action('admin_menu', function () {
12
  add_submenu_page(
13
  null,
14
+ __('Thank you for updating WP RSS Aggregator', WPRSS_TEXT_DOMAIN),
15
+ __('Thank you for updating WP RSS Aggregator', WPRSS_TEXT_DOMAIN),
16
  'manage_options',
17
  WPRSS_UPDATE_PAGE_SLUG,
18
  'wprss_render_update_page'
includes/admin.php CHANGED
@@ -1,230 +1,194 @@
1
  <?php
 
 
 
 
 
2
 
3
- add_action('admin_head', 'wprss_custom_post_type_icon');
4
- /**
5
- * Custom Post Type Icon for Admin Menu & Post Screen
6
- *
7
- * @since 2.0
8
- */
9
- function wprss_custom_post_type_icon()
10
- {
11
- ?>
12
- <style>
13
- /* Post Screen - 32px */
14
- .icon32-posts-wprss_feed {
15
- background: transparent url( <?php echo WPRSS_IMG . 'icon-adminpage32.png'; ?> ) no-repeat left top !important;
16
- }
17
-
18
- /* Post Screen - 32px */
19
- .icon32-posts-wprss_feed_item {
20
- background: transparent url( <?php echo WPRSS_IMG . 'icon-adminpage32.png'; ?> ) no-repeat left top !important;
21
- }
22
- </style>
23
- <?php
24
- }
25
-
26
- add_action('admin_menu', function () {
27
- add_submenu_page(
28
- 'edit.php?post_type=wprss_feed',
29
- __('WP RSS Aggregator Settings', 'wprss'),
30
- __('Settings', 'wprss'),
31
- apply_filters('wprss_capability', 'manage_feed_settings'),
32
- 'wprss-aggregator-settings',
33
- 'wprss_settings_page_display'
34
- );
35
- }, 30);
36
-
37
- add_action('admin_menu', function () {
38
- add_submenu_page(
39
- 'edit.php?post_type=wprss_feed',
40
- __('Help & Support', 'wprss'),
41
- __('Help & Support', 'wprss'),
42
- apply_filters('wprss_capability', 'manage_feed_settings'),
43
- 'wprss-help', 'wprss_help_page_display'
44
- );
45
- }, 60);
46
-
47
- // Hides the "Add New" submenu
48
- add_action('admin_menu', function () {
49
- global $submenu;
50
- unset($submenu['edit.php?post_type=wprss_feed'][10]);
51
- });
52
-
53
- add_filter('admin_body_class', 'wprss_base_admin_body_class');
54
- /**
55
- * Set body class for admin screens
56
- * http://www.kevinleary.net/customizing-wordpress-admin-css-javascript/
57
- *
58
- * @since 2.0
59
- */
60
- function wprss_base_admin_body_class($classes)
61
- {
62
- $action = filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
63
- $post = filter_input(INPUT_GET, 'post', FILTER_VALIDATE_INT);
64
- $postType = filter_input(INPUT_GET, 'post_type', FILTER_SANITIZE_STRING);
65
-
66
- // Current action
67
- if (is_admin() && !empty($action)) {
68
- $classes .= ' action-' . esc_attr($action);
69
- }
70
-
71
- // Current post ID
72
- if (is_admin() && !empty($post)) {
73
- $classes .= ' post-' . esc_attr($post);
74
- }
75
-
76
- // New post type & listing page
77
- if (!empty($postType)) {
78
- $classes .= ' post-type-' . esc_attr($postType);
79
  }
80
 
81
- // Editing a post type
82
- if (!empty($post)) {
83
- $currPost = get_post($post);
84
 
85
- if ($currPost instanceof WP_Post && !empty($currPost->post_type)) {
86
- $classes .= ' post-type-' . esc_attr($currPost->post_type);
 
 
 
 
 
 
 
 
 
 
87
  }
88
- }
89
 
90
- return $classes;
91
- }
92
-
93
- /**
94
- * Change title on wprss_feed post type screen
95
- *
96
- * @since 2.0
97
- *
98
- * @param string $original The original title placeholder.
99
- *
100
- * @return string
101
- */
102
- function wprss_change_title_text($original)
103
- {
104
- if (get_post_type() === 'wprss_feed') {
105
- return __('Name this feed', 'wprss');
106
  }
107
 
108
- return $original;
109
- }
110
-
111
- add_filter('plugin_action_links', 'wprss_plugin_action_links', 10, 2);
112
- /**
113
- * Add Settings action link in plugin listing
114
- *
115
- * @since 3.0
116
- *
117
- * @param array $action_links
118
- * @param string $plugin_file
119
- *
120
- * @return array
121
- */
122
- function wprss_plugin_action_links($action_links, $plugin_file)
123
- {
124
- // check to make sure we are on the correct plugin
125
- if ($plugin_file == 'wp-rss-aggregator/wp-rss-aggregator.php') {
126
- // the anchor tag and href to the URLs we want.
127
- $settings_link = sprintf(
128
- '<a href="%s">%s</a>',
129
- esc_attr(admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings'),
130
- __('Settings', 'wprss')
131
- );
132
-
133
- $docs_link = sprintf(
134
- '<a href="%s">%s</a>',
135
- esc_attr('https://www.wprssaggregator.com/documentation/'),
136
- __('Documentation', 'wprss')
137
- );
138
 
139
- // add the links to the beginning of the list
140
- array_unshift($action_links, $settings_link, $docs_link);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
142
 
143
- return $action_links;
144
- }
145
-
146
- /**
147
- * Function for registering application's scripts that depends on advanced libraries.
148
- * It will enqueue manifest and vendor scripts, which contains all required logic
149
- * for bootstrapping application and dependencies.
150
- *
151
- * Use only for Vue-related apps that use Webpack for being built.
152
- *
153
- * @since 4.12.1
154
- *
155
- * @param $handle
156
- * @param string $src
157
- * @param array $deps
158
- * @param bool $ver
159
- * @param bool $in_footer
160
- */
161
- function wprss_plugin_enqueue_app_scripts($handle, $src = '', $deps = [], $ver = false, $in_footer = false)
162
- {
163
- /*
164
- * Manifest file holds function used for bootstrapping and ordered
165
- * loading of dependencies and application.
166
  */
167
- wp_enqueue_script('wpra-manifest', WPRSS_APP_JS . 'wpra-manifest.min.js', [], '0.1', true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
- /*
170
- * Vendor file holds all common dependencies for "compilable" applications.
 
 
 
171
  *
172
- * For example, `intro` pages application's and plugin's page application's files
173
- * holds only logic for that particular application. Common dependencies like Vue
174
- * live in this file and loaded before that application.
175
  */
176
- wp_enqueue_script('wpra-vendor', WPRSS_APP_JS . 'wpra-vendor.min.js', [
177
- 'wpra-manifest',
178
- ], '0.1', true);
 
 
 
 
 
 
179
 
180
- /*
181
- * Enqueue requested script.
182
- */
183
- $deps = array_merge([
184
- 'wpra-manifest',
185
- 'wpra-vendor',
186
- ], $deps);
187
- wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
188
- }
189
-
190
- add_filter('admin_footer_text', 'wprss_admin_footer');
191
- /**
192
- * Adds footer text on the plugin pages.
193
- *
194
- * @param string $footer The footer text to filter
195
- *
196
- * @return string The filtered footer text with added plugin text, or the param
197
- * value if the page is not specific to the plugin.
198
- */
199
- function wprss_admin_footer($footer)
200
- {
201
- // Current post type
202
- global $typenow;
203
- // Check if type is a plugin type. If not, stop
204
- // Plugin type is in the form 'wprss_*'' where * is 'feed', 'blacklist', etc)
205
- if (stripos($typenow, 'wprss_') !== 0) {
206
- return $footer;
207
- }
208
 
209
- // Prepare fragments of the message
210
- $thank_you = sprintf(
211
- __('Thank you for using <a href="%1$s" target="_blank">WP RSS Aggregator</a>.', 'wprss'),
212
- esc_attr('https://www.wprssaggregator.com/')
213
- );
214
- $rate_us = sprintf(
215
- __('Please <a href="%1$s" target="_blank">rate us</a>!', 'wprss'),
216
- esc_attr('https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?filter=5#postform')
217
- );
218
-
219
- // Return the final text
220
- return sprintf('<span class="wp-rss-footer-text">%1$s %2$s</span>', $thank_you, $rate_us);
221
- }
222
-
223
- // Un-trashed feed sources are published, not draft
224
- add_filter('wp_untrash_post_status', function ($status, $postId) {
225
- $postType = get_post_type($postId);
226
-
227
- return ($postType === 'wprss_feed' || $postType === 'wprss_feed_item')
228
- ? 'publish'
229
- : $status;
230
- }, 10, 3);
1
  <?php
2
+ /**
3
+ * Plugin administration related functions
4
+ *
5
+ * @package WPRSSAggregator
6
+ */
7
 
8
+ add_action( 'admin_head', 'wprss_custom_post_type_icon' );
9
+ /**
10
+ * Custom Post Type Icon for Admin Menu & Post Screen
11
+ * @since 2.0
12
+ */
13
+ function wprss_custom_post_type_icon() {
14
+ ?>
15
+ <style>
16
+ /* Post Screen - 32px */
17
+ .icon32-posts-wprss_feed {
18
+ background: transparent url( <?php echo WPRSS_IMG . 'icon-adminpage32.png'; ?> ) no-repeat left top !important;
19
+ }
20
+ /* Post Screen - 32px */
21
+ .icon32-posts-wprss_feed_item {
22
+ background: transparent url( <?php echo WPRSS_IMG . 'icon-adminpage32.png'; ?> ) no-repeat left top !important;
23
+ }
24
+ </style>
25
+ <?php }
26
+
27
+ add_action('admin_menu', function () {
28
+ add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'WP RSS Aggregator Settings', WPRSS_TEXT_DOMAIN ), __( 'Settings', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings' ), 'wprss-aggregator-settings', 'wprss_settings_page_display' );
29
+ }, 30);
30
+
31
+ add_action('admin_menu', function () {
32
+ add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Help & Support', WPRSS_TEXT_DOMAIN ), __( 'Help & Support', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings'), 'wprss-help', 'wprss_help_page_display' );
33
+ }, 60);
34
+
35
+ // Hides the "Add New" submenu
36
+ add_action('admin_menu', function () {
37
+ global $submenu;
38
+ unset( $submenu['edit.php?post_type=wprss_feed'][10] );
39
+ });
40
+
41
+ add_filter('admin_body_class', 'wprss_base_admin_body_class');
42
+ /**
43
+ * Set body class for admin screens
44
+ * http://www.kevinleary.net/customizing-wordpress-admin-css-javascript/
45
+ * @since 2.0
46
+ */
47
+ function wprss_base_admin_body_class( $classes )
48
+ {
49
+ // Current action
50
+ if ( is_admin() && isset($_GET['action']) ) {
51
+ $classes .= 'action-'.$_GET['action'];
52
+ }
53
+ // Current post ID
54
+ if ( is_admin() && isset($_GET['post']) ) {
55
+ $classes .= ' ';
56
+ $classes .= 'post-'.$_GET['post'];
57
+ }
58
+ // New post type & listing page
59
+ if ( isset($_GET['post_type']) ) $post_type = $_GET['post_type'];
60
+ if ( isset($post_type) ) {
61
+ $classes .= ' ';
62
+ $classes .= 'post-type-'.$post_type;
63
+ }
64
+ // Editting a post type
65
+ if ( isset( $_GET['post'] ) ) {
66
+ $post_query = $_GET['post'];
67
+ }
68
+ if ( isset($post_query) ) {
69
+ $current_post_edit = get_post($post_query);
70
+ $current_post_type = $current_post_edit->post_type;
71
+ if ( !empty($current_post_type) ) {
72
+ $classes .= ' ';
73
+ $classes .= 'post-type-'.$current_post_type;
74
+ }
75
+ }
76
+ // Return the $classes array
77
+ return $classes;
 
 
 
 
 
 
78
  }
79
 
 
 
 
80
 
81
+ /**
82
+ * Change title on wprss_feed post type screen
83
+ *
84
+ * @since 2.0
85
+ *
86
+ * @param string $original The original title placeholder.
87
+ *
88
+ * @return string
89
+ */
90
+ function wprss_change_title_text($original) {
91
+ if (get_post_type() === 'wprss_feed') {
92
+ return __('Name this feed', WPRSS_TEXT_DOMAIN);
93
  }
 
94
 
95
+ return $original;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ add_filter( 'plugin_action_links', 'wprss_plugin_action_links', 10, 2 );
100
+ /**
101
+ * Add Settings action link in plugin listing
102
+ *
103
+ * @since 3.0
104
+ * @param array $action_links
105
+ * @param string $plugin_file
106
+ * @return array
107
+ */
108
+ function wprss_plugin_action_links( $action_links, $plugin_file ) {
109
+ // check to make sure we are on the correct plugin
110
+ if ( $plugin_file == 'wp-rss-aggregator/wp-rss-aggregator.php' ) {
111
+ // the anchor tag and href to the URLs we want.
112
+ $settings_link = '<a href="' . admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings">' . __( 'Settings', WPRSS_TEXT_DOMAIN ) . '</a>';
113
+ $docs_link = '<a href="https://www.wprssaggregator.com/documentation/">' . __( 'Documentation', WPRSS_TEXT_DOMAIN ) . '</a>';
114
+ // add the links to the beginning of the list
115
+ array_unshift( $action_links, $settings_link, $docs_link );
116
+ }
117
+ return $action_links;
118
  }
119
 
120
+ /**
121
+ * Function for registering application's scripts that depends on advanced libraries.
122
+ * It will enqueue manifest and vendor scripts, which contains all required logic
123
+ * for bootstrapping application and dependencies.
124
+ *
125
+ * Use only for Vue-related apps that use Webpack for being built.
126
+ *
127
+ * @since 4.12.1
128
+ *
129
+ * @param $handle
130
+ * @param string $src
131
+ * @param array $deps
132
+ * @param bool $ver
133
+ * @param bool $in_footer
 
 
 
 
 
 
 
 
 
134
  */
135
+ function wprss_plugin_enqueue_app_scripts( $handle, $src = '', $deps = array(), $ver = false, $in_footer = false ) {
136
+ /*
137
+ * Manifest file holds function used for bootstrapping and ordered
138
+ * loading of dependencies and application.
139
+ */
140
+ wp_enqueue_script('wpra-manifest', WPRSS_APP_JS . 'wpra-manifest.min.js', array(), '0.1', true);
141
+
142
+ /*
143
+ * Vendor file holds all common dependencies for "compilable" applications.
144
+ *
145
+ * For example, `intro` pages application's and plugin's page application's files
146
+ * holds only logic for that particular application. Common dependencies like Vue
147
+ * live in this file and loaded before that application.
148
+ */
149
+ wp_enqueue_script('wpra-vendor', WPRSS_APP_JS . 'wpra-vendor.min.js', array(
150
+ 'wpra-manifest'
151
+ ), '0.1', true);
152
+
153
+ /*
154
+ * Enqueue requested script.
155
+ */
156
+ $deps = array_merge(array(
157
+ 'wpra-manifest',
158
+ 'wpra-vendor',
159
+ ), $deps);
160
+ wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
161
+ }
162
 
163
+ add_filter('admin_footer_text', 'wprss_admin_footer');
164
+ /**
165
+ * Adds footer text on the plugin pages.
166
+ *
167
+ * @param string $footer The footer text to filter
168
  *
169
+ * @return string The filtered footer text with added plugin text, or the param
170
+ * value if the page is not specific to the plugin.
 
171
  */
172
+ function wprss_admin_footer($footer)
173
+ {
174
+ // Current post type
175
+ global $typenow;
176
+ // Check if type is a plugin type. If not, stop
177
+ // Plugin type is in the form 'wprss_*'' where * is 'feed', 'blacklist', etc)
178
+ if (stripos($typenow, 'wprss_') !== 0) {
179
+ return $footer;
180
+ }
181
 
182
+ // Prepare fragments of the message
183
+ $thank_you = sprintf(
184
+ __('Thank you for using <a href="%1$s" target="_blank">WP RSS Aggregator</a>.', 'wprss'),
185
+ 'https://www.wprssaggregator.com/'
186
+ );
187
+ $rate_us = sprintf(
188
+ __('Please <a href="%1$s" target="_blank">rate us</a>!', 'wprss'),
189
+ 'https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?filter=5#postform'
190
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
+ // Return the final text
193
+ return sprintf('<span class="wp-rss-footer-text">%1$s %2$s</span>', $thank_you, $rate_us);
194
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/black-friday-2021.php DELETED
@@ -1,28 +0,0 @@
1
- <?php
2
-
3
- add_action('admin_notices', function () {
4
- if (!wprss_is_wprss_page() || count(wprss_get_addons()) > 0) {
5
- return;
6
- }
7
-
8
- $year = (int) date('Y');
9
- $month = (int) date('n');
10
- $day = (int) date('j');
11
-
12
- if ($year !== 2021 || $month !== 11 || $day < 22 || $day > 29) {
13
- return;
14
- }
15
-
16
- printf(
17
- '<div class="notice notice-info">
18
- <p>
19
- %s
20
- <a href="https://www.wprssaggregator.com/pricing/" target="_blank"><b>%s</b></a>
21
- %s
22
- </p>
23
- </div>',
24
- __('Black Friday/Cyber Monday:', 'wprss'),
25
- __('Get 30% off WP RSS Aggregator plans today!', 'wprss'),
26
- __('Offer ends on the 29th of November.', 'wprss')
27
- );
28
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/cpt-feeds.php CHANGED
@@ -1,124 +1,101 @@
1
  <?php
2
 
3
- add_action('wp_head', 'wprss_cpt_feeds');
4
- /**
5
- * Adds Link tags to the head of the page, for CPTs' feeds.
6
- */
7
- function wprss_cpt_feeds()
8
- {
9
- // Get all post types
10
- $post_types = get_post_types([
11
- 'public' => true,
12
- '_builtin' => false,
13
- ]);
14
 
15
- // If current page is archive page for a particular post type
16
- if (is_post_type_archive()) {
17
- // Remove post type from the post types list
18
- unset($post_types[get_post_type()]);
19
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- // Filter which post types to use
22
- // False: none
23
- // True: all
24
- // Array: particular post types
25
- // String: Single post type
26
- $post_type_feeds = apply_filters('wprss_cpt_feeds', false);
27
- switch (gettype($post_type_feeds)) {
28
- // If it's a boolean ...
29
- case 'boolean':
30
- // If it is FALSE, exit function. Do nothing. Simply.
31
- if ($post_type_feeds === false) return;
32
- // Otherwise, if TRUE, no further action is needed.
33
- break;
34
- // If it's a string ...
35
- case 'string':
36
- // If the post type does not exist, stop
37
- if (!isset($post_types[$post_type_feeds])) return;
38
- // Otherwise, only use this post type
39
- $single = $post_types[$post_type_feeds];
40
- $post_types = [$single => $single];
41
- break;
42
- // If it's an array ...
43
- case 'array':
44
- $post_types = array_intersect($post_types, $post_type_feeds);
45
- break;
46
- // If any other type, stop.
47
- default:
48
- return;
49
- }
50
 
51
- // Get only the values of the post types
52
- $post_types = array_values($post_types);
 
53
 
54
- // Get the site name and RSS feed URL, parsed as an array
55
- $siteName = get_bloginfo("name");
56
- $feedURL = parse_url(get_bloginfo('rss2_url'));
 
57
 
58
- // Foreach post type
59
- foreach ($post_types as $i => $post_type) {
60
- // Get its RSS feed URL
61
- $feed = get_post_type_archive_feed_link($post_type);
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- // If it doesnt have one, use the internal WP feed URL using the post_type query arg
64
- if ($feed === '' || !is_string($feed)) {
65
- // Start with the feed URL of the site
66
- $feed = $feedURL;
67
- // If there are no query args, set to an empty string
68
- if (!isset($feed['query'])) {
69
- $feed['query'] = '';
70
- }
71
- // If the query is not empty, we need to add an ampersand
72
- if (strlen($feed['query']) > 0) {
73
- $feed['query'] .= '&';
74
- }
75
- // Add the post_type query arg
76
- $feed['query'] .= "post_type=$post_type";
77
- // Unparse the URL array into a string
78
- $feed = wprss_unparse_url($feed);
79
- }
80
 
81
- // Get the Post Type Pretty Name
82
- $obj = get_post_type_object($post_type);
83
- $name = $obj->labels->name;
 
 
84
 
85
- // Print the <link> tag
86
- $feedName = sprintf(__('%1$s &raquo; %2$s Feed', 'wprss'), $siteName, $name);
87
 
88
- printf(
89
- '<link rel="%1$s" type="%2$s" title="%3$s" href="%4$s" />',
90
- "alternate",
91
- "application/rss+xml",
92
- $feedName,
93
- $feed
94
- );
95
-
96
- echo "\n";
97
- }
98
- }
99
-
100
- if (!function_exists('wprss_unparse_url')) {
101
- function wprss_unparse_url($parsed_url)
102
- {
103
- $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
104
- $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
105
- $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
106
- $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
107
- $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
108
- $pass = ($user || $pass) ? "$pass@" : '';
109
- $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
110
- $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
111
- $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
112
-
113
- return implode('', [
114
- $scheme,
115
- $user,
116
- $pass,
117
- $host,
118
- $port,
119
- $path,
120
- $query,
121
- $fragment,
122
- ]);
123
- }
124
- }
1
  <?php
2
 
3
+ add_action( 'wp_head', 'wprss_cpt_feeds' );
4
+ /**
5
+ * Adds Link tags to the head of the page, for CPTs' feeds.
6
+ */
7
+ function wprss_cpt_feeds() {
8
+ // Get all post types
9
+ $post_types = get_post_types(array(
10
+ 'public' => true,
11
+ '_builtin' => false
12
+ ));
 
13
 
14
+ // If current page is archive page for a particular post type
15
+ if ( is_post_type_archive() ) {
16
+ // Remove post type from the post types list
17
+ unset( $post_types[ get_post_type() ] );
18
+ }
19
+
20
+ // Filter which post types to use
21
+ // False: none
22
+ // True: all
23
+ // Array: particular post types
24
+ // String: Single post type
25
+ $post_type_feeds = apply_filters( 'wprss_cpt_feeds', FALSE );
26
+ switch( gettype( $post_type_feeds ) ) {
27
+ // If it's a boolean ...
28
+ case 'boolean':
29
+ // If it is FALSE, exit function. Do nothing. Simply.
30
+ if ( $post_type_feeds === FALSE ) return;
31
+ // Otherwise, if TRUE, no further action is needed.
32
+ break;
33
+ // If it's a string ...
34
+ case 'string':
35
+ // If the post type does not exist, stop
36
+ if ( !isset( $post_types[ $post_type_feeds ] ) ) return;
37
+ // Otherwise, only use this post type
38
+ $single = $post_types[ $post_type_feeds ];
39
+ $post_types = array( $single => $single );
40
+ break;
41
+ // If it's an array ...
42
+ case 'array':
43
+ $post_types = array_intersect($post_types, $post_type_feeds);
44
+ break;
45
+ // If any other type, stop.
46
+ default: return;
47
+ }
48
 
49
+ // Get only the values of the post types
50
+ $post_types = array_values( $post_types );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ // Get the site name and RSS feed URL, parsed as an array
53
+ $siteName = get_bloginfo("name");
54
+ $feedURL = parse_url( get_bloginfo( 'rss2_url' ) );
55
 
56
+ // Foreach post type
57
+ foreach ( $post_types as $i => $post_type ) {
58
+ // Get its RSS feed URL
59
+ $feed = get_post_type_archive_feed_link( $post_type );
60
 
61
+ // If it doesnt have one, use the interal WP feed URL using the post_type query arg
62
+ if ( $feed === '' || !is_string( $feed ) ) {
63
+ // Start with the feed URL of the site
64
+ $feed = $feedURL;
65
+ // If there are no query args, set to an emprty string
66
+ if ( !isset( $feed['query'] ) )
67
+ $feed['query'] = '';
68
+ // If the query is not empty, we need to add an ampersand
69
+ if ( strlen( $feed['query'] ) > 0 )
70
+ $feed['query'] .= '&';
71
+ // Add the post_type query arg
72
+ $feed['query'] .= "post_type=$post_type";
73
+ // Unparse the URL array into a string
74
+ $feed = wprss_unparse_url( $feed );
75
+ }
76
 
77
+ // Get the Post Type Pretty Name
78
+ $obj = get_post_type_object( $post_type );
79
+ $name = $obj->labels->name;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
+ // Print the <link> tag
82
+ $feedname = sprintf( __( '%1$s &raquo; %2$s Feed', WPRSS_TEXT_DOMAIN ), $siteName, $name );
83
+ printf( __( '<link rel="%1$s" type="%2$s" title="%3$s" href="%4$s" />'."\n", WPRSS_TEXT_DOMAIN ),"alternate","application/rss+xml", $feedname, $feed );
84
+ }
85
+ }
86
 
 
 
87
 
88
+ if ( !function_exists('wprss_unparse_url') ) {
89
+ function wprss_unparse_url( $parsed_url ) {
90
+ $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
91
+ $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
92
+ $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
93
+ $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
94
+ $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
95
+ $pass = ($user || $pass) ? "$pass@" : '';
96
+ $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
97
+ $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
98
+ $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
99
+ return "$scheme$user$pass$host$port$path$query$fragment";
100
+ }
101
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/cron-jobs.php CHANGED
@@ -1,397 +1,319 @@
1
- <?php
2
-
3
- define('WPRA_FETCH_ALL_FEEDS_HOOK', 'wprss_fetch_all_feeds_hook');
4
- define('WPRA_FETCH_FEED_HOOK', 'wprss_fetch_single_feed_hook');
5
- define('WPRA_TRUNCATE_ITEMS_HOOK', 'wprss_truncate_posts_hook');
6
- define('WPRA_ACTIVATE_FEED_HOOK', 'wprss_activate_feed_schedule_hook');
7
- define('WPRA_PAUSE_FEED_HOOK', 'wprss_pause_feed_schedule_hook');
8
-
9
- define('WPRA_TRUNCATE_ITEMS_INTERVAL', 'daily');
10
-
11
- /**
12
- * Alias for add_action, primarily used for readability to distinguish between cron-events and normal hooks.
13
- *
14
- * @since 4.17
15
- *
16
- * @param string $cron The cron hook event.
17
- * @param callable $callback The callback to invoke for the cron.
18
- */
19
- function wpra_on_cron_do($cron, $callback)
20
- {
21
- add_action($cron, $callback);
22
- }
23
-
24
- // Cron events
25
- wpra_on_cron_do(WPRA_FETCH_ALL_FEEDS_HOOK, 'wprss_fetch_insert_all_feed_items_from_cron');
26
- wpra_on_cron_do(WPRA_TRUNCATE_ITEMS_HOOK, 'wprss_truncate_posts');
27
- wpra_on_cron_do(WPRA_ACTIVATE_FEED_HOOK, 'wprss_activate_feed_source');
28
- wpra_on_cron_do(WPRA_PAUSE_FEED_HOOK, 'wprss_pause_feed_source');
29
-
30
- // Initialize crons that must always be scheduled
31
- add_action('init', 'wpra_init_crons');
32
-
33
- // When a feed source is activated, schedule its fetch cron
34
- add_action('wprss_on_feed_source_activated', 'wprss_feed_source_update_start_schedule');
35
-
36
- // When a feed source is paused, cancel its fetch cron
37
- add_action('wprss_on_feed_source_paused', 'wprss_feed_source_update_stop_schedule');
38
-
39
- // Filter the possible cron intervals to add more options
40
- add_filter('cron_schedules', 'wprss_filter_cron_schedules');
41
-
42
- /**
43
- * Initializes the cron jobs.
44
- *
45
- * @since 4.17
46
- */
47
- function wpra_init_crons()
48
- {
49
- wprss_schedule_fetch_all_feeds_cron();
50
- wprss_schedule_truncate_posts_cron();
51
- }
52
-
53
- /**
54
- * Creates the cron to fetch feeds.
55
- *
56
- * @since 2.0
57
- */
58
- function wprss_schedule_fetch_all_feeds_cron()
59
- {
60
- // Check if the global fetch is scheduled
61
- if (wp_next_scheduled(WPRA_FETCH_ALL_FEEDS_HOOK)) {
62
- return;
63
- }
64
-
65
- // If the event is not scheduled, schedule it
66
- $interval = wprss_get_general_setting('cron_interval');
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 4.17
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
- *
91
- * @since 2.0
92
- */
93
- function wprss_schedule_truncate_posts_cron()
94
- {
95
- // Check if the truncatation cron is scheduled
96
- if (wp_next_scheduled(WPRA_TRUNCATE_ITEMS_HOOK)) {
97
- return;
98
- }
99
-
100
- // If not, schedule it
101
- wp_schedule_event(time(), WPRA_TRUNCATE_ITEMS_INTERVAL, WPRA_TRUNCATE_ITEMS_HOOK);
102
- }
103
-
104
- /**
105
- * Updates the feed processing cron job schedules.
106
- * Removes the current schedules and adds the ones in the feed source's meta.
107
- *
108
- * @since 3.8
109
- *
110
- * @param int $feed_id The id of the wprss_feed
111
- */
112
- function wprss_update_feed_processing_schedules($feed_id)
113
- {
114
- // Get the feed's activate and pause times
115
- $activate = get_post_meta($feed_id, 'wprss_activate_feed', true);
116
- $pause = get_post_meta($feed_id, 'wprss_pause_feed', true);
117
-
118
- // Parse as time strings
119
- $activate = wprss_strtotime($activate);
120
- $pause = wprss_strtotime($pause);
121
-
122
- if (!empty($activate)) {
123
- wpra_reschedule($activate, WPRA_ACTIVATE_FEED_HOOK, null, [$feed_id]);
124
- }
125
-
126
- if ($pause !== '') {
127
- wpra_reschedule($pause, WPRA_PAUSE_FEED_HOOK, null, [$feed_id]);
128
- }
129
- }
130
-
131
- /**
132
- * Starts the looping schedule for a feed source. Runs on a schedule
133
- *
134
- * @since 3.9
135
- *
136
- * @param int $feed_id The ID of the feed source
137
- */
138
- function wprss_feed_source_update_start_schedule($feed_id)
139
- {
140
- // Stop any currently scheduled update operations
141
- wprss_feed_source_update_stop_schedule($feed_id);
142
-
143
- // Get the interval
144
- $interval = get_post_meta($feed_id, 'wprss_update_interval', true);
145
- // Do nothing if the feed source has no update interval (not sure if possible) or if the interval
146
- // is set to global
147
- if ($interval === '' || $interval === wprss_get_default_feed_source_update_interval()) {
148
- return;
149
- }
150
-
151
- wp_schedule_event(time(), $interval, WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
152
- }
153
-
154
- /**
155
- * Stops any scheduled update operations for a feed source. Runs on a schedule.
156
- *
157
- * @since 3.9
158
- *
159
- * @param int $feed_id The ID of the feed source ( wprss_feed )
160
- */
161
- function wprss_feed_source_update_stop_schedule($feed_id)
162
- {
163
- $timestamp = wprss_get_next_feed_source_update($feed_id);
164
-
165
- // If a schedule exists, unschedule it
166
- if ($timestamp !== false) {
167
- wp_unschedule_event($timestamp, WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
168
- }
169
- }
170
-
171
- /**
172
- * Returns the timestamp for the next global update
173
- *
174
- * @since 4.18
175
- *
176
- * @return int The timestamp of the next global update operation, or false if no update is scheduled.
177
- */
178
- function wprss_get_next_global_update()
179
- {
180
- return wp_next_scheduled(WPRA_FETCH_ALL_FEEDS_HOOK, []);
181
- }
182
-
183
- /**
184
- * Returns the timestamp for the next feed source update
185
- *
186
- * @since 3.9
187
- *
188
- * @param int $feed_id The ID of the feed source ( wprss_feed )
189
- * @param bool $explicit If true, the function won't default to the global update if the feed doesn't use its own
190
- * update interval.
191
- *
192
- * @return int The timestamp of the next update operation, or false if no update is scheduled.
193
- */
194
- function wprss_get_next_feed_source_update($feed_id, $explicit = true)
195
- {
196
- $next = wp_next_scheduled(WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
197
-
198
- if ($explicit) {
199
- return $next;
200
- }
201
-
202
- $meta = get_post_meta($feed_id, 'wprss_update_interval', true);
203
-
204
- return (empty($meta) || $meta === wprss_get_default_feed_source_update_interval())
205
- ? wprss_get_next_global_update()
206
- : $next;
207
- }
208
-
209
- /**
210
- * Reschedules a cron event, unscheduling any existing matching crons.
211
- *
212
- * @since 4.17
213
- *
214
- * @param int $timestamp The timestamp.
215
- * @param string $event The hook event.
216
- * @param string|null $recurrence The recurrence.
217
- * @param array $args Additional args.
218
- */
219
- function wpra_reschedule($timestamp, $event, $recurrence = null, $args = [])
220
- {
221
- $existing = wp_next_scheduled($event, $args);
222
-
223
- if ($existing !== false) {
224
- wp_unschedule_event($existing, $event, $args);
225
- }
226
-
227
- if ($recurrence === null) {
228
- wp_schedule_single_event($timestamp, $event, $args);
229
- } else {
230
- wp_schedule_event($timestamp, $recurrence, $event, $args);
231
- }
232
- }
233
-
234
- /**
235
- * Clears all events scheduled to a particular hook, regardless of their args.
236
- *
237
- * @since 4.17.9
238
- *
239
- * @param string $hook
240
- */
241
- function wpra_clear_all_scheduled_hooks($hook)
242
- {
243
- foreach (wpra_get_crons() as $key => $events) {
244
- if ($key === $hook) {
245
- foreach ($events as $event) {
246
- wp_clear_scheduled_hook($key, $event->args);
247
- }
248
- }
249
- }
250
- }
251
-
252
- /**
253
- * Retrieves all cron jobs from WordPress.
254
- *
255
- * @since 4.17.9
256
- *
257
- * @return array A mapping of hook names to sub-arrays of even objects.
258
- */
259
- function wpra_get_crons()
260
- {
261
- $cronsArray = _get_cron_array();
262
- $crons = [];
263
- foreach ($cronsArray as $ts => $list) {
264
- foreach ($list as $hook => $events) {
265
- $crons[$hook] = isset($crons[$hook]) ? $crons[$hook] : [];
266
-
267
- foreach ($events as $event) {
268
- $crons[$hook][] = (object) $event;
269
- }
270
- }
271
- }
272
-
273
- return $crons;
274
- }
275
-
276
- /**
277
- * Retrieves the cron schedules that WPRA uses.
278
- *
279
- * @since 4.17
280
- *
281
- * @return array
282
- */
283
- function wpra_get_cron_schedules()
284
- {
285
- return [
286
- 'five_min' => array(
287
- 'display' => __('Once every 5 minutes', 'wprss'),
288
- 'interval' => MINUTE_IN_SECONDS * 5,
289
- ),
290
- 'ten_min' => array(
291
- 'display' => __('Once every 10 minutes', 'wprss'),
292
- 'interval' => MINUTE_IN_SECONDS * 10,
293
- ),
294
- 'fifteen_min' => array(
295
- 'display' => __('Once every 15 minutes', 'wprss'),
296
- 'interval' => MINUTE_IN_SECONDS * 15,
297
- ),
298
- 'thirty_min' => array(
299
- 'display' => __('Once every 30 minutes', 'wprss'),
300
- 'interval' => MINUTE_IN_SECONDS * 30,
301
- ),
302
- 'two_hours' => array(
303
- 'display' => __('Once every 2 hours', 'wprss'),
304
- 'interval' => HOUR_IN_SECONDS * 2,
305
- ),
306
- 'weekly' => array(
307
- 'display' => __('Once weekly', 'wprss'),
308
- 'interval' => WEEK_IN_SECONDS,
309
- ),
310
- ];
311
- }
312
-
313
- /**
314
- * Registers the cron schedules to WordPress, avoiding duplicates.
315
- *
316
- * @since 3.0
317
- */
318
- function wprss_filter_cron_schedules($schedules)
319
- {
320
- // Register each WPRA schedule
321
- $wpraSchedules = wpra_get_cron_schedules();
322
- foreach ($wpraSchedules as $key => $schedule) {
323
- // If the interval already exists, skip the schedule
324
- if (wprss_schedule_interval_already_exists($schedules, $schedule['interval'])) {
325
- continue;
326
- }
327
-
328
- $schedules[$key] = $schedule;
329
- }
330
-
331
- return $schedules;
332
- }
333
-
334
- /**
335
- * Checks if a schedule interval already exists in a given list os schedules.
336
- *
337
- * @see wprss_filter_cron_schedules()
338
- *
339
- * @param array $schedules The schedules to search in.
340
- * @param int $interval The interval to search for.
341
- *
342
- * @return bool
343
- */
344
- function wprss_schedule_interval_already_exists(array $schedules, $interval) {
345
- foreach ($schedules as $schedule) {
346
- if (isset($schedule['interval']) && $schedule['interval'] == $interval) {
347
- return true;
348
- }
349
- }
350
-
351
- return false;
352
- }
353
-
354
- /**
355
- * Deletes a custom cron schedule.
356
- *
357
- * Credits: WPCrontrol
358
- *
359
- * @since 3.7
360
- *
361
- * @param string $name The internal_name of the schedule to delete.
362
- */
363
- function wprss_delete_schedule($name)
364
- {
365
- $scheds = get_option('crontrol_schedules', array());
366
- unset($scheds[$name]);
367
- update_option('crontrol_schedules', $scheds);
368
- }
369
-
370
- /**
371
- * Parses the date time string into a UTC timestamp.
372
- * The string must be in the format: m/d/y h:m:s
373
- *
374
- * @since 3.9
375
- */
376
- function wprss_strtotime($str)
377
- {
378
- if (empty($str)) {
379
- return 0;
380
- }
381
-
382
- $parts = explode(' ', $str);
383
- $date = explode('/', $parts[0]);
384
- $time = explode(':', $parts[1]);
385
-
386
- return mktime($time[0], $time[1], $time[2], $date[1], $date[0], $date[2]);
387
- }
388
-
389
- /**
390
- * Returns the default value for the per feed source update interval
391
- *
392
- * @since 3.9
393
- */
394
- function wprss_get_default_feed_source_update_interval()
395
- {
396
- return 'global';
397
- }
1
+ <?php
2
+
3
+ define('WPRA_FETCH_ALL_FEEDS_HOOK', 'wprss_fetch_all_feeds_hook');
4
+ define('WPRA_FETCH_FEED_HOOK', 'wprss_fetch_single_feed_hook');
5
+ define('WPRA_TRUNCATE_ITEMS_HOOK', 'wprss_truncate_posts_hook');
6
+ define('WPRA_ACTIVATE_FEED_HOOK', 'wprss_activate_feed_schedule_hook');
7
+ define('WPRA_PAUSE_FEED_HOOK', 'wprss_pause_feed_schedule_hook');
8
+
9
+ define('WPRA_TRUNCATE_ITEMS_INTERVAL', 'daily');
10
+
11
+ /**
12
+ * Alias for add_action, primarily used for readability to distinguish between cron-events and normal hooks.
13
+ *
14
+ * @since 4.17
15
+ *
16
+ * @param string $cron The cron hook event.
17
+ * @param callable $callback The callback to invoke for the cron.
18
+ */
19
+ function wpra_on_cron_do($cron, $callback)
20
+ {
21
+ add_action($cron, $callback);
22
+ }
23
+
24
+ // Cron events
25
+ wpra_on_cron_do(WPRA_FETCH_ALL_FEEDS_HOOK, 'wprss_fetch_insert_all_feed_items_from_cron');
26
+ wpra_on_cron_do(WPRA_TRUNCATE_ITEMS_HOOK, 'wprss_truncate_posts');
27
+ wpra_on_cron_do(WPRA_ACTIVATE_FEED_HOOK, 'wprss_activate_feed_source');
28
+ wpra_on_cron_do(WPRA_PAUSE_FEED_HOOK, 'wprss_pause_feed_source');
29
+
30
+ // Initialize crons that must always be scheduled
31
+ add_action('init', 'wpra_init_crons');
32
+
33
+ // When a feed source is activated, schedule its fetch cron
34
+ add_action('wprss_on_feed_source_activated', 'wprss_feed_source_update_start_schedule');
35
+
36
+ // When a feed source is paused, cancel its fetch cron
37
+ add_action('wprss_on_feed_source_paused', 'wprss_feed_source_update_stop_schedule');
38
+
39
+ // Filter the possible cron intervals to add more options
40
+ add_filter('cron_schedules', 'wprss_filter_cron_schedules');
41
+
42
+ /**
43
+ * Initializes the cron jobs.
44
+ *
45
+ * @since 4.17
46
+ */
47
+ function wpra_init_crons()
48
+ {
49
+ wprss_schedule_fetch_all_feeds_cron();
50
+ wprss_schedule_truncate_posts_cron();
51
+ }
52
+
53
+ /**
54
+ * Creates the cron to fetch feeds.
55
+ *
56
+ * @since 2.0
57
+ */
58
+ function wprss_schedule_fetch_all_feeds_cron()
59
+ {
60
+ // Check if the global fetch is scheduled
61
+ if (wp_next_scheduled(WPRA_FETCH_ALL_FEEDS_HOOK)) {
62
+ return;
63
+ }
64
+
65
+ // If the event is not scheduled, schedule it
66
+ $interval = wprss_get_general_setting('cron_interval');
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 4.17
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
+ *
91
+ * @since 2.0
92
+ */
93
+ function wprss_schedule_truncate_posts_cron()
94
+ {
95
+ // Check if the truncatation cron is scheduled
96
+ if (wp_next_scheduled(WPRA_TRUNCATE_ITEMS_HOOK)) {
97
+ return;
98
+ }
99
+
100
+ // If not, schedule it
101
+ wp_schedule_event(time(), WPRA_TRUNCATE_ITEMS_INTERVAL, WPRA_TRUNCATE_ITEMS_HOOK);
102
+ }
103
+
104
+ /**
105
+ * Updates the feed processing cron job schedules.
106
+ * Removes the current schedules and adds the ones in the feed source's meta.
107
+ *
108
+ * @since 3.8
109
+ *
110
+ * @param int $feed_id The id of the wprss_feed
111
+ */
112
+ function wprss_update_feed_processing_schedules($feed_id)
113
+ {
114
+ // Get the feed's activate and pause times
115
+ $activate = get_post_meta($feed_id, 'wprss_activate_feed', true);
116
+ $pause = get_post_meta($feed_id, 'wprss_pause_feed', true);
117
+
118
+ // Parse as time strings
119
+ $activate = wprss_strtotime($activate);
120
+ $pause = wprss_strtotime($pause);
121
+
122
+ if (!empty($activate)) {
123
+ wpra_reschedule($activate, WPRA_ACTIVATE_FEED_HOOK, null, [$feed_id]);
124
+ }
125
+
126
+ if ($pause !== '') {
127
+ wpra_reschedule($pause, WPRA_PAUSE_FEED_HOOK, null, [$feed_id]);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Starts the looping schedule for a feed source. Runs on a schedule
133
+ *
134
+ * @since 3.9
135
+ *
136
+ * @param int $feed_id The ID of the feed source
137
+ */
138
+ function wprss_feed_source_update_start_schedule($feed_id)
139
+ {
140
+ // Stop any currently scheduled update operations
141
+ wprss_feed_source_update_stop_schedule($feed_id);
142
+
143
+ // Get the interval
144
+ $interval = get_post_meta($feed_id, 'wprss_update_interval', true);
145
+ // Do nothing if the feed source has no update interval (not sure if possible) or if the interval
146
+ // is set to global
147
+ if ($interval === '' || $interval === wprss_get_default_feed_source_update_interval()) {
148
+ return;
149
+ }
150
+
151
+ wp_schedule_event(time(), $interval, WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
152
+ }
153
+
154
+ /**
155
+ * Stops any scheduled update operations for a feed source. Runs on a schedule.
156
+ *
157
+ * @since 3.9
158
+ *
159
+ * @param int $feed_id The ID of the feed source ( wprss_feed )
160
+ */
161
+ function wprss_feed_source_update_stop_schedule($feed_id)
162
+ {
163
+ $timestamp = wprss_get_next_feed_source_update($feed_id);
164
+
165
+ // If a schedule exists, unschedule it
166
+ if ($timestamp !== false) {
167
+ wp_unschedule_event($timestamp, WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Returns the timestamp for the next feed source update
173
+ *
174
+ * @since 3.9
175
+ *
176
+ * @param int $feed_id The ID of the feed source ( wprss_feed )
177
+ *
178
+ * @return int The timestamp of the next update operation, or false is no
179
+ * update is scheduled.
180
+ */
181
+ function wprss_get_next_feed_source_update($feed_id)
182
+ {
183
+ return wp_next_scheduled(WPRA_FETCH_FEED_HOOK, [strval($feed_id)]);
184
+ }
185
+
186
+ /**
187
+ * Reschedules a cron event, unscheduling any existing matching crons.
188
+ *
189
+ * @since 4.17
190
+ *
191
+ * @param int $timestamp The timestamp.
192
+ * @param string $event The hook event.
193
+ * @param string|null $recurrence The recurrence.
194
+ * @param array $args Additional args.
195
+ */
196
+ function wpra_reschedule($timestamp, $event, $recurrence = null, $args = [])
197
+ {
198
+ $existing = wp_next_scheduled($event, $args);
199
+
200
+ if ($existing !== false) {
201
+ wp_unschedule_event($existing, $event, $args);
202
+ }
203
+
204
+ if ($recurrence === null) {
205
+ wp_schedule_single_event($timestamp, $event, $args);
206
+ } else {
207
+ wp_schedule_event($timestamp, $recurrence, $event, $args);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Retrieves the cron schedules that WPRA uses.
213
+ *
214
+ * @since 4.17
215
+ *
216
+ * @return array
217
+ */
218
+ function wpra_get_cron_schedules()
219
+ {
220
+ return [
221
+ 'five_min' => array(
222
+ 'display' => __('Once every 5 minutes', 'wprss'),
223
+ 'interval' => MINUTE_IN_SECONDS * 5,
224
+ ),
225
+ 'ten_min' => array(
226
+ 'display' => __('Once every 10 minutes', 'wprss'),
227
+ 'interval' => MINUTE_IN_SECONDS * 10,
228
+ ),
229
+ 'fifteen_min' => array(
230
+ 'display' => __('Once every 15 minutes', 'wprss'),
231
+ 'interval' => MINUTE_IN_SECONDS * 15,
232
+ ),
233
+ 'thirty_min' => array(
234
+ 'display' => __('Once every 30 minutes', 'wprss'),
235
+ 'interval' => MINUTE_IN_SECONDS * 30,
236
+ ),
237
+ 'two_hours' => array(
238
+ 'display' => __('Once every 2 hours', 'wprss'),
239
+ 'interval' => HOUR_IN_SECONDS * 2,
240
+ ),
241
+ 'weekly' => array(
242
+ 'display' => __('Once weekly', 'wprss'),
243
+ 'interval' => WEEK_IN_SECONDS,
244
+ ),
245
+ ];
246
+ }
247
+
248
+ /**
249
+ * Registers the cron schedules to WordPress, avoiding duplicates.
250
+ *
251
+ * @since 3.0
252
+ */
253
+ function wprss_filter_cron_schedules($schedules)
254
+ {
255
+ // Pluck out the intervals
256
+ $intervals = array_map(function ($schedule) {
257
+ return $schedule['interval'];
258
+ }, $schedules);
259
+ // Get a map of intervals -> keys for fast interval lookup
260
+ $intervalsMap = array_flip($intervals);
261
+
262
+ // Register each WPRA schedule
263
+ $wpraSchedules = wpra_get_cron_schedules();
264
+ foreach ($wpraSchedules as $key => $schedule) {
265
+ // If the interval already exists, skip the schedule
266
+ if (array_key_exists($schedule['interval'], $intervalsMap)) {
267
+ continue;
268
+ }
269
+
270
+ $schedules[$key] = $schedule;
271
+ }
272
+
273
+ return $schedules;
274
+ }
275
+
276
+ /**
277
+ * Deletes a custom cron schedule.
278
+ *
279
+ * Credits: WPCrontrol
280
+ *
281
+ * @since 3.7
282
+ *
283
+ * @param string $name The internal_name of the schedule to delete.
284
+ */
285
+ function wprss_delete_schedule($name)
286
+ {
287
+ $scheds = get_option('crontrol_schedules', array());
288
+ unset($scheds[$name]);
289
+ update_option('crontrol_schedules', $scheds);
290
+ }
291
+
292
+ /**
293
+ * Parses the date time string into a UTC timestamp.
294
+ * The string must be in the format: m/d/y h:m:s
295
+ *
296
+ * @since 3.9
297
+ */
298
+ function wprss_strtotime($str)
299
+ {
300
+ if (empty($str)) {
301
+ return 0;
302
+ }
303
+
304
+ $parts = explode(' ', $str);
305
+ $date = explode('/', $parts[0]);
306
+ $time = explode(':', $parts[1]);
307
+
308
+ return mktime($time[0], $time[1], $time[2], $date[1], $date[0], $date[2]);
309
+ }
310
+
311
+ /**
312
+ * Returns the default value for the per feed source update interval
313
+ *
314
+ * @since 3.9
315
+ */
316
+ function wprss_get_default_feed_source_update_interval()
317
+ {
318
+ return 'global';
319
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/fallback-mbstring.php CHANGED
@@ -196,7 +196,7 @@ class WPRSS_MBString {
196
  * Taken from {@link https://github.com/drupal/drupal/blob/9.x/core/includes/unicode.inc#L432 here}.
197
  *
198
  * @since 4.7
199
- * @param string $text The string to run the operation on.
200
  * @return string The string in lowercase.
201
  */
202
  public static function mb_strtolower( $text ) {
196
  * Taken from {@link https://github.com/drupal/drupal/blob/9.x/core/includes/unicode.inc#L432 here}.
197
  *
198
  * @since 4.7
199
+ * @param $text The string to run the operation on.
200
  * @return string The string in lowercase.
201
  */
202
  public static function mb_strtolower( $text ) {
includes/feed-access.php CHANGED
@@ -10,7 +10,6 @@ class WPRSS_Feed_Access
10
  {
11
 
12
  const RESOURCE_CLASS = 'WPRSS_SimplePie_File';
13
- const ITEM_CLASS = 'WPRSS_SimplePie_Item';
14
  const D_REDIRECTS = 5;
15
 
16
  const SETTING_KEY_CERTIFICATE_PATH = 'certificate-path';
@@ -172,7 +171,6 @@ class WPRSS_Feed_Access
172
  */
173
  public function set_feed_options($feed, $feedSourceId = null)
174
  {
175
- $feed->set_item_class(static::ITEM_CLASS);
176
  $feed->set_file_class( static::RESOURCE_CLASS );
177
  $feed->set_useragent($this->get_useragent($feedSourceId));
178
  WPRSS_SimplePie_File::set_default_certificate_file_path($this->get_certificate_file_path());
@@ -200,17 +198,17 @@ class WPRSS_Feed_Access
200
  */
201
  public function add_settings( $settings ) {
202
  $settings['advanced'][ self::SETTING_KEY_CERTIFICATE_PATH ] = array(
203
- 'label' => __( 'Certificate path', 'wprss' ),
204
  'callback' => array( $this, 'render_certificate_path_setting' )
205
  );
206
  /* @since 4.8.2 */
207
  $settings['advanced'][ self::SETTING_KEY_FEED_REQUEST_USERAGENT ] = array(
208
- 'label' => __( 'Feed request useragent', 'wprss' ),
209
  'callback' => array( $this, 'render_feed_request_useragent_setting' )
210
  );
211
  /* @since 4.14.1 */
212
  $settings['advanced'][ self::SETTING_KEY_CACHE ] = array(
213
- 'label' => __( 'Enable feed cache', 'wprss' ),
214
  'callback' => array( $this, 'render_feed_cache_setting' )
215
  );
216
 
@@ -245,15 +243,10 @@ class WPRSS_Feed_Access
245
  * @param array $field Data of this field.
246
  */
247
  public function render_certificate_path_setting( $field ) {
248
- $feed_limit = wprss_get_general_setting($field['field_id']);
249
-
250
- printf(
251
- '<input type="text" id="%1$s" name="wprss_settings_general[%1$s]" value="%2$s" />',
252
- esc_attr($field['field_id']),
253
- esc_attr($feed_limit)
254
- );
255
-
256
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
257
  }
258
 
259
  /**
@@ -265,16 +258,10 @@ class WPRSS_Feed_Access
265
  */
266
  public function render_feed_request_useragent_setting( $field )
267
  {
268
- $value = wprss_get_general_setting($field['field_id']);
269
-
270
- printf(
271
- '<input type="text" id="%1$s" name="wprss_settings_general[%1$s]" value="%2$s" placeholder="%3$s" />',
272
- esc_attr($field['field_id']),
273
- esc_attr($value),
274
- __('Default', 'wprss')
275
- );
276
-
277
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
278
  }
279
 
280
  /**
@@ -287,19 +274,15 @@ class WPRSS_Feed_Access
287
  public function render_feed_cache_setting( $field )
288
  {
289
  $value = (int) wprss_get_general_setting($field['field_id']);
290
-
291
- printf(
292
- '<input name="wprss_settings_general[%s]" type="hidden" value="0" />',
293
- esc_attr($field['field_id'])
294
- );
295
-
296
- printf(
297
- '<input type="checkbox" value="1" id="%1$s" name="wprss_settings_general[%1$s]" %2$s />',
298
- esc_attr($field['field_id']),
299
- checked(1, $value, false)
300
- );
301
-
302
- echo wprss_settings_inline_help($field['field_id'], $field['tooltip']);
303
  }
304
 
305
  /**
@@ -384,18 +367,6 @@ add_action('wprss_init', function() {
384
  WPRSS_Feed_Access::instance();
385
  });
386
 
387
- class WPRSS_SimplePie_Item extends SimplePie_Item {
388
-
389
- public function sanitize($data, $type, $base = '')
390
- {
391
- if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML | SIMPLEPIE_CONSTRUCT_MAYBE_HTML)) {
392
- return $data;
393
- }
394
-
395
- return parent::sanitize($data, $type, $base);
396
- }
397
- }
398
-
399
 
400
  /**
401
  * A padding layer used to give WPRSS more control over fetching of feed resources.
@@ -445,6 +416,7 @@ class WPRSS_SimplePie_File extends SimplePie_File {
445
  curl_setopt( $fp, CURLOPT_RETURNTRANSFER, 1 );
446
  curl_setopt( $fp, CURLOPT_TIMEOUT, $timeout );
447
  curl_setopt( $fp, CURLOPT_CONNECTTIMEOUT, $timeout );
 
448
  curl_setopt( $fp, CURLOPT_USERAGENT, $useragent );
449
  curl_setopt( $fp, CURLOPT_HTTPHEADER, $headers2 );
450
  if ( !ini_get( 'open_basedir' ) && !ini_get( 'safe_mode' ) && version_compare( SimplePie_Misc::get_curl_version(), '7.15.2', '>=' ) ) {
10
  {
11
 
12
  const RESOURCE_CLASS = 'WPRSS_SimplePie_File';
 
13
  const D_REDIRECTS = 5;
14
 
15
  const SETTING_KEY_CERTIFICATE_PATH = 'certificate-path';
171
  */
172
  public function set_feed_options($feed, $feedSourceId = null)
173
  {
 
174
  $feed->set_file_class( static::RESOURCE_CLASS );
175
  $feed->set_useragent($this->get_useragent($feedSourceId));
176
  WPRSS_SimplePie_File::set_default_certificate_file_path($this->get_certificate_file_path());
198
  */
199
  public function add_settings( $settings ) {
200
  $settings['advanced'][ self::SETTING_KEY_CERTIFICATE_PATH ] = array(
201
+ 'label' => __( 'Certificate path', WPRSS_TEXT_DOMAIN ),
202
  'callback' => array( $this, 'render_certificate_path_setting' )
203
  );
204
  /* @since 4.8.2 */
205
  $settings['advanced'][ self::SETTING_KEY_FEED_REQUEST_USERAGENT ] = array(
206
+ 'label' => __( 'Feed request useragent', WPRSS_TEXT_DOMAIN ),
207
  'callback' => array( $this, 'render_feed_request_useragent_setting' )
208
  );
209
  /* @since 4.14.1 */
210
  $settings['advanced'][ self::SETTING_KEY_CACHE ] = array(
211
+ 'label' => __( 'Enable feed cache', WPRSS_TEXT_DOMAIN ),
212
  'callback' => array( $this, 'render_feed_cache_setting' )
213
  );
214
 
243
  * @param array $field Data of this field.
244
  */
245
  public function render_certificate_path_setting( $field ) {
246
+ $feed_limit = wprss_get_general_setting( $field['field_id'] );
247
+ ?>
248
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[<?php echo $field['field_id'] ?>]" type="text" value="<?php echo $feed_limit ?>" />
249
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
250
  }
251
 
252
  /**
258
  */
259
  public function render_feed_request_useragent_setting( $field )
260
  {
261
+ $value = wprss_get_general_setting( $field['field_id'] );
262
+ ?>
263
+ <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[<?php echo $field['field_id'] ?>]" type="text" value="<?php echo $value ?>" placeholder="<?php echo __('Default', WPRSS_TEXT_DOMAIN) ?>" />
264
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
 
265
  }
266
 
267
  /**
274
  public function render_feed_cache_setting( $field )
275
  {
276
  $value = (int) wprss_get_general_setting($field['field_id']);
277
+ ?>
278
+ <input name="wprss_settings_general[<?= $field['field_id'] ?>]" type="hidden" value="0" />
279
+ <input id="<?= $field['field_id'] ?>"
280
+ name="wprss_settings_general[<?= $field['field_id'] ?>]"
281
+ type="checkbox"
282
+ value="1"
283
+ <?= checked(1, $value, false) ?>
284
+ />
285
+ <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
286
  }
287
 
288
  /**
367
  WPRSS_Feed_Access::instance();
368
  });
369
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
  /**
372
  * A padding layer used to give WPRSS more control over fetching of feed resources.
416
  curl_setopt( $fp, CURLOPT_RETURNTRANSFER, 1 );
417
  curl_setopt( $fp, CURLOPT_TIMEOUT, $timeout );
418
  curl_setopt( $fp, CURLOPT_CONNECTTIMEOUT, $timeout );
419
+ curl_setopt( $fp, CURLOPT_REFERER, $url );
420
  curl_setopt( $fp, CURLOPT_USERAGENT, $useragent );
421
  curl_setopt( $fp, CURLOPT_HTTPHEADER, $headers2 );
422
  if ( !ini_get( 'open_basedir' ) && !ini_get( 'safe_mode' ) && version_compare( SimplePie_Misc::get_curl_version(), '7.15.2', '>=' ) ) {
includes/feed-blacklist.php CHANGED
@@ -82,42 +82,34 @@ function wprss_is_blacklisted($permalink)
82
  */
83
  function wprss_check_if_blacklist_item()
84
  {
85
- // Get the ID from the GET param
86
- $id = filter_input(INPUT_GET, 'wprss_blacklist', FILTER_VALIDATE_INT);
87
- if (empty($id)) {
88
  return;
89
  }
90
 
 
 
91
  // If the post does not exist, stop. Show a message
92
- $post = (is_int($id) && $id > 0)
93
- ? get_post($id)
94
- : null;
95
- if ($post === null) {
96
  wp_die(__('The item you are trying to blacklist does not exist', 'wprss'));
97
  }
98
 
99
  // If the post type is not correct,
100
- if (get_post_meta($id, 'wprss_item_permalink', true) === '' || $post->post_status !== 'trash') {
101
  wp_die(__('The item you are trying to blacklist is not valid!', 'wprss'));
102
  }
103
 
104
- check_admin_referer('blacklist-item-' . $id, 'wprss_blacklist_item');
105
- wprss_blacklist_item($id);
106
 
107
  // Get the current post type for the current page
108
- $postType = filter_input(INPUT_GET, 'post_type', FILTER_SANITIZE_STRING);
109
- $postType = $postType ? $postType : 'post';
110
-
111
  // Check the current page, and generate the URL query string for the page
112
- $paged = filter_input(INPUT_GET, 'paged', FILTER_VALIDATE_INT);
113
- $pagedArg = $paged
114
- ? '&paged=' . urlencode($paged)
115
- : '';
116
-
117
  // Set the notice transient
118
  set_transient('wprss_item_blacklist_notice', 'true');
119
  // Refresh the page without the GET parameter
120
- wp_redirect(admin_url("edit.php?post_type=$postType&post_status=trash" . $pagedArg));
121
 
122
  exit;
123
  }
@@ -152,9 +144,8 @@ function wprss_check_notice_transient()
152
  function wprss_blacklist_row_actions($actions)
153
  {
154
  // Check the current page, and generate the URL query string for the page
155
- $paged = filter_input(INPUT_GET, 'paged', FILTER_VALIDATE_INT);
156
- $pagedArg = is_int($paged) && $paged > 0
157
- ? '&paged=' . urlencode($paged)
158
  : '';
159
 
160
  // Check the post type
@@ -179,7 +170,7 @@ function wprss_blacklist_row_actions($actions)
179
  admin_url("edit.php?post_type=$post_type&wprss_blacklist=$ID"),
180
  $ID
181
  );
182
- $plain_url = $plain_url . $pagedArg;
183
  // Add a nonce to the URL
184
  $nonced_url = wp_nonce_url($plain_url, 'blacklist-item-' . $ID, 'wprss_blacklist_item');
185
 
82
  */
83
  function wprss_check_if_blacklist_item()
84
  {
85
+ // If the GET param is not set, do nothing. Return.
86
+ if (empty($_GET['wprss_blacklist'])) {
 
87
  return;
88
  }
89
 
90
+ // Get the ID from the GET param
91
+ $ID = $_GET['wprss_blacklist'];
92
  // If the post does not exist, stop. Show a message
93
+ if (get_post($ID) === null) {
 
 
 
94
  wp_die(__('The item you are trying to blacklist does not exist', 'wprss'));
95
  }
96
 
97
  // If the post type is not correct,
98
+ if (get_post_meta($ID, 'wprss_item_permalink', true) === '' || get_post_status($ID) !== 'trash') {
99
  wp_die(__('The item you are trying to blacklist is not valid!', 'wprss'));
100
  }
101
 
102
+ check_admin_referer('blacklist-item-' . $ID, 'wprss_blacklist_item');
103
+ wprss_blacklist_item($ID);
104
 
105
  // Get the current post type for the current page
106
+ $post_type = isset($_GET['post_type']) ? $_GET['post_type'] : 'post';
 
 
107
  // Check the current page, and generate the URL query string for the page
108
+ $paged = isset($_GET['paged']) ? '&paged=' . $_GET['paged'] : '';
 
 
 
 
109
  // Set the notice transient
110
  set_transient('wprss_item_blacklist_notice', 'true');
111
  // Refresh the page without the GET parameter
112
+ wp_redirect(admin_url("edit.php?post_type=$post_type&post_status=trash" . $paged));
113
 
114
  exit;
115
  }
144
  function wprss_blacklist_row_actions($actions)
145
  {
146
  // Check the current page, and generate the URL query string for the page
147
+ $paged = isset($_GET['paged'])
148
+ ? sprintf('&paged=%s', $_GET['paged'])
 
149
  : '';
150
 
151
  // Check the post type
170
  admin_url("edit.php?post_type=$post_type&wprss_blacklist=$ID"),
171
  $ID
172
  );
173
+ $plain_url = $plain_url . $paged;
174
  // Add a nonce to the URL
175
  $nonced_url = wp_nonce_url($plain_url, 'blacklist-item-' . $ID, 'wprss_blacklist_item');
176
 
includes/feed-importing-images.php CHANGED
@@ -5,8 +5,7 @@ use Psr\Log\LoggerInterface;
5
  use RebelCode\Wpra\Core\Data\DataSetInterface;
6
  use RebelCode\Wpra\Core\Logger\FeedLoggerInterface;
7
 
8
- class Wpra_Rss_Namespace
9
- {
10
  const ITUNES = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
11
  }
12
 
@@ -24,9 +23,9 @@ add_filter('wprss_ftp_post_meta', function ($meta, $id, $source, $item) {
24
  * The "import" process here basically just fetches the images from the item's content/excerpt, the media:thumbnail
25
  * tag and the enclosures. The entire list of images is saved, along with the URL of the best image.
26
  *
27
- * @param int|string $itemId The ID of the feed item.
28
- * @param SimplePie_Item $item The simple pie item object.
29
- * @param int|string $sourceId The ID of the feed source from which the item was imported.
30
  */
31
  function wpra_detect_item_type($itemId, $item, $sourceId)
32
  {
@@ -71,9 +70,9 @@ function wpra_get_images_logger($feedId = null)
71
  * The "import" process here basically just fetches the images from the item's content/excerpt, the media:thumbnail
72
  * tag and the enclosures. The entire list of images is saved, along with the URL of the best image.
73
  *
74
- * @param int|string $itemId The ID of the feed item.
75
- * @param SimplePie_Item $item The simple pie item object.
76
- * @param int|string $sourceId The ID of the feed source from which the item was imported.
77
  */
78
  function wpra_import_item_images($itemId, $item, $sourceId)
79
  {
@@ -112,7 +111,8 @@ function wpra_import_item_images($itemId, $item, $sourceId)
112
  // If the featured image importing feature is enabled, import the featured image
113
  if (wpra_image_feature_enabled('import_ft_images')) {
114
  $ftImageUrl = null;
115
- switch ($ftImageOpt) {
 
116
  case 'auto':
117
  if (!empty($bestImage)) {
118
  $ftImageUrl = $bestImage;
@@ -172,9 +172,9 @@ function wpra_import_item_images($itemId, $item, $sourceId)
172
 
173
  if ($usedDefault) {
174
  update_post_meta($itemId, 'wprss_item_is_using_def_image', '1');
175
- $logger->notice('Used the feed source\'s default featured image for "{0}"', [$title]);
176
  } else {
177
- $logger->notice('No featured image was found for item "{0}"', [$title]);
178
  }
179
  }
180
  } else {
@@ -187,7 +187,7 @@ function wpra_import_item_images($itemId, $item, $sourceId)
187
 
188
  wp_update_post([
189
  'ID' => $itemId,
190
- 'post_content' => $newContent,
191
  ]);
192
  }
193
  }
@@ -208,7 +208,7 @@ function wpra_import_item_images($itemId, $item, $sourceId)
208
  // Update the post content
209
  wp_update_post([
210
  'ID' => $itemId,
211
- 'post_content' => $content,
212
  ]);
213
  }
214
 
@@ -262,40 +262,23 @@ function wpra_download_item_images($images, $postId)
262
  */
263
  function wpra_get_item_images($item)
264
  {
265
- return apply_filters('wpra/images/detect_from_item', [
266
- 'thumbnail' => array_filter([wpra_get_sp_thumbnail_image($item)]),
267
- 'image' => wpra_get_item_rss_images($item),
268
- 'media' => [wpra_get_item_media_thumbnail_image($item)],
269
- 'enclosure' => wpra_get_item_enclosure_images($item),
270
- 'content' => wpra_get_item_content_images($item),
271
- 'itunes' => wpra_get_item_itunes_images($item),
272
- 'feed' => array_filter([$item->get_feed()->get_image_url()]),
273
- ], $item);
274
- }
275
-
276
- /**
277
- * Retrieves the thumbnail as determined by SimplePie.
278
- *
279
- * @param SimplePie_Item $item
280
- *
281
- * @return string|null
282
- */
283
- function wpra_get_sp_thumbnail_image($item)
284
- {
285
- $thumbnail = $item->get_thumbnail();
286
 
287
- if (!is_array($thumbnail) || !isset($thumbnail['url'])) {
288
- return null;
289
- }
 
 
290
 
291
- return $thumbnail['url'];
292
  }
293
 
294
  /**
295
  * Processes a list of image URLs to strip away images that are unreachable or too small, as well as identify which
296
  * image in the list is the best image (in terms of dimensions and aspect ratio).
297
  *
298
- * @param array $images The image URLs.
299
  * @param array|DataSetInterface $source The feed source data set.
300
  * @param string|null $bestImage This variable given as this parameter will be set to the URL of
301
  * the best found image.
@@ -319,17 +302,14 @@ function wpra_process_images($images, $source, &$bestImage = null)
319
  $minWidth = 0;
320
  $minHeight = 0;
321
  if (wpra_image_feature_enabled('image_min_size')) {
322
- $minWidth = (int) apply_filters('wprss_thumbnail_min_width', $source['image_min_width']);
323
- $minHeight = (int) apply_filters('wprss_thumbnail_min_height', $source['image_min_height']);
324
  }
325
 
326
  foreach ($images as $group => $urls) {
327
  foreach ($urls as $imageUrl) {
328
- if (empty($imageUrl)) {
329
- continue;
330
- }
331
  try {
332
- /* @var WPRSS_Image_Cache_Image $tmp_img */
333
  $tmp_img = $imgContainer->get($imageUrl);
334
 
335
  $dimensions = ($tmp = $tmp_img->get_local_path())
@@ -381,28 +361,6 @@ function wpra_process_images($images, $source, &$bestImage = null)
381
  return $finalImages;
382
  }
383
 
384
- /**
385
- * Returns the images from the RSS <image> tags for the given feed item.
386
- *
387
- * @param SimplePie_Item $item The feed item
388
- *
389
- * @return array The string URLs of the images.
390
- */
391
- function wpra_get_item_rss_images($item)
392
- {
393
- if (isset($item->data['child']['']['image'])) {
394
- $imageTags = $item->data['child']['']['image'];
395
-
396
- $urls = array_map(function ($tag) {
397
- return isset($tag['data']) ? trim($tag['data']) : null;
398
- }, $imageTags);
399
-
400
- return array_filter($urls);
401
- }
402
-
403
- return [];
404
- }
405
-
406
  /**
407
  * Returns the <media:thumbnail> image for the given feed item.
408
  *
@@ -422,25 +380,32 @@ function wpra_get_item_media_thumbnail_image($item)
422
  return null;
423
  }
424
 
425
- // Stop if enclosure is an audio file
426
- // Prevents podcast stats from being tainted
427
  $type = $enclosure->get_type();
428
- if (empty($type) || stripos($type, 'audio/') === 0) {
429
  return null;
430
  }
431
 
432
- $urlsToTry = [
433
- $enclosure->get_link(),
434
- $enclosure->get_thumbnail(),
435
- ];
 
436
 
437
- foreach ($urlsToTry as $url) {
438
- // Check if image can be downloaded
439
- if (!empty($url) && wpra_is_url_an_image($url)) {
440
- return $url;
 
 
 
441
  }
442
  }
443
 
 
 
 
 
444
  return null;
445
  }
446
 
@@ -455,30 +420,17 @@ function wpra_get_item_media_thumbnail_image($item)
455
  */
456
  function wpra_get_item_enclosure_images($item)
457
  {
458
- $images = [];
459
-
460
- foreach ($item->get_enclosures() as $enclosure) {
461
- // Continue if enclosure is an audio file
462
- // Prevents podcast stats from being tainted
463
- if ($enclosure === null || stripos($enclosure->get_type(), 'audio/') === 0) {
464
- continue;
465
- }
466
-
467
- $thumbnails = $enclosure->get_thumbnails();
468
- $thumbnails = is_array($thumbnails) ? $thumbnails : [];
469
-
470
- foreach ($thumbnails as $thumbnail) {
471
- if (empty($thumbnail)) {
472
- continue;
473
- }
474
 
475
- if (wpra_is_url_an_image($thumbnail)) {
476
- $images[] = $thumbnail;
477
- }
478
- }
479
  }
480
 
481
- return $images;
 
 
 
482
  }
483
 
484
  /**
@@ -498,7 +450,7 @@ function wpra_get_item_content_images($item)
498
  $i = 0;
499
  $images = [];
500
  while (!empty($matches[1][$i])) {
501
- $imageUrl = urldecode(trim(html_entity_decode($matches[1][$i])));
502
  // Increment early to allow the iteration body to use "continue" statements
503
  $i++;
504
 
@@ -525,7 +477,7 @@ function wpra_get_item_content_images($item)
525
  */
526
  function wpra_get_item_itunes_images($item)
527
  {
528
- $tags = $item->get_item_tags(Wpra_Rss_Namespace::ITUNES, 'image');
529
 
530
  if (!is_array($tags) || empty($tags)) {
531
  return [];
@@ -553,17 +505,17 @@ function wpra_get_item_itunes_images($item)
553
  * @since 4.14
554
  *
555
  * @param string $content The content in which to search for and remove the image.
556
- * @param string $url The URL of the image to remove.
557
- * @param int $limit Optional number of image occurrences to remove.
558
  *
559
  * @return string The new content, with any matching `img` HTML tags removed.
560
  */
561
  function wpra_remove_image_from_content($content, $url, $limit = 1)
562
  {
563
- $tag_search = [
564
  '<img[^<>]*?src="%s"[^<>]*?>',
565
- '<img[^<>]*?srcset="[^<>]*?%s.[^<>]*?"[^<>]*?>',
566
- ];
567
 
568
  foreach ($tag_search as $regex) {
569
  // This will transform the expression to match images in html-encoded content
@@ -633,7 +585,7 @@ function wpra_set_featured_image_from_url($post_id, $url)
633
  }
634
 
635
  // Otherwise, get the attachment ID for the URL from the database
636
- set_post_thumbnail($post_id, wpra_get_attachment_id_from_url($url));
637
  }
638
 
639
  /**
@@ -665,13 +617,15 @@ function wpra_is_url_local($url, $home_url = null)
665
  *
666
  * @see parse_url()
667
  *
668
- * @param string|array $url The URL which is to be rebuilt, or a result of parse_url().
669
- * @param bool|array $parts An array of which parts to use for building the new URL. Boolean false for all.
 
670
  *
671
  * @return null|string The rebuilt URL on success, or null of given URL is malformed.
672
  */
673
  function wpra_rebuild_url($url, $parts = false)
674
  {
 
675
  // Allow parsed array
676
  if (is_string($url)) {
677
  $url = parse_url($url);
@@ -733,11 +687,11 @@ function wpra_encode_and_parse_url($url)
733
  *
734
  * @since 2.7.4
735
  *
736
- * @param string $url (required) The URL of the image to download
737
- * @param int $post_id (required) The post ID the media is to be associated with
738
- * @param bool $attach (optional) Whether to make this attachment the Featured Image for the post.
739
- * @param string $filename (optional) Replacement filename for the URL filename (do not include extension)
740
- * @param array $post_data (optional) Array of key => values for wp_posts table (ex: 'post_title' => 'foobar',
741
  * 'post_status' => 'draft')
742
  *
743
  * @return int|object The ID of the attachment or a WP_Error on failure
@@ -748,9 +702,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
748
  return new WP_Error('missing', "Need a valid URL and post ID...");
749
  }
750
 
751
- // Allow 30 seconds prior to beginning the actual download
752
- set_time_limit(apply_filters('wpra/images/time_limit/prepare', 30));
753
-
754
  // Check if the image already exists in the media library
755
  $existing = get_posts([
756
  'post_type' => 'attachment',
@@ -770,11 +721,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
770
 
771
  try {
772
  /* @var $img WPRSS_Image_Cache_Image */
773
- $url = apply_filters('wpra/images/url_to_download', $url);
774
-
775
- // Allow 1 minute for the download process
776
- set_time_limit(apply_filters('wpra/images/time_limit/download', 60));
777
-
778
  $img = $images->get($url);
779
  } catch (Exception $e) {
780
  return new WP_Error('could_not_load_image', $e->getMessage(), $url);
@@ -824,8 +770,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
824
  $parts = parse_url(trim($img->get_url()));
825
  $baseName = uniqid($parts['host']);
826
 
827
- $parts['path'] = apply_filters('wpra/images/cache_path', $parts['path']);
828
-
829
  if (!empty($filename)) {
830
  // user given filename for title, add original URL extension
831
  $baseName = $filename . "." . $ext;
@@ -837,13 +781,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
837
  }
838
  }
839
 
840
- // Fix for Facebook images that come from a PHP endpoint
841
- if (stripos($baseName, 'safe_image.php') !== false) {
842
- $hash = crc32(trim($img->get_url()));
843
-
844
- $baseName = str_replace('safe_image.php', $hash . '.jpeg', $baseName);
845
- }
846
-
847
  $file_array['name'] = $baseName;
848
 
849
  // set additional wp_posts columns
@@ -886,18 +823,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
886
  $image['ext'] = empty($image['ext']) ? $file_ext : $image['ext'];
887
  $image['type'] = empty($image['type']) ? $mime_type : $image['type'];
888
 
889
- // If the image has a `proper_filename` and an `ext`
890
- if (!empty($image['proper_filename']) && !empty($image['ext'])) {
891
- $filename = strtolower($image['proper_filename']);
892
- $extension = strtolower($image['ext']);
893
-
894
- // Do a case insensitive check for the extension in the proper_filename. If not found, we
895
- // add the extension
896
- if (!preg_match('/' . $extension . '$/i', $filename)) {
897
- $image['proper_filename'] .= '.' . $extension;
898
- }
899
- }
900
-
901
  return $image;
902
  }, 10);
903
  }
@@ -907,9 +832,6 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
907
  // For some reason, deep down filesize() returned 0 for the temporary file without this
908
  clearstatcache(false, $file_array['tmp_name']);
909
 
910
- // Allocate 30 for WordPress to copy and process the image
911
- set_time_limit(apply_filters('wpra/images/time_limit/copy', 30));
912
-
913
  // $post_data can override the items saved to wp_posts table,
914
  // like post_mime_type, guid, post_parent, post_title, post_content, post_status
915
  $att_id = media_handle_sideload($file_array, $post_id, '', $post_data);
@@ -931,7 +853,7 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
931
 
932
  // set as post thumbnail if desired
933
  if ($attach) {
934
- set_post_thumbnail($post_id, $att_id);
935
  }
936
 
937
  // Save the original image URL in the attachment's meta data
@@ -945,7 +867,7 @@ function wpra_media_sideload_image($url = null, $post_id = null, $attach = null,
945
  *
946
  * @since 4.14
947
  *
948
- * @param string $local_image_path Local path of the downloaded image
949
  * @param string $remote_image_path Remote image url
950
  *
951
  * @return array Values with extension first and mime type.
@@ -988,6 +910,7 @@ function wpra_check_file_type($local_image_path, $remote_image_path)
988
  */
989
  function wpra_get_mime_type_ext_mapping()
990
  {
 
991
  // Get MIME to extension mappings ( from WordPress wp_check_filetype_and_ext() function )
992
  return apply_filters(
993
  'getimagesize_mimes_to_exts', [
@@ -1005,8 +928,7 @@ function wpra_get_mime_type_ext_mapping()
1005
  *
1006
  * @since 4.14
1007
  */
1008
- function wpra_get_attachment_id_from_url($image_src)
1009
- {
1010
  global $wpdb;
1011
  $query = "SELECT ID FROM {$wpdb->posts} WHERE guid='$image_src'";
1012
  $id = $wpdb->get_var($query);
@@ -1029,23 +951,3 @@ function wpra_image_feature_enabled($feature)
1029
 
1030
  return $c->has($key) && $c->get($key) === true;
1031
  }
1032
-
1033
- /**
1034
- * Checks if a URL refers to an image.
1035
- *
1036
- * @param string $url The URL to test.
1037
- *
1038
- * @return bool
1039
- */
1040
- function wpra_is_url_an_image($url)
1041
- {
1042
- $headers = @get_headers($url, true);
1043
- $headers = is_array($headers) ? $headers : [];
1044
- $headers = array_change_key_case($headers, CASE_LOWER);
1045
-
1046
- if (empty($headers['content-type'])) {
1047
- return false;
1048
- }
1049
-
1050
- return isset($headers['content-type']) && stripos(trim($headers['content-type']), 'image/') === 0;
1051
- }
5
  use RebelCode\Wpra\Core\Data\DataSetInterface;
6
  use RebelCode\Wpra\Core\Logger\FeedLoggerInterface;
7
 
8
+ class Wpra_Rss_Namespace {
 
9
  const ITUNES = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
10
  }
11
 
23
  * The "import" process here basically just fetches the images from the item's content/excerpt, the media:thumbnail
24
  * tag and the enclosures. The entire list of images is saved, along with the URL of the best image.
25
  *
26
+ * @param int|string $itemId The ID of the feed item.
27
+ * @param SimplePie_Item $item The simple pie item object.
28
+ * @param int|string $sourceId The ID of the feed source from which the item was imported.
29
  */
30
  function wpra_detect_item_type($itemId, $item, $sourceId)
31
  {
70
  * The "import" process here basically just fetches the images from the item's content/excerpt, the media:thumbnail
71
  * tag and the enclosures. The entire list of images is saved, along with the URL of the best image.
72
  *
73
+ * @param int|string $itemId The ID of the feed item.
74
+ * @param SimplePie_Item $item The simple pie item object.
75
+ * @param int|string $sourceId The ID of the feed source from which the item was imported.
76
  */
77
  function wpra_import_item_images($itemId, $item, $sourceId)
78
  {
111
  // If the featured image importing feature is enabled, import the featured image
112
  if (wpra_image_feature_enabled('import_ft_images')) {
113
  $ftImageUrl = null;
114
+ switch ($ftImageOpt)
115
+ {
116
  case 'auto':
117
  if (!empty($bestImage)) {
118
  $ftImageUrl = $bestImage;
172
 
173
  if ($usedDefault) {
174
  update_post_meta($itemId, 'wprss_item_is_using_def_image', '1');
175
+ $logger->notice('Used the feed source\'s default featured image for "{title}"', ['title' => $title]);
176
  } else {
177
+ $logger->notice('No featured image was found for item "{title}"', ['title' => $title]);
178
  }
179
  }
180
  } else {
187
 
188
  wp_update_post([
189
  'ID' => $itemId,
190
+ 'post_content' => $newContent
191
  ]);
192
  }
193
  }
208
  // Update the post content
209
  wp_update_post([
210
  'ID' => $itemId,
211
+ 'post_content' => $content
212
  ]);
213
  }
214
 
262
  */
263
  function wpra_get_item_images($item)
264
  {
265
+ // Detect images and save them
266
+ $images = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
+ // Add the media thumbnail image
269
+ $images['media'] = [wpra_get_item_media_thumbnail_image($item)];
270
+ $images['enclosure'] = wpra_get_item_enclosure_images($item);
271
+ $images['content'] = wpra_get_item_content_images($item);
272
+ $images['itunes'] = wpra_get_item_itunes_images($item);
273
 
274
+ return $images;
275
  }
276
 
277
  /**
278
  * Processes a list of image URLs to strip away images that are unreachable or too small, as well as identify which
279
  * image in the list is the best image (in terms of dimensions and aspect ratio).
280
  *
281
+ * @param array $images The image URLs.
282
  * @param array|DataSetInterface $source The feed source data set.
283
  * @param string|null $bestImage This variable given as this parameter will be set to the URL of
284
  * the best found image.
302
  $minWidth = 0;
303
  $minHeight = 0;
304
  if (wpra_image_feature_enabled('image_min_size')) {
305
+ $minWidth = (int)apply_filters('wprss_thumbnail_min_width', $source['image_min_width']);
306
+ $minHeight = (int)apply_filters('wprss_thumbnail_min_height', $source['image_min_height']);
307
  }
308
 
309
  foreach ($images as $group => $urls) {
310
  foreach ($urls as $imageUrl) {
 
 
 
311
  try {
312
+ /* @var $tmp_img WPRSS_Image_Cache_Image */
313
  $tmp_img = $imgContainer->get($imageUrl);
314
 
315
  $dimensions = ($tmp = $tmp_img->get_local_path())
361
  return $finalImages;
362
  }
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  /**
365
  * Returns the <media:thumbnail> image for the given feed item.
366
  *
380
  return null;
381
  }
382
 
383
+ // Stop if enclosure is not an image
 
384
  $type = $enclosure->get_type();
385
+ if (!empty($type) && stripos($type, 'image/') !== 0) {
386
  return null;
387
  }
388
 
389
+ // Stop if enclosure tag has no link
390
+ $url = $enclosure->get_link();
391
+ if (empty($url)) {
392
+ return null;
393
+ }
394
 
395
+ // Check if image can be downloaded
396
+ if (wpra_container()->has('wpra/images/container')) {
397
+ try {
398
+ /* @var $image WPRSS_Image_Cache_Image */
399
+ $image = wpra_container()->get('wpra/images/container')->get($url);
400
+ } catch (Exception $exception) {
401
+ return null;
402
  }
403
  }
404
 
405
+ if ($image->get_local_path()) {
406
+ return $url;
407
+ }
408
+
409
  return null;
410
  }
411
 
420
  */
421
  function wpra_get_item_enclosure_images($item)
422
  {
423
+ $enclosure = $item->get_enclosure();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
+ // Stop if item has no enclosure
426
+ if (is_null($enclosure)) {
427
+ return [];
 
428
  }
429
 
430
+ // Get all the thumbnails from the enclosure
431
+ $thumbnails = (array) $enclosure->get_thumbnails();
432
+
433
+ return $thumbnails;
434
  }
435
 
436
  /**
450
  $i = 0;
451
  $images = [];
452
  while (!empty($matches[1][$i])) {
453
+ $imageUrl = urldecode(trim($matches[1][$i]));
454
  // Increment early to allow the iteration body to use "continue" statements
455
  $i++;
456
 
477
  */
478
  function wpra_get_item_itunes_images($item)
479
  {
480
+ $tags = $item->get_item_tags(Wpra_Rss_Namespace::ITUNES,'image');
481
 
482
  if (!is_array($tags) || empty($tags)) {
483
  return [];
505
  * @since 4.14
506
  *
507
  * @param string $content The content in which to search for and remove the image.
508
+ * @param string $url The URL of the image to remove.
509
+ * @param int $limit Optional number of image occurrences to remove.
510
  *
511
  * @return string The new content, with any matching `img` HTML tags removed.
512
  */
513
  function wpra_remove_image_from_content($content, $url, $limit = 1)
514
  {
515
+ $tag_search = array(
516
  '<img[^<>]*?src="%s"[^<>]*?>',
517
+ '<img[^<>]*?srcset="[^<>]*?%s.[^<>]*?"[^<>]*?>'
518
+ );
519
 
520
  foreach ($tag_search as $regex) {
521
  // This will transform the expression to match images in html-encoded content
585
  }
586
 
587
  // Otherwise, get the attachment ID for the URL from the database
588
+ set_post_thumbnail( $post_id, wpra_get_attachment_id_from_url($url) );
589
  }
590
 
591
  /**
617
  *
618
  * @see parse_url()
619
  *
620
+ * @param string|array $url The URL which is to be rebuilt, or a result of parse_url().
621
+ *
622
+ * @param bool|array $parts An array of which parts to use for building the new URL. Boolean false for all.
623
  *
624
  * @return null|string The rebuilt URL on success, or null of given URL is malformed.
625
  */
626
  function wpra_rebuild_url($url, $parts = false)
627
  {
628
+
629
  // Allow parsed array
630
  if (is_string($url)) {
631
  $url = parse_url($url);
687
  *
688
  * @since 2.7.4
689
  *
690
+ * @param string $url (required) The URL of the image to download
691
+ * @param int $post_id (required) The post ID the media is to be associated with
692
+ * @param bool $attach (optional) Whether to make this attachment the Featured Image for the post.
693
+ * @param string $filename (optional) Replacement filename for the URL filename (do not include extension)
694
+ * @param array $post_data (optional) Array of key => values for wp_posts table (ex: 'post_title' => 'foobar',
695
  * 'post_status' => 'draft')
696
  *
697
  * @return int|object The ID of the attachment or a WP_Error on failure
702
  return new WP_Error('missing', "Need a valid URL and post ID...");
703
  }
704
 
 
 
 
705
  // Check if the image already exists in the media library
706
  $existing = get_posts([
707
  'post_type' => 'attachment',
721
 
722
  try {
723
  /* @var $img WPRSS_Image_Cache_Image */
 
 
 
 
 
724
  $img = $images->get($url);
725
  } catch (Exception $e) {
726
  return new WP_Error('could_not_load_image', $e->getMessage(), $url);
770
  $parts = parse_url(trim($img->get_url()));
771
  $baseName = uniqid($parts['host']);
772
 
 
 
773
  if (!empty($filename)) {
774
  // user given filename for title, add original URL extension
775
  $baseName = $filename . "." . $ext;
781
  }
782
  }
783
 
 
 
 
 
 
 
 
784
  $file_array['name'] = $baseName;
785
 
786
  // set additional wp_posts columns
823
  $image['ext'] = empty($image['ext']) ? $file_ext : $image['ext'];
824
  $image['type'] = empty($image['type']) ? $mime_type : $image['type'];
825
 
 
 
 
 
 
 
 
 
 
 
 
 
826
  return $image;
827
  }, 10);
828
  }
832
  // For some reason, deep down filesize() returned 0 for the temporary file without this
833
  clearstatcache(false, $file_array['tmp_name']);
834
 
 
 
 
835
  // $post_data can override the items saved to wp_posts table,
836
  // like post_mime_type, guid, post_parent, post_title, post_content, post_status
837
  $att_id = media_handle_sideload($file_array, $post_id, '', $post_data);
853
 
854
  // set as post thumbnail if desired
855
  if ($attach) {
856
+ set_post_thumbnail( $post_id, $att_id );
857
  }
858
 
859
  // Save the original image URL in the attachment's meta data
867
  *
868
  * @since 4.14
869
  *
870
+ * @param string $local_image_path Local path of the downloaded image
871
  * @param string $remote_image_path Remote image url
872
  *
873
  * @return array Values with extension first and mime type.
910
  */
911
  function wpra_get_mime_type_ext_mapping()
912
  {
913
+
914
  // Get MIME to extension mappings ( from WordPress wp_check_filetype_and_ext() function )
915
  return apply_filters(
916
  'getimagesize_mimes_to_exts', [
928
  *
929
  * @since 4.14
930
  */
931
+ function wpra_get_attachment_id_from_url( $image_src ) {
 
932
  global $wpdb;
933
  $query = "SELECT ID FROM {$wpdb->posts} WHERE guid='$image_src'";
934
  $id = $wpdb->get_var($query);
951
 
952
  return $c->has($key) && $c->get($key) === true;
953
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/feed-importing.php CHANGED
@@ -1,318 +1,278 @@
1
  <?php
2
 
3
- /**
4
- * Functions relating to feed importing
5
- *
6
- * @package WPRSSAggregator
7
- */
8
-
9
- // Warning: Order may be important
10
- add_filter('wprss_normalize_permalink', 'wprss_google_news_url_fix', 8);
11
- add_filter('wprss_normalize_permalink', 'wprss_bing_news_url_fix', 9);
12
- add_filter('wprss_normalize_permalink', 'wprss_google_alerts_url_fix', 10);
13
- add_filter('wprss_normalize_permalink', 'wprss_convert_video_permalink', 100);
14
-
15
- // Adds comparators for item sorting
16
- add_filter('wprss_item_comparators', 'wprss_sort_comparators_default');
17
-
18
- add_action( 'wprss_fetch_single_feed_hook', 'wprss_fetch_insert_single_feed_items' );
19
- /**
20
- * The main feed fetching function.
21
- * Fetches the feed items from the source provided and inserts them into the DB.
22
- *
23
- * Called on hook 'wprss_fetch_single_feed_hook'.
24
- *
25
- * @since 3.2
26
- *
27
- * @throws Exception
28
- */
29
- function wprss_fetch_insert_single_feed_items( $feed_ID ) {
30
- set_transient('wpra/feeds/importing/' . $feed_ID, true, 0);
31
-
32
- global $wprss_importing_feed;
33
- $wprss_importing_feed = $feed_ID;
34
-
35
- register_shutdown_function('wprss_detect_exec_timeout');
36
-
37
- $importFn = function ($feed_ID) {
38
- $feedName = get_the_title($feed_ID);
39
-
40
- $logger = wpra_get_logger($feed_ID);
41
- $logger->info('Starting import for "{0}"', [$feedName]);
42
-
43
- $t = microtime(true);
44
 
45
- // Check if the feed source is active.
46
- if ( ! wprss_is_feed_source_active( $feed_ID ) && ! wprss_feed_source_force_next_fetch( $feed_ID ) ) {
47
- $logger->info('Feed is not active. Finished');
48
- return;
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- // If the feed source is forced for next fetch, remove the force next fetch data
52
- if ( wprss_feed_source_force_next_fetch( $feed_ID ) ) {
53
- delete_post_meta( $feed_ID, 'wprss_force_next_fetch' );
54
- }
55
 
56
- // Truncate old items first
57
- wprss_truncate_items_for_source( $feed_ID );
58
 
59
- // Get the feed source URL from post meta, and filter it
60
- $feed_url = get_post_meta( $feed_ID, 'wprss_url', true );
61
- $feed_url = apply_filters( 'wprss_feed_source_url', $feed_url, $feed_ID );
62
- $logger->debug('Feed source URL: {0}', [$feed_url]);
63
 
64
- // Get the feed limit from post meta
65
- $feed_limit = get_post_meta( $feed_ID, 'wprss_limit', true );
66
 
67
- // If the feed has no individual limit
68
- if ( $feed_limit === '' || intval( $feed_limit ) <= 0 ) {
69
- // Get the global limit
70
- $global_limit = wprss_get_general_setting('limit_feed_items_imported');
71
- // If no global limit is set, mark as NULL
72
- if ( $global_limit === '' || intval($global_limit) <= 0 ) {
73
- $feed_limit = NULL;
 
 
74
  }
75
- else $feed_limit = $global_limit;
76
- }
77
-
78
- // Filter the URL for validity
79
- if ( ! wprss_validate_url( $feed_url ) ) {
80
- $logger->error('Feed URL is not valid!');
81
- } else {
82
- // Get the feed items from the source
83
- $items = wprss_get_feed_items( $feed_url, $feed_ID );
84
 
85
- // If got NULL, convert to an empty array
86
- if ( $items === NULL ) {
87
- $items_to_insert = array();
88
  } else {
89
- // See `wprss_item_comparators` filter
90
- wprss_sort_items($items);
91
 
92
- // If using a limit ...
93
- if ( $feed_limit === NULL ) {
94
- $items_to_insert = $items;
95
  } else {
96
- $items_to_insert = array_slice( $items, 0, $feed_limit );
97
- $logger->debug('{0} items in the feed, {1} items after applying limit', [
98
- count($items),
99
- count($items_to_insert)
100
- ]);
101
- }
102
- }
103
 
104
- $unique_titles_only = get_post_meta($feed_ID, 'wprss_unique_titles', true);
105
- $unique_titles_only = ($unique_titles_only === '')
106
- ? wprss_get_general_setting('unique_titles')
107
- : $unique_titles_only;
108
- $unique_titles_only = filter_var($unique_titles_only, FILTER_VALIDATE_BOOLEAN);
109
-
110
- // Gather the existing feed item IDs for this feed source
111
- $useGuids = get_post_meta($feed_ID, 'wprss_use_guids', true);
112
- $useGuids = filter_var($useGuids, FILTER_VALIDATE_BOOLEAN);
113
-
114
- // Gather the IDs and titles of the items that are imported
115
- // The import process will not only check the IDs and titles against the DB, but also against the feed
116
- // itself. This prevents duplicate items in the feed from importing duplicates.
117
- $existingIds = [];
118
- $existingTitles = [];
119
-
120
- // Generate a list of items fetched, that are not already in the DB
121
- $new_items = array();
122
- foreach ( $items_to_insert as $item ) {
123
- $itemTitle = $item->get_title();
124
- $guid = $item->get_id();
125
- $permalink = $item->get_permalink();
126
- $permalink = wprss_normalize_permalink( $permalink, $item, $feed_ID );
127
-
128
- // Check if blacklisted
129
- if (wprss_is_blacklisted($permalink)) {
130
- $logger->debug('Item "{0}" is blacklisted', [$itemTitle]);
131
- continue;
132
  }
133
 
134
- $itemId = $useGuids ? $guid : $permalink;
135
-
136
- // Check if already imported in database
137
- //-----------------------------------------
138
- $itemIdExists = $useGuids ? wprss_guid_exists($guid) : wprss_permalink_exists($permalink);
139
- $itemsTitleExists = $unique_titles_only && wprss_item_title_exists($item->get_title());
140
-
141
- if ($itemIdExists || $itemsTitleExists) {
142
- $reason = $itemIdExists
143
- ? ($useGuids ? 'GUID' : 'permalink')
144
- : 'Non-unique title';
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- $logger->debug('Item "{title}" already exists in the database. Reason: {reason}', [
147
- 'title' => $itemTitle,
148
- 'reason' => $reason
149
- ]);
150
 
151
- continue;
152
- }
153
 
154
- // Check if item is duplicated in the feed
155
- //-----------------------------------------
156
- $itemIdIsDuped = array_key_exists($itemId, $existingIds);
157
- $itemTitleIsDuped = $unique_titles_only && array_key_exists($itemTitle, $existingTitles);
 
 
 
158
 
159
- if ($itemIdIsDuped || $itemTitleIsDuped) {
160
- $reason = $itemIdIsDuped
161
- ? ($useGuids ? 'GUID' : 'permalink')
162
- : 'Non-unique title';
163
 
164
- $logger->debug('Item "{title}" is duplicated in the feed. Reason: {reason}', [
165
- 'title' => $itemTitle,
166
- 'reason' => $reason,
167
- ]);
168
 
169
- continue;
170
- } else {
171
- $existingIds[$itemId] = 1;
172
- $existingTitles[$itemTitle] = 1;
173
  }
174
 
175
- $new_items[] = $item;
176
- }
177
 
178
- $original_count = count( $items_to_insert );
179
- $new_count = count( $new_items );
 
180
 
181
- if ( $new_count !== $original_count ) {
182
- $logger->debug('{0} will be skipped', [$original_count - $new_count]);
183
- }
 
 
184
 
185
- $items_to_insert = $new_items;
186
- $per_import = wprss_get_general_setting('limit_feed_items_per_import');
187
- if (!empty($per_import)) {
188
- $items_to_insert = array_slice( $items_to_insert, 0, $per_import );
189
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
- // If using a limit - delete any excess items to make room for the new items
192
- if ( $feed_limit !== NULL ) {
193
- // Get the number of feed items in DB, and their count
194
- $db_feed_items = wprss_get_feed_items_for_source( $feed_ID );
195
- $num_db_feed_items = $db_feed_items->post_count;
196
-
197
- // Get the number of feed items we can store until we reach the limit
198
- $num_can_insert = $feed_limit - $num_db_feed_items;
199
- // Calculate how many feed items we must delete before importing, to keep to the limit
200
- $num_new_items = count( $new_items );
201
- $num_feed_items_to_delete = $num_can_insert > $num_new_items
202
- ? 0
203
- : $num_new_items - $num_can_insert;
204
-
205
- // Get an array with the DB feed items in reverse order (the oldest first)
206
- $db_feed_items_reversed = array_reverse( $db_feed_items->posts );
207
- // Cut the array to get only the first few that are to be deleted ( equal to $num_feed_items_to_delete )
208
- $feed_items_to_delete = array_slice( $db_feed_items_reversed, 0, $num_feed_items_to_delete );
209
-
210
- // Iterate the feed items and delete them
211
- $num_items_deleted = 0;
212
- foreach ( $feed_items_to_delete as $post ) {
213
- wp_delete_post( $post->ID, TRUE );
214
- $num_items_deleted++;
215
  }
216
 
217
- if ($num_items_deleted > 0) {
218
- $logger->info('Deleted the oldest {0} items', [$num_items_deleted]);
 
 
 
 
219
  }
220
  }
221
 
222
- update_post_meta( $feed_ID, 'wprss_last_update', time() );
223
- update_post_meta( $feed_ID, 'wprss_last_update_items', 0 );
224
 
225
- // Insert the items into the db
226
- if ( !empty( $items_to_insert ) ) {
227
- wprss_items_insert_post( $items_to_insert, $feed_ID );
 
228
  }
229
- }
230
-
231
- $next_scheduled = get_post_meta( $feed_ID, 'wprss_reschedule_event', TRUE );
232
 
233
- if ( $next_scheduled !== '' ) {
234
- wprss_feed_source_update_start_schedule( $feed_ID );
235
- delete_post_meta( $feed_ID, 'wprss_reschedule_event' );
236
- $logger->info('Scheduled next update');
237
- }
238
-
239
- $t = microtime(true) - $t;
240
 
241
- $logger->info(sprintf('Import completed in %.2f seconds!', $t));
242
- };
243
 
244
- try {
245
- $importFn($feed_ID);
246
- } catch (Exception $e) {
247
- wpra_get_logger($feed_ID)->error($e->getMessage());
248
- throw $e;
249
- }
250
 
251
- delete_transient('wpra/feeds/importing/' . $feed_ID);
252
- wprss_flag_feed_as_idle($feed_ID);
253
- $wprss_importing_feed = null;
254
- }
255
 
256
- /**
257
- * Fetches the feed items from a feed at the given URL.
258
- *
259
- * Called from 'wprss_fetch_insert_single_feed_items'
260
- *
261
- * @since 3.0
262
- *
263
- * @return SimplePie_Item[]|null
264
- */
265
- function wprss_get_feed_items( $feed_url, $source, $force_feed = FALSE ) {
266
- // Add filters and actions prior to fetching the feed items
267
- add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
268
 
269
- /* Fetch the feed from the soure URL specified */
270
- $feed = wprss_fetch_feed( $feed_url, $source, $force_feed );
 
 
 
 
 
 
 
 
271
 
272
- if (is_wp_error($feed)) {
273
- wpra_get_logger($source)->error('Failed to fetch the feed from {0}. Error: {1}', [
274
- $feed_url,
275
- $feed->get_error_message()
276
- ]);
277
 
278
- return NULL;
279
- }
 
 
 
280
 
281
- update_post_meta( $source, 'wprss_site_url', $feed->get_permalink() );
282
- update_post_meta( $source, 'wprss_feed_image', $feed->get_image_url() );
283
 
284
- // Remove previously added filters and actions
285
- remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
286
 
287
- return @$feed->get_items();
288
- }
289
 
290
- if (defined('WP_DEBUG') && WP_DEBUG) {
291
- /**
292
- * Allow debugging of wp_cron jobs using xDebug.
293
- *
294
- * This is done by taking the XDEBUG cookie received from the browser (which enables an xDebug session) and passing it
295
- * to WP Cron. That way, code initiated from a cron job will be debuggable.
296
- *
297
- * @param array $cronRequest
298
- *
299
- * @return array $cron_request_array with the current XDEBUG_SESSION cookie added if set
300
- */
301
- add_action('cron_request', function($cronRequest) {
302
- if (empty($_COOKIE['XDEBUG_SESSION'])) {
303
- return ($cronRequest);
304
- }
305
 
306
- $cookie = filter_var($_COOKIE['XDEBUG_SESSION'], FILTER_SANITIZE_STRING);
307
 
308
- if (empty($cronRequest['args']['cookies'])) {
309
- $cronRequest['args']['cookies'] = [];
310
- }
 
 
 
 
 
 
 
 
 
 
311
 
312
- $cronRequest['args']['cookies']['XDEBUG_SESSION'] = $cookie;
 
 
 
313
 
314
- return $cronRequest;
315
- });
316
  }
317
 
318
  /**
@@ -356,837 +316,742 @@ function wprss_get_feed_cache_dir()
356
  }
357
 
358
 
359
- /**
360
- * A clone of the function 'fetch_feed' in wp-includes/feed.php [line #529]
361
- *
362
- * Called from 'wprss_get_feed_items'
363
- *
364
- * @since 3.5
365
- */
366
- function wprss_fetch_feed($url, $source = null, $param_force_feed = false)
367
- {
368
- // Trim the URL
369
- $url = trim($url);
370
- // Parse the URL
371
- $parsed = wpra_parse_url($url);
372
- // Filter the URL
373
- $url = apply_filters('wpra/importer/feed/url', $url, $parsed);
374
-
375
- // Initialize the Feed
376
- $feed = new SimplePie();
377
- $feed->set_feed_url($url);
378
- $feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_ALL);
379
-
380
- // If a feed source was passed
381
- if ($source !== null || $param_force_feed) {
382
- // Get the force-feed option for the feed source
383
- $force_feed = get_post_meta($source, 'wprss_force_feed', true);
384
- // If turned on, force the feed
385
- if ($force_feed == 'true' || $param_force_feed) {
386
- $feed->force_feed(true);
387
- $feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE);
388
-
389
- global $wpraNoSslVerification;
390
- $wpraNoSslVerification = true;
391
- }
392
- }
393
-
394
- // Set timeout limit
395
- $fetch_time_limit = wprss_get_feed_fetch_time_limit();
396
- $feed->set_timeout($fetch_time_limit);
397
-
398
- $cacheEnabled = wprss_is_feed_cache_enabled();
399
- $feed->enable_cache($cacheEnabled);
400
-
401
- if ($cacheEnabled) {
402
- $feed->set_cache_location(wprss_get_feed_cache_dir());
403
- }
404
-
405
- // Reference array action hook, for the feed object and the URL
406
- do_action_ref_array('wp_feed_options', array(&$feed, $url));
407
-
408
- // Prepare the tags to strip from the feed
409
- $tags_to_strip = apply_filters('wprss_feed_tags_to_strip', $feed->strip_htmltags, $source);
410
- // Strip them
411
- $feed->strip_htmltags($tags_to_strip);
412
-
413
- do_action('wprss_fetch_feed_before', $feed, $source);
414
-
415
- // Fetch the feed
416
- $feed->init();
417
- $feed->handle_content_type();
418
-
419
- do_action('wprss_fetch_feed_after', $feed);
420
-
421
- // Convert the feed error into a WP_Error, if applicable
422
- if ($feed->error()) {
423
- if ($source !== null) {
424
- $msg = sprintf(
425
- __('Failed to fetch the RSS feed. Error: %s', 'wprss'),
426
- $feed->error()
427
- );
428
- update_post_meta($source, 'wprss_error_last_import', $msg);
429
- }
430
- return new WP_Error('simplepie-error', $feed->error(), array('feed' => $feed));
431
- }
432
- // If no error, return the feed and remove any error meta
433
- delete_post_meta($source, 'wprss_error_last_import');
434
- return $feed;
435
- }
436
-
437
-
438
- /**
439
- * Normalizes the given permalink.
440
- *
441
- * @param string $permalink The permalink to normalize
442
- * @return string The normalized permalink
443
- * @since 4.2.3
444
- */
445
- function wprss_normalize_permalink( $permalink, $item, $feed_ID) {
446
- // Apply normalization functions on the permalink
447
- $permalink = trim( $permalink );
448
- $permalink = htmlspecialchars_decode($permalink);
449
- $permalink = apply_filters( 'wprss_normalize_permalink', $permalink, $item, $feed_ID);
450
- // Return the normalized permalink
451
- return $permalink;
452
- }
453
-
454
-
455
- /**
456
- * Extracts the actual URL from a Google News permalink
457
- *
458
- * @param string $permalink The permalink to normalize.
459
- * @since 4.2.3
460
- */
461
- function wprss_google_news_url_fix($permalink) {
462
- return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?' . preg_quote('news.google.com', '!') . '.*!');
463
- }
464
-
465
-
466
- /**
467
- * Extracts the actual URL from a Google Alerts permalink
468
- *
469
- * @param string $permalink The permalink to normalize.
470
- * @since 4.7.3
471
- */
472
- function wprss_google_alerts_url_fix($permalink) {
473
- return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('google.com/url', '!') . '.*!');
474
- }
475
-
476
-
477
- /**
478
- * Extracts the actual URL from a Bing permalink
479
- *
480
- * @param string $permalink The permalink to normalize.
481
- * @since 4.2.3
482
- */
483
- function wprss_bing_news_url_fix($permalink) {
484
- return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('bing.com/news', '!') . '.*!');
485
- }
486
-
487
-
488
- /**
489
- * Checks if the permalink is a tracking permalink based on host, and if
490
- * it is, returns the normalized URL of the proper feed item article,
491
- * determined by the named query argument.
492
- *
493
- * Fixes the issue with equivalent Google News etc. items having
494
- * different URLs, that contain randomly generated GET parameters.
495
- * Example:
496
- *
497
- * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=V3e9U6izMMnm1QaB1YHoDA&url=http://abcd...
498
- * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=One9U-HQLsTp1Aal-oDQBQ&url=http://abcd...
499
- *
500
- * @param string $permalink The permalink URL to check and/or normalize.
501
- * @param string|array $patterns One or an array of host names, for which the URL should be fixed.
502
- * @param string Name of the query argument that specifies the actual URL.
503
- * @return string The normalized URL of the original article, as indicated by the `url`
504
- * parameter in the URL query string.
505
- * @since 4.2.3
506
- */
507
- function wprss_tracking_url_fix( $permalink, $patterns, $argName = 'url' ) {
508
- // Parse the url
509
- $parsed = parse_url( urldecode( html_entity_decode( $permalink ) ) );
510
- $patterns = is_array($patterns) ? $patterns :array($patterns);
511
-
512
- // If parsing failed, return the permalink
513
- if ( $parsed === FALSE || $parsed === NULL ) return $permalink;
514
-
515
- // Determine if it's a tracking item
516
- $isMatch = false;
517
- foreach( $patterns as $_idx => $_pattern ) {
518
- if( preg_match($_pattern, $permalink) ) {
519
- $isMatch = true;
520
- break;
521
- }
522
- }
523
-
524
- if( !$isMatch ) return $permalink;
525
-
526
- // Check if the url GET query string is present
527
- if ( !isset( $parsed['query'] ) ) return $permalink;
528
-
529
- // Parse the query string
530
- $query = array();
531
- parse_str( $parsed['query'], $query );
532
-
533
- // Check if the url GET parameter is present in the query string
534
- if ( !is_array($query) || !isset( $query[$argName] ) ) return $permalink;
535
-
536
- return urldecode( $query[$argName] );
537
- }
538
-
539
-
540
- /**
541
- * Converts YouTube, Vimeo and DailyMotion video urls
542
- * into embedded video player urls.
543
- * If the permalink is not a video url, the permalink is returned as is.
544
- *
545
- * @param string $permalink The string permalink url to convert.
546
- * @return string A string, with the convert permalink, or the same permalink passed as parameter if
547
- * not a video url.
548
- * @since 4.0
549
- */
550
- function wprss_convert_video_permalink( $permalink ) {
551
- // CHECK PERMALINK FOR VIDEO HOSTS : YOUTUBE, VIMEO AND DAILYMOTION
552
- $found_video_host = preg_match( '/http[s]?:\/\/(www\.)?(youtube|dailymotion|vimeo)\.com\/(.*)/i', $permalink, $matches );
553
-
554
- // If video host was found
555
- if ( $found_video_host !== 0 && $found_video_host !== FALSE ) {
556
-
557
- // Get general options
558
- $options = get_option( 'wprss_settings_general' );
559
- // Get the video link option entry, or false if it does not exist
560
- $video_link = ( isset($options['video_link']) )? $options['video_link'] : 'false';
561
-
562
- // If the video link option is true, change the video URL to its repective host's embedded
563
- // video player URL. Otherwise, leave the permalink as is.
564
- if ( strtolower( $video_link ) === 'true' ) {
565
- $host = $matches[2];
566
- switch( $host ) {
567
- case 'youtube':
568
- preg_match( '/([&?])v=([^&]+)/', $permalink, $yt_matches );
569
- $permalink = 'https://www.youtube.com/embed/' . $yt_matches[1];
570
- break;
571
- case 'vimeo':
572
- preg_match( '/(\d*)$/i', $permalink, $vim_matches );
573
- $permalink = 'https://player.vimeo.com/video/' . $vim_matches[0];
574
- break;
575
- case 'dailymotion':
576
- preg_match( '/(\.com\/)(video\/)(.*)/i', $permalink, $dm_matches );
577
- $permalink = 'https://www.dailymotion.com/embed/video/' . $dm_matches[3];
578
- break;
579
  }
580
  }
581
- }
582
 
583
- return $permalink;
584
- }
 
585
 
 
 
586
 
587
- /**
588
- * Insert wprss_feed_item posts into the DB
589
- *
590
- * @since 3.0
591
- *
592
- * @param SimplePie_Item[] $items
593
- * @param int|string $feed_ID
594
- */
595
- function wprss_items_insert_post( $items, $feed_ID ) {
596
- update_post_meta( $feed_ID, 'wprss_feed_is_updating', $update_started_at = time() );
597
- $logger = wpra_get_logger($feed_ID);
598
-
599
- // Count of items inserted
600
- $items_inserted = 0;
601
-
602
- // The date format expected by WordPress when inserting posts
603
- $date_format = 'Y-m-d H:i:s';
604
- // Check if we can schedule future items
605
- $schedule_items_filter = apply_filters('wpra/importer/allow_scheduled_items', false);
606
- $schedule_items_option = wprss_get_general_setting('schedule_future_items');
607
- $schedule_future_items = $schedule_items_filter || $schedule_items_option;
608
-
609
- // Get whether the imported items count should still be updated, even if the item is imported by a filter or add-on
610
- $still_update_count = apply_filters( 'wprss_still_update_import_count', FALSE );
611
-
612
- foreach ( $items as $i => $item ) {
613
- $permalink = $item->get_permalink();
614
- $permalink = wprss_normalize_permalink($permalink, $item, $feed_ID);
615
-
616
- $logger->debug('Beginning import for item "{0}"', [$item->get_title()]);
617
 
618
- // Save the enclosure URL
619
- $enclosure_url = '';
620
- $enclosure = $item->get_enclosure(0);
621
 
622
- if ($enclosure && $enclosure->get_link()) {
623
- $enclosure_url = $enclosure->get_link();
624
- }
 
625
 
626
- // Extend the importing time and refresh the feed's updating flag to reflect that it is active
627
- $time_limit = wprss_get_item_import_time_limit();
628
- set_time_limit( $time_limit );
629
 
630
- global $wp_filter;
631
- if (isset($wp_filter['wprss_insert_post_item_conditionals'])) {
632
- $hook = $wp_filter['wprss_insert_post_item_conditionals'];
633
 
634
- if (count($hook->callbacks) > 0) {
635
- $logger->debug('Hooks for `wprss_insert_post_item_conditionals`:');
636
- }
637
 
638
- foreach ($hook->callbacks as $list) {
639
- foreach ($list as $callback) {
640
- $logger->debug('-> {0}', [wprss_format_hook_callback($callback)]);
641
- }
 
642
  }
 
643
  }
644
-
645
- $logger->debug('Checking conditionals ...');
646
-
647
- // Apply filters that determine if the feed item should be inserted into the DB or not.
648
- $ogItem = $item;
649
- $item = apply_filters( 'wprss_insert_post_item_conditionals', $item, $feed_ID, $permalink );
650
- /* @var $item SimplePie_Item */
651
-
652
- // If the item is not NULL, continue to inserting the feed item post into the DB
653
- if ( $item !== NULL && !is_bool($item) ) {
654
- $logger->debug('Resuming insertion into DB');
655
-
656
- $post_status = 'publish';
657
-
658
- // Get the date and normalize if not valid or not given by the feed
659
- $timestamp = $item->get_date( 'U' );
660
- $has_date = !empty($timestamp);
661
-
662
- if ($has_date) {
663
- $logger->debug('Feed item "{0}" date: {1}', [$item->get_title(), $item->get_date($date_format)]);
664
-
665
- if ($timestamp > time()) {
666
- // Item has a future timestamp ...
667
- $logger->debug('Item "{0}" has a future date', [$item->get_title()]);
668
-
669
- // If we can schedule future items, set the post status to "future" (aka scheduled).
670
- // Otherwise, clamp the timestamp to the current time minus 1 second for each item iteration.
671
- // This results in the items having a 1-second time difference between them, and preserves their
672
- // order when sorting by their timestamp.
673
- if ($schedule_future_items) {
674
- $logger->debug('Setting future status');
675
- $post_status = 'future';
676
- } else {
677
- $logger->debug('Date was clamped to present time');
678
- $timestamp = min(time() - $i, $timestamp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
680
- }
681
- } else {
682
- // Item has no date, use the current time
683
- $logger->debug('Item "{0}" has no date. Using current time', [$item->get_title()]);
684
- $timestamp = time();
685
- }
686
-
687
- $date = date( $date_format, $timestamp );
688
- $date_gmt = gmdate( $date_format, $timestamp );
689
-
690
- $logger->debug('Date for "{0}" will be {1}', [$item->get_title(), $date]);
691
-
692
- // Do not let WordPress sanitize the excerpt
693
- // WordPress sanitizes the excerpt because it's expected to be typed by a user and sent in a POST
694
- // request. However, our excerpt is being inserted as a raw string with custom sanitization.
695
- remove_all_filters( 'excerpt_save_pre' );
696
-
697
- $title = trim(html_entity_decode($item->get_title()));
698
- $title = empty($title) ? $item->get_id() : $title;
699
-
700
- // Prepare the item data
701
- $feed_item = apply_filters(
702
- 'wprss_populate_post_data',
703
- array(
704
- 'post_title' => $title,
705
- 'post_content' => $item->get_content(),
706
- 'post_excerpt' => wprss_sanitize_excerpt($item->get_description()),
707
- 'post_status' => $post_status,
708
- 'post_type' => 'wprss_feed_item',
709
- 'post_date' => $date,
710
- 'post_date_gmt' => $date_gmt
711
- ),
712
- $item
713
- );
714
-
715
- if ( defined('ICL_SITEPRESS_VERSION') )
716
- @include_once( WP_PLUGIN_DIR . '/sitepress-multilingual-cms/inc/wpml-api.php' );
717
- if ( defined('ICL_LANGUAGE_CODE') ) {
718
- $_POST['icl_post_language'] = $language_code = ICL_LANGUAGE_CODE;
719
- }
720
 
721
- // Create and insert post object into the DB
722
- $inserted_ID = wp_insert_post( $feed_item );
723
-
724
- if ( !is_wp_error( $inserted_ID ) ) {
725
-
726
- if ( is_object( $inserted_ID ) ) {
727
- if ( isset( $inserted_ID['ID'] ) ) {
728
- $inserted_ID = $inserted_ID['ID'];
729
- }
730
- elseif ( isset( $inserted_ID->ID ) ) {
731
- $inserted_ID = $inserted_ID->ID;
732
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
  }
 
 
734
 
735
- $logger->debug('Item "{0}" was inserted into DB, ID: {1}', [
736
- $ogItem->get_title(),
737
- $inserted_ID,
738
- ]);
739
-
740
- // Create and insert post meta into the DB
741
- wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink );
742
-
743
- $logger->debug('Inserted meta data for item #{0}', [
744
- $inserted_ID,
745
- ]);
746
 
747
- // Increment the inserted items counter
748
- $items_inserted++;
749
-
750
- $logger->notice('Finished import for item {0}, ID {1}', [
751
- $ogItem->get_title(),
752
- $inserted_ID,
753
- ]);
754
- }
755
- else {
756
- update_post_meta( $feed_ID, 'wprss_error_last_import', 'An error occurred while inserting a feed item into the database.' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
757
 
758
- $logger->error('Failed to save item "{0}" into the database', [$item->get_title()]);
759
- }
760
- }
761
- // If the item is TRUE, then a hook function in the filter inserted the item.
762
- // increment the inserted counter
763
- elseif ( ( is_bool($item) && $item === TRUE ) || ( $still_update_count === TRUE && $item !== FALSE ) ) {
764
- $logger->debug('Item "{0}" was imported by an add-on or filter', [
765
- $ogItem->get_title(),
766
- ]);
767
- $items_inserted++;
768
- } elseif (has_filter('wprss_insert_post_item_conditionals', 'wprss_kf_check_post_item_keywords')) {
769
- $logger->info('Item "{0}" was rejected by your keyword or tag filtering.', [
770
- $ogItem->get_title()
771
- ]);
772
- } else {
773
- $logger->notice('Item "{0}" was rejected by an add-on or filter.', [
774
- $ogItem->get_title()
775
- ]);
776
  }
777
- }
778
-
779
- update_post_meta( $feed_ID, 'wprss_last_update_items', $items_inserted );
780
- }
781
-
782
- /**
783
- * Inserts the appropriate post meta for feed items.
784
- *
785
- * Called from 'wprss_items_insert_post'
786
- *
787
- * @since 2.3
788
- *
789
- * @param int $inserted_ID The inserted post ID.
790
- * @param SimplePie_Item $item The SimplePie item object.
791
- * @param string $permalink The item's permalink.
792
- */
793
- function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink ) {
794
- update_post_meta($inserted_ID, 'wprss_item_guid', $item->get_id());
795
- update_post_meta($inserted_ID, 'wprss_item_permalink', $permalink );
796
- update_post_meta($inserted_ID, 'wprss_item_date', $item->get_date(DATE_ISO8601));
797
 
798
- $enclosure = $item->get_enclosure(0);
799
- $enclosureUrl = $enclosure ? $enclosure->get_link() : null;
800
 
801
- if ($enclosureUrl) {
802
- $enclosureType = $enclosure->get_type();
803
-
804
- update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosureUrl );
805
- update_post_meta( $inserted_ID, 'wprss_item_enclosure_type', $enclosureType );
806
-
807
- if (stripos($enclosureType, 'audio') !== false) {
808
- update_post_meta( $inserted_ID, 'wprss_item_audio', $enclosureUrl );
809
  }
810
- }
811
-
812
- /* @var $item SimplePie_Item */
813
- $feed = $item->get_feed();
814
-
815
- // Get the source from the RSS item
816
- $source = wprss_get_item_source_info($item);
817
- // Get the source name if available. If empty, default to the feed source CPT title
818
- $sourceName = empty($source->name) ? $feed->get_title() : $source->name;
819
- // Get the source URL if available. If empty, default to the RSS feed's URL
820
- $sourceUrl = empty($source->link) ? $feed->get_permalink() : $source->link;
821
 
822
- update_post_meta( $inserted_ID, 'wprss_item_source_name', $sourceName);
823
- update_post_meta( $inserted_ID, 'wprss_item_source_url', $sourceUrl);
 
 
 
 
 
 
 
824
 
825
- $author = $item->get_author();
826
- if ($author instanceof SimplePie_Author) {
827
- update_post_meta( $inserted_ID, 'wprss_item_author', $author->get_name() );
828
- update_post_meta( $inserted_ID, 'wprss_item_author_email', $author->get_email() );
829
- update_post_meta( $inserted_ID, 'wprss_item_author_link', $author->get_link() );
830
- }
831
-
832
- update_post_meta( $inserted_ID, 'wprss_feed_id', $feed_ID);
833
- do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
834
- }
835
-
836
- /**
837
- * Gets the source info from a feed item.
838
- *
839
- * @param SimplePie_Item $item
840
- *
841
- * @return object An object with 2 properties: 'name' and 'link'.
842
- */
843
- function wprss_get_item_source_info(SimplePie_Item $item)
844
- {
845
- $source = $item->get_source();
846
-
847
- if ($source === null) {
848
- // Attempt to get RSS 2.0 <source>
849
- $rss2Source = $item->get_item_tags('', 'source');
850
-
851
- $rss2Source = is_array($rss2Source) ? $rss2Source : [];
852
- $name = isset($rss2Source[0]['data']) ? $rss2Source[0]['data'] : '';
853
- $link = isset($rss2Source[0]['attribs']['']['url']) ? $rss2Source[0]['attribs']['']['url'] : '';
854
-
855
- $source = (object) [
856
- 'name' => $name,
857
- 'link' => $link,
858
- ];
859
- } else {
860
- $source = (object) [
861
- 'name' => $source->get_title(),
862
- 'link' => $source->get_permalink(),
863
- ];
864
  }
865
 
866
- return $source;
867
- }
868
-
869
-
870
- /**
871
- * Returns the time limit for the importing of a single feed item.
872
- * The value if filtered through 'wprss_item_import_time_limit'. The default value is WPRSS_ITEM_IMPORT_TIME_LIMIT.
873
- *
874
- * @since 4.6.6
875
- * @return int The maximum amount of seconds allowed for a single feed item to import.
876
- */
877
- function wprss_get_item_import_time_limit() {
878
- return apply_filters( 'wprss_item_import_time_limit', WPRSS_ITEM_IMPORT_TIME_LIMIT );
879
- }
880
-
881
- /**
882
- * Returns the time limit for a feed fetch operation.
883
- * The value if filtered through 'wprss_feed_fetch_time_limit'. The default value is WPRSS_FEED_FETCH_TIME_LIMIT.
884
- *
885
- * @since 4.6.6
886
- * @return int The maximum amount of seconds allowed for an RSS feed XML document to be fetched.
887
- */
888
- function wprss_get_feed_fetch_time_limit() {
889
- return apply_filters( 'wprss_feed_fetch_time_limit', WPRSS_FEED_FETCH_TIME_LIMIT );
890
- }
891
-
892
 
893
- /**
894
- * Fetches all feed items from all feed sources.
895
- * Iteratively calls 'wprss_fetch_insert_single_feed_items' for all feed sources.
896
- *
897
- * This function is used by the cron job or the debugging functions to get all feeds from all feed sources
898
- *
899
- * @param boolean $all If set to TRUE, the function will pull from all feed sources, regardless of their individual
900
- * update interval. If set to FALSE, only feed sources using the global update system will be updated.
901
- * (Optional) Default: TRUE.
902
- * @since 3.0
903
- */
904
- function wprss_fetch_insert_all_feed_items( $all = TRUE ) {
905
- wpra_get_logger()->info('Beginning import for all feed sources');
906
- // Get all feed sources
907
- $feed_sources = wprss_get_all_feed_sources();
908
-
909
- if( $feed_sources->have_posts() ) {
910
- // Start by getting one feed source, we will cycle through them one by one,
911
- // fetching feed items and adding them to the database in each pass
912
- while ( $feed_sources->have_posts() ) {
913
- $feed_sources->the_post();
914
-
915
- $interval = get_post_meta( get_the_ID(), 'wprss_update_interval', TRUE );
916
- $using_global_interval = ( $interval === wprss_get_default_feed_source_update_interval() || $interval === '' );
917
-
918
- // Check if fetching from all, or if feed source uses the global interval
919
- if ( $all === TRUE || $using_global_interval ) {
920
- wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( get_the_ID() ) );
921
- }
922
  }
923
- wp_reset_postdata(); // Restore the $post global to the current post in the main query
924
  }
925
- }
926
-
927
 
928
- /**
929
- * Runs the above function with parameter FALSE
930
- *
931
- * @since 3.9
932
- */
933
- function wprss_fetch_insert_all_feed_items_from_cron() {
934
- wprss_fetch_insert_all_feed_items( FALSE );
935
- }
936
-
937
-
938
- /**
939
- * Shutdown function for detecting if the PHP script reaches the maximum execution time limit
940
- * while importing a feed.
941
- *
942
- * @since 4.6.6
943
- */
944
- function wprss_detect_exec_timeout() {
945
- global $wprss_importing_feed;
946
- $feed_ID = (isset($wprss_importing_feed) && !empty($wprss_importing_feed))
947
- ? $wprss_importing_feed
948
- : null;
949
-
950
- if ($feed_ID === null) {
951
- return;
952
- }
953
 
954
- // Remove the "importing" flag from the feed source
955
- wprss_flag_feed_as_idle($feed_ID);
 
 
956
 
957
- // If no error, stop
958
- $error = error_get_last();
959
- if (empty($error)) {
960
- return;
961
- }
962
 
963
- $errorDetails = $error['message'];
964
- if (!empty($error['file'])) {
965
- $errorDetails .= ' in ' . $error['file'];
966
- }
967
- if (!empty($error['line'])) {
968
- $errorDetails .= ' on line ' . $error['line'];
969
  }
970
 
971
- $msg = sprintf(
972
- __('The importing process failed after %d seconds with the message: "%s"', 'wprss'),
973
- wprss_get_item_import_time_limit(),
974
- $errorDetails
975
- );
976
- // Save the error in the feed source's meta and the plugin log
977
- update_post_meta($feed_ID, 'wprss_error_last_import', $msg);
978
- wpra_get_logger($feed_ID)->error($msg);
979
- }
980
-
981
- /**
982
- * Validates a feed item.
983
- *
984
- * @since 4.11.2
985
- *
986
- * @param SimplePie_Item|mixed $item The item to validate.
987
- *
988
- * @return SimplePie_Item|null The item, if it passes; otherwise, null.
989
- */
990
- function wprss_item_filter_valid($item)
991
- {
992
- return $item instanceof SimplePie_Item
993
- ? $item
994
- : null;
995
- }
996
 
997
- /**
998
- * Sorts items according to settings.
999
- *
1000
- * Use the `wprss_item_comparators` filter to change the list of comparators
1001
- * used to determine the new order of items. See {@see wprss_items_sort_compare_items()}.
1002
- *
1003
- * @since 4.11.2
1004
- *
1005
- * @param SimplePie_Item[] $items The items list.
1006
- * @param WP_Post $feedSource The feed source, for which to sort, if any.
1007
- */
1008
- function wprss_sort_items(&$items, $feedSource = null)
1009
- {
1010
- // Callbacks used to compare items
1011
- $comparators = apply_filters('wprss_item_comparators', array());
1012
- if (empty($comparators)) {
1013
- return;
1014
  }
1015
 
1016
- try {
1017
- usort($items, function ($itemA, $itemB) use ($comparators, $feedSource) {
1018
- return wprss_items_sort_compare_items($itemA, $itemB, $comparators, $feedSource);
1019
- });
1020
- } catch (\InvalidArgumentException $e) {
1021
- wpra_get_logger($feedSource)->warning('Encountered an error while sorting the database items: {0}', [
1022
- $e->getMessage()
1023
- ]);
1024
- }
1025
- }
 
 
 
 
 
 
 
 
1026
 
1027
- /**
1028
- * Recursively compares two items using a list of comparators.
1029
- *
1030
- * If a comparator determines that two items are equal, then the items are
1031
- * evaluated using the next comparator in list, recursively until one of
1032
- * the comparators establishes a difference between items, or the list of
1033
- * comparators is exhausted.
1034
- *
1035
- * @since 4.11.2
1036
- *
1037
- * @param SimplePie_Item|mixed $itemA The item being compared;
1038
- * @param SimplePie_Item|mixed $itemB The item being compared to;
1039
- * @param callable[] $comparators A list of functions for item comparison.
1040
- *
1041
- * @return int A result usable as a return value for {@see usort()}.
1042
- *
1043
- * @throws \InvalidArgumentException If the comparator is not callable.
1044
- */
1045
- function wprss_items_sort_compare_items($itemA, $itemB, $comparators, $feedSource = null)
1046
- {
1047
- if (empty($comparators)) {
1048
- return 0;
1049
- }
1050
 
1051
- $comparator = array_shift($comparators);
1052
- if (!is_callable($comparator)) {
1053
- throw new \InvalidArgumentException('Comparator must be callable');
1054
- }
1055
 
1056
- $result = call_user_func_array($comparator, array($itemA, $itemB, $feedSource));
1057
- if (!$result) {
1058
- return wprss_items_sort_compare_items($itemA, $itemB, $comparators);
1059
- }
 
 
 
1060
 
1061
- return $result;
1062
- }
 
1063
 
1064
- /**
1065
- * Retrieves a custom field of a feed source, or a general setting if the field doesn't exist.
1066
- *
1067
- * @since 4.11.2
1068
- *
1069
- * @param string $key The key of the field or setting.
1070
- * @param WP_Post|null $feedSource The feed source, if any.
1071
- * @return mixed
1072
- */
1073
- function wprss_get_source_meta_or_setting($key, $feedSource = null)
1074
- {
1075
- $value = null;
1076
- if ($feedSource instanceof WP_Post) {
1077
- $value = $feedSource->{$key};
1078
  }
1079
 
1080
- return $value !== null && $value !== false
1081
- ? $value
1082
- : wprss_get_general_setting($key);
1083
- }
1084
-
1085
- /**
1086
- * Determines date order of two feed items.
1087
- *
1088
- * Which should come first is determined by `feed_items_import_order` setting.
1089
- *
1090
- * @since 4.11.2
1091
- *
1092
- * @param SimplePie_Item|mixed $itemA The first item.
1093
- * @param SimplePie_Item|mixed $itemB The second item.
1094
- * @param WP_Post|null $feedSource The feed source for which the items are being compared, if any.
1095
- * @return int A comparison result for {@see usort()}.
1096
- */
1097
- function wprss_item_comparator_date($itemA, $itemB, $feedSource = null)
1098
- {
1099
- $sortOrder = wprss_get_source_meta_or_setting('feed_items_import_order', $feedSource);
1100
- if (empty($sortOrder)) {
1101
- return 0;
1102
  }
1103
 
1104
- if (!wprss_item_filter_valid($itemA) || !wprss_item_filter_valid($itemB)) {
1105
- return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1106
  }
1107
 
1108
- $aDate = intval($itemA->get_gmdate('U'));
1109
- $bDate = intval($itemB->get_gmdate('U'));
1110
-
1111
- switch ($sortOrder) {
1112
- case 'latest':
1113
- if ($aDate === $bDate) {
1114
- return null;
1115
- }
1116
- return $aDate > $bDate ? -1 : 1;
1117
-
1118
- case 'oldest':
1119
- return $aDate < $bDate ? -1 : 1;
1120
-
1121
- case '':
1122
- default:
1123
- return 0;
 
 
 
 
 
 
 
 
 
1124
  }
1125
- }
1126
-
1127
- /**
1128
- * Retrieves default comparators for sorting.
1129
- *
1130
- * @since 4.11.2
1131
- *
1132
- * @param WP_Post|null $feedSource The feed source, for which to get comparators, if any.
1133
- *
1134
- * @return callable[] The list of comparators.
1135
- */
1136
- function wprss_sort_comparators_default($feedSource = null)
1137
- {
1138
- $helper = wprss_wp_container()->get('wprss.admin_helper');
1139
- $defaultArgs = array(2 => $feedSource);
1140
- return array(
1141
- $helper->createCommand('wprss_item_comparator_date', $defaultArgs),
1142
- );
1143
- }
1144
-
1145
- /**
1146
- * Sanitizes a post excerpt, cleverly removing all HTML markup while preserving text content and whitespace.
1147
- *
1148
- * @since 4.14
1149
- *
1150
- * @param string $excerpt The excerpt to sanitize.
1151
- *
1152
- * @return string
1153
- */
1154
- function wprss_sanitize_excerpt($excerpt) {
1155
- // Decode HTML entities back to their respective characters
1156
- $excerpt = html_entity_decode($excerpt);
1157
- // Add a space between any HTML elements
1158
- $excerpt = str_replace('>', ' >', $excerpt);
1159
- // Strip all HTML tags
1160
- $excerpt = strip_tags($excerpt);
1161
- // Remove any redundant spaces
1162
- $excerpt = str_replace(' ', ' ', trim($excerpt));
1163
-
1164
- return $excerpt;
1165
- }
1166
-
1167
- /**
1168
- * Parses a URL, it's query and its path.
1169
- *
1170
- * @since 4.14
1171
- *
1172
- * @param string $url The URL to parse.
1173
- *
1174
- * @return array
1175
- */
1176
- function wpra_parse_url($url)
1177
- {
1178
- // Parse the URL
1179
- $parsed = parse_url($url);
1180
-
1181
- // Move the path to "path_str"
1182
- $parsed['path_str'] = isset($parsed['path']) ? $parsed['path'] : '';
1183
- // Explode the path
1184
- $parsed['path'] = explode('/', $parsed['path_str']);
1185
-
1186
- // Move the query to "query_str"
1187
- $parsed['query_str'] = isset($parsed['query']) ? $parsed['query'] : '';
1188
- // Parse the query
1189
- parse_str($parsed['query_str'], $parsed['query']);
1190
-
1191
- return $parsed;
1192
- }
1
  <?php
2
 
3
+ /**
4
+ * Functions relating to feed importing
5
+ *
6
+ * @package WPRSSAggregator
7
+ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ // Warning: Order may be important
10
+ add_filter('wprss_normalize_permalink', 'wprss_google_news_url_fix', 8);
11
+ add_filter('wprss_normalize_permalink', 'wprss_bing_news_url_fix', 9);
12
+ add_filter('wprss_normalize_permalink', 'wprss_google_alerts_url_fix', 10);
13
+ add_filter('wprss_normalize_permalink', 'wprss_convert_video_permalink', 100);
14
+
15
+ // Adds comparators for item sorting
16
+ add_filter('wprss_item_comparators', 'wprss_sort_comparators_default');
17
+
18
+ add_action( 'wprss_fetch_single_feed_hook', 'wprss_fetch_insert_single_feed_items' );
19
+ /**
20
+ * The main feed fetching function.
21
+ * Fetches the feed items from the source provided and inserts them into the DB.
22
+ *
23
+ * Called on hook 'wprss_fetch_single_feed_hook'.
24
+ *
25
+ * @since 3.2
26
+ */
27
+ function wprss_fetch_insert_single_feed_items( $feed_ID ) {
28
+ set_transient('wpra/feeds/importing/' . $feed_ID, true, 0);
29
+
30
+ global $wprss_importing_feed;
31
+ $wprss_importing_feed = $feed_ID;
32
+
33
+ register_shutdown_function('wprss_detect_exec_timeout');
34
+
35
+ $importFn = function ($feed_ID) {
36
+ $logger = wpra_get_logger($feed_ID);
37
+
38
+ $logger->info('Starting import of feed {id}', ['id' => $feed_ID]);
39
+
40
+ // Check if the feed source is active.
41
+ if ( ! wprss_is_feed_source_active( $feed_ID ) && ! wprss_feed_source_force_next_fetch( $feed_ID ) ) {
42
+ $logger->info('Feed is not active. Finished');
43
+ return;
44
+ }
45
 
46
+ // If the feed source is forced for next fetch, remove the force next fetch data
47
+ if ( wprss_feed_source_force_next_fetch( $feed_ID ) ) {
48
+ delete_post_meta( $feed_ID, 'wprss_force_next_fetch' );
49
+ }
50
 
51
+ // Truncate old items first
52
+ wprss_truncate_items_for_source( $feed_ID );
53
 
54
+ // Get the feed source URL from post meta, and filter it
55
+ $feed_url = get_post_meta( $feed_ID, 'wprss_url', true );
56
+ $feed_url = apply_filters( 'wprss_feed_source_url', $feed_url, $feed_ID );
57
+ $logger->debug('Feed source URL: {0}', [$feed_url]);
58
 
59
+ // Get the feed limit from post meta
60
+ $feed_limit = get_post_meta( $feed_ID, 'wprss_limit', true );
61
 
62
+ // If the feed has no individual limit
63
+ if ( $feed_limit === '' || intval( $feed_limit ) <= 0 ) {
64
+ // Get the global limit
65
+ $global_limit = wprss_get_general_setting('limit_feed_items_imported');
66
+ // If no global limit is set, mark as NULL
67
+ if ( $global_limit === '' || intval($global_limit) <= 0 ) {
68
+ $feed_limit = NULL;
69
+ }
70
+ else $feed_limit = $global_limit;
71
  }
 
 
 
 
 
 
 
 
 
72
 
73
+ // Filter the URL for validaty
74
+ if ( ! wprss_validate_url( $feed_url ) ) {
75
+ $logger->error('Feed URL is not valid!');
76
  } else {
77
+ // Get the feed items from the source
78
+ $items = wprss_get_feed_items( $feed_url, $feed_ID );
79
 
80
+ // If got NULL, convert to an empty array
81
+ if ( $items === NULL ) {
82
+ $items_to_insert = array();
83
  } else {
84
+ // See `wprss_item_comparators` filter
85
+ wprss_sort_items($items);
 
 
 
 
 
86
 
87
+ // If using a limit ...
88
+ if ( $feed_limit === NULL ) {
89
+ $items_to_insert = $items;
90
+ } else {
91
+ $items_to_insert = array_slice( $items, 0, $feed_limit );
92
+ $logger->debug('{0} items in the feed, {1} items after applying limit', [
93
+ count($items),
94
+ count($items_to_insert)
95
+ ]);
96
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
98
 
99
+ $unique_titles_only = get_post_meta($feed_ID, 'wprss_unique_titles', true);
100
+ $unique_titles_only = ($unique_titles_only === '')
101
+ ? wprss_get_general_setting('unique_titles')
102
+ : $unique_titles_only;
103
+ $unique_titles_only = filter_var($unique_titles_only, FILTER_VALIDATE_BOOLEAN);
104
+ // Gather the titles of the items that are imported
105
+ // The import process will check not only the titles in the DB but the titles currently in the feed
106
+ $existing_titles = [];
107
+
108
+ // Gather the permalinks of existing feed item's related to this feed source
109
+ $existing_permalinks = wprss_get_existing_permalinks( $feed_ID );
110
+
111
+ // Generate a list of items fetched, that are not already in the DB
112
+ $new_items = array();
113
+ foreach ( $items_to_insert as $item ) {
114
+ $item_title = $item->get_title();
115
+ $permalink = wprss_normalize_permalink( $item->get_permalink(), $item, $feed_ID );
116
+
117
+ // Check if blacklisted
118
+ if (wprss_is_blacklisted($permalink)) {
119
+ $logger->debug('Item "{0}" is blacklisted', [$item_title]);
120
+
121
+ continue;
122
+ }
123
 
124
+ // Check if already imported
125
+ if (array_key_exists($permalink, $existing_permalinks)) {
126
+ $logger->debug('Item "{0}" already exists in the database', [$item_title]);
 
127
 
128
+ continue;
129
+ }
130
 
131
+ // Check if title exists (if the option is enabled)
132
+ if ($unique_titles_only) {
133
+ $title_exists_db = wprss_item_title_exists($item->get_title());
134
+ $title_exists_feed = array_key_exists($item_title, $existing_titles);
135
+ $title_exists = $title_exists_db || $title_exists_feed;
136
+ // Add this item's title to the list to check against
137
+ $existing_titles[$item_title] = 1;
138
 
139
+ if ($title_exists) {
140
+ $logger->debug('An item with the title "{0}" already exists', [$item_title]);
 
 
141
 
142
+ continue;
143
+ }
144
+ }
 
145
 
146
+ $new_items[] = $item;
 
 
 
147
  }
148
 
149
+ $original_count = count( $items_to_insert );
150
+ $new_count = count( $new_items );
151
 
152
+ if ( $new_count !== $original_count ) {
153
+ $logger->debug('{0} will be skipped', [$original_count - $new_count]);
154
+ }
155
 
156
+ $items_to_insert = $new_items;
157
+ $per_import = wprss_get_general_setting('limit_feed_items_per_import');
158
+ if (!empty($per_import)) {
159
+ $items_to_insert = array_slice( $items_to_insert, 0, $per_import );
160
+ }
161
 
162
+ // If using a limit - delete any excess items to make room for the new items
163
+ if ( $feed_limit !== NULL ) {
164
+ // Get the number of feed items in DB, and their count
165
+ $db_feed_items = wprss_get_feed_items_for_source( $feed_ID );
166
+ $num_db_feed_items = $db_feed_items->post_count;
167
+
168
+ // Get the number of feed items we can store until we reach the limit
169
+ $num_can_insert = $feed_limit - $num_db_feed_items;
170
+ // Calculate how many feed items we must delete before importing, to keep to the limit
171
+ $num_new_items = count( $new_items );
172
+ $num_feed_items_to_delete = $num_can_insert > $num_new_items
173
+ ? 0
174
+ : $num_new_items - $num_can_insert;
175
+
176
+ // Get an array with the DB feed items in reverse order (oldest first)
177
+ $db_feed_items_reversed = array_reverse( $db_feed_items->posts );
178
+ // Cut the array to get only the first few that are to be deleted ( equal to $num_feed_items_to_delete )
179
+ $feed_items_to_delete = array_slice( $db_feed_items_reversed, 0, $num_feed_items_to_delete );
180
+
181
+ // Iterate the feed items and delete them
182
+ $num_items_deleted = 0;
183
+ foreach ( $feed_items_to_delete as $key => $post ) {
184
+ wp_delete_post( $post->ID, TRUE );
185
+ $num_items_deleted++;
186
+ }
187
 
188
+ if ($num_items_deleted > 0) {
189
+ $logger->info('Deleted the oldest {0} items', [$num_items_deleted]);
190
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
 
193
+ update_post_meta( $feed_ID, 'wprss_last_update', $last_update_time = time() );
194
+ update_post_meta( $feed_ID, 'wprss_last_update_items', 0 );
195
+
196
+ // Insert the items into the db
197
+ if ( !empty( $items_to_insert ) ) {
198
+ wprss_items_insert_post( $items_to_insert, $feed_ID );
199
  }
200
  }
201
 
202
+ $next_scheduled = get_post_meta( $feed_ID, 'wprss_reschedule_event', TRUE );
 
203
 
204
+ if ( $next_scheduled !== '' ) {
205
+ wprss_feed_source_update_start_schedule( $feed_ID );
206
+ delete_post_meta( $feed_ID, 'wprss_reschedule_event' );
207
+ $logger->info('Scheduled next update');
208
  }
 
 
 
209
 
210
+ $logger->info('Import completed!');
 
 
 
 
 
 
211
 
212
+ };
 
213
 
214
+ $importFn($feed_ID);
 
 
 
 
 
215
 
216
+ delete_transient('wpra/feeds/importing/' . $feed_ID);
217
+ wprss_flag_feed_as_idle($feed_ID);
218
+ $wprss_importing_feed = null;
219
+ }
220
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
+ /**
223
+ * Fetches the feed items from a feed at the given URL.
224
+ *
225
+ * Called from 'wprss_fetch_insert_single_feed_items'
226
+ *
227
+ * @since 3.0
228
+ */
229
+ function wprss_get_feed_items( $feed_url, $source, $force_feed = FALSE ) {
230
+ // Add filters and actions prior to fetching the feed items
231
+ add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
232
 
233
+ /* Fetch the feed from the soure URL specified */
234
+ $feed = wprss_fetch_feed( $feed_url, $source, $force_feed );
 
 
 
235
 
236
+ if (is_wp_error($feed)) {
237
+ wpra_get_logger($source)->error('Failed to fetch the feed from {0}. Error: {1}', [
238
+ $feed_url,
239
+ $feed->get_error_message()
240
+ ]);
241
 
242
+ return NULL;
243
+ }
244
 
245
+ update_post_meta( $source, 'wprss_site_url', $feed->get_permalink() );
246
+ update_post_meta( $source, 'wprss_feed_image', $feed->get_image_url() );
247
 
248
+ // Remove previously added filters and actions
249
+ remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
250
 
251
+ return @$feed->get_items();
252
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
+ //add_action ('cron_request', 'wpse_cron_add_xdebug_cookie', 10, 2) ;
255
 
256
+ /**
257
+ * Allow debugging of wp_cron jobs
258
+ *
259
+ * @param array $cron_request_array
260
+ * @param string $doing_wp_cron
261
+ *
262
+ * @return array $cron_request_array with the current XDEBUG_SESSION cookie added if set
263
+ */
264
+ function wpse_cron_add_xdebug_cookie ($cron_request_array, $doing_wp_cron)
265
+ {
266
+ if (empty ($_COOKIE['XDEBUG_SESSION'])) {
267
+ return ($cron_request_array) ;
268
+ }
269
 
270
+ if (empty ($cron_request_array['args']['cookies'])) {
271
+ $cron_request_array['args']['cookies'] = array () ;
272
+ }
273
+ $cron_request_array['args']['cookies']['XDEBUG_SESSION'] = $_COOKIE['XDEBUG_SESSION'] ;
274
 
275
+ return ($cron_request_array) ;
 
276
  }
277
 
278
  /**
316
  }
317
 
318
 
319
+ /**
320
+ * A clone of the function 'fetch_feed' in wp-includes/feed.php [line #529]
321
+ *
322
+ * Called from 'wprss_get_feed_items'
323
+ *
324
+ * @since 3.5
325
+ */
326
+ function wprss_fetch_feed($url, $source = null, $param_force_feed = false)
327
+ {
328
+ // Trim the URL
329
+ $url = trim($url);
330
+ // Parse the URL
331
+ $parsed = wpra_parse_url($url);
332
+ // Filter the URL
333
+ $url = apply_filters('wpra/importer/feed/url', $url, $parsed);
334
+
335
+ // Initialize the Feed
336
+ $feed = new SimplePie();
337
+ $feed->set_feed_url($url);
338
+ $feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_ALL);
339
+
340
+ // If a feed source was passed
341
+ if ($source !== null || $param_force_feed) {
342
+ // Get the force feed option for the feed source
343
+ $force_feed = get_post_meta($source, 'wprss_force_feed', true);
344
+ // If turned on, force the feed
345
+ if ($force_feed == 'true' || $param_force_feed) {
346
+ $feed->force_feed(true);
347
+
348
+ global $wpraNoSslVerification;
349
+ $wpraNoSslVerification = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  }
351
  }
 
352
 
353
+ // Set timeout limit
354
+ $fetch_time_limit = wprss_get_feed_fetch_time_limit();
355
+ $feed->set_timeout($fetch_time_limit);
356
 
357
+ $cacheEnabled = wprss_is_feed_cache_enabled();
358
+ $feed->enable_cache($cacheEnabled);
359
 
360
+ if ($cacheEnabled) {
361
+ $feed->set_cache_location(wprss_get_feed_cache_dir());
362
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
364
+ // Reference array action hook, for the feed object and the URL
365
+ do_action_ref_array('wp_feed_options', array(&$feed, $url));
 
366
 
367
+ // Prepare the tags to strip from the feed
368
+ $tags_to_strip = apply_filters('wprss_feed_tags_to_strip', $feed->strip_htmltags, $source);
369
+ // Strip them
370
+ $feed->strip_htmltags($tags_to_strip);
371
 
372
+ do_action('wprss_fetch_feed_before', $feed, $source);
 
 
373
 
374
+ // Fetch the feed
375
+ $feed->init();
376
+ $feed->handle_content_type();
377
 
378
+ do_action('wprss_fetch_feed_after', $feed);
 
 
379
 
380
+ // Convert the feed error into a WP_Error, if applicable
381
+ if ($feed->error()) {
382
+ if ($source !== null) {
383
+ $msg = sprintf(__('Failed to fetch the RSS feed. Error: %s', WPRSS_TEXT_DOMAIN), $feed->error());
384
+ update_post_meta($source, 'wprss_error_last_import', $msg);
385
  }
386
+ return new WP_Error('simplepie-error', $feed->error(), array('feed' => $feed));
387
  }
388
+ // If no error, return the feed and remove any error meta
389
+ delete_post_meta($source, 'wprss_error_last_import');
390
+ return $feed;
391
+ }
392
+
393
+
394
+ /**
395
+ * Normalizes the given permalink.
396
+ *
397
+ * @param $permalink The permalink to normalize
398
+ * @return string The normalized permalink
399
+ * @since 4.2.3
400
+ */
401
+ function wprss_normalize_permalink( $permalink, $item, $feed_ID) {
402
+ // Apply normalization functions on the permalink
403
+ $permalink = trim( $permalink );
404
+ $permalink = apply_filters( 'wprss_normalize_permalink', $permalink, $item, $feed_ID);
405
+ // Return the normalized permalink
406
+ return $permalink;
407
+ }
408
+
409
+
410
+ /**
411
+ * Extracts the actual URL from a Google News permalink
412
+ *
413
+ * @param string $permalink The permalink to normalize.
414
+ * @since 4.2.3
415
+ */
416
+ function wprss_google_news_url_fix($permalink) {
417
+ return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?' . preg_quote('news.google.com', '!') . '.*!');
418
+ }
419
+
420
+
421
+ /**
422
+ * Extracts the actual URL from a Google Alerts permalink
423
+ *
424
+ * @param string $permalink The permalink to normalize.
425
+ * @since 4.7.3
426
+ */
427
+ function wprss_google_alerts_url_fix($permalink) {
428
+ return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('google.com/url', '!') . '.*!');
429
+ }
430
+
431
+
432
+ /**
433
+ * Extracts the actual URL from a Bing permalink
434
+ *
435
+ * @param string $permalink The permalink to normalize.
436
+ * @since 4.2.3
437
+ */
438
+ function wprss_bing_news_url_fix($permalink) {
439
+ return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('bing.com/news', '!') . '.*!');
440
+ }
441
+
442
+
443
+ /**
444
+ * Checks if the permalink is a tracking permalink based on host, and if
445
+ * it is, returns the normalized URL of the proper feed item article,
446
+ * determined by the named query argument.
447
+ *
448
+ * Fixes the issue with equivalent Google News etc. items having
449
+ * different URLs, that contain randomly generated GET parameters.
450
+ * Example:
451
+ *
452
+ * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=V3e9U6izMMnm1QaB1YHoDA&url=http://abcd...
453
+ * http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=One9U-HQLsTp1Aal-oDQBQ&url=http://abcd...
454
+ *
455
+ * @param string $permalink The permalink URL to check and/or normalize.
456
+ * @param string|array $patterns One or an array of host names, for which the URL should be fixed.
457
+ * @param string Name of the query argument that specifies the actual URL.
458
+ * @return string The normalized URL of the original article, as indicated by the `url`
459
+ * parameter in the URL query string.
460
+ * @since 4.2.3
461
+ */
462
+ function wprss_tracking_url_fix( $permalink, $patterns, $argName = 'url' ) {
463
+ // Parse the url
464
+ $parsed = parse_url( urldecode( html_entity_decode( $permalink ) ) );
465
+ $patterns = is_array($patterns) ? $patterns :array($patterns);
466
+
467
+ // If parsing failed, return the permalink
468
+ if ( $parsed === FALSE || $parsed === NULL ) return $permalink;
469
+
470
+ // Determine if it's a tracking item
471
+ $isMatch = false;
472
+ foreach( $patterns as $_idx => $_pattern ) {
473
+ if( preg_match($_pattern, $permalink) ) {
474
+ $isMatch = true;
475
+ break;
476
+ }
477
+ }
478
+
479
+ if( !$isMatch ) return $permalink;
480
+
481
+ // Check if the url GET query string is present
482
+ if ( !isset( $parsed['query'] ) ) return $permalink;
483
+
484
+ // Parse the query string
485
+ $query = array();
486
+ parse_str( $parsed['query'], $query );
487
+
488
+ // Check if the url GET parameter is present in the query string
489
+ if ( !is_array($query) || !isset( $query[$argName] ) ) return $permalink;
490
+
491
+ return urldecode( $query[$argName] );
492
+ }
493
+
494
+
495
+ /**
496
+ * Converts YouTube, Vimeo and DailyMotion video urls
497
+ * into embedded video player urls.
498
+ * If the permalink is not a video url, the permalink is returned as is.
499
+ *
500
+ * @param $permalink The string permalink url to convert.
501
+ * @return A string, with the convert permalink, or the same permalink passed as parameter if
502
+ * not a video url.
503
+ * @since 4.0
504
+ */
505
+ function wprss_convert_video_permalink( $permalink ) {
506
+ // CHECK PERMALINK FOR VIDEO HOSTS : YOUTUBE, VIMEO AND DAILYMOTION
507
+ $found_video_host = preg_match( '/http[s]?:\/\/(www\.)?(youtube|dailymotion|vimeo)\.com\/(.*)/i', $permalink, $matches );
508
+
509
+ // If video host was found
510
+ if ( $found_video_host !== 0 && $found_video_host !== FALSE ) {
511
+
512
+ // Get general options
513
+ $options = get_option( 'wprss_settings_general' );
514
+ // Get the video link option entry, or false if it does not exist
515
+ $video_link = ( isset($options['video_link']) )? $options['video_link'] : 'false';
516
+
517
+ // If the video link option is true, change the video URL to its repective host's embedded
518
+ // video player URL. Otherwise, leave the permalink as is.
519
+ if ( strtolower( $video_link ) === 'true' ) {
520
+ $host = $matches[2];
521
+ switch( $host ) {
522
+ case 'youtube':
523
+ preg_match( '/(&|\?)v=([^&]+)/', $permalink, $yt_matches );
524
+ $permalink = 'https://www.youtube.com/embed/' . $yt_matches[2];
525
+ break;
526
+ case 'vimeo':
527
+ preg_match( '/(\d*)$/i', $permalink, $vim_matches );
528
+ $permalink = 'https://player.vimeo.com/video/' . $vim_matches[0];
529
+ break;
530
+ case 'dailymotion':
531
+ preg_match( '/(\.com\/)(video\/)(.*)/i', $permalink, $dm_matches );
532
+ $permalink = 'https://www.dailymotion.com/embed/video/' . $dm_matches[3];
533
+ break;
534
+ }
535
+ }
536
+ }
537
+
538
+ return $permalink;
539
+ }
540
+
541
+
542
+ /**
543
+ * Insert wprss_feed_item posts into the DB
544
+ *
545
+ * @since 3.0
546
+ *
547
+ * @param SimplePie_Item[] $items
548
+ * @param int|string $feed_ID
549
+ */
550
+ function wprss_items_insert_post( $items, $feed_ID ) {
551
+ update_post_meta( $feed_ID, 'wprss_feed_is_updating', $update_started_at = time() );
552
+ $logger = wpra_get_logger($feed_ID);
553
+
554
+ // Gather the permalinks of existing feed item's related to this feed source
555
+ $existing_permalinks = wprss_get_existing_permalinks( $feed_ID );
556
+
557
+ // Count of items inserted
558
+ $items_inserted = 0;
559
+
560
+ foreach ( $items as $i => $item ) {
561
+
562
+ // Normalize the URL
563
+ $permalink = $item->get_permalink(); // Link or enclosure URL
564
+ $permalink = htmlspecialchars_decode( $permalink ); // SimplePie encodes HTML special chars
565
+
566
+ $logger->debug('Saving item "{0}"', [$item->get_title()]);
567
+
568
+ $permalink = wprss_normalize_permalink( $permalink, $item, $feed_ID );
569
+
570
+ // Save the enclosure URL
571
+ $enclosure_url = '';
572
+ $enclosure = $item->get_enclosure(0);
573
+
574
+ if ($enclosure && $enclosure->get_link()) {
575
+ $enclosure_url = $enclosure->get_link();
576
+ }
577
+
578
+ // Check if newly fetched item already present in existing feed items,
579
+ // if not insert it into wp_posts and insert post meta.
580
+ if ( ! ( array_key_exists( $permalink, $existing_permalinks ) ) ) {
581
+ // Extend the importing time and refresh the feed's updating flag to reflect that it is active
582
+ $time_limit = wprss_get_item_import_time_limit();
583
+ set_time_limit( $time_limit );
584
+
585
+ // Apply filters that determine if the feed item should be inserted into the DB or not.
586
+ $ogItem = $item;
587
+ $item = apply_filters( 'wprss_insert_post_item_conditionals', $item, $feed_ID, $permalink );
588
+ /* @var $item SimplePie_Item */
589
+
590
+ // Check if the imported count should still be updated, even if the item is NULL
591
+ $still_update_count = apply_filters( 'wprss_still_update_import_count', FALSE );
592
+
593
+ // If the item is not NULL, continue to inserting the feed item post into the DB
594
+ if ( $item !== NULL && !is_bool($item) ) {
595
+ $post_status = 'publish';
596
+
597
+ // Get the date and GTM date and normalize if not valid dor not present
598
+ $format = 'Y-m-d H:i:s';
599
+ $has_date = $item->get_date( 'U' ) ? TRUE : FALSE;
600
+ $timestamp = $has_date ? $item->get_date( 'U' ) : date( 'U' );
601
+
602
+ // Item has a future timestamp
603
+ if ($timestamp > time()) {
604
+ $schedule_items_filter = apply_filters('wpra/importer/allow_scheduled_items', false);
605
+ $schedule_items_option = wprss_get_general_setting('schedule_future_items');
606
+
607
+ if ($schedule_items_filter || $schedule_items_option) {
608
+ // If can schedule future items, set the post status to "future" (aka scheduled)
609
+ $post_status = 'future';
610
+ } else {
611
+ // If cannot schedule future items, clamp the timestamp to the currrent time minus
612
+ // 1 second for each iteration done so far
613
+ $timestamp = min(time() - $i, $timestamp);
614
+ }
615
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
 
617
+ $date = date( $format, $timestamp );
618
+ $date_gmt = gmdate( $format, $timestamp );
619
+
620
+ // Do not let WordPress sanitize the excerpt
621
+ // WordPress sanitizes the excerpt because it's expected to be typed by a user and sent in a POST
622
+ // request. However, our excerpt is being inserted as a raw string with custom sanitization.
623
+ remove_all_filters( 'excerpt_save_pre' );
624
+
625
+ // Prepare the item data
626
+ $feed_item = apply_filters(
627
+ 'wprss_populate_post_data',
628
+ array(
629
+ 'post_title' => html_entity_decode( $item->get_title() ),
630
+ 'post_content' => $item->get_content(),
631
+ 'post_excerpt' => wprss_sanitize_excerpt($item->get_description()),
632
+ 'post_status' => $post_status,
633
+ 'post_type' => 'wprss_feed_item',
634
+ 'post_date' => $date,
635
+ 'post_date_gmt' => $date_gmt
636
+ ),
637
+ $item
638
+ );
639
+
640
+ if ( defined('ICL_SITEPRESS_VERSION') )
641
+ @include_once( WP_PLUGIN_DIR . '/sitepress-multilingual-cms/inc/wpml-api.php' );
642
+ if ( defined('ICL_LANGUAGE_CODE') ) {
643
+ $_POST['icl_post_language'] = $language_code = ICL_LANGUAGE_CODE;
644
+ }
645
+
646
+ // Create and insert post object into the DB
647
+ $inserted_ID = wp_insert_post( $feed_item );
648
+
649
+ if ( !is_wp_error( $inserted_ID ) ) {
650
+
651
+ if ( is_object( $inserted_ID ) ) {
652
+ if ( isset( $inserted_ID['ID'] ) ) {
653
+ $inserted_ID = $inserted_ID['ID'];
654
+ }
655
+ elseif ( isset( $inserted_ID->ID ) ) {
656
+ $inserted_ID = $inserted_ID->ID;
657
+ }
658
+ }
659
+
660
+ // Increment the inserted items counter
661
+ $items_inserted++;
662
+
663
+ // Create and insert post meta into the DB
664
+ wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url );
665
+
666
+ // Remember newly added permalink
667
+ $existing_permalinks[$permalink] = 1;
668
+ }
669
+ else {
670
+ update_post_meta( $feed_ID, 'wprss_error_last_import', 'An error occurred while inserting a feed item into the database.' );
671
+
672
+ $logger->error('Failed to save item "{0}" into the database', [$item->get_title()]);
673
+ }
674
+ }
675
+ // If the item is TRUE, then a hook function in the filter inserted the item.
676
+ // increment the inserted counter
677
+ elseif ( ( is_bool($item) && $item === TRUE ) || ( $still_update_count === TRUE && $item !== FALSE ) ) {
678
+ $items_inserted++;
679
+ } elseif (has_filter('wprss_insert_post_item_conditionals', 'wprss_kf_check_post_item_keywords')) {
680
+ $logger->info('Item "{0}" was rejected by your keyword or tag filtering.', [
681
+ $ogItem->get_title()
682
+ ]);
683
+ } else {
684
+ $logger->notice('Item "{0}" was rejected by an add-on.', [
685
+ $ogItem->get_title()
686
+ ]);
687
  }
688
+ }
689
+ }
690
 
691
+ update_post_meta( $feed_ID, 'wprss_last_update_items', $items_inserted );
692
+ }
 
 
 
 
 
 
 
 
 
693
 
694
+ /**
695
+ * Inserts the appropriate post meta for feed items.
696
+ *
697
+ * Called from 'wprss_items_insert_post'
698
+ *
699
+ * @since 2.3
700
+ *
701
+ * @param int $inserted_ID The inserted post ID.
702
+ * @param SimplePie_Item $item The SimplePie item object.
703
+ * @param string $permalink The item's permalink.
704
+ * @param string $enclosure_url The URL to the item's enclosure.
705
+ */
706
+ function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url ) {
707
+ update_post_meta( $inserted_ID, 'wprss_item_date', $item->get_date(DATE_ISO8601) );
708
+ update_post_meta( $inserted_ID, 'wprss_item_permalink', $permalink );
709
+ update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosure_url );
710
+
711
+ /* @var $item SimplePie_Item */
712
+ $feed = $item->get_feed();
713
+
714
+ // Get the source from the RSS item
715
+ $source = $item->get_source();
716
+
717
+ // Get the source name if available. If empty, default to the feed source CPT title
718
+ $source_name = ($source === null) ? '' : $source->get_title();
719
+ $source_name = empty($source_name) ? $feed->get_title() : $source_name;
720
+
721
+ // Get the source URL if available. If empty, default to the RSS feed's URL
722
+ $source_url = ($source === null) ? '' : $source->get_permalink();
723
+ $source_url = empty($source_url) ? $feed->get_permalink() : $source_url;
724
+
725
+ update_post_meta( $inserted_ID, 'wprss_item_source_name', $source_name);
726
+ update_post_meta( $inserted_ID, 'wprss_item_source_url', $source_url);
727
+
728
+ $author = $item->get_author();
729
+ if ($author instanceof SimplePie_Author) {
730
+ update_post_meta( $inserted_ID, 'wprss_item_author', $author->get_name() );
731
+ update_post_meta( $inserted_ID, 'wprss_item_author_email', $author->get_email() );
732
+ update_post_meta( $inserted_ID, 'wprss_item_author_link', $author->get_link() );
733
+ }
734
+
735
+ update_post_meta( $inserted_ID, 'wprss_feed_id', $feed_ID);
736
+ do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
737
+ }
738
+
739
+
740
+ /**
741
+ * Returns the time limit for the importing of a single feed item.
742
+ * The value if filtered through 'wprss_item_import_time_limit'. The default value is WPRSS_ITEM_IMPORT_TIME_LIMIT.
743
+ *
744
+ * @since 4.6.6
745
+ * @return int The maximum amount of seconds allowed for a single feed item to import.
746
+ */
747
+ function wprss_get_item_import_time_limit() {
748
+ return apply_filters( 'wprss_item_import_time_limit', WPRSS_ITEM_IMPORT_TIME_LIMIT );
749
+ }
750
+
751
+ /**
752
+ * Returns the time limit for a feed fetch operation.
753
+ * The value if filtered through 'wprss_feed_fetch_time_limit'. The default value is WPRSS_FEED_FETCH_TIME_LIMIT.
754
+ *
755
+ * @since 4.6.6
756
+ * @return int The maximum amount of seconds allowed for an RSS feed XML document to be fetched.
757
+ */
758
+ function wprss_get_feed_fetch_time_limit() {
759
+ return apply_filters( 'wprss_feed_fetch_time_limit', WPRSS_FEED_FETCH_TIME_LIMIT );
760
+ }
761
+
762
+
763
+ /**
764
+ * Fetches all feed items from all feed sources.
765
+ * Iteratively calls 'wprss_fetch_insert_single_feed_items' for all feed sources.
766
+ *
767
+ * This function is used by the cron job or the debugging functions to get all feeds from all feed sources
768
+ *
769
+ * @param $all If set to TRUE, the function will pull from all feed sources, regardless of their individual
770
+ * update interval. If set to FALSE, only feed sources using the global update system will be updated.
771
+ * (Optional) Default: TRUE.
772
+ * @since 3.0
773
+ */
774
+ function wprss_fetch_insert_all_feed_items( $all = TRUE ) {
775
+ wpra_get_logger()->info('Beginning import for all feed sources');
776
+ // Get all feed sources
777
+ $feed_sources = wprss_get_all_feed_sources();
778
+
779
+ if( $feed_sources->have_posts() ) {
780
+ // Start by getting one feed source, we will cycle through them one by one,
781
+ // fetching feed items and adding them to the database in each pass
782
+ while ( $feed_sources->have_posts() ) {
783
+ $feed_sources->the_post();
784
+
785
+ $interval = get_post_meta( get_the_ID(), 'wprss_update_interval', TRUE );
786
+ $using_global_interval = ( $interval === wprss_get_default_feed_source_update_interval() || $interval === '' );
787
+
788
+ // Check if fetching from all, or if feed source uses the global interval
789
+ if ( $all === TRUE || $using_global_interval ) {
790
+ wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( get_the_ID() ) );
791
+ }
792
+ }
793
+ wp_reset_postdata(); // Restore the $post global to the current post in the main query
794
+ }
795
+ }
796
+
797
+
798
+ /**
799
+ * Runs the above function with parameter FALSE
800
+ *
801
+ * @since 3.9
802
+ */
803
+ function wprss_fetch_insert_all_feed_items_from_cron() {
804
+ wprss_fetch_insert_all_feed_items( FALSE );
805
+ }
806
+
807
+
808
+ /**
809
+ * Shutdown function for detecting if the PHP script reaches the maximum execution time limit
810
+ * while importing a feed.
811
+ *
812
+ * @since 4.6.6
813
+ */
814
+ function wprss_detect_exec_timeout() {
815
+ global $wprss_importing_feed;
816
+ $feed_ID = (isset($wprss_importing_feed) && !empty($wprss_importing_feed))
817
+ ? $wprss_importing_feed
818
+ : null;
819
 
820
+ if ($feed_ID === null) {
821
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
822
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
+ // Remove the "importing" flag from the feed source
825
+ wprss_flag_feed_as_idle($feed_ID);
826
 
827
+ // If no error, stop
828
+ $error = error_get_last();
829
+ if (empty($error)) {
830
+ return;
 
 
 
 
831
  }
 
 
 
 
 
 
 
 
 
 
 
832
 
833
+ $msg = sprintf(
834
+ __('The importing process failed after %d seconds with the message: "%s"', 'wprss'),
835
+ wprss_get_item_import_time_limit(),
836
+ $error['message']
837
+ );
838
+ // Save the error in the feed source's meta and the plugin log
839
+ update_post_meta($feed_ID, 'wprss_error_last_import', $msg);
840
+ wpra_get_logger($feed_ID)->error($msg);
841
+ }
842
 
843
+ /**
844
+ * Validates a feed item.
845
+ *
846
+ * @since 4.11.2
847
+ *
848
+ * @param \SimplePie_Item|mixed $item The item to validate.
849
+ *
850
+ * @return \SimplePie_Item|null The item, if it passes; otherwise, null.
851
+ */
852
+ function wprss_item_filter_valid($item)
853
+ {
854
+ return $item instanceof \SimplePie_Item
855
+ ? $item
856
+ : null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
857
  }
858
 
859
+ /**
860
+ * Sorts items according to settings.
861
+ *
862
+ * Use the `wprss_item_comparators` filter to change the list of comparators
863
+ * used to determine the new order of items. See {@see wprss_items_sort_compare_items()}.
864
+ *
865
+ * @since 4.11.2
866
+ *
867
+ * @param \SimplePie_Item[] $items The items list.
868
+ * @param \WP_Post $feedSource The feed source, for which to sort, if any.
869
+ */
870
+ function wprss_sort_items(&$items, $feedSource = null)
871
+ {
872
+ // Callbacks used to compare items
873
+ $comparators = apply_filters('wprss_item_comparators', array());
874
+ if (empty($comparators)) {
875
+ return;
876
+ }
 
 
 
 
 
 
 
 
877
 
878
+ try {
879
+ usort($items, function ($itemA, $itemB) use ($comparators, $feedSource) {
880
+ return wprss_items_sort_compare_items($itemA, $itemB, $comparators, $feedSource);
881
+ });
882
+ } catch (\InvalidArgumentException $e) {
883
+ wpra_get_logger($feedSource)->warning('Encountered an error while sorting the database items: {0}', [
884
+ $e->getMessage()
885
+ ]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
  }
 
887
  }
 
 
888
 
889
+ /**
890
+ * Recursively compares two items using a list of comparators.
891
+ *
892
+ * If a comparator determines that two items are equal, then the items are
893
+ * evaluated using the next comparator in list, recursively until one of
894
+ * the comparators establishes a difference between items, or the list of
895
+ * comparators is exhausted.
896
+ *
897
+ * @since 4.11.2
898
+ *
899
+ * @param \SimplePie_Item|mixed $itemA The item being compared;
900
+ * @param \SimplePie_Item|mixed $itemB The item being compared to;
901
+ * @param callable[] $comparators A list of functions for item comparison.
902
+ *
903
+ * @return int A result usable as a return value for {@see usort()}.
904
+ *
905
+ * @throws \InvalidArgumentException If the comparator is not callable.
906
+ */
907
+ function wprss_items_sort_compare_items($itemA, $itemB, $comparators, $feedSource = null)
908
+ {
909
+ if (empty($comparators)) {
910
+ return 0;
911
+ }
 
 
912
 
913
+ $comparator = array_shift($comparators);
914
+ if (!is_callable($comparator)) {
915
+ throw new \InvalidArgumentException('Comparator must be callable');
916
+ }
917
 
918
+ $result = call_user_func_array($comparator, array($itemA, $itemB, $feedSource));
919
+ if (!$result) {
920
+ return wprss_items_sort_compare_items($itemA, $itemB, $comparators);
921
+ }
 
922
 
923
+ return $result;
 
 
 
 
 
924
  }
925
 
926
+ /**
927
+ * Retrieves a custom field of a feed source, or a general setting if the field doesn't exist.
928
+ *
929
+ * @since 4.11.2
930
+ *
931
+ * @param string $key The key of the field or setting.
932
+ * @param \WP_Post|null $feedSource The feed source, if any.
933
+ * @return type
934
+ */
935
+ function wprss_get_source_meta_or_setting($key, $feedSource = null)
936
+ {
937
+ $value = null;
938
+ if ($feedSource instanceof \WP_Post) {
939
+ $value = $feedSource->{$key};
940
+ }
 
 
 
 
 
 
 
 
 
 
941
 
942
+ return $value !== null && $value !== false
943
+ ? $value
944
+ : wprss_get_general_setting($key);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
945
  }
946
 
947
+ /**
948
+ * Determines date order of two feed items.
949
+ *
950
+ * Which should come first is determined by `feed_items_import_order` setting.
951
+ *
952
+ * @since 4.11.2
953
+ *
954
+ * @param \SimplePie_Item|mixed $itemA The first item.
955
+ * @param \SimplePie_Item|mixed $itemB The second item.
956
+ * @param \WP_Post|null $feedSource The feed source for which the items are being compared, if any.
957
+ * @return int A comparison result for {@see usort()}.
958
+ */
959
+ function wprss_item_comparator_date($itemA, $itemB, $feedSource = null)
960
+ {
961
+ $sortOrder = wprss_get_source_meta_or_setting('feed_items_import_order', $feedSource);
962
+ if (empty($sortOrder)) {
963
+ return 0;
964
+ }
965
 
966
+ if (!wprss_item_filter_valid($itemA) || !wprss_item_filter_valid($itemB)) {
967
+ return 0;
968
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
969
 
970
+ $aDate = intval($itemA->get_gmdate('U'));
971
+ $bDate = intval($itemB->get_gmdate('U'));
 
 
972
 
973
+ switch ($sortOrder) {
974
+ case 'latest':
975
+ if ($aDate === $bDate) {
976
+ return null;
977
+ }
978
+ return $aDate > $bDate ? -1 : 1;
979
+ break;
980
 
981
+ case 'oldest':
982
+ return $aDate < $bDate ? -1 : 1;
983
+ break;
984
 
985
+ case '':
986
+ default:
987
+ return 0;
988
+ break;
989
+ }
 
 
 
 
 
 
 
 
 
990
  }
991
 
992
+ /**
993
+ * Retrieves default comparators for sorting.
994
+ *
995
+ * @since 4.11.2
996
+ *
997
+ * @param \WP_Post|null $feedSource The feed source, for which to get comparators, if any.
998
+ *
999
+ * @return callable[] The list of comparators.
1000
+ */
1001
+ function wprss_sort_comparators_default($feedSource = null)
1002
+ {
1003
+ $helper = wprss_wp_container()->get('wprss.admin_helper');
1004
+ $defaultArgs = array(2 => $feedSource);
1005
+ return array(
1006
+ $helper->createCommand('wprss_item_comparator_date', $defaultArgs),
1007
+ );
 
 
 
 
 
 
1008
  }
1009
 
1010
+ /**
1011
+ * Sanitizes a post excerpt, cleverly removing all HTML markup while preserving text content and whitespace.
1012
+ *
1013
+ * @since 4.14
1014
+ *
1015
+ * @param string $excerpt The excerpt to sanitize.
1016
+ *
1017
+ * @return string
1018
+ */
1019
+ function wprss_sanitize_excerpt($excerpt) {
1020
+ // Decode HTML entities back to their respective characters
1021
+ $excerpt = html_entity_decode($excerpt);
1022
+ // Add a space between any HTML elements
1023
+ $excerpt = str_replace('>', ' >', $excerpt);
1024
+ // Strip all HTML tags
1025
+ $excerpt = strip_tags($excerpt);
1026
+ // Remove any redundant spaces
1027
+ $excerpt = str_replace(' ', ' ', trim($excerpt));
1028
+
1029
+ return $excerpt;
1030
  }
1031
 
1032
+ /**
1033
+ * Parses a URL, it's query and its path.
1034
+ *
1035
+ * @since 4.14
1036
+ *
1037
+ * @param string $url The URL to parse.
1038
+ *
1039
+ * @return array
1040
+ */
1041
+ function wpra_parse_url($url)
1042
+ {
1043
+ // Parse the URL
1044
+ $parsed = parse_url($url);
1045
+
1046
+ // Move the path to "path_str"
1047
+ $parsed['path_str'] = isset($parsed['path']) ? $parsed['path'] : '';
1048
+ // Explode the path
1049
+ $parsed['path'] = explode('/', $parsed['path_str']);
1050
+
1051
+ // Move the query to "query_str"
1052
+ $parsed['query_str'] = isset($parsed['query']) ? $parsed['query'] : '';
1053
+ // Parse the query
1054
+ parse_str($parsed['query_str'], $parsed['query']);
1055
+
1056
+ return $parsed;
1057
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/feed-processing.php CHANGED
@@ -1,710 +1,798 @@
1
  <?php
2
 
3
- define('WPRSS_TRANSIENT_NAME_IS_REIMPORTING', 'is_reimporting');
4
-
5
- /**
6
- * Returns whether or not the feed source will forcefully fetch the next fetch,
7
- * ignoring whether or not it is paused or not.
8
- *
9
- * @since 3.7
10
- *
11
- * @param int $source_id The ID of the feed source
12
- *
13
- * @return boolean
14
- */
15
- function wprss_feed_source_force_next_fetch($source_id)
16
- {
17
- $force = get_post_meta($source_id, 'wprss_force_next_fetch', true);
18
-
19
- return ($force !== '');
20
- }
21
-
22
- /**
23
- * Change the default feed cache recreation period to 2 hours
24
- *
25
- * Probably not needed since we are now disabling caching altogether
26
- *
27
- * @since 2.1
28
- */
29
- function wprss_feed_cache_lifetime($seconds)
30
- {
31
- return 1; // one second
32
- }
33
-
34
- /**
35
- * Disable caching of feeds in transients, we don't need it as we are storing them in the wp_posts table
36
- *
37
- * @since 3.0
38
- */
39
- function wprss_do_not_cache_feeds(&$feed)
40
- {
41
- $feed->enable_cache(false);
42
- }
43
-
44
- /**
45
- * Parameters for query to get all feed sources
46
- *
47
- * @since 3.0
48
- */
49
- function wprss_get_all_feed_sources()
50
- {
51
- $queryArgs = apply_filters(
52
- 'wprss_get_all_feed_sources',
53
- [
54
- 'post_type' => 'wprss_feed',
55
- 'post_status' => 'publish',
56
- 'cache_results' => false, // Disable caching, used for one-off queries
57
- 'no_found_rows' => true, // We don't need pagination, so disable it
58
- 'posts_per_page' => -1,
59
- ]
60
- );
61
-
62
- return new WP_Query($queryArgs);
63
- }
64
-
65
- /**
66
- * Retrieves the query to use for retrieving imported items.
67
- *
68
- * @since 4.17.4
69
- */
70
- function wprss_get_imported_items_query($source_id = null)
71
- {
72
- $args = [
73
- 'post_type' => array_values(get_post_types()),
74
- 'post_status' => 'any',
75
- 'cache_results' => false,
76
- 'no_found_rows' => true,
77
- 'posts_per_page' => -1,
78
- 'ignore_sticky_posts' => 'true',
79
- 'orderby' => 'date',
80
- 'order' => 'DESC',
81
- 'meta_query' => [
82
- 'relation' => 'AND',
83
- ],
84
- 'suppress_filters' => 1,
85
- ];
86
-
87
- if ($source_id !== null) {
88
- $args['meta_query'][] = [
89
- 'key' => 'wprss_feed_id',
90
- 'value' => (string) $source_id,
91
- 'compare' => '=',
92
- ];
93
- } else {
94
- $args['meta_query'][] = [
95
- 'key' => 'wprss_feed_id',
96
- 'compare' => 'EXISTS',
97
  ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
 
100
- return apply_filters('wprss_get_feed_items_for_source_args', $args, $source_id);
101
- }
102
-
103
- /**
104
- * Queries for imported items.
105
- *
106
- * @since 4.17.4
107
- */
108
- function wprss_get_imported_items($source_id = null)
109
- {
110
- return new WP_Query(wprss_get_imported_items_query($source_id));
111
- }
112
-
113
- /**
114
- * Returns all the feed items of a source.
115
- *
116
- * @since 3.8
117
- */
118
- function wprss_get_feed_items_for_source($source_id)
119
- {
120
- return wprss_get_imported_items($source_id);
121
- }
122
-
123
- /** Checks if a permalink exists in the database. */
124
- function wprss_permalink_exists($permalink) {
125
- global $wpdb;
126
-
127
- $numRows = $wpdb->query(
128
- $wpdb->prepare(
129
- "SELECT `meta_value`
130
- FROM {$wpdb->postmeta}
131
- WHERE (`meta_key` = 'wprss_item_permalink' AND `meta_value` = %s)",
132
- $permalink
133
- )
134
- );
135
-
136
- return !!$numRows;
137
- }
138
-
139
- /** Checks if a GUID exists in the database. */
140
- function wprss_guid_exists($guid) {
141
- global $wpdb;
142
-
143
- $numRows = $wpdb->query(
144
- $wpdb->prepare(
145
- "SELECT `meta_value`
146
- FROM {$wpdb->postmeta}
147
- WHERE (`meta_key` = 'wprss_item_guid' AND `meta_value` = %s)",
148
- $guid
149
- )
150
- );
151
-
152
- return !!$numRows;
153
- }
154
-
155
- /**
156
- * Checks if an item title exists in the database.
157
- *
158
- * @since 4.14
159
- *
160
- * @param string $title The title to search for.
161
- *
162
- * @return bool True if the title exists, false if not.
163
- */
164
- function wprss_item_title_exists($title)
165
- {
166
- global $wpdb;
167
-
168
- $numRows = $wpdb->query(
169
- $wpdb->prepare(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  "SELECT p.`post_title`
171
- FROM {$wpdb->posts} AS p
172
- JOIN {$wpdb->postmeta} AS q ON p.`ID` = q.`post_id`
173
- WHERE q.`meta_key` = 'wprss_feed_id' AND p.`post_title` = %s",
174
- [html_entity_decode($title)]
175
- )
176
- );
177
-
178
- return !!$numRows;
179
- }
180
-
181
- add_action('publish_wprss_feed', 'wprss_fetch_insert_feed_items', 10);
182
- /**
183
- * Fetches feed items from source provided and inserts into db
184
- *
185
- * This function is used when inserting or un-trashing a feed source, it only gets feeds from that particular source.
186
- *
187
- * @since 3.0
188
- */
189
- function wprss_fetch_insert_feed_items($post_id)
190
- {
191
- wp_schedule_single_event(time(), 'wprss_fetch_single_feed_hook', [$post_id]);
192
- }
193
-
194
- /**
195
- * Returns the image of the feed.
196
- * The reason this function exists is for add-ons to be able to detect if the plugin core
197
- * supports feed image functionality through a simple function_exists() call.
198
- *
199
- * @since 1.0
200
- *
201
- * @param int $source_id The ID of the feed source
202
- *
203
- * @return string The link to the feed image
204
- */
205
- function wprss_get_feed_image($source_id)
206
- {
207
- return get_post_meta($source_id, 'wprss_feed_image', true);
208
- }
209
-
210
- add_action('post_updated', 'wprss_updated_feed_source', 10, 3);
211
- /**
212
- * This function is triggered just after a post is updated.
213
- * It checks if the updated post is a feed source, and carries out any
214
- * updating necessary.
215
- *
216
- * @since 3.3
217
- */
218
- function wprss_updated_feed_source($post_ID, $post_after, $post_before)
219
- {
220
- // Check if the post is a feed source and is published
221
-
222
- if (($post_after->post_type == 'wprss_feed') && ($post_after->post_status == 'publish')) {
223
- if (isset($_POST['wprss_url']) && !empty($_POST['wprss_url'])) {
224
- $url = $_POST['wprss_url'];
225
- $feed = wprss_fetch_feed($url);
226
- if ($feed !== null && !is_wp_error($feed)) {
227
- update_post_meta($post_ID, 'wprss_site_url', $feed->get_permalink());
228
- update_post_meta($post_ID, 'wprss_feed_image', $feed->get_image_url());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  }
 
231
 
232
- if (isset($_POST['wprss_limit']) && !empty($_POST['wprss_limit'])) {
233
- // Checking feed limit change
234
- // Get the limit currently saved in db, and limit in POST request
235
- //$limit = get_post_meta( $post_ID, 'wprss_limit', true );
236
- $limit = $_POST['wprss_limit'];
237
- // Get all feed items for this source
238
- $feed_sources = new WP_Query(
239
- [
240
- 'post_type' => 'wprss_feed_item',
241
- 'post_status' => 'publish',
242
- 'cache_results' => false, // Disable caching, used for one-off queries
243
- 'no_found_rows' => true, // We don't need pagination, so disable it
244
- 'posts_per_page' => -1,
245
- 'orderby' => 'date',
246
- 'order' => 'ASC',
247
- 'meta_query' => [
248
- [
249
- 'key' => 'wprss_feed_id',
250
- 'value' => $post_ID,
251
- 'compare' => 'LIKE',
252
- ],
253
- ],
254
- ]
255
- );
256
- // If the limit is smaller than the number of found posts, delete the feed items
257
- // and re-import, to ensure that most recent feed items are present.
258
- $difference = intval($feed_sources->post_count) - intval($limit);
259
- if ($difference > 0) {
260
- // Loop and delete the excess feed items
261
- while ($feed_sources->have_posts() && $difference > 0) {
262
- $feed_sources->the_post();
263
- wp_delete_post(get_the_ID(), true);
264
- $difference--;
 
 
 
 
 
 
265
  }
266
  }
267
  }
268
  }
269
- }
270
-
271
- add_action('added_post_meta', 'wprss_update_feed_meta', 10, 4);
272
- add_action('updated_post_meta', 'wprss_update_feed_meta', 10, 4);
273
- /**
274
- * This function is run whenever a post is saved or updated.
275
- *
276
- * @since 3.4
277
- */
278
- function wprss_update_feed_meta($meta_id, $post_id, $meta_key, $meta_value)
279
- {
280
- $post = get_post($post_id);
281
- if ($post !== null && $post->post_status === 'publish' && $post->post_type === 'wprss_feed') {
282
- if ($meta_key === 'wprss_url') {
283
- wprss_change_fb_url($post_id, $meta_value);
 
 
 
 
 
 
 
 
284
  }
285
  }
286
- }
287
-
288
- function wprss_change_fb_url($post_id, $url)
289
- {
290
- # Check if url begins with a known facebook hostname.
291
- if (stripos($url, 'http://facebook.com') === 0
292
- || stripos($url, 'http://www.facebook.com') === 0
293
- || stripos($url, 'https://facebook.com') === 0
294
- || stripos($url, 'https://www.facebook.com') === 0
295
- ) {
296
- # Generate the new URL to FB Graph
297
- $com_index = stripos($url, '.com');
298
- $fb_page = substr($url, $com_index + 4); # 4 = length of ".com"
299
- $fb_graph_url = 'https://graph.facebook.com' . $fb_page;
300
- # Contact FB Graph and get data
301
- $response = wp_remote_get($fb_graph_url);
302
- # If the response successful and has a body
303
- if (!is_wp_error($response) && isset($response['body'])) {
304
- # Parse the body as a JSON string
305
- $json = json_decode($response['body'], true);
306
- # If an id is present ...
307
- if (isset($json['id'])) {
308
- # Generate the final URL for this feed and update the post meta
309
- $final_url = "https://www.facebook.com/feeds/page.php?format=rss20&id=" . $json['id'];
310
- update_post_meta($post_id, 'wprss_url', $final_url, $url);
311
- }
312
  }
313
  }
314
- }
315
-
316
- add_action('trash_wprss_feed', 'wprss_delete_feed_items'); // maybe use wp_trash_post action? wp_trash_wprss_feed
317
- /**
318
- * Delete feed items on trashing of corresponding feed source
319
- *
320
- * @since 2.0
321
- */
322
- function wprss_delete_feed_items($source_id)
323
- {
324
- $force_delete = apply_filters('wprss_force_delete_when_by_source', true);
325
-
326
- // WPML fix: removes the current language from the query WHERE and JOIN clauses
327
- global $sitepress;
328
- if ($sitepress !== null) {
329
- remove_filter('posts_join', [$sitepress, 'posts_join_filter']);
330
- remove_filter('posts_where', [$sitepress, 'posts_where_filter']);
331
- }
332
-
333
- $args = wprss_get_imported_items_query($source_id);
334
- $items = get_posts($args);
335
-
336
- foreach ($items as $item) {
337
- wp_delete_post($item->ID, $force_delete);
338
- }
339
- }
340
-
341
- add_action('wprss_delete_all_feed_items_hook', 'wprss_delete_all_feed_items');
342
- /**
343
- * Delete all feed items
344
- *
345
- * @since 3.0
346
- */
347
- function wprss_delete_all_feed_items()
348
- {
349
- $args = wprss_get_imported_items_query();
350
- $items = get_posts($args);
351
-
352
- foreach ($items as $item) {
353
- wp_delete_post($item->ID, true);
354
- }
355
- }
356
-
357
- /**
358
- * Marks the feed source as 'updating' (importing).
359
- *
360
- * @since 4.6.6
361
- * @return int The time value set in the 'updating' meta field
362
- */
363
- function wprss_flag_feed_as_updating($feed_ID)
364
- {
365
- update_post_meta($feed_ID, 'wprss_feed_is_updating', $start_time = time());
366
- return $start_time;
367
- }
368
-
369
- /**
370
- * Marks the feed source as 'idle' (not importing).
371
- *
372
- * @since 4.6.6
373
- */
374
- function wprss_flag_feed_as_idle($feed_ID)
375
- {
376
- update_post_meta($feed_ID, 'wprss_feed_is_updating', '');
377
- }
378
-
379
- /**
380
- * Returns whether the feed source is updating.
381
- *
382
- * @param string|int The id of the feed source
383
- *
384
- * @return bool TRUE if the feed source is currently updating, FALSE otherwise.
385
- */
386
- function wprss_is_feed_source_updating($id)
387
- {
388
- // Get the 'updating' meta field
389
- $is_updating_meta = get_post_meta($id, 'wprss_feed_is_updating', true);
390
-
391
- // Check if the feed has the 'updating' meta field set
392
- if ($is_updating_meta === '') {
393
- // If not, then the feed is not updating
394
- return false;
395
- }
396
-
397
- // Get the limit used for the feed
398
- $limit = get_post_meta($id, 'wprss_limit', true);
399
- if ($limit === '' || intval($limit) <= 0) {
400
- $global_limit = wprss_get_general_setting('limit_feed_items_imported');
401
- $limit = ($global_limit === '' || intval($global_limit) <= 0) ? null : $global_limit;
402
- }
403
-
404
- // Calculate the allowed maximum time, based on the maximum number of items allowed to be
405
- // imported from this source.
406
- // If no limit is used, 60s (1min) is used.
407
- $single_item_time_limit = wprss_get_feed_fetch_time_limit();
408
- $allowed_time = $limit === null ? 120 : $single_item_time_limit * intval($limit);
409
-
410
- // Calculate how many seconds have passed since the feed last signalled that it is updating
411
- $diff = time() - $is_updating_meta;
412
-
413
- // Get the transient that is set when the import function is called and the time of the next scheduled cron
414
- $is_updating_transient = get_transient('wpra/feeds/importing/' . $id);
415
- $scheduled = (wprss_get_next_feed_source_update($id) !== false);
416
- // If more than 5 seconds have passed and the transient is not yet set and the cron was not scheduled
417
- // then the cron probably failed to be registered
418
- if ($diff > 5 && !$is_updating_transient && !$scheduled) {
419
- wprss_flag_feed_as_idle($id);
420
- update_post_meta(
421
- $id,
422
- 'wprss_error_last_import',
423
- __('The plugin failed to schedule a fetch for this feed. Please try again.', 'wprss')
424
- );
425
 
426
- return false;
427
- }
428
-
429
- // If the difference is greater than the allowed maximum amount of time, mark the feed as idle.
430
- if ($diff > $allowed_time) {
431
- wprss_flag_feed_as_idle($id);
432
- // Feed is not updating
433
- return false;
434
- }
435
-
436
- // Feed is updating
437
- return true;
438
- }
439
-
440
- /**
441
- * Returns whether the feed source is deleting its feed items.
442
- *
443
- * @param string|int The id of the feed source
444
- *
445
- * @return bool TRUE if the feed source is currently deleting its items, FALSE otherwise.
446
- */
447
- function wprss_is_feed_source_deleting($id)
448
- {
449
- $is_deleting_meta = get_post_meta($id, 'wprss_feed_is_deleting_items', true);
450
-
451
- if ($is_deleting_meta === '') {
452
- return false;
453
- }
454
-
455
- $diff = time() - $is_deleting_meta;
456
-
457
- $items = wprss_get_feed_items_for_source($id);
458
- if ($items->post_count === 0 || $diff > 300) {
459
- delete_post_meta($id, 'wprss_feed_is_deleting_items');
460
- return false;
461
- }
462
-
463
- return true;
464
- }
465
-
466
- /**
467
- * Returns the given parameter as a string. Used in wprss_truncate_posts()
468
- *
469
- * @since 3.5.1
470
- * @return string The given parameter as a string
471
- */
472
- function wprss_return_as_string($item)
473
- {
474
- return "'$item'";
475
- }
476
-
477
- /**
478
- * Returns true if the feed item is older than the given timestamp,
479
- * false otherwise;
480
- *
481
- * @since 3.8
482
- */
483
- function wprss_is_feed_item_older_than($id, $timestamp)
484
- {
485
- // GET THE DATE
486
- $age = get_the_time('U', $id);
487
- if ($age === '') {
488
- return false;
489
- }
490
- // Calculate the age difference
491
- $difference = $age - $timestamp;
492
- // Return whether the difference is negative ( the age is smaller than the timestamp )
493
- return ($difference <= 0);
494
- }
495
-
496
- /**
497
- * Returns the maximum age setting for a feed source.
498
- *
499
- * @since 3.8
500
- */
501
- function wprss_get_max_age_for_feed_source($source_id)
502
- {
503
- $general_settings = get_option('wprss_settings_general');
504
- // Get the metadata for age for this feed source
505
- $age_limit = trim(get_post_meta($source_id, 'wprss_age_limit', true));
506
- $age_unit = get_post_meta($source_id, 'wprss_age_unit', true);
507
-
508
- // If the meta does not exist, use the global settings
509
- if ($age_limit === '') {
510
- $age_limit = trim(wprss_get_general_setting('limit_feed_items_age'));
511
- $age_unit = wprss_get_general_setting('limit_feed_items_age_unit');
512
- }
513
-
514
- // If the age limit is an empty string, use no limit
515
- if ($age_limit === '') {
516
- return false;
517
- }
518
-
519
- // Return the timestamp of the max age date
520
- return strtotime("-$age_limit $age_unit");
521
- }
522
-
523
- /**
524
- * Truncates the items for a single feed source based on its age limit.
525
- *
526
- * @since 4.14
527
- *
528
- * @param int|WP_Post $source The source ID or post instance.
529
- */
530
- function wprss_truncate_items_for_source($source)
531
- {
532
- $id = ($source instanceof WP_Post)
533
- ? $source->ID
534
- : $source;
535
-
536
- $logger = wpra_get_logger($id);
537
-
538
- // Get the max age setting for this feed source
539
- $max_age = wprss_get_max_age_for_feed_source($id);
540
-
541
- // If the data is empty, do not delete
542
- if ($max_age === false) {
543
- return;
544
- }
545
-
546
- // Get all feed items for this source
547
- $feed_items = wprss_get_feed_items_for_source($id);
548
-
549
- // If there are no feed items, stop
550
- if (!$feed_items->have_posts()) {
551
- return;
552
- }
553
-
554
- // Extend the timeout time limit for the deletion of the feed items
555
- set_time_limit(wprss_get_item_import_time_limit());
556
-
557
- $logger->debug('Truncating existing items');
558
-
559
- // For each feed item
560
- while ($feed_items->have_posts()) {
561
- $feed_items->the_post();
562
- // If the post is older than the maximum age
563
- $item_id = get_the_ID();
564
-
565
- if (wprss_is_feed_item_older_than($item_id, $max_age) === true) {
566
- // Delete the post
567
- wp_delete_post($item_id, true);
568
  }
 
 
 
 
 
 
 
 
 
 
569
  }
570
 
571
- // Reset feed items query data
572
- wp_reset_postdata();
573
- }
574
-
575
- /**
576
- * Delete old feed items from the database to avoid bloat.
577
- * As of 3.8, it uses the new feed age system.
578
- *
579
- * @since 3.8
580
- */
581
- function wprss_truncate_posts()
582
- {
583
- // Get general settings
584
- $general_settings = get_option('wprss_settings_general');
585
- // Get all feed sources
586
- $feed_sources = wprss_get_all_feed_sources();
587
-
588
- // Check if there are feed sources
589
- if ($feed_sources->have_posts()) {
590
- // Truncate items for each feed source
591
- while ($feed_sources->have_posts()) {
592
- $feed_sources->the_post();
593
- wprss_truncate_items_for_source(get_the_ID());
594
  }
595
- // Reset feed sources query data
596
- wp_reset_postdata();
 
 
 
 
 
 
 
 
597
  }
598
 
599
- // If the filter to use the fixed limit is enabled, call the old truncation function
600
- if (apply_filters('wprss_use_fixed_feed_limit',
601
- false) === true && isset($general_settings['limit_feed_items_db'])) {
602
- wprss_old_truncate_posts();
 
 
 
 
 
603
  }
604
- }
605
 
606
- /**
607
- * The old truncation function.
608
- * This truncation method uses the deprecated fixed feed limit.
609
- *
610
- * @since 2.0
611
- */
612
- function wprss_old_truncate_posts()
613
- {
614
- global $wpdb;
615
- $general_settings = get_option('wprss_settings_general');
616
 
617
- if ($general_settings['limit_feed_items_db'] == 0) {
618
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
  }
620
 
621
- // Set your threshold of max posts and post_type name
622
- $threshold = $general_settings['limit_feed_items_db'];
623
- $post_types = apply_filters('wprss_truncation_post_types', ['wprss_feed_item']);
624
- $post_types_str = array_map('wprss_return_as_string', $post_types);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
625
 
626
- $post_type_list = implode(',', $post_types_str);
 
 
 
 
 
 
 
 
 
 
 
 
 
627
 
628
- // Query post type
629
- // $wpdb query allows me to select specific columns instead of grabbing the entire post object.
630
- $query = "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
  SELECT ID, post_title FROM $wpdb->posts
632
  WHERE post_type IN ($post_type_list)
633
  AND post_status = 'publish'
634
  ORDER BY post_modified DESC
635
  ";
636
 
637
- $results = $wpdb->get_results($query);
638
 
639
- // Check if there are any results
640
- $i = 0;
641
- if (count($results)) {
642
- foreach ($results as $post) {
643
- $i++;
644
 
645
- // Skip any posts within our threshold
646
- if ($i <= $threshold) {
647
- continue;
648
- }
649
 
650
- // Let the WordPress API do the heavy lifting for cleaning up entire post trails
651
- $purge = wp_delete_post($post->ID, true);
 
652
  }
653
  }
654
- }
655
 
656
- add_filter('wprss_insert_post_item_conditionals', 'wprss_check_feed_item_date_on_import', 2, 3);
657
- /**
658
- * When a feed item is imported, it's date is compared against the max age of it's feed source.
659
- *
660
- * @since 3.8
661
- */
662
- function wprss_check_feed_item_date_on_import($item, $source, $permalink)
663
- {
664
- if ($item === null) {
665
- return null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  }
667
 
668
- // Get the age of the item and the max age setting for its feed source
669
- $age = $item->get_date('U');
670
- $max_age = wprss_get_max_age_for_feed_source($source);
671
 
672
- // If the age is not a valid timestamp, and the max age setting is disabled, return the item
673
- if ($age === '' || $age === null || $max_age === false || $max_age === null) {
674
- return $item;
 
 
 
 
675
  }
676
 
677
- // Calculate the age difference
678
- $difference = $age - $max_age;
679
 
680
- if ($difference <= 0) {
681
- wpra_get_logger()->debug('Item "{0}" was rejected by age limit settings.', [
682
- $item->get_title(),
683
- ]);
684
 
685
- return null;
686
- } else {
687
- return $item;
688
- }
689
- }
 
 
 
 
690
 
691
- /**
692
- * Deletes all imported feeds.
693
- *
694
- * @since 3.0
695
- */
696
- function wprss_feed_reset()
697
- {
698
- wp_schedule_single_event(time(), 'wprss_delete_all_feed_items_hook');
699
- }
700
 
701
- function wprss_schedule_reimport_all($deleted_ids)
702
- {
703
- if (!get_transient(WPRSS_TRANSIENT_NAME_IS_REIMPORTING)) {
704
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  }
706
 
707
- wprss_log('Re-import scheduled...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM);
708
- delete_transient(WPRSS_TRANSIENT_NAME_IS_REIMPORTING);
709
- wprss_fetch_insert_all_feed_items(true);
710
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
+ define( 'WPRSS_TRANSIENT_NAME_IS_REIMPORTING', 'is_reimporting' );
4
+
5
+ /**
6
+ * Feed processing related functions
7
+ *
8
+ * @package WPRSSAggregator
9
+ */
10
+
11
+ /**
12
+ * Returns whether or not the feed source will forcefully fetch the next fetch,
13
+ * ignoring whether or not it is paused or not.
14
+ *
15
+ * @param $source_id The ID of the feed soruce
16
+ * @return boolean
17
+ * @since 3.7
18
+ */
19
+ function wprss_feed_source_force_next_fetch( $source_id ) {
20
+ $force = get_post_meta( $source_id, 'wprss_force_next_fetch', TRUE );
21
+ return ( $force !== '' || $force == '1' );
22
+ }
23
+
24
+
25
+ /**
26
+ * Change the default feed cache recreation period to 2 hours
27
+ *
28
+ * Probably not needed since we are now disabling caching altogether
29
+ *
30
+ * @since 2.1
31
+ */
32
+ function wprss_feed_cache_lifetime( $seconds ) {
33
+ return 1; // one second
34
+ }
35
+
36
+
37
+ /**
38
+ * Disable caching of feeds in transients, we don't need it as we are storing them in the wp_posts table
39
+ *
40
+ * @since 3.0
41
+ */
42
+ function wprss_do_not_cache_feeds( &$feed ) {
43
+ $feed->enable_cache( false );
44
+ }
45
+
46
+
47
+ /**
48
+ * Parameters for query to get all feed sources
49
+ *
50
+ * @since 3.0
51
+ */
52
+ function wprss_get_all_feed_sources() {
53
+ // Get all feed sources
54
+ $feed_sources = new WP_Query( apply_filters(
55
+ 'wprss_get_all_feed_sources',
56
+ array(
57
+ 'post_type' => 'wprss_feed',
58
+ 'post_status' => 'publish',
59
+ 'cache_results' => false, // Disable caching, used for one-off queries
60
+ 'no_found_rows' => true, // We don't need pagination, so disable it
61
+ 'posts_per_page' => -1
62
+ )
63
+ ) );
64
+ return $feed_sources;
65
+ }
66
+
67
+
68
+ /**
69
+ * Retrieves the query to use for retrieving imported items.
70
+ *
71
+ * @since 4.17.4
72
+ */
73
+ function wprss_get_imported_items_query($source_id = null) {
74
+ $args = [
75
+ 'post_type' => array_values(get_post_types()),
76
+ 'post_status' => 'any',
77
+ 'cache_results' => false,
78
+ 'no_found_rows' => true,
79
+ 'posts_per_page' => -1,
80
+ 'ignore_sticky_posts' => 'true',
81
+ 'orderby' => 'date',
82
+ 'order' => 'DESC',
83
+ 'meta_query' => [
84
+ 'relation' => 'AND',
85
+ ],
86
+ 'suppress_filters' => 1
 
 
 
 
 
 
 
 
 
 
87
  ];
88
+
89
+ if ($source_id !== null) {
90
+ $args['meta_query'][] = [
91
+ 'key' => 'wprss_feed_id',
92
+ 'value' => (string) $source_id,
93
+ 'compare' => '=',
94
+ ];
95
+ } else {
96
+ $args['meta_query'][] = [
97
+ 'key' => 'wprss_feed_id',
98
+ 'compare' => 'EXISTS',
99
+ ];
100
+ }
101
+
102
+ return apply_filters('wprss_get_feed_items_for_source_args', $args, $source_id);
103
+ }
104
+
105
+ /**
106
+ * Queries for imported items.
107
+ *
108
+ * @since 4.17.4
109
+ */
110
+ function wprss_get_imported_items($source_id = null) {
111
+ return new WP_Query(wprss_get_imported_items_query($source_id));
112
  }
113
 
114
+ /**
115
+ * Returns all the feed items of a source.
116
+ *
117
+ * @since 3.8
118
+ */
119
+ function wprss_get_feed_items_for_source( $source_id ) {
120
+ return wprss_get_imported_items($source_id);
121
+ }
122
+
123
+
124
+ /**
125
+ * Parameters for query to get feed sources
126
+ *
127
+ * @since 3.0
128
+ */
129
+ function wprss_get_feed_source() {
130
+ // Get all feed sources
131
+ $feed_sources = new WP_Query( apply_filters(
132
+ 'wprss_get_all_feed_sources',
133
+ array(
134
+ 'post_type' => 'wprss_feed',
135
+ 'post_status' => 'publish',
136
+ 'cache_results' => false, // Disable caching, used for one-off queries
137
+ 'no_found_rows' => true, // We don't need pagination, so disable it
138
+ 'posts_per_page' => -1
139
+ )
140
+ ) );
141
+ return $feed_sources;
142
+ }
143
+
144
+
145
+ /**
146
+ * Database query to get existing permalinks
147
+ *
148
+ * @since 3.0
149
+ */
150
+ function wprss_get_existing_permalinks( $feed_ID ) {
151
+ global $wpdb;
152
+
153
+ $cols = $wpdb->get_col(
154
+ "SELECT q.`meta_value`
155
+ FROM {$wpdb->postmeta} AS p
156
+ JOIN {$wpdb->postmeta} AS q ON (q.`meta_key` = 'wprss_item_permalink' AND p.`post_id` = q.`post_id`)
157
+ WHERE p.`meta_key` = 'wprss_feed_id' AND p.`meta_value` = '{$feed_ID}'"
158
+ );
159
+
160
+ return @array_flip($cols);
161
+ }
162
+
163
+ /**
164
+ * Checks if an item title exists in the database.
165
+ *
166
+ * @since 4.14
167
+ *
168
+ * @param string $title The title to search for.
169
+ *
170
+ * @return bool True if the title exists, false if not.
171
+ */
172
+ function wprss_item_title_exists( $title ) {
173
+ global $wpdb;
174
+
175
+ $cols = $wpdb->get_col(
176
+ $wpdb->prepare(
177
+ "SELECT *
178
+ FROM `{$wpdb->posts}` AS p
179
+ JOIN `{$wpdb->postmeta}` AS q ON p.`ID` = q.`post_id`
180
+ WHERE q.`meta_key` = 'wprss_feed_id' AND p.`post_title` = %s",
181
+ [$title]
182
+ )
183
+ );
184
+
185
+ return count($cols) > 0;
186
+ }
187
+
188
+ /**
189
+ * Database query to get existing titles
190
+ *
191
+ * @since 4.7
192
+ */
193
+ function wprss_get_existing_titles( $feed_ID = NULL ) {
194
+ global $wpdb;
195
+
196
+ $condition = ($feed_ID !== NULL) ? "AND q.`meta_value` = '{$feed_ID}'" : '';
197
+
198
+ $cols = $wpdb->get_col(
199
  "SELECT p.`post_title`
200
+ FROM `{$wpdb->posts}` AS p
201
+ JOIN `{$wpdb->postmeta}` AS q ON p.`ID` = q.`post_id`
202
+ WHERE q.`meta_key` = 'wprss_feed_id' $condition"
203
+ );
204
+
205
+ return @array_flip($cols);
206
+ }
207
+
208
+
209
+ /**
210
+ * Checks if a permalink exists.
211
+ *
212
+ * Untested!
213
+ *
214
+ * @param string $permalink The permalink, expected to be normalized.
215
+ * @return bool
216
+ */
217
+ function wprss_permalink_exists( $permalink ) {
218
+ global $wpdb;
219
+
220
+ $wpdb->query(
221
+ $wpdb->prepare(
222
+ "SELECT *
223
+ FROM {$wpdb->postmeta}
224
+ WHERE `meta_value` = '{$permalink}'"
225
+ )
226
+ );
227
+
228
+ return $wpdb->num_rows > 0;
229
+ }
230
+
231
+
232
+ add_action( 'publish_wprss_feed', 'wprss_fetch_insert_feed_items', 10 );
233
+ /**
234
+ * Fetches feed items from source provided and inserts into db
235
+ *
236
+ * This function is used when inserting or untrashing a new feed source, it only gets feeds from that particular source
237
+ *
238
+ * @since 3.0
239
+ */
240
+ function wprss_fetch_insert_feed_items( $post_id ) {
241
+ wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
242
+ }
243
+
244
+
245
+ /**
246
+ * Returns the image of the feed.
247
+ * The reason this function exists is for add-ons to be able to detect if the plugin core
248
+ * supports feed image functionality through a simple function_exists() call.
249
+ *
250
+ * @param $source_id The ID of the feed source
251
+ * @return string The link to the feed image
252
+ * @since 1.0
253
+ */
254
+ function wprss_get_feed_image( $source_id ) {
255
+ return get_post_meta( $source_id, 'wprss_feed_image', true );
256
+ }
257
+
258
+
259
+ add_action( 'post_updated', 'wprss_updated_feed_source', 10, 3 );
260
+ /**
261
+ * This function is triggered just after a post is updated.
262
+ * It checks if the updated post is a feed source, and carries out any
263
+ * updating necassary.
264
+ *
265
+ * @since 3.3
266
+ */
267
+ function wprss_updated_feed_source( $post_ID, $post_after, $post_before ) {
268
+ // Check if the post is a feed source and is published
269
+
270
+ if ( ( $post_after->post_type == 'wprss_feed' ) && ( $post_after->post_status == 'publish' ) ) {
271
+
272
+ if ( isset( $_POST['wprss_url'] ) && !empty( $_POST['wprss_url'] ) ) {
273
+ $url = $_POST['wprss_url'];
274
+ $feed = wprss_fetch_feed( $url );
275
+ if ( $feed !== NULL && !is_wp_error( $feed ) ) {
276
+ update_post_meta( $post_ID, 'wprss_site_url', $feed->get_permalink() );
277
+ update_post_meta( $post_ID, 'wprss_feed_image', $feed->get_image_url() );
278
+ }
279
  }
280
+
281
+
282
+ if ( isset( $_POST['wprss_limit'] ) && !empty( $_POST['wprss_limit'] ) ) {
283
+ // Checking feed limit change
284
+ // Get the limit currently saved in db, and limit in POST request
285
+ //$limit = get_post_meta( $post_ID, 'wprss_limit', true );
286
+ $limit = $_POST['wprss_limit'];
287
+ // Get all feed items for this source
288
+ $feed_sources = new WP_Query(
289
+ array(
290
+ 'post_type' => 'wprss_feed_item',
291
+ 'post_status' => 'publish',
292
+ 'cache_results' => false, // Disable caching, used for one-off queries
293
+ 'no_found_rows' => true, // We don't need pagination, so disable it
294
+ 'posts_per_page' => -1,
295
+ 'orderby' => 'date',
296
+ 'order' => 'ASC',
297
+ 'meta_query' => array(
298
+ array(
299
+ 'key' => 'wprss_feed_id',
300
+ 'value' => $post_ID,
301
+ 'compare' => 'LIKE'
302
+ )
303
+ )
304
+ )
305
+ );
306
+ // If the limit is smaller than the number of found posts, delete the feed items
307
+ // and re-import, to ensure that most recent feed items are present.
308
+ $difference = intval( $feed_sources->post_count ) - intval( $limit );
309
+ if ( $difference > 0 ) {
310
+ // Loop and delete the excess feed items
311
+ while ( $feed_sources->have_posts() && $difference > 0 ) {
312
+ $feed_sources->the_post();
313
+ wp_delete_post( get_the_ID(), true );
314
+ $difference--;
315
+ }
316
+ }
317
+ }
318
  }
319
+ }
320
 
321
+
322
+ add_action( 'added_post_meta', 'wprss_update_feed_meta', 10, 4 );
323
+ add_action( 'updated_post_meta', 'wprss_update_feed_meta', 10, 4 );
324
+ /**
325
+ * This function is run whenever a post is saved or updated.
326
+ *
327
+ * @since 3.4
328
+ */
329
+ function wprss_update_feed_meta( $meta_id, $post_id, $meta_key, $meta_value ) {
330
+ $post = get_post( $post_id );
331
+ if ( $post !== NULL && $post->post_status === 'publish' && $post->post_type === 'wprss_feed' ) {
332
+ if ( $meta_key === 'wprss_url' )
333
+ wprss_change_fb_url( $post_id, $meta_value );
334
+ }
335
+ }
336
+
337
+
338
+ function wprss_change_fb_url( $post_id, $url ) {
339
+ # Check if url begins with a known facebook hostname.
340
+ if ( stripos( $url, 'http://facebook.com' ) === 0
341
+ || stripos( $url, 'http://www.facebook.com' ) === 0
342
+ || stripos( $url, 'https://facebook.com' ) === 0
343
+ || stripos( $url, 'https://www.facebook.com' ) === 0
344
+ ) {
345
+ # Generate the new URL to FB Graph
346
+ $com_index = stripos( $url, '.com' );
347
+ $fb_page = substr( $url, $com_index + 4 ); # 4 = length of ".com"
348
+ $fb_graph_url = 'https://graph.facebook.com' . $fb_page;
349
+ # Contact FB Graph and get data
350
+ $response = wp_remote_get( $fb_graph_url );
351
+ # If the repsonse successful and has a body
352
+ if ( !is_wp_error( $response ) && isset( $response['body'] ) ) {
353
+ # Parse the body as a JSON string
354
+ $json = json_decode( $response['body'], true );
355
+ # If an id is present ...
356
+ if ( isset( $json['id'] ) ) {
357
+ # Generate the final URL for this feed and update the post meta
358
+ $final_url = "https://www.facebook.com/feeds/page.php?format=rss20&id=" . $json['id'];
359
+ update_post_meta( $post_id, 'wprss_url', $final_url, $url );
360
  }
361
  }
362
  }
363
  }
364
+
365
+
366
+ add_action( 'trash_wprss_feed', 'wprss_delete_feed_items' ); // maybe use wp_trash_post action? wp_trash_wprss_feed
367
+ /**
368
+ * Delete feed items on trashing of corresponding feed source
369
+ *
370
+ * @since 2.0
371
+ */
372
+ function wprss_delete_feed_items ($source_id) {
373
+ $force_delete = apply_filters('wprss_force_delete_when_by_source', true);
374
+
375
+ // WPML fix: removes the current language from the query WHERE and JOIN clauses
376
+ global $sitepress;
377
+ if ($sitepress !== null) {
378
+ remove_filter('posts_join', [$sitepress,'posts_join_filter']);
379
+ remove_filter('posts_where', [$sitepress,'posts_where_filter']);
380
+ }
381
+
382
+ $args = wprss_get_imported_items_query($source_id);
383
+ $items = get_posts($args);
384
+
385
+ foreach ($items as $item) {
386
+ wp_delete_post($item->ID, $force_delete);
387
  }
388
  }
389
+
390
+
391
+ add_action( 'wprss_delete_all_feed_items_hook', 'wprss_delete_all_feed_items' );
392
+ /**
393
+ * Delete all feed items
394
+ *
395
+ * @since 3.0
396
+ */
397
+ function wprss_delete_all_feed_items() {
398
+ $args = wprss_get_imported_items_query();
399
+ $items = get_posts($args);
400
+
401
+ foreach ($items as $item) {
402
+ wp_delete_post($item->ID, true);
 
 
 
 
 
 
 
 
 
 
 
 
403
  }
404
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
 
406
+
407
+ /**
408
+ * Marks the feed source as 'updating' (importing).
409
+ *
410
+ * @since 4.6.6
411
+ * @return int The time value set in the 'updating' meta field
412
+ */
413
+ function wprss_flag_feed_as_updating( $feed_ID ) {
414
+ update_post_meta( $feed_ID, 'wprss_feed_is_updating', $start_time = time() );
415
+ return $start_time;
416
+ }
417
+
418
+ /**
419
+ * Marks the feed source as 'idle' (not importing).
420
+ *
421
+ * @since 4.6.6
422
+ */
423
+ function wprss_flag_feed_as_idle( $feed_ID ) {
424
+ update_post_meta( $feed_ID, 'wprss_feed_is_updating', '' );
425
+ }
426
+
427
+
428
+ /**
429
+ * Returns whether or not the feed source is updating.
430
+ *
431
+ * @param (string|int) The id of the feed source
432
+ * @return (bool) TRUE if the feed source is currently updating, FALSE otherwise.
433
+ *
434
+ */
435
+ function wprss_is_feed_source_updating( $id ) {
436
+ // Get the 'updating' meta field
437
+ $is_updating_meta = get_post_meta( $id, 'wprss_feed_is_updating', TRUE );
438
+
439
+ // Check if the feed has the 'updating' meta field set
440
+ if ( $is_updating_meta === '' ) {
441
+ // If not, then the feed is not updating
442
+ return FALSE;
443
+ }
444
+
445
+ // Get the limit used for the feed
446
+ $limit = get_post_meta( $id, 'wprss_limit', true );
447
+ if ( $limit === '' || intval( $limit ) <= 0 ) {
448
+ $global_limit = wprss_get_general_setting('limit_feed_items_imported');
449
+ $limit = ( $global_limit === '' || intval( $global_limit ) <= 0 ) ? NULL : $global_limit;
450
+ }
451
+
452
+ // Calculate the allowed maximum time, based on the maximum number of items allowed to be
453
+ // imported from this source.
454
+ // If no limit is used, 60s (1min) is used.
455
+ $single_item_time_limit = wprss_get_feed_fetch_time_limit();
456
+ $allowed_time = $limit === NULL ? 120 : $single_item_time_limit * intval( $limit );
457
+
458
+ // Calculate how many seconds have passed since the feed last signalled that it is updating
459
+ $diff = time() - $is_updating_meta;
460
+
461
+ // Get the transient that is set when the import function is called and the time of the next scheduled cron
462
+ $is_updating_transient = get_transient('wpra/feeds/importing/' . $id);
463
+ $scheduled = (wprss_get_next_feed_source_update($id) !== false);
464
+ // If more than 5 seconds have passed and the transient is not yet set and the cron was not scheduled
465
+ // then the cron probably failed to be registered
466
+ if ( $diff > 5 && !$is_updating_transient && !$scheduled) {
467
+ wprss_flag_feed_as_idle($id);
468
+ update_post_meta(
469
+ $id,
470
+ 'wprss_error_last_import',
471
+ __('The plugin failed to schedule a fetch for this feed. Please try again.', 'wprss')
472
+ );
473
+
474
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  }
476
+
477
+ // If the difference is greater than the allowed maximum amount of time, mark the feed as idle.
478
+ if ( $diff > $allowed_time ) {
479
+ wprss_flag_feed_as_idle( $id );
480
+ // Feed is not updating
481
+ return FALSE;
482
+ }
483
+
484
+ // Feed is updating
485
+ return TRUE;
486
  }
487
 
488
+
489
+ /**
490
+ * Returns whether or not the feed source is deleting its feeed items.
491
+ *
492
+ * @param (string|int) The id of the feed source
493
+ * @return (bool) TRUE if the feed source is currently deleting its items, FALSE otherwise.
494
+ *
495
+ */
496
+ function wprss_is_feed_source_deleting( $id ) {
497
+ $is_deleting_meta = get_post_meta( $id, 'wprss_feed_is_deleting_items', TRUE );
498
+
499
+ if ( $is_deleting_meta === '' ) {
500
+ return FALSE;
 
 
 
 
 
 
 
 
 
 
501
  }
502
+
503
+ $diff = time() - $is_deleting_meta;
504
+
505
+ $items = wprss_get_feed_items_for_source( $id );
506
+ if ( $items->post_count === 0 || $diff > 300 ) {
507
+ delete_post_meta( $id, 'wprss_feed_is_deleting_items' );
508
+ return FALSE;
509
+ }
510
+
511
+ return TRUE;
512
  }
513
 
514
+
515
+ /**
516
+ * Returns the given parameter as a string. Used in wprss_truncate_posts()
517
+ *
518
+ * @return string The given parameter as a string
519
+ * @since 3.5.1
520
+ */
521
+ function wprss_return_as_string( $item ) {
522
+ return "'$item'";
523
  }
 
524
 
 
 
 
 
 
 
 
 
 
 
525
 
526
+ /**
527
+ * Returns true if the feed item is older than the given timestamp,
528
+ * false otherwise;
529
+ *
530
+ * @since 3.8
531
+ */
532
+ function wprss_is_feed_item_older_than( $id, $timestamp ) {
533
+ // GET THE DATE
534
+ $age = get_the_time( 'U', $id );
535
+ if ( $age === '' ) return FALSE;
536
+ // Calculate the age difference
537
+ $difference = $age - $timestamp;
538
+ // Return whether the difference is negative ( the age is smaller than the timestamp )
539
+ return ( $difference <= 0 );
540
+ }
541
+
542
+
543
+ /**
544
+ * Returns the maximum age setting for a feed source.
545
+ *
546
+ * @since 3.8
547
+ */
548
+ function wprss_get_max_age_for_feed_source( $source_id ) {
549
+ $general_settings = get_option( 'wprss_settings_general' );
550
+ // Get the meta data for age for this feed source
551
+ $age_limit = trim( get_post_meta( $source_id, 'wprss_age_limit', TRUE ) );
552
+ $age_unit = get_post_meta( $source_id, 'wprss_age_unit', TRUE );
553
+
554
+ // If the meta does not exist, use the global settings
555
+ if( $age_limit === '' ) {
556
+ $age_limit = trim( wprss_get_general_setting( 'limit_feed_items_age' ) );
557
+ $age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
558
+ }
559
+
560
+ // If the age limit is an empty string, use no limit
561
+ if ( $age_limit === '' ) {
562
+ return FALSE;
563
+ }
564
+
565
+ // Return the timestamp of the max age date
566
+ return strtotime( "-$age_limit $age_unit" );
567
  }
568
 
569
+ /**
570
+ * Truncates the items for a single feed source based on its age limit.
571
+ *
572
+ * @since 4.14
573
+ *
574
+ * @param int|WP_Post $source The source ID or post instance.
575
+ */
576
+ function wprss_truncate_items_for_source( $source )
577
+ {
578
+ $id = ( $source instanceof WP_Post )
579
+ ? $source->ID
580
+ : $source;
581
+
582
+ // Get the max age setting for this feed source
583
+ $max_age = wprss_get_max_age_for_feed_source( $id );
584
+
585
+ // If the data is empty, do not delete
586
+ if ( $max_age === false ) {
587
+ return;
588
+ }
589
+
590
+ // Get all feed items for this source
591
+ $feed_items = wprss_get_feed_items_for_source( $id );
592
+
593
+ // If there are no feed items, stop
594
+ if ( ! $feed_items->have_posts() ) {
595
+ return;
596
+ }
597
 
598
+ // Extend the timeout time limit for the deletion of the feed items
599
+ set_time_limit( wprss_get_item_import_time_limit() );
600
+
601
+ // For each feed item
602
+ while ( $feed_items->have_posts() ) {
603
+ $feed_items->the_post();
604
+ // If the post is older than the maximum age
605
+ $item_id = get_the_ID();
606
+
607
+ if ( wprss_is_feed_item_older_than( $item_id, $max_age ) === true ){
608
+ // Delete the post
609
+ wp_delete_post( $item_id, true );
610
+ }
611
+ }
612
 
613
+ // Reset feed items query data
614
+ wp_reset_postdata();
615
+ }
616
+
617
+ /**
618
+ * Delete old feed items from the database to avoid bloat.
619
+ * As of 3.8, it uses the new feed age system.
620
+ *
621
+ * @since 3.8
622
+ */
623
+ function wprss_truncate_posts() {
624
+ // Get general settings
625
+ $general_settings = get_option( 'wprss_settings_general' );
626
+ // Get all feed sources
627
+ $feed_sources = wprss_get_all_feed_sources();
628
+
629
+ // Check if there are feed sources
630
+ if( $feed_sources->have_posts() ) {
631
+ // Truncate items for each feed source
632
+ while ( $feed_sources->have_posts() ) {
633
+ $feed_sources->the_post();
634
+ wprss_truncate_items_for_source( get_the_ID() );
635
+ }
636
+ // Reset feed sources query data
637
+ wp_reset_postdata();
638
+ }
639
+
640
+ // If the filter to use the fixed limit is enabled, call the old truncation function
641
+ if ( apply_filters( 'wprss_use_fixed_feed_limit', FALSE ) === TRUE && isset( $general_settings['limit_feed_items_db'] ) ) {
642
+ wprss_old_truncate_posts();
643
+ }
644
+ }
645
+
646
+
647
+ /**
648
+ * The old truncation function.
649
+ * This truncation method uses the deprecated fixed feed limit.
650
+ *
651
+ * @since 2.0
652
+ */
653
+ function wprss_old_truncate_posts() {
654
+ global $wpdb;
655
+ $general_settings = get_option( 'wprss_settings_general' );
656
+
657
+ if ( $general_settings['limit_feed_items_db'] == 0 ) {
658
+ return;
659
+ }
660
+
661
+ // Set your threshold of max posts and post_type name
662
+ $threshold = $general_settings['limit_feed_items_db'];
663
+ $post_types = apply_filters( 'wprss_truncation_post_types', array( 'wprss_feed_item' ) );
664
+ $post_types_str = array_map( 'wprss_return_as_string', $post_types );
665
+
666
+ $post_type_list = implode( ',' , $post_types_str );
667
+
668
+ // Query post type
669
+ // $wpdb query allows me to select specific columns instead of grabbing the entire post object.
670
+ $query = "
671
  SELECT ID, post_title FROM $wpdb->posts
672
  WHERE post_type IN ($post_type_list)
673
  AND post_status = 'publish'
674
  ORDER BY post_modified DESC
675
  ";
676
 
677
+ $results = $wpdb->get_results( $query );
678
 
679
+ // Check if there are any results
680
+ $i = 0;
681
+ if ( count( $results ) ){
682
+ foreach ( $results as $post ) {
683
+ $i++;
684
 
685
+ // Skip any posts within our threshold
686
+ if ( $i <= $threshold )
687
+ continue;
 
688
 
689
+ // Let the WordPress API do the heavy lifting for cleaning up entire post trails
690
+ $purge = wp_delete_post( $post->ID, true );
691
+ }
692
  }
693
  }
 
694
 
695
+
696
+ add_filter( 'wprss_insert_post_item_conditionals', 'wprss_check_feed_item_date_on_import', 2, 3 );
697
+ /**
698
+ * When a feed item is imported, it's date is compared against the max age of it's feed source.
699
+ *
700
+ *
701
+ * @since 3.8
702
+ */
703
+ function wprss_check_feed_item_date_on_import( $item, $source, $permalink ){
704
+ if ( $item === NULL ) return NULL;
705
+
706
+ // Get the age of the item and the max age setting for its feed source
707
+ $age = $item->get_date( 'U' );
708
+ $max_age = wprss_get_max_age_for_feed_source( $source );
709
+
710
+ // If the age is not a valid timestamp, and the max age setting is disabled, return the item
711
+ if ( $age === '' || $age === NULL || $max_age === FALSE || $max_age === NULL ) {
712
+ return $item;
713
+ }
714
+
715
+ // Calculate the age difference
716
+ $difference = $age - $max_age;
717
+
718
+ if ( $difference <= 0 ) {
719
+ return NULL;
720
+ } else {
721
+ return $item;
722
+ }
723
  }
724
 
 
 
 
725
 
726
+ /**
727
+ * Deletes all imported feeds.
728
+ *
729
+ * @since 3.0
730
+ */
731
+ function wprss_feed_reset() {
732
+ wp_schedule_single_event( time(), 'wprss_delete_all_feed_items_hook' );
733
  }
734
 
 
 
735
 
 
 
 
 
736
 
737
+ function wprss_schedule_reimport_all($deleted_ids) {
738
+ if( !get_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING ) )
739
+ return;
740
+
741
+ wprss_log( 'Re-import scheduled...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM);
742
+ delete_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING );
743
+ wprss_fetch_insert_all_feed_items( TRUE );
744
+ }
745
+
746
 
747
+ /**
748
+ * Deletes N oldest feed items for the given source
749
+ *
750
+ * @since 4.2
751
+ * @deprecated
752
+ */
753
+ function wprss_delete_oldest_feed_items( $n, $source ) {
754
+ // If the source does not exist, do nothing
755
+ if ( get_post( $source ) == NULL ) return;
756
 
757
+ // Make sure $n is an integer
758
+ $n = intval($n);
759
+
760
+ // Do nothing if n is zero or negative
761
+ if ( $n <= 0 ) return;
762
+
763
+ // Get the feed items, as an array, not WP_Query.
764
+ // We will need to perform some array operations
765
+ $feed_items = wprss_get_feed_items_for_source( $source );
766
+ $feed_items = $feed_items->get_posts();
767
+ // Get number of feed items
768
+ $count = count( $feed_items );
769
+
770
+ // Index of first feed item to delete
771
+ $start = $count - $n;
772
+ // Cut the array of feed items to get the items to delete
773
+ $to_delete = array_slice( $feed_items, $start );
774
+ // log -- for now
775
+ foreach( $to_delete as $fi ) {
776
+ //wprss_log_obj( "To delete" , $fi->ID );
777
+ }
778
  }
779
 
780
+
781
+ /**
782
+ * Deletes the required number of feed items for the given source,
783
+ * to keep the number of feed items below its limit.
784
+ *
785
+ * @since 4.2
786
+ * @deprecated
787
+ */
788
+ function wprss_truncate_feed_items_for_source( $source ) {
789
+ // Get the limit setting
790
+ $limit = get_post_meta( $source, 'wprss_limit', true );
791
+
792
+ // Calculate the number of feed items to delete
793
+ $feed_items = wprss_get_feed_items_for_source( $source );
794
+ $n = intval($feed_items->found_posts) - intval($limit);
795
+
796
+ // Delete the feed items
797
+ wprss_delete_oldest_feed_items( $n, $source );
798
+ }
includes/feed-states.php CHANGED
@@ -1,136 +1,122 @@
1
  <?php
2
-
3
- namespace
4
- {
5
  /**
6
- * Activates the feed source. Runs on a schedule.
7
  *
8
- * @since 3.7
9
- *
10
- * @param int|string $feedId The of of the wprss_feed
11
  */
12
- function wprss_activate_feed_source($feedId)
13
- {
14
- update_post_meta($feedId, 'wprss_state', 'active');
15
- update_post_meta($feedId, 'wprss_activate_feed', '');
16
 
17
- // Add an action hook, so functions can be run when a feed source is activated
18
- do_action('wprss_on_feed_source_activated', $feedId);
19
- }
20
-
21
- /**
22
- * Pauses the feed source. Runs on a schedule.
23
- *
24
- * @since 3.7
25
- *
26
- * @param int|string $feedId The ID of the feed source.
27
- */
28
- function wprss_pause_feed_source($feedId)
29
- {
30
- update_post_meta($feedId, 'wprss_state', 'paused');
31
- update_post_meta($feedId, 'wprss_pause_feed', '');
32
-
33
- // Add an action hook, so functions can be run when a feed source is paused
34
- do_action('wprss_on_feed_source_paused', $feedId);
35
- }
36
-
37
- /**
38
- * Returns whether or not a feed source is active.
39
- *
40
- * @since 3.7
41
- *
42
- * @param int|string $feedId The ID of the feed source.
43
- *
44
- * @return boolean
45
- */
46
- function wprss_is_feed_source_active($feedId)
47
- {
48
- $state = get_post_meta($feedId, 'wprss_state', true);
49
-
50
- return empty($state) || $state === 'active';
51
- }
52
- }
53
-
54
- namespace RebelCode\Wpra\Feeds\States
55
- {
56
- const NOTICE_TRANSIENT_ACTIVATED = 'activated';
57
- const NOTICE_TRANSIENT_PAUSED = 'paused';
58
 
 
59
  /**
60
  * Changes the state of feed sources selected from the table bulk actions.
 
 
61
  */
62
- add_action('admin_init', function () {
63
- $postType = filter_input(INPUT_GET, 'post_type', FILTER_SANITIZE_STRING);
64
- $action = filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
65
- $action2 = filter_input(INPUT_GET, 'action2', FILTER_SANITIZE_STRING);
66
- $postIds = filter_input(INPUT_GET, 'post', FILTER_VALIDATE_INT, FILTER_REQUIRE_ARRAY);
67
-
68
- $action = sanitize_text_field($action);
69
- $action2 = sanitize_text_field($action2);
70
-
71
- if ($postType && ($action || $action2) && $postIds) {
72
- $action = (!empty($action) && $action !== '-1') ? $action : $action2;
73
- $action = strtolower($action);
74
- $stateChange = null;
75
-
76
- switch ($action) {
77
- // Activate all feed sources in $postIds
78
  case 'activate':
79
- foreach ($postIds as $postId) {
80
- wprss_activate_feed_source($postId);
81
  }
82
- $stateChange = NOTICE_TRANSIENT_ACTIVATED;
 
83
  break;
84
 
85
- // Pause all feed sources in $postIds
86
  case 'pause':
87
- foreach ($postIds as $postId) {
88
- wprss_pause_feed_source($postId);
89
  }
90
- $stateChange = NOTICE_TRANSIENT_PAUSED;
 
91
  break;
92
  }
93
 
94
- if ($stateChange !== null) {
95
- // Set a transient to show the admin notice, after redirection
96
- set_transient('wprss_notify_bulk_change_state', $stateChange);
97
- /* Note:
98
- * Transients are used since bulk actions will, after processing, case a redirect to the same page.
99
- * Thus, using add_action( 'all_admin_notices', ... ) will result in the notice appearing on the
100
- * first request, and not be shown after redirection.
101
- * The transient is set to show the notification AFTER redirection.
102
- */
103
- }
104
  }
105
- }, 2);
 
106
 
 
 
107
  /**
108
  * Checks if the 'wprss_notify_bulk_change_state' transient is set.
109
  * If it is, it will show the appropriate admin notice
 
 
110
  */
111
- add_action('admin_init', function () {
112
- $transient = get_transient('wprss_notify_bulk_change_state');
113
-
114
- if (empty($transient)) {
115
- return;
 
 
 
 
 
 
 
116
  }
 
117
 
118
- $transient = strtolower($transient);
119
- $notice = null;
120
 
121
- switch ($transient) {
122
- case NOTICE_TRANSIENT_ACTIVATED:
123
- $notice = 'bulk_feed_activated';
124
- break;
125
- case NOTICE_TRANSIENT_PAUSED:
126
- $notice = 'bulk_feed_paused';
127
- break;
128
- }
 
 
129
 
130
- if ($notice !== null) {
131
- wprss()->getAdminAjaxNotices()->addNotice($notice);
132
- }
133
 
134
- delete_transient('wprss_notify_bulk_change_state');
135
- }, 1);
136
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
 
 
2
  /**
3
+ * Functions relating to feed source states
4
  *
5
+ * @package WPRSSAggregator
 
 
6
  */
 
 
 
 
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ add_action( 'admin_init', 'wprss_bulk_change_state', 2 );
10
  /**
11
  * Changes the state of feed sources selected from the table bulk actions.
12
+ *
13
+ * @since 4.1
14
  */
15
+ function wprss_bulk_change_state() {
16
+ // If the id and state are in POST data
17
+ if ( isset( $_GET['post_type'] ) && (isset( $_GET['action'] ) || isset( $_GET['action2'] )) && isset( $_GET['post'] ) ) {
18
+ // Get the action and post ids from GET request
19
+ $action = isset($_GET['action']) && $_GET['action'] !== '-1' ? $_GET['action'] : $_GET['action2'];
20
+ $post_ids = $_GET['post'];
21
+
22
+ // check the action
23
+ switch ( $action ) {
24
+ // Activate all feed sources in $post_ids
 
 
 
 
 
 
25
  case 'activate':
26
+ foreach( $post_ids as $post_id ) {
27
+ wprss_activate_feed_source( $post_id );
28
  }
29
+ // Set a transient to show the admin notice, after redirection
30
+ set_transient( 'wprss_notify_bulk_change_state', 'activated', 0 );
31
  break;
32
 
33
+ // Pause all feed sources in $post_ids
34
  case 'pause':
35
+ foreach( $post_ids as $post_id ) {
36
+ wprss_pause_feed_source( $post_id );
37
  }
38
+ // Set a transient to show the admin notice, after redirection
39
+ set_transient( 'wprss_notify_bulk_change_state', 'paused', 0 );
40
  break;
41
  }
42
 
43
+ /* Note:
44
+ * Transients are used since bulk actions will, after processing, case a redirect to the same page.
45
+ * Thus, using add_action( 'all_admin_notices', ... ) will result in the notice appearing on the first request,
46
+ * and not be shown after redirection.
47
+ * The transient is set to show the notification AFTER redirection.
48
+ */
 
 
 
 
49
  }
50
+ }
51
+
52
 
53
+
54
+ add_action( 'admin_init', 'check_for_state_notice_after_redirect', 1 );
55
  /**
56
  * Checks if the 'wprss_notify_bulk_change_state' transient is set.
57
  * If it is, it will show the appropriate admin notice
58
+ *
59
+ * @since 4.1
60
  */
61
+ function check_for_state_notice_after_redirect() {
62
+ $transient = get_transient( 'wprss_notify_bulk_change_state' );
63
+ if ( $transient !== FALSE ) {
64
+ switch ( $transient ) {
65
+ case 'activated':
66
+ wprss()->getAdminAjaxNotices()->addNotice('bulk_feed_activated');
67
+ break;
68
+ case 'paused':
69
+ wprss()->getAdminAjaxNotices()->addNotice('bulk_feed_paused');
70
+ break;
71
+ }
72
+ delete_transient( 'wprss_notify_bulk_change_state' );
73
  }
74
+ }
75
 
 
 
76
 
77
+
78
+ /**
79
+ * Activates the feed source. Runs on a schedule.
80
+ *
81
+ * @param $feed_id The of of the wprss_feed
82
+ * @since 3.7
83
+ */
84
+ function wprss_activate_feed_source( $feed_id ) {
85
+ update_post_meta( $feed_id, 'wprss_state', 'active' );
86
+ update_post_meta( $feed_id, 'wprss_activate_feed', '' );
87
 
88
+ // Add an action hook, so functions can be run when a feed source is activated
89
+ do_action( 'wprss_on_feed_source_activated', $feed_id );
90
+ }
91
 
92
+
93
+ /**
94
+ * Pauses the feed source. Runs on a schedule.
95
+ *
96
+ * @param $feed_id The of of the wprss_feed
97
+ * @since 3.7
98
+ */
99
+ function wprss_pause_feed_source( $feed_id ) {
100
+ update_post_meta( $feed_id, 'wprss_state', 'paused' );
101
+ update_post_meta( $feed_id, 'wprss_pause_feed', '' );
102
+
103
+ // Add an action hook, so functions can be run when a feed source is paused
104
+ do_action( 'wprss_on_feed_source_paused', $feed_id );
105
+ }
106
+
107
+
108
+
109
+
110
+
111
+
112
+ /**
113
+ * Returns whether or not a feed source is active.
114
+ *
115
+ * @param $source_id The ID of the feed soruce
116
+ * @return boolean
117
+ * @since 3.7
118
+ */
119
+ function wprss_is_feed_source_active( $source_id ) {
120
+ $state = get_post_meta( $source_id, 'wprss_state', TRUE );
121
+ return ( $state === '' || $state === 'active' );
122
+ }
includes/functions.php CHANGED
@@ -73,12 +73,8 @@ function wpra_safe_remote_get($url, $args)
73
  */
74
  function wpra_get_plugin_state($basename)
75
  {
76
- if (!function_exists('is_plugin_active') && file_exists(ABSPATH . 'wp-admin/includes/plugin.php')) {
77
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
78
- }
79
-
80
  // ACTIVE
81
- if (function_exists('is_plugin_active') && is_plugin_active($basename)) {
82
  return 2;
83
  }
84
 
@@ -108,34 +104,6 @@ function wpra_get_activate_plugin_url($basename)
108
  );
109
  }
110
 
111
- /**
112
- * Retrieves the callbacks that are attached to a hook.
113
- *
114
- * @since 4.18
115
- *
116
- * @param string $hook The hook name.
117
- *
118
- * @return callable[] A list of callbacks.
119
- */
120
- function wpra_get_hook_callbacks($hook)
121
- {
122
- global $wp_filter;
123
-
124
- $results = [];
125
-
126
- if (isset($wp_filter[$hook])) {
127
- $hook = $wp_filter[$hook];
128
-
129
- foreach ($hook->callbacks as $list) {
130
- foreach ($list as $callback) {
131
- $results[] = $callback;
132
- }
133
- }
134
- }
135
-
136
- return $results;
137
- }
138
-
139
  /**
140
  * Returns a representation of an HTML expression that matches all representations of that HTML.
141
  *
73
  */
74
  function wpra_get_plugin_state($basename)
75
  {
 
 
 
 
76
  // ACTIVE
77
+ if (is_plugin_active($basename)) {
78
  return 2;
79
  }
80
 
104
  );
105
  }
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  /**
108
  * Returns a representation of an HTML expression that matches all representations of that HTML.
109
  *
includes/image-caching.php CHANGED
File without changes
includes/legacy-feed-display.php CHANGED
@@ -1,583 +1,541 @@
1
  <?php
2
- /**
3
- * Feed display related functions
4
- *
5
- * @package WPRSSAggregator
6
- */
7
-
8
- /**
9
- * Display template for a feed source. Simulates a shortcode call.
10
- *
11
- * @since 4.6.6
12
- * @deprecated 4.13 This function was left here because the ET addon references it.
13
- */
14
- function wprss_render_feed_view($content)
15
- {
16
- return $content;
17
- }
18
-
19
- /**
20
- * Display template for a feed source. Simulates a shortcode call.
21
- *
22
- * @since 4.6.6
23
- * @deprecated 4.13 This function was left here because the ET addon references it.
24
- */
25
- function wprss_render_feed_item_view($content)
26
- {
27
- return $content;
28
- }
29
-
30
- /**
31
- * Redirects to wprss_display_feed_items
32
- * It is used for backwards compatibility to versions < 2.0
33
- *
34
- * @since 2.1
35
- */
36
- function wp_rss_aggregator($args = [])
37
- {
38
- $template = wpra_get('feeds/templates/master_template');
39
- $fullArgs = $args;
40
-
41
- // Use legacy mode if arg was not explicitly given
42
- if (!isset($fullArgs['legacy'])) {
43
- $fullArgs['legacy'] = true;
44
  }
45
 
46
- return $template->render($args);
47
- }
48
-
49
- /**
50
- * Handles the display for a single feed item.
51
- *
52
- * @since 4.6.6
53
- */
54
- function wprss_display_single_feed_item($atts = [])
55
- {
56
- if (empty($atts)) {
57
- return '';
58
  }
59
 
60
- $id = empty($atts['id']) ? false : $atts['id'];
61
- if ($id === false || get_post_type($id) !== 'wprss_feed_item' || ($item = get_post($id)) === false) {
62
- return '';
63
- }
 
 
 
 
 
 
 
 
 
 
64
 
65
- //Enqueue scripts / styles
66
- wp_enqueue_script('jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', ['jquery']);
67
- wp_enqueue_script('wprss_custom', WPRSS_JS . 'custom.js', ['jquery', 'jquery.colorbox-min']);
68
-
69
- setup_postdata($item);
70
- $output = wprss_render_feed_item($id);
71
- $output = apply_filters('wprss_shortcode_single_output', $output);
72
- wp_reset_postdata();
73
-
74
- return $output;
75
- }
76
-
77
- /**
78
- * Renders a single feed item.
79
- *
80
- * @since 4.6.6
81
- *
82
- * @param string $default The default text to return if something fails.
83
- * @param int $ID The ID of the feed item to render
84
- *
85
- * @return string The output
86
- */
87
- function wprss_render_feed_item($ID = null, $default = '', $args = [])
88
- {
89
- $ID = ($ID === null)
90
- ? get_the_ID()
91
- : $ID;
92
-
93
- if (is_feed()) {
94
- return $default;
95
  }
96
 
97
- // Prepare the options
98
- $generalSettings = get_option('wprss_settings_general');
99
- $displaySettings = wprss_get_display_settings($generalSettings);
100
- $excerptsSettings = get_option('wprss_settings_excerpts');
101
- $thumbnailsSettings = get_option('wprss_settings_thumbnails');
102
-
103
- $args = wp_parse_args($args, [
104
- 'link_before' => '',
105
- 'link_after' => '',
106
- ]);
107
- $extraOptions = apply_filters('wprss_template_extra_options', [], $args);
108
-
109
- // Declare each item in $args as its own variable
110
- $beforeLink = $args['link_before'];
111
- $afterLink = $args['link_after'];
112
- extract($args, EXTR_SKIP);
113
-
114
- // Get the item meta
115
- $permalink = get_post_meta($ID, 'wprss_item_permalink', true);
116
- $enclosure = get_post_meta($ID, 'wprss_item_enclosure', true);
117
- $feedId = get_post_meta($ID, 'wprss_feed_id', true);
118
- $linkToEnclosure = get_post_meta($feedId, 'wprss_enclosure', true);
119
- $feedName = get_the_title($feedId);
120
- $siteUrl = get_post_meta($feedId, 'wprss_site_url', true);
121
- $timestamp = get_the_time('U', $ID);
122
-
123
- $linkTitleSetting = wprss_get_general_setting('title_link');
124
-
125
- $linkSourceSetting = isset($generalSettings['source_link'])
126
- ? $generalSettings['source_link']
127
- : 0;
128
- $linkSourceMeta = get_post_meta($feedId, 'wprss_source_link', true);
129
- $linkSource = empty($linkSourceMeta)
130
- ? $linkSourceSetting
131
- : $linkSourceMeta;
132
- $linkSource = intval(trim($linkSource));
133
-
134
- // Fallback for feeds created with older versions of the plugin
135
- if ($siteUrl === '') {
136
- $siteUrl = get_post_meta($feedId, 'wprss_url', true);
137
  }
138
- // convert from Unix timestamp
139
- $date = wprss_date_i18n($timestamp);
140
 
141
- // Prepare the title
142
- $itemTitle = get_the_title();
143
- $itemTitle = wprss_shorten_title($itemTitle, $ID);
144
- $itemTitleUrl = ($linkToEnclosure === 'true' && $enclosure !== '') ? $enclosure : $permalink;
145
-
146
- // Prepare the text that precedes the source
147
- $sourcePrefix = wprss_get_general_setting('text_preceding_source');
148
- $sourcePrefix = ltrim(__($sourcePrefix, 'wprss') . ' ');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
- $datePrefix = wprss_get_general_setting('text_preceding_date');
151
- $datePrefix = ltrim(__($datePrefix, 'wprss') . ' ');
 
 
 
 
 
 
152
 
153
- do_action('wprss_get_post_data');
 
 
 
 
 
 
 
 
 
154
 
155
- $meta = $extraOptions;
156
- $extraMeta = apply_filters('wprss_template_extra_meta', $meta, $args, $ID);
157
 
158
- ///////////////////////////////////////////////////////////////
159
- // BEGIN TEMPLATE
 
 
 
 
 
 
160
 
161
- // Prepare the output
162
- $output = '';
163
- // Begin output buffering
164
- ob_start();
165
- // Print the links before
166
- echo $beforeLink;
167
 
168
- // The Title
169
- $titleHtml = wprss_link_display($itemTitleUrl, $itemTitle, $linkTitleSetting);
170
- $titleHtml = apply_filters('wprss_item_title', $titleHtml, $itemTitleUrl, $itemTitle, $linkTitleSetting);
171
- echo $titleHtml;
172
 
173
- do_action('wprss_after_feed_item_title', $extraMeta, $displaySettings, $ID);
174
 
175
- // FEED ITEM META
176
- echo '<div class="wprss-feed-meta">';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
- // SOURCE
179
- if (wprss_get_general_setting('source_enable') == 1) {
180
- echo '<span class="feed-source">';
181
- $sourceLinkText = apply_filters('wprss_item_source_link', wprss_link_display($siteUrl, $feedName, $linkSource));
182
- $sourceLinkText = $sourcePrefix . $sourceLinkText;
183
- echo $sourceLinkText;
184
- echo '</span>';
185
- }
 
 
186
 
187
- // DATE
188
- if (wprss_get_general_setting('date_enable') == 1) {
189
- echo '<span class="feed-date">';
190
- $dateText = apply_filters('wprss_item_date', $date);
191
- $dateText = $datePrefix . $dateText;
192
- echo esc_html($dateText);
193
- echo '</span>';
194
- }
195
 
196
- // AUTHOR
197
- $author = get_post_meta($ID, 'wprss_item_author', true);
198
- if (wprss_get_general_setting('authors_enable') == 1 && $author !== null && is_string($author) && $author !== '') {
199
- echo '<span class="feed-author">';
200
- $authorText = apply_filters('wprss_item_author', $author);
201
- echo apply_filters(
202
- 'wprss_author_prefix_text',
203
- _x('By', 'Text before author name. Example: "By John Smith" ', 'wprss')
204
  );
205
- echo ' ' . esc_html($authorText);
206
- echo '</span>';
207
- }
208
 
209
- echo '</div>';
210
 
211
- // TIME AGO
212
- if (wprss_get_general_setting('date_enable') == 1 && wprss_get_general_setting('time_ago_format_enable') == 1) {
213
- $timeAgo = human_time_diff($timestamp, time());
214
- echo '<div class="wprss-time-ago">';
215
- $timeAgoText = apply_filters('wprss_item_time_ago', $timeAgo);
216
- printf(_x('%1$s ago', 'Time ago', 'wprss'), $timeAgoText);
217
- echo '</div>';
218
  }
219
 
220
- // END TEMPLATE - Retrieve buffered output
221
- $output .= ob_get_clean();
222
- $output = apply_filters('wprss_single_feed_output', $output, $permalink);
223
- $output .= $afterLink;
224
-
225
- // Print the output
226
- return $output;
227
- }
228
-
229
- /**
230
- * Retrieve settings and prepare them for use in the display function
231
- *
232
- * @since 3.0
233
- */
234
- function wprss_get_display_settings($settings = null)
235
- {
236
- if ($settings === null) {
237
- $settings = get_option('wprss_settings_general');
238
- }
239
- // Parse the arguments together with their default values
240
- $args = wp_parse_args(
241
- $settings,
242
- [
243
- 'open_dd' => 'blank',
244
- 'follow_dd' => '',
245
- ]
246
- );
247
-
248
- // Prepare the 'open' setting - how to open links for feed items
249
- $open = '';
250
- switch ($args['open_dd']) {
251
- case 'lightbox' :
252
- $open = 'class="colorbox"';
253
- break;
254
- case 'blank' :
255
- $open = 'target="_blank"';
256
- break;
257
- }
258
 
259
- // Prepare the 'follow' setting - whether links marked as nofollow or not
260
- $follow = ($args['follow_dd'] == 'no_follow') ? 'rel="nofollow"' : '';
261
-
262
- // Prepare the final settings array
263
- $display_settings = [
264
- 'open' => $open,
265
- 'follow' => $follow,
266
- ];
267
-
268
- do_action('wprss_get_settings');
269
-
270
- return $display_settings;
271
- }
272
-
273
- /**
274
- * Merges the default arguments with the user set arguments
275
- *
276
- * @since 3.0
277
- */
278
- function wprss_get_shortcode_default_args($args)
279
- {
280
- // Default shortcode/function arguments for displaying feed items
281
- $shortcode_args = apply_filters(
282
- 'wprss_shortcode_args',
283
- [
284
- 'links_before' => '<ul class="rss-aggregator">',
285
- 'links_after' => '</ul>',
286
- 'link_before' => '<li class="feed-item">',
287
- 'link_after' => '</li>',
288
- ]
289
- );
290
-
291
- // Parse incoming $args into an array and merge it with $shortcode_args
292
- return wp_parse_args($args, $shortcode_args);
293
- }
294
-
295
- /**
296
- * Prepares and builds the query for fetching the feed items
297
- *
298
- * @since 3.0
299
- */
300
- function wprss_get_feed_items_query($settings)
301
- {
302
- if (isset($settings['feed_limit'])) {
303
- $posts_per_page = $settings['feed_limit'];
304
- } else {
305
- $posts_per_page = wprss_get_general_setting('feed_limit');
306
- }
307
- global $paged;
308
- if (get_query_var('paged')) {
309
- $paged = get_query_var('paged');
310
- } elseif (get_query_var('page')) {
311
- $paged = get_query_var('page');
312
- } else {
313
- $paged = 1;
314
- }
315
 
316
- $feed_items_args = [
317
- 'post_type' => get_post_types(),
318
- 'posts_per_page' => $posts_per_page,
319
- 'orderby' => 'date',
320
- 'order' => 'DESC',
321
- 'paged' => $paged,
322
- 'suppress_filters' => true,
323
- 'ignore_sticky_posts' => true,
324
- 'meta_query' => [
325
- 'relation' => 'AND',
326
- [
327
- 'key' => 'wprss_feed_id',
328
- 'compare' => 'EXISTS',
329
- ],
330
- ],
331
- ];
332
-
333
- if (isset($settings['pagination'])) {
334
- $pagination = strtolower($settings['pagination']);
335
- if (in_array($pagination, ['false', 'off', '0'])) {
336
- unset($feed_items_args['paged']);
337
- }
338
- }
339
 
340
- if (isset($settings['no-paged']) && $settings['no-paged'] === true) {
341
- unset($feed_items_args['no-paged']);
342
  }
343
 
344
- // If either the source or exclude arguments are set (but not both), prepare a meta query
345
- if (isset($settings['source']) xor isset($settings['exclude'])) {
346
- // Set the appropriate setting and operator
347
- $setting = 'source';
348
- $operator = 'IN';
349
- if (isset($settings['exclude'])) {
350
- $setting = 'exclude';
351
- $operator = 'NOT IN';
 
 
 
 
 
 
 
 
 
 
 
352
  }
353
- $feeds = array_filter(array_map('intval', explode(',', $settings[$setting])));
354
- foreach ($feeds as $feed)
355
- trim($feed);
356
- if (!empty($feeds)) {
357
- $feed_items_args['meta_query'] = [
358
- [
 
 
 
 
 
 
359
  'key' => 'wprss_feed_id',
360
- 'value' => $feeds,
361
- 'type' => 'numeric',
362
- 'compare' => $operator,
363
- ],
364
- ];
 
 
 
 
 
365
  }
366
- }
367
 
368
- // Arguments for the next query to fetch all feed items
369
- $feed_items_args = apply_filters('wprss_display_feed_items_query', $feed_items_args, $settings);
370
-
371
- // Query to get all feed items for display
372
- $feed_items = new WP_Query($feed_items_args);
373
-
374
- if (isset($settings['get-args']) && $settings['get-args'] === true) {
375
- return $feed_items_args;
376
- } else return $feed_items;
377
- }
378
-
379
- add_action('wprss_display_template', 'wprss_default_display_template', 10, 3 );
380
- /**
381
- * Default template for feed items display
382
- *
383
- * @since 3.0
384
- *
385
- * @param $args array The shortcode arguments
386
- * @param $feed_items WP_Query The feed items to display
387
- */
388
- function wprss_default_display_template($args, $feed_items)
389
- {
390
- global $wp_query;
391
- global $paged;
392
-
393
- // Swap the current WordPress Query with our own
394
- $old_wp_query = $wp_query;
395
- $wp_query = $feed_items;
396
-
397
- // Prepare the output
398
- $output = '';
399
-
400
- // Check if our current query returned any feed items
401
- if ($feed_items->have_posts()) {
402
- // PRINT LINKS BEFORE LIST OF FEED ITEMS
403
- $output .= $args['links_before'];
404
-
405
- // FOR EACH ITEM
406
- while ($feed_items->have_posts()) {
407
- // Get the item
408
- $feed_items->the_post();
409
- // Add the output
410
- $output .= wprss_render_feed_item(NULL, '', $args);
411
  }
412
 
413
- // OUTPUT LINKS AFTER LIST OF FEED ITEMS
414
- $output .= $args['links_after'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
 
416
- // Add pagination if needed
417
- if (!isset($args['pagination']) || !in_array($args['pagination'], array('off', 'false', '0', 0))) {
418
- $output = apply_filters('wprss_pagination', $output);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  }
420
 
421
- // Filter the final output, and print it
422
- echo apply_filters('feed_output', $output);
423
- } else {
424
- // No items found message
425
- echo apply_filters('no_feed_items_found', __('No feed items found.', 'wprss'));
426
  }
427
 
428
- // Reset the WordPress query
429
- $wp_query = $old_wp_query;
430
- wp_reset_postdata();
431
- }
432
-
433
- /**
434
- * Generates an HTML link, using the saved display settings.
435
- *
436
- * @param string $link The link URL
437
- * @param string $text The link text to display
438
- * @param string $bool Optional boolean. If FALSE, the text is returned unlinked. Default: TRUE.
439
- * @return string The generated link
440
- * @since 4.2.4
441
- */
442
- function wprss_link_display( $link, $text, $bool = true ) {
443
- $settings = wprss_get_display_settings(get_option('wprss_settings_general'));
444
-
445
- return $bool
446
- ? sprintf('<a %s %s href="%s">%s</a>', $settings['open'], $settings['follow'], esc_attr($link), esc_html($text))
447
- : $text;
448
- }
449
-
450
-
451
- add_filter( 'wprss_pagination', 'wprss_pagination_links' );
452
- /**
453
- * Display pagination links
454
- *
455
- * @since 3.5
456
- */
457
- function wprss_pagination_links( $output ) {
458
- // Get the general setting
459
- $pagination = wprss_get_general_setting( 'pagination' );;
460
-
461
- // Check the pagination setting, if using page numbers
462
- if ( $pagination === 'numbered' ) {
463
- global $wp_query;
464
- $big = 999999999; // need an unlikely integer
465
- $output .= paginate_links( array(
466
- 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
467
- 'format' => '?paged=%#%',
468
- 'current' => max( 1, get_query_var('paged') ),
469
- 'total' => $wp_query->max_num_pages
470
- ) );
471
- return $output;
472
  }
473
- // Otherwise, using default paginations
474
- else {
475
- sprintf(
476
- '<div class="nav-links">%s %s</div>',
477
- sprintf(
478
- '<div class="nav-previous alignleft">%s</div>',
479
- get_next_posts_link(__('Older posts', 'wprss'))
480
- ),
481
- sprintf(
482
- '<div class="nav-next alignright">%s</div>',
483
- get_previous_posts_link(__('Newer posts', 'wprss'))
484
- )
485
- );
486
 
487
- return $output;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  }
489
- }
490
-
491
- /**
492
- * Checks the title limit option and shortens the title when necessary.
493
- *
494
- * @since 1.0
495
- *
496
- * @param string $title The title of tge feed item.
497
- * @param int|string|null $id The ID of the feed item.
498
- *
499
- * @return string
500
- */
501
- function wprss_shorten_title($title, $id = null)
502
- {
503
- if (isset($id) && get_post_type($id) === 'wprss_feed_item') {
504
- $settings = get_option('wprss_settings_general');
505
- $limit = isset($settings['title_limit'])
506
- ? intval($settings['title_limit'])
507
- : 0;
508
-
509
- if ($limit > 0 && strlen($title) > $limit) {
510
- $suffix = apply_filters('wprss_shortened_title_ending', '...');
511
- $title = substr($title, 0, $limit) . $suffix;
512
  }
 
 
513
  }
514
 
515
- return $title;
516
- }
517
-
518
-
519
- /**
520
- * Display feed items on the front end (via shortcode or function)
521
- *
522
- * @since 2.0
523
- */
524
- function wprss_display_feed_items($args = [])
525
- {
526
- $settings = get_option('wprss_settings_general');
527
- $args = wprss_get_shortcode_default_args($args);
528
-
529
- $args = apply_filters('wprss_shortcode_args', $args);
530
-
531
- $query_args = $settings;
532
- if (isset($args['limit'])) {
533
- $query_args['feed_limit'] = filter_var($args['limit'], FILTER_VALIDATE_INT, [
534
- 'options' => [
535
- 'min_range' => 1,
536
- 'default' => $query_args['feed_limit'],
537
- ],
538
- ]);
539
- }
540
 
541
- if (isset($args['pagination'])) {
542
- $query_args['pagination'] = $args['pagination'];
543
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
 
545
- if (isset($args['source'])) {
546
- $query_args['source'] = $args['source'];
547
- } elseif (isset($args['exclude'])) {
548
- $query_args['exclude'] = $args['exclude'];
549
  }
550
 
551
- $query_args = apply_filters('wprss_process_shortcode_args', $query_args, $args);
552
-
553
- $feed_items = wprss_get_feed_items_query($query_args);
554
-
555
- do_action('wprss_display_template', $args, $feed_items);
556
- }
557
-
558
- /**
559
- * Limits a phrase/content to a defined number of words
560
- *
561
- * NOT BEING USED as we're using the native WP function, although the native one strips tags, so I'll
562
- * probably revisit this one again soon.
563
- *
564
- * @since 3.0
565
- * @param string $words
566
- * @param integer $limit
567
- * @param string $append
568
- * @return string
569
- */
570
- function wprss_limit_words($words, $limit, $append = '')
571
- {
572
- /* Add 1 to the specified limit becuase arrays start at 0 */
573
- $limit = $limit + 1;
574
- /* Store each individual word as an array element
575
- up to the limit */
576
- $words = explode(' ', $words, $limit);
577
- /* Shorten the array by 1 because that final element will be the sum of all the words after the limit */
578
- array_pop($words);
579
- /* Implode the array for output, and append an ellipse */
580
- $words = implode(' ', $words) . $append;
581
- /* Return the result */
582
- return rtrim($words);
583
- }
1
  <?php
2
+ /**
3
+ * Feed display related functions
4
+ *
5
+ * @package WPRSSAggregator
6
+ */
7
+
8
+ /**
9
+ * Display template for a feed source. Simulates a shortcode call.
10
+ *
11
+ * @since 4.6.6
12
+ * @deprecated 4.13 This function was left here because the ET addon references it.
13
+ */
14
+ function wprss_render_feed_view( $content ) {
15
+ return $content;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
17
 
18
+ /**
19
+ * Display template for a feed source. Simulates a shortcode call.
20
+ *
21
+ * @since 4.6.6
22
+ * @deprecated 4.13 This function was left here because the ET addon references it.
23
+ */
24
+ function wprss_render_feed_item_view( $content ) {
25
+ return $content;
 
 
 
 
26
  }
27
 
28
+ /**
29
+ * Redirects to wprss_display_feed_items
30
+ * It is used for backwards compatibility to versions < 2.0
31
+ *
32
+ * @since 2.1
33
+ */
34
+ function wp_rss_aggregator( $args = array() ) {
35
+ $template = wpra_get('feeds/templates/master_template');
36
+ $fullArgs = $args;
37
+
38
+ // Use legacy mode if arg was not explicitly given
39
+ if (!isset($fullArgs['legacy'])) {
40
+ $fullArgs['legacy'] = true;
41
+ }
42
 
43
+ return $template->render($args);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
 
46
+ /**
47
+ * Handles the display for a single feed item.
48
+ *
49
+ * @since 4.6.6
50
+ */
51
+ function wprss_display_single_feed_item( $atts = array() ) {
52
+ if ( empty( $atts ) ) return;
53
+ $id = empty( $atts['id'] ) ? FALSE : $atts['id'];
54
+ if ( $id === FALSE || get_post_type( $id ) !== 'wprss_feed_item' || ( $item = get_post( $id ) ) === FALSE ) {
55
+ return '';
56
+ }
57
+ //Enqueue scripts / styles
58
+ wp_enqueue_script( 'jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', array( 'jquery' ) );
59
+ wp_enqueue_script( 'wprss_custom', WPRSS_JS . 'custom.js', array( 'jquery', 'jquery.colorbox-min' ) );
60
+
61
+ setup_postdata( $item );
62
+ $output = wprss_render_feed_item( $id );
63
+ $output = apply_filters( 'wprss_shortcode_single_output', $output );
64
+ wp_reset_postdata();
65
+ return $output;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
 
 
67
 
68
+ /**
69
+ * Renders a single feed item.
70
+ *
71
+ * @param int $ID The ID of the feed item to render
72
+ * @param string $default The default text to return if something fails.
73
+ * @return string The output
74
+ * @since 4.6.6
75
+ */
76
+ function wprss_render_feed_item( $ID = NULL, $default = '', $args = array() ) {
77
+ $ID = ( $ID === NULL )? get_the_ID() : $ID;
78
+ if ( is_feed() ) return $default;
79
+
80
+ // Prepare the options
81
+ $general_settings = get_option( 'wprss_settings_general' );
82
+ $display_settings = wprss_get_display_settings( $general_settings );
83
+ $excerpts_settings = get_option( 'wprss_settings_excerpts' );
84
+ $thumbnails_settings = get_option( 'wprss_settings_thumbnails' );
85
+
86
+ $args = wp_parse_args($args, array(
87
+ 'link_before' => '',
88
+ 'link_after' => ''
89
+ ));
90
+ $extra_options = apply_filters( 'wprss_template_extra_options', array(), $args);
91
+
92
+ // Declare each item in $args as its own variable
93
+ extract( $args, EXTR_SKIP );
94
+
95
+ // Get the item meta
96
+ $permalink = get_post_meta( $ID, 'wprss_item_permalink', true );
97
+ $enclosure = get_post_meta( $ID, 'wprss_item_enclosure', true );
98
+ $feed_source_id = get_post_meta( $ID, 'wprss_feed_id', true );
99
+ $link_enclosure = get_post_meta( $feed_source_id, 'wprss_enclosure', true );
100
+ $source_name = get_the_title( $feed_source_id );
101
+ $source_url = get_post_meta( $feed_source_id, 'wprss_site_url', true );
102
+ $timestamp = get_the_time( 'U', $ID );
103
+
104
+ $general_source_link = isset( $general_settings['source_link'] ) ? $general_settings['source_link'] : 0;
105
+ $feed_source_link = get_post_meta( $feed_source_id, 'wprss_source_link', true );
106
+ $source_link = ( $feed_source_link === '' || intval($feed_source_link) < 0 ) // If not explicit value
107
+ ? $general_source_link // Fall back to general setting
108
+ : $feed_source_link; // Otherwise, use value
109
+ $source_link = intval(trim($source_link));
110
+
111
+ // Fallback for feeds created with older versions of the plugin
112
+ if ( $source_url === '' ) $source_url = get_post_meta( $feed_source_id, 'wprss_url', true );
113
+ // convert from Unix timestamp
114
+ $date = wprss_date_i18n( $timestamp );
115
+
116
+ // Prepare the title
117
+ $feed_item_title = get_the_title();
118
+ $feed_item_title_link = ( $link_enclosure === 'true' && $enclosure !== '' )? $enclosure : $permalink;
119
+
120
+ // Prepare the text that precedes the source
121
+ $text_preceding_source = wprss_get_general_setting('text_preceding_source');
122
+ $text_preceding_source = ltrim( __( $text_preceding_source, WPRSS_TEXT_DOMAIN ) . ' ' );
123
+
124
+ $text_preceding_date = wprss_get_general_setting('text_preceding_date');
125
+ $text_preceding_date = ltrim( __( $text_preceding_date, WPRSS_TEXT_DOMAIN ) . ' ' );
126
+
127
+ do_action( 'wprss_get_post_data' );
128
+
129
+ $meta = $extra_options;
130
+ $extra_meta = apply_filters( 'wprss_template_extra_meta', $meta, $args, $ID );
131
+
132
+ ///////////////////////////////////////////////////////////////
133
+ // BEGIN TEMPLATE
134
+
135
+ // Prepare the output
136
+ $output = '';
137
+ // Begin output buffering
138
+ ob_start();
139
+ // Print the links before
140
+ echo $link_before;
141
+
142
+ // The Title
143
+ $item_title = wprss_link_display( $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link') );
144
+ $item_title = apply_filters('wprss_item_title', $item_title, $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link'));
145
+ echo $item_title;
146
+
147
+ do_action( 'wprss_after_feed_item_title', $extra_meta, $display_settings, $ID );
148
+
149
+ // FEED ITEM META
150
+ echo '<div class="wprss-feed-meta">';
151
+
152
+ // SOURCE
153
+ if ( wprss_get_general_setting('source_enable') == 1 ) {
154
+ echo '<span class="feed-source">';
155
+ $source_link_text = apply_filters('wprss_item_source_link', wprss_link_display( $source_url, $source_name, $source_link ) );
156
+ $source_link_text = $text_preceding_source . $source_link_text;
157
+ echo $source_link_text;
158
+ echo '</span>';
159
+ }
160
 
161
+ // DATE
162
+ if ( wprss_get_general_setting('date_enable') == 1 ) {
163
+ echo '<span class="feed-date">';
164
+ $date_text = apply_filters( 'wprss_item_date', $date );
165
+ $date_text = $text_preceding_date . $date_text;
166
+ echo $date_text;
167
+ echo '</span>';
168
+ }
169
 
170
+ // AUTHOR
171
+ $author = get_post_meta( $ID, 'wprss_item_author', TRUE );
172
+ if ( wprss_get_general_setting('authors_enable') == 1 && $author !== NULL && is_string( $author ) && $author !== '' ) {
173
+ echo '<span class="feed-author">';
174
+ $author_text = apply_filters( 'wprss_item_author', $author );
175
+ $author_prefix_text = apply_filters( 'wprss_author_prefix_text', 'By' );
176
+ _e( $author_prefix_text, WPRSS_TEXT_DOMAIN );
177
+ echo ' ' . $author_text;
178
+ echo '</span>';
179
+ }
180
 
181
+ echo '</div>';
 
182
 
183
+ // TIME AGO
184
+ if ( wprss_get_general_setting('date_enable') == 1 && wprss_get_general_setting('time_ago_format_enable') == 1 ) {
185
+ $time_ago = human_time_diff( $timestamp, time() );
186
+ echo '<div class="wprss-time-ago">';
187
+ $time_ago_text = apply_filters( 'wprss_item_time_ago', $time_ago );
188
+ printf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), $time_ago_text );
189
+ echo '</div>';
190
+ }
191
 
192
+ // END TEMPLATE - Retrieve buffered output
193
+ $output .= ob_get_clean();
194
+ $output = apply_filters( 'wprss_single_feed_output', $output, $permalink );
195
+ $output .= "$link_after";
 
 
196
 
197
+ // Print the output
198
+ return $output;
199
+ }
 
200
 
 
201
 
202
+ /**
203
+ * Retrieve settings and prepare them for use in the display function
204
+ *
205
+ * @since 3.0
206
+ */
207
+ function wprss_get_display_settings( $settings = NULL ) {
208
+ if ( $settings === NULL ) {
209
+ $settings = get_option( 'wprss_settings_general' );
210
+ }
211
+ // Parse the arguments together with their default values
212
+ $args = wp_parse_args(
213
+ $settings,
214
+ array(
215
+ 'open_dd' => 'blank',
216
+ 'follow_dd' => '',
217
+ )
218
+ );
219
 
220
+ // Prepare the 'open' setting - how to open links for feed items
221
+ $open = '';
222
+ switch ( $args['open_dd'] ) {
223
+ case 'lightbox' :
224
+ $open = 'class="colorbox"';
225
+ break;
226
+ case 'blank' :
227
+ $open = 'target="_blank"';
228
+ break;
229
+ }
230
 
231
+ // Prepare the 'follow' setting - whether links marked as nofollow or not
232
+ $follow = ( $args['follow_dd'] == 'no_follow' )? 'rel="nofollow"' : '';
 
 
 
 
 
 
233
 
234
+ // Prepare the final settings array
235
+ $display_settings = array(
236
+ 'open' => $open,
237
+ 'follow' => $follow
 
 
 
 
238
  );
 
 
 
239
 
240
+ do_action( 'wprss_get_settings' );
241
 
242
+ return $display_settings;
 
 
 
 
 
 
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
+ /**
247
+ * Merges the default arguments with the user set arguments
248
+ *
249
+ * @since 3.0
250
+ */
251
+ function wprss_get_shortcode_default_args( $args ) {
252
+ // Default shortcode/function arguments for displaying feed items
253
+ $shortcode_args = apply_filters(
254
+ 'wprss_shortcode_args',
255
+ array(
256
+ 'links_before' => '<ul class="rss-aggregator">',
257
+ 'links_after' => '</ul>',
258
+ 'link_before' => '<li class="feed-item">',
259
+ 'link_after' => '</li>'
260
+ )
261
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
 
263
+ // Parse incoming $args into an array and merge it with $shortcode_args
264
+ $args = wp_parse_args( $args, $shortcode_args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
+ return $args;
 
267
  }
268
 
269
+
270
+ /**
271
+ * Prepares and builds the query for fetching the feed items
272
+ *
273
+ * @since 3.0
274
+ */
275
+ function wprss_get_feed_items_query( $settings ) {
276
+ if( isset( $settings['feed_limit'] ) ) {
277
+ $posts_per_page = $settings['feed_limit'];
278
+ } else {
279
+ $posts_per_page = wprss_get_general_setting('feed_limit');
280
+ }
281
+ global $paged;
282
+ if ( get_query_var('paged') ) {
283
+ $paged = get_query_var('paged');
284
+ } elseif ( get_query_var('page') ) {
285
+ $paged = get_query_var('page');
286
+ } else {
287
+ $paged = 1;
288
  }
289
+
290
+ $feed_items_args = array(
291
+ 'post_type' => get_post_types(),
292
+ 'posts_per_page' => $posts_per_page,
293
+ 'orderby' => 'date',
294
+ 'order' => 'DESC',
295
+ 'paged' => $paged,
296
+ 'suppress_filters' => true,
297
+ 'ignore_sticky_posts' => true,
298
+ 'meta_query' => array(
299
+ 'relation' => 'AND',
300
+ array(
301
  'key' => 'wprss_feed_id',
302
+ 'compare' => 'EXISTS',
303
+ )
304
+ )
305
+ );
306
+
307
+ if ( isset($settings['pagination']) ) {
308
+ $pagination = strtolower( $settings['pagination'] );
309
+ if ( in_array( $pagination, array('false','off','0') ) ) {
310
+ unset( $feed_items_args['paged'] );
311
+ }
312
  }
 
313
 
314
+ if ( isset( $settings['no-paged'] ) && $settings['no-paged'] === TRUE ) {
315
+ unset( $feed_items_args['no-paged'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  }
317
 
318
+ // If either the source or exclude arguments are set (but not both), prepare a meta query
319
+ if ( isset( $settings['source'] ) xor isset( $settings['exclude'] ) ) {
320
+ // Set the appropriate setting and operator
321
+ $setting = 'source';
322
+ $operator = 'IN';
323
+ if ( isset( $settings['exclude'] ) ) {
324
+ $setting = 'exclude';
325
+ $operator = 'NOT IN';
326
+ }
327
+ $feeds = array_filter( array_map( 'intval', explode( ',', $settings[$setting] ) ) );
328
+ foreach ( $feeds as $feed )
329
+ trim( $feed );
330
+ if ( !empty( $feeds ) ) {
331
+ $feed_items_args['meta_query'] = array(
332
+ array(
333
+ 'key' => 'wprss_feed_id',
334
+ 'value' => $feeds,
335
+ 'type' => 'numeric',
336
+ 'compare' => $operator,
337
+ ),
338
+ );
339
+ }
340
+ }
341
+
342
+ // Arguments for the next query to fetch all feed items
343
+ $feed_items_args = apply_filters( 'wprss_display_feed_items_query', $feed_items_args, $settings );
344
+
345
+ // Query to get all feed items for display
346
+ $feed_items = new WP_Query( $feed_items_args );
347
+
348
+ if ( isset( $settings['get-args'] ) && $settings['get-args'] === TRUE ) {
349
+ return $feed_items_args;
350
+ } else return $feed_items;
351
+ }
352
 
353
+
354
+ add_action( 'wprss_display_template', 'wprss_default_display_template', 10, 3 );
355
+ /**
356
+ * Default template for feed items display
357
+ *
358
+ * @since 3.0
359
+ * @param $args array The shortcode arguments
360
+ * @param $feed_items WP_Query The feed items to display
361
+ */
362
+ function wprss_default_display_template( $args, $feed_items ) {
363
+ global $wp_query;
364
+ global $paged;
365
+
366
+ // Swap the current WordPress Query with our own
367
+ $old_wp_query = $wp_query;
368
+ $wp_query = $feed_items;
369
+
370
+ // Prepare the output
371
+ $output = '';
372
+
373
+ // Check if our current query returned any feed items
374
+ if ( $feed_items->have_posts() ) {
375
+ // PRINT LINKS BEFORE LIST OF FEED ITEMS
376
+ $output .= $args['links_before'];
377
+
378
+ // FOR EACH ITEM
379
+ while ( $feed_items->have_posts() ) {
380
+ // Get the item
381
+ $feed_items->the_post();
382
+ // Add the output
383
+ $output .= wprss_render_feed_item( NULL, '', $args );
384
+ }
385
+
386
+ // OUTPUT LINKS AFTER LIST OF FEED ITEMS
387
+ $output .= $args['links_after'];
388
+
389
+ // Add pagination if needed
390
+ if ( !isset( $args['pagination'] ) || !in_array( $args['pagination'], array('off','false','0',0) ) ) {
391
+ $output = apply_filters( 'wprss_pagination', $output );
392
+ }
393
+
394
+ // Filter the final output, and print it
395
+ echo apply_filters( 'feed_output', $output );
396
+ } else {
397
+ // No items found message
398
+ echo apply_filters( 'no_feed_items_found', __( 'No feed items found.', WPRSS_TEXT_DOMAIN ) );
399
  }
400
 
401
+ // Reset the WordPress query
402
+ $wp_query = $old_wp_query;
403
+ wp_reset_postdata();
 
 
404
  }
405
 
406
+
407
+ /**
408
+ * Generates an HTML link, using the saved display settings.
409
+ *
410
+ * @param string $link The link URL
411
+ * @param string $text The link text to display
412
+ * @param string $bool Optional boolean. If FALSE, the text is returned unlinked. Default: TRUE.
413
+ * @return string The generated link
414
+ * @since 4.2.4
415
+ */
416
+ function wprss_link_display( $link, $text, $bool = TRUE ) {
417
+ $display_settings = wprss_get_display_settings( get_option( 'wprss_settings_general' ) );
418
+ $a = $bool ? "<a {$display_settings['open']} {$display_settings['follow']} href='$link'>$text</a>" : $text;
419
+ return $a;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
421
 
422
+
423
+ add_filter( 'wprss_pagination', 'wprss_pagination_links' );
424
+ /**
425
+ * Display pagination links
426
+ *
427
+ * @since 3.5
428
+ */
429
+ function wprss_pagination_links( $output ) {
430
+ // Get the general setting
431
+ $pagination = wprss_get_general_setting( 'pagination' );;
432
+
433
+ // Check the pagination setting, if using page numbers
434
+ if ( $pagination === 'numbered' ) {
435
+ global $wp_query;
436
+ $big = 999999999; // need an unlikely integer
437
+ $output .= paginate_links( array(
438
+ 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
439
+ 'format' => '?paged=%#%',
440
+ 'current' => max( 1, get_query_var('paged') ),
441
+ 'total' => $wp_query->max_num_pages
442
+ ) );
443
+ return $output;
444
+ }
445
+ // Otherwise, using default paginations
446
+ else {
447
+ $output .= '<div class="nav-links">';
448
+ $output .= ' <div class="nav-previous alignleft">' . get_next_posts_link( __( 'Older posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
449
+ $output .= ' <div class="nav-next alignright">' . get_previous_posts_link( __( 'Newer posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
450
+ $output .= '</div>';
451
+ return $output;
452
+ }
453
  }
454
+
455
+
456
+ add_filter( 'the_title', 'wprss_shorten_title', 10, 2 );
457
+ /**
458
+ * Checks the title limit option and shortens the title when necassary.
459
+ *
460
+ * @since 1.0
461
+ */
462
+ function wprss_shorten_title( $title, $id = null ) {
463
+ if ( $id === null ) return $title;
464
+ // Get the option. If does not exist, use 0, which is ignored.
465
+ $general_settings = get_option( 'wprss_settings_general' );
466
+ $title_limit = isset( $general_settings['title_limit'] )? intval( $general_settings['title_limit'] ) : 0;
467
+ // Check if the title is for a wprss_feed_item, and check if trimming is needed
468
+ if ( isset( $id ) && get_post_type( $id ) === 'wprss_feed_item' && $title_limit > 0 && strlen( $title ) > $title_limit ) {
469
+ // Return the trimmed version of the title
470
+ return substr( $title, 0, $title_limit ) . apply_filters( 'wprss_shortened_title_ending', '...' );
 
 
 
 
 
 
471
  }
472
+ // Otherwise, return the same title
473
+ return $title;
474
  }
475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
+ /**
478
+ * Display feed items on the front end (via shortcode or function)
479
+ *
480
+ * @since 2.0
481
+ */
482
+ function wprss_display_feed_items( $args = array() ) {
483
+ $settings = get_option( 'wprss_settings_general' );
484
+ $args = wprss_get_shortcode_default_args( $args );
485
+
486
+ $args = apply_filters( 'wprss_shortcode_args', $args );
487
+
488
+ $query_args = $settings;
489
+ if ( isset( $args['limit'] ) ) {
490
+ $query_args['feed_limit'] = filter_var( $args['limit'], FILTER_VALIDATE_INT, array(
491
+ 'options' => array(
492
+ 'min_range' => 1,
493
+ 'default' => $query_args['feed_limit'],
494
+ ),
495
+ ) );
496
+ }
497
+
498
+ if ( isset( $args['pagination'] ) ) {
499
+ $query_args['pagination'] = $args['pagination'];
500
+ }
501
+
502
+ if ( isset( $args['source'] ) ) {
503
+ $query_args['source'] = $args['source'];
504
+ }
505
+ elseif ( isset( $args['exclude'] ) ) {
506
+ $query_args['exclude'] = $args['exclude'];
507
+ }
508
+
509
+ $query_args = apply_filters( 'wprss_process_shortcode_args', $query_args, $args );
510
 
511
+ $feed_items = wprss_get_feed_items_query( $query_args );
512
+
513
+ do_action( 'wprss_display_template', $args, $feed_items );
 
514
  }
515
 
516
+
517
+ /**
518
+ * Limits a phrase/content to a defined number of words
519
+ *
520
+ * NOT BEING USED as we're using the native WP function, although the native one strips tags, so I'll
521
+ * probably revisit this one again soon.
522
+ *
523
+ * @since 3.0
524
+ * @param string $words
525
+ * @param integer $limit
526
+ * @param string $append
527
+ * @return string
528
+ */
529
+ function wprss_limit_words( $words, $limit, $append = '' ) {
530
+ /* Add 1 to the specified limit becuase arrays start at 0 */
531
+ $limit = $limit + 1;
532
+ /* Store each individual word as an array element
533
+ up to the limit */
534
+ $words = explode( ' ', $words, $limit );
535
+ /* Shorten the array by 1 because that final element will be the sum of all the words after the limit */
536
+ array_pop( $words );
537
+ /* Implode the array for output, and append an ellipse */
538
+ $words = implode( ' ', $words ) . $append;
539
+ /* Return the result */
540
+ return rtrim( $words );
541
+ }
 
 
 
 
 
 
 
includes/libraries/WordPress-Readme-Parser/ReadmeParser.php CHANGED
File without changes
includes/libraries/browser.php CHANGED
File without changes
includes/libraries/php-markdown/markdown.php CHANGED
File without changes
includes/licensing.php CHANGED
File without changes
includes/misc-functions.php CHANGED
@@ -395,63 +395,3 @@ if (!function_exists('wprss_verify_nonce'))
395
  : false;
396
  }
397
  }
398
-
399
- /**
400
- * Formats a hook callback into a readable string.
401
- *
402
- * @param array $callback A callback entry.
403
- *
404
- * @return string The callback name.
405
- */
406
- function wprss_format_hook_callback(array $callback)
407
- {
408
- // Break static strings: "Example::method"
409
- // into arrays: ["Example", "method"]
410
- if (is_string($callback['function']) && (strpos($callback['function'], '::') !== false)) {
411
- $callback['function'] = explode('::', $callback['function']);
412
- }
413
-
414
- if (is_array($callback['function'])) {
415
- if (is_object($callback['function'][0])) {
416
- $class = get_class($callback['function'][0]);
417
- $access = '->';
418
- } else {
419
- $class = $callback['function'][0];
420
- $access = '::';
421
- }
422
-
423
- $callback['name'] = $class . $access . $callback['function'][1] . '()';
424
- } elseif (is_object($callback['function'])) {
425
- if (is_a($callback['function'], 'Closure')) {
426
- $callback['name'] = 'Closure';
427
- } else {
428
- $class = get_class($callback['function']);
429
-
430
- $callback['name'] = $class . '->__invoke()';
431
- }
432
- } else {
433
- $callback['name'] = $callback['function'] . '()';
434
- }
435
-
436
- return $callback['name'];
437
- }
438
-
439
- /**
440
- * Retrieves the file extension from a URI.
441
- *
442
- * @since 4.18
443
- *
444
- * @param string $uri The URI
445
- *
446
- * @return string|null The file extension or null if it could not be determined.
447
- */
448
- function wpra_get_uri_extension($uri)
449
- {
450
- $path = parse_url($uri, PHP_URL_PATH);
451
-
452
- if (!$path || empty($path)) {
453
- return null;
454
- }
455
-
456
- return strtolower(pathinfo($path, PATHINFO_EXTENSION));
457
- }
395
  : false;
396
  }
397
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/multimedia.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Checks if a URI points to an audio file.
5
- *
6
- * @since 4.18
7
- *
8
- * @param string $uri The URI to check.
9
- *
10
- * @return bool True if the URI points to an audio file, false if not.
11
- */
12
- function wpra_is_audio_file($uri)
13
- {
14
- switch (wpra_get_uri_extension($uri)) {
15
- case 'aac':
16
- case 'adts':
17
- case 'aif':
18
- case 'aifc':
19
- case 'aiff':
20
- case 'cdda':
21
- case 'bwf':
22
- case 'kar':
23
- case 'mid':
24
- case 'midi':
25
- case 'smf':
26
- case 'm4a':
27
- case 'mp3':
28
- case 'swa':
29
- case 'wav':
30
- case 'wax':
31
- case 'wma':
32
- return true;
33
- default:
34
- return false;
35
- }
36
- }
37
-
38
- /**
39
- * Checks if a URI points to a video file.
40
- *
41
- * @since 4.18
42
- *
43
- * @param string $uri The URI to check.
44
- *
45
- * @return bool True if the URI points to a video file, false if not.
46
- */
47
- function wpra_is_video_file($uri)
48
- {
49
- switch (wpra_get_uri_extension($uri)) {
50
- case 'mp4':
51
- case 'mkv':
52
- case 'mov':
53
- case 'avi':
54
- case 'webm':
55
- case 'ogg':
56
- return true;
57
- default:
58
- return false;
59
- }
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/opml-importer.php CHANGED
@@ -59,21 +59,22 @@
59
  * @return void
60
  */
61
  public function opml_import() {
62
- echo '<div class="wrap">';
63
- printf('<h2 class="wrap">%s</h2>', __('Import OPML', 'wprss'));
 
 
64
 
65
  // Get the current step from URL query string
66
- $step = filter_input(INPUT_GET, 'step', FILTER_VALIDATE_INT);
67
- $step = empty($step) ? 0 : $step;
68
 
69
  // Check the current step
70
  switch ( $step ) {
71
  default :
72
  case 0 :
73
  // Show the Import Message and the import upload form
74
- printf('<p>%s</p>', __('Howdy! Import your feeds here from an OPML (.xml) export file.', 'wprss'));
75
- printf('<p>%s</p>', __('Click the button below, choose your file, and click \'Upload\'.', 'wprss'));
76
- printf('<p>%s</p>', __('We will take care of the rest.', 'wprss'));
77
 
78
  // Show an import upload form that submits to the same page, with GET parameter step=1
79
  wp_import_upload_form( 'admin.php?import=wprss_opml_importer&amp;step=1' );
@@ -92,8 +93,8 @@
92
  }
93
  break;
94
  }
95
-
96
- echo '</div>';
97
  }
98
 
99
 
@@ -103,26 +104,18 @@
103
  $file = wp_import_handle_upload();
104
 
105
  // If the 'error' property is set, show the error message and return FALSE
106
- if (isset($file['error'])) {
107
- printf(
108
- '<p><strong>%s</strong><br/>%s</p>',
109
- __('Sorry, an error has been encountered.', 'wprss'),
110
- esc_html($file['error'])
111
- );
112
- return false;
113
- // If the file does not exist, then show the error message and return FALSE
114
- } elseif (!file_exists($file['file'])) {
115
- printf(
116
- '<p><strong>%s</strong><br/>%s</p>',
117
- __('Sorry, it seems your uploaded file has been misplaced!', 'wprss'),
118
- sprintf(
119
- __('The uploaded file could not be found at %s. It is likely that this was caused by a permissions problem.', 'wprss'),
120
- '<code>' . esc_html($file['file']) . '</code>'
121
- )
122
- );
123
-
124
- return false;
125
- }
126
 
127
 
128
  $this->id = (int) $file['id'];
@@ -191,16 +184,16 @@
191
  $opml = new WPRSS_OPML( $file );
192
 
193
  // Show Success Message
194
- ?><h3><?php _e( 'Feeds were imported successfully!', 'wprss' ) ?></h3><?php
195
 
196
  // Show imported feeds
197
  ?>
198
  <table class="widefat">
199
  <thead>
200
  <tr>
201
- <th><?php _e( 'ID', 'wprss' ) ?></th>
202
- <th><?php _e( 'Title', 'wprss' ) ?></th>
203
- <th><?php _e( 'URL', 'wprss' ) ?></th>
204
  </tr>
205
  </thead>
206
 
@@ -229,9 +222,9 @@
229
 
230
  <tfoot>
231
  <tr>
232
- <th><?php _e( 'ID', 'wprss' ) ?></th>
233
- <th><?php _e( 'Title', 'wprss' ) ?></th>
234
- <th><?php _e( 'URL', 'wprss' ) ?></th>
235
  </tr>
236
  </tfoot>
237
 
@@ -240,7 +233,7 @@
240
 
241
  } catch (Exception $e) {
242
  // Show Error Message
243
- ?><div class="error"><?php echo wpautop( __( $e->getMessage(), 'wprss' ) ) ?></div><?php
244
  }
245
  }
246
 
@@ -261,8 +254,8 @@
261
 
262
  register_importer(
263
  'wprss_opml_importer',
264
- __( 'WP RSS OPML', 'wprss' ),
265
- __( 'Import Feeds from an OPML file into WP RSS Aggregator', 'wprss' ),
266
  array( WPRSS_OPML_Importer::$singleton ,'opml_import' )
267
  );
268
 
59
  * @return void
60
  */
61
  public function opml_import() {
62
+ // Show the Icon and Title
63
+ ?>
64
+ <div class="wrap">
65
+ <h2><?php _e( 'Import OPML', WPRSS_TEXT_DOMAIN ) ?></h2><?php
66
 
67
  // Get the current step from URL query string
68
+ $step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
 
69
 
70
  // Check the current step
71
  switch ( $step ) {
72
  default :
73
  case 0 :
74
  // Show the Import Message and the import upload form
75
+ echo '<p>' . __( 'Howdy! Import your feeds here from an OPML (.xml) export file.', WPRSS_TEXT_DOMAIN ) . '</p>';
76
+ echo '<p>' . __( "Click the button below, choose your file, and click 'Upload'.", WPRSS_TEXT_DOMAIN ) . '</p>';
77
+ echo '<p>' . __( 'We will take care of the rest.', WPRSS_TEXT_DOMAIN ) . '</p>';
78
 
79
  // Show an import upload form that submits to the same page, with GET parameter step=1
80
  wp_import_upload_form( 'admin.php?import=wprss_opml_importer&amp;step=1' );
93
  }
94
  break;
95
  }
96
+
97
+ ?></div><?php
98
  }
99
 
100
 
104
  $file = wp_import_handle_upload();
105
 
106
  // If the 'error' property is set, show the error message and return FALSE
107
+ if ( isset( $file['error'] ) ) {
108
+ echo '<p><strong>' . __( 'Sorry, an error has been encountered.', WPRSS_TEXT_DOMAIN ) . '</strong><br />';
109
+ echo esc_html( $file['error'] ) . '</p>';
110
+ return false;
111
+ // If the file does not exist, then show the error message and return FALSE
112
+ } else if ( ! file_exists( $file['file'] ) ) {
113
+ echo '<p><strong>' . __( 'Sorry, it seems your uploaded file has been misplaced!', WPRSS_TEXT_DOMAIN ) . '</strong><br />';
114
+ echo __( 'The uploaded file could not be found at ', WPRSS_TEXT_DOMAIN ) . '<code>' . esc_html( $file['file'] ) . '</code>';
115
+ echo __( 'It is likely that this was caused by a permissions problem.' , WPRSS_TEXT_DOMAIN );
116
+ echo '</p>';
117
+ return false;
118
+ }
 
 
 
 
 
 
 
 
119
 
120
 
121
  $this->id = (int) $file['id'];
184
  $opml = new WPRSS_OPML( $file );
185
 
186
  // Show Success Message
187
+ ?><h3><?php _e( 'Feeds were imported successfully!', WPRSS_TEXT_DOMAIN ) ?></h3><?php
188
 
189
  // Show imported feeds
190
  ?>
191
  <table class="widefat">
192
  <thead>
193
  <tr>
194
+ <th><?php _e( 'ID', WPRSS_TEXT_DOMAIN ) ?></th>
195
+ <th><?php _e( 'Title', WPRSS_TEXT_DOMAIN ) ?></th>
196
+ <th><?php _e( 'URL', WPRSS_TEXT_DOMAIN ) ?></th>
197
  </tr>
198
  </thead>
199
 
222
 
223
  <tfoot>
224
  <tr>
225
+ <th><?php _e( 'ID', WPRSS_TEXT_DOMAIN ) ?></th>
226
+ <th><?php _e( 'Title', WPRSS_TEXT_DOMAIN ) ?></th>
227
+ <th><?php _e( 'URL', WPRSS_TEXT_DOMAIN ) ?></th>
228
  </tr>
229
  </tfoot>
230
 
233
 
234
  } catch (Exception $e) {
235
  // Show Error Message
236
+ ?><div class="error"><?php echo wpautop( __( $e->getMessage(), WPRSS_TEXT_DOMAIN ) ) ?></div><?php
237
  }
238
  }
239
 
254
 
255
  register_importer(
256
  'wprss_opml_importer',
257
+ __( 'WP RSS OPML', WPRSS_TEXT_DOMAIN ),
258
+ __( 'Import Feeds from an OPML file into WP RSS Aggregator', WPRSS_TEXT_DOMAIN ),
259
  array( WPRSS_OPML_Importer::$singleton ,'opml_import' )
260
  );
261
 
includes/readme.php CHANGED
File without changes
includes/roles-capabilities.php CHANGED
@@ -14,20 +14,21 @@
14
  */
15
  function wprss_remove_caps()
16
  {
17
- global $wp_roles;
18
-
19
- if (!isset($wp_roles)) {
20
- $wp_roles = new WP_Roles();
21
  }
22
 
23
- if ($wp_roles instanceof WP_Roles) {
 
24
  /** Site Administrator Capabilities */
25
  $wp_roles->remove_cap('administrator', 'manage_feed_settings');
26
  /** Editor Capabilities */
27
  $wp_roles->remove_cap('editor', 'manage_feed_settings');
28
 
29
  /** Remove the Main Post Type Capabilities */
30
- $capabilities = wprss_get_core_caps();
31
 
32
  foreach ($capabilities as $cap_group) {
33
  foreach ($cap_group as $cap) {
@@ -37,42 +38,3 @@ function wprss_remove_caps()
37
  }
38
  }
39
  }
40
-
41
- /**
42
- * Gets the core post type capabilities.
43
- *
44
- * @since 4.18
45
- */
46
- function wprss_get_core_caps()
47
- {
48
- $capabilities = [];
49
-
50
- $capability_types = ['feed', 'feed_source'];
51
-
52
- foreach ($capability_types as $capability_type) {
53
- $capabilities[$capability_type] = [
54
- // Post type
55
- "edit_{$capability_type}",
56
- "read_{$capability_type}",
57
- "delete_{$capability_type}",
58
- "edit_{$capability_type}s",
59
- "edit_others_{$capability_type}s",
60
- "publish_{$capability_type}s",
61
- "read_private_{$capability_type}s",
62
- "delete_{$capability_type}s",
63
- "delete_private_{$capability_type}s",
64
- "delete_published_{$capability_type}s",
65
- "delete_others_{$capability_type}s",
66
- "edit_private_{$capability_type}s",
67
- "edit_published_{$capability_type}s",
68
-
69
- // Terms
70
- "manage_{$capability_type}_terms",
71
- "edit_{$capability_type}_terms",
72
- "delete_{$capability_type}_terms",
73
- "assign_{$capability_type}_terms",
74
- ];
75
- }
76
-
77
- return $capabilities;
78
- }
14
  */
15
  function wprss_remove_caps()
16
  {
17
+ if (class_exists('WP_Roles')) {
18
+ if (!isset($wp_roles)) {
19
+ $wp_roles = new WP_Roles();
20
+ }
21
  }
22
 
23
+ if (is_object($wp_roles)) {
24
+
25
  /** Site Administrator Capabilities */
26
  $wp_roles->remove_cap('administrator', 'manage_feed_settings');
27
  /** Editor Capabilities */
28
  $wp_roles->remove_cap('editor', 'manage_feed_settings');
29
 
30
  /** Remove the Main Post Type Capabilities */
31
+ $capabilities = $this->get_core_caps();
32
 
33
  foreach ($capabilities as $cap_group) {
34
  foreach ($cap_group as $cap) {
38
  }
39
  }
40
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/scripts.php CHANGED
@@ -1,267 +1,265 @@
1
  <?php
2
- /**
3
- * Scripts
4
- *
5
- * @package WPRSSAggregator
6
- */
7
-
8
- use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
9
-
10
- add_action('init', function () {
11
- $version = wprss()->getVersion();
12
-
13
- // Add the Class library, the Xdn library, and the Aventura namespace and classes
14
- wp_register_script('wprss-xdn-class', wprss_get_script_url('class'), ['jquery'], $version);
15
- wp_register_script('wprss-xdn-lib', wprss_get_script_url('xdn'), ['wprss-xdn-class'], $version);
16
- wp_register_script('aventura', wprss_get_script_url('aventura'), ['wprss-xdn-lib'], $version);
17
-
18
- wp_register_script('wprss-admin-addon-ajax', WPRSS_JS . 'admin-addon-ajax.js', ['jquery'], $version);
19
- wp_localize_script('wprss-admin-addon-ajax', 'wprss_admin_addon_ajax', [
20
- 'please_wait' => __('Please wait ...', 'wprss'),
21
- 'nonce' => wp_create_nonce('wprss_admin_addon_ajax'),
22
- ]);
23
-
24
- // Prepare the URL for removing bulk from blacklist, with a nonce
25
- $blacklist_remove_url = admin_url('edit.php?wprss-bulk=1');
26
- $blacklist_remove_url = wp_nonce_url($blacklist_remove_url, 'blacklist-remove-selected', 'wprss_blacklist_trash');
27
- $blacklist_remove_url .= '&wprss-blacklist-remove=';
28
- wp_register_script('wprss-admin-custom', WPRSS_JS . 'admin-custom.js',
29
- ['jquery', 'jquery-ui-datepicker', 'jquery-ui-slider'], $version);
30
- wp_localize_script('wprss-admin-custom', 'wprss_admin_custom', [
31
- 'failed_to_import' => __('Failed to import', 'wprss'),
32
- 'items_are_importing' => __('Importing!', 'wprss'),
33
- 'items_are_deleting' => __('Deleting!', 'wprss'),
34
- 'please_wait' => __('Please wait ...', 'wprss'),
35
- 'bulk_add' => __('Bulk Add', 'wprss'),
36
- 'ok' => __('OK', 'wprss'),
37
- 'cancel' => __('Cancel', 'wprss'),
38
- 'blacklist_desc' => __('The feed items listed here will be disregarded when importing new items from your feed sources.',
39
- 'wprss'),
40
- 'blacklist_remove' => __('Remove selected from Blacklist', 'wprss'),
41
- 'blacklist_remove_url' => $blacklist_remove_url,
42
- ]);
43
- // Creates the wprss_urls object in JS
44
- wp_localize_script('wprss-admin-custom', 'wprss_urls', [
45
- 'import_export' => admin_url('edit.php?post_type=wprss_feed&page=wprss-import-export-settings'),
46
- ]);
47
-
48
- wp_register_script('jquery-ui-timepicker-addon', WPRSS_JS . 'jquery-ui-timepicker-addon.js',
49
- ['jquery', 'jquery-ui-datepicker'], $version);
50
- wp_register_script('wprss-custom-bulk-actions', WPRSS_JS . 'admin-custom-bulk-actions.js', ['jquery'], $version);
51
- wp_localize_script('wprss-custom-bulk-actions', 'wprss_admin_bulk', [
52
- 'activate' => __('Activate', 'wprss'),
53
- 'pause' => __('Pause', 'wprss'),
54
- ]);
55
-
56
- wp_register_script('wprss-feed-source-table-heartbeat', WPRSS_JS . 'heartbeat.js', [], $version);
57
- wp_localize_script('wprss-feed-source-table-heartbeat', 'wprss_admin_heartbeat', [
58
- 'ago' => __('ago', 'wprss'),
59
- ]);
60
- wp_register_script('wprss-admin-license-manager', WPRSS_JS . 'admin-license-manager.js', [], $version);
61
-
62
- wp_register_script('wprss-admin-licensing', WPRSS_JS . 'admin-licensing.js', [], $version);
63
- wp_localize_script('wprss-admin-licensing', 'wprss_admin_licensing', [
64
- 'activating' => __('Activating...', 'wprss'),
65
- 'deactivating' => __('Deactivating...', 'wprss'),
66
- ]);
67
-
68
- wp_register_script('wprss-admin-help', WPRSS_JS . 'admin-help.js', [], $version);
69
- wp_localize_script('wprss-admin-help', 'wprss_admin_help', [
70
- 'sending' => __('Sending...', 'wprss'),
71
- 'sent-error' => sprintf(
72
- __(
73
- 'There was an error sending the form. Please use the <a href="%s">contact form on our site.</a>',
74
- 'wprss'
75
- ),
76
- esc_attr('https://www.wprssaggregator.com/contact/')
77
- ),
78
- 'sent-ok' => __(
79
- 'Your message has been sent and we\'ll send you a confirmation e-mail when we receive it.',
80
- 'wprss'
81
- ),
82
- ]);
83
-
84
- wp_register_script('wprss-hs-beacon-js', WPRSS_JS . 'beacon.min.js', [], $version);
85
- wp_localize_script('wprss-hs-beacon-js', 'WprssHelpBeaconConfig', [
86
- 'premiumSupport' => (wprss_licensing_get_manager()->licenseWithStatusExists(License_Status::VALID)),
87
- ]);
88
-
89
- wp_register_script('wprss-gallery-js', WPRSS_JS . 'gallery.js', ['jquery'], $version, true);
90
-
91
- wp_register_script('wpra-tools', WPRSS_JS . 'admin/tools/main.js', ['jquery'], $version, true);
92
- wp_register_script('wpra-logs-tool', WPRSS_JS . 'admin/tools/logs.js', ['jquery'], $version, true);
93
- wp_register_script('wpra-blacklist-tool', WPRSS_JS . 'admin/tools/blacklist.js', ['jquery'], $version, true);
94
-
95
- $wpSchedules = wp_get_schedules();
96
- $globSchedule = wprss_get_general_setting('cron_interval');
97
- $customSchedule = [
98
- 'display' => __('Use Global Cron', 'wprss'),
99
- 'interval' => $wpSchedules[$globSchedule]['interval'],
100
- ];
101
- $schedules = array_merge(['global' => $customSchedule], $wpSchedules);
102
-
103
- wp_register_script('wpra-crons-tool', WPRSS_JS . 'admin/tools/crons.js', ['jquery'], $version, true);
104
- wp_localize_script('wpra-crons-tool', 'WpraCronsTool', [
105
- 'restUrl' => trailingslashit(rest_url()),
106
- 'restApiNonce' => wp_create_nonce('wp_rest'),
107
- 'globalInterval' => $globSchedule,
108
- 'globalTime' => wprss_get_global_update_time(),
109
- 'globalWord' => __('Global', 'wprss'),
110
- 'perPage' => 30,
111
- 'schedules' => $schedules,
112
- ]);
113
-
114
- wp_register_script('wpra-reset-tool', WPRSS_JS . 'admin/tools/reset.js', ['jquery'], $version, true);
115
- wp_localize_script('wpra-reset-tool', 'WpraResetTool', [
116
- 'message' => __('Are you sure you want to do this? This operation cannot be undone.', 'wprss'),
117
- ]);
118
- }, 9);
119
-
120
- add_action('admin_enqueue_scripts', 'wprss_admin_scripts_styles');
121
- /**
122
- * Insert required scripts, styles and filters on the admin side
123
- *
124
- * @since 2.0
125
- */
126
- function wprss_admin_scripts_styles()
127
- {
128
- $isWpraScreen = wprss_is_wprss_page();
129
-
130
- // On all admin screens
131
- wp_enqueue_style('wprss-admin-editor-styles');
132
- wp_enqueue_style('wprss-admin-tracking-styles');
133
- wp_enqueue_style('wprss-admin-general-styles');
134
-
135
- // Only on WPRA-related admin screens
136
- if ($isWpraScreen) {
137
- wprss_admin_exclusive_scripts_styles();
138
  }
139
 
140
- do_action('wprss_admin_scripts_styles');
141
- } // end wprss_admin_scripts_styles
142
 
143
- /**
144
- * Enqueues backend scripts on WPRA-related pages only
145
- *
146
- * @since 4.10
147
- */
148
- function wprss_admin_exclusive_scripts_styles()
149
- {
150
- $screen = get_current_screen();
151
- $pageBase = $screen->base;
152
- $postType = $screen->post_type;
153
-
154
- wp_enqueue_style('wprss-admin-styles');
155
- wp_enqueue_style('wprss-fa');
156
- wp_enqueue_style('wprss-admin-3.8-styles');
157
-
158
- wp_enqueue_script('wprss-xdn-class');
159
- wp_enqueue_script('wprss-xdn-lib');
160
- wp_enqueue_script('aventura');
161
-
162
- wp_enqueue_script('wprss-admin-addon-ajax');
163
-
164
- wp_enqueue_script('wprss-admin-custom');
165
-
166
- wp_enqueue_script('jquery-ui-timepicker-addon');
167
- wp_enqueue_style('jquery-style');
168
-
169
- if ($pageBase === 'post' && $postType = 'wprss_feed') {
170
- // Change text on post screen from 'Enter title here' to 'Enter feed name here'
171
- add_filter('enter_title_here', 'wprss_change_title_text');
172
- wp_enqueue_media();
173
- wp_enqueue_script('wprss-gallery-js');
174
- }
175
- if ('wprss_feed' === $postType) {
176
- wp_enqueue_script('wprss-custom-bulk-actions');
177
- }
178
- if ('wprss_feed_item' === $postType) {
179
- wp_enqueue_script('wprss-custom-bulk-actions-feed-item');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
181
 
182
- // Load Heartbeat script and set dependancy for Heartbeat to ensure Heartbeat is loaded
183
- if ($pageBase === 'edit' && $postType === 'wprss_feed' && apply_filters('wprss_ajax_polling', true) === true) {
184
- wp_enqueue_script('wprss-feed-source-table-heartbeat');
185
- }
186
 
187
- if ($pageBase === 'wprss_feed_page_wprss-aggregator-settings') {
188
- wp_enqueue_script('wprss-admin-license-manager');
189
- wp_enqueue_script('wprss-admin-licensing');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  }
191
 
192
- if ($pageBase === 'wprss_feed_page_wprss-help') {
193
- wp_enqueue_script('wprss-admin-help');
194
- }
195
 
196
- if ($pageBase === 'wprss_feed_page_wpra_tools') {
197
- wp_enqueue_script('wpra-tools');
198
- wp_enqueue_script('wpra-logs-tool');
199
- wp_enqueue_script('wpra-blacklist-tool');
200
- wp_enqueue_script('wpra-crons-tool');
201
- wp_enqueue_script('wpra-reset-tool');
 
 
202
  }
203
 
204
- if (wprss_is_help_beacon_enabled()) {
205
- wp_enqueue_script('wprss-hs-beacon-js');
206
- wp_enqueue_style('wprss-hs-beacon-css');
207
- }
208
 
209
- do_action('wprss_admin_exclusive_scripts_styles');
210
- }
211
-
212
- add_action('wp_enqueue_scripts', 'wprss_load_scripts');
213
- /**
214
- * Enqueues the required scripts.
215
- *
216
- * @since 3.0
217
- */
218
- function wprss_load_scripts()
219
- {
220
- /* wp_enqueue_script( 'jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', array( 'jquery' ) );
221
- wp_enqueue_script( 'custom', WPRSS_JS . 'custom.js', array( 'jquery', 'jquery.colorbox-min' ) ); */
222
- do_action('wprss_register_scripts');
223
- } // end wprss_head_scripts_styles
224
-
225
- /**
226
- * Returns the path to the WPRSS templates directory
227
- *
228
- * @since 3.0
229
- * @return string
230
- */
231
- function wprss_get_templates_dir()
232
- {
233
- return WPRSS_DIR . 'templates';
234
- }
235
-
236
- /**
237
- * Returns the URL to the WPRSS templates directory
238
- *
239
- * @since 3.0
240
- * @return string
241
- */
242
- function wprss_get_templates_uri()
243
- {
244
- return WPRSS_URI . 'templates';
245
- }
246
-
247
- add_action('init', 'wprss_register_styles');
248
- /**
249
- * Registers all WPRA styles.
250
- *
251
- * Does not enqueue anything.
252
- *
253
- * @since 3.0
254
- */
255
- function wprss_register_styles()
256
- {
257
- $version = wprss()->getVersion();
258
-
259
- wp_register_style('wprss-admin-styles', WPRSS_CSS . 'admin-styles.css', [], $version);
260
- wp_register_style('wprss-fa', WPRSS_CSS . 'font-awesome.min.css', [], $version);
261
- wp_register_style('wprss-admin-3.8-styles', WPRSS_CSS . 'admin-3.8.css', [], $version);
262
- wp_register_style('wprss-admin-editor-styles', WPRSS_CSS . 'admin-editor.css', [], $version);
263
- wp_register_style('wprss-admin-tracking-styles', WPRSS_CSS . 'admin-tracking-styles.css', [], $version);
264
- wp_register_style('wprss-admin-general-styles', WPRSS_CSS . 'admin-general-styles.css', [], $version);
265
- wp_register_style('wprss-hs-beacon-css', WPRSS_CSS . 'beacon.css', [], $version);
266
- wp_register_style('jquery-style', WPRSS_CSS . 'jquery-ui-smoothness.css', [], $version);
267
- }
1
  <?php
2
+ /**
3
+ * Scripts
4
+ *
5
+ * @package WPRSSAggregator
6
+ */
7
+
8
+ use Aventura\Wprss\Core\Licensing\License\Status as License_Status;
9
+
10
+ add_action( 'init', 'wprss_register_scripts', 9 );
11
+ function wprss_register_scripts()
12
+ {
13
+ $version = wprss()->getVersion();
14
+
15
+ // Add the Class library, the Xdn library, and the Aventura namespace and classes
16
+ wp_register_script( 'wprss-xdn-class', wprss_get_script_url( 'class' ), array('jquery'), $version );
17
+ wp_register_script( 'wprss-xdn-lib', wprss_get_script_url( 'xdn' ), array('wprss-xdn-class'), $version );
18
+ wp_register_script( 'aventura', wprss_get_script_url( 'aventura' ), array('wprss-xdn-lib'), $version );
19
+
20
+ wp_register_script( 'wprss-admin-addon-ajax', WPRSS_JS .'admin-addon-ajax.js', array('jquery'), $version );
21
+ wp_localize_script( 'wprss-admin-addon-ajax', 'wprss_admin_addon_ajax', array(
22
+ 'please_wait' => __( 'Please wait ...', WPRSS_TEXT_DOMAIN )
23
+ ));
24
+
25
+ // Prepare the URL for removing bulk from blacklist, with a nonce
26
+ $blacklist_remove_url = admin_url( 'edit.php?wprss-bulk=1' );
27
+ $blacklist_remove_url = wp_nonce_url( $blacklist_remove_url, 'blacklist-remove-selected', 'wprss_blacklist_trash' );
28
+ $blacklist_remove_url .= '&wprss-blacklist-remove=';
29
+ wp_register_script( 'wprss-admin-custom', WPRSS_JS .'admin-custom.js', array('jquery','jquery-ui-datepicker','jquery-ui-slider'), $version );
30
+ wp_localize_script( 'wprss-admin-custom', 'wprss_admin_custom', array(
31
+ 'failed_to_import' => __( 'Failed to import', WPRSS_TEXT_DOMAIN ),
32
+ 'items_are_importing' => __( 'Importing!', WPRSS_TEXT_DOMAIN ),
33
+ 'items_are_deleting' => __( 'Deleting!', WPRSS_TEXT_DOMAIN ),
34
+ 'please_wait' => __( 'Please wait ...', WPRSS_TEXT_DOMAIN ),
35
+ 'bulk_add' => __( 'Bulk Add', WPRSS_TEXT_DOMAIN ),
36
+ 'ok' => __( 'OK', WPRSS_TEXT_DOMAIN ),
37
+ 'cancel' => __( 'Cancel', WPRSS_TEXT_DOMAIN ),
38
+ 'blacklist_desc' => __( 'The feed items listed here will be disregarded when importing new items from your feed sources.', WPRSS_TEXT_DOMAIN ),
39
+ 'blacklist_remove' => __( 'Remove selected from Blacklist', WPRSS_TEXT_DOMAIN ),
40
+ 'blacklist_remove_url' => $blacklist_remove_url
41
+ ));
42
+ // Creates the wprss_urls object in JS
43
+ wp_localize_script( 'wprss-admin-custom', 'wprss_urls', array(
44
+ 'import_export' => admin_url('edit.php?post_type=wprss_feed&page=wprss-import-export-settings')
45
+ ));
46
+
47
+ wp_register_script( 'jquery-ui-timepicker-addon', WPRSS_JS .'jquery-ui-timepicker-addon.js', array('jquery','jquery-ui-datepicker'), $version );
48
+ wp_register_script( 'wprss-custom-bulk-actions', WPRSS_JS . 'admin-custom-bulk-actions.js', array( 'jquery' ), $version );
49
+ wp_localize_script( 'wprss-custom-bulk-actions', 'wprss_admin_bulk', array(
50
+ 'activate' => __( 'Activate', WPRSS_TEXT_DOMAIN ),
51
+ 'pause' => __( 'Pause', WPRSS_TEXT_DOMAIN )
52
+ ));
53
+
54
+ wp_register_script( 'wprss-feed-source-table-heartbeat', WPRSS_JS .'heartbeat.js', array(), $version );
55
+ wp_localize_script( 'wprss-feed-source-table-heartbeat', 'wprss_admin_heartbeat', array(
56
+ 'ago' => __( 'ago', WPRSS_TEXT_DOMAIN )
57
+ ));
58
+ wp_register_script( 'wprss-admin-license-manager', WPRSS_JS . 'admin-license-manager.js', array(), $version );
59
+
60
+ wp_register_script( 'wprss-admin-licensing', WPRSS_JS . 'admin-licensing.js', array(), $version );
61
+ wp_localize_script( 'wprss-admin-licensing', 'wprss_admin_licensing', array(
62
+ 'activating' => __('Activating...', WPRSS_TEXT_DOMAIN),
63
+ 'deactivating' => __('Deactivating...', WPRSS_TEXT_DOMAIN)
64
+ ));
65
+
66
+ wp_register_script( 'wprss-admin-help', WPRSS_JS . 'admin-help.js', array(), $version );
67
+ wp_localize_script( 'wprss-admin-help', 'wprss_admin_help', array(
68
+ 'sending' => __('Sending...', WPRSS_TEXT_DOMAIN),
69
+ 'sent-error' => sprintf(__('There was an error sending the form. Please use the <a href="%s">contact form on our site.</a>', WPRSS_TEXT_DOMAIN), esc_attr('https://www.wprssaggregator.com/contact/')),
70
+ 'sent-ok' => __("Your message has been sent and we'll send you a confirmation e-mail when we receive it.", WPRSS_TEXT_DOMAIN)
71
+ ));
72
+
73
+ wp_register_script( 'wprss-hs-beacon-js', WPRSS_JS . 'beacon.min.js', array(), $version );
74
+ wp_localize_script( 'wprss-hs-beacon-js', 'WprssHelpBeaconConfig', array (
75
+ 'premiumSupport' => ( wprss_licensing_get_manager()->licenseWithStatusExists( License_Status::VALID ) )
76
+ ));
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
+ $wpSchedules = wp_get_schedules();
85
+ $globSchedule = wprss_get_general_setting('cron_interval');
86
+ $customSchedule = [
87
+ 'display' => __('Use Global Cron', 'wprss'),
88
+ 'interval' => $wpSchedules[$globSchedule]['interval'],
89
+ ];
90
+ $schedules = array_merge(['global' => $customSchedule], $wpSchedules);
91
+
92
+ wp_register_script('wpra-crons-tool', WPRSS_JS . 'admin/tools/crons.js', ['jquery'], $version, true);
93
+ wp_localize_script('wpra-crons-tool', 'WpraCronsTool', [
94
+ 'restUrl' => rest_url(),
95
+ 'restApiNonce' => wp_create_nonce('wp_rest'),
96
+ 'globalInterval' => $globSchedule,
97
+ 'globalTime' => wprss_get_global_update_time(),
98
+ 'globalWord' => __('Global', 'wprss'),
99
+ 'perPage' => 30,
100
+ 'schedules' => $schedules
101
+ ]);
102
+
103
+ wp_register_script('wpra-reset-tool', WPRSS_JS . 'admin/tools/reset.js', ['jquery'], $version, true);
104
+ wp_localize_script('wpra-reset-tool', 'WpraResetTool', [
105
+ 'message' => __('Are you sure you want to do this? This operation cannot be undone.', 'wprss')
106
+ ]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
 
 
 
109
 
110
+ add_action( 'admin_enqueue_scripts', 'wprss_admin_scripts_styles' );
111
+ /**
112
+ * Insert required scripts, styles and filters on the admin side
113
+ *
114
+ * @since 2.0
115
+ */
116
+ function wprss_admin_scripts_styles()
117
+ {
118
+ $isWpraScreen = wprss_is_wprss_page();
119
+ $screen = get_current_screen();
120
+ $pageBase = $screen->base;
121
+ $postType = $screen->post_type;
122
+ $page = isset( $_GET['page'] )? $_GET['page'] : '';
123
+ $version = wprss()->getVersion();
124
+
125
+ // On all admin screens
126
+ wp_enqueue_style( 'wprss-admin-editor-styles' );
127
+ wp_enqueue_style( 'wprss-admin-tracking-styles' );
128
+ wp_enqueue_style( 'wprss-admin-general-styles' );
129
+
130
+ // Only on WPRA-related admin screens
131
+ if ($isWpraScreen) {
132
+ wprss_admin_exclusive_scripts_styles();
133
+ }
134
+
135
+ do_action( 'wprss_admin_scripts_styles' );
136
+ } // end wprss_admin_scripts_styles
137
+
138
+ /**
139
+ * Enqueues backend scripts on WPRA-related pages only
140
+ *
141
+ * @since 4.10
142
+ */
143
+ function wprss_admin_exclusive_scripts_styles()
144
+ {
145
+ $screen = get_current_screen();
146
+ $pageBase = $screen->base;
147
+ $postType = $screen->post_type;
148
+ $page = isset( $_GET['page'] )? $_GET['page'] : '';
149
+ $version = wprss()->getVersion();
150
+
151
+ wp_enqueue_style( 'wprss-admin-styles' );
152
+ wp_enqueue_style( 'wprss-fa' );
153
+ wp_enqueue_style( 'wprss-admin-3.8-styles' );
154
+
155
+ wp_enqueue_script( 'wprss-xdn-class' );
156
+ wp_enqueue_script( 'wprss-xdn-lib' );
157
+ wp_enqueue_script( 'aventura' );
158
+
159
+ wp_enqueue_script( 'wprss-admin-addon-ajax' );
160
+
161
+ wp_enqueue_script( 'wprss-admin-custom' );
162
+
163
+ wp_enqueue_script( 'jquery-ui-timepicker-addon' );
164
+ wp_enqueue_style( 'jquery-style' );
165
+
166
+ if ($pageBase === 'post' && $postType = 'wprss_feed') {
167
+ // Change text on post screen from 'Enter title here' to 'Enter feed name here'
168
+ add_filter( 'enter_title_here', 'wprss_change_title_text' );
169
+ wp_enqueue_media();
170
+ wp_enqueue_script( 'wprss-gallery-js' );
171
+ }
172
+ if ('wprss_feed' === $postType) {
173
+ wp_enqueue_script( 'wprss-custom-bulk-actions' );
174
+ }
175
+ if ('wprss_feed_item' === $postType) {
176
+ wp_enqueue_script( 'wprss-custom-bulk-actions-feed-item' );
177
+ }
178
+
179
+ // Load Heartbeat script and set dependancy for Heartbeat to ensure Heartbeat is loaded
180
+ if ($pageBase === 'edit' && $postType === 'wprss_feed' && apply_filters('wprss_ajax_polling', TRUE) === TRUE ) {
181
+ wp_enqueue_script( 'wprss-feed-source-table-heartbeat' );
182
+ }
183
+
184
+ if ($pageBase === 'wprss_feed_page_wprss-aggregator-settings') {
185
+ wp_enqueue_script( 'wprss-admin-license-manager' );
186
+ wp_enqueue_script( 'wprss-admin-licensing' );
187
+ }
188
+
189
+ if ($pageBase === 'wprss_feed_page_wprss-help') {
190
+ wp_enqueue_script( 'wprss-admin-help' );
191
+ }
192
+
193
+ if ($pageBase === 'wprss_feed_page_wpra_tools') {
194
+ wp_enqueue_script('wpra-tools');
195
+ wp_enqueue_script('wpra-logs-tool');
196
+ wp_enqueue_script('wpra-blacklist-tool');
197
+ wp_enqueue_script('wpra-crons-tool');
198
+ wp_enqueue_script('wpra-reset-tool');
199
+ }
200
+
201
+ if (wprss_is_help_beacon_enabled()) {
202
+ wp_enqueue_script('wprss-hs-beacon-js');
203
+ wp_enqueue_style('wprss-hs-beacon-css');
204
+ }
205
+
206
+ do_action('wprss_admin_exclusive_scripts_styles');
207
  }
208
 
 
 
 
 
209
 
210
+ add_action( 'wp_enqueue_scripts', 'wprss_load_scripts' );
211
+ /**
212
+ * Enqueues the required scripts.
213
+ *
214
+ * @since 3.0
215
+ */
216
+ function wprss_load_scripts() {
217
+ /* wp_enqueue_script( 'jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', array( 'jquery' ) );
218
+ wp_enqueue_script( 'custom', WPRSS_JS . 'custom.js', array( 'jquery', 'jquery.colorbox-min' ) ); */
219
+ do_action( 'wprss_register_scripts' );
220
+ } // end wprss_head_scripts_styles
221
+
222
+
223
+ /**
224
+ * Returns the path to the WPRSS templates directory
225
+ *
226
+ * @since 3.0
227
+ * @return string
228
+ */
229
+ function wprss_get_templates_dir() {
230
+ return WPRSS_DIR . 'templates';
231
  }
232
 
 
 
 
233
 
234
+ /**
235
+ * Returns the URL to the WPRSS templates directory
236
+ *
237
+ * @since 3.0
238
+ * @return string
239
+ */
240
+ function wprss_get_templates_uri() {
241
+ return WPRSS_URI . 'templates';
242
  }
243
 
 
 
 
 
244
 
245
+ add_action( 'init', 'wprss_register_styles' );
246
+ /**
247
+ * Registers all WPRA styles.
248
+ *
249
+ * Does not enqueue anything.
250
+ *
251
+ * @since 3.0
252
+ */
253
+ function wprss_register_styles()
254
+ {
255
+ $version = wprss()->getVersion();
256
+
257
+ wp_register_style( 'wprss-admin-styles', WPRSS_CSS . 'admin-styles.css', array(), $version );
258
+ wp_register_style( 'wprss-fa', WPRSS_CSS . 'font-awesome.min.css', array(), $version );
259
+ wp_register_style( 'wprss-admin-3.8-styles', WPRSS_CSS . 'admin-3.8.css', array(), $version );
260
+ wp_register_style( 'wprss-admin-editor-styles', WPRSS_CSS . 'admin-editor.css', array(), $version );
261
+ wp_register_style( 'wprss-admin-tracking-styles', WPRSS_CSS . 'admin-tracking-styles.css', array(), $version );
262
+ wp_register_style( 'wprss-admin-general-styles', WPRSS_CSS . 'admin-general-styles.css', array(), $version );
263
+ wp_register_style( 'wprss-hs-beacon-css', WPRSS_CSS . 'beacon.css', array(), $version );
264
+ wp_register_style( 'jquery-style', 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css', array(), $version );
265
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/system-info.php CHANGED
@@ -42,30 +42,26 @@ HOME_URL: <?php echo home_url() . "\n"; ?>
42
  Plugin Version: <?php echo WPRSS_VERSION . "\n"; ?>
43
  WordPress Version: <?php echo get_bloginfo( 'version' ) . "\n"; ?>
44
 
45
- <?php echo htmlspecialchars((string) $browser) ; ?>
46
 
47
  PHP Version: <?php echo PHP_VERSION . "\n"; ?>
48
  MySQL Version: <?php $server_info = wprss_sysinfo_get_db_server();
49
  if ( $server_info ) {
50
  if (isset($server_info['warning'])) {
51
- printf(
52
- '%s - %s',
53
- htmlspecialchars($server_info['extension']),
54
- htmlspecialchars($server_info['warning'])
55
- );
56
  } else {
57
- printf(
58
  '%1$s (%2$s)',
59
- htmlspecialchars($server_info['server_info']),
60
- htmlspecialchars($server_info['extension'])
61
  );
62
  }
63
  } else {
64
- _e( 'Could not determine database driver version', 'wprss' );
65
  }
66
  ?>
67
 
68
- Web Server Info: <?php echo htmlspecialchars($_SERVER['SERVER_SOFTWARE']) . "\n"; ?>
69
 
70
  PHP Safe Mode: <?php if (version_compare(PHP_VERSION, '5.4', '>=')) {
71
  echo "No\n";
@@ -78,15 +74,7 @@ PHP Time Limit: <?php echo ini_get( 'max_execution_time' ) . "\n"; ?>
78
 
79
  WP_DEBUG: <?php echo defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' . "\n" : 'Disabled' . "\n" : 'Not set' . "\n" ?>
80
 
81
- WP Table Prefix: <?php
82
- $wpdbPrefixLen = strlen($wpdb->prefix);
83
- echo 'Length: ' . $wpdbPrefixLen;
84
- echo ' | Status: ';
85
- echo ($wpdbPrefixLen > 16)
86
- ? 'ERROR: Too Long'
87
- : 'Acceptable';
88
- echo "\n";
89
- ?>
90
 
91
  Show On Front: <?php echo get_option( 'show_on_front' ) . "\n" ?>
92
  Page On Front: <?php $id = get_option( 'page_on_front' ); echo get_the_title( $id ) . ' #' . $id . "\n" ?>
@@ -103,13 +91,13 @@ UPLOAD_MAX_FILESIZE: <?php if ( function_exists( 'phpversion' ) ) echo ( wp
103
  POST_MAX_SIZE: <?php if ( function_exists( 'phpversion' ) ) echo ( wprss_let_to_num( ini_get( 'post_max_size' ) )/( 1024*1024 ) )."MB"; ?><?php echo "\n"; ?>
104
  WordPress Memory Limit: <?php echo ( wprss_let_to_num( WP_MEMORY_LIMIT )/( 1024*1024 ) )."MB"; ?><?php echo "\n"; ?>
105
  DISPLAY ERRORS: <?php echo ( ini_get( 'display_errors' ) ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A'; ?><?php echo "\n"; ?>
106
- FSOCKOPEN: <?php echo ( function_exists( 'fsockopen' ) ) ? __( 'Your server supports fsockopen.', 'wprss' ) : __( 'Your server does not support fsockopen.', 'wprss' ); ?><?php echo "\n"; ?>
107
 
108
  PLUGIN MODULES:
109
 
110
  <?php
111
  foreach (wpra_modules() as $key => $module) {
112
- echo ' - ' . htmlspecialchars($key) . PHP_EOL;
113
  }
114
  ?>
115
 
@@ -117,19 +105,21 @@ ACTIVE PLUGINS:
117
 
118
  <?php
119
  $plugins = get_plugins();
120
- $active_plugins = get_option('active_plugins', []);
121
- $inactive_plugins = [];
122
- foreach ($plugins as $plugin_path => $plugin) {
123
  // If the plugin isn't active, don't show it.
124
- if (!in_array($plugin_path, $active_plugins)) {
125
  $inactive_plugins[] = $plugin;
126
  continue;
127
  }
128
 
129
- echo htmlspecialchars($plugin['Name']) . ': ' . htmlspecialchars($plugin['Version']) . "\n";
130
- }
131
 
132
- if (is_multisite()): ?>
 
 
 
133
 
134
  NETWORK ACTIVE PLUGINS:
135
 
@@ -147,7 +137,7 @@ foreach ( $plugins as $plugin_path ) {
147
 
148
  $plugin = get_plugin_data( $plugin_path );
149
 
150
- echo htmlspecialchars($plugin['Name']) . ': ' . htmlspecialchars($plugin['Version']) . "\n";
151
  }
152
 
153
  endif;
@@ -157,8 +147,8 @@ if ( !is_multisite() ) : ?>
157
  DEACTIVATED PLUGINS:
158
 
159
  <?php
160
- foreach ( $inactive_plugins as $plugin ) {
161
- echo htmlspecialchars($plugin['Name']) . ': ' . htmlspecialchars($plugin['Version']) . "\n";
162
  }
163
 
164
  endif;
@@ -167,8 +157,13 @@ endif;
167
  CURRENT THEME:
168
 
169
  <?php
170
- $theme_data = wp_get_theme();
171
- echo htmlspecialchars($theme_data->Name) . ': ' . htmlspecialchars($theme_data->Version);
 
 
 
 
 
172
  ?>
173
 
174
 
@@ -222,7 +217,7 @@ foreach ($extensions as $extension) {
222
 
223
  ### End System Info ###
224
  <?php
225
- }
226
 
227
 
228
  /**
@@ -237,7 +232,7 @@ foreach ($extensions as $extension) {
237
  * @param null|string $host The address of the database host, to which to connect.
238
  * May contain the port number in standard URI format.
239
  * Default: value of the DB_HOST constant, if defined, otherwise null.
240
- * @param null|string $username The username to be used for connecting to the database.
241
  * Default: value of the DB_USER constant, if defined, otherwise null.
242
  * @param null|string $password The password to be used for connecting to the database.
243
  * Default: value of the DB_PASSWORD constant, if defined, otherwise null.
@@ -267,5 +262,24 @@ function wprss_sysinfo_get_db_server( $host = null, $username = null, $password
267
  return $result;
268
  }
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  return null;
271
  }
42
  Plugin Version: <?php echo WPRSS_VERSION . "\n"; ?>
43
  WordPress Version: <?php echo get_bloginfo( 'version' ) . "\n"; ?>
44
 
45
+ <?php echo $browser ; ?>
46
 
47
  PHP Version: <?php echo PHP_VERSION . "\n"; ?>
48
  MySQL Version: <?php $server_info = wprss_sysinfo_get_db_server();
49
  if ( $server_info ) {
50
  if (isset($server_info['warning'])) {
51
+ echo $server_info['extension'] . ' - ' . $server_info['warning'];
 
 
 
 
52
  } else {
53
+ echo sprintf(
54
  '%1$s (%2$s)',
55
+ $server_info['server_info'],
56
+ $server_info['extension']
57
  );
58
  }
59
  } else {
60
+ _e( 'Could not determine database driver version', WPRSS_TEXT_DOMAIN );
61
  }
62
  ?>
63
 
64
+ Web Server Info: <?php echo $_SERVER['SERVER_SOFTWARE'] . "\n"; ?>
65
 
66
  PHP Safe Mode: <?php if (version_compare(PHP_VERSION, '5.4', '>=')) {
67
  echo "No\n";
74
 
75
  WP_DEBUG: <?php echo defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' . "\n" : 'Disabled' . "\n" : 'Not set' . "\n" ?>
76
 
77
+ WP Table Prefix: <?php echo "Length: ". strlen( $wpdb->prefix ); echo " Status:"; if ( strlen( $wpdb->prefix )>16 ) {echo " ERROR: Too Long";} else {echo " Acceptable";} echo "\n"; ?>
 
 
 
 
 
 
 
 
78
 
79
  Show On Front: <?php echo get_option( 'show_on_front' ) . "\n" ?>
80
  Page On Front: <?php $id = get_option( 'page_on_front' ); echo get_the_title( $id ) . ' #' . $id . "\n" ?>
91
  POST_MAX_SIZE: <?php if ( function_exists( 'phpversion' ) ) echo ( wprss_let_to_num( ini_get( 'post_max_size' ) )/( 1024*1024 ) )."MB"; ?><?php echo "\n"; ?>
92
  WordPress Memory Limit: <?php echo ( wprss_let_to_num( WP_MEMORY_LIMIT )/( 1024*1024 ) )."MB"; ?><?php echo "\n"; ?>
93
  DISPLAY ERRORS: <?php echo ( ini_get( 'display_errors' ) ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A'; ?><?php echo "\n"; ?>
94
+ FSOCKOPEN: <?php echo ( function_exists( 'fsockopen' ) ) ? __( 'Your server supports fsockopen.', WPRSS_TEXT_DOMAIN ) : __( 'Your server does not support fsockopen.', WPRSS_TEXT_DOMAIN ); ?><?php echo "\n"; ?>
95
 
96
  PLUGIN MODULES:
97
 
98
  <?php
99
  foreach (wpra_modules() as $key => $module) {
100
+ echo ' - ' . $key . PHP_EOL;
101
  }
102
  ?>
103
 
105
 
106
  <?php
107
  $plugins = get_plugins();
108
+ $active_plugins = get_option( 'active_plugins', array() );
109
+ $inactive_plugins = array();
110
+ foreach ( $plugins as $plugin_path => $plugin ):
111
  // If the plugin isn't active, don't show it.
112
+ if ( ! in_array( $plugin_path, $active_plugins ) ) {
113
  $inactive_plugins[] = $plugin;
114
  continue;
115
  }
116
 
117
+ echo $plugin['Name']; ?>: <?php echo $plugin['Version'] ."\n";
 
118
 
119
+ endforeach;
120
+
121
+ if ( is_multisite() ) :
122
+ ?>
123
 
124
  NETWORK ACTIVE PLUGINS:
125
 
137
 
138
  $plugin = get_plugin_data( $plugin_path );
139
 
140
+ echo $plugin['Name'] . ': ' . $plugin['Version'] ."\n";
141
  }
142
 
143
  endif;
147
  DEACTIVATED PLUGINS:
148
 
149
  <?php
150
+ foreach ( $inactive_plugins as $inactive_plugin ) {
151
+ echo $inactive_plugin['Name']; ?>: <?php echo $inactive_plugin['Version'] . "\n";
152
  }
153
 
154
  endif;
157
  CURRENT THEME:
158
 
159
  <?php
160
+ if ( get_bloginfo( 'version' ) < '3.4' ) {
161
+ $theme_data = get_theme_data( get_stylesheet_directory() . '/style.css' );
162
+ echo $theme_data['Name'] . ': ' . $theme_data['Version'];
163
+ } else {
164
+ $theme_data = wp_get_theme();
165
+ echo $theme_data->Name . ': ' . $theme_data->Version;
166
+ }
167
  ?>
168
 
169
 
217
 
218
  ### End System Info ###
219
  <?php
220
+ }
221
 
222
 
223
  /**
232
  * @param null|string $host The address of the database host, to which to connect.
233
  * May contain the port number in standard URI format.
234
  * Default: value of the DB_HOST constant, if defined, otherwise null.
235
+ * @param null|string $username The username to be used for connecting to the databse.
236
  * Default: value of the DB_USER constant, if defined, otherwise null.
237
  * @param null|string $password The password to be used for connecting to the database.
238
  * Default: value of the DB_PASSWORD constant, if defined, otherwise null.
262
  return $result;
263
  }
264
 
265
+ if ( function_exists( 'mysql_connect' ) ) {
266
+ if (version_compare(PHP_VERSION, '7.0', '>=')) {
267
+ $result['warning'] = __(
268
+ 'The mysql extension is deprecated since PHP 5.5 and removed since PHP 7.0; Use mysqli instead',
269
+ 'wprss'
270
+ );
271
+ $result['extension'] = 'mysql';
272
+ $result['server_info'] = '';
273
+ return $result;
274
+ }
275
+
276
+ if ( $port ) $host = implode ( ':', array( $host, $port ) );
277
+
278
+ $mysql = mysql_connect( $host, $username, $password );
279
+ $result['extension'] = 'mysql';
280
+ $result['server_info'] = mysql_get_server_info( $mysql );
281
+ return $result;
282
+ }
283
+
284
  return null;
285
  }
includes/templates-update.php DELETED
@@ -1,15 +0,0 @@
1
- <?php
2
-
3
- define('WPRA_TMP_0_2_BASENAME', 'wp-rss-templates-0.2/wp-rss-templates.php');
4
- define('WPRA_TMP_PROPER_BASENAME', 'wp-rss-templates/wp-rss-templates.php');
5
-
6
- add_action('update_option_active_plugins', function ($oldValue, $newValue) {
7
- $oldPlugins = array_flip($oldValue);
8
- $newPlugins = array_flip($newValue);
9
-
10
- if (isset($oldPlugins[WPRA_TMP_0_2_BASENAME]) && !isset($newPlugins[WPRA_TMP_0_2_BASENAME])) {
11
- if (file_exists(WP_PLUGIN_DIR . '/' . WPRA_TMP_PROPER_BASENAME)) {
12
- activate_plugin(WPRA_TMP_PROPER_BASENAME);
13
- }
14
- }
15
- }, 10, 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/update.php CHANGED
@@ -64,9 +64,9 @@
64
 
65
  // NO FOLLOW CHANGE FIX
66
  $options = get_option( 'wprss_settings_general' );
67
- if ( $options['follow_dd'] === __( "No Follow", 'wprss' ) ) {
68
  $options['follow_dd'] = 'no_follow';
69
- } elseif ( $options['follow_dd'] === __( "Follow", 'wprss' ) ) {
70
  $options['follow_dd'] = 'follow';
71
  }
72
  }
@@ -128,11 +128,11 @@
128
  // Open Link Behavior Name Fix
129
  $settings = get_option( 'wprss_settings_general' );
130
 
131
- if( $settings['open_dd'] === 'New window' || $settings['open_dd'] === __( 'New window', 'wprss' ) ){
132
  $settings['open_dd'] = 'blank';
133
- }else if( $settings['open_dd'] === 'Lightbox' || $settings['open_dd'] === __( 'Lightbox', 'wprss' ) ){
134
  $settings['open_dd'] = 'lightbox';
135
- }else if( $settings['open_dd'] === 'Self' || $settings['open_dd'] === __( 'Self', 'wprss' ) ){
136
  $settings['open_dd'] = 'self';
137
  }
138
 
64
 
65
  // NO FOLLOW CHANGE FIX
66
  $options = get_option( 'wprss_settings_general' );
67
+ if ( $options['follow_dd'] === __( "No Follow", WPRSS_TEXT_DOMAIN ) ) {
68
  $options['follow_dd'] = 'no_follow';
69
+ } elseif ( $options['follow_dd'] === __( "Follow", WPRSS_TEXT_DOMAIN ) ) {
70
  $options['follow_dd'] = 'follow';
71
  }
72
  }
128
  // Open Link Behavior Name Fix
129
  $settings = get_option( 'wprss_settings_general' );
130
 
131
+ if( $settings['open_dd'] === 'New window' || $settings['open_dd'] === __( 'New window', WPRSS_TEXT_DOMAIN ) ){
132
  $settings['open_dd'] = 'blank';
133
+ }else if( $settings['open_dd'] === 'Lightbox' || $settings['open_dd'] === __( 'Lightbox', WPRSS_TEXT_DOMAIN ) ){
134
  $settings['open_dd'] = 'lightbox';
135
+ }else if( $settings['open_dd'] === 'Self' || $settings['open_dd'] === __( 'Self', WPRSS_TEXT_DOMAIN ) ){
136
  $settings['open_dd'] = 'self';
137
  }
138
 
js/admin-addon-ajax.js CHANGED
@@ -12,7 +12,6 @@ jQuery( document ).ready( function($) {
12
  action: 'wprss_dismiss_addon_notice',
13
  addon: addon,
14
  notice: notice,
15
- nonce: wprss_admin_addon_ajax.nonce,
16
  },
17
  success: function( data, status, jqXHR) {
18
  if ( data === 'true' ) {
@@ -26,4 +25,4 @@ jQuery( document ).ready( function($) {
26
  }
27
  });
28
 
29
- });
12
  action: 'wprss_dismiss_addon_notice',
13
  addon: addon,
14
  notice: notice,
 
15
  },
16
  success: function( data, status, jqXHR) {
17
  if ( data === 'true' ) {
25
  }
26
  });
27
 
28
+ });
js/admin-custom-bulk-actions.js CHANGED
File without changes
js/admin-custom.js CHANGED
@@ -160,7 +160,8 @@ function toggle_feed_state_ajax_callback(e) {
160
 
161
 
162
 
163
- jQuery(window).on('load', function() {
 
164
 
165
  function wprssParseDate(str){
166
  var t = str.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
@@ -284,7 +285,7 @@ jQuery(window).on('load', function() {
284
  * WP-like collapsing settings in metabox
285
  */
286
  (function($, wprss_admin_custom){
287
- $(window).on('load', function() {
288
 
289
  // Adds the Bulk Add button
290
  $('<a>').text( wprss_admin_custom.bulk_add ).attr('href', wprss_urls.import_export).addClass('add-new-h2').insertAfter( $('.add-new-h2') );
@@ -442,7 +443,7 @@ if ( !String.prototype.trim ) {
442
 
443
  // For add-ons page
444
  (function($) {
445
- $(window).on('load', function() {
446
  $('#add-ons .add-on-group').each(function(){
447
  var $el = $(this),
448
  h = 0;
@@ -491,7 +492,7 @@ if ( !String.prototype.trim ) {
491
  linkEl.text(linkEl.text() + ' (' + count + ')')
492
 
493
  // If there are no logs for this filter, disable it
494
- if (count === 0) {
495
  filterEl.addClass('wpra-log-filter-disabled');
496
  return;
497
  }
160
 
161
 
162
 
163
+ jQuery(window).load( function(){
164
+
165
 
166
  function wprssParseDate(str){
167
  var t = str.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
285
  * WP-like collapsing settings in metabox
286
  */
287
  (function($, wprss_admin_custom){
288
+ $(window).load( function(){
289
 
290
  // Adds the Bulk Add button
291
  $('<a>').text( wprss_admin_custom.bulk_add ).attr('href', wprss_urls.import_export).addClass('add-new-h2').insertAfter( $('.add-new-h2') );
443
 
444
  // For add-ons page
445
  (function($) {
446
+ $(window).load(function(){
447
  $('#add-ons .add-on-group').each(function(){
448
  var $el = $(this),
449
  h = 0;
492
  linkEl.text(linkEl.text() + ' (' + count + ')')
493
 
494
  // If there are no logs for this filter, disable it
495
+ if (count == 0) {
496
  filterEl.addClass('wpra-log-filter-disabled');
497
  return;
498
  }
js/admin-help.js CHANGED
File without changes
js/admin-license-manager.js CHANGED
File without changes
js/admin-licensing.js CHANGED
File without changes
js/admin/tools/crons.js CHANGED
@@ -134,7 +134,7 @@
134
  page = (page === null || page === undefined) ? Store.page : page;
135
 
136
  $.ajax({
137
- url: Config.restUrl + 'wpra/v1/sources',
138
  method: 'GET',
139
  data: {
140
  num: Config.perPage,
134
  page = (page === null || page === undefined) ? Store.page : page;
135
 
136
  $.ajax({
137
+ url: Config.restUrl + '/wpra/v1/sources',
138
  method: 'GET',
139
  data: {
140
  num: Config.perPage,
js/admin/tools/logs.js CHANGED
@@ -1,3 +1,11 @@
1
  (function ($) {
2
 
 
 
 
 
 
 
 
 
3
  })(jQuery);
1
  (function ($) {
2
 
3
+ $(document).ready(function () {
4
+ // Toggle the log options when the "Show options" link is clicked
5
+ $('#wprss-error-log-options-link').click(function (e) {
6
+ $('#wprss-error-log-options').slideToggle(200);
7
+ e.preventDefault();
8
+ });
9
+ });
10
+
11
  })(jQuery);
js/build/common.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.WPRA=o():e.WPRA=o()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([6],{52:function(e,o){}},[52])});
1
+ !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.WPRA=o():e.WPRA=o()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([6],{53:function(e,o){}},[53])});
js/build/intro.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([2],{16:function(e,t,i){"use strict";function n(e,t){for(var i=(arguments.length>2&&void 0!==arguments[2]&&arguments[2],new FormData),n=Object.keys(t),s=Array.isArray(n),r=0,n=s?n:n[Symbol.iterator]();;){var a;if(s){if(r>=n.length)break;a=n[r++]}else{if(r=n.next(),r.done)break;a=r.value}var o=a;i.set(o,t[o])}return fetch(e,{method:"post",body:i}).then(function(e){return e.json()}).then(function(e){if(200!==e.status)throw e;return e})}Object.defineProperty(t,"__esModule",{value:!0});var s=i(4),r=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"wizard-holder animated fadeIn"},[i("div",{staticClass:"connect-steps"},[i("div",{staticClass:"step-items"},[i("div",{staticClass:"step-progress",class:"step-progress--"+e.activeScreenIndex}),e._v(" "),e._l(e.screens,function(t,n){return i("div",{staticClass:"step-item",class:{"step-item_active":e.active(t.id),"step-item_completed":t.completed()&&n<e.activeScreenIndex}},[i("div",{staticClass:"step-item__status"},[t.completed()&&n<e.activeScreenIndex?i("span",{staticClass:"dashicons dashicons-yes"}):e._e()]),e._v(" "),i("div",{staticClass:"step-item__info"},[i("div",{staticClass:"step-item__title"},[e._v(e._s(t.title))]),e._v(" "),t.description?i("div",{staticClass:"step-item__description"},[e._v(e._s(t.description))]):e._e()])])})],2)]),e._v(" "),i("div",{staticClass:"wizard"},[i("transition",{attrs:{name:e.transition,mode:"out-in"}},[e.active("feed")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n Enter your first RSS Feed URL\n ")]),e._v(" "),i("form",{staticClass:"wizard_info",attrs:{id:"feedForm"},on:{submit:function(t){return t.preventDefault(),e.next.apply(null,arguments)}}},[i("div",{staticClass:"form-group"},[i("input",{directives:[{name:"model",rawName:"v-model",value:e.form.feedSourceUrl,expression:"form.feedSourceUrl"}],staticClass:"wpra-feed-input",attrs:{type:"text",placeholder:"https://www.sourcedomain.com/feed/"},domProps:{value:e.form.feedSourceUrl},on:{input:function(t){t.target.composing||e.$set(e.form,"feedSourceUrl",t.target.value)}}}),e._v(" "),e.isFeedError?i("span",{staticClass:"dashicons dashicons-warning warning-icon"}):e._e(),e._v(" "),e.isFeedError?i("a",{attrs:{href:e.validateLink,target:"_blank"}},[e._v("Validate feed")]):e._e()])]),e._v(" "),e.isFeedError?i("div",{staticClass:"wizard_error"},[i("p",[e._v("This RSS feed URL appears to be invalid. Here are a couple of things you can try:")]),e._v(" "),i("ol",[i("li",[e._v('Check whether the URL you entered is the correct one by trying one of the options when clicking on "How do I find an RSS feed URL?" below.')]),e._v(" "),i("li",[e._v("\n Test out this other RSS feed URL to make sure the plugin is working correctly - https://www.wpmayor.com/feed/ - If it works, you may "),i("a",{attrs:{href:e.supportUrl,target:"_blank"}},[e._v("contact us here")]),e._v(" to help you with your source.\n ")]),e._v(" "),i("li",[e._v("Test the URL's validity by W3C standards, the standards we use in our plugins, using the “Validate feed” link above.")])])]):e._e(),e._v(" "),i("expander",{attrs:{title:"How do I find an RSS feed URL?"}},[i("p",[e._v("WP RSS Aggregator fetches feed items through RSS feeds. Almost every website in the world provides an RSS feed. Here's how to find it:")]),e._v(" "),i("p",[e._v("Option 1: Add /feed to the website's homepage URL ")]),e._v(" "),i("p",[e._v("Many sites have their RSS feed at the same URL. For instance, if the website's URL is www.thiswebsite.com, then the RSS feed could be at www.thiswebsite.com/feed.")]),e._v(" "),i("p",[e._v("Option 2: Look for the RSS share icon")]),e._v(" "),i("p",[e._v("Many websites have share icons on their pages for Facebook, Twitter and more. Many times, there will also be an orange RSS icon. Click on that to access the RSS feed URL.")]),e._v(" "),i("p",[e._v("Option 3: Browser RSS Auto-Discovery")]),e._v(" "),i("p",[e._v("Most browsers either include an RSS auto-discovery tool by default or they allow you to add extensions for it. Firefox shows an RSS icon above the website, in the address bar, which you can click on directly. Chrome offers extensions such as this one.")]),e._v(" "),i("p",[e._v("Option 4: Look at the Page Source")]),e._v(" "),i("p",[e._v('When on any page of the website you\'re looking to import feed items from, right click and press "View Page Source". Once the new window opens, use the “Find” feature (Ctrl-F on PC, Command-F on Mac) and search for " RSS". This should take you to a line that reads like this (or similar):')]),e._v(" "),i("p",[i("code",[e._v('\n <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="https://www.sourcedomain.com/feed/" />\n ')])]),e._v(" "),i("p",[e._v("The RSS feed’s URL is found between the quotes after href=. In the above case, it would be https://www.sourcedomain.com/feed/.")]),e._v(" "),i("p",[i("a",{attrs:{href:e.knowledgeBaseUrl,target:"_blank"}},[e._v("Browse our Knowledge Base for more information.")])])])],1):e._e(),e._v(" "),e.active("feedItems")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n Latest feed items from your selected feed source:\n ")]),e._v(" "),i("div",{staticClass:"wpra-feed-items"},e._l(e.feed.items,function(t){return i("div",{staticClass:"wpra-feed-item"},[i("div",{staticClass:"wpra-feed-item__link"},[i("a",{attrs:{href:t.permalink,target:"_blank"}},[e._v(e._s(t.title))])]),e._v(" "),i("div",{staticClass:"wpra-feed-item__info"},[t.date||t.author?[t.date?[e._v("\n Published on "+e._s(t.date)+"\n ")]:e._e(),e._v(" "),t.date&&t.author?[e._v("|")]:e._e(),e._v(" "),t.author?[e._v("\n By "+e._s(t.author)+"\n ")]:e._e()]:e._e()],2)])}),0),e._v(" "),i("div",{staticClass:"wrpa-shortcode"},[i("div",{staticClass:"wrpa-shortcode-preview"},[i("div",{staticClass:"wrpa-shortcode-label"},[e._v("\n Create a draft page to preview these feed items on your site:\n ")]),e._v(" "),i("a",{staticClass:"button",class:{"button-primary":e.isPrepared,"loading-button":e.isPreparing},attrs:{href:e.previewUrl,target:"_blank"},on:{click:e.preparePreview}},[e._v("\n "+e._s(e.isPrepared?"Preview the Page":"Create Draft Page")+"\n ")])]),e._v(" "),i("div",{staticClass:"wrpa-shortcode-form",on:{click:function(t){return e.copyToClipboard()}}},[i("div",{staticClass:"wrpa-shortcode-label"},[e._v("\n Copy the shortcode to any page or post on your site:\n ")]),e._v(" "),i("input",{ref:"selected",staticClass:"wrpa-shortcode-form__shortcode",attrs:{type:"text",readonly:"",value:"[wp-rss-aggregator]"}}),e._v(" "),i("div",{staticClass:"wrpa-shortcode-form__button"},[e._v("\n "+e._s(e.isCopied?"Copied!":"Click to copy")+"\n ")])])])]):e._e(),e._v(" "),e.active("finish")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n That's it! Your first feed source is ready to go.\n ")]),e._v(" "),i("div",{staticClass:"wpra-cols-title"},[e._v("\n Do more with your content. Here's what Erik Tozier is doing on Personal Finance Blogs.\n ")]),e._v(" "),i("div",{staticClass:"wpra-cols"},[i("div",{staticClass:"col"},[i("p",[e._v("\n Erik created Personal Finance Blogs in 2019 and grew it rapidly in just a few months\n purely by curating content from the personal finance space.\n ")]),e._v(" "),i("p",[e._v("\n The flexibility of the "),i("a",{attrs:{href:e.proPlanUrl}},[e._v("WP RSS Aggregator Pro Plan")]),e._v(" gave Erik\n greater visual customization to keep his readers engaged, with Keyword Filtering\n helping to control the quality of the content.\n ")]),e._v(" "),i("p",[e._v('\n Erik was also quoted as saying that "the support has been great", which is something we\n pride ourselves on at WP RSS Aggregator.\n ')]),e._v(" "),i("div",{staticStyle:{"margin-bottom":".5rem"}},[i("a",{staticClass:"button",attrs:{href:e.proPlanCtaUrl,target:"_blank"}},[e._v("\n Check out our Pro Plan\n ")])]),e._v(" "),i("div",[i("a",{staticStyle:{"font-size":".9em"},attrs:{href:e.supportUrl,target:"_blank"}},[e._v("Contact support for more information.")])])]),e._v(" "),i("div",{staticClass:"col"},[i("img",{staticClass:"img wpra-demo-photo",attrs:{src:e.demoImageUrl}}),e._v(" "),i("div",{staticClass:"wpra-feedback"},[i("div",{staticClass:"wpra-feedback__copy"},[i("div",{staticClass:"wpra-feedback__text"},[e._v("\n We’ve seen some strong traffic growth month over month. And so yeah, we’re up to over 10,000 page views a month – which is great for a new blog.\n ")]),e._v(" "),i("div",{staticClass:"wpra-feedback__rating"},[i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"})]),e._v(" "),i("div",{staticClass:"wpra-feedback__by"},[i("a",{attrs:{href:e.caseStudyUrl,target:"_blank"}},[e._v("\n Erik Tozier - Read the full case study\n ")])])])])])])]):e._e()]),e._v(" "),i("div",{staticClass:"connect-actions pad"},[i("div",{staticClass:"pad-item--grow"},[e.active("finish")?e._e():i("button",{staticClass:"button-clear",on:{click:e.finish}},[e._v("\n Skip the introduction\n ")])]),e._v(" "),i("div",{staticClass:"pad-item--no-shrink"},[e.isBackAvailable?i("button",{staticClass:"button-clear",on:{click:e.back}},[e._v("\n Back\n ")]):e._e(),e._v(" "),i("button",{staticClass:"button button-primary button-large",class:{"loading-button":e.isLoading},on:{click:e.next}},[e._v("\n "+e._s(e.active("finish")?"Continue to Plugin":"Next")+"\n ")])])])],1)])},a=[],o=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"wpra-expander",class:{"wpra-expander--expanded":e.isExpanded}},[i("div",{staticClass:"wpra-expander__title",on:{click:function(t){e.isExpanded=!e.isExpanded}}},[e._v("\n "+e._s(e.title)+"\n "),i("span",{staticClass:"dashicons dashicons-arrow-down-alt2"})]),e._v(" "),i("transition-expand",[e.isExpanded?i("div",[i("div",{staticClass:"wpra-expander__content"},[e._t("default")],2)]):e._e()])],1)},c=[],d=i(5),l={data:function(){return{isExpanded:this.defaultExpanded}},props:{title:{},defaultExpanded:{value:!1}},components:{TransitionExpand:d.a}},u=l,p=i(1),h=Object(p.a)(u,o,c,!1,null,null,null),v=h.exports,f=i(6),_=function(e){return e},m=window.wprssWizardConfig,w={data:function(){var e=this;return{prevHeight:0,screens:[{id:"feed",title:_("Add feed source URL"),description:!1,next:this.submitFeed,completed:function(){return e.feed.items.length},entered:function(){e.focusOnInput("feed")}},{id:"feedItems",title:_("Display feed items"),description:!1,next:this.continueItems,completed:function(){return e.feed.items.length&&e.itemsPassed}},{id:"finish",title:_("All done!"),description:!1,next:this.completeIntroduction,completed:function(){return e.feed.items.length&&e.itemsPassed}}],isCopied:!1,isPreparing:!1,isPrepared:!1,transition:"slide-up",activeScreen:"feed",form:{feedSourceUrl:null},itemsPassed:!1,stepLoading:!1,isLoading:!1,isFeedError:!1,feed:{items:[]},previewUrl:m.previewUrl,proPlanUrl:m.proPlanUrl,proPlanCtaUrl:m.proPlanCtaUrl,addOnsUrl:m.addOnsUrl,supportUrl:m.supportUrl,demoImageUrl:m.demoImageUrl,caseStudyUrl:m.caseStudyUrl,knowledgeBaseUrl:m.knowledgeBaseUrl}},computed:{validateLink:function(){return"https://validator.w3.org/feed/check.cgi?url="+encodeURI(this.form.feedSourceUrl)},activeScreenIndex:function(){var e=this;return this.screens.findIndex(function(t){return t.id===e.activeScreen})},currentScreen:function(){var e=this;return this.screens.find(function(t){return t.id===e.activeScreen})},actionCompleted:function(){return this.currentScreen.completed()},isBackAvailable:function(){return this.activeScreenIndex>0&&this.activeScreenIndex<this.screens.length}},mounted:function(){this.onScreenEnter()},methods:{preparePreview:function(e){var t=this;if(this.isPreparing)return void e.preventDefault();this.isPrepared||(e.preventDefault(),this.isPreparing=!0,fetch(this.previewUrl).then(function(){t.isPreparing=!1,t.isPrepared=!0}))},submitFeed:function(){var e=this,t=Object.assign(m.feedEndpoint.defaultPayload,{wprss_intro_feed_url:this.form.feedSourceUrl});return this.isLoading=!0,this.isFeedError=!1,n(m.feedEndpoint.url,t).then(function(t){return e.feed.items=t.data.feed_items.slice(0,3),e.isLoading=!1,{}}).catch(function(t){throw e.isLoading=!1,e.isFeedError=!0,t})},continueItems:function(){return this.itemsPassed=!0,Promise.resolve({})},completeIntroduction:function(){return Promise.resolve({})},next:function(){var e=this;this.transition="slide-up";var t=this.currentScreen.next?this.currentScreen.next:function(){return Promise.resolve(!1)};this.stepLoading=!0,t().then(function(t){e.stepLoading=!1},function(e){throw e}).then(function(){var t=e.activeScreenIndex+1;t>=e.screens.length?e.finish():(e.activeScreen=e.screens[t].id,e.onScreenEnter())}).catch(function(e){console.error(e)})},onScreenEnter:function(){var e=this;this.$nextTick(function(){e.currentScreen.entered&&e.currentScreen.entered()})},focusOnInput:function(e){if(!this.$refs[e]||!this.$refs[e].focus)return!1;this.$refs[e].focus()},back:function(){this.transition="slide-down",this.activeScreen=this.screens[this.activeScreenIndex-1].id},finish:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=function(){return window.location.href=m.feedListUrl};if(e)return void(confirm("Are you sure you want to skip the introduction?")&&t());t()},active:function(e){return this.activeScreen===e},copyToClipboard:function(){var e=this;this.isCopied||(Object(f.a)("[wp-rss-aggregator]"),this.isCopied=!0,setTimeout(function(){e.isCopied=!1},1e3))}},components:{Expander:v}},g=w,y=Object(p.a)(g,r,a,!1,null,null,null),C=y.exports;i(20),i(17),new s.a({el:"#wpra-wizard-app",template:"<Wizard/>",components:{Wizard:C}})},17:function(e,t){},5:function(e,t,i){"use strict";var n={name:"TransitionExpand",functional:!0,render:function(e,t){return e("transition",{props:{name:"expand"},on:{afterEnter:function(e){e.style.height="auto"},enter:function(e){var t=getComputedStyle(e),i=t.width;e.style.width=i,e.style.position="absolute",e.style.visibility="hidden",e.style.height="auto";var n=getComputedStyle(e),s=n.height;e.style.width=null,e.style.position=null,e.style.visibility=null,e.style.height=0,getComputedStyle(e).height,setTimeout(function(){e.style.height=s})},leave:function(e){var t=getComputedStyle(e),i=t.height;e.style.height=i,getComputedStyle(e).height,setTimeout(function(){e.style.height=0})}}},t.children)}},s=n,r=i(1),a=Object(r.a)(s,void 0,void 0,!1,null,null,null);t.a=a.exports},6:function(e,t,i){"use strict";function n(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!navigator.clipboard)return void s(e,t);navigator.clipboard.writeText(e).then(function(){},function(e){console.error("Async: Could not copy text: ",e)})}t.a=n;var s=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;t=t||document.body.parentElement;var i=document.createElement("textarea");i.value=e;var n=t.scrollTop;document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy")}catch(e){console.error("Fallback: Oops, unable to copy",e)}document.body.removeChild(i),t.scrollTop=n}}},[16])});
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([2],{16:function(e,t,i){"use strict";function n(e,t){for(var i=(arguments.length>2&&void 0!==arguments[2]&&arguments[2],new FormData),n=Object.keys(t),s=Array.isArray(n),r=0,n=s?n:n[Symbol.iterator]();;){var a;if(s){if(r>=n.length)break;a=n[r++]}else{if(r=n.next(),r.done)break;a=r.value}var o=a;i.set(o,t[o])}return fetch(e,{method:"post",body:i}).then(function(e){return e.json()}).then(function(e){if(200!==e.status)throw e;return e})}Object.defineProperty(t,"__esModule",{value:!0});var s=i(4),r=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"wizard-holder animated fadeIn"},[i("div",{staticClass:"connect-steps"},[i("div",{staticClass:"step-items"},[i("div",{staticClass:"step-progress",class:"step-progress--"+e.activeScreenIndex}),e._v(" "),e._l(e.screens,function(t,n){return i("div",{staticClass:"step-item",class:{"step-item_active":e.active(t.id),"step-item_completed":t.completed()&&n<e.activeScreenIndex}},[i("div",{staticClass:"step-item__status"},[t.completed()&&n<e.activeScreenIndex?i("span",{staticClass:"dashicons dashicons-yes"}):e._e()]),e._v(" "),i("div",{staticClass:"step-item__info"},[i("div",{staticClass:"step-item__title"},[e._v(e._s(t.title))]),e._v(" "),t.description?i("div",{staticClass:"step-item__description"},[e._v(e._s(t.description))]):e._e()])])})],2)]),e._v(" "),i("div",{staticClass:"wizard"},[i("transition",{attrs:{name:e.transition,mode:"out-in"}},[e.active("feed")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n Enter your first RSS Feed URL\n ")]),e._v(" "),i("form",{staticClass:"wizard_info",attrs:{id:"feedForm"},on:{submit:function(t){return t.preventDefault(),e.next(t)}}},[i("div",{staticClass:"form-group"},[i("input",{directives:[{name:"model",rawName:"v-model",value:e.form.feedSourceUrl,expression:"form.feedSourceUrl"}],staticClass:"wpra-feed-input",attrs:{type:"text",placeholder:"https://www.sourcedomain.com/feed/"},domProps:{value:e.form.feedSourceUrl},on:{input:function(t){t.target.composing||e.$set(e.form,"feedSourceUrl",t.target.value)}}}),e._v(" "),e.isFeedError?i("span",{staticClass:"dashicons dashicons-warning warning-icon"}):e._e(),e._v(" "),e.isFeedError?i("a",{attrs:{href:e.validateLink,target:"_blank"}},[e._v("Validate feed")]):e._e()])]),e._v(" "),e.isFeedError?i("div",{staticClass:"wizard_error"},[i("p",[e._v("This RSS feed URL appears to be invalid. Here are a couple of things you can try:")]),e._v(" "),i("ol",[i("li",[e._v('Check whether the URL you entered is the correct one by trying one of the options when clicking on "How do I find an RSS feed URL?" below.')]),e._v(" "),i("li",[e._v("\n Test out this other RSS feed URL to make sure the plugin is working correctly - https://www.wpmayor.com/feed/ - If it works, you may "),i("a",{attrs:{href:e.supportUrl,target:"_blank"}},[e._v("contact us here")]),e._v(" to help you with your source.\n ")]),e._v(" "),i("li",[e._v("Test the URL's validity by W3C standards, the standards we use in our plugins, using the “Validate feed” link above.")])])]):e._e(),e._v(" "),i("expander",{attrs:{title:"How do I find an RSS feed URL?"}},[i("p",[e._v("WP RSS Aggregator fetches feed items through RSS feeds. Almost every website in the world provides an RSS feed. Here's how to find it:")]),e._v(" "),i("p",[e._v("Option 1: Add /feed to the website's homepage URL ")]),e._v(" "),i("p",[e._v("Many sites have their RSS feed at the same URL. For instance, if the website's URL is www.thiswebsite.com, then the RSS feed could be at www.thiswebsite.com/feed.")]),e._v(" "),i("p",[e._v("Option 2: Look for the RSS share icon")]),e._v(" "),i("p",[e._v("Many websites have share icons on their pages for Facebook, Twitter and more. Many times, there will also be an orange RSS icon. Click on that to access the RSS feed URL.")]),e._v(" "),i("p",[e._v("Option 3: Browser RSS Auto-Discovery")]),e._v(" "),i("p",[e._v("Most browsers either include an RSS auto-discovery tool by default or they allow you to add extensions for it. Firefox shows an RSS icon above the website, in the address bar, which you can click on directly. Chrome offers extensions such as this one.")]),e._v(" "),i("p",[e._v("Option 4: Look at the Page Source")]),e._v(" "),i("p",[e._v('When on any page of the website you\'re looking to import feed items from, right click and press "View Page Source". Once the new window opens, use the “Find” feature (Ctrl-F on PC, Command-F on Mac) and search for " RSS". This should take you to a line that reads like this (or similar):')]),e._v(" "),i("p",[i("code",[e._v('\n <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="https://www.sourcedomain.com/feed/" />\n ')])]),e._v(" "),i("p",[e._v("The RSS feed’s URL is found between the quotes after href=. In the above case, it would be https://www.sourcedomain.com/feed/.")]),e._v(" "),i("p",[i("a",{attrs:{href:e.knowledgeBaseUrl,target:"_blank"}},[e._v("Browse our Knowledge Base for more information.")])])])],1):e._e(),e._v(" "),e.active("feedItems")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n Latest feed items from your selected feed source:\n ")]),e._v(" "),i("div",{staticClass:"wpra-feed-items"},e._l(e.feed.items,function(t){return i("div",{staticClass:"wpra-feed-item"},[i("div",{staticClass:"wpra-feed-item__link"},[i("a",{attrs:{href:t.permalink,target:"_blank"}},[e._v(e._s(t.title))])]),e._v(" "),i("div",{staticClass:"wpra-feed-item__info"},[t.date||t.author?[t.date?[e._v("\n Published on "+e._s(t.date)+"\n ")]:e._e(),e._v(" "),t.date&&t.author?[e._v("|")]:e._e(),e._v(" "),t.author?[e._v("\n By "+e._s(t.author)+"\n ")]:e._e()]:e._e()],2)])}),0),e._v(" "),i("div",{staticClass:"wrpa-shortcode"},[i("div",{staticClass:"wrpa-shortcode-preview"},[i("div",{staticClass:"wrpa-shortcode-label"},[e._v("\n Create a draft page to preview these feed items on your site:\n ")]),e._v(" "),i("a",{staticClass:"button",class:{"button-primary":e.isPrepared,"loading-button":e.isPreparing},attrs:{href:e.previewUrl,target:"_blank"},on:{click:e.preparePreview}},[e._v("\n "+e._s(e.isPrepared?"Preview the Page":"Create Draft Page")+"\n ")])]),e._v(" "),i("div",{staticClass:"wrpa-shortcode-form",on:{click:function(t){e.copyToClipboard()}}},[i("div",{staticClass:"wrpa-shortcode-label"},[e._v("\n Copy the shortcode to any page or post on your site:\n ")]),e._v(" "),i("input",{ref:"selected",staticClass:"wrpa-shortcode-form__shortcode",attrs:{type:"text",readonly:"",value:"[wp-rss-aggregator]"}}),e._v(" "),i("div",{staticClass:"wrpa-shortcode-form__button"},[e._v("\n "+e._s(e.isCopied?"Copied!":"Click to copy")+"\n ")])])])]):e._e(),e._v(" "),e.active("finish")?i("div",{key:e.activeScreen,staticClass:"wizard_content"},[i("div",{staticClass:"wizard_hello"},[e._v("\n That's it! Your first feed source is ready to go.\n ")]),e._v(" "),i("div",{staticClass:"wpra-cols-title"},[e._v("\n Do more with your content. Here's what Erik Tozier is doing on Personal Finance Blogs.\n ")]),e._v(" "),i("div",{staticClass:"wpra-cols"},[i("div",{staticClass:"col"},[i("p",[e._v("\n Erik created Personal Finance Blogs in 2019 and grew it rapidly in just a few months\n purely by curating content from the personal finance space.\n ")]),e._v(" "),i("p",[e._v("\n The flexibility of the "),i("a",{attrs:{href:e.proPlanUrl}},[e._v("WP RSS Aggregator Pro Plan")]),e._v(" gave Erik\n greater visual customization to keep his readers engaged, with Keyword Filtering\n helping to control the quality of the content.\n ")]),e._v(" "),i("p",[e._v('\n Erik was also quoted as saying that "the support has been great", which is something we\n pride ourselves on at WP RSS Aggregator.\n ')]),e._v(" "),i("div",{staticStyle:{"margin-bottom":".5rem"}},[i("a",{staticClass:"button",attrs:{href:e.proPlanCtaUrl,target:"_blank"}},[e._v("\n Check out our Pro Plan\n ")])]),e._v(" "),i("div",[i("a",{staticStyle:{"font-size":".9em"},attrs:{href:e.supportUrl,target:"_blank"}},[e._v("Contact support for more information.")])])]),e._v(" "),i("div",{staticClass:"col"},[i("img",{staticClass:"img wpra-demo-photo",attrs:{src:e.demoImageUrl}}),e._v(" "),i("div",{staticClass:"wpra-feedback"},[i("div",{staticClass:"wpra-feedback__copy"},[i("div",{staticClass:"wpra-feedback__text"},[e._v("\n We’ve seen some strong traffic growth month over month. And so yeah, we’re up to over 10,000 page views a month – which is great for a new blog.\n ")]),e._v(" "),i("div",{staticClass:"wpra-feedback__rating"},[i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"}),e._v(" "),i("span",{staticClass:"dashicons dashicons-star-filled"})]),e._v(" "),i("div",{staticClass:"wpra-feedback__by"},[i("a",{attrs:{href:e.caseStudyUrl,target:"_blank"}},[e._v("\n Erik Tozier - Read the full case study\n ")])])])])])])]):e._e()]),e._v(" "),i("div",{staticClass:"connect-actions pad"},[i("div",{staticClass:"pad-item--grow"},[e.active("finish")?e._e():i("button",{staticClass:"button-clear",on:{click:e.finish}},[e._v("\n Skip the introduction\n ")])]),e._v(" "),i("div",{staticClass:"pad-item--no-shrink"},[e.isBackAvailable?i("button",{staticClass:"button-clear",on:{click:e.back}},[e._v("\n Back\n ")]):e._e(),e._v(" "),i("button",{staticClass:"button button-primary button-large",class:{"loading-button":e.isLoading},on:{click:e.next}},[e._v("\n "+e._s(e.active("finish")?"Continue to Plugin":"Next")+"\n ")])])])],1)])},a=[],o=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"wpra-expander",class:{"wpra-expander--expanded":e.isExpanded}},[i("div",{staticClass:"wpra-expander__title",on:{click:function(t){e.isExpanded=!e.isExpanded}}},[e._v("\n "+e._s(e.title)+"\n "),i("span",{staticClass:"dashicons dashicons-arrow-down-alt2"})]),e._v(" "),i("transition-expand",[e.isExpanded?i("div",[i("div",{staticClass:"wpra-expander__content"},[e._t("default")],2)]):e._e()])],1)},c=[],d=i(5),l={data:function(){return{isExpanded:this.defaultExpanded}},props:{title:{},defaultExpanded:{value:!1}},components:{TransitionExpand:d.a}},u=l,p=i(1),v=Object(p.a)(u,o,c,!1,null,null,null);v.options.__file="Expander.vue";var h=v.exports,f=i(6),_=function(e){return e},m=window.wprssWizardConfig,w={data:function(){var e=this;return{prevHeight:0,screens:[{id:"feed",title:_("Add feed source URL"),description:!1,next:this.submitFeed,completed:function(){return e.feed.items.length},entered:function(){e.focusOnInput("feed")}},{id:"feedItems",title:_("Display feed items"),description:!1,next:this.continueItems,completed:function(){return e.feed.items.length&&e.itemsPassed}},{id:"finish",title:_("All done!"),description:!1,next:this.completeIntroduction,completed:function(){return e.feed.items.length&&e.itemsPassed}}],isCopied:!1,isPreparing:!1,isPrepared:!1,transition:"slide-up",activeScreen:"feed",form:{feedSourceUrl:null},itemsPassed:!1,stepLoading:!1,isLoading:!1,isFeedError:!1,feed:{items:[]},previewUrl:m.previewUrl,proPlanUrl:m.proPlanUrl,proPlanCtaUrl:m.proPlanCtaUrl,addOnsUrl:m.addOnsUrl,supportUrl:m.supportUrl,demoImageUrl:m.demoImageUrl,caseStudyUrl:m.caseStudyUrl,knowledgeBaseUrl:m.knowledgeBaseUrl}},computed:{validateLink:function(){return"https://validator.w3.org/feed/check.cgi?url="+encodeURI(this.form.feedSourceUrl)},activeScreenIndex:function(){var e=this;return this.screens.findIndex(function(t){return t.id===e.activeScreen})},currentScreen:function(){var e=this;return this.screens.find(function(t){return t.id===e.activeScreen})},actionCompleted:function(){return this.currentScreen.completed()},isBackAvailable:function(){return this.activeScreenIndex>0&&this.activeScreenIndex<this.screens.length}},mounted:function(){this.onScreenEnter()},methods:{preparePreview:function(e){var t=this;if(this.isPreparing)return void e.preventDefault();this.isPrepared||(e.preventDefault(),this.isPreparing=!0,fetch(this.previewUrl).then(function(){t.isPreparing=!1,t.isPrepared=!0}))},submitFeed:function(){var e=this,t=Object.assign(m.feedEndpoint.defaultPayload,{wprss_intro_feed_url:this.form.feedSourceUrl});return this.isLoading=!0,this.isFeedError=!1,n(m.feedEndpoint.url,t).then(function(t){return e.feed.items=t.data.feed_items.slice(0,3),e.isLoading=!1,{}}).catch(function(t){throw e.isLoading=!1,e.isFeedError=!0,t})},continueItems:function(){return this.itemsPassed=!0,Promise.resolve({})},completeIntroduction:function(){return Promise.resolve({})},next:function(){var e=this;this.transition="slide-up";var t=this.currentScreen.next?this.currentScreen.next:function(){return Promise.resolve(!1)};this.stepLoading=!0,t().then(function(t){e.stepLoading=!1},function(e){throw e}).then(function(){var t=e.activeScreenIndex+1;t>=e.screens.length?e.finish():(e.activeScreen=e.screens[t].id,e.onScreenEnter())}).catch(function(e){console.error(e)})},onScreenEnter:function(){var e=this;this.$nextTick(function(){e.currentScreen.entered&&e.currentScreen.entered()})},focusOnInput:function(e){if(!this.$refs[e]||!this.$refs[e].focus)return!1;this.$refs[e].focus()},back:function(){this.transition="slide-down",this.activeScreen=this.screens[this.activeScreenIndex-1].id},finish:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=function(){return window.location.href=m.feedListUrl};if(e)return void(confirm("Are you sure you want to skip the introduction?")&&t());t()},active:function(e){return this.activeScreen===e},copyToClipboard:function(){var e=this;this.isCopied||(Object(f.a)("[wp-rss-aggregator]"),this.isCopied=!0,setTimeout(function(){e.isCopied=!1},1e3))}},components:{Expander:h}},g=w,y=Object(p.a)(g,r,a,!1,null,null,null);y.options.__file="Wizard.vue";var C=y.exports;i(20),i(17),new s.a({el:"#wpra-wizard-app",template:"<Wizard/>",components:{Wizard:C}})},17:function(e,t){},5:function(e,t,i){"use strict";var n={name:"TransitionExpand",functional:!0,render:function(e,t){return e("transition",{props:{name:"expand"},on:{afterEnter:function(e){e.style.height="auto"},enter:function(e){var t=getComputedStyle(e),i=t.width;e.style.width=i,e.style.position="absolute",e.style.visibility="hidden",e.style.height="auto";var n=getComputedStyle(e),s=n.height;e.style.width=null,e.style.position=null,e.style.visibility=null,e.style.height=0,getComputedStyle(e).height,setTimeout(function(){e.style.height=s})},leave:function(e){var t=getComputedStyle(e),i=t.height;e.style.height=i,getComputedStyle(e).height,setTimeout(function(){e.style.height=0})}}},t.children)}},s=n,r=i(1),a=Object(r.a)(s,void 0,void 0,!1,null,null,null);a.options.__file="TransitionExpand.vue",t.a=a.exports},6:function(e,t,i){"use strict";function n(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!navigator.clipboard)return void s(e,t);navigator.clipboard.writeText(e).then(function(){},function(e){console.error("Async: Could not copy text: ",e)})}t.a=n;var s=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;t=t||document.body.parentElement;var i=document.createElement("textarea");i.value=e;var n=t.scrollTop;document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy")}catch(e){console.error("Fallback: Oops, unable to copy",e)}document.body.removeChild(i),t.scrollTop=n}}},[16])});
js/build/pagination.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([4],{50:function(e,t,a){a(51),jQuery(document).ready(function(e){var t=function(t,a){t.addClass("wpra-loading"),e([document.documentElement,document.body]).animate({scrollTop:t.offset().top-50},500);var n=a.template;delete a.template;var o=n.length?n:"0",p=WpraPagination.baseUri.replace("%s",o);e.ajax({type:"POST",url:p,data:JSON.stringify(a),contentType:"application/json"}).done(function(a){$newEl=e(a.html),$newEl.find(".colorbox").colorbox({iframe:!0,width:"80%",height:"80%"}),t.replaceWith($newEl)})},a=function(e){var a=e.closest("[data-template-ctx]"),n=a.data("wpra-template"),o=a.data("template-ctx"),p=Object.assign({},{template:n},JSON.parse(atob(o)));p.page=e.data("wpra-page"),t(a,p)};e("body").on("click","a[data-wpra-page]",function(t){t.preventDefault(),a(e(this))})})},51:function(e,t){}},[50])});
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([4],{51:function(e,t,a){a(52),jQuery(document).ready(function(e){var t=function(t,a){t.addClass("wpra-loading"),e([document.documentElement,document.body]).animate({scrollTop:t.offset().top-50},500);var n=a.template;delete a.template;var o=n.length?n:"0",p=WpraPagination.baseUri.replace("%s",o);e.ajax({type:"POST",url:p,data:JSON.stringify(a),contentType:"application/json"}).done(function(a){$newEl=e(a.html),$newEl.find(".colorbox").colorbox({iframe:!0,width:"80%",height:"80%"}),t.replaceWith($newEl)})},a=function(e){var a=e.closest("[data-template-ctx]"),n=a.data("wpra-template"),o=a.data("template-ctx"),p=Object.assign({},{template:n},JSON.parse(atob(o)));p.page=e.data("wpra-page"),t(a,p)};e("body").on("click","a[data-wpra-page]",function(t){t.preventDefault(),a(e(this))})})},52:function(e,t){}},[51])});
js/build/plugins.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([3],{21:function(e,t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=a(4),n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"wpra-plugin-disable-poll"},[a("modal",{attrs:{active:e.isModalVisible,"header-class":"invisible-header"},on:{close:e.closeModal}},[a("div",{attrs:{slot:"header"},slot:"header"},[a("div",{staticClass:"wpra-plugin-disable-poll__logo"},[a("img",{attrs:{src:e.image("light-line-logo.png"),alt:""}})]),e._v(" "),a("h3",[e._v("\n Do you have a moment to share why you are deactivating WP RSS Aggregator?\n ")]),e._v(" "),a("p",[e._v("\n Your feedback will help us to improve our plugins and service.\n ")])]),e._v(" "),a("div",{attrs:{slot:"body"},slot:"body"},[a("SerializedForm",{attrs:{form:e.form},model:{value:e.model,callback:function(t){e.model=t},expression:"model"}})],1),e._v(" "),a("div",{attrs:{slot:"footer"},slot:"footer"},[a("div",{staticClass:"footer-confirm__buttons"},[a("button",{staticClass:"button button-clear",on:{click:e.deactivate}},[e._v("\n Skip & Deactivate\n ")]),e._v(" "),a("button",{staticClass:"button button-primary",class:{"loading-button":e.isDeactivating},on:{click:e.submit}},[e._v("\n Submit & Deactivate\n ")])])])])],1)},i=[],l=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("transition",{attrs:{name:"modal-transition"}},[e.active?a("div",{staticClass:"modal",on:{click:function(t){return t.target!==t.currentTarget?null:e.$emit("close")}}},[a("div",{class:["modal__body",this.modalBodyClass]},[a("div",{staticClass:"modal__header",class:e.headerClass},[e._t("header")],2),e._v(" "),a("div",{staticClass:"modal__content"},[e._t("body")],2),e._v(" "),a("div",{staticClass:"modal__footer"},[e._t("footer")],2)])]):e._e()])},s=[],r={props:{active:{type:Boolean},title:{type:String},modalBodyClass:{type:String,default:""},headerClass:{default:function(){return{}}},dialogOpenedClass:{type:String,default:"modal-opened"}},watch:{active:function(e){this.$emit(e?"open":"close")}},mounted:function(){var e=this;this.$on("open",function(){document.querySelector("body").classList.add(e.dialogOpenedClass)}),this.$on("close",function(){document.querySelector("body").classList.remove(e.dialogOpenedClass)})}},d=r,c=a(1),u=Object(c.a)(d,l,s,!1,null,null,null),m=u.exports,p=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"form"},e._l(e.form,function(t){return e.satisfiesCondition(t)?a("div",{staticClass:"form-group"},["radio"===t.type?[t.label?a("label",{attrs:{for:t.name},domProps:{innerHTML:e._s(t.label)}}):e._e(),e._v(" "),e._l(t.options,function(o,n){return a("div",{staticClass:"form-check"},[a("input",{directives:[{name:"model",rawName:"v-model",value:e.model[t.name],expression:"model[datum.name]"}],attrs:{type:"radio",name:t.name,id:t.name+"_"+n},domProps:{value:o.value,checked:e._q(e.model[t.name],o.value)},on:{change:function(a){return e.$set(e.model,t.name,o.value)}}}),e._v(" "),a("label",{attrs:{for:t.name+"_"+n}},[e._v("\n "+e._s(o.label||o.value)+"\n ")])])})]:e._e(),e._v(" "),"textarea"===t.type?[t.label?a("label",{attrs:{for:t.name},domProps:{innerHTML:e._s(t.label)}}):e._e(),e._v(" "),a("textarea",{directives:[{name:"model",rawName:"v-model",value:e.model[t.name],expression:"model[datum.name]"}],attrs:{id:t.name},domProps:{value:e.model[t.name]},on:{input:function(a){a.target.composing||e.$set(e.model,t.name,a.target.value)}}})]:e._e(),e._v(" "),"content"===t.type?[a("div",{class:t.className},[a("p",{domProps:{innerHTML:e._s(t.label)}})])]:e._e()],2):e._e()}),0)},v=[],f={props:{form:{type:Array},value:{type:Object}},computed:{model:{get:function(){return this.value},set:function(e){this.$emit("input",e)}}},methods:{satisfiesCondition:function(e){if(!e.condition)return!0;var t=this.getConditionFunction(e.condition.operator);return!!t&&t(e.condition.field,e.condition.value)},getConditionFunction:function(e){var t=this,a={"=":function(e,a){return t.model[e]===a}};return a[e]?a[e]:null}}},_=f,b=Object(c.a)(_,p,v,!1,null,null,null),h=b.exports,g=a(9),y=a.n(g),C=document.querySelector('[data-slug="wp-rss-aggregator"] .deactivate a'),P={components:{Modal:m,SerializedForm:h},data:function(){return{isDeactivating:!1,deactivateUrl:null,submitUrl:WrpaDisablePoll.url,model:WrpaDisablePoll.model,form:WrpaDisablePoll.form,audience:WrpaDisablePoll.audience||100,isModalVisible:!1}},watch:{"model.reason":function(){this.model.follow_up=null}},mounted:function(){this.getRandomInt(0,100)<this.audience&&C.addEventListener("click",this.handleDeactivateClick)},methods:{getRandomInt:function(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e+1))+e},image:function(e){return WrpaDisablePoll.image+e},handleDeactivateClick:function(e){this.isModalVisible||(e.preventDefault(),this.isModalVisible=!0)},closeModal:function(){this.isModalVisible=!1,this.deactivateUrl=null},submit:function(){var e=this;this.isDeactivating=!0,y.a.post(this.submitUrl,this.model,{headers:{"Content-Type":"application/x-www-form-urlencoded"}}).then(function(){e.deactivate()}).finally(function(){e.isDeactivating=!1})},deactivate:function(){C.click()}}},D=P,w=Object(c.a)(D,n,i,!1,null,null,null),M=w.exports;a(22),new o.a({el:"#wpra-plugins-app",template:"<PluginDisablePoll/>",components:{PluginDisablePoll:M}})},22:function(e,t){}},[21])});
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WPRA=t():e.WPRA=t()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([3],{21:function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=o(4),i=function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("div",{staticClass:"wpra-plugin-disable-poll"},[o("modal",{attrs:{active:e.isModalVisible,"header-class":"invisible-header"},on:{close:e.closeModal}},[o("div",{attrs:{slot:"header"},slot:"header"},[o("div",{staticClass:"wpra-plugin-disable-poll__logo"},[o("img",{attrs:{src:e.image("light-line-logo.png"),alt:""}})]),e._v(" "),o("h3",[e._v("\n Do you have a moment to share why you are deactivating WP RSS Aggregator?\n ")]),e._v(" "),o("p",[e._v("\n Your feedback will help us to improve our plugins and service.\n ")])]),e._v(" "),o("div",{attrs:{slot:"body"},slot:"body"},[o("SerializedForm",{attrs:{form:e.form},model:{value:e.model,callback:function(t){e.model=t},expression:"model"}})],1),e._v(" "),o("div",{attrs:{slot:"footer"},slot:"footer"},[o("div",{staticClass:"footer-confirm__buttons"},[o("button",{staticClass:"button button-clear",on:{click:e.deactivate}},[e._v("\n Skip & Deactivate\n ")]),e._v(" "),o("button",{staticClass:"button button-primary",class:{"loading-button":e.isDeactivating},on:{click:e.submit}},[e._v("\n Submit & Deactivate\n ")])])])])],1)},n=[],l=function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("transition",{attrs:{name:"modal-transition"}},[e.active?o("div",{staticClass:"modal",on:{click:function(t){if(t.target!==t.currentTarget)return null;e.$emit("close")}}},[o("div",{class:["modal__body",this.modalBodyClass]},[o("div",{staticClass:"modal__header",class:e.headerClass},[e._t("header")],2),e._v(" "),o("div",{staticClass:"modal__content"},[e._t("body")],2),e._v(" "),o("div",{staticClass:"modal__footer"},[e._t("footer")],2)])]):e._e()])},s=[],r={props:{active:{type:Boolean},title:{type:String},modalBodyClass:{type:String,default:""},headerClass:{default:function(){return{}}},dialogOpenedClass:{type:String,default:"modal-opened"}},watch:{active:function(e){this.$emit(e?"open":"close")}},mounted:function(){var e=this;this.$on("open",function(){document.querySelector("body").classList.add(e.dialogOpenedClass)}),this.$on("close",function(){document.querySelector("body").classList.remove(e.dialogOpenedClass)})}},d=r,c=o(1),u=Object(c.a)(d,l,s,!1,null,null,null);u.options.__file="Modal.vue";var m=u.exports,v=function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("div",{staticClass:"form"},e._l(e.form,function(t){return e.satisfiesCondition(t)?o("div",{staticClass:"form-group"},["radio"===t.type?[t.label?o("label",{attrs:{for:t.name},domProps:{innerHTML:e._s(t.label)}}):e._e(),e._v(" "),e._l(t.options,function(a,i){return o("div",{staticClass:"form-check"},[o("input",{directives:[{name:"model",rawName:"v-model",value:e.model[t.name],expression:"model[datum.name]"}],attrs:{type:"radio",name:t.name,id:t.name+"_"+i},domProps:{value:a.value,checked:e._q(e.model[t.name],a.value)},on:{change:function(o){e.$set(e.model,t.name,a.value)}}}),e._v(" "),o("label",{attrs:{for:t.name+"_"+i}},[e._v("\n "+e._s(a.label||a.value)+"\n ")])])})]:e._e(),e._v(" "),"textarea"===t.type?[t.label?o("label",{attrs:{for:t.name},domProps:{innerHTML:e._s(t.label)}}):e._e(),e._v(" "),o("textarea",{directives:[{name:"model",rawName:"v-model",value:e.model[t.name],expression:"model[datum.name]"}],attrs:{id:t.name},domProps:{value:e.model[t.name]},on:{input:function(o){o.target.composing||e.$set(e.model,t.name,o.target.value)}}})]:e._e(),e._v(" "),"content"===t.type?[o("div",{class:t.className},[o("p",{domProps:{innerHTML:e._s(t.label)}})])]:e._e()],2):e._e()}),0)},p=[],f={props:{form:{type:Array},value:{type:Object}},computed:{model:{get:function(){return this.value},set:function(e){this.$emit("input",e)}}},methods:{satisfiesCondition:function(e){if(!e.condition)return!0;var t=this.getConditionFunction(e.condition.operator);return!!t&&t(e.condition.field,e.condition.value)},getConditionFunction:function(e){var t=this,o={"=":function(e,o){return t.model[e]===o}};return o[e]?o[e]:null}}},_=f,b=Object(c.a)(_,v,p,!1,null,null,null);b.options.__file="SerializedForm.vue";var h=b.exports,g=o(9),y=o.n(g),C=document.querySelector('[data-slug="wp-rss-aggregator"] .deactivate a'),P={components:{Modal:m,SerializedForm:h},data:function(){return{isDeactivating:!1,deactivateUrl:null,submitUrl:WrpaDisablePoll.url,model:WrpaDisablePoll.model,form:WrpaDisablePoll.form,audience:WrpaDisablePoll.audience||100,isModalVisible:!1}},watch:{"model.reason":function(){this.model.follow_up=null}},mounted:function(){this.getRandomInt(0,100)<this.audience&&C.addEventListener("click",this.handleDeactivateClick)},methods:{getRandomInt:function(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e+1))+e},image:function(e){return WrpaDisablePoll.image+e},handleDeactivateClick:function(e){this.isModalVisible||(e.preventDefault(),this.isModalVisible=!0)},closeModal:function(){this.isModalVisible=!1,this.deactivateUrl=null},submit:function(){var e=this;this.isDeactivating=!0,y.a.post(this.submitUrl,this.model,{headers:{"Content-Type":"application/x-www-form-urlencoded"}}).then(function(){e.deactivate()}).finally(function(){e.isDeactivating=!1})},deactivate:function(){C.click()}}},D=P,M=Object(c.a)(D,i,n,!1,null,null,null);M.options.__file="PluginDisablePoll.vue";var w=M.exports;o(22),new a.a({el:"#wpra-plugins-app",template:"<PluginDisablePoll/>",components:{PluginDisablePoll:w}})},22:function(e,t){}},[21])});
js/build/templates.min.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.WPRA=e():t.WPRA=e()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([1],{40:function(t,e,i){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){return new I(t)}function a(t){return t&&"object"===(void 0===t?"undefined":Z(t))&&"[object RegExp]"!==Object.prototype.toString.call(t)&&"[object Date]"!==Object.prototype.toString.call(t)}function r(t){return Array.isArray(t)?[]:{}}function s(t,e){return e&&!0===e.clone&&a(t)?u(r(t),t,e):t}function l(t,e,i){var n=t.slice();return e.forEach(function(e,o){void 0===n[o]?n[o]=s(e,i):a(e)?n[o]=u(t[o],e,i):-1===t.indexOf(e)&&n.push(s(e,i))}),n}function p(t,e,i){var n={};return a(t)&&Object.keys(t).forEach(function(e){n[e]=s(t[e],i)}),Object.keys(e).forEach(function(o){a(e[o])&&t[o]?n[o]=u(t[o],e[o],i):n[o]=s(e[o],i)}),n}function u(t,e,i){var n=Array.isArray(e),o=i||{arrayMerge:l},a=o.arrayMerge||l;return n?Array.isArray(t)?a(t,e,i):s(e,i):p(t,e,i)}function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function d(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var h=i(42),f=i(43),m=i.n(f),y=i(9),v=i.n(y),b=i(45),g=i.n(b),_=i(46),w=i.n(_),k=i(47),x=i(2),S=i.n(x),A=i(48),T=i.n(A),C={props:{path:{},gate:{}},inject:["router"],methods:{getPath:function(){return this.router.buildRoute(this.path)},navigate:function(t){var e=!this.gate||this.gate();t.preventDefault(),e&&this.router.navigate(this.path)}},render:function(){var t=this,e=arguments[0],i=this.getPath();return e("a",S()([{attrs:{href:i}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.navigate.apply(t,[e].concat(n))}}}]),[this.$slots.default])}},O=null,P={props:{mediaType:{type:String,default:"image"},mediaTitle:{type:String,default:"Select Media"},mediaValueProperty:{type:String,default:"id"}},methods:{mediaNode:function(){var t=this,e=this.$createElement;return this.assertMediaLoaded(),e("div",[e("input",{attrs:{type:"text"},domProps:{value:this.value}}),e("button",S()([{class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.openFrame.apply(t,[e].concat(n))}}}]),["Choose image"])])},openFrame:function(){O||(O=this.createFrame()),O.open()},createFrame:function(){var t=this;return O=wp.media({title:this.mediaTitle,multiple:!1,library:{type:this.mediaType}}),O.on("close",function(){var e=O.state().get("selection"),i=null;e.each(function(t){i=t}),i&&i.id&&t.$emit("input",{id:i.id,url:i.attributes.url}[t.mediaValueProperty])}),O.on("open",function(){var e=O.state().get("selection");if("id"===t.mediaValueProperty&&t.value){var i=wp.media.attachment(t.value);i.fetch(),e.add(i?[i]:[])}}),O},assertMediaLoaded:function(){if(!window.wp.media)throw Error("[MediaInput] wp.media dependency is not loaded")}}},j={mixins:[P],props:{id:{type:String,default:function(){return Math.random().toString(36).substr(0,12)}},label:{},description:{},after:{},type:{},value:{},placeholder:{},title:{},inputDisabled:{},options:{default:function(){return{}}}},methods:{inputNode:function(){var t=this,e=this.$createElement;return"media"===this.type?this.mediaNode():"checkbox"===this.type?e("input",S()([{attrs:{type:"checkbox",id:this.id,placeholder:this.placeholder,disabled:this.$attrs.disabled||this.inputDisabled},domProps:{checked:!!this.value}},{attrs:this.$attrs},{on:{change:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(){return t.$emit("input",!t.value)}).apply(void 0,[e].concat(n))}}}])):"select"!==this.type?e("input",S()([{attrs:{type:this.type,id:this.id,placeholder:this.placeholder,disabled:this.$attrs.disabled||this.inputDisabled},domProps:{value:this.value}},{attrs:this.$attrs},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.$emit("input",e.target.value)}).apply(void 0,[e].concat(n))}}}])):this.selectNode()},selectNode:function(){var t=this,e=this.$createElement,i=Object.keys(this.options).map(function(i){return e("option",{domProps:{value:i,selected:t.value===i}},[t.options[i]])});return e("select",S()([{attrs:this.$attrs},{attrs:{id:this.id,disabled:this.$attrs.disabled||this.inputDisabled}},{on:{change:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.$emit("input",e.target.value)}).apply(void 0,[e].concat(n))}}}]),[i])}},render:function(){var t=arguments[0],e=[];return this.title&&e.push({name:"tippy"}),t("div",{class:{"form-input":!0,"form-input--disabled":this.$attrs.disabled||!1}},[this.label?t("label",{class:"form-input__label",attrs:{for:this.id}},[t("div",[this.label,this.title?t("div",S()([{class:"form-input__tip"},{directives:e},{attrs:{title:this.title}}]),[t("span",{class:"dashicons dashicons-editor-help"})]):null]),this.description?t("div",S()([{class:"form-input__label-description"},{domProps:{innerHTML:this.description}}])):""]):null,t("div",{class:"form-input__field"},[this.inputNode(),this.after])])}},L=function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",{staticClass:"wpra-bottom-panel"},[t._t("default")],2)},W=[],M={},$=M,N=i(1),R=Object(N.a)($,L,W,!1,null,null,null),E=R.exports,D=function(t){return JSON.parse(JSON.stringify(t))},F="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},I=function(){function t(e){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"id";return n(this,t),this.data=e,this.primaryField=i,this}return t.prototype.find=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("object"!==(void 0===t?"undefined":F(t))&&null!==t){var i;i={},i[this.primaryField]=t,t=i}for(var n in this.data)if(this._isMatching(this.data[n],t))return this.data[n];return e},t.prototype.pluck=function(t){return this.data.map(function(e){return e[t]})},t.prototype.remove=function(t){for(var e in this.data)this._isMatching(this.data[e],t)&&this.data.splice(e,1);return this},t.prototype.appendDiff=function(t){for(var e=t,i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}var a=o;this.contains(a)||this.data.push(a)}},t.prototype.prependDiff=function(t){for(var e=t.slice().reverse(),i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}var a=o;this.contains(a)||this.data.unshift(a)}},t.prototype.contains=function(t){for(var e=this.data,i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}if(o.id==t.id)return!0}return!1},t.prototype.filterValues=function(t){var e=this;return Object.keys(this.data).filter(function(i){return t(e.data[i],i)}).reduce(function(t,i){return t[i]=e.data[i],t},{})},t.prototype.filter=function(t){var e=this;return this.data.filter(function(i){return e._isMatching(i,t)})},t.prototype.whereIn=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"id",i=[],n={};n[e]=null;for(var o=t,a=Array.isArray(o),r=0,o=a?o:o[Symbol.iterator]();;){var s;if(a){if(r>=o.length)break;s=o[r++]}else{if(r=o.next(),r.done)break;s=r.value}var l=s;n[e]=l;var p=this.find(n);p&&i.push(p)}return i},t.prototype.key=function(e){return new t(this.data.slice().reduce(function(t,i){return t[i[e]]=i,t},{}))},t.prototype.mapValues=function(t){var e=this;return Object.keys(this.data).map(function(i){e.data[i]=t(e.data[i],i)}),this},t.prototype.values=function(){return this.data},t.prototype._isMatching=function(t,e){if(!(t instanceof Object||e instanceof Object))return t==e;for(var i=!0,n=Object.keys(e),o=Array.isArray(n),a=0,n=o?n:n[Symbol.iterator]();;){var r;if(o){if(a>=n.length)break;r=n[a++]}else{if(a=n.next(),a.done)break;r=a.value}var s=r,l=t.hasOwnProperty(s)&&t[s]==e[s];i=i&&l}return i},t}(),U=o,B={data:function(){return{loading:!1,columns:{name:{label:"Template Name",class:"column-primary"},style:{label:"Template Type"},previewTemplate:{label:"Preview"}},filters:WpraTemplates.options.type,checked:[],filter:{paged:parseInt(this.router.params.paged||1),type:this.router.params.type||"",s:this.router.params.s||""},baseUrl:WpraTemplates.base_url,total:0}},inject:["hooks","http","router"],computed:{totalPages:function(){return Math.ceil(this.total/20)},list:{get:function(){return this.$store.state.templates.items},set:function(t){this.$store.commit("templates/set",t)}}},methods:{navigated:function(){var t=this;Object.keys(this.filter).forEach(function(e){t.filter[e]=t.router.params[e]||""}),this.filter.paged=parseInt(this.filter.paged||1),this.fetchList()},fetchList:function(){var t=this;this.loading=!0;var e=this.getParams(),i=parseInt(e.paged);return delete e.paged,i&&1!==i&&(e.page=i),this.http.get(this.baseUrl,{params:e}).then(function(e){t.list=e.data.items,t.total=e.data.count}).finally(function(){t.loading=!1})},deleteTemplate:function(t){var e=this;if(confirm("Are you sure you want to delete this template? If this template is being used in a shortcode or Gutenberg block anywhere on your site, the default template will be used instead."))return this.loading=!0,this.http.delete(this.baseUrl+"/"+t).then(function(){return e.fetchList()}).then(function(){e.loading=!1})},bulkDelete:function(){var t=this;if(confirm("Are you sure you want to delete these templates? If a template is being used in a shortcode or Gutenberg block anywhere on your site, the default template will be used instead."))return this.loading=!0,this.http.delete(this.baseUrl,{params:{ids:this.checked}}).then(function(){return t.checked=[],t.$refs.table.checkedItems=[],t.fetchList()}).then(function(){t.loading=!1})},duplicateTemplate:function(t){var e=D(t);delete e.id,"__built_in"===e.type&&delete e.type,e.name=e.name+" (Copy)",this.$store.commit("templates/updatePreset",e),this.router.navigate({name:"templates",params:{action:"new"}})},getPreviewLink:function(t){return WpraGlobal.admin_base_url+"?wpra_preview_template="+t.id},createTemplate:function(){this.$store.commit("templates/updatePreset",{}),this.router.navigate({name:"templates",params:{action:"new"}})},setChecked:function(t){var e=this;this.checked=t.filter(function(t){return"__built_in"!==U(e.list).find(t,{}).type})},getParams:function(){var t=this;return Object.keys(this.filter).filter(function(e){return!!t.filter[e]&&"all"!==t.filter[e]}).reduce(function(e,i){return e[i]=t.filter[i],e},{})},setFilter:function(t,e){this.filter[t]=e},submitFilter:function(){this.router.mergeParams(this.getParams())},getRowClass:function(t){return"__built_in"===t.type?"built-in":""}},render:function(){var t=this,e=arguments[0],i=function(t){return{name:"templates",params:{action:"edit",id:t}}},n=this.hooks.apply("wpra-templates-list-cells",this,{name:function(n){var o=n.row;return[e("div",[e("strong",[e(C,{attrs:{path:i(o.id)}},[o.name])]),e("small",{style:{paddingLeft:"4px",opacity:"0.6"}},[o.slug]),"__built_in"===o.type?e("span",{style:{opacity:"0.6",display:"block"}},['This is the default feed template. To create your own, either duplicate it or click "Add New" above.']):null]),e("div",{class:"row-actions"},[e("span",{attrs:{className:"edit"}},[e(C,{attrs:{path:i(o.id)}},["Edit"])," |"]),e("span",{class:"inline",style:{paddingLeft:"4px"}},[e("a",S()([{attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),a=1;a<i;a++)n[a-1]=arguments[a];(function(e){e.preventDefault(),t.duplicateTemplate(o)}).apply(void 0,[e].concat(n))}}}]),["Duplicate"])," ","__built_in"!==o.type?"|":""]),"__built_in"!==o.type?e("span",S()([{class:"trash",style:{paddingLeft:"4px"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),a=1;a<i;a++)n[a-1]=arguments[a];(function(e){e.preventDefault(),t.deleteTemplate(o.id)}).apply(void 0,[e].concat(n))}}}]),[e("a",{attrs:{href:"#","aria-label":"Delete Item"},class:"submitdelete"},["Delete"])]):null])]},style:function(i){var n=i.row;return t.filters[n.type]?[e("div",[t.filters[n.type]])]:[e("div",[t.filters.list," ",e("span",{style:{opacity:.7,fontSize:"90%"}},["(Missing type: ",e("code",[n.type]),")"])])]},previewTemplate:function(i){var n=i.row;return[e("div",[e("a",{attrs:{href:t.getPreviewLink(n),target:"wpra-preview-template"},class:"wpra-preview-link"},["Open preview ",e("span",{class:"dashicons dashicons-external"})])])]},filters:function(){var i=Object.keys(WpraTemplates.options.type).filter(function(t){return"_"!==t[0]}).reduce(function(t,e){return t[e]=WpraTemplates.options.type[e],t},{all:"Select Template Type"});return[e(j,S()([{attrs:{type:"select",options:i,value:t.filter.type},style:{margin:0}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){t.filter.type=e,t.submitFilter()}).apply(void 0,[e].concat(n))}}}]))]}}),o=e("div",[e("h1",{class:"wp-heading-inline"},["Templates"]),e("a",S()([{class:"page-title-action",attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.createTemplate()}).apply(void 0,[e].concat(n))}}}]),["Add New"]),e("p",{class:"search-box",style:{padding:"10px 0"}},[e("label",{class:"screen-reader-text",attrs:{for:"post-search-input"}},["Search Templates:"]),e("input",S()([{attrs:{type:"search",id:"post-search-input",name:"s"},domProps:{value:this.filter.s}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.filter.s=e.target.value}).apply(void 0,[e].concat(n))},keyup:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];if(!("button"in e)&&t._k(e.keyCode,"enter",13))return null;t.submitFilter.apply(t,[e].concat(n))}}}])),e("input",S()([{attrs:{type:"submit",id:"search-submit",value:"Search Templates"},class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.submitFilter.apply(t,[e].concat(n))}}}]))]),e(T.a,S()([{attrs:{columns:this.columns,rows:this.list,loading:this.loading,totalItems:this.total,perPage:20,totalPages:this.totalPages,currentPage:this.filter.paged,notFound:"No templates found.",rowClass:this.getRowClass},ref:"table",class:{"wpra-no-cb":0===this.list.length||1===this.list.length&&"__built_in"===this.list[0].type},scopedSlots:n},{on:{checked:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.setChecked.apply(t,[e].concat(n))},pagination:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){t.filter.paged=e,t.submitFilter()}).apply(void 0,[e].concat(n))}}}])),this.checked.length?e(E,[e("div",{class:"flex-row"},[e("div",{class:"flex-col"},[e("div",{class:"wpra-bottom-panel__title"},["Bulk Actions"]),e("a",S()([{attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.bulkDelete()}).apply(void 0,[e].concat(n))}}}]),["Delete"])])])]):null]);return this.hooks.apply("wpra-templates-list",this,o)}},V={inject:["hooks"],data:function(){return{expanded:!0}},props:{title:{},id:{},submit:{type:Boolean,default:!1},context:{}},methods:{toggle:function(){this.expanded=!this.expanded}},render:function(t){var e=this;return this.hooks.apply("postbox-"+this.id,this.context||this,t("div",{class:"postbox wpra-postbox",attrs:{id:this.submit?"submitdiv":""}},[t("div",{class:"postbox-header"},[t("h2",S()([{class:"hndle ui-sortable-handle"},{on:{click:function(t){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];e.toggle.apply(e,[t].concat(n))}}}]),[t("span",[this.title])])]),t("div",{class:"inside"},[this.hooks.apply("postbox-content-"+this.id,this.context||this,[this.$slots.default],{h:t})])]),{h:t})}},G=V,J=Object(N.a)(G,void 0,void 0,!1,null,null,null),q=J.exports,z={render:function(){return(0,arguments[0])("div",{attrs:{id:"postbox-container-2"},class:"postbox-container"},[this.$slots.default])}},H={render:function(){return(0,arguments[0])("div",{attrs:{id:"postbox-container-1"},class:"wpra-postbox-container postbox-container"},[this.$slots.default])}},K={render:function(){return(0,arguments[0])("div",{attrs:{id:"post-body"}},[this.$slots.default])}},X={props:{loading:{type:Boolean,default:!1}},render:function(){return(0,arguments[0])("button",{attrs:{disabled:this.loading},class:{button:!0,"loading-button":this.loading}},[this.$slots.default])}},Y={data:function(){return{shouldBeVisible:!0}},props:{id:{type:String,required:!0},title:{type:String},body:{type:String},learnMore:{default:!1},okayText:{type:String,default:"Got it"},learnMoreText:{type:String,default:"Learn more"},visible:{type:Boolean,default:!0}},computed:{isVisible:function(){return this.visible&&this.shouldBeVisible&&JSON.parse(localStorage.getItem(this.getBlockKey())||"true")}},methods:{onOkayClick:function(){this.shouldBeVisible=!1,localStorage.setItem(this.getBlockKey(),JSON.stringify(!1))},onLearnMoreClick:function(){window.open(this.learnMore,"_blank").focus()},getBlockKey:function(){return"wpra-"+this.id+"-visible"}},render:function(){var t=arguments[0];if(!this.isVisible)return null;var e=this.learnMore?t(X,{class:"button-clear",nativeOn:{click:this.onLearnMoreClick}},[this.learnMoreText," ",t("span",{class:"dashicons dashicons-external"})]):null;return t("div",{class:"wpra-notice-block"},[t("div",{class:"wpra-notice-block__title"},[this.title]),t("div",S()([{class:"wpra-notice-block__body"},{domProps:{innerHTML:this.body}}])),t("div",{class:"wpra-notice-block__buttons"},[t(X,{class:"brand button-primary",nativeOn:{click:this.onOkayClick}},[this.okayText]),e])])}},Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};u.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error("first argument should be an array with at least two elements");return t.reduce(function(t,i){return u(t,i,e)})};var Q=u,tt=i(49),et=i.n(tt),it={data:function(){return{changes:{model:{}}}},methods:{isChanged:function(){return!et()(this.model,this.changes.model)},rememberModel:function(){this.$set(this.changes,"model",D(this.model))},cancelChanges:function(){confirm("Are you sure you want to cancel your changes for this template? This action cannot be reverted and all changes made since your last save will be lost.")&&this.$set(this,"model",D(this.changes.model))}}},nt={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(t){var e,i,n,o,a,r,s,l="",p=0;for(t=nt._utf8_encode(t);p<t.length;)e=t.charCodeAt(p++),i=t.charCodeAt(p++),n=t.charCodeAt(p++),o=e>>2,a=(3&e)<<4|i>>4,r=(15&i)<<2|n>>6,s=63&n,isNaN(i)?r=s=64:isNaN(n)&&(s=64),l=l+this._keyStr.charAt(o)+this._keyStr.charAt(a)+this._keyStr.charAt(r)+this._keyStr.charAt(s);return l},decode:function(t){var e,i,n,o,a,r,s,l="",p=0;for(t=t.replace(/[^A-Za-z0-9\+\/\=]/g,"");p<t.length;)o=this._keyStr.indexOf(t.charAt(p++)),a=this._keyStr.indexOf(t.charAt(p++)),r=this._keyStr.indexOf(t.charAt(p++)),s=this._keyStr.indexOf(t.charAt(p++)),e=o<<2|a>>4,i=(15&a)<<4|r>>2,n=(3&r)<<6|s,l+=String.fromCharCode(e),64!=r&&(l+=String.fromCharCode(i)),64!=s&&(l+=String.fromCharCode(n));return l=nt._utf8_decode(l)},_utf8_encode:function(t){t=t.replace(/\r\n/g,"\n");for(var e="",i=0;i<t.length;i++){var n=t.charCodeAt(i);n<128?e+=String.fromCharCode(n):n>127&&n<2048?(e+=String.fromCharCode(n>>6|192),e+=String.fromCharCode(63&n|128)):(e+=String.fromCharCode(n>>12|224),e+=String.fromCharCode(n>>6&63|128),e+=String.fromCharCode(63&n|128))}return e},_utf8_decode:function(t){for(var e="",i=0,n=0,o=0;i<t.length;)n=t.charCodeAt(i),n<128?(e+=String.fromCharCode(n),i++):n>191&&n<224?(o=t.charCodeAt(i+1),e+=String.fromCharCode((31&n)<<6|63&o),i+=2):(o=t.charCodeAt(i+1),c3=t.charCodeAt(i+2),e+=String.fromCharCode((15&n)<<12|(63&o)<<6|63&c3),i+=3);return e}},ot=nt,at=i(6),rt={mixins:[it],data:function(){return{typeOptions:Object.keys(WpraTemplates.options.type).filter(function(t){return"_"!==t[0]}).reduce(function(t,e){return t[e]=WpraTemplates.options.type[e],t},{}),model:D(WpraTemplates.model_schema),validation:D(WpraTemplates.model_schema),tooltips:D(WpraTemplates.model_tooltips),baseUrl:WpraTemplates.base_url,isSaving:!1,isLoading:!1}},inject:["hooks","http","router","notification"],mounted:function(){this.resolveEditingItem()},computed:{previewUrl:function(){var t=ot.encode(JSON.stringify(this.model.options));return WpraGlobal.admin_base_url+"?wpra_preview_template="+this.router.params.id+"&wpra_template_options="+t}},methods:{resolveEditingItem:function(){var t=this,e=Q(D(WpraTemplates.model_schema),this.$store.state.templates.preset);this.isLoading=!0,function(){var e=t.router.params.id;if(!e)return Promise.resolve(null);var i=t.$store.getters["templates/item"](e);return i?Promise.resolve(i):t.http.get(t.baseUrl+"/"+e).then(function(t){return t.data})}().then(function(i){if(t.isLoading=!1,!i)return t.$set(t,"model",e),void t.rememberModel();i=Object.assign({},i),t.model=Q(t.model,i),t.rememberModel()})},save:function(){var t=this,e=!this.model.id;this.isSaving=!0,this.runRequest().then(function(i){t.model=Q(t.model,i.data),t.rememberModel(),t.notification.show("Template saved!",{type:"success",icon:function(t){return t.classList.add("dashicons","dashicons-yes"),t}}),e&&t.router.navigate({name:"templates",params:{action:"edit",id:i.data.id}})},function(e){t.notification.show("Something went wrong. Template is not saved!",{type:"error",icon:function(t){return t.classList.add("dashicons","dashicons-warning"),t}})}).finally(function(){t.isSaving=!1})},runRequest:function(){var t=this.model.id?"put":"post",e=this.model.id?this.baseUrl+"/"+this.model.id:this.baseUrl;return this.http[t](e,this.prepareModel())},prepareModel:function(){var t=this,e=Object.keys(WpraTemplates.model_schema);return Object.keys(this.model).filter(function(i){return!(!e.includes(i)||"__built_in"===t.model.type&&["name","type"].includes(i)||["slug","id"].includes(i))}).reduce(function(e,i){return e[i]=t.model[i],e},{})},getShortcode:function(){return'[wp-rss-aggregator template="'+this.model.slug+'"]'},preventLoosingNotSavedData:function(){return!this.isChanged()||confirm("You have unsaved changes. All changes will be lost if you go back to the Template list before updating. Are you sure you want to continue?")},copyShortcode:function(t){Object(at.a)(this.getShortcode());var e=t.target.innerText;t.target.style.width=t.target.getBoundingClientRect().width+"px",t.target.disabled=!0,t.target.innerText="Copied!",setTimeout(function(){t.target.style.width=null,t.target.innerText=e,t.target.disabled=!1},5e3)}},render:function(){var t=this,e=arguments[0],i={name:"templates"},n=null,o=null,a=e(Y,{class:"postbox",attrs:{id:"templates-usage",title:"Setting up your Templates",body:'Templates are used to display the items imported using WP RSS Aggregator. Choose the preferred options below and use them anywhere on your site via our <a href="https://kb.wprssaggregator.com/article/54-displaying-imported-items-shortcode#tinymce" target="_blank">shortcode</a> or our <a href="https://kb.wprssaggregator.com/article/454-displaying-imported-items-block-gutenberg" target="_blank">block</a>.',learnMore:"https://kb.wprssaggregator.com/article/457-templates"}});this.router.params.id&&(n=e("div",{attrs:{id:""},style:{padding:"6px 0"}},[e("div",{class:"misc-pub-section misc-pub-visibility"},[e("a",{attrs:{href:this.previewUrl,role:"button",target:"wpra-preview-template"},class:"wpra-preview-link",style:{marginLeft:"4px",textDecoration:"none"}},["Open preview",e("span",{class:"dashicons dashicons-external"})])])])),this.model.id&&(o=e("div",{class:"wpra-shortcode-copy",attrs:{title:"Copy chortcode"}},[e("div",{class:"wpra-shortcode-copy__content"},[e("strong",["Shortcode: "]),e("code",[this.getShortcode()])]),e("div",{class:"wpra-shortcode-copy__icon"},[e("button",S()([{class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.copyShortcode.apply(t,[e].concat(n))}}}]),["Copy Shortcode"])])]));var r=e("div",[e("div",{class:"page-title"},[e(C,{class:"back-button",attrs:{path:i,gate:this.preventLoosingNotSavedData}},[e("span",{class:"dashicons dashicons-arrow-left-alt"}),"Templates"]),e("h1",[this.router.params.id?this.changes.model.name||this.changes.model.slug:"Create a New Template"]),o]),e("div",{attrs:{id:"poststuff"}},[this.isLoading?e("div",{class:"loading-container"}):e(K,{class:"metabox-holder columns-2"},[e(z,[a,e(q,{attrs:{id:"template-details",title:"Template Details",context:this}},[e(j,S()([{attrs:{type:"text",label:"Template name",value:this.model.name,disabled:"__built_in"===this.model.type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.name=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Template type",value:this.model.type,options:this.typeOptions,disabled:"__built_in"===this.model.type,inputDisabled:!WpraTemplates.options.is_type_enabled,description:WpraTemplates.options.is_type_enabled?null:'<div class="disable-ignored"><strong class="disable-ignored">Get more template types, including a customisable grid template.</strong> <a target="_blank" href="https://www.wprssaggregator.com/extensions/templates/" class="disable-ignored">Learn more.</a></div>'}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.type=e}).apply(void 0,[e].concat(n))}}}])),"__built_in"===this.model.type?e("div",{class:"wpra-info-box"},[e("div",{class:"wpra-info-box__icon"},[e("span",{class:"dashicons dashicons-info"})]),e("div",{class:"wpra-info-box__text"},["This is the default template for WP RSS Aggregator. It is used as the fallback template when one is not selected via the shortcode or block. To create a new one, please go back to the templates list page."])]):null]),e(q,{attrs:{id:"template-options",title:"Template Options",context:this}},[e(j,S()([{attrs:{type:"checkbox",label:"Link title to original article",value:this.model.options.title_is_link,title:this.tooltips.options.title_is_link}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.title_is_link=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"number",label:"Title maximum length",value:this.model.options.title_max_length||"",placeholder:"No limit",title:this.tooltips.options.title_max_length}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.title_max_length=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"number",label:"Number of items to show",value:this.model.options.limit||"",title:this.tooltips.options.limit,placeholder:"Show all items",min:"0"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.limit=""===e?0:e}).apply(void 0,[e].concat(n))}}}])),e("div",{attrs:{id:"wpra-list-template-publish-date"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show publish date",value:this.model.options.date_enabled,title:this.tooltips.options.date_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Date prefix",value:this.model.options.date_prefix,disabled:!this.model.options.date_enabled,title:this.tooltips.options.date_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_prefix=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Date format",value:this.model.options.date_format,disabled:this.model.options.date_use_time_ago||!this.model.options.date_enabled,title:this.tooltips.options.date_format}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_format=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"checkbox",label:'Use "time ago" format',description:"Example: 20 minutes ago",value:this.model.options.date_use_time_ago,disabled:!this.model.options.date_enabled,title:this.tooltips.options.date_use_time_ago}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_use_time_ago=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-source"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show source name",value:this.model.options.source_enabled,title:this.tooltips.options.source_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Source prefix",value:this.model.options.source_prefix,disabled:!this.model.options.source_enabled,title:this.tooltips.options.source_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_prefix=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"checkbox",label:"Link source name",value:this.model.options.source_is_link,disabled:!this.model.options.source_enabled,title:this.tooltips.options.source_is_link}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_is_link=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-author"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show author name",value:this.model.options.author_enabled,title:this.tooltips.options.author_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.author_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Author prefix",value:this.model.options.author_prefix,disabled:!this.model.options.author_enabled,title:this.tooltips.options.author_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.author_prefix=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-pagination"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Pagination",value:this.model.options.pagination,title:this.tooltips.options.pagination,disabled:parseInt(this.model.options.limit)<1||!this.model.options.limit},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.pagination=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Pagination style",options:WpraTemplates.options.pagination_type,value:this.model.options.pagination_type,disabled:!this.model.options.pagination||parseInt(this.model.options.limit)<1||!this.model.options.limit,title:this.tooltips.options.pagination_type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.pagination_type=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-bullets"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show bullets",value:this.model.options.bullets_enabled,title:this.tooltips.options.bullets_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.bullets_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Bullet style",options:WpraTemplates.options.bullet_type,value:this.model.options.bullet_type,disabled:!this.model.options.bullets_enabled,title:this.tooltips.options.bullet_type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.bullet_type=e}).apply(void 0,[e].concat(n))}}}]))]),WpraTemplates.audio_features_enabled&&e("div",{attrs:{id:"wpra-list-template-media"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show audio player",value:this.model.options.audio_player_enabled,title:this.tooltips.options.audio_player_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.audio_player_enabled=e}).apply(void 0,[e].concat(n))}}}]))])])]),e(H,[e(q,{attrs:{id:"template-create",title:this.model.id?"Update Template":"Create Template",submit:!0,context:this},class:"wpra-postbox-last"},[e("div",{class:"submitbox",attrs:{id:"submitpost"}},[n,e("div",{attrs:{id:"major-publishing-actions"}},[e("div",{attrs:{id:"delete-action"}},[this.isChanged()?e("a",S()([{attrs:{href:"#"},class:"submitdelete"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.cancelChanges()}).apply(void 0,[e].concat(n))}}}]),["Cancel Changes"]):null]),e("div",{attrs:{id:"publishing-action"}},[e(X,{class:"button-primary button-large",attrs:{loading:this.isSaving},nativeOn:{click:this.save}},[this.model.id?"Save":"Publish"])]),e("div",{class:"clear"})])])]),e(q,{attrs:{id:"template-link-preferences",title:"Link Preferences",context:this}},[e("p",{style:{opacity:.65}},["These options apply to all links within this template."]),e(j,S()([{attrs:{type:"checkbox",label:"Set links as nofollow",value:this.model.options.links_nofollow,title:this.tooltips.options.links_nofollow}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.links_nofollow=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Open links behaviour",value:this.model.options.links_behavior,options:WpraTemplates.options.links_behavior,title:this.tooltips.options.links_behavior},class:"form-input--vertical"},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.links_behavior=e}).apply(void 0,[e].concat(n))}}}])),"lightbox"===this.model.options.links_behavior?e("div",{class:"notice notice-info notice-alt"},[e("p",["Some sites may not allow their content to be shown in a lightbox."]),e("p",["Embedded content usually works. Try ticking the below checkbox."]),e("p",[e("a",{attrs:{href:"https://kb.wprssaggregator.com/article/471-q-why-wont-some-of-my-feed-items-work-with-the-lightbox-link-behaviour-for-templates",target:"_blank"}},["Learn more"])])]):null,e(j,S()([{attrs:{type:"checkbox",label:"Set links to open embeds",value:this.model.options.link_to_embed,title:this.tooltips.options.link_to_embed}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.link_to_embed=e}).apply(void 0,[e].concat(n))}}}]))]),e(q,{attrs:{id:"template-custom-css",title:"Custom Style",context:this}},[e(j,S()([{attrs:{type:"text",label:"Custom HTML class name",value:this.model.options.custom_css_classname,title:this.tooltips.options.custom_css_classname},class:"form-input--vertical"},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.custom_css_classname=e}).apply(void 0,[e].concat(n))}}}]))])])])])]);return this.hooks.apply("wpra-templates-form",this,r)}},st=function(t){var e=t.store,i=t.router;return{store:e,data:function(){return{afterNavigate:function(){},params:{},currentRoute:null}},created:function(){i.setApp(this),this.currentRoute=i.parseLocation(window.location),this.navigated()},mounted:function(){var t=this;window.addEventListener("popstate",function(){t.currentRoute=i.parseLocation(window.location),t.navigated()})},methods:{ViewComponent:function(){return i.findRoute(this.currentRoute).component},navigated:function(){var t=this;this.$nextTick(function(){var e=t.$refs.main;e&&e.navigated&&e.navigated({route:i.findRoute(t.currentRoute)})})}},render:function(t){var e=t(this.ViewComponent(),{ref:"main"});return this.afterNavigate(),e}}},lt=function(){function t(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),pt=function(t){t||(t=location.href);var e=t.indexOf("?"),i=t.indexOf("#");if(-1==i&&-1==e)return{};-1==i&&(i=t.length);var n=-1==e||i==e+1?t.substring(i):t.substring(e+1,i),o={};return n.split("&").forEach(function(t){if(t){t=t.split("+").join(" ");var e=t.indexOf("="),i=e>-1?t.substr(0,e):t,n=e>-1?decodeURIComponent(t.substr(e+1)):"",a=i.indexOf("[");if(-1==a)o[decodeURIComponent(i)]=n;else{var r=i.indexOf("]",a),s=decodeURIComponent(i.substring(a+1,r));i=decodeURIComponent(i.substring(0,a)),o[i]||(o[i]=[]),s?o[i][s]=n:o[i].push(n)}}}),o},ut=function(){function t(e,i){c(this,t),this.routes=e,this.options=i,this.baseParams=i.baseParams||["post_type","page","action","id"]}return t.prototype.setApp=function(t){this.app=t,this.app.afterNavigate=this.options.afterNavigating||function(){}},t.prototype.findRoute=function(t){return this.routes.find(function(e){var i=e.route;return-1!==t.indexOf(i)})},t.prototype.updateParams=function(t){this.app.$set(this.app,"params",t)},t.prototype.mergeParams=function(t){var e=this,i=Object.keys(this.params).filter(function(i){return-1!==e.baseParams.indexOf(i)||t.hasOwnProperty(i)}).reduce(function(t,i){return t[i]=e.params[i],t},{}),n=Object.assign({},i,t);this.updateParams(n),window.history.pushState(null,null,this.routeFromParams()),this.app.navigated()},t.prototype.routeFromParams=function(){var t=!!Object.keys(this.params).length;return location.pathname+(t?"?"+this.buildParams(this.params):"")},t.prototype.buildRoute=function(t){if(t.name){var e=this.routes.find(function(e){return e.name===t.name});if(!e)return null;var i=e.route,n=-1!==i.indexOf("?")?"&":"?";return i+(t.params?n+this.buildParams(t.params?t.params:{}):"")}},t.prototype.buildParams=function(t){return Object.keys(t).map(function(e){return e+"="+t[e]}).join("&")},t.prototype.parseLocation=function(t){return this.updateParams(pt(t.search)),pt(t.search),t.pathname+t.search},t.prototype.navigate=function(t){this.app&&(this.app.currentRoute=this.buildRoute(t)),this.updateParams(Object.assign({},t.params||{},pt(this.buildRoute(t)))),window.history.pushState(null,null,this.buildRoute(t)),this.app.navigated()},lt(t,[{key:"params",get:function(){return this.app?this.app.params:{}}}]),t}(),ct=ut,dt={set:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];t.isInitialized=!0,t.items=e},updatePreset:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;t.preset=e}},ht={},ft={isInitialized:!1,items:[],preset:{}},mt={item:function(t){return function(e){return U(t.items).find(e)}}},yt={namespaced:!0,mutations:dt,actions:ht,state:ft,getters:mt},vt=function(){function t(e,i){d(this,t),this.showMethod=e,this.errorMethod=i}return t.prototype.show=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.showMethod(t,e)},t.prototype.error=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.errorMethod(t,e)},t}(),bt=vt,gt=i(5),_t={Input:j,NoticeBlock:Y,Postbox:q,RouteLink:C,TransitionExpand:gt.a,Button:X},wt={register:function(t){t.TemplateEdit=function(){return rt},t.TemplateList=function(){return B},t.router=function(t){var e=t.document,i=t.TemplateEdit,n=t.TemplateList;return new ct([{route:WpraGlobal.templates_url_base+"&action",name:"templates-form",component:i},{route:WpraGlobal.templates_url_base,name:"templates",component:n}],{afterNavigating:function(){e.querySelector("html").scrollTop=0}})},t.App=function(t){return st(t)},t.vuex=function(t){return t.vue.use(k.a),k.a},t.notification=function(t){var e=t.vue;return e.use(g.a,{position:"top-center",duration:4e3,iconPack:"callback"}),new bt(e.toasted.show,e.toasted.error)},t.store=function(t){return new t.vuex.Store({modules:{templates:yt},state:{}})},t.http=function(){var t=WpraGlobal&&WpraGlobal.nonce?{headers:{"X-WP-Nonce":WpraGlobal.nonce}}:{};return v.a.create(t)};for(var e=Object.entries(_t),i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if("break"===function(){if(i){if(n>=e.length)return"break";o=e[n++]}else{if(n=e.next(),n.done)return"break";o=n.value}var a=o,r=a[0],s=a[1];t[r]=function(){return s}}())break}return t},run:function(t){t.container.vue.use(w.a,{theme:"light",animation:"fade",arrow:!0,arrowTransform:"scale(0)",placement:"right"})}},kt=i(4);i(41);var xt=h.Container,St=h.Core,At=h.Services;window.UiFramework&&(window.UiFramework=Object.assign({},window.UiFramework,St.UiFramework));var Tt={uiFramework:h,hooks:new At.HookService,document:document,vue:function(t){return kt.a.use(t.uiFramework.Core.InjectedComponents,{container:t}),kt.a}},Ct=new xt.ContainerFactory(m.a),Ot=new St.UiFramework.App(Ct,Tt);window.UiFramework.registerPlugin("templates-app",wt),Ot.use(WpraTemplates.modules||["templates-app"]),Ot.init({"#wpra-templates-app":"App"})},41:function(t,e){},5:function(t,e,i){"use strict";var n={name:"TransitionExpand",functional:!0,render:function(t,e){return t("transition",{props:{name:"expand"},on:{afterEnter:function(t){t.style.height="auto"},enter:function(t){var e=getComputedStyle(t),i=e.width;t.style.width=i,t.style.position="absolute",t.style.visibility="hidden",t.style.height="auto";var n=getComputedStyle(t),o=n.height;t.style.width=null,t.style.position=null,t.style.visibility=null,t.style.height=0,getComputedStyle(t).height,setTimeout(function(){t.style.height=o})},leave:function(t){var e=getComputedStyle(t),i=e.height;t.style.height=i,getComputedStyle(t).height,setTimeout(function(){t.style.height=0})}}},e.children)}},o=n,a=i(1),r=Object(a.a)(o,void 0,void 0,!1,null,null,null);e.a=r.exports},6:function(t,e,i){"use strict";function n(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!navigator.clipboard)return void o(t,e);navigator.clipboard.writeText(t).then(function(){},function(t){console.error("Async: Could not copy text: ",t)})}e.a=n;var o=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e=e||document.body.parentElement;var i=document.createElement("textarea");i.value=t;var n=e.scrollTop;document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy")}catch(t){console.error("Fallback: Oops, unable to copy",t)}document.body.removeChild(i),e.scrollTop=n}}},[40])});
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.WPRA=e():t.WPRA=e()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([1],{41:function(t,e,i){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t){return new I(t)}function a(t){return t&&"object"===(void 0===t?"undefined":Z(t))&&"[object RegExp]"!==Object.prototype.toString.call(t)&&"[object Date]"!==Object.prototype.toString.call(t)}function r(t){return Array.isArray(t)?[]:{}}function s(t,e){return e&&!0===e.clone&&a(t)?u(r(t),t,e):t}function l(t,e,i){var n=t.slice();return e.forEach(function(e,o){void 0===n[o]?n[o]=s(e,i):a(e)?n[o]=u(t[o],e,i):-1===t.indexOf(e)&&n.push(s(e,i))}),n}function p(t,e,i){var n={};return a(t)&&Object.keys(t).forEach(function(e){n[e]=s(t[e],i)}),Object.keys(e).forEach(function(o){a(e[o])&&t[o]?n[o]=u(t[o],e[o],i):n[o]=s(e[o],i)}),n}function u(t,e,i){var n=Array.isArray(e),o=i||{arrayMerge:l},a=o.arrayMerge||l;return n?Array.isArray(t)?a(t,e,i):s(e,i):p(t,e,i)}function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function d(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var h=i(43),f=i(44),m=i.n(f),y=i(9),v=i.n(y),b=i(46),g=i.n(b),_=i(47),w=i.n(_),k=i(48),x=i(2),S=i.n(x),A=i(49),T=i.n(A),C={props:{path:{},gate:{}},inject:["router"],methods:{getPath:function(){return this.router.buildRoute(this.path)},navigate:function(t){var e=!this.gate||this.gate();t.preventDefault(),e&&this.router.navigate(this.path)}},render:function(){var t=this,e=arguments[0],i=this.getPath();return e("a",S()([{attrs:{href:i}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.navigate.apply(t,[e].concat(n))}}}]),[this.$slots.default])}},O=null,P={props:{mediaType:{type:String,default:"image"},mediaTitle:{type:String,default:"Select Media"},mediaValueProperty:{type:String,default:"id"}},methods:{mediaNode:function(){var t=this,e=this.$createElement;return this.assertMediaLoaded(),e("div",[e("input",{attrs:{type:"text"},domProps:{value:this.value}}),e("button",S()([{class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.openFrame.apply(t,[e].concat(n))}}}]),["Choose image"])])},openFrame:function(){O||(O=this.createFrame()),O.open()},createFrame:function(){var t=this;return O=wp.media({title:this.mediaTitle,multiple:!1,library:{type:this.mediaType}}),O.on("close",function(){var e=O.state().get("selection"),i=null;e.each(function(t){i=t}),i&&i.id&&t.$emit("input",{id:i.id,url:i.attributes.url}[t.mediaValueProperty])}),O.on("open",function(){var e=O.state().get("selection");if("id"===t.mediaValueProperty&&t.value){var i=wp.media.attachment(t.value);i.fetch(),e.add(i?[i]:[])}}),O},assertMediaLoaded:function(){if(!window.wp.media)throw Error("[MediaInput] wp.media dependency is not loaded")}}},j={mixins:[P],props:{id:{type:String,default:function(){return Math.random().toString(36).substr(0,12)}},label:{},description:{},after:{},type:{},value:{},placeholder:{},title:{},inputDisabled:{},options:{default:function(){return{}}}},methods:{inputNode:function(){var t=this,e=this.$createElement;return"media"===this.type?this.mediaNode():"checkbox"===this.type?e("input",S()([{attrs:{type:"checkbox",id:this.id,placeholder:this.placeholder,disabled:this.$attrs.disabled||this.inputDisabled},domProps:{checked:!!this.value}},{attrs:this.$attrs},{on:{change:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(){return t.$emit("input",!t.value)}).apply(void 0,[e].concat(n))}}}])):"select"!==this.type?e("input",S()([{attrs:{type:this.type,id:this.id,placeholder:this.placeholder,disabled:this.$attrs.disabled||this.inputDisabled},domProps:{value:this.value}},{attrs:this.$attrs},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.$emit("input",e.target.value)}).apply(void 0,[e].concat(n))}}}])):this.selectNode()},selectNode:function(){var t=this,e=this.$createElement,i=Object.keys(this.options).map(function(i){return e("option",{domProps:{value:i,selected:t.value===i}},[t.options[i]])});return e("select",S()([{attrs:this.$attrs},{attrs:{id:this.id,disabled:this.$attrs.disabled||this.inputDisabled}},{on:{change:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.$emit("input",e.target.value)}).apply(void 0,[e].concat(n))}}}]),[i])}},render:function(){var t=arguments[0],e=[];return this.title&&e.push({name:"tippy"}),t("div",{class:{"form-input":!0,"form-input--disabled":this.$attrs.disabled||!1}},[this.label?t("label",{class:"form-input__label",attrs:{for:this.id}},[t("div",[this.label,this.title?t("div",S()([{class:"form-input__tip"},{directives:e},{attrs:{title:this.title}}]),[t("span",{class:"dashicons dashicons-editor-help"})]):null]),this.description?t("div",S()([{class:"form-input__label-description"},{domProps:{innerHTML:this.description}}])):""]):null,t("div",{class:"form-input__field"},[this.inputNode(),this.after])])}},L=function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",{staticClass:"wpra-bottom-panel"},[t._t("default")],2)},W=[],M={},$=M,N=i(1),R=Object(N.a)($,L,W,!1,null,null,null);R.options.__file="BottomPanel.vue";var E=R.exports,D=function(t){return JSON.parse(JSON.stringify(t))},F="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},I=function(){function t(e){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"id";return n(this,t),this.data=e,this.primaryField=i,this}return t.prototype.find=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("object"!==(void 0===t?"undefined":F(t))&&null!==t){var i;i={},i[this.primaryField]=t,t=i}for(var n in this.data)if(this._isMatching(this.data[n],t))return this.data[n];return e},t.prototype.pluck=function(t){return this.data.map(function(e){return e[t]})},t.prototype.remove=function(t){for(var e in this.data)this._isMatching(this.data[e],t)&&this.data.splice(e,1);return this},t.prototype.appendDiff=function(t){for(var e=t,i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}var a=o;this.contains(a)||this.data.push(a)}},t.prototype.prependDiff=function(t){for(var e=t.slice().reverse(),i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}var a=o;this.contains(a)||this.data.unshift(a)}},t.prototype.contains=function(t){for(var e=this.data,i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if(i){if(n>=e.length)break;o=e[n++]}else{if(n=e.next(),n.done)break;o=n.value}if(o.id==t.id)return!0}return!1},t.prototype.filterValues=function(t){var e=this;return Object.keys(this.data).filter(function(i){return t(e.data[i],i)}).reduce(function(t,i){return t[i]=e.data[i],t},{})},t.prototype.filter=function(t){var e=this;return this.data.filter(function(i){return e._isMatching(i,t)})},t.prototype.whereIn=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"id",i=[],n={};n[e]=null;for(var o=t,a=Array.isArray(o),r=0,o=a?o:o[Symbol.iterator]();;){var s;if(a){if(r>=o.length)break;s=o[r++]}else{if(r=o.next(),r.done)break;s=r.value}var l=s;n[e]=l;var p=this.find(n);p&&i.push(p)}return i},t.prototype.key=function(e){return new t(this.data.slice().reduce(function(t,i){return t[i[e]]=i,t},{}))},t.prototype.mapValues=function(t){var e=this;return Object.keys(this.data).map(function(i){e.data[i]=t(e.data[i],i)}),this},t.prototype.values=function(){return this.data},t.prototype._isMatching=function(t,e){if(!(t instanceof Object||e instanceof Object))return t==e;for(var i=!0,n=Object.keys(e),o=Array.isArray(n),a=0,n=o?n:n[Symbol.iterator]();;){var r;if(o){if(a>=n.length)break;r=n[a++]}else{if(a=n.next(),a.done)break;r=a.value}var s=r,l=t.hasOwnProperty(s)&&t[s]==e[s];i=i&&l}return i},t}(),U=o,B={data:function(){return{loading:!1,columns:{name:{label:"Template Name",class:"column-primary"},style:{label:"Template Type"},previewTemplate:{label:"Preview"}},filters:WpraTemplates.options.type,checked:[],filter:{paged:parseInt(this.router.params.paged||1),type:this.router.params.type||"",s:this.router.params.s||""},baseUrl:WpraTemplates.base_url,total:0}},inject:["hooks","http","router"],computed:{totalPages:function(){return Math.ceil(this.total/20)},list:{get:function(){return this.$store.state.templates.items},set:function(t){this.$store.commit("templates/set",t)}}},methods:{navigated:function(){var t=this;Object.keys(this.filter).forEach(function(e){t.filter[e]=t.router.params[e]||""}),this.filter.paged=parseInt(this.filter.paged||1),this.fetchList()},fetchList:function(){var t=this;this.loading=!0;var e=this.getParams(),i=parseInt(e.paged);return delete e.paged,i&&1!==i&&(e.page=i),this.http.get(this.baseUrl,{params:e}).then(function(e){t.list=e.data.items,t.total=e.data.count}).finally(function(){t.loading=!1})},deleteTemplate:function(t){var e=this;if(confirm("Are you sure you want to delete this template? If this template is being used in a shortcode or Gutenberg block anywhere on your site, the default template will be used instead."))return this.loading=!0,this.http.delete(this.baseUrl+"/"+t).then(function(){return e.fetchList()}).then(function(){e.loading=!1})},bulkDelete:function(){var t=this;if(confirm("Are you sure you want to delete these templates? If a template is being used in a shortcode or Gutenberg block anywhere on your site, the default template will be used instead."))return this.loading=!0,this.http.delete(this.baseUrl,{params:{ids:this.checked}}).then(function(){return t.checked=[],t.$refs.table.checkedItems=[],t.fetchList()}).then(function(){t.loading=!1})},duplicateTemplate:function(t){var e=D(t);delete e.id,"__built_in"===e.type&&delete e.type,e.name=e.name+" (Copy)",this.$store.commit("templates/updatePreset",e),this.router.navigate({name:"templates",params:{action:"new"}})},getPreviewLink:function(t){return WpraGlobal.admin_base_url+"?wpra_preview_template="+t.id},createTemplate:function(){this.$store.commit("templates/updatePreset",{}),this.router.navigate({name:"templates",params:{action:"new"}})},setChecked:function(t){var e=this;this.checked=t.filter(function(t){return"__built_in"!==U(e.list).find(t,{}).type})},getParams:function(){var t=this;return Object.keys(this.filter).filter(function(e){return!!t.filter[e]&&"all"!==t.filter[e]}).reduce(function(e,i){return e[i]=t.filter[i],e},{})},setFilter:function(t,e){this.filter[t]=e},submitFilter:function(){this.router.mergeParams(this.getParams())},getRowClass:function(t){return"__built_in"===t.type?"built-in":""}},render:function(){var t=this,e=arguments[0],i=function(t){return{name:"templates",params:{action:"edit",id:t}}},n=this.hooks.apply("wpra-templates-list-cells",this,{name:function(n){var o=n.row;return[e("div",[e("strong",[e(C,{attrs:{path:i(o.id)}},[o.name])]),e("small",{style:{paddingLeft:"4px",opacity:"0.6"}},[o.slug]),"__built_in"===o.type?e("span",{style:{opacity:"0.6",display:"block"}},['This is the default feed template. To create your own, either duplicate it or click "Add New" above.']):null]),e("div",{class:"row-actions"},[e("span",{attrs:{className:"edit"}},[e(C,{attrs:{path:i(o.id)}},["Edit"])," |"]),e("span",{class:"inline",style:{paddingLeft:"4px"}},[e("a",S()([{attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),a=1;a<i;a++)n[a-1]=arguments[a];(function(e){e.preventDefault(),t.duplicateTemplate(o)}).apply(void 0,[e].concat(n))}}}]),["Duplicate"])," ","__built_in"!==o.type?"|":""]),"__built_in"!==o.type?e("span",S()([{class:"trash",style:{paddingLeft:"4px"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),a=1;a<i;a++)n[a-1]=arguments[a];(function(e){e.preventDefault(),t.deleteTemplate(o.id)}).apply(void 0,[e].concat(n))}}}]),[e("a",{attrs:{href:"#","aria-label":"Delete Item"},class:"submitdelete"},["Delete"])]):null])]},style:function(i){var n=i.row;return t.filters[n.type]?[e("div",[t.filters[n.type]])]:[e("div",[t.filters.list," ",e("span",{style:{opacity:.7,fontSize:"90%"}},["(Missing type: ",e("code",[n.type]),")"])])]},previewTemplate:function(i){var n=i.row;return[e("div",[e("a",{attrs:{href:t.getPreviewLink(n),target:"wpra-preview-template"},class:"wpra-preview-link"},["Open preview ",e("span",{class:"dashicons dashicons-external"})])])]},filters:function(){var i=Object.keys(WpraTemplates.options.type).filter(function(t){return"_"!==t[0]}).reduce(function(t,e){return t[e]=WpraTemplates.options.type[e],t},{all:"Select Template Type"});return[e(j,S()([{attrs:{type:"select",options:i,value:t.filter.type},style:{margin:0}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){t.filter.type=e,t.submitFilter()}).apply(void 0,[e].concat(n))}}}]))]}}),o=e("div",[e("h1",{class:"wp-heading-inline"},["Templates"]),e("a",S()([{class:"page-title-action",attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.createTemplate()}).apply(void 0,[e].concat(n))}}}]),["Add New"]),e("p",{class:"search-box",style:{padding:"10px 0"}},[e("label",{class:"screen-reader-text",attrs:{for:"post-search-input"}},["Search Templates:"]),e("input",S()([{attrs:{type:"search",id:"post-search-input",name:"s"},domProps:{value:this.filter.s}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.filter.s=e.target.value}).apply(void 0,[e].concat(n))},keyup:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];if(!("button"in e)&&t._k(e.keyCode,"enter",13))return null;t.submitFilter.apply(t,[e].concat(n))}}}])),e("input",S()([{attrs:{type:"submit",id:"search-submit",value:"Search Templates"},class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.submitFilter.apply(t,[e].concat(n))}}}]))]),e(T.a,S()([{attrs:{columns:this.columns,rows:this.list,loading:this.loading,totalItems:this.total,perPage:20,totalPages:this.totalPages,currentPage:this.filter.paged,notFound:"No templates found.",rowClass:this.getRowClass},ref:"table",class:{"wpra-no-cb":0===this.list.length||1===this.list.length&&"__built_in"===this.list[0].type},scopedSlots:n},{on:{checked:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.setChecked.apply(t,[e].concat(n))},pagination:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){t.filter.paged=e,t.submitFilter()}).apply(void 0,[e].concat(n))}}}])),this.checked.length?e(E,[e("div",{class:"flex-row"},[e("div",{class:"flex-col"},[e("div",{class:"wpra-bottom-panel__title"},["Bulk Actions"]),e("a",S()([{attrs:{href:"#"}},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.bulkDelete()}).apply(void 0,[e].concat(n))}}}]),["Delete"])])])]):null]);return this.hooks.apply("wpra-templates-list",this,o)}},V={inject:["hooks"],data:function(){return{expanded:!0}},props:{title:{},id:{},submit:{type:Boolean,default:!1},context:{}},methods:{toggle:function(){this.expanded=!this.expanded}},render:function(t){var e=this;return this.hooks.apply("postbox-"+this.id,this.context||this,t("div",{class:"postbox wpra-postbox",attrs:{id:this.submit?"submitdiv":""}},[t("button",S()([{attrs:{type:"button","aria-expanded":"true"},class:"handlediv"},{on:{click:function(t){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];e.toggle.apply(e,[t].concat(n))}}}]),[t("span",{class:"screen-reader-text"},["Toggle panel: ",this.title]),t("span",{class:"toggle-indicator",attrs:{"aria-hidden":"true"}})]),t("h2",S()([{class:"hndle ui-sortable-handle"},{on:{click:function(t){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];e.toggle.apply(e,[t].concat(n))}}}]),[t("span",[this.title])]),t("div",{class:"inside"},[this.hooks.apply("postbox-content-"+this.id,this.context||this,[this.$slots.default],{h:t})])]),{h:t})}},G=V,J=Object(N.a)(G,void 0,void 0,!1,null,null,null);J.options.__file="Postbox.vue";var q=J.exports,z={render:function(){return(0,arguments[0])("div",{attrs:{id:"postbox-container-2"},class:"postbox-container"},[this.$slots.default])}},H={render:function(){return(0,arguments[0])("div",{attrs:{id:"postbox-container-1"},class:"wpra-postbox-container postbox-container"},[this.$slots.default])}},K={render:function(){return(0,arguments[0])("div",{attrs:{id:"post-body"}},[this.$slots.default])}},X={props:{loading:{type:Boolean,default:!1}},render:function(){return(0,arguments[0])("button",{attrs:{disabled:this.loading},class:{button:!0,"loading-button":this.loading}},[this.$slots.default])}},Y={data:function(){return{shouldBeVisible:!0}},props:{id:{type:String,required:!0},title:{type:String},body:{type:String},learnMore:{default:!1},okayText:{type:String,default:"Got it"},learnMoreText:{type:String,default:"Learn more"},visible:{type:Boolean,default:!0}},computed:{isVisible:function(){return this.visible&&this.shouldBeVisible&&JSON.parse(localStorage.getItem(this.getBlockKey())||"true")}},methods:{onOkayClick:function(){this.shouldBeVisible=!1,localStorage.setItem(this.getBlockKey(),JSON.stringify(!1))},onLearnMoreClick:function(){window.open(this.learnMore,"_blank").focus()},getBlockKey:function(){return"wpra-"+this.id+"-visible"}},render:function(){var t=arguments[0];if(!this.isVisible)return null;var e=this.learnMore?t(X,{class:"button-clear",nativeOn:{click:this.onLearnMoreClick}},[this.learnMoreText," ",t("span",{class:"dashicons dashicons-external"})]):null;return t("div",{class:"wpra-notice-block"},[t("div",{class:"wpra-notice-block__title"},[this.title]),t("div",S()([{class:"wpra-notice-block__body"},{domProps:{innerHTML:this.body}}])),t("div",{class:"wpra-notice-block__buttons"},[t(X,{class:"brand button-primary",nativeOn:{click:this.onOkayClick}},[this.okayText]),e])])}},Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};u.all=function(t,e){if(!Array.isArray(t)||t.length<2)throw new Error("first argument should be an array with at least two elements");return t.reduce(function(t,i){return u(t,i,e)})};var Q=u,tt=i(50),et=i.n(tt),it={data:function(){return{changes:{model:{}}}},methods:{isChanged:function(){return!et()(this.model,this.changes.model)},rememberModel:function(){this.$set(this.changes,"model",D(this.model))},cancelChanges:function(){confirm("Are you sure you want to cancel your changes for this template? This action cannot be reverted and all changes made since your last save will be lost.")&&this.$set(this,"model",D(this.changes.model))}}},nt={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(t){var e,i,n,o,a,r,s,l="",p=0;for(t=nt._utf8_encode(t);p<t.length;)e=t.charCodeAt(p++),i=t.charCodeAt(p++),n=t.charCodeAt(p++),o=e>>2,a=(3&e)<<4|i>>4,r=(15&i)<<2|n>>6,s=63&n,isNaN(i)?r=s=64:isNaN(n)&&(s=64),l=l+this._keyStr.charAt(o)+this._keyStr.charAt(a)+this._keyStr.charAt(r)+this._keyStr.charAt(s);return l},decode:function(t){var e,i,n,o,a,r,s,l="",p=0;for(t=t.replace(/[^A-Za-z0-9\+\/\=]/g,"");p<t.length;)o=this._keyStr.indexOf(t.charAt(p++)),a=this._keyStr.indexOf(t.charAt(p++)),r=this._keyStr.indexOf(t.charAt(p++)),s=this._keyStr.indexOf(t.charAt(p++)),e=o<<2|a>>4,i=(15&a)<<4|r>>2,n=(3&r)<<6|s,l+=String.fromCharCode(e),64!=r&&(l+=String.fromCharCode(i)),64!=s&&(l+=String.fromCharCode(n));return l=nt._utf8_decode(l)},_utf8_encode:function(t){t=t.replace(/\r\n/g,"\n");for(var e="",i=0;i<t.length;i++){var n=t.charCodeAt(i);n<128?e+=String.fromCharCode(n):n>127&&n<2048?(e+=String.fromCharCode(n>>6|192),e+=String.fromCharCode(63&n|128)):(e+=String.fromCharCode(n>>12|224),e+=String.fromCharCode(n>>6&63|128),e+=String.fromCharCode(63&n|128))}return e},_utf8_decode:function(t){for(var e="",i=0,n=0,o=0;i<t.length;)n=t.charCodeAt(i),n<128?(e+=String.fromCharCode(n),i++):n>191&&n<224?(o=t.charCodeAt(i+1),e+=String.fromCharCode((31&n)<<6|63&o),i+=2):(o=t.charCodeAt(i+1),c3=t.charCodeAt(i+2),e+=String.fromCharCode((15&n)<<12|(63&o)<<6|63&c3),i+=3);return e}},ot=nt,at=i(6),rt={mixins:[it],data:function(){return{typeOptions:Object.keys(WpraTemplates.options.type).filter(function(t){return"_"!==t[0]}).reduce(function(t,e){return t[e]=WpraTemplates.options.type[e],t},{}),model:D(WpraTemplates.model_schema),validation:D(WpraTemplates.model_schema),tooltips:D(WpraTemplates.model_tooltips),baseUrl:WpraTemplates.base_url,isSaving:!1,isLoading:!1}},inject:["hooks","http","router","notification"],mounted:function(){this.resolveEditingItem()},computed:{previewUrl:function(){var t=ot.encode(JSON.stringify(this.model.options));return WpraGlobal.admin_base_url+"?wpra_preview_template="+this.router.params.id+"&wpra_template_options="+t}},methods:{resolveEditingItem:function(){var t=this,e=Q(D(WpraTemplates.model_schema),this.$store.state.templates.preset);this.isLoading=!0,function(){var e=t.router.params.id;if(!e)return Promise.resolve(null);var i=t.$store.getters["templates/item"](e);return i?Promise.resolve(i):t.http.get(t.baseUrl+"/"+e).then(function(t){return t.data})}().then(function(i){if(t.isLoading=!1,!i)return t.$set(t,"model",e),void t.rememberModel();i=Object.assign({},i),t.model=Q(t.model,i),t.rememberModel()})},save:function(){var t=this,e=!this.model.id;this.isSaving=!0,this.runRequest().then(function(i){t.model=Q(t.model,i.data),t.rememberModel(),t.notification.show("Template saved!",{type:"success",icon:function(t){return t.classList.add("dashicons","dashicons-yes"),t}}),e&&t.router.navigate({name:"templates",params:{action:"edit",id:i.data.id}})},function(e){t.notification.show("Something went wrong. Template is not saved!",{type:"error",icon:function(t){return t.classList.add("dashicons","dashicons-warning"),t}})}).finally(function(){t.isSaving=!1})},runRequest:function(){var t=this.model.id?"put":"post",e=this.model.id?this.baseUrl+"/"+this.model.id:this.baseUrl;return this.http[t](e,this.prepareModel())},prepareModel:function(){var t=this,e=Object.keys(WpraTemplates.model_schema);return Object.keys(this.model).filter(function(i){return!(!e.includes(i)||"__built_in"===t.model.type&&["name","type"].includes(i)||["slug","id"].includes(i))}).reduce(function(e,i){return e[i]=t.model[i],e},{})},getShortcode:function(){return'[wp-rss-aggregator template="'+this.model.slug+'"]'},preventLoosingNotSavedData:function(){return!this.isChanged()||confirm("You have unsaved changes. All changes will be lost if you go back to the Template list before updating. Are you sure you want to continue?")},copyShortcode:function(t){Object(at.a)(this.getShortcode());var e=t.target.innerText;t.target.style.width=t.target.getBoundingClientRect().width+"px",t.target.disabled=!0,t.target.innerText="Copied!",setTimeout(function(){t.target.style.width=null,t.target.innerText=e,t.target.disabled=!1},5e3)}},render:function(){var t=this,e=arguments[0],i={name:"templates"},n=null,o=null,a=e(Y,{class:"postbox",attrs:{id:"templates-usage",title:"Setting up your Templates",body:'Templates are used to display the items imported using WP RSS Aggregator. Choose the preferred options below and use them anywhere on your site via our <a href="https://kb.wprssaggregator.com/article/54-displaying-imported-items-shortcode#tinymce" target="_blank">shortcode</a> or our <a href="https://kb.wprssaggregator.com/article/454-displaying-imported-items-block-gutenberg" target="_blank">block</a>.',learnMore:"https://kb.wprssaggregator.com/article/457-templates"}});this.router.params.id&&(n=e("div",{attrs:{id:""},style:{padding:"6px 0"}},[e("div",{class:"misc-pub-section misc-pub-visibility"},[e("a",{attrs:{href:this.previewUrl,role:"button",target:"wpra-preview-template"},class:"wpra-preview-link",style:{marginLeft:"4px",textDecoration:"none"}},["Open preview",e("span",{class:"dashicons dashicons-external"})])])])),this.model.id&&(o=e("div",{class:"wpra-shortcode-copy",attrs:{title:"Copy chortcode"}},[e("div",{class:"wpra-shortcode-copy__content"},[e("strong",["Shortcode: "]),e("code",[this.getShortcode()])]),e("div",{class:"wpra-shortcode-copy__icon"},[e("button",S()([{class:"button"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];t.copyShortcode.apply(t,[e].concat(n))}}}]),["Copy Shortcode"])])]));var r=e("div",[e("div",{class:"page-title"},[e(C,{class:"back-button",attrs:{path:i,gate:this.preventLoosingNotSavedData}},[e("span",{class:"dashicons dashicons-arrow-left-alt"}),"Templates"]),e("h1",[this.router.params.id?this.changes.model.name||this.changes.model.slug:"Create a New Template"]),o]),e("div",{attrs:{id:"poststuff"}},[this.isLoading?e("div",{class:"loading-container"}):e(K,{class:"metabox-holder columns-2"},[e(z,[a,e(q,{attrs:{id:"template-details",title:"Template Details",context:this}},[e(j,S()([{attrs:{type:"text",label:"Template name",value:this.model.name,disabled:"__built_in"===this.model.type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.name=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Template type",value:this.model.type,options:this.typeOptions,disabled:"__built_in"===this.model.type,inputDisabled:!WpraTemplates.options.is_type_enabled,description:WpraTemplates.options.is_type_enabled?null:'<div class="disable-ignored"><strong class="disable-ignored">Get more template types, including a customisable grid template.</strong> <a target="_blank" href="https://www.wprssaggregator.com/extensions/templates/" class="disable-ignored">Learn more.</a></div>'}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.type=e}).apply(void 0,[e].concat(n))}}}])),"__built_in"===this.model.type?e("div",{class:"wpra-info-box"},[e("div",{class:"wpra-info-box__icon"},[e("span",{class:"dashicons dashicons-info"})]),e("div",{class:"wpra-info-box__text"},["This is the default template for WP RSS Aggregator. It is used as the fallback template when one is not selected via the shortcode or block. To create a new one, please go back to the Templates List."])]):null]),e(q,{attrs:{id:"template-options",title:"Template Options",context:this}},[e(j,S()([{attrs:{type:"checkbox",label:"Link title to original article",value:this.model.options.title_is_link,title:this.tooltips.options.title_is_link}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.title_is_link=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"number",label:"Title maximum length",value:this.model.options.title_max_length||"",placeholder:"No limit",title:this.tooltips.options.title_max_length}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.title_max_length=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"number",label:"Number of items to show",value:this.model.options.limit||"",title:this.tooltips.options.limit,placeholder:"Show all items",min:"0"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.limit=""===e?0:e}).apply(void 0,[e].concat(n))}}}])),e("div",{attrs:{id:"wpra-list-template-publish-date"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show publish date",value:this.model.options.date_enabled,title:this.tooltips.options.date_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Date prefix",value:this.model.options.date_prefix,disabled:!this.model.options.date_enabled,title:this.tooltips.options.date_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_prefix=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Date format",value:this.model.options.date_format,disabled:this.model.options.date_use_time_ago||!this.model.options.date_enabled,title:this.tooltips.options.date_format}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_format=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"checkbox",label:'Use "time ago" format',description:"Example: 20 minutes ago",value:this.model.options.date_use_time_ago,disabled:!this.model.options.date_enabled,title:this.tooltips.options.date_use_time_ago}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.date_use_time_ago=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-source"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show source name",value:this.model.options.source_enabled,title:this.tooltips.options.source_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Source prefix",value:this.model.options.source_prefix,disabled:!this.model.options.source_enabled,title:this.tooltips.options.source_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_prefix=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"checkbox",label:"Link source name",value:this.model.options.source_is_link,disabled:!this.model.options.source_enabled,title:this.tooltips.options.source_is_link}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.source_is_link=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-author"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show author name",value:this.model.options.author_enabled,title:this.tooltips.options.author_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.author_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"text",label:"Author prefix",value:this.model.options.author_prefix,disabled:!this.model.options.author_enabled,title:this.tooltips.options.author_prefix}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.author_prefix=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-pagination"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Pagination",value:this.model.options.pagination,title:this.tooltips.options.pagination,disabled:parseInt(this.model.options.limit)<1||!this.model.options.limit},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.pagination=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Pagination style",options:WpraTemplates.options.pagination_type,value:this.model.options.pagination_type,disabled:!this.model.options.pagination||parseInt(this.model.options.limit)<1||!this.model.options.limit,title:this.tooltips.options.pagination_type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.pagination_type=e}).apply(void 0,[e].concat(n))}}}]))]),e("div",{attrs:{id:"wpra-list-template-bullets"},style:{paddingTop:"10px"}},[e(j,S()([{attrs:{type:"checkbox",label:"Show bullets",value:this.model.options.bullets_enabled,title:this.tooltips.options.bullets_enabled},style:{fontWeight:"bold"}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.bullets_enabled=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Bullet style",options:WpraTemplates.options.bullet_type,value:this.model.options.bullet_type,disabled:!this.model.options.bullets_enabled,title:this.tooltips.options.bullet_type}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.bullet_type=e}).apply(void 0,[e].concat(n))}}}]))])])]),e(H,[e(q,{attrs:{id:"template-create",title:this.model.id?"Update Template":"Create Template",submit:!0,context:this},class:"wpra-postbox-last"},[e("div",{class:"submitbox",attrs:{id:"submitpost"}},[n,e("div",{attrs:{id:"major-publishing-actions"}},[e("div",{attrs:{id:"delete-action"}},[this.isChanged()?e("a",S()([{attrs:{href:"#"},class:"submitdelete"},{on:{click:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){e.preventDefault(),t.cancelChanges()}).apply(void 0,[e].concat(n))}}}]),["Cancel Changes"]):null]),e("div",{attrs:{id:"publishing-action"}},[e(X,{class:"button-primary button-large",attrs:{loading:this.isSaving},nativeOn:{click:this.save}},[this.model.id?"Save":"Publish"])]),e("div",{class:"clear"})])])]),e(q,{attrs:{id:"template-link-preferences",title:"Link Preferences",context:this}},[e("p",{style:{opacity:.65}},["These options apply to all links within this template."]),e(j,S()([{attrs:{type:"checkbox",label:"Set links as nofollow",value:this.model.options.links_nofollow,title:this.tooltips.options.links_nofollow}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.links_nofollow=e}).apply(void 0,[e].concat(n))}}}])),e(j,S()([{attrs:{type:"select",label:"Open links behaviour",value:this.model.options.links_behavior,options:WpraTemplates.options.links_behavior,title:this.tooltips.options.links_behavior},class:"form-input--vertical"},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.links_behavior=e}).apply(void 0,[e].concat(n))}}}])),"lightbox"===this.model.options.links_behavior?e("div",{class:"notice notice-info notice-alt"},[e("p",["Some sites may not allow their content to be shown in a lightbox."]),e("p",["Embedded content usually works. Try ticking the below checkbox."]),e("p",[e("a",{attrs:{href:"https://kb.wprssaggregator.com/article/471-q-why-wont-some-of-my-feed-items-work-with-the-lightbox-link-behaviour-for-templates",target:"_blank"}},["Learn more"])])]):null,e(j,S()([{attrs:{type:"checkbox",label:"Set links to open embeds",value:this.model.options.link_to_embed,title:this.tooltips.options.link_to_embed}},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.link_to_embed=e}).apply(void 0,[e].concat(n))}}}]))]),e(q,{attrs:{id:"template-custom-css",title:"Custom Style",context:this}},[e(j,S()([{attrs:{type:"text",label:"Custom HTML class name",value:this.model.options.custom_css_classname,title:this.tooltips.options.custom_css_classname},class:"form-input--vertical"},{on:{input:function(e){for(var i=arguments.length,n=Array(i>1?i-1:0),o=1;o<i;o++)n[o-1]=arguments[o];(function(e){return t.model.options.custom_css_classname=e}).apply(void 0,[e].concat(n))}}}]))])])])])]);return this.hooks.apply("wpra-templates-form",this,r)}},st=function(t){var e=t.store,i=t.router;return{store:e,data:function(){return{afterNavigate:function(){},params:{},currentRoute:null}},created:function(){i.setApp(this),this.currentRoute=i.parseLocation(window.location),this.navigated()},mounted:function(){var t=this;window.addEventListener("popstate",function(){t.currentRoute=i.parseLocation(window.location),t.navigated()})},methods:{ViewComponent:function(){return i.findRoute(this.currentRoute).component},navigated:function(){var t=this;this.$nextTick(function(){var e=t.$refs.main;e&&e.navigated&&e.navigated({route:i.findRoute(t.currentRoute)})})}},render:function(t){var e=t(this.ViewComponent(),{ref:"main"});return this.afterNavigate(),e}}},lt=function(){function t(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,i,n){return i&&t(e.prototype,i),n&&t(e,n),e}}(),pt=function(t){t||(t=location.href);var e=t.indexOf("?"),i=t.indexOf("#");if(-1==i&&-1==e)return{};-1==i&&(i=t.length);var n=-1==e||i==e+1?t.substring(i):t.substring(e+1,i),o={};return n.split("&").forEach(function(t){if(t){t=t.split("+").join(" ");var e=t.indexOf("="),i=e>-1?t.substr(0,e):t,n=e>-1?decodeURIComponent(t.substr(e+1)):"",a=i.indexOf("[");if(-1==a)o[decodeURIComponent(i)]=n;else{var r=i.indexOf("]",a),s=decodeURIComponent(i.substring(a+1,r));i=decodeURIComponent(i.substring(0,a)),o[i]||(o[i]=[]),s?o[i][s]=n:o[i].push(n)}}}),o},ut=function(){function t(e,i){c(this,t),this.routes=e,this.options=i,this.baseParams=i.baseParams||["post_type","page","action","id"]}return t.prototype.setApp=function(t){this.app=t,this.app.afterNavigate=this.options.afterNavigating||function(){}},t.prototype.findRoute=function(t){return this.routes.find(function(e){var i=e.route;return-1!==t.indexOf(i)})},t.prototype.updateParams=function(t){this.app.$set(this.app,"params",t)},t.prototype.mergeParams=function(t){var e=this,i=Object.keys(this.params).filter(function(i){return-1!==e.baseParams.indexOf(i)||t.hasOwnProperty(i)}).reduce(function(t,i){return t[i]=e.params[i],t},{}),n=Object.assign({},i,t);this.updateParams(n),window.history.pushState(null,null,this.routeFromParams()),this.app.navigated()},t.prototype.routeFromParams=function(){var t=!!Object.keys(this.params).length;return location.pathname+(t?"?"+this.buildParams(this.params):"")},t.prototype.buildRoute=function(t){if(t.name){var e=this.routes.find(function(e){return e.name===t.name});if(!e)return null;var i=e.route,n=-1!==i.indexOf("?")?"&":"?";return i+(t.params?n+this.buildParams(t.params?t.params:{}):"")}},t.prototype.buildParams=function(t){return Object.keys(t).map(function(e){return e+"="+t[e]}).join("&")},t.prototype.parseLocation=function(t){return this.updateParams(pt(t.search)),pt(t.search),t.pathname+t.search},t.prototype.navigate=function(t){this.app&&(this.app.currentRoute=this.buildRoute(t)),this.updateParams(Object.assign({},t.params||{},pt(this.buildRoute(t)))),window.history.pushState(null,null,this.buildRoute(t)),this.app.navigated()},lt(t,[{key:"params",get:function(){return this.app?this.app.params:{}}}]),t}(),ct=ut,dt={set:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];t.isInitialized=!0,t.items=e},updatePreset:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;t.preset=e}},ht={},ft={isInitialized:!1,items:[],preset:{}},mt={item:function(t){return function(e){return U(t.items).find(e)}}},yt={namespaced:!0,mutations:dt,actions:ht,state:ft,getters:mt},vt=function(){function t(e,i){d(this,t),this.showMethod=e,this.errorMethod=i}return t.prototype.show=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.showMethod(t,e)},t.prototype.error=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.errorMethod(t,e)},t}(),bt=vt,gt=i(5),_t={Input:j,NoticeBlock:Y,Postbox:q,RouteLink:C,TransitionExpand:gt.a,Button:X},wt={register:function(t){t.TemplateEdit=function(){return rt},t.TemplateList=function(){return B},t.router=function(t){var e=t.document,i=t.TemplateEdit,n=t.TemplateList;return new ct([{route:WpraGlobal.templates_url_base+"&action",name:"templates-form",component:i},{route:WpraGlobal.templates_url_base,name:"templates",component:n}],{afterNavigating:function(){e.querySelector("html").scrollTop=0}})},t.App=function(t){return st(t)},t.vuex=function(t){return t.vue.use(k.a),k.a},t.notification=function(t){var e=t.vue;return e.use(g.a,{position:"top-center",duration:4e3,iconPack:"callback"}),new bt(e.toasted.show,e.toasted.error)},t.store=function(t){return new t.vuex.Store({modules:{templates:yt},state:{}})},t.http=function(){var t=WpraGlobal&&WpraGlobal.nonce?{headers:{"X-WP-Nonce":WpraGlobal.nonce}}:{};return v.a.create(t)};for(var e=Object.entries(_t),i=Array.isArray(e),n=0,e=i?e:e[Symbol.iterator]();;){var o;if("break"===function(){if(i){if(n>=e.length)return"break";o=e[n++]}else{if(n=e.next(),n.done)return"break";o=n.value}var a=o,r=a[0],s=a[1];t[r]=function(){return s}}())break}return t},run:function(t){t.container.vue.use(w.a,{theme:"light",animation:"fade",arrow:!0,arrowTransform:"scale(0)",placement:"right"})}},kt=i(4);i(42);var xt=h.Container,St=h.Core,At=h.Services;window.UiFramework&&(window.UiFramework=Object.assign({},window.UiFramework,St.UiFramework));var Tt={uiFramework:h,hooks:new At.HookService,document:document,vue:function(t){return kt.a.use(t.uiFramework.Core.InjectedComponents,{container:t}),kt.a}},Ct=new xt.ContainerFactory(m.a),Ot=new St.UiFramework.App(Ct,Tt);window.UiFramework.registerPlugin("templates-app",wt),Ot.use(WpraTemplates.modules||["templates-app"]),Ot.init({"#wpra-templates-app":"App"})},42:function(t,e){},5:function(t,e,i){"use strict";var n={name:"TransitionExpand",functional:!0,render:function(t,e){return t("transition",{props:{name:"expand"},on:{afterEnter:function(t){t.style.height="auto"},enter:function(t){var e=getComputedStyle(t),i=e.width;t.style.width=i,t.style.position="absolute",t.style.visibility="hidden",t.style.height="auto";var n=getComputedStyle(t),o=n.height;t.style.width=null,t.style.position=null,t.style.visibility=null,t.style.height=0,getComputedStyle(t).height,setTimeout(function(){t.style.height=o})},leave:function(t){var e=getComputedStyle(t),i=e.height;t.style.height=i,getComputedStyle(t).height,setTimeout(function(){t.style.height=0})}}},e.children)}},o=n,a=i(1),r=Object(a.a)(o,void 0,void 0,!1,null,null,null);r.options.__file="TransitionExpand.vue",e.a=r.exports},6:function(t,e,i){"use strict";function n(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!navigator.clipboard)return void o(t,e);navigator.clipboard.writeText(t).then(function(){},function(t){console.error("Async: Could not copy text: ",t)})}e.a=n;var o=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e=e||document.body.parentElement;var i=document.createElement("textarea");i.value=t;var n=e.scrollTop;document.body.appendChild(i),i.focus(),i.select();try{document.execCommand("copy")}catch(t){console.error("Fallback: Oops, unable to copy",t)}document.body.removeChild(i),e.scrollTop=n}}},[41])});
js/build/update.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.WPRA=o():e.WPRA=o()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([5],{53:function(e,o){}},[53])});
1
+ !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.WPRA=o():e.WPRA=o()}("undefined"!=typeof self?self:this,function(){return webpackJsonpWPRA([5],{54:function(e,o){}},[54])});
js/build/wpra-vendor.min.js CHANGED
@@ -1,27 +1,27 @@
1
- webpackJsonpWPRA([0],[function(t,e,n){"use strict";function r(t){return"[object Array]"===T.call(t)}function i(t){return"[object ArrayBuffer]"===T.call(t)}function o(t){return"undefined"!=typeof FormData&&t instanceof FormData}function a(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer}function s(t){return"string"==typeof t}function c(t){return"number"==typeof t}function u(t){return void 0===t}function l(t){return null!==t&&"object"==typeof t}function f(t){return"[object Date]"===T.call(t)}function p(t){return"[object File]"===T.call(t)}function d(t){return"[object Blob]"===T.call(t)}function h(t){return"[object Function]"===T.call(t)}function v(t){return l(t)&&h(t.pipe)}function m(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams}function y(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&"undefined"!=typeof window&&"undefined"!=typeof document}function b(t,e){if(null!==t&&void 0!==t)if("object"!=typeof t&&(t=[t]),r(t))for(var n=0,i=t.length;n<i;n++)e.call(null,t[n],n,t);else for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.call(null,t[o],o,t)}function w(){function t(t,n){"object"==typeof e[n]&&"object"==typeof t?e[n]=w(e[n],t):e[n]=t}for(var e={},n=0,r=arguments.length;n<r;n++)b(arguments[n],t);return e}function x(t,e,n){return b(e,function(e,r){t[r]=n&&"function"==typeof e?_(e,n):e}),t}var _=n(10),k=n(24),T=Object.prototype.toString;t.exports={isArray:r,isArrayBuffer:i,isBuffer:k,isFormData:o,isArrayBufferView:a,isString:s,isNumber:c,isObject:l,isUndefined:u,isDate:f,isFile:p,isBlob:d,isFunction:h,isStream:v,isURLSearchParams:m,isStandardBrowserEnv:g,forEach:b,merge:w,extend:x,trim:y}},function(t,e,n){"use strict";function r(t,e,n,r,i,o,a,s){var c="function"==typeof t?t.options:t;e&&(c.render=e,c.staticRenderFns=n,c._compiled=!0),r&&(c.functional=!0),o&&(c._scopeId="data-v-"+o);var u;if(a?(u=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},c._ssrRegister=u):i&&(u=s?function(){i.call(this,(c.functional?this.parent:this).$root.$options.shadowRoot)}:i),u)if(c.functional){c._injectStyles=u;var l=c.render;c.render=function(t,e){return u.call(e),l(t,e)}}else{var f=c.beforeCreate;c.beforeCreate=f?[].concat(f,u):[u]}return{exports:t,options:c}}e.a=r},function(t,e){function n(t,e){return function(){t&&t.apply(this,arguments),e&&e.apply(this,arguments)}}var r=/^(attrs|props|on|nativeOn|class|style|hook)$/;t.exports=function(t){return t.reduce(function(t,e){var i,o,a,s,c;for(a in e)if(i=t[a],o=e[a],i&&r.test(a))if("class"===a&&("string"==typeof i&&(c=i,t[a]=i={},i[c]=!0),"string"==typeof o&&(c=o,e[a]=o={},o[c]=!0)),"on"===a||"nativeOn"===a||"hook"===a)for(s in o)i[s]=n(i[s],o[s]);else if(Array.isArray(i))t[a]=i.concat(o);else if(Array.isArray(o))t[a]=[i].concat(o);else for(s in o)i[s]=o[s];else t[a]=e[a];return t},{})}},function(t,e){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){"use strict";(function(t,n){function r(t){return void 0===t||null===t}function i(t){return void 0!==t&&null!==t}function o(t){return!0===t}function a(t){return!1===t}function s(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function c(t){return null!==t&&"object"==typeof t}function u(t){return"[object Object]"===Oo.call(t)}function l(t){return"[object RegExp]"===Oo.call(t)}function f(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function p(t){return i(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function d(t){return null==t?"":Array.isArray(t)||u(t)&&t.toString===Oo?JSON.stringify(t,null,2):String(t)}function h(t){var e=parseFloat(t);return isNaN(e)?t:e}function v(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i<r.length;i++)n[r[i]]=!0;return e?function(t){return n[t.toLowerCase()]}:function(t){return n[t]}}function m(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}function y(t,e){return Eo.call(t,e)}function g(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}function b(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function w(t,e){return t.bind(e)}function x(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function _(t,e){for(var n in e)t[n]=e[n];return t}function k(t){for(var e={},n=0;n<t.length;n++)t[n]&&_(e,t[n]);return e}function T(t,e,n){}function O(t,e){if(t===e)return!0;var n=c(t),r=c(e);if(!n||!r)return!n&&!r&&String(t)===String(e);try{var i=Array.isArray(t),o=Array.isArray(e);if(i&&o)return t.length===e.length&&t.every(function(t,n){return O(t,e[n])});if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(i||o)return!1;var a=Object.keys(t),s=Object.keys(e);return a.length===s.length&&a.every(function(n){return O(t[n],e[n])})}catch(t){return!1}}function A(t,e){for(var n=0;n<t.length;n++)if(O(t[n],e))return n;return-1}function C(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments))}}function E(t){var e=(t+"").charCodeAt(0);return 36===e||95===e}function S(t,e,n,r){Object.defineProperty(t,e,{value:n,enumerable:!!r,writable:!0,configurable:!0})}function P(t){if(!Ho.test(t)){var e=t.split(".");return function(t){for(var n=0;n<e.length;n++){if(!t)return;t=t[e[n]]}return t}}}function j(t){return"function"==typeof t&&/native code/.test(t.toString())}function L(t){la.push(t),ua.target=t}function M(){la.pop(),ua.target=la[la.length-1]}function $(t){return new fa(void 0,void 0,void 0,String(t))}function I(t){var e=new fa(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}function N(t){ya=t}function D(t,e){t.__proto__=e}function R(t,e,n){for(var r=0,i=n.length;r<i;r++){var o=n[r];S(t,o,e[o])}}function F(t,e){if(c(t)&&!(t instanceof fa)){var n;return y(t,"__ob__")&&t.__ob__ instanceof ga?n=t.__ob__:ya&&!ia()&&(Array.isArray(t)||u(t))&&Object.isExtensible(t)&&!t._isVue&&(n=new ga(t)),e&&n&&n.vmCount++,n}}function B(t,e,n,r,i){var o=new ua,a=Object.getOwnPropertyDescriptor(t,e);if(!a||!1!==a.configurable){var s=a&&a.get,c=a&&a.set;s&&!c||2!==arguments.length||(n=t[e]);var u=!i&&F(n);Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var e=s?s.call(t):n;return ua.target&&(o.depend(),u&&(u.dep.depend(),Array.isArray(e)&&X(e))),e},set:function(e){var r=s?s.call(t):n;e===r||e!==e&&r!==r||s&&!c||(c?c.call(t,e):n=e,u=!i&&F(e),o.notify())}})}}function U(t,e,n){if(Array.isArray(t)&&f(e))return t.length=Math.max(t.length,e),t.splice(e,1,n),n;if(e in t&&!(e in Object.prototype))return t[e]=n,n;var r=t.__ob__;return t._isVue||r&&r.vmCount?n:r?(B(r.value,e,n),r.dep.notify(),n):(t[e]=n,n)}function H(t,e){if(Array.isArray(t)&&f(e))return void t.splice(e,1);var n=t.__ob__;t._isVue||n&&n.vmCount||y(t,e)&&(delete t[e],n&&n.dep.notify())}function X(t){for(var e=void 0,n=0,r=t.length;n<r;n++)e=t[n],e&&e.__ob__&&e.__ob__.dep.depend(),Array.isArray(e)&&X(e)}function z(t,e){if(!e)return t;for(var n,r,i,o=aa?Reflect.ownKeys(e):Object.keys(e),a=0;a<o.length;a++)"__ob__"!==(n=o[a])&&(r=t[n],i=e[n],y(t,n)?r!==i&&u(r)&&u(i)&&z(r,i):U(t,n,i));return t}function Y(t,e,n){return n?function(){var r="function"==typeof e?e.call(n,n):e,i="function"==typeof t?t.call(n,n):t;return r?z(r,i):i}:e?t?function(){return z("function"==typeof e?e.call(this,this):e,"function"==typeof t?t.call(this,this):t)}:e:t}function q(t,e){var n=e?t?t.concat(e):Array.isArray(e)?e:[e]:t;return n?V(n):n}function V(t){for(var e=[],n=0;n<t.length;n++)-1===e.indexOf(t[n])&&e.push(t[n]);return e}function W(t,e,n,r){var i=Object.create(t||null);return e?_(i,e):i}function G(t,e){var n=t.props;if(n){var r,i,o,a={};if(Array.isArray(n))for(r=n.length;r--;)"string"==typeof(i=n[r])&&(o=Po(i),a[o]={type:null});else if(u(n))for(var s in n)i=n[s],o=Po(s),a[o]=u(i)?i:{type:i};t.props=a}}function K(t,e){var n=t.inject;if(n){var r=t.inject={};if(Array.isArray(n))for(var i=0;i<n.length;i++)r[n[i]]={from:n[i]};else if(u(n))for(var o in n){var a=n[o];r[o]=u(a)?_({from:o},a):{from:a}}}}function J(t){var e=t.directives;if(e)for(var n in e){var r=e[n];"function"==typeof r&&(e[n]={bind:r,update:r})}}function Q(t,e,n){function r(r){var i=ba[r]||xa;s[r]=i(t[r],e[r],n,r)}if("function"==typeof e&&(e=e.options),G(e,n),K(e,n),J(e),!e._base&&(e.extends&&(t=Q(t,e.extends,n)),e.mixins))for(var i=0,o=e.mixins.length;i<o;i++)t=Q(t,e.mixins[i],n);var a,s={};for(a in t)r(a);for(a in e)y(t,a)||r(a);return s}function Z(t,e,n,r){if("string"==typeof n){var i=t[e];if(y(i,n))return i[n];var o=Po(n);if(y(i,o))return i[o];var a=jo(o);return y(i,a)?i[a]:i[n]||i[o]||i[a]}}function tt(t,e,n,r){var i=e[t],o=!y(n,t),a=n[t],s=it(Boolean,i.type);if(s>-1)if(o&&!y(i,"default"))a=!1;else if(""===a||a===Mo(t)){var c=it(String,i.type);(c<0||s<c)&&(a=!0)}if(void 0===a){a=et(r,i,t);var u=ya;N(!0),F(a),N(u)}return a}function et(t,e,n){if(y(e,"default")){var r=e.default;return t&&t.$options.propsData&&void 0===t.$options.propsData[n]&&void 0!==t._props[n]?t._props[n]:"function"==typeof r&&"Function"!==nt(e.type)?r.call(t):r}}function nt(t){var e=t&&t.toString().match(_a);return e?e[1]:""}function rt(t,e){return nt(t)===nt(e)}function it(t,e){if(!Array.isArray(e))return rt(e,t)?0:-1;for(var n=0,r=e.length;n<r;n++)if(rt(e[n],t))return n;return-1}function ot(t,e,n){L();try{if(e)for(var r=e;r=r.$parent;){var i=r.$options.errorCaptured;if(i)for(var o=0;o<i.length;o++)try{var a=!1===i[o].call(r,t,e,n);if(a)return}catch(t){st(t,r,"errorCaptured hook")}}st(t,e,n)}finally{M()}}function at(t,e,n,r,i){var o;try{(o=n?t.apply(e,n):t.call(e))&&!o._isVue&&p(o)&&!o._handled&&(o.catch(function(t){return ot(t,r,i+" (Promise/async)")}),o._handled=!0)}catch(t){ot(t,r,i)}return o}function st(t,e,n){if(Bo.errorHandler)try{return Bo.errorHandler.call(null,t,e,n)}catch(e){e!==t&&ct(e,null,"config.errorHandler")}ct(t,e,n)}function ct(t,e,n){if(!zo&&!Yo||"undefined"==typeof console)throw t;console.error(t)}function ut(){Oa=!1;var t=Ta.slice(0);Ta.length=0;for(var e=0;e<t.length;e++)t[e]()}function lt(t,e){var n;if(Ta.push(function(){if(t)try{t.call(e)}catch(t){ot(t,e,"nextTick")}else n&&n(e)}),Oa||(Oa=!0,wa()),!t&&"undefined"!=typeof Promise)return new Promise(function(t){n=t})}function ft(t){pt(t,Pa),Pa.clear()}function pt(t,e){var n,r,i=Array.isArray(t);if(!(!i&&!c(t)||Object.isFrozen(t)||t instanceof fa)){if(t.__ob__){var o=t.__ob__.dep.id;if(e.has(o))return;e.add(o)}if(i)for(n=t.length;n--;)pt(t[n],e);else for(r=Object.keys(t),n=r.length;n--;)pt(t[r[n]],e)}}function dt(t,e){function n(){var t=arguments,r=n.fns;if(!Array.isArray(r))return at(r,null,arguments,e,"v-on handler");for(var i=r.slice(),o=0;o<i.length;o++)at(i[o],null,t,e,"v-on handler")}return n.fns=t,n}function ht(t,e,n,i,a,s){var c,u,l,f;for(c in t)u=t[c],l=e[c],f=ja(c),r(u)||(r(l)?(r(u.fns)&&(u=t[c]=dt(u,s)),o(f.once)&&(u=t[c]=a(f.name,u,f.capture)),n(f.name,u,f.capture,f.passive,f.params)):u!==l&&(l.fns=u,t[c]=l));for(c in e)r(t[c])&&(f=ja(c),i(f.name,e[c],f.capture))}function vt(t,e,n){function a(){n.apply(this,arguments),m(s.fns,a)}t instanceof fa&&(t=t.data.hook||(t.data.hook={}));var s,c=t[e];r(c)?s=dt([a]):i(c.fns)&&o(c.merged)?(s=c,s.fns.push(a)):s=dt([c,a]),s.merged=!0,t[e]=s}function mt(t,e,n){var o=e.options.props;if(!r(o)){var a={},s=t.attrs,c=t.props;if(i(s)||i(c))for(var u in o){var l=Mo(u);yt(a,c,u,l,!0)||yt(a,s,u,l,!1)}return a}}function yt(t,e,n,r,o){if(i(e)){if(y(e,n))return t[n]=e[n],o||delete e[n],!0;if(y(e,r))return t[n]=e[r],o||delete e[r],!0}return!1}function gt(t){for(var e=0;e<t.length;e++)if(Array.isArray(t[e]))return Array.prototype.concat.apply([],t);return t}function bt(t){return s(t)?[$(t)]:Array.isArray(t)?xt(t):void 0}function wt(t){return i(t)&&i(t.text)&&a(t.isComment)}function xt(t,e){var n,a,c,u,l=[];for(n=0;n<t.length;n++)a=t[n],r(a)||"boolean"==typeof a||(c=l.length-1,u=l[c],Array.isArray(a)?a.length>0&&(a=xt(a,(e||"")+"_"+n),wt(a[0])&&wt(u)&&(l[c]=$(u.text+a[0].text),a.shift()),l.push.apply(l,a)):s(a)?wt(u)?l[c]=$(u.text+a):""!==a&&l.push($(a)):wt(a)&&wt(u)?l[c]=$(u.text+a.text):(o(t._isVList)&&i(a.tag)&&r(a.key)&&i(e)&&(a.key="__vlist"+e+"_"+n+"__"),l.push(a)));return l}function _t(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}function kt(t){var e=Tt(t.$options.inject,t);e&&(N(!1),Object.keys(e).forEach(function(n){B(t,n,e[n])}),N(!0))}function Tt(t,e){if(t){for(var n=Object.create(null),r=aa?Reflect.ownKeys(t):Object.keys(t),i=0;i<r.length;i++){var o=r[i];if("__ob__"!==o){for(var a=t[o].from,s=e;s;){if(s._provided&&y(s._provided,a)){n[o]=s._provided[a];break}s=s.$parent}if(!s&&"default"in t[o]){var c=t[o].default;n[o]="function"==typeof c?c.call(e):c}}}return n}}function Ot(t,e){if(!t||!t.length)return{};for(var n={},r=0,i=t.length;r<i;r++){var o=t[r],a=o.data;if(a&&a.attrs&&a.attrs.slot&&delete a.attrs.slot,o.context!==e&&o.fnContext!==e||!a||null==a.slot)(n.default||(n.default=[])).push(o);else{var s=a.slot,c=n[s]||(n[s]=[]);"template"===o.tag?c.push.apply(c,o.children||[]):c.push(o)}}for(var u in n)n[u].every(At)&&delete n[u];return n}function At(t){return t.isComment&&!t.asyncFactory||" "===t.text}function Ct(t){return t.isComment&&t.asyncFactory}function Et(t,e,n){var r,i=Object.keys(e).length>0,o=t?!!t.$stable:!i,a=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(o&&n&&n!==To&&a===n.$key&&!i&&!n.$hasNormal)return n;r={};for(var s in t)t[s]&&"$"!==s[0]&&(r[s]=St(e,s,t[s]))}else r={};for(var c in e)c in r||(r[c]=Pt(e,c));return t&&Object.isExtensible(t)&&(t._normalized=r),S(r,"$stable",o),S(r,"$key",a),S(r,"$hasNormal",i),r}function St(t,e,n){var r=function(){var t=arguments.length?n.apply(null,arguments):n({});t=t&&"object"==typeof t&&!Array.isArray(t)?[t]:bt(t);var e=t&&t[0];return t&&(!e||1===t.length&&e.isComment&&!Ct(e))?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:r,enumerable:!0,configurable:!0}),r}function Pt(t,e){return function(){return t[e]}}function jt(t,e){var n,r,o,a,s;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,o=t.length;r<o;r++)n[r]=e(t[r],r);else if("number"==typeof t)for(n=new Array(t),r=0;r<t;r++)n[r]=e(r+1,r);else if(c(t))if(aa&&t[Symbol.iterator]){n=[];for(var u=t[Symbol.iterator](),l=u.next();!l.done;)n.push(e(l.value,n.length)),l=u.next()}else for(a=Object.keys(t),n=new Array(a.length),r=0,o=a.length;r<o;r++)s=a[r],n[r]=e(t[s],s,r);return i(n)||(n=[]),n._isVList=!0,n}function Lt(t,e,n,r){var i,o=this.$scopedSlots[t];o?(n=n||{},r&&(n=_(_({},r),n)),i=o(n)||("function"==typeof e?e():e)):i=this.$slots[t]||("function"==typeof e?e():e);var a=n&&n.slot;return a?this.$createElement("template",{slot:a},i):i}function Mt(t){return Z(this.$options,"filters",t,!0)||No}function $t(t,e){return Array.isArray(t)?-1===t.indexOf(e):t!==e}function It(t,e,n,r,i){var o=Bo.keyCodes[e]||n;return i&&r&&!Bo.keyCodes[e]?$t(i,r):o?$t(o,t):r?Mo(r)!==e:void 0===t}function Nt(t,e,n,r,i){if(n&&c(n)){Array.isArray(n)&&(n=k(n));var o;for(var a in n)!function(a){if("class"===a||"style"===a||Co(a))o=t;else{var s=t.attrs&&t.attrs.type;o=r||Bo.mustUseProp(e,s,a)?t.domProps||(t.domProps={}):t.attrs||(t.attrs={})}var c=Po(a),u=Mo(a);c in o||u in o||(o[a]=n[a],!i)||((t.on||(t.on={}))["update:"+a]=function(t){n[a]=t})}(a)}return t}function Dt(t,e){var n=this._staticTrees||(this._staticTrees=[]),r=n[t];return r&&!e?r:(r=n[t]=this.$options.staticRenderFns[t].call(this._renderProxy,null,this),Ft(r,"__static__"+t,!1),r)}function Rt(t,e,n){return Ft(t,"__once__"+e+(n?"_"+n:""),!0),t}function Ft(t,e,n){if(Array.isArray(t))for(var r=0;r<t.length;r++)t[r]&&"string"!=typeof t[r]&&Bt(t[r],e+"_"+r,n);else Bt(t,e,n)}function Bt(t,e,n){t.isStatic=!0,t.key=e,t.isOnce=n}function Ut(t,e){if(e&&u(e)){var n=t.on=t.on?_({},t.on):{};for(var r in e){var i=n[r],o=e[r];n[r]=i?[].concat(i,o):o}}return t}function Ht(t,e,n,r){e=e||{$stable:!n};for(var i=0;i<t.length;i++){var o=t[i];Array.isArray(o)?Ht(o,e,n):o&&(o.proxy&&(o.fn.proxy=!0),e[o.key]=o.fn)}return r&&(e.$key=r),e}function Xt(t,e){for(var n=0;n<e.length;n+=2){var r=e[n];"string"==typeof r&&r&&(t[e[n]]=e[n+1])}return t}function zt(t,e){return"string"==typeof t?e+t:t}function Yt(t){t._o=Rt,t._n=h,t._s=d,t._l=jt,t._t=Lt,t._q=O,t._i=A,t._m=Dt,t._f=Mt,t._k=It,t._b=Nt,t._v=$,t._e=da,t._u=Ht,t._g=Ut,t._d=Xt,t._p=zt}function qt(t,e,n,r,i){var a,s=this,c=i.options;y(r,"_uid")?(a=Object.create(r),a._original=r):(a=r,r=r._original);var u=o(c._compiled),l=!u;this.data=t,this.props=e,this.children=n,this.parent=r,this.listeners=t.on||To,this.injections=Tt(c.inject,r),this.slots=function(){return s.$slots||Et(t.scopedSlots,s.$slots=Ot(n,r)),s.$slots},Object.defineProperty(this,"scopedSlots",{enumerable:!0,get:function(){return Et(t.scopedSlots,this.slots())}}),u&&(this.$options=c,this.$slots=this.slots(),this.$scopedSlots=Et(t.scopedSlots,this.$slots)),c._scopeId?this._c=function(t,e,n,i){var o=ee(a,t,e,n,i,l);return o&&!Array.isArray(o)&&(o.fnScopeId=c._scopeId,o.fnContext=r),o}:this._c=function(t,e,n,r){return ee(a,t,e,n,r,l)}}function Vt(t,e,n,r,o){var a=t.options,s={},c=a.props;if(i(c))for(var u in c)s[u]=tt(u,c,e||To);else i(n.attrs)&&Gt(s,n.attrs),i(n.props)&&Gt(s,n.props);var l=new qt(n,s,o,r,t),f=a.render.call(null,l._c,l);if(f instanceof fa)return Wt(f,n,l.parent,a,l);if(Array.isArray(f)){for(var p=bt(f)||[],d=new Array(p.length),h=0;h<p.length;h++)d[h]=Wt(p[h],n,l.parent,a,l);return d}}function Wt(t,e,n,r,i){var o=I(t);return o.fnContext=n,o.fnOptions=r,e.slot&&((o.data||(o.data={})).slot=e.slot),o}function Gt(t,e){for(var n in e)t[Po(n)]=e[n]}function Kt(t,e,n,a,s){if(!r(t)){var u=n.$options._base;if(c(t)&&(t=u.extend(t)),"function"==typeof t){var l;if(r(t.cid)&&(l=t,void 0===(t=ce(l,u))))return se(l,e,n,a,s);e=e||{},He(t),i(e.model)&&te(t.options,e);var f=mt(e,t,s);if(o(t.options.functional))return Vt(t,f,e,n,a);var p=e.on;if(e.on=e.nativeOn,o(t.options.abstract)){var d=e.slot;e={},d&&(e.slot=d)}Qt(e);var h=t.options.name||s;return new fa("vue-component-"+t.cid+(h?"-"+h:""),e,void 0,void 0,void 0,n,{Ctor:t,propsData:f,listeners:p,tag:s,children:a},l)}}}function Jt(t,e){var n={_isComponent:!0,_parentVnode:t,parent:e},r=t.data.inlineTemplate;return i(r)&&(n.render=r.render,n.staticRenderFns=r.staticRenderFns),new t.componentOptions.Ctor(n)}function Qt(t){for(var e=t.hook||(t.hook={}),n=0;n<$a.length;n++){var r=$a[n],i=e[r],o=Ma[r];i===o||i&&i._merged||(e[r]=i?Zt(o,i):o)}}function Zt(t,e){var n=function(n,r){t(n,r),e(n,r)};return n._merged=!0,n}function te(t,e){var n=t.model&&t.model.prop||"value",r=t.model&&t.model.event||"input";(e.attrs||(e.attrs={}))[n]=e.model.value;var o=e.on||(e.on={}),a=o[r],s=e.model.callback;i(a)?(Array.isArray(a)?-1===a.indexOf(s):a!==s)&&(o[r]=[s].concat(a)):o[r]=s}function ee(t,e,n,r,i,a){return(Array.isArray(n)||s(n))&&(i=r,r=n,n=void 0),o(a)&&(i=Na),ne(t,e,n,r,i)}function ne(t,e,n,r,o){if(i(n)&&i(n.__ob__))return da();if(i(n)&&i(n.is)&&(e=n.is),!e)return da();Array.isArray(r)&&"function"==typeof r[0]&&(n=n||{},n.scopedSlots={default:r[0]},r.length=0),o===Na?r=bt(r):o===Ia&&(r=gt(r));var a,s;if("string"==typeof e){var c;s=t.$vnode&&t.$vnode.ns||Bo.getTagNamespace(e),a=Bo.isReservedTag(e)?new fa(Bo.parsePlatformTagName(e),n,r,void 0,void 0,t):n&&n.pre||!i(c=Z(t.$options,"components",e))?new fa(e,n,r,void 0,void 0,t):Kt(c,n,t,r,e)}else a=Kt(e,n,t,r);return Array.isArray(a)?a:i(a)?(i(s)&&re(a,s),i(n)&&ie(n),a):da()}function re(t,e,n){if(t.ns=e,"foreignObject"===t.tag&&(e=void 0,n=!0),i(t.children))for(var a=0,s=t.children.length;a<s;a++){var c=t.children[a];i(c.tag)&&(r(c.ns)||o(n)&&"svg"!==c.tag)&&re(c,e,n)}}function ie(t){c(t.style)&&ft(t.style),c(t.class)&&ft(t.class)}function oe(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,r=n&&n.context;t.$slots=Ot(e._renderChildren,r),t.$scopedSlots=To,t._c=function(e,n,r,i){return ee(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return ee(t,e,n,r,i,!0)};var i=n&&n.data;B(t,"$attrs",i&&i.attrs||To,null,!0),B(t,"$listeners",e._parentListeners||To,null,!0)}function ae(t,e){return(t.__esModule||aa&&"Module"===t[Symbol.toStringTag])&&(t=t.default),c(t)?e.extend(t):t}function se(t,e,n,r,i){var o=da();return o.asyncFactory=t,o.asyncMeta={data:e,context:n,children:r,tag:i},o}function ce(t,e){if(o(t.error)&&i(t.errorComp))return t.errorComp;if(i(t.resolved))return t.resolved;var n=Da;if(n&&i(t.owners)&&-1===t.owners.indexOf(n)&&t.owners.push(n),o(t.loading)&&i(t.loadingComp))return t.loadingComp;if(n&&!i(t.owners)){var a=t.owners=[n],s=!0,u=null,l=null;n.$on("hook:destroyed",function(){return m(a,n)});var f=function(t){for(var e=0,n=a.length;e<n;e++)a[e].$forceUpdate();t&&(a.length=0,null!==u&&(clearTimeout(u),u=null),null!==l&&(clearTimeout(l),l=null))},d=C(function(n){t.resolved=ae(n,e),s?a.length=0:f(!0)}),h=C(function(e){i(t.errorComp)&&(t.error=!0,f(!0))}),v=t(d,h);return c(v)&&(p(v)?r(t.resolved)&&v.then(d,h):p(v.component)&&(v.component.then(d,h),i(v.error)&&(t.errorComp=ae(v.error,e)),i(v.loading)&&(t.loadingComp=ae(v.loading,e),0===v.delay?t.loading=!0:u=setTimeout(function(){u=null,r(t.resolved)&&r(t.error)&&(t.loading=!0,f(!1))},v.delay||200)),i(v.timeout)&&(l=setTimeout(function(){l=null,r(t.resolved)&&h(null)},v.timeout)))),s=!1,t.loading?t.loadingComp:t.resolved}}function ue(t){if(Array.isArray(t))for(var e=0;e<t.length;e++){var n=t[e];if(i(n)&&(i(n.componentOptions)||Ct(n)))return n}}function le(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&he(t,e)}function fe(t,e){La.$on(t,e)}function pe(t,e){La.$off(t,e)}function de(t,e){var n=La;return function r(){null!==e.apply(null,arguments)&&n.$off(t,r)}}function he(t,e,n){La=t,ht(e,n||{},fe,pe,de,t),La=void 0}function ve(t){var e=Ra;return Ra=t,function(){Ra=e}}function me(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}function ye(t,e,n){t.$el=e,t.$options.render||(t.$options.render=da),_e(t,"beforeMount");var r;return r=function(){t._update(t._render(),n)},new Ga(t,r,T,{before:function(){t._isMounted&&!t._isDestroyed&&_e(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,_e(t,"mounted")),t}function ge(t,e,n,r,i){var o=r.data.scopedSlots,a=t.$scopedSlots,s=!!(o&&!o.$stable||a!==To&&!a.$stable||o&&t.$scopedSlots.$key!==o.$key||!o&&t.$scopedSlots.$key),c=!!(i||t.$options._renderChildren||s);if(t.$options._parentVnode=r,t.$vnode=r,t._vnode&&(t._vnode.parent=r),t.$options._renderChildren=i,t.$attrs=r.data.attrs||To,t.$listeners=n||To,e&&t.$options.props){N(!1);for(var u=t._props,l=t.$options._propKeys||[],f=0;f<l.length;f++){var p=l[f],d=t.$options.props;u[p]=tt(p,d,e,t)}N(!0),t.$options.propsData=e}n=n||To;var h=t.$options._parentListeners;t.$options._parentListeners=n,he(t,n,h),c&&(t.$slots=Ot(i,r.context),t.$forceUpdate())}function be(t){for(;t&&(t=t.$parent);)if(t._inactive)return!0;return!1}function we(t,e){if(e){if(t._directInactive=!1,be(t))return}else if(t._directInactive)return;if(t._inactive||null===t._inactive){t._inactive=!1;for(var n=0;n<t.$children.length;n++)we(t.$children[n]);_e(t,"activated")}}function xe(t,e){if(!(e&&(t._directInactive=!0,be(t))||t._inactive)){t._inactive=!0;for(var n=0;n<t.$children.length;n++)xe(t.$children[n]);_e(t,"deactivated")}}function _e(t,e){L();var n=t.$options[e],r=e+" hook";if(n)for(var i=0,o=n.length;i<o;i++)at(n[i],t,null,t,r);t._hasHookEvent&&t.$emit("hook:"+e),M()}function ke(){za=Fa.length=Ba.length=0,Ua={},Ha=Xa=!1}function Te(){Ya=qa(),Xa=!0;var t,e;for(Fa.sort(function(t,e){return t.id-e.id}),za=0;za<Fa.length;za++)t=Fa[za],t.before&&t.before(),e=t.id,Ua[e]=null,t.run();var n=Ba.slice(),r=Fa.slice();ke(),Ce(n),Oe(r),oa&&Bo.devtools&&oa.emit("flush")}function Oe(t){for(var e=t.length;e--;){var n=t[e],r=n.vm;r._watcher===n&&r._isMounted&&!r._isDestroyed&&_e(r,"updated")}}function Ae(t){t._inactive=!1,Ba.push(t)}function Ce(t){for(var e=0;e<t.length;e++)t[e]._inactive=!0,we(t[e],!0)}function Ee(t){var e=t.id;if(null==Ua[e]){if(Ua[e]=!0,Xa){for(var n=Fa.length-1;n>za&&Fa[n].id>t.id;)n--;Fa.splice(n+1,0,t)}else Fa.push(t);Ha||(Ha=!0,lt(Te))}}function Se(t,e,n){Ka.get=function(){return this[e][n]},Ka.set=function(t){this[e][n]=t},Object.defineProperty(t,n,Ka)}function Pe(t){t._watchers=[];var e=t.$options;e.props&&je(t,e.props),e.methods&&Re(t,e.methods),e.data?Le(t):F(t._data={},!0),e.computed&&$e(t,e.computed),e.watch&&e.watch!==Zo&&Fe(t,e.watch)}function je(t,e){var n=t.$options.propsData||{},r=t._props={},i=t.$options._propKeys=[];!t.$parent||N(!1);for(var o in e)!function(o){i.push(o);var a=tt(o,e,n,t);B(r,o,a),o in t||Se(t,"_props",o)}(o);N(!0)}function Le(t){var e=t.$options.data;e=t._data="function"==typeof e?Me(e,t):e||{},u(e)||(e={});for(var n=Object.keys(e),r=t.$options.props,i=(t.$options.methods,n.length);i--;){var o=n[i];r&&y(r,o)||E(o)||Se(t,"_data",o)}F(e,!0)}function Me(t,e){L();try{return t.call(e,e)}catch(t){return ot(t,e,"data()"),{}}finally{M()}}function $e(t,e){var n=t._computedWatchers=Object.create(null),r=ia();for(var i in e){var o=e[i],a="function"==typeof o?o:o.get;r||(n[i]=new Ga(t,a||T,T,Ja)),i in t||Ie(t,i,o)}}function Ie(t,e,n){var r=!ia();"function"==typeof n?(Ka.get=r?Ne(e):De(n),Ka.set=T):(Ka.get=n.get?r&&!1!==n.cache?Ne(e):De(n.get):T,Ka.set=n.set||T),Object.defineProperty(t,e,Ka)}function Ne(t){return function(){var e=this._computedWatchers&&this._computedWatchers[t];if(e)return e.dirty&&e.evaluate(),ua.target&&e.depend(),e.value}}function De(t){return function(){return t.call(this,this)}}function Re(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?T:$o(e[n],t)}function Fe(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var i=0;i<r.length;i++)Be(t,n,r[i]);else Be(t,n,r)}}function Be(t,e,n,r){return u(n)&&(r=n,n=n.handler),"string"==typeof n&&(n=t[n]),t.$watch(e,n,r)}function Ue(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}function He(t){var e=t.options;if(t.super){var n=He(t.super);if(n!==t.superOptions){t.superOptions=n;var r=Xe(t);r&&_(t.extendOptions,r),e=t.options=Q(n,t.extendOptions),e.name&&(e.components[e.name]=t)}}return e}function Xe(t){var e,n=t.options,r=t.sealedOptions;for(var i in n)n[i]!==r[i]&&(e||(e={}),e[i]=n[i]);return e}function ze(t){this._init(t)}function Ye(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=x(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}function qe(t){t.mixin=function(t){return this.options=Q(this.options,t),this}}function Ve(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i[r])return i[r];var o=t.name||n.options.name,a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=Q(n.options,t),a.super=n,a.options.props&&We(a),a.options.computed&&Ge(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,Ro.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=_({},a.options),i[r]=a,a}}function We(t){var e=t.options.props;for(var n in e)Se(t.prototype,"_props",n)}function Ge(t){var e=t.options.computed;for(var n in e)Ie(t.prototype,n,e[n])}function Ke(t){Ro.forEach(function(e){t[e]=function(t,n){return n?("component"===e&&u(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}})}function Je(t){return t&&(t.Ctor.options.name||t.tag)}function Qe(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!l(t)&&t.test(e)}function Ze(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var s=a.name;s&&!e(s)&&tn(n,o,r,i)}}}function tn(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,m(n,e)}function en(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=nn(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=nn(e,n.data));return rn(e.staticClass,e.class)}function nn(t,e){return{staticClass:on(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function rn(t,e){return i(t)||i(e)?on(t,an(e)):""}function on(t,e){return t?e?t+" "+e:t:e||""}function an(t){return Array.isArray(t)?sn(t):c(t)?cn(t):"string"==typeof t?t:""}function sn(t){for(var e,n="",r=0,o=t.length;r<o;r++)i(e=an(t[r]))&&""!==e&&(n&&(n+=" "),n+=e);return n}function cn(t){var e="";for(var n in t)t[n]&&(e&&(e+=" "),e+=n);return e}function un(t){return Os(t)?"svg":"math"===t?"math":void 0}function ln(t){if(!zo)return!0;if(Cs(t))return!1;if(t=t.toLowerCase(),null!=Es[t])return Es[t];var e=document.createElement(t);return t.indexOf("-")>-1?Es[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Es[t]=/HTMLUnknownElement/.test(e.toString())}function fn(t){if("string"==typeof t){return document.querySelector(t)||document.createElement("div")}return t}function pn(t,e){var n=document.createElement(t);return"select"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute("multiple","multiple"),n)}function dn(t,e){return document.createElementNS(ks[t],e)}function hn(t){return document.createTextNode(t)}function vn(t){return document.createComment(t)}function mn(t,e,n){t.insertBefore(e,n)}function yn(t,e){t.removeChild(e)}function gn(t,e){t.appendChild(e)}function bn(t){return t.parentNode}function wn(t){return t.nextSibling}function xn(t){return t.tagName}function _n(t,e){t.textContent=e}function kn(t,e){t.setAttribute(e,"")}function Tn(t,e){var n=t.data.ref;if(i(n)){var r=t.context,o=t.componentInstance||t.elm,a=r.$refs;e?Array.isArray(a[n])?m(a[n],o):a[n]===o&&(a[n]=void 0):t.data.refInFor?Array.isArray(a[n])?a[n].indexOf(o)<0&&a[n].push(o):a[n]=[o]:a[n]=o}}function On(t,e){return t.key===e.key&&t.asyncFactory===e.asyncFactory&&(t.tag===e.tag&&t.isComment===e.isComment&&i(t.data)===i(e.data)&&An(t,e)||o(t.isAsyncPlaceholder)&&r(e.asyncFactory.error))}function An(t,e){if("input"!==t.tag)return!0;var n,r=i(n=t.data)&&i(n=n.attrs)&&n.type,o=i(n=e.data)&&i(n=n.attrs)&&n.type;return r===o||Ss(r)&&Ss(o)}function Cn(t,e,n){var r,o,a={};for(r=e;r<=n;++r)o=t[r].key,i(o)&&(a[o]=r);return a}function En(t,e){(t.data.directives||e.data.directives)&&Sn(t,e)}function Sn(t,e){var n,r,i,o=t===Ls,a=e===Ls,s=Pn(t.data.directives,t.context),c=Pn(e.data.directives,e.context),u=[],l=[];for(n in c)r=s[n],i=c[n],r?(i.oldValue=r.value,i.oldArg=r.arg,Ln(i,"update",e,t),i.def&&i.def.componentUpdated&&l.push(i)):(Ln(i,"bind",e,t),i.def&&i.def.inserted&&u.push(i));if(u.length){var f=function(){for(var n=0;n<u.length;n++)Ln(u[n],"inserted",e,t)};o?vt(e,"insert",f):f()}if(l.length&&vt(e,"postpatch",function(){for(var n=0;n<l.length;n++)Ln(l[n],"componentUpdated",e,t)}),!o)for(n in s)c[n]||Ln(s[n],"unbind",t,t,a)}function Pn(t,e){var n=Object.create(null);if(!t)return n;var r,i;for(r=0;r<t.length;r++)i=t[r],i.modifiers||(i.modifiers=Is),n[jn(i)]=i,i.def=Z(e.$options,"directives",i.name,!0);return n}function jn(t){return t.rawName||t.name+"."+Object.keys(t.modifiers||{}).join(".")}function Ln(t,e,n,r,i){var o=t.def&&t.def[e];if(o)try{o(n.elm,t,n,r,i)}catch(r){ot(r,n.context,"directive "+t.name+" "+e+" hook")}}function Mn(t,e){var n=e.componentOptions;if(!(i(n)&&!1===n.Ctor.options.inheritAttrs||r(t.data.attrs)&&r(e.data.attrs))){var o,a,s=e.elm,c=t.data.attrs||{},u=e.data.attrs||{};i(u.__ob__)&&(u=e.data.attrs=_({},u));for(o in u)a=u[o],c[o]!==a&&$n(s,o,a,e.data.pre);(Wo||Ko)&&u.value!==c.value&&$n(s,"value",u.value);for(o in c)r(u[o])&&(ws(o)?s.removeAttributeNS(bs,xs(o)):vs(o)||s.removeAttribute(o))}}function $n(t,e,n,r){r||t.tagName.indexOf("-")>-1?In(t,e,n):gs(e)?_s(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):vs(e)?t.setAttribute(e,ys(e,n)):ws(e)?_s(n)?t.removeAttributeNS(bs,xs(e)):t.setAttributeNS(bs,e,n):In(t,e,n)}function In(t,e,n){if(_s(n))t.removeAttribute(e);else{if(Wo&&!Go&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}function Nn(t,e){var n=e.elm,o=e.data,a=t.data;if(!(r(o.staticClass)&&r(o.class)&&(r(a)||r(a.staticClass)&&r(a.class)))){var s=en(e),c=n._transitionClasses;i(c)&&(s=on(s,an(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}function Dn(t){function e(){(a||(a=[])).push(t.slice(h,i).trim()),h=i+1}var n,r,i,o,a,s=!1,c=!1,u=!1,l=!1,f=0,p=0,d=0,h=0;for(i=0;i<t.length;i++)if(r=n,n=t.charCodeAt(i),s)39===n&&92!==r&&(s=!1);else if(c)34===n&&92!==r&&(c=!1);else if(u)96===n&&92!==r&&(u=!1);else if(l)47===n&&92!==r&&(l=!1);else if(124!==n||124===t.charCodeAt(i+1)||124===t.charCodeAt(i-1)||f||p||d){switch(n){case 34:c=!0;break;case 39:s=!0;break;case 96:u=!0;break;case 40:d++;break;case 41:d--;break;case 91:p++;break;case 93:p--;break;case 123:f++;break;case 125:f--}if(47===n){for(var v=i-1,m=void 0;v>=0&&" "===(m=t.charAt(v));v--);m&&Fs.test(m)||(l=!0)}}else void 0===o?(h=i+1,o=t.slice(0,i).trim()):e();if(void 0===o?o=t.slice(0,i).trim():0!==h&&e(),a)for(i=0;i<a.length;i++)o=Rn(o,a[i]);return o}function Rn(t,e){var n=e.indexOf("(");if(n<0)return'_f("'+e+'")('+t+")";var r=e.slice(0,n),i=e.slice(n+1);return'_f("'+r+'")('+t+(")"!==i?","+i:i)}function Fn(t,e){console.error("[Vue compiler]: "+t)}function Bn(t,e){return t?t.map(function(t){return t[e]}).filter(function(t){return t}):[]}function Un(t,e,n,r,i){(t.props||(t.props=[])).push(Jn({name:e,value:n,dynamic:i},r)),t.plain=!1}function Hn(t,e,n,r,i){(i?t.dynamicAttrs||(t.dynamicAttrs=[]):t.attrs||(t.attrs=[])).push(Jn({name:e,value:n,dynamic:i},r)),t.plain=!1}function Xn(t,e,n,r){t.attrsMap[e]=n,t.attrsList.push(Jn({name:e,value:n},r))}function zn(t,e,n,r,i,o,a,s){(t.directives||(t.directives=[])).push(Jn({name:e,rawName:n,value:r,arg:i,isDynamicArg:o,modifiers:a},s)),t.plain=!1}function Yn(t,e,n){return n?"_p("+e+',"'+t+'")':t+e}function qn(t,e,n,r,i,o,a,s){r=r||To,r.right?s?e="("+e+")==='click'?'contextmenu':("+e+")":"click"===e&&(e="contextmenu",delete r.right):r.middle&&(s?e="("+e+")==='click'?'mouseup':("+e+")":"click"===e&&(e="mouseup")),r.capture&&(delete r.capture,e=Yn("!",e,s)),r.once&&(delete r.once,e=Yn("~",e,s)),r.passive&&(delete r.passive,e=Yn("&",e,s));var c;r.native?(delete r.native,c=t.nativeEvents||(t.nativeEvents={})):c=t.events||(t.events={});var u=Jn({value:n.trim(),dynamic:s},a);r!==To&&(u.modifiers=r);var l=c[e];Array.isArray(l)?i?l.unshift(u):l.push(u):c[e]=l?i?[u,l]:[l,u]:u,t.plain=!1}function Vn(t,e){return t.rawAttrsMap[":"+e]||t.rawAttrsMap["v-bind:"+e]||t.rawAttrsMap[e]}function Wn(t,e,n){var r=Gn(t,":"+e)||Gn(t,"v-bind:"+e);if(null!=r)return Dn(r);if(!1!==n){var i=Gn(t,e);if(null!=i)return JSON.stringify(i)}}function Gn(t,e,n){var r;if(null!=(r=t.attrsMap[e]))for(var i=t.attrsList,o=0,a=i.length;o<a;o++)if(i[o].name===e){i.splice(o,1);break}return n&&delete t.attrsMap[e],r}function Kn(t,e){for(var n=t.attrsList,r=0,i=n.length;r<i;r++){var o=n[r];if(e.test(o.name))return n.splice(r,1),o}}function Jn(t,e){return e&&(null!=e.start&&(t.start=e.start),null!=e.end&&(t.end=e.end)),t}function Qn(t,e,n){var r=n||{},i=r.number,o=r.trim,a="$$v";o&&(a="(typeof $$v === 'string'? $$v.trim(): $$v)"),i&&(a="_n("+a+")");var s=Zn(e,a);t.model={value:"("+e+")",expression:JSON.stringify(e),callback:"function ($$v) {"+s+"}"}}function Zn(t,e){var n=tr(t);return null===n.key?t+"="+e:"$set("+n.exp+", "+n.key+", "+e+")"}function tr(t){if(t=t.trim(),ns=t.length,t.indexOf("[")<0||t.lastIndexOf("]")<ns-1)return os=t.lastIndexOf("."),os>-1?{exp:t.slice(0,os),key:'"'+t.slice(os+1)+'"'}:{exp:t,key:null};for(rs=t,os=as=ss=0;!nr();)is=er(),rr(is)?or(is):91===is&&ir(is);return{exp:t.slice(0,as),key:t.slice(as+1,ss)}}function er(){return rs.charCodeAt(++os)}function nr(){return os>=ns}function rr(t){return 34===t||39===t}function ir(t){var e=1;for(as=os;!nr();)if(t=er(),rr(t))or(t);else if(91===t&&e++,93===t&&e--,0===e){ss=os;break}}function or(t){for(var e=t;!nr()&&(t=er())!==e;);}function ar(t,e,n){cs=n;var r=e.value,i=e.modifiers,o=t.tag,a=t.attrsMap.type;if(t.component)return Qn(t,r,i),!1;if("select"===o)ur(t,r,i);else if("input"===o&&"checkbox"===a)sr(t,r,i);else if("input"===o&&"radio"===a)cr(t,r,i);else if("input"===o||"textarea"===o)lr(t,r,i);else if(!Bo.isReservedTag(o))return Qn(t,r,i),!1;return!0}function sr(t,e,n){var r=n&&n.number,i=Wn(t,"value")||"null",o=Wn(t,"true-value")||"true",a=Wn(t,"false-value")||"false";Un(t,"checked","Array.isArray("+e+")?_i("+e+","+i+")>-1"+("true"===o?":("+e+")":":_q("+e+","+o+")")),qn(t,"change","var $$a="+e+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Zn(e,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Zn(e,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Zn(e,"$$c")+"}",null,!0)}function cr(t,e,n){var r=n&&n.number,i=Wn(t,"value")||"null";i=r?"_n("+i+")":i,Un(t,"checked","_q("+e+","+i+")"),qn(t,"change",Zn(e,i),null,!0)}function ur(t,e,n){var r=n&&n.number,i='Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = "_value" in o ? o._value : o.value;return '+(r?"_n(val)":"val")+"})",o="var $$selectedVal = "+i+";";o=o+" "+Zn(e,"$event.target.multiple ? $$selectedVal : $$selectedVal[0]"),qn(t,"change",o,null,!0)}function lr(t,e,n){var r=t.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?Bs:"input",l="$event.target.value";s&&(l="$event.target.value.trim()"),a&&(l="_n("+l+")");var f=Zn(e,l);c&&(f="if($event.target.composing)return;"+f),Un(t,"value","("+e+")"),qn(t,u,f,null,!0),(s||a)&&qn(t,"blur","$forceUpdate()")}function fr(t){if(i(t[Bs])){var e=Wo?"change":"input";t[e]=[].concat(t[Bs],t[e]||[]),delete t[Bs]}i(t[Us])&&(t.change=[].concat(t[Us],t.change||[]),delete t[Us])}function pr(t,e,n){var r=us;return function i(){null!==e.apply(null,arguments)&&hr(t,i,n,r)}}function dr(t,e,n,r){if(Hs){var i=Ya,o=e;e=o._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=i||t.timeStamp<=0||t.target.ownerDocument!==document)return o.apply(this,arguments)}}us.addEventListener(t,e,ta?{capture:n,passive:r}:n)}function hr(t,e,n,r){(r||us).removeEventListener(t,e._wrapper||e,n)}function vr(t,e){if(!r(t.data.on)||!r(e.data.on)){var n=e.data.on||{},i=t.data.on||{};us=e.elm,fr(n),ht(n,i,dr,hr,pr,e.context),us=void 0}}function mr(t,e){if(!r(t.data.domProps)||!r(e.data.domProps)){var n,o,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};i(c.__ob__)&&(c=e.data.domProps=_({},c));for(n in s)n in c||(a[n]="");for(n in c){if(o=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),o===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n&&"PROGRESS"!==a.tagName){a._value=o;var u=r(o)?"":String(o);yr(a,u)&&(a.value=u)}else if("innerHTML"===n&&Os(a.tagName)&&r(a.innerHTML)){ls=ls||document.createElement("div"),ls.innerHTML="<svg>"+o+"</svg>";for(var l=ls.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else if(o!==s[n])try{a[n]=o}catch(t){}}}}function yr(t,e){return!t.composing&&("OPTION"===t.tagName||gr(t,e)||br(t,e))}function gr(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}function br(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.number)return h(n)!==h(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}function wr(t){var e=xr(t.style);return t.staticStyle?_(t.staticStyle,e):e}function xr(t){return Array.isArray(t)?k(t):"string"==typeof t?Ys(t):t}function _r(t,e){var n,r={};if(e)for(var i=t;i.componentInstance;)(i=i.componentInstance._vnode)&&i.data&&(n=wr(i.data))&&_(r,n);(n=wr(t.data))&&_(r,n);for(var o=t;o=o.parent;)o.data&&(n=wr(o.data))&&_(r,n);return r}function kr(t,e){var n=e.data,o=t.data;if(!(r(n.staticStyle)&&r(n.style)&&r(o.staticStyle)&&r(o.style))){var a,s,c=e.elm,u=o.staticStyle,l=o.normalizedStyle||o.style||{},f=u||l,p=xr(e.data.style)||{};e.data.normalizedStyle=i(p.__ob__)?_({},p):p;var d=_r(e,!0);for(s in f)r(d[s])&&Ws(c,s,"");for(s in d)(a=d[s])!==f[s]&&Ws(c,s,null==a?"":a)}}function Tr(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Qs).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Or(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Qs).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");n=n.trim(),n?t.setAttribute("class",n):t.removeAttribute("class")}}function Ar(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&_(e,Zs(t.name||"v")),_(e,t),e}return"string"==typeof t?Zs(t):void 0}}function Cr(t){sc(function(){sc(t)})}function Er(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Tr(t,e))}function Sr(t,e){t._transitionClasses&&m(t._transitionClasses,e),Or(t,e)}function Pr(t,e,n){var r=jr(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===ec?ic:ac,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c<a&&u()},o+1),t.addEventListener(s,l)}function jr(t,e){var n,r=window.getComputedStyle(t),i=(r[rc+"Delay"]||"").split(", "),o=(r[rc+"Duration"]||"").split(", "),a=Lr(i,o),s=(r[oc+"Delay"]||"").split(", "),c=(r[oc+"Duration"]||"").split(", "),u=Lr(s,c),l=0,f=0;return e===ec?a>0&&(n=ec,l=a,f=o.length):e===nc?u>0&&(n=nc,l=u,f=c.length):(l=Math.max(a,u),n=l>0?a>u?ec:nc:null,f=n?n===ec?o.length:c.length:0),{type:n,timeout:l,propCount:f,hasTransform:n===ec&&cc.test(r[rc+"Property"])}}function Lr(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max.apply(null,e.map(function(e,n){return Mr(e)+Mr(t[n])}))}function Mr(t){return 1e3*Number(t.slice(0,-1).replace(",","."))}function $r(t,e){var n=t.elm;i(n._leaveCb)&&(n._leaveCb.cancelled=!0,n._leaveCb());var o=Ar(t.data.transition);if(!r(o)&&!i(n._enterCb)&&1===n.nodeType){for(var a=o.css,s=o.type,u=o.enterClass,l=o.enterToClass,f=o.enterActiveClass,p=o.appearClass,d=o.appearToClass,v=o.appearActiveClass,m=o.beforeEnter,y=o.enter,g=o.afterEnter,b=o.enterCancelled,w=o.beforeAppear,x=o.appear,_=o.afterAppear,k=o.appearCancelled,T=o.duration,O=Ra,A=Ra.$vnode;A&&A.parent;)O=A.context,A=A.parent;var E=!O._isMounted||!t.isRootInsert;if(!E||x||""===x){var S=E&&p?p:u,P=E&&v?v:f,j=E&&d?d:l,L=E?w||m:m,M=E&&"function"==typeof x?x:y,$=E?_||g:g,I=E?k||b:b,N=h(c(T)?T.enter:T),D=!1!==a&&!Go,R=Dr(M),F=n._enterCb=C(function(){D&&(Sr(n,j),Sr(n,P)),F.cancelled?(D&&Sr(n,S),I&&I(n)):$&&$(n),n._enterCb=null});t.data.show||vt(t,"insert",function(){var e=n.parentNode,r=e&&e._pending&&e._pending[t.key];r&&r.tag===t.tag&&r.elm._leaveCb&&r.elm._leaveCb(),M&&M(n,F)}),L&&L(n),D&&(Er(n,S),Er(n,P),Cr(function(){Sr(n,S),F.cancelled||(Er(n,j),R||(Nr(N)?setTimeout(F,N):Pr(n,s,F)))})),t.data.show&&(e&&e(),M&&M(n,F)),D||R||F()}}}function Ir(t,e){function n(){k.cancelled||(!t.data.show&&o.parentNode&&((o.parentNode._pending||(o.parentNode._pending={}))[t.key]=t),d&&d(o),w&&(Er(o,l),Er(o,p),Cr(function(){Sr(o,l),k.cancelled||(Er(o,f),x||(Nr(_)?setTimeout(k,_):Pr(o,u,k)))})),v&&v(o,k),w||x||k())}var o=t.elm;i(o._enterCb)&&(o._enterCb.cancelled=!0,o._enterCb());var a=Ar(t.data.transition);if(r(a)||1!==o.nodeType)return e();if(!i(o._leaveCb)){var s=a.css,u=a.type,l=a.leaveClass,f=a.leaveToClass,p=a.leaveActiveClass,d=a.beforeLeave,v=a.leave,m=a.afterLeave,y=a.leaveCancelled,g=a.delayLeave,b=a.duration,w=!1!==s&&!Go,x=Dr(v),_=h(c(b)?b.leave:b),k=o._leaveCb=C(function(){o.parentNode&&o.parentNode._pending&&(o.parentNode._pending[t.key]=null),w&&(Sr(o,f),Sr(o,p)),k.cancelled?(w&&Sr(o,l),y&&y(o)):(e(),m&&m(o)),o._leaveCb=null});g?g(n):n()}}function Nr(t){return"number"==typeof t&&!isNaN(t)}function Dr(t){if(r(t))return!1;var e=t.fns;return i(e)?Dr(Array.isArray(e)?e[0]:e):(t._length||t.length)>1}function Rr(t,e){!0!==e.data.show&&$r(e)}function Fr(t,e,n){Br(t,e,n),(Wo||Ko)&&setTimeout(function(){Br(t,e,n)},0)}function Br(t,e,n){var r=e.value,i=t.multiple;if(!i||Array.isArray(r)){for(var o,a,s=0,c=t.options.length;s<c;s++)if(a=t.options[s],i)o=A(r,Hr(a))>-1,a.selected!==o&&(a.selected=o);else if(O(Hr(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));i||(t.selectedIndex=-1)}}function Ur(t,e){return e.every(function(e){return!O(e,t)})}function Hr(t){return"_value"in t?t._value:t.value}function Xr(t){t.target.composing=!0}function zr(t){t.target.composing&&(t.target.composing=!1,Yr(t.target,"input"))}function Yr(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function qr(t){return!t.componentInstance||t.data&&t.data.transition?t:qr(t.componentInstance._vnode)}function Vr(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Vr(ue(e.children)):t}function Wr(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[Po(o)]=i[o];return e}function Gr(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}function Kr(t){for(;t=t.parent;)if(t.data.transition)return!0}function Jr(t,e){return e.key===t.key&&e.tag===t.tag}function Qr(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function Zr(t){t.data.newPos=t.elm.getBoundingClientRect()}function ti(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}function ei(t,e){var n=e?Rc(e):Nc;if(n.test(t)){for(var r,i,o,a=[],s=[],c=n.lastIndex=0;r=n.exec(t);){(i=r.index)>c&&(s.push(o=t.slice(c,i)),a.push(JSON.stringify(o)));var u=Dn(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c<t.length&&(s.push(o=t.slice(c)),a.push(JSON.stringify(o))),{expression:a.join("+"),tokens:s}}}function ni(t,e){var n=(e.warn,Gn(t,"class"));n&&(t.staticClass=JSON.stringify(n));var r=Wn(t,"class",!1);r&&(t.classBinding=r)}function ri(t){var e="";return t.staticClass&&(e+="staticClass:"+t.staticClass+","),t.classBinding&&(e+="class:"+t.classBinding+","),e}function ii(t,e){var n=(e.warn,Gn(t,"style"));n&&(t.staticStyle=JSON.stringify(Ys(n)));var r=Wn(t,"style",!1);r&&(t.styleBinding=r)}function oi(t){var e="";return t.staticStyle&&(e+="staticStyle:"+t.staticStyle+","),t.styleBinding&&(e+="style:("+t.styleBinding+"),"),e}function ai(t,e){var n=e?ou:iu;return t.replace(n,function(t){return ru[t]})}function si(t,e){function n(e){l+=e,t=t.substring(e)}function r(t,n,r){var i,s;if(null==n&&(n=l),null==r&&(r=l),t)for(s=t.toLowerCase(),i=a.length-1;i>=0&&a[i].lowerCasedTag!==s;i--);else i=0;if(i>=0){for(var c=a.length-1;c>=i;c--)e.end&&e.end(a[c].tag,n,r);a.length=i,o=i&&a[i-1].tag}else"br"===s?e.start&&e.start(t,[],!0,n,r):"p"===s&&(e.start&&e.start(t,[],!1,n,r),e.end&&e.end(t,n,r))}for(var i,o,a=[],s=e.expectHTML,c=e.isUnaryTag||Io,u=e.canBeLeftOpenTag||Io,l=0;t;){if(i=t,o&&eu(o)){var f=0,p=o.toLowerCase(),d=nu[p]||(nu[p]=new RegExp("([\\s\\S]*?)(</"+p+"[^>]*>)","i")),h=t.replace(d,function(t,n,r){return f=r.length,eu(p)||"noscript"===p||(n=n.replace(/<!\--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)]]>/g,"$1")),su(p,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""});l+=t.length-h.length,t=h,r(p,l-f,l)}else{var v=t.indexOf("<");if(0===v){if(Zc.test(t)){var m=t.indexOf("--\x3e");if(m>=0){e.shouldKeepComment&&e.comment(t.substring(4,m),l,l+m+3),n(m+3);continue}}if(tu.test(t)){var y=t.indexOf("]>");if(y>=0){n(y+2);continue}}var g=t.match(Qc);if(g){n(g[0].length);continue}var b=t.match(Jc);if(b){var w=l;n(b[0].length),r(b[1],w,l);continue}var x=function(){var e=t.match(Gc);if(e){var r={tagName:e[1],attrs:[],start:l};n(e[0].length);for(var i,o;!(i=t.match(Kc))&&(o=t.match(qc)||t.match(Yc));)o.start=l,n(o[0].length),o.end=l,r.attrs.push(o);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=l,r}}();if(x){!function(t){var n=t.tagName,i=t.unarySlash;s&&("p"===o&&zc(n)&&r(o),u(n)&&o===n&&r(n));for(var l=c(n)||!!i,f=t.attrs.length,p=new Array(f),d=0;d<f;d++){var h=t.attrs[d],v=h[3]||h[4]||h[5]||"",m="a"===n&&"href"===h[1]?e.shouldDecodeNewlinesForHref:e.shouldDecodeNewlines;p[d]={name:h[1],value:ai(v,m)}}l||(a.push({tag:n,lowerCasedTag:n.toLowerCase(),attrs:p,start:t.start,end:t.end}),o=n),e.start&&e.start(n,p,l,t.start,t.end)}(x),su(x.tagName,t)&&n(1);continue}}var _=void 0,k=void 0,T=void 0;if(v>=0){for(k=t.slice(v);!(Jc.test(k)||Gc.test(k)||Zc.test(k)||tu.test(k)||(T=k.indexOf("<",1))<0);)v+=T,k=t.slice(v);_=t.substring(0,v)}v<0&&(_=t),_&&n(_.length),e.chars&&_&&e.chars(_,l-_.length,l)}if(t===i){e.chars&&e.chars(t);break}}r()}function ci(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:Si(e),rawAttrsMap:{},parent:n,children:[]}}function ui(t,e){function n(t){if(r(t),l||t.processed||(t=pi(t,e)),s.length||t===o||o.if&&(t.elseif||t.else)&&wi(o,{exp:t.elseif,block:t}),a&&!t.forbidden)if(t.elseif||t.else)gi(t,a);else{if(t.slotScope){var n=t.slotTarget||'"default"';(a.scopedSlots||(a.scopedSlots={}))[n]=t}a.children.push(t),t.parent=a}t.children=t.children.filter(function(t){return!t.slotScope}),r(t),t.pre&&(l=!1),Sc(t.tag)&&(f=!1);for(var i=0;i<Ec.length;i++)Ec[i](t,e)}function r(t){if(!f)for(var e;(e=t.children[t.children.length-1])&&3===e.type&&" "===e.text;)t.children.pop()}Tc=e.warn||Fn,Sc=e.isPreTag||Io,Pc=e.mustUseProp||Io,jc=e.getTagNamespace||Io;var i=e.isReservedTag||Io;Lc=function(t){return!(!(t.component||t.attrsMap[":is"]||t.attrsMap["v-bind:is"])&&i(t.attrsMap.is?t.attrsMap.is:t.tag))},Ac=Bn(e.modules,"transformNode"),Cc=Bn(e.modules,"preTransformNode"),Ec=Bn(e.modules,"postTransformNode"),Oc=e.delimiters;var o,a,s=[],c=!1!==e.preserveWhitespace,u=e.whitespace,l=!1,f=!1;return si(t,{warn:Tc,expectHTML:e.expectHTML,isUnaryTag:e.isUnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecodeNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,outputSourceRange:e.outputSourceRange,start:function(t,r,i,c,u){var p=a&&a.ns||jc(t);Wo&&"svg"===p&&(r=Li(r));var d=ci(t,r,a);p&&(d.ns=p),ji(d)&&!ia()&&(d.forbidden=!0);for(var h=0;h<Cc.length;h++)d=Cc[h](d,e)||d;l||(li(d),d.pre&&(l=!0)),Sc(d.tag)&&(f=!0),l?fi(d):d.processed||(vi(d),yi(d),xi(d)),o||(o=d),i?n(d):(a=d,s.push(d))},end:function(t,e,r){var i=s[s.length-1];s.length-=1,a=s[s.length-1],n(i)},chars:function(t,e,n){if(a&&(!Wo||"textarea"!==a.tag||a.attrsMap.placeholder!==t)){var r=a.children;if(t=f||t.trim()?Pi(a)?t:wu(t):r.length?u?"condense"===u&&gu.test(t)?"":" ":c?" ":"":""){f||"condense"!==u||(t=t.replace(bu," "));var i,o;!l&&" "!==t&&(i=ei(t,Oc))?o={type:2,expression:i.expression,tokens:i.tokens,text:t}:" "===t&&r.length&&" "===r[r.length-1].text||(o={type:3,text:t}),o&&r.push(o)}}},comment:function(t,e,n){if(a){var r={type:3,text:t,isComment:!0};a.children.push(r)}}}),o}function li(t){null!=Gn(t,"v-pre")&&(t.pre=!0)}function fi(t){var e=t.attrsList,n=e.length;if(n)for(var r=t.attrs=new Array(n),i=0;i<n;i++)r[i]={name:e[i].name,value:JSON.stringify(e[i].value)},null!=e[i].start&&(r[i].start=e[i].start,r[i].end=e[i].end);else t.pre||(t.plain=!0)}function pi(t,e){di(t),t.plain=!t.key&&!t.scopedSlots&&!t.attrsList.length,hi(t),_i(t),Ti(t),Oi(t);for(var n=0;n<Ac.length;n++)t=Ac[n](t,e)||t;return Ai(t),t}function di(t){var e=Wn(t,"key");e&&(t.key=e)}function hi(t){var e=Wn(t,"ref");e&&(t.ref=e,t.refInFor=Ci(t))}function vi(t){var e;if(e=Gn(t,"v-for")){var n=mi(e);n&&_(t,n)}}function mi(t){var e=t.match(lu);if(e){var n={};n.for=e[2].trim();var r=e[1].trim().replace(pu,""),i=r.match(fu);return i?(n.alias=r.replace(fu,"").trim(),n.iterator1=i[1].trim(),i[2]&&(n.iterator2=i[2].trim())):n.alias=r,n}}function yi(t){var e=Gn(t,"v-if");if(e)t.if=e,wi(t,{exp:e,block:t});else{null!=Gn(t,"v-else")&&(t.else=!0);var n=Gn(t,"v-else-if");n&&(t.elseif=n)}}function gi(t,e){var n=bi(e.children);n&&n.if&&wi(n,{exp:t.elseif,block:t})}function bi(t){for(var e=t.length;e--;){if(1===t[e].type)return t[e];t.pop()}}function wi(t,e){t.ifConditions||(t.ifConditions=[]),t.ifConditions.push(e)}function xi(t){null!=Gn(t,"v-once")&&(t.once=!0)}function _i(t){var e;"template"===t.tag?(e=Gn(t,"scope"),t.slotScope=e||Gn(t,"slot-scope")):(e=Gn(t,"slot-scope"))&&(t.slotScope=e);var n=Wn(t,"slot");if(n&&(t.slotTarget='""'===n?'"default"':n,t.slotTargetDynamic=!(!t.attrsMap[":slot"]&&!t.attrsMap["v-bind:slot"]),"template"===t.tag||t.slotScope||Hn(t,"slot",n,Vn(t,"slot"))),"template"===t.tag){var r=Kn(t,yu);if(r){var i=ki(r),o=i.name,a=i.dynamic;t.slotTarget=o,t.slotTargetDynamic=a,t.slotScope=r.value||xu}}else{var s=Kn(t,yu);if(s){var c=t.scopedSlots||(t.scopedSlots={}),u=ki(s),l=u.name,f=u.dynamic,p=c[l]=ci("template",[],t);p.slotTarget=l,p.slotTargetDynamic=f,p.children=t.children.filter(function(t){if(!t.slotScope)return t.parent=p,!0}),p.slotScope=s.value||xu,t.children=[],t.plain=!1}}}function ki(t){var e=t.name.replace(yu,"");return e||"#"!==t.name[0]&&(e="default"),du.test(e)?{name:e.slice(1,-1),dynamic:!0}:{name:'"'+e+'"',dynamic:!1}}function Ti(t){"slot"===t.tag&&(t.slotName=Wn(t,"name"))}function Oi(t){var e;(e=Wn(t,"is"))&&(t.component=e),null!=Gn(t,"inline-template")&&(t.inlineTemplate=!0)}function Ai(t){var e,n,r,i,o,a,s,c,u=t.attrsList;for(e=0,n=u.length;e<n;e++)if(r=i=u[e].name,o=u[e].value,uu.test(r))if(t.hasBindings=!0,a=Ei(r.replace(uu,"")),a&&(r=r.replace(mu,"")),vu.test(r))r=r.replace(vu,""),o=Dn(o),c=du.test(r),c&&(r=r.slice(1,-1)),a&&(a.prop&&!c&&"innerHtml"===(r=Po(r))&&(r="innerHTML"),a.camel&&!c&&(r=Po(r)),a.sync&&(s=Zn(o,"$event"),c?qn(t,'"update:"+('+r+")",s,null,!1,Tc,u[e],!0):(qn(t,"update:"+Po(r),s,null,!1,Tc,u[e]),Mo(r)!==Po(r)&&qn(t,"update:"+Mo(r),s,null,!1,Tc,u[e])))),a&&a.prop||!t.component&&Pc(t.tag,t.attrsMap.type,r)?Un(t,r,o,u[e],c):Hn(t,r,o,u[e],c);else if(cu.test(r))r=r.replace(cu,""),c=du.test(r),c&&(r=r.slice(1,-1)),qn(t,r,o,a,!1,Tc,u[e],c);else{r=r.replace(uu,"");var l=r.match(hu),f=l&&l[1];c=!1,f&&(r=r.slice(0,-(f.length+1)),du.test(f)&&(f=f.slice(1,-1),c=!0)),zn(t,r,i,o,f,c,a,u[e])}else Hn(t,r,JSON.stringify(o),u[e]),!t.component&&"muted"===r&&Pc(t.tag,t.attrsMap.type,r)&&Un(t,r,"true",u[e])}function Ci(t){for(var e=t;e;){if(void 0!==e.for)return!0;e=e.parent}return!1}function Ei(t){var e=t.match(mu);if(e){var n={};return e.forEach(function(t){n[t.slice(1)]=!0}),n}}function Si(t){for(var e={},n=0,r=t.length;n<r;n++)e[t[n].name]=t[n].value;return e}function Pi(t){return"script"===t.tag||"style"===t.tag}function ji(t){return"style"===t.tag||"script"===t.tag&&(!t.attrsMap.type||"text/javascript"===t.attrsMap.type)}function Li(t){for(var e=[],n=0;n<t.length;n++){var r=t[n];_u.test(r.name)||(r.name=r.name.replace(ku,""),e.push(r))}return e}function Mi(t,e){if("input"===t.tag){var n=t.attrsMap;if(!n["v-model"])return;var r;if((n[":type"]||n["v-bind:type"])&&(r=Wn(t,"type")),n.type||r||!n["v-bind"]||(r="("+n["v-bind"]+").type"),r){var i=Gn(t,"v-if",!0),o=i?"&&("+i+")":"",a=null!=Gn(t,"v-else",!0),s=Gn(t,"v-else-if",!0),c=$i(t);vi(c),Xn(c,"type","checkbox"),pi(c,e),c.processed=!0,c.if="("+r+")==='checkbox'"+o,wi(c,{exp:c.if,block:c});var u=$i(t);Gn(u,"v-for",!0),Xn(u,"type","radio"),pi(u,e),wi(c,{exp:"("+r+")==='radio'"+o,block:u});var l=$i(t);return Gn(l,"v-for",!0),Xn(l,":type",r),pi(l,e),wi(c,{exp:i,block:l}),a?c.else=!0:s&&(c.elseif=s),c}}}function $i(t){return ci(t.tag,t.attrsList.slice(),t.parent)}function Ii(t,e){e.value&&Un(t,"textContent","_s("+e.value+")",e)}function Ni(t,e){e.value&&Un(t,"innerHTML","_s("+e.value+")",e)}function Di(t,e){t&&(Mc=Eu(e.staticKeys||""),$c=e.isReservedTag||Io,Fi(t),Bi(t,!1))}function Ri(t){return v("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(t?","+t:""))}function Fi(t){if(t.static=Ui(t),1===t.type){if(!$c(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var e=0,n=t.children.length;e<n;e++){var r=t.children[e];Fi(r),r.static||(t.static=!1)}if(t.ifConditions)for(var i=1,o=t.ifConditions.length;i<o;i++){var a=t.ifConditions[i].block;Fi(a),a.static||(t.static=!1)}}}function Bi(t,e){if(1===t.type){if((t.static||t.once)&&(t.staticInFor=e),t.static&&t.children.length&&(1!==t.children.length||3!==t.children[0].type))return void(t.staticRoot=!0);if(t.staticRoot=!1,t.children)for(var n=0,r=t.children.length;n<r;n++)Bi(t.children[n],e||!!t.for);if(t.ifConditions)for(var i=1,o=t.ifConditions.length;i<o;i++)Bi(t.ifConditions[i].block,e)}}function Ui(t){return 2!==t.type&&(3===t.type||!(!t.pre&&(t.hasBindings||t.if||t.for||Ao(t.tag)||!$c(t.tag)||Hi(t)||!Object.keys(t).every(Mc))))}function Hi(t){for(;t.parent;){if(t=t.parent,"template"!==t.tag)return!1;if(t.for)return!0}return!1}function Xi(t,e){var n=e?"nativeOn:":"on:",r="",i="";for(var o in t){var a=zi(t[o]);t[o]&&t[o].dynamic?i+=o+","+a+",":r+='"'+o+'":'+a+","}return r="{"+r.slice(0,-1)+"}",i?n+"_d("+r+",["+i.slice(0,-1)+"])":n+r}function zi(t){if(!t)return"function(){}";if(Array.isArray(t))return"["+t.map(function(t){return zi(t)}).join(",")+"]";var e=ju.test(t.value),n=Su.test(t.value),r=ju.test(t.value.replace(Pu,""));if(t.modifiers){var i="",o="",a=[];for(var s in t.modifiers)if(Iu[s])o+=Iu[s],Lu[s]&&a.push(s);else if("exact"===s){var c=t.modifiers;o+=$u(["ctrl","shift","alt","meta"].filter(function(t){return!c[t]}).map(function(t){return"$event."+t+"Key"}).join("||"))}else a.push(s);return a.length&&(i+=Yi(a)),o&&(i+=o),"function($event){"+i+(e?"return "+t.value+".apply(null, arguments)":n?"return ("+t.value+").apply(null, arguments)":r?"return "+t.value:t.value)+"}"}return e||n?t.value:"function($event){"+(r?"return "+t.value:t.value)+"}"}function Yi(t){return"if(!$event.type.indexOf('key')&&"+t.map(qi).join("&&")+")return null;"}function qi(t){var e=parseInt(t,10);if(e)return"$event.keyCode!=="+e;var n=Lu[t],r=Mu[t];return"_k($event.keyCode,"+JSON.stringify(t)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}function Vi(t,e){t.wrapListeners=function(t){return"_g("+t+","+e.value+")"}}function Wi(t,e){t.wrapData=function(n){return"_b("+n+",'"+t.tag+"',"+e.value+","+(e.modifiers&&e.modifiers.prop?"true":"false")+(e.modifiers&&e.modifiers.sync?",true":"")+")"}}function Gi(t,e){var n=new Du(e);return{render:"with(this){return "+(t?"script"===t.tag?"null":Ki(t,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Ki(t,e){if(t.parent&&(t.pre=t.pre||t.parent.pre),t.staticRoot&&!t.staticProcessed)return Ji(t,e);if(t.once&&!t.onceProcessed)return Qi(t,e);if(t.for&&!t.forProcessed)return eo(t,e);if(t.if&&!t.ifProcessed)return Zi(t,e);if("template"!==t.tag||t.slotTarget||e.pre){if("slot"===t.tag)return mo(t,e);var n;if(t.component)n=yo(t.component,t,e);else{var r;(!t.plain||t.pre&&e.maybeComponent(t))&&(r=no(t,e));var i=t.inlineTemplate?null:uo(t,e,!0);n="_c('"+t.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o<e.transforms.length;o++)n=e.transforms[o](t,n);return n}return uo(t,e)||"void 0"}function Ji(t,e){t.staticProcessed=!0;var n=e.pre;return t.pre&&(e.pre=t.pre),e.staticRenderFns.push("with(this){return "+Ki(t,e)+"}"),e.pre=n,"_m("+(e.staticRenderFns.length-1)+(t.staticInFor?",true":"")+")"}function Qi(t,e){if(t.onceProcessed=!0,t.if&&!t.ifProcessed)return Zi(t,e);if(t.staticInFor){for(var n="",r=t.parent;r;){if(r.for){n=r.key;break}r=r.parent}return n?"_o("+Ki(t,e)+","+e.onceId+++","+n+")":Ki(t,e)}return Ji(t,e)}function Zi(t,e,n,r){return t.ifProcessed=!0,to(t.ifConditions.slice(),e,n,r)}function to(t,e,n,r){function i(t){return n?n(t,e):t.once?Qi(t,e):Ki(t,e)}if(!t.length)return r||"_e()";var o=t.shift();return o.exp?"("+o.exp+")?"+i(o.block)+":"+to(t,e,n,r):""+i(o.block)}function eo(t,e,n,r){var i=t.for,o=t.alias,a=t.iterator1?","+t.iterator1:"",s=t.iterator2?","+t.iterator2:"";return t.forProcessed=!0,(r||"_l")+"(("+i+"),function("+o+a+s+"){return "+(n||Ki)(t,e)+"})"}function no(t,e){var n="{",r=ro(t,e);r&&(n+=r+","),t.key&&(n+="key:"+t.key+","),t.ref&&(n+="ref:"+t.ref+","),t.refInFor&&(n+="refInFor:true,"),t.pre&&(n+="pre:true,"),t.component&&(n+='tag:"'+t.tag+'",');for(var i=0;i<e.dataGenFns.length;i++)n+=e.dataGenFns[i](t);if(t.attrs&&(n+="attrs:"+go(t.attrs)+","),t.props&&(n+="domProps:"+go(t.props)+","),t.events&&(n+=Xi(t.events,!1)+","),t.nativeEvents&&(n+=Xi(t.nativeEvents,!0)+","),t.slotTarget&&!t.slotScope&&(n+="slot:"+t.slotTarget+","),t.scopedSlots&&(n+=oo(t,t.scopedSlots,e)+","),t.model&&(n+="model:{value:"+t.model.value+",callback:"+t.model.callback+",expression:"+t.model.expression+"},"),t.inlineTemplate){var o=io(t,e);o&&(n+=o+",")}return n=n.replace(/,$/,"")+"}",t.dynamicAttrs&&(n="_b("+n+',"'+t.tag+'",'+go(t.dynamicAttrs)+")"),t.wrapData&&(n=t.wrapData(n)),t.wrapListeners&&(n=t.wrapListeners(n)),n}function ro(t,e){var n=t.directives;if(n){var r,i,o,a,s="directives:[",c=!1;for(r=0,i=n.length;r<i;r++){o=n[r],a=!0;var u=e.directives[o.name];u&&(a=!!u(t,o,e.warn)),a&&(c=!0,s+='{name:"'+o.name+'",rawName:"'+o.rawName+'"'+(o.value?",value:("+o.value+"),expression:"+JSON.stringify(o.value):"")+(o.arg?",arg:"+(o.isDynamicArg?o.arg:'"'+o.arg+'"'):"")+(o.modifiers?",modifiers:"+JSON.stringify(o.modifiers):"")+"},")}return c?s.slice(0,-1)+"]":void 0}}function io(t,e){var n=t.children[0];if(n&&1===n.type){var r=Gi(n,e.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map(function(t){return"function(){"+t+"}"}).join(",")+"]}"}}function oo(t,e,n){var r=t.for||Object.keys(e).some(function(t){var n=e[t];return n.slotTargetDynamic||n.if||n.for||so(n)}),i=!!t.if;if(!r)for(var o=t.parent;o;){if(o.slotScope&&o.slotScope!==xu||o.for){r=!0;break}o.if&&(i=!0),o=o.parent}var a=Object.keys(e).map(function(t){return co(e[t],n)}).join(",");return"scopedSlots:_u(["+a+"]"+(r?",null,true":"")+(!r&&i?",null,false,"+ao(a):"")+")"}function ao(t){for(var e=5381,n=t.length;n;)e=33*e^t.charCodeAt(--n);return e>>>0}function so(t){return 1===t.type&&("slot"===t.tag||t.children.some(so))}function co(t,e){var n=t.attrsMap["slot-scope"];if(t.if&&!t.ifProcessed&&!n)return Zi(t,e,co,"null");if(t.for&&!t.forProcessed)return eo(t,e,co);var r=t.slotScope===xu?"":String(t.slotScope),i="function("+r+"){return "+("template"===t.tag?t.if&&n?"("+t.if+")?"+(uo(t,e)||"undefined")+":undefined":uo(t,e)||"undefined":Ki(t,e))+"}",o=r?"":",proxy:true";return"{key:"+(t.slotTarget||'"default"')+",fn:"+i+o+"}"}function uo(t,e,n,r,i){var o=t.children;if(o.length){var a=o[0];if(1===o.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?e.maybeComponent(a)?",1":",0":"";return""+(r||Ki)(a,e)+s}var c=n?lo(o,e.maybeComponent):0,u=i||po;return"["+o.map(function(t){return u(t,e)}).join(",")+"]"+(c?","+c:"")}}function lo(t,e){for(var n=0,r=0;r<t.length;r++){var i=t[r];if(1===i.type){if(fo(i)||i.ifConditions&&i.ifConditions.some(function(t){return fo(t.block)})){n=2;break}(e(i)||i.ifConditions&&i.ifConditions.some(function(t){return e(t.block)}))&&(n=1)}}return n}function fo(t){return void 0!==t.for||"template"===t.tag||"slot"===t.tag}function po(t,e){return 1===t.type?Ki(t,e):3===t.type&&t.isComment?vo(t):ho(t)}function ho(t){return"_v("+(2===t.type?t.expression:bo(JSON.stringify(t.text)))+")"}function vo(t){return"_e("+JSON.stringify(t.text)+")"}function mo(t,e){var n=t.slotName||'"default"',r=uo(t,e),i="_t("+n+(r?",function(){return "+r+"}":""),o=t.attrs||t.dynamicAttrs?go((t.attrs||[]).concat(t.dynamicAttrs||[]).map(function(t){return{name:Po(t.name),value:t.value,dynamic:t.dynamic}})):null,a=t.attrsMap["v-bind"];return!o&&!a||r||(i+=",null"),o&&(i+=","+o),a&&(i+=(o?"":",null")+","+a),i+")"}function yo(t,e,n){var r=e.inlineTemplate?null:uo(e,n,!0);return"_c("+t+","+no(e,n)+(r?","+r:"")+")"}function go(t){for(var e="",n="",r=0;r<t.length;r++){var i=t[r],o=bo(i.value);i.dynamic?n+=i.name+","+o+",":e+='"'+i.name+'":'+o+","}return e="{"+e.slice(0,-1)+"}",n?"_d("+e+",["+n.slice(0,-1)+"])":e}function bo(t){return t.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function wo(t,e){try{return new Function(t)}catch(n){return e.push({err:n,code:t}),T}}function xo(t){var e=Object.create(null);return function(n,r,i){r=_({},r),r.warn,delete r.warn;var o=r.delimiters?String(r.delimiters)+n:n;if(e[o])return e[o];var a=t(n,r),s={},c=[];return s.render=wo(a.render,c),s.staticRenderFns=a.staticRenderFns.map(function(t){return wo(t,c)}),e[o]=s}}function _o(t){return Ic=Ic||document.createElement("div"),Ic.innerHTML=t?'<a href="\n"/>':'<div a="\n"/>',Ic.innerHTML.indexOf("&#10;")>0}function ko(t){if(t.outerHTML)return t.outerHTML;var e=document.createElement("div");return e.appendChild(t.cloneNode(!0)),e.innerHTML}/*!
2
- * Vue.js v2.6.14
3
- * (c) 2014-2021 Evan You
4
  * Released under the MIT License.
5
  */
6
- var To=Object.freeze({}),Oo=Object.prototype.toString,Ao=v("slot,component",!0),Co=v("key,ref,slot,slot-scope,is"),Eo=Object.prototype.hasOwnProperty,So=/-(\w)/g,Po=g(function(t){return t.replace(So,function(t,e){return e?e.toUpperCase():""})}),jo=g(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),Lo=/\B([A-Z])/g,Mo=g(function(t){return t.replace(Lo,"-$1").toLowerCase()}),$o=Function.prototype.bind?w:b,Io=function(t,e,n){return!1},No=function(t){return t},Do="data-server-rendered",Ro=["component","directive","filter"],Fo=["beforeCreate","created","beforeMount","mounted","beforeUpdate","updated","beforeDestroy","destroyed","activated","deactivated","errorCaptured","serverPrefetch"],Bo={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:Io,isReservedAttr:Io,isUnknownElement:Io,getTagNamespace:T,parsePlatformTagName:No,mustUseProp:Io,async:!0,_lifecycleHooks:Fo},Uo=/a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/,Ho=new RegExp("[^"+Uo.source+".$_\\d]"),Xo="__proto__"in{},zo="undefined"!=typeof window,Yo="undefined"!=typeof WXEnvironment&&!!WXEnvironment.platform,qo=Yo&&WXEnvironment.platform.toLowerCase(),Vo=zo&&window.navigator.userAgent.toLowerCase(),Wo=Vo&&/msie|trident/.test(Vo),Go=Vo&&Vo.indexOf("msie 9.0")>0,Ko=Vo&&Vo.indexOf("edge/")>0,Jo=(Vo&&Vo.indexOf("android"),Vo&&/iphone|ipad|ipod|ios/.test(Vo)||"ios"===qo),Qo=(Vo&&/chrome\/\d+/.test(Vo),Vo&&/phantomjs/.test(Vo),Vo&&Vo.match(/firefox\/(\d+)/)),Zo={}.watch,ta=!1;if(zo)try{var ea={};Object.defineProperty(ea,"passive",{get:function(){ta=!0}}),window.addEventListener("test-passive",null,ea)}catch(t){}var na,ra,ia=function(){return void 0===na&&(na=!zo&&!Yo&&void 0!==t&&t.process&&"server"===t.process.env.VUE_ENV),na},oa=zo&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,aa="undefined"!=typeof Symbol&&j(Symbol)&&"undefined"!=typeof Reflect&&j(Reflect.ownKeys);ra="undefined"!=typeof Set&&j(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var sa=T,ca=0,ua=function(){this.id=ca++,this.subs=[]};ua.prototype.addSub=function(t){this.subs.push(t)},ua.prototype.removeSub=function(t){m(this.subs,t)},ua.prototype.depend=function(){ua.target&&ua.target.addDep(this)},ua.prototype.notify=function(){for(var t=this.subs.slice(),e=0,n=t.length;e<n;e++)t[e].update()},ua.target=null;var la=[],fa=function(t,e,n,r,i,o,a,s){this.tag=t,this.data=e,this.children=n,this.text=r,this.elm=i,this.ns=void 0,this.context=o,this.fnContext=void 0,this.fnOptions=void 0,this.fnScopeId=void 0,this.key=e&&e.key,this.componentOptions=a,this.componentInstance=void 0,this.parent=void 0,this.raw=!1,this.isStatic=!1,this.isRootInsert=!0,this.isComment=!1,this.isCloned=!1,this.isOnce=!1,this.asyncFactory=s,this.asyncMeta=void 0,this.isAsyncPlaceholder=!1},pa={child:{configurable:!0}};pa.child.get=function(){return this.componentInstance},Object.defineProperties(fa.prototype,pa);var da=function(t){void 0===t&&(t="");var e=new fa;return e.text=t,e.isComment=!0,e},ha=Array.prototype,va=Object.create(ha);["push","pop","shift","unshift","splice","sort","reverse"].forEach(function(t){var e=ha[t];S(va,t,function(){for(var n=[],r=arguments.length;r--;)n[r]=arguments[r];var i,o=e.apply(this,n),a=this.__ob__;switch(t){case"push":case"unshift":i=n;break;case"splice":i=n.slice(2)}return i&&a.observeArray(i),a.dep.notify(),o})});var ma=Object.getOwnPropertyNames(va),ya=!0,ga=function(t){this.value=t,this.dep=new ua,this.vmCount=0,S(t,"__ob__",this),Array.isArray(t)?(Xo?D(t,va):R(t,va,ma),this.observeArray(t)):this.walk(t)};ga.prototype.walk=function(t){for(var e=Object.keys(t),n=0;n<e.length;n++)B(t,e[n])},ga.prototype.observeArray=function(t){for(var e=0,n=t.length;e<n;e++)F(t[e])};var ba=Bo.optionMergeStrategies;ba.data=function(t,e,n){return n?Y(t,e,n):e&&"function"!=typeof e?t:Y(t,e)},Fo.forEach(function(t){ba[t]=q}),Ro.forEach(function(t){ba[t+"s"]=W}),ba.watch=function(t,e,n,r){if(t===Zo&&(t=void 0),e===Zo&&(e=void 0),!e)return Object.create(t||null);if(!t)return e;var i={};_(i,t);for(var o in e){var a=i[o],s=e[o];a&&!Array.isArray(a)&&(a=[a]),i[o]=a?a.concat(s):Array.isArray(s)?s:[s]}return i},ba.props=ba.methods=ba.inject=ba.computed=function(t,e,n,r){if(!t)return e;var i=Object.create(null);return _(i,t),e&&_(i,e),i},ba.provide=Y;var wa,xa=function(t,e){return void 0===e?t:e},_a=/^\s*function (\w+)/,ka=!1,Ta=[],Oa=!1;if("undefined"!=typeof Promise&&j(Promise)){var Aa=Promise.resolve();wa=function(){Aa.then(ut),Jo&&setTimeout(T)},ka=!0}else if(Wo||"undefined"==typeof MutationObserver||!j(MutationObserver)&&"[object MutationObserverConstructor]"!==MutationObserver.toString())wa=void 0!==n&&j(n)?function(){n(ut)}:function(){setTimeout(ut,0)};else{var Ca=1,Ea=new MutationObserver(ut),Sa=document.createTextNode(String(Ca));Ea.observe(Sa,{characterData:!0}),wa=function(){Ca=(Ca+1)%2,Sa.data=String(Ca)},ka=!0}var Pa=new ra,ja=g(function(t){var e="&"===t.charAt(0);t=e?t.slice(1):t;var n="~"===t.charAt(0);t=n?t.slice(1):t;var r="!"===t.charAt(0);return t=r?t.slice(1):t,{name:t,once:n,capture:r,passive:e}});Yt(qt.prototype);var La,Ma={init:function(t,e){if(t.componentInstance&&!t.componentInstance._isDestroyed&&t.data.keepAlive){var n=t;Ma.prepatch(n,n)}else(t.componentInstance=Jt(t,Ra)).$mount(e?t.elm:void 0,e)},prepatch:function(t,e){var n=e.componentOptions;ge(e.componentInstance=t.componentInstance,n.propsData,n.listeners,e,n.children)},insert:function(t){var e=t.context,n=t.componentInstance;n._isMounted||(n._isMounted=!0,_e(n,"mounted")),t.data.keepAlive&&(e._isMounted?Ae(n):we(n,!0))},destroy:function(t){var e=t.componentInstance;e._isDestroyed||(t.data.keepAlive?xe(e,!0):e.$destroy())}},$a=Object.keys(Ma),Ia=1,Na=2,Da=null,Ra=null,Fa=[],Ba=[],Ua={},Ha=!1,Xa=!1,za=0,Ya=0,qa=Date.now;if(zo&&!Wo){var Va=window.performance;Va&&"function"==typeof Va.now&&qa()>document.createEvent("Event").timeStamp&&(qa=function(){return Va.now()})}var Wa=0,Ga=function(t,e,n,r,i){this.vm=t,i&&(t._watcher=this),t._watchers.push(this),r?(this.deep=!!r.deep,this.user=!!r.user,this.lazy=!!r.lazy,this.sync=!!r.sync,this.before=r.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++Wa,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new ra,this.newDepIds=new ra,this.expression="","function"==typeof e?this.getter=e:(this.getter=P(e),this.getter||(this.getter=T)),this.value=this.lazy?void 0:this.get()};Ga.prototype.get=function(){L(this);var t,e=this.vm;try{t=this.getter.call(e,e)}catch(t){if(!this.user)throw t;ot(t,e,'getter for watcher "'+this.expression+'"')}finally{this.deep&&ft(t),M(),this.cleanupDeps()}return t},Ga.prototype.addDep=function(t){var e=t.id;this.newDepIds.has(e)||(this.newDepIds.add(e),this.newDeps.push(t),this.depIds.has(e)||t.addSub(this))},Ga.prototype.cleanupDeps=function(){for(var t=this.deps.length;t--;){var e=this.deps[t];this.newDepIds.has(e.id)||e.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0},Ga.prototype.update=function(){this.lazy?this.dirty=!0:this.sync?this.run():Ee(this)},Ga.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||c(t)||this.deep){var e=this.value;if(this.value=t,this.user){var n='callback for watcher "'+this.expression+'"';at(this.cb,this.vm,[t,e],this.vm,n)}else this.cb.call(this.vm,t,e)}}},Ga.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},Ga.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Ga.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||m(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var Ka={enumerable:!0,configurable:!0,get:T,set:T},Ja={lazy:!0},Qa=0;!function(t){t.prototype._init=function(t){var e=this;e._uid=Qa++,e._isVue=!0,t&&t._isComponent?Ue(e,t):e.$options=Q(He(e.constructor),t||{},e),e._renderProxy=e,e._self=e,me(e),le(e),oe(e),_e(e,"beforeCreate"),kt(e),Pe(e),_t(e),_e(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(ze),function(t){var e={};e.get=function(){return this._data};var n={};n.get=function(){return this._props},Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=U,t.prototype.$delete=H,t.prototype.$watch=function(t,e,n){var r=this;if(u(e))return Be(r,t,e,n);n=n||{},n.user=!0;var i=new Ga(r,t,e,n);if(n.immediate){var o='callback for immediate watcher "'+i.expression+'"';L(),at(e,r,[i.value],r,o),M()}return function(){i.teardown()}}}(ze),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var i=0,o=t.length;i<o;i++)r.$on(t[i],n);else(r._events[t]||(r._events[t]=[])).push(n),e.test(t)&&(r._hasHookEvent=!0);return r},t.prototype.$once=function(t,e){function n(){r.$off(t,n),e.apply(r,arguments)}var r=this;return n.fn=e,r.$on(t,n),r},t.prototype.$off=function(t,e){var n=this;if(!arguments.length)return n._events=Object.create(null),n;if(Array.isArray(t)){for(var r=0,i=t.length;r<i;r++)n.$off(t[r],e);return n}var o=n._events[t];if(!o)return n;if(!e)return n._events[t]=null,n;for(var a,s=o.length;s--;)if((a=o[s])===e||a.fn===e){o.splice(s,1);break}return n},t.prototype.$emit=function(t){var e=this,n=e._events[t];if(n){n=n.length>1?x(n):n;for(var r=x(arguments,1),i='event handler for "'+t+'"',o=0,a=n.length;o<a;o++)at(n[o],e,r,e,i)}return e}}(ze),function(t){t.prototype._update=function(t,e){var n=this,r=n.$el,i=n._vnode,o=ve(n);n._vnode=t,n.$el=i?n.__patch__(i,t):n.__patch__(n.$el,t,e,!1),o(),r&&(r.__vue__=null),n.$el&&(n.$el.__vue__=n),n.$vnode&&n.$parent&&n.$vnode===n.$parent._vnode&&(n.$parent.$el=n.$el)},t.prototype.$forceUpdate=function(){var t=this;t._watcher&&t._watcher.update()},t.prototype.$destroy=function(){var t=this;if(!t._isBeingDestroyed){_e(t,"beforeDestroy"),t._isBeingDestroyed=!0;var e=t.$parent;!e||e._isBeingDestroyed||t.$options.abstract||m(e.$children,t),t._watcher&&t._watcher.teardown();for(var n=t._watchers.length;n--;)t._watchers[n].teardown();t._data.__ob__&&t._data.__ob__.vmCount--,t._isDestroyed=!0,t.__patch__(t._vnode,null),_e(t,"destroyed"),t.$off(),t.$el&&(t.$el.__vue__=null),t.$vnode&&(t.$vnode.parent=null)}}}(ze),function(t){Yt(t.prototype),t.prototype.$nextTick=function(t){return lt(t,this)},t.prototype._render=function(){var t=this,e=t.$options,n=e.render,r=e._parentVnode;r&&(t.$scopedSlots=Et(r.data.scopedSlots,t.$slots,t.$scopedSlots)),t.$vnode=r;var i;try{Da=t,i=n.call(t._renderProxy,t.$createElement)}catch(e){ot(e,t,"render"),i=t._vnode}finally{Da=null}return Array.isArray(i)&&1===i.length&&(i=i[0]),i instanceof fa||(i=da()),i.parent=r,i}}(ze);var Za=[String,RegExp,Array],ts={name:"keep-alive",abstract:!0,props:{include:Za,exclude:Za,max:[String,Number]},methods:{cacheVNode:function(){var t=this,e=t.cache,n=t.keys,r=t.vnodeToCache,i=t.keyToCache;if(r){var o=r.tag,a=r.componentInstance,s=r.componentOptions;e[i]={name:Je(s),tag:o,componentInstance:a},n.push(i),this.max&&n.length>parseInt(this.max)&&tn(e,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)tn(this.cache,t,this.keys)},mounted:function(){var t=this;this.cacheVNode(),this.$watch("include",function(e){Ze(t,function(t){return Qe(e,t)})}),this.$watch("exclude",function(e){Ze(t,function(t){return!Qe(e,t)})})},updated:function(){this.cacheVNode()},render:function(){var t=this.$slots.default,e=ue(t),n=e&&e.componentOptions;if(n){var r=Je(n),i=this,o=i.include,a=i.exclude;if(o&&(!r||!Qe(o,r))||a&&r&&Qe(a,r))return e;var s=this,c=s.cache,u=s.keys,l=null==e.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):e.key;c[l]?(e.componentInstance=c[l].componentInstance,m(u,l),u.push(l)):(this.vnodeToCache=e,this.keyToCache=l),e.data.keepAlive=!0}return e||t&&t[0]}},es={KeepAlive:ts};!function(t){var e={};e.get=function(){return Bo},Object.defineProperty(t,"config",e),t.util={warn:sa,extend:_,mergeOptions:Q,defineReactive:B},t.set=U,t.delete=H,t.nextTick=lt,t.observable=function(t){return F(t),t},t.options=Object.create(null),Ro.forEach(function(e){t.options[e+"s"]=Object.create(null)}),t.options._base=t,_(t.options.components,es),Ye(t),qe(t),Ve(t),Ke(t)}(ze),Object.defineProperty(ze.prototype,"$isServer",{get:ia}),Object.defineProperty(ze.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(ze,"FunctionalRenderContext",{value:qt}),ze.version="2.6.14";var ns,rs,is,os,as,ss,cs,us,ls,fs,ps=v("style,class"),ds=v("input,textarea,option,select,progress"),hs=function(t,e,n){return"value"===n&&ds(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},vs=v("contenteditable,draggable,spellcheck"),ms=v("events,caret,typing,plaintext-only"),ys=function(t,e){return _s(e)||"false"===e?"false":"contenteditable"===t&&ms(e)?e:"true"},gs=v("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),bs="http://www.w3.org/1999/xlink",ws=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},xs=function(t){return ws(t)?t.slice(6,t.length):""},_s=function(t){return null==t||!1===t},ks={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},Ts=v("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot"),Os=v("svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignobject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view",!0),As=function(t){return"pre"===t},Cs=function(t){return Ts(t)||Os(t)},Es=Object.create(null),Ss=v("text,number,password,search,email,tel,url"),Ps=Object.freeze({createElement:pn,createElementNS:dn,createTextNode:hn,createComment:vn,insertBefore:mn,removeChild:yn,appendChild:gn,parentNode:bn,nextSibling:wn,tagName:xn,setTextContent:_n,setStyleScope:kn}),js={create:function(t,e){Tn(e)},update:function(t,e){t.data.ref!==e.data.ref&&(Tn(t,!0),Tn(e))},destroy:function(t){Tn(t,!0)}},Ls=new fa("",{},[]),Ms=["create","activate","update","remove","destroy"],$s={create:En,update:En,destroy:function(t){En(t,Ls)}},Is=Object.create(null),Ns=[js,$s],Ds={create:Mn,update:Mn},Rs={create:Nn,update:Nn},Fs=/[\w).+\-_$\]]/,Bs="__r",Us="__c",Hs=ka&&!(Qo&&Number(Qo[1])<=53),Xs={create:vr,update:vr},zs={create:mr,update:mr},Ys=g(function(t){var e={},n=/;(?![^(]*\))/g,r=/:(.+)/;return t.split(n).forEach(function(t){if(t){var n=t.split(r);n.length>1&&(e[n[0].trim()]=n[1].trim())}}),e}),qs=/^--/,Vs=/\s*!important$/,Ws=function(t,e,n){if(qs.test(e))t.style.setProperty(e,n);else if(Vs.test(n))t.style.setProperty(Mo(e),n.replace(Vs,""),"important");else{var r=Ks(e);if(Array.isArray(n))for(var i=0,o=n.length;i<o;i++)t.style[r]=n[i];else t.style[r]=n}},Gs=["Webkit","Moz","ms"],Ks=g(function(t){if(fs=fs||document.createElement("div").style,"filter"!==(t=Po(t))&&t in fs)return t;for(var e=t.charAt(0).toUpperCase()+t.slice(1),n=0;n<Gs.length;n++){var r=Gs[n]+e;if(r in fs)return r}}),Js={create:kr,update:kr},Qs=/\s+/,Zs=g(function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}}),tc=zo&&!Go,ec="transition",nc="animation",rc="transition",ic="transitionend",oc="animation",ac="animationend";tc&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(rc="WebkitTransition",ic="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(oc="WebkitAnimation",ac="webkitAnimationEnd"));var sc=zo?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()},cc=/\b(transform|all)(,|$)/,uc=zo?{create:Rr,activate:Rr,remove:function(t,e){!0!==t.data.show?Ir(t,e):e()}}:{},lc=[Ds,Rs,Xs,zs,Js,uc],fc=lc.concat(Ns),pc=function(t){function e(t){return new fa(j.tagName(t).toLowerCase(),{},[],void 0,t)}function n(t,e){function n(){0==--n.listeners&&a(t)}return n.listeners=e,n}function a(t){var e=j.parentNode(t);i(e)&&j.removeChild(e,t)}function c(t,e,n,r,a,s,c){if(i(t.elm)&&i(s)&&(t=s[c]=I(t)),t.isRootInsert=!a,!u(t,e,n,r)){var l=t.data,f=t.children,h=t.tag;i(h)?(t.elm=t.ns?j.createElementNS(t.ns,h):j.createElement(h,t),y(t),d(t,f,e),i(l)&&m(t,e),p(n,t.elm,r)):o(t.isComment)?(t.elm=j.createComment(t.text),p(n,t.elm,r)):(t.elm=j.createTextNode(t.text),p(n,t.elm,r))}}function u(t,e,n,r){var a=t.data;if(i(a)){var s=i(t.componentInstance)&&a.keepAlive;if(i(a=a.hook)&&i(a=a.init)&&a(t,!1),i(t.componentInstance))return l(t,e),p(n,t.elm,r),o(s)&&f(t,e,n,r),!0}}function l(t,e){i(t.data.pendingInsert)&&(e.push.apply(e,t.data.pendingInsert),t.data.pendingInsert=null),t.elm=t.componentInstance.$el,h(t)?(m(t,e),y(t)):(Tn(t),e.push(t))}function f(t,e,n,r){for(var o,a=t;a.componentInstance;)if(a=a.componentInstance._vnode,i(o=a.data)&&i(o=o.transition)){for(o=0;o<S.activate.length;++o)S.activate[o](Ls,a);e.push(a);break}p(n,t.elm,r)}function p(t,e,n){i(t)&&(i(n)?j.parentNode(n)===t&&j.insertBefore(t,e,n):j.appendChild(t,e))}function d(t,e,n){if(Array.isArray(e))for(var r=0;r<e.length;++r)c(e[r],n,t.elm,null,!0,e,r);else s(t.text)&&j.appendChild(t.elm,j.createTextNode(String(t.text)))}function h(t){for(;t.componentInstance;)t=t.componentInstance._vnode;return i(t.tag)}function m(t,e){for(var n=0;n<S.create.length;++n)S.create[n](Ls,t);C=t.data.hook,i(C)&&(i(C.create)&&C.create(Ls,t),i(C.insert)&&e.push(t))}function y(t){var e;if(i(e=t.fnScopeId))j.setStyleScope(t.elm,e);else for(var n=t;n;)i(e=n.context)&&i(e=e.$options._scopeId)&&j.setStyleScope(t.elm,e),n=n.parent;i(e=Ra)&&e!==t.context&&e!==t.fnContext&&i(e=e.$options._scopeId)&&j.setStyleScope(t.elm,e)}function g(t,e,n,r,i,o){for(;r<=i;++r)c(n[r],o,t,e,!1,n,r)}function b(t){var e,n,r=t.data;if(i(r))for(i(e=r.hook)&&i(e=e.destroy)&&e(t),e=0;e<S.destroy.length;++e)S.destroy[e](t);if(i(e=t.children))for(n=0;n<t.children.length;++n)b(t.children[n])}function w(t,e,n){for(;e<=n;++e){var r=t[e];i(r)&&(i(r.tag)?(x(r),b(r)):a(r.elm))}}function x(t,e){if(i(e)||i(t.data)){var r,o=S.remove.length+1;for(i(e)?e.listeners+=o:e=n(t.elm,o),i(r=t.componentInstance)&&i(r=r._vnode)&&i(r.data)&&x(r,e),r=0;r<S.remove.length;++r)S.remove[r](t,e);i(r=t.data.hook)&&i(r=r.remove)?r(t,e):e()}else a(t.elm)}function _(t,e,n,o,a){for(var s,u,l,f,p=0,d=0,h=e.length-1,v=e[0],m=e[h],y=n.length-1,b=n[0],x=n[y],_=!a;p<=h&&d<=y;)r(v)?v=e[++p]:r(m)?m=e[--h]:On(v,b)?(T(v,b,o,n,d),v=e[++p],b=n[++d]):On(m,x)?(T(m,x,o,n,y),m=e[--h],x=n[--y]):On(v,x)?(T(v,x,o,n,y),_&&j.insertBefore(t,v.elm,j.nextSibling(m.elm)),v=e[++p],x=n[--y]):On(m,b)?(T(m,b,o,n,d),_&&j.insertBefore(t,m.elm,v.elm),m=e[--h],b=n[++d]):(r(s)&&(s=Cn(e,p,h)),u=i(b.key)?s[b.key]:k(b,e,p,h),r(u)?c(b,o,t,v.elm,!1,n,d):(l=e[u],On(l,b)?(T(l,b,o,n,d),e[u]=void 0,_&&j.insertBefore(t,l.elm,v.elm)):c(b,o,t,v.elm,!1,n,d)),b=n[++d]);p>h?(f=r(n[y+1])?null:n[y+1].elm,g(t,f,n,d,y,o)):d>y&&w(e,p,h)}function k(t,e,n,r){for(var o=n;o<r;o++){var a=e[o];if(i(a)&&On(t,a))return o}}function T(t,e,n,a,s,c){if(t!==e){i(e.elm)&&i(a)&&(e=a[s]=I(e));var u=e.elm=t.elm;if(o(t.isAsyncPlaceholder))return void(i(e.asyncFactory.resolved)?A(t.elm,e,n):e.isAsyncPlaceholder=!0);if(o(e.isStatic)&&o(t.isStatic)&&e.key===t.key&&(o(e.isCloned)||o(e.isOnce)))return void(e.componentInstance=t.componentInstance);var l,f=e.data;i(f)&&i(l=f.hook)&&i(l=l.prepatch)&&l(t,e);var p=t.children,d=e.children;if(i(f)&&h(e)){for(l=0;l<S.update.length;++l)S.update[l](t,e);i(l=f.hook)&&i(l=l.update)&&l(t,e)}r(e.text)?i(p)&&i(d)?p!==d&&_(u,p,d,n,c):i(d)?(i(t.text)&&j.setTextContent(u,""),g(u,null,d,0,d.length-1,n)):i(p)?w(p,0,p.length-1):i(t.text)&&j.setTextContent(u,""):t.text!==e.text&&j.setTextContent(u,e.text),i(f)&&i(l=f.hook)&&i(l=l.postpatch)&&l(t,e)}}function O(t,e,n){if(o(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r<e.length;++r)e[r].data.hook.insert(e[r])}function A(t,e,n,r){var a,s=e.tag,c=e.data,u=e.children;if(r=r||c&&c.pre,e.elm=t,o(e.isComment)&&i(e.asyncFactory))return e.isAsyncPlaceholder=!0,!0;if(i(c)&&(i(a=c.hook)&&i(a=a.init)&&a(e,!0),i(a=e.componentInstance)))return l(e,n),!0;if(i(s)){if(i(u))if(t.hasChildNodes())if(i(a=c)&&i(a=a.domProps)&&i(a=a.innerHTML)){if(a!==t.innerHTML)return!1}else{for(var f=!0,p=t.firstChild,h=0;h<u.length;h++){if(!p||!A(p,u[h],n,r)){f=!1;break}p=p.nextSibling}if(!f||p)return!1}else d(e,u,n);if(i(c)){var v=!1;for(var y in c)if(!L(y)){v=!0,m(e,n);break}!v&&c.class&&ft(c.class)}}else t.data!==e.text&&(t.data=e.text);return!0}var C,E,S={},P=t.modules,j=t.nodeOps;for(C=0;C<Ms.length;++C)for(S[Ms[C]]=[],E=0;E<P.length;++E)i(P[E][Ms[C]])&&S[Ms[C]].push(P[E][Ms[C]]);var L=v("attrs,class,staticClass,staticStyle,key");return function(t,n,a,s){if(r(n))return void(i(t)&&b(t));var u=!1,l=[];if(r(t))u=!0,c(n,l);else{var f=i(t.nodeType);if(!f&&On(t,n))T(t,n,l,null,null,s);else{if(f){if(1===t.nodeType&&t.hasAttribute(Do)&&(t.removeAttribute(Do),a=!0),o(a)&&A(t,n,l))return O(n,l,!0),t;t=e(t)}var p=t.elm,d=j.parentNode(p);if(c(n,l,p._leaveCb?null:d,j.nextSibling(p)),i(n.parent))for(var v=n.parent,m=h(n);v;){for(var y=0;y<S.destroy.length;++y)S.destroy[y](v);if(v.elm=n.elm,m){for(var g=0;g<S.create.length;++g)S.create[g](Ls,v);var x=v.data.hook.insert;if(x.merged)for(var _=1;_<x.fns.length;_++)x.fns[_]()}else Tn(v);v=v.parent}i(d)?w([t],0,0):i(t.tag)&&b(t)}}return O(n,l,u),n.elm}}({nodeOps:Ps,modules:fc});Go&&document.addEventListener("selectionchange",function(){var t=document.activeElement;t&&t.vmodel&&Yr(t,"input")});var dc={inserted:function(t,e,n,r){"select"===n.tag?(r.elm&&!r.elm._vOptions?vt(n,"postpatch",function(){dc.componentUpdated(t,e,n)}):Fr(t,e,n.context),t._vOptions=[].map.call(t.options,Hr)):("textarea"===n.tag||Ss(t.type))&&(t._vModifiers=e.modifiers,e.modifiers.lazy||(t.addEventListener("compositionstart",Xr),t.addEventListener("compositionend",zr),t.addEventListener("change",zr),Go&&(t.vmodel=!0)))},componentUpdated:function(t,e,n){if("select"===n.tag){Fr(t,e,n.context);var r=t._vOptions,i=t._vOptions=[].map.call(t.options,Hr);i.some(function(t,e){return!O(t,r[e])})&&(t.multiple?e.value.some(function(t){return Ur(t,i)}):e.value!==e.oldValue&&Ur(e.value,i))&&Yr(t,"change")}}},hc={bind:function(t,e,n){var r=e.value;n=qr(n);var i=n.data&&n.data.transition,o=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&i?(n.data.show=!0,$r(n,function(){t.style.display=o})):t.style.display=r?o:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&(n=qr(n),n.data&&n.data.transition?(n.data.show=!0,r?$r(n,function(){t.style.display=t.__vOriginalDisplay}):Ir(n,function(){t.style.display="none"})):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,i){i||(t.style.display=t.__vOriginalDisplay)}},vc={model:dc,show:hc},mc={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]},yc=function(t){return t.tag||Ct(t)},gc=function(t){return"show"===t.name},bc={name:"transition",props:mc,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(yc),n.length)){var r=this.mode,i=n[0];if(Kr(this.$vnode))return i;var o=Vr(i);if(!o)return i;if(this._leaving)return Gr(t,i);var a="__transition-"+this._uid+"-";o.key=null==o.key?o.isComment?a+"comment":a+o.tag:s(o.key)?0===String(o.key).indexOf(a)?o.key:a+o.key:o.key;var c=(o.data||(o.data={})).transition=Wr(this),u=this._vnode,l=Vr(u);if(o.data.directives&&o.data.directives.some(gc)&&(o.data.show=!0),l&&l.data&&!Jr(o,l)&&!Ct(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=_({},c);if("out-in"===r)return this._leaving=!0,vt(f,"afterLeave",function(){e._leaving=!1,e.$forceUpdate()}),Gr(t,i);if("in-out"===r){if(Ct(o))return u;var p,d=function(){p()};vt(c,"afterEnter",d),vt(c,"enterCancelled",d),vt(f,"delayLeave",function(t){p=t})}}return i}}},wc=_({tag:String,moveClass:String},mc);delete wc.mode;var xc={props:wc,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var i=ve(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,i(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=Wr(this),s=0;s<i.length;s++){var c=i[s];c.tag&&null!=c.key&&0!==String(c.key).indexOf("__vlist")&&(o.push(c),n[c.key]=c,(c.data||(c.data={})).transition=a)}if(r){for(var u=[],l=[],f=0;f<r.length;f++){var p=r[f];p.data.transition=a,p.data.pos=p.elm.getBoundingClientRect(),n[p.key]?u.push(p):l.push(p)}this.kept=t(e,null,u),this.removed=l}return t(e,null,o)},updated:function(){var t=this.prevChildren,e=this.moveClass||(this.name||"v")+"-move";t.length&&this.hasMove(t[0].elm,e)&&(t.forEach(Qr),t.forEach(Zr),t.forEach(ti),this._reflow=document.body.offsetHeight,t.forEach(function(t){if(t.data.moved){var n=t.elm,r=n.style;Er(n,e),r.transform=r.WebkitTransform=r.transitionDuration="",n.addEventListener(ic,n._moveCb=function t(r){r&&r.target!==n||r&&!/transform$/.test(r.propertyName)||(n.removeEventListener(ic,t),n._moveCb=null,Sr(n,e))})}}))},methods:{hasMove:function(t,e){if(!tc)return!1;if(this._hasMove)return this._hasMove;var n=t.cloneNode();t._transitionClasses&&t._transitionClasses.forEach(function(t){Or(n,t)}),Tr(n,e),n.style.display="none",this.$el.appendChild(n);var r=jr(n);return this.$el.removeChild(n),this._hasMove=r.hasTransform}}},_c={Transition:bc,TransitionGroup:xc};ze.config.mustUseProp=hs,ze.config.isReservedTag=Cs,ze.config.isReservedAttr=ps,ze.config.getTagNamespace=un,ze.config.isUnknownElement=ln,_(ze.options.directives,vc),_(ze.options.components,_c),ze.prototype.__patch__=zo?pc:T,ze.prototype.$mount=function(t,e){return t=t&&zo?fn(t):void 0,ye(this,t,e)},zo&&setTimeout(function(){Bo.devtools&&oa&&oa.emit("init",ze)},0);var kc,Tc,Oc,Ac,Cc,Ec,Sc,Pc,jc,Lc,Mc,$c,Ic,Nc=/\{\{((?:.|\r?\n)+?)\}\}/g,Dc=/[-.*+?^${}()|[\]\/\\]/g,Rc=g(function(t){var e=t[0].replace(Dc,"\\$&"),n=t[1].replace(Dc,"\\$&");return new RegExp(e+"((?:.|\\n)+?)"+n,"g")}),Fc={staticKeys:["staticClass"],transformNode:ni,genData:ri},Bc={staticKeys:["staticStyle"],transformNode:ii,genData:oi},Uc={decode:function(t){return kc=kc||document.createElement("div"),kc.innerHTML=t,kc.textContent}},Hc=v("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),Xc=v("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),zc=v("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Yc=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,qc=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Vc="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+Uo.source+"]*",Wc="((?:"+Vc+"\\:)?"+Vc+")",Gc=new RegExp("^<"+Wc),Kc=/^\s*(\/?)>/,Jc=new RegExp("^<\\/"+Wc+"[^>]*>"),Qc=/^<!DOCTYPE [^>]+>/i,Zc=/^<!\--/,tu=/^<!\[/,eu=v("script,style,textarea",!0),nu={},ru={"&lt;":"<","&gt;":">","&quot;":'"',"&amp;":"&","&#10;":"\n","&#9;":"\t","&#39;":"'"},iu=/&(?:lt|gt|quot|amp|#39);/g,ou=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,au=v("pre,textarea",!0),su=function(t,e){return t&&au(t)&&"\n"===e[0]},cu=/^@|^v-on:/,uu=/^v-|^@|^:|^#/,lu=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,fu=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,pu=/^\(|\)$/g,du=/^\[.*\]$/,hu=/:(.*)$/,vu=/^:|^\.|^v-bind:/,mu=/\.[^.\]]+(?=[^\]]*$)/g,yu=/^v-slot(:|$)|^#/,gu=/[\r\n]/,bu=/[ \f\t\r\n]+/g,wu=g(Uc.decode),xu="_empty_",_u=/^xmlns:NS\d+/,ku=/^NS\d+:/,Tu={preTransformNode:Mi},Ou=[Fc,Bc,Tu],Au={model:ar,text:Ii,html:Ni},Cu={expectHTML:!0,modules:Ou,directives:Au,isPreTag:As,isUnaryTag:Hc,mustUseProp:hs,canBeLeftOpenTag:Xc,isReservedTag:Cs,getTagNamespace:un,staticKeys:function(t){return t.reduce(function(t,e){return t.concat(e.staticKeys||[])},[]).join(",")}(Ou)},Eu=g(Ri),Su=/^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/,Pu=/\([^)]*?\);*$/,ju=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Lu={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Mu={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},$u=function(t){return"if("+t+")return null;"},Iu={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:$u("$event.target !== $event.currentTarget"),ctrl:$u("!$event.ctrlKey"),shift:$u("!$event.shiftKey"),alt:$u("!$event.altKey"),meta:$u("!$event.metaKey"),left:$u("'button' in $event && $event.button !== 0"),middle:$u("'button' in $event && $event.button !== 1"),right:$u("'button' in $event && $event.button !== 2")},Nu={on:Vi,bind:Wi,cloak:T},Du=function(t){this.options=t,this.warn=t.warn||Fn,this.transforms=Bn(t.modules,"transformCode"),this.dataGenFns=Bn(t.modules,"genData"),this.directives=_(_({},Nu),t.directives);var e=t.isReservedTag||Io;this.maybeComponent=function(t){return!!t.component||!e(t.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1},Ru=(new RegExp("\\b"+"do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,super,throw,while,yield,delete,export,import,return,switch,default,extends,finally,continue,debugger,function,arguments".split(",").join("\\b|\\b")+"\\b"),new RegExp("\\b"+"delete,typeof,void".split(",").join("\\s*\\([^\\)]*\\)|\\b")+"\\s*\\([^\\)]*\\)"),function(t){return function(e){function n(n,r){var i=Object.create(e),o=[],a=[],s=function(t,e,n){(n?a:o).push(t)};if(r){r.modules&&(i.modules=(e.modules||[]).concat(r.modules)),r.directives&&(i.directives=_(Object.create(e.directives||null),r.directives));for(var c in r)"modules"!==c&&"directives"!==c&&(i[c]=r[c])}i.warn=s;var u=t(n.trim(),i);return u.errors=o,u.tips=a,u}return{compile:n,compileToFunctions:xo(n)}}}(function(t,e){var n=ui(t.trim(),e);!1!==e.optimize&&Di(n,e);var r=Gi(n,e);return{ast:n,render:r.render,staticRenderFns:r.staticRenderFns}})),Fu=Ru(Cu),Bu=(Fu.compile,Fu.compileToFunctions),Uu=!!zo&&_o(!1),Hu=!!zo&&_o(!0),Xu=g(function(t){var e=fn(t);return e&&e.innerHTML}),zu=ze.prototype.$mount;ze.prototype.$mount=function(t,e){if((t=t&&fn(t))===document.body||t===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=Xu(r));else{if(!r.nodeType)return this;r=r.innerHTML}else t&&(r=ko(t));if(r){var i=Bu(r,{outputSourceRange:!1,shouldDecodeNewlines:Uu,shouldDecodeNewlinesForHref:Hu,delimiters:n.delimiters,comments:n.comments},this),o=i.render,a=i.staticRenderFns;n.render=o,n.staticRenderFns=a}}return zu.call(this,t,e)},ze.compile=Bu,e.a=ze}).call(e,n(3),n(18).setImmediate)},,,function(t,e,n){"use strict";(function(e){function r(t,e){!i.isUndefined(t)&&i.isUndefined(t["Content-Type"])&&(t["Content-Type"]=e)}var i=n(0),o=n(26),a={"Content-Type":"application/x-www-form-urlencoded"},s={adapter:function(){var t;return"undefined"!=typeof XMLHttpRequest?t=n(11):void 0!==e&&(t=n(11)),t}(),transformRequest:[function(t,e){return o(e,"Content-Type"),i.isFormData(t)||i.isArrayBuffer(t)||i.isBuffer(t)||i.isStream(t)||i.isFile(t)||i.isBlob(t)?t:i.isArrayBufferView(t)?t.buffer:i.isURLSearchParams(t)?(r(e,"application/x-www-form-urlencoded;charset=utf-8"),t.toString()):i.isObject(t)?(r(e,"application/json;charset=utf-8"),JSON.stringify(t)):t}],transformResponse:[function(t){if("string"==typeof t)try{t=JSON.parse(t)}catch(t){}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(t){return t>=200&&t<300}};s.headers={common:{Accept:"application/json, text/plain, */*"}},i.forEach(["delete","get","head"],function(t){s.headers[t]={}}),i.forEach(["post","put","patch"],function(t){s.headers[t]=i.merge(a)}),t.exports=s}).call(e,n(8))},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(t){if(l===setTimeout)return setTimeout(t,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(t,0);try{return l(t,0)}catch(e){try{return l.call(null,t,0)}catch(e){return l.call(this,t,0)}}}function o(t){if(f===clearTimeout)return clearTimeout(t);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(t);try{return f(t)}catch(e){try{return f.call(null,t)}catch(e){return f.call(this,t)}}}function a(){v&&d&&(v=!1,d.length?h=d.concat(h):m=-1,h.length&&s())}function s(){if(!v){var t=i(a);v=!0;for(var e=h.length;e;){for(d=h,h=[];++m<e;)d&&d[m].run();m=-1,e=h.length}d=null,v=!1,o(t)}}function c(t,e){this.fun=t,this.array=e}function u(){}var l,f,p=t.exports={};!function(){try{l="function"==typeof setTimeout?setTimeout:n}catch(t){l=n}try{f="function"==typeof clearTimeout?clearTimeout:r}catch(t){f=r}}();var d,h=[],v=!1,m=-1;p.nextTick=function(t){var e=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)e[n-1]=arguments[n];h.push(new c(t,e)),1!==h.length||v||i(s)},c.prototype.run=function(){this.fun.apply(null,this.array)},p.title="browser",p.browser=!0,p.env={},p.argv=[],p.version="",p.versions={},p.on=u,p.addListener=u,p.once=u,p.off=u,p.removeListener=u,p.removeAllListeners=u,p.emit=u,p.prependListener=u,p.prependOnceListener=u,p.listeners=function(t){return[]},p.binding=function(t){throw new Error("process.binding is not supported")},p.cwd=function(){return"/"},p.chdir=function(t){throw new Error("process.chdir is not supported")},p.umask=function(){return 0}},function(t,e,n){t.exports=n(23)},function(t,e,n){"use strict";t.exports=function(t,e){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return t.apply(e,n)}}},function(t,e,n){"use strict";var r=n(0),i=n(27),o=n(29),a=n(30),s=n(31),c=n(12);t.exports=function(t){return new Promise(function(e,u){var l=t.data,f=t.headers;r.isFormData(l)&&delete f["Content-Type"];var p=new XMLHttpRequest;if(t.auth){var d=t.auth.username||"",h=t.auth.password||"";f.Authorization="Basic "+btoa(d+":"+h)}if(p.open(t.method.toUpperCase(),o(t.url,t.params,t.paramsSerializer),!0),p.timeout=t.timeout,p.onreadystatechange=function(){if(p&&4===p.readyState&&(0!==p.status||p.responseURL&&0===p.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in p?a(p.getAllResponseHeaders()):null,r=t.responseType&&"text"!==t.responseType?p.response:p.responseText,o={data:r,status:p.status,statusText:p.statusText,headers:n,config:t,request:p};i(e,u,o),p=null}},p.onerror=function(){u(c("Network Error",t,null,p)),p=null},p.ontimeout=function(){u(c("timeout of "+t.timeout+"ms exceeded",t,"ECONNABORTED",p)),p=null},r.isStandardBrowserEnv()){var v=n(32),m=(t.withCredentials||s(t.url))&&t.xsrfCookieName?v.read(t.xsrfCookieName):void 0;m&&(f[t.xsrfHeaderName]=m)}if("setRequestHeader"in p&&r.forEach(f,function(t,e){void 0===l&&"content-type"===e.toLowerCase()?delete f[e]:p.setRequestHeader(e,t)}),t.withCredentials&&(p.withCredentials=!0),t.responseType)try{p.responseType=t.responseType}catch(e){if("json"!==t.responseType)throw e}"function"==typeof t.onDownloadProgress&&p.addEventListener("progress",t.onDownloadProgress),"function"==typeof t.onUploadProgress&&p.upload&&p.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(t){p&&(p.abort(),u(t),p=null)}),void 0===l&&(l=null),p.send(l)})}},function(t,e,n){"use strict";var r=n(28);t.exports=function(t,e,n,i,o){var a=new Error(t);return r(a,e,n,i,o)}},function(t,e,n){"use strict";t.exports=function(t){return!(!t||!t.__CANCEL__)}},function(t,e,n){"use strict";function r(t){this.message=t}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,t.exports=r},function(t,e){(function(e){t.exports=e}).call(e,{})},,,function(t,e,n){(function(t){function r(t,e){this._id=t,this._clearFn=e}var i=void 0!==t&&t||"undefined"!=typeof self&&self||window,o=Function.prototype.apply;e.setTimeout=function(){return new r(o.call(setTimeout,i,arguments),clearTimeout)},e.setInterval=function(){return new r(o.call(setInterval,i,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t&&t.close()},r.prototype.unref=r.prototype.ref=function(){},r.prototype.close=function(){this._clearFn.call(i,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n(19),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(e,n(3))},function(t,e,n){(function(t,e){!function(t,n){"use strict";function r(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n<e.length;n++)e[n]=arguments[n+1];var r={callback:t,args:e};return u[c]=r,s(c),c++}function i(t){delete u[t]}function o(t){var e=t.callback,r=t.args;switch(r.length){case 0:e();break;case 1:e(r[0]);break;case 2:e(r[0],r[1]);break;case 3:e(r[0],r[1],r[2]);break;default:e.apply(n,r)}}function a(t){if(l)setTimeout(a,0,t);else{var e=u[t];if(e){l=!0;try{o(e)}finally{i(t),l=!1}}}}if(!t.setImmediate){var s,c=1,u={},l=!1,f=t.document,p=Object.getPrototypeOf&&Object.getPrototypeOf(t);p=p&&p.setTimeout?p:t,"[object process]"==={}.toString.call(t.process)?function(){s=function(t){e.nextTick(function(){a(t)})}}():function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?function(){var e="setImmediate$"+Math.random()+"$",n=function(n){n.source===t&&"string"==typeof n.data&&0===n.data.indexOf(e)&&a(+n.data.slice(e.length))};t.addEventListener?t.addEventListener("message",n,!1):t.attachEvent("onmessage",n),s=function(n){t.postMessage(e+n,"*")}}():t.MessageChannel?function(){var t=new MessageChannel;t.port1.onmessage=function(t){a(t.data)},s=function(e){t.port2.postMessage(e)}}():f&&"onreadystatechange"in f.createElement("script")?function(){var t=f.documentElement;s=function(e){var n=f.createElement("script");n.onreadystatechange=function(){a(e),n.onreadystatechange=null,t.removeChild(n),n=null},t.appendChild(n)}}():function(){s=function(t){setTimeout(a,0,t)}}(),p.setImmediate=r,p.clearImmediate=i}}("undefined"==typeof self?void 0===t?this:t:self)}).call(e,n(3),n(8))},function(t,e,n){"use strict";function r(t){return t&&DataView.prototype.isPrototypeOf(t)}function i(t){if("string"!=typeof t&&(t=String(t)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(t)||""===t)throw new TypeError('Invalid character in header field name: "'+t+'"');return t.toLowerCase()}function o(t){return"string"!=typeof t&&(t=String(t)),t}function a(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return _.iterable&&(e[Symbol.iterator]=function(){return e}),e}function s(t){this.map={},t instanceof s?t.forEach(function(t,e){this.append(e,t)},this):Array.isArray(t)?t.forEach(function(t){this.append(t[0],t[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(e){this.append(e,t[e])},this)}function c(t){if(t.bodyUsed)return Promise.reject(new TypeError("Already read"));t.bodyUsed=!0}function u(t){return new Promise(function(e,n){t.onload=function(){e(t.result)},t.onerror=function(){n(t.error)}})}function l(t){var e=new FileReader,n=u(e);return e.readAsArrayBuffer(t),n}function f(t){var e=new FileReader,n=u(e);return e.readAsText(t),n}function p(t){for(var e=new Uint8Array(t),n=new Array(e.length),r=0;r<e.length;r++)n[r]=String.fromCharCode(e[r]);return n.join("")}function d(t){if(t.slice)return t.slice(0);var e=new Uint8Array(t.byteLength);return e.set(new Uint8Array(t)),e.buffer}function h(){return this.bodyUsed=!1,this._initBody=function(t){this.bodyUsed=this.bodyUsed,this._bodyInit=t,t?"string"==typeof t?this._bodyText=t:_.blob&&Blob.prototype.isPrototypeOf(t)?this._bodyBlob=t:_.formData&&FormData.prototype.isPrototypeOf(t)?this._bodyFormData=t:_.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)?this._bodyText=t.toString():_.arrayBuffer&&_.blob&&r(t)?(this._bodyArrayBuffer=d(t.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):_.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(t)||T(t))?this._bodyArrayBuffer=d(t):this._bodyText=t=Object.prototype.toString.call(t):this._bodyText="",this.headers.get("content-type")||("string"==typeof t?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):_.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},_.blob&&(this.blob=function(){var t=c(this);if(t)return t;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){if(this._bodyArrayBuffer){return c(this)||(ArrayBuffer.isView(this._bodyArrayBuffer)?Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset,this._bodyArrayBuffer.byteOffset+this._bodyArrayBuffer.byteLength)):Promise.resolve(this._bodyArrayBuffer))}return this.blob().then(l)}),this.text=function(){var t=c(this);if(t)return t;if(this._bodyBlob)return f(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(p(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},_.formData&&(this.formData=function(){return this.text().then(y)}),this.json=function(){return this.text().then(JSON.parse)},this}function v(t){var e=t.toUpperCase();return O.indexOf(e)>-1?e:t}function m(t,e){if(!(this instanceof m))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');e=e||{};var n=e.body;if(t instanceof m){if(t.bodyUsed)throw new TypeError("Already read");this.url=t.url,this.credentials=t.credentials,e.headers||(this.headers=new s(t.headers)),this.method=t.method,this.mode=t.mode,this.signal=t.signal,n||null==t._bodyInit||(n=t._bodyInit,t.bodyUsed=!0)}else this.url=String(t);if(this.credentials=e.credentials||this.credentials||"same-origin",!e.headers&&this.headers||(this.headers=new s(e.headers)),this.method=v(e.method||this.method||"GET"),this.mode=e.mode||this.mode||null,this.signal=e.signal||this.signal,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&n)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(n),!("GET"!==this.method&&"HEAD"!==this.method||"no-store"!==e.cache&&"no-cache"!==e.cache)){var r=/([?&])_=[^&]*/;if(r.test(this.url))this.url=this.url.replace(r,"$1_="+(new Date).getTime());else{var i=/\?/;this.url+=(i.test(this.url)?"&":"?")+"_="+(new Date).getTime()}}}function y(t){var e=new FormData;return t.trim().split("&").forEach(function(t){if(t){var n=t.split("="),r=n.shift().replace(/\+/g," "),i=n.join("=").repla
1
+ webpackJsonpWPRA([0],[function(t,e,n){"use strict";function r(t){return"[object Array]"===T.call(t)}function i(t){return"[object ArrayBuffer]"===T.call(t)}function o(t){return"undefined"!=typeof FormData&&t instanceof FormData}function a(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer}function s(t){return"string"==typeof t}function c(t){return"number"==typeof t}function u(t){return void 0===t}function l(t){return null!==t&&"object"==typeof t}function p(t){return"[object Date]"===T.call(t)}function f(t){return"[object File]"===T.call(t)}function d(t){return"[object Blob]"===T.call(t)}function h(t){return"[object Function]"===T.call(t)}function v(t){return l(t)&&h(t.pipe)}function m(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams}function y(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&"undefined"!=typeof window&&"undefined"!=typeof document}function b(t,e){if(null!==t&&void 0!==t)if("object"!=typeof t&&(t=[t]),r(t))for(var n=0,i=t.length;n<i;n++)e.call(null,t[n],n,t);else for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.call(null,t[o],o,t)}function w(){function t(t,n){"object"==typeof e[n]&&"object"==typeof t?e[n]=w(e[n],t):e[n]=t}for(var e={},n=0,r=arguments.length;n<r;n++)b(arguments[n],t);return e}function x(t,e,n){return b(e,function(e,r){t[r]=n&&"function"==typeof e?_(e,n):e}),t}var _=n(10),k=n(24),T=Object.prototype.toString;t.exports={isArray:r,isArrayBuffer:i,isBuffer:k,isFormData:o,isArrayBufferView:a,isString:s,isNumber:c,isObject:l,isUndefined:u,isDate:p,isFile:f,isBlob:d,isFunction:h,isStream:v,isURLSearchParams:m,isStandardBrowserEnv:g,forEach:b,merge:w,extend:x,trim:y}},function(t,e,n){"use strict";function r(t,e,n,r,i,o,a,s){var c="function"==typeof t?t.options:t;e&&(c.render=e,c.staticRenderFns=n,c._compiled=!0),r&&(c.functional=!0),o&&(c._scopeId="data-v-"+o);var u;if(a?(u=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},c._ssrRegister=u):i&&(u=s?function(){i.call(this,this.$root.$options.shadowRoot)}:i),u)if(c.functional){c._injectStyles=u;var l=c.render;c.render=function(t,e){return u.call(e),l(t,e)}}else{var p=c.beforeCreate;c.beforeCreate=p?[].concat(p,u):[u]}return{exports:t,options:c}}e.a=r},function(t,e){function n(t,e){return function(){t&&t.apply(this,arguments),e&&e.apply(this,arguments)}}var r=/^(attrs|props|on|nativeOn|class|style|hook)$/;t.exports=function(t){return t.reduce(function(t,e){var i,o,a,s,c;for(a in e)if(i=t[a],o=e[a],i&&r.test(a))if("class"===a&&("string"==typeof i&&(c=i,t[a]=i={},i[c]=!0),"string"==typeof o&&(c=o,e[a]=o={},o[c]=!0)),"on"===a||"nativeOn"===a||"hook"===a)for(s in o)i[s]=n(i[s],o[s]);else if(Array.isArray(i))t[a]=i.concat(o);else if(Array.isArray(o))t[a]=[i].concat(o);else for(s in o)i[s]=o[s];else t[a]=e[a];return t},{})}},function(t,e){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){"use strict";(function(t,n){function r(t){return void 0===t||null===t}function i(t){return void 0!==t&&null!==t}function o(t){return!0===t}function a(t){return!1===t}function s(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function c(t){return null!==t&&"object"==typeof t}function u(t){return"[object Object]"===po.call(t)}function l(t){return"[object RegExp]"===po.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function f(t){return null==t?"":"object"==typeof t?JSON.stringify(t,null,2):String(t)}function d(t){var e=parseFloat(t);return isNaN(e)?t:e}function h(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i<r.length;i++)n[r[i]]=!0;return e?function(t){return n[t.toLowerCase()]}:function(t){return n[t]}}function v(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}function m(t,e){return vo.call(t,e)}function y(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}function g(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function b(t,e){return t.bind(e)}function w(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function x(t,e){for(var n in e)t[n]=e[n];return t}function _(t){for(var e={},n=0;n<t.length;n++)t[n]&&x(e,t[n]);return e}function k(t,e,n){}function T(t,e){if(t===e)return!0;var n=c(t),r=c(e);if(!n||!r)return!n&&!r&&String(t)===String(e);try{var i=Array.isArray(t),o=Array.isArray(e);if(i&&o)return t.length===e.length&&t.every(function(t,n){return T(t,e[n])});if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(i||o)return!1;var a=Object.keys(t),s=Object.keys(e);return a.length===s.length&&a.every(function(n){return T(t[n],e[n])})}catch(t){return!1}}function O(t,e){for(var n=0;n<t.length;n++)if(T(t[n],e))return n;return-1}function E(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments))}}function C(t){var e=(t+"").charCodeAt(0);return 36===e||95===e}function A(t,e,n,r){Object.defineProperty(t,e,{value:n,enumerable:!!r,writable:!0,configurable:!0})}function S(t){if(!Ao.test(t)){var e=t.split(".");return function(t){for(var n=0;n<e.length;n++){if(!t)return;t=t[e[n]]}return t}}}function P(t){return"function"==typeof t&&/native code/.test(t.toString())}function j(t){Go.push(t),Wo.target=t}function L(){Go.pop(),Wo.target=Go[Go.length-1]}function M(t){return new Ko(void 0,void 0,void 0,String(t))}function $(t){var e=new Ko(t.tag,t.data,t.children&&t.children.slice(),t.text,t.elm,t.context,t.componentOptions,t.asyncFactory);return e.ns=t.ns,e.isStatic=t.isStatic,e.key=t.key,e.isComment=t.isComment,e.fnContext=t.fnContext,e.fnOptions=t.fnOptions,e.fnScopeId=t.fnScopeId,e.asyncMeta=t.asyncMeta,e.isCloned=!0,e}function I(t){na=t}function N(t,e){t.__proto__=e}function D(t,e,n){for(var r=0,i=n.length;r<i;r++){var o=n[r];A(t,o,e[o])}}function R(t,e){if(c(t)&&!(t instanceof Ko)){var n;return m(t,"__ob__")&&t.__ob__ instanceof ra?n=t.__ob__:na&&!Xo()&&(Array.isArray(t)||u(t))&&Object.isExtensible(t)&&!t._isVue&&(n=new ra(t)),e&&n&&n.vmCount++,n}}function F(t,e,n,r,i){var o=new Wo,a=Object.getOwnPropertyDescriptor(t,e);if(!a||!1!==a.configurable){var s=a&&a.get,c=a&&a.set;s&&!c||2!==arguments.length||(n=t[e]);var u=!i&&R(n);Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var e=s?s.call(t):n;return Wo.target&&(o.depend(),u&&(u.dep.depend(),Array.isArray(e)&&H(e))),e},set:function(e){var r=s?s.call(t):n;e===r||e!==e&&r!==r||s&&!c||(c?c.call(t,e):n=e,u=!i&&R(e),o.notify())}})}}function B(t,e,n){if(Array.isArray(t)&&p(e))return t.length=Math.max(t.length,e),t.splice(e,1,n),n;if(e in t&&!(e in Object.prototype))return t[e]=n,n;var r=t.__ob__;return t._isVue||r&&r.vmCount?n:r?(F(r.value,e,n),r.dep.notify(),n):(t[e]=n,n)}function U(t,e){if(Array.isArray(t)&&p(e))return void t.splice(e,1);var n=t.__ob__;t._isVue||n&&n.vmCount||m(t,e)&&(delete t[e],n&&n.dep.notify())}function H(t){for(var e=void 0,n=0,r=t.length;n<r;n++)e=t[n],e&&e.__ob__&&e.__ob__.dep.depend(),Array.isArray(e)&&H(e)}function X(t,e){if(!e)return t;for(var n,r,i,o=Object.keys(e),a=0;a<o.length;a++)n=o[a],r=t[n],i=e[n],m(t,n)?r!==i&&u(r)&&u(i)&&X(r,i):B(t,n,i);return t}function z(t,e,n){return n?function(){var r="function"==typeof e?e.call(n,n):e,i="function"==typeof t?t.call(n,n):t;return r?X(r,i):i}:e?t?function(){return X("function"==typeof e?e.call(this,this):e,"function"==typeof t?t.call(this,this):t)}:e:t}function Y(t,e){var n=e?t?t.concat(e):Array.isArray(e)?e:[e]:t;return n?q(n):n}function q(t){for(var e=[],n=0;n<t.length;n++)-1===e.indexOf(t[n])&&e.push(t[n]);return e}function V(t,e,n,r){var i=Object.create(t||null);return e?x(i,e):i}function W(t,e){var n=t.props;if(n){var r,i,o,a={};if(Array.isArray(n))for(r=n.length;r--;)"string"==typeof(i=n[r])&&(o=yo(i),a[o]={type:null});else if(u(n))for(var s in n)i=n[s],o=yo(s),a[o]=u(i)?i:{type:i};t.props=a}}function G(t,e){var n=t.inject;if(n){var r=t.inject={};if(Array.isArray(n))for(var i=0;i<n.length;i++)r[n[i]]={from:n[i]};else if(u(n))for(var o in n){var a=n[o];r[o]=u(a)?x({from:o},a):{from:a}}}}function K(t){var e=t.directives;if(e)for(var n in e){var r=e[n];"function"==typeof r&&(e[n]={bind:r,update:r})}}function J(t,e,n){function r(r){var i=ia[r]||sa;s[r]=i(t[r],e[r],n,r)}if("function"==typeof e&&(e=e.options),W(e,n),G(e,n),K(e),!e._base&&(e.extends&&(t=J(t,e.extends,n)),e.mixins))for(var i=0,o=e.mixins.length;i<o;i++)t=J(t,e.mixins[i],n);var a,s={};for(a in t)r(a);for(a in e)m(t,a)||r(a);return s}function Q(t,e,n,r){if("string"==typeof n){var i=t[e];if(m(i,n))return i[n];var o=yo(n);if(m(i,o))return i[o];var a=go(o);return m(i,a)?i[a]:i[n]||i[o]||i[a]}}function Z(t,e,n,r){var i=e[t],o=!m(n,t),a=n[t],s=rt(Boolean,i.type);if(s>-1)if(o&&!m(i,"default"))a=!1;else if(""===a||a===wo(t)){var c=rt(String,i.type);(c<0||s<c)&&(a=!0)}if(void 0===a){a=tt(r,i,t);var u=na;I(!0),R(a),I(u)}return a}function tt(t,e,n){if(m(e,"default")){var r=e.default;return t&&t.$options.propsData&&void 0===t.$options.propsData[n]&&void 0!==t._props[n]?t._props[n]:"function"==typeof r&&"Function"!==et(e.type)?r.call(t):r}}function et(t){var e=t&&t.toString().match(/^\s*function (\w+)/);return e?e[1]:""}function nt(t,e){return et(t)===et(e)}function rt(t,e){if(!Array.isArray(e))return nt(e,t)?0:-1;for(var n=0,r=e.length;n<r;n++)if(nt(e[n],t))return n;return-1}function it(t,e,n){if(e)for(var r=e;r=r.$parent;){var i=r.$options.errorCaptured;if(i)for(var o=0;o<i.length;o++)try{var a=!1===i[o].call(r,t,e,n);if(a)return}catch(t){ot(t,r,"errorCaptured hook")}}ot(t,e,n)}function ot(t,e,n){if(Co.errorHandler)try{return Co.errorHandler.call(null,t,e,n)}catch(t){at(t,null,"config.errorHandler")}at(t,e,n)}function at(t,e,n){if(!Po&&!jo||"undefined"==typeof console)throw t;console.error(t)}function st(){ua=!1;var t=ca.slice(0);ca.length=0;for(var e=0;e<t.length;e++)t[e]()}function ct(t){return t._withTask||(t._withTask=function(){la=!0;try{return t.apply(null,arguments)}finally{la=!1}})}function ut(t,e){var n;if(ca.push(function(){if(t)try{t.call(e)}catch(t){it(t,e,"nextTick")}else n&&n(e)}),ua||(ua=!0,la?aa():oa()),!t&&"undefined"!=typeof Promise)return new Promise(function(t){n=t})}function lt(t){pt(t,va),va.clear()}function pt(t,e){var n,r,i=Array.isArray(t);if(!(!i&&!c(t)||Object.isFrozen(t)||t instanceof Ko)){if(t.__ob__){var o=t.__ob__.dep.id;if(e.has(o))return;e.add(o)}if(i)for(n=t.length;n--;)pt(t[n],e);else for(r=Object.keys(t),n=r.length;n--;)pt(t[r[n]],e)}}function ft(t){function e(){var t=arguments,n=e.fns;if(!Array.isArray(n))return n.apply(null,arguments);for(var r=n.slice(),i=0;i<r.length;i++)r[i].apply(null,t)}return e.fns=t,e}function dt(t,e,n,i,a,s){var c,u,l,p;for(c in t)u=t[c],l=e[c],p=ma(c),r(u)||(r(l)?(r(u.fns)&&(u=t[c]=ft(u)),o(p.once)&&(u=t[c]=a(p.name,u,p.capture)),n(p.name,u,p.capture,p.passive,p.params)):u!==l&&(l.fns=u,t[c]=l));for(c in e)r(t[c])&&(p=ma(c),i(p.name,e[c],p.capture))}function ht(t,e,n){function a(){n.apply(this,arguments),v(s.fns,a)}t instanceof Ko&&(t=t.data.hook||(t.data.hook={}));var s,c=t[e];r(c)?s=ft([a]):i(c.fns)&&o(c.merged)?(s=c,s.fns.push(a)):s=ft([c,a]),s.merged=!0,t[e]=s}function vt(t,e,n){var o=e.options.props;if(!r(o)){var a={},s=t.attrs,c=t.props;if(i(s)||i(c))for(var u in o){var l=wo(u);mt(a,c,u,l,!0)||mt(a,s,u,l,!1)}return a}}function mt(t,e,n,r,o){if(i(e)){if(m(e,n))return t[n]=e[n],o||delete e[n],!0;if(m(e,r))return t[n]=e[r],o||delete e[r],!0}return!1}function yt(t){for(var e=0;e<t.length;e++)if(Array.isArray(t[e]))return Array.prototype.concat.apply([],t);return t}function gt(t){return s(t)?[M(t)]:Array.isArray(t)?wt(t):void 0}function bt(t){return i(t)&&i(t.text)&&a(t.isComment)}function wt(t,e){var n,a,c,u,l=[];for(n=0;n<t.length;n++)a=t[n],r(a)||"boolean"==typeof a||(c=l.length-1,u=l[c],Array.isArray(a)?a.length>0&&(a=wt(a,(e||"")+"_"+n),bt(a[0])&&bt(u)&&(l[c]=M(u.text+a[0].text),a.shift()),l.push.apply(l,a)):s(a)?bt(u)?l[c]=M(u.text+a):""!==a&&l.push(M(a)):bt(a)&&bt(u)?l[c]=M(u.text+a.text):(o(t._isVList)&&i(a.tag)&&r(a.key)&&i(e)&&(a.key="__vlist"+e+"_"+n+"__"),l.push(a)));return l}function xt(t,e){return(t.__esModule||Yo&&"Module"===t[Symbol.toStringTag])&&(t=t.default),c(t)?e.extend(t):t}function _t(t,e,n,r,i){var o=Qo();return o.asyncFactory=t,o.asyncMeta={data:e,context:n,children:r,tag:i},o}function kt(t,e,n){if(o(t.error)&&i(t.errorComp))return t.errorComp;if(i(t.resolved))return t.resolved;if(o(t.loading)&&i(t.loadingComp))return t.loadingComp;if(!i(t.contexts)){var a=t.contexts=[n],s=!0,u=function(t){for(var e=0,n=a.length;e<n;e++)a[e].$forceUpdate();t&&(a.length=0)},l=E(function(n){t.resolved=xt(n,e),s?a.length=0:u(!0)}),p=E(function(e){i(t.errorComp)&&(t.error=!0,u(!0))}),f=t(l,p);return c(f)&&("function"==typeof f.then?r(t.resolved)&&f.then(l,p):i(f.component)&&"function"==typeof f.component.then&&(f.component.then(l,p),i(f.error)&&(t.errorComp=xt(f.error,e)),i(f.loading)&&(t.loadingComp=xt(f.loading,e),0===f.delay?t.loading=!0:setTimeout(function(){r(t.resolved)&&r(t.error)&&(t.loading=!0,u(!1))},f.delay||200)),i(f.timeout)&&setTimeout(function(){r(t.resolved)&&p(null)},f.timeout))),s=!1,t.loading?t.loadingComp:t.resolved}t.contexts.push(n)}function Tt(t){return t.isComment&&t.asyncFactory}function Ot(t){if(Array.isArray(t))for(var e=0;e<t.length;e++){var n=t[e];if(i(n)&&(i(n.componentOptions)||Tt(n)))return n}}function Et(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Pt(t,e)}function Ct(t,e){ha.$on(t,e)}function At(t,e){ha.$off(t,e)}function St(t,e){var n=ha;return function r(){null!==e.apply(null,arguments)&&n.$off(t,r)}}function Pt(t,e,n){ha=t,dt(e,n||{},Ct,At,St,t),ha=void 0}function jt(t,e){var n={};if(!t)return n;for(var r=0,i=t.length;r<i;r++){var o=t[r],a=o.data;if(a&&a.attrs&&a.attrs.slot&&delete a.attrs.slot,o.context!==e&&o.fnContext!==e||!a||null==a.slot)(n.default||(n.default=[])).push(o);else{var s=a.slot,c=n[s]||(n[s]=[]);"template"===o.tag?c.push.apply(c,o.children||[]):c.push(o)}}for(var u in n)n[u].every(Lt)&&delete n[u];return n}function Lt(t){return t.isComment&&!t.asyncFactory||" "===t.text}function Mt(t,e){e=e||{};for(var n=0;n<t.length;n++)Array.isArray(t[n])?Mt(t[n],e):e[t[n].key]=t[n].fn;return e}function $t(t){var e=ya;return ya=t,function(){ya=e}}function It(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}function Nt(t,e,n){t.$el=e,t.$options.render||(t.$options.render=Qo),Ut(t,"beforeMount");var r;return r=function(){t._update(t._render(),n)},new Oa(t,r,k,{before:function(){t._isMounted&&!t._isDestroyed&&Ut(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,Ut(t,"mounted")),t}function Dt(t,e,n,r,i){var o=!!(i||t.$options._renderChildren||r.data.scopedSlots||t.$scopedSlots!==lo);if(t.$options._parentVnode=r,t.$vnode=r,t._vnode&&(t._vnode.parent=r),t.$options._renderChildren=i,t.$attrs=r.data.attrs||lo,t.$listeners=n||lo,e&&t.$options.props){I(!1);for(var a=t._props,s=t.$options._propKeys||[],c=0;c<s.length;c++){var u=s[c],l=t.$options.props;a[u]=Z(u,l,e,t)}I(!0),t.$options.propsData=e}n=n||lo;var p=t.$options._parentListeners;t.$options._parentListeners=n,Pt(t,n,p),o&&(t.$slots=jt(i,r.context),t.$forceUpdate())}function Rt(t){for(;t&&(t=t.$parent);)if(t._inactive)return!0;return!1}function Ft(t,e){if(e){if(t._directInactive=!1,Rt(t))return}else if(t._directInactive)return;if(t._inactive||null===t._inactive){t._inactive=!1;for(var n=0;n<t.$children.length;n++)Ft(t.$children[n]);Ut(t,"activated")}}function Bt(t,e){if(!(e&&(t._directInactive=!0,Rt(t))||t._inactive)){t._inactive=!0;for(var n=0;n<t.$children.length;n++)Bt(t.$children[n]);Ut(t,"deactivated")}}function Ut(t,e){j();var n=t.$options[e];if(n)for(var r=0,i=n.length;r<i;r++)try{n[r].call(t)}catch(n){it(n,t,e+" hook")}t._hasHookEvent&&t.$emit("hook:"+e),L()}function Ht(){ka=ga.length=ba.length=0,wa={},xa=_a=!1}function Xt(){_a=!0;var t,e;for(ga.sort(function(t,e){return t.id-e.id}),ka=0;ka<ga.length;ka++)t=ga[ka],t.before&&t.before(),e=t.id,wa[e]=null,t.run();var n=ba.slice(),r=ga.slice();Ht(),qt(n),zt(r),zo&&Co.devtools&&zo.emit("flush")}function zt(t){for(var e=t.length;e--;){var n=t[e],r=n.vm;r._watcher===n&&r._isMounted&&!r._isDestroyed&&Ut(r,"updated")}}function Yt(t){t._inactive=!1,ba.push(t)}function qt(t){for(var e=0;e<t.length;e++)t[e]._inactive=!0,Ft(t[e],!0)}function Vt(t){var e=t.id;if(null==wa[e]){if(wa[e]=!0,_a){for(var n=ga.length-1;n>ka&&ga[n].id>t.id;)n--;ga.splice(n+1,0,t)}else ga.push(t);xa||(xa=!0,ut(Xt))}}function Wt(t,e,n){Ea.get=function(){return this[e][n]},Ea.set=function(t){this[e][n]=t},Object.defineProperty(t,n,Ea)}function Gt(t){t._watchers=[];var e=t.$options;e.props&&Kt(t,e.props),e.methods&&re(t,e.methods),e.data?Jt(t):R(t._data={},!0),e.computed&&Zt(t,e.computed),e.watch&&e.watch!==Ro&&ie(t,e.watch)}function Kt(t,e){var n=t.$options.propsData||{},r=t._props={},i=t.$options._propKeys=[];!t.$parent||I(!1);for(var o in e)!function(o){i.push(o);var a=Z(o,e,n,t);F(r,o,a),o in t||Wt(t,"_props",o)}(o);I(!0)}function Jt(t){var e=t.$options.data;e=t._data="function"==typeof e?Qt(e,t):e||{},u(e)||(e={});for(var n=Object.keys(e),r=t.$options.props,i=(t.$options.methods,n.length);i--;){var o=n[i];r&&m(r,o)||C(o)||Wt(t,"_data",o)}R(e,!0)}function Qt(t,e){j();try{return t.call(e,e)}catch(t){return it(t,e,"data()"),{}}finally{L()}}function Zt(t,e){var n=t._computedWatchers=Object.create(null),r=Xo();for(var i in e){var o=e[i],a="function"==typeof o?o:o.get;r||(n[i]=new Oa(t,a||k,k,Ca)),i in t||te(t,i,o)}}function te(t,e,n){var r=!Xo();"function"==typeof n?(Ea.get=r?ee(e):ne(n),Ea.set=k):(Ea.get=n.get?r&&!1!==n.cache?ee(e):ne(n.get):k,Ea.set=n.set||k),Object.defineProperty(t,e,Ea)}function ee(t){return function(){var e=this._computedWatchers&&this._computedWatchers[t];if(e)return e.dirty&&e.evaluate(),Wo.target&&e.depend(),e.value}}function ne(t){return function(){return t.call(this,this)}}function re(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?k:xo(e[n],t)}function ie(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var i=0;i<r.length;i++)oe(t,n,r[i]);else oe(t,n,r)}}function oe(t,e,n,r){return u(n)&&(r=n,n=n.handler),"string"==typeof n&&(n=t[n]),t.$watch(e,n,r)}function ae(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}function se(t){var e=ce(t.$options.inject,t);e&&(I(!1),Object.keys(e).forEach(function(n){F(t,n,e[n])}),I(!0))}function ce(t,e){if(t){for(var n=Object.create(null),r=Yo?Reflect.ownKeys(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}):Object.keys(t),i=0;i<r.length;i++){for(var o=r[i],a=t[o].from,s=e;s;){if(s._provided&&m(s._provided,a)){n[o]=s._provided[a];break}s=s.$parent}if(!s&&"default"in t[o]){var c=t[o].default;n[o]="function"==typeof c?c.call(e):c}}return n}}function ue(t,e){var n,r,o,a,s;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,o=t.length;r<o;r++)n[r]=e(t[r],r);else if("number"==typeof t)for(n=new Array(t),r=0;r<t;r++)n[r]=e(r+1,r);else if(c(t))for(a=Object.keys(t),n=new Array(a.length),r=0,o=a.length;r<o;r++)s=a[r],n[r]=e(t[s],s,r);return i(n)||(n=[]),n._isVList=!0,n}function le(t,e,n,r){var i,o=this.$scopedSlots[t];o?(n=n||{},r&&(n=x(x({},r),n)),i=o(n)||e):i=this.$slots[t]||e;var a=n&&n.slot;return a?this.$createElement("template",{slot:a},i):i}function pe(t){return Q(this.$options,"filters",t,!0)||ko}function fe(t,e){return Array.isArray(t)?-1===t.indexOf(e):t!==e}function de(t,e,n,r,i){var o=Co.keyCodes[e]||n;return i&&r&&!Co.keyCodes[e]?fe(i,r):o?fe(o,t):r?wo(r)!==e:void 0}function he(t,e,n,r,i){if(n&&c(n)){Array.isArray(n)&&(n=_(n));var o;for(var a in n)!function(a){if("class"===a||"style"===a||ho(a))o=t;else{var s=t.attrs&&t.attrs.type;o=r||Co.mustUseProp(e,s,a)?t.domProps||(t.domProps={}):t.attrs||(t.attrs={})}var c=yo(a);a in o||c in o||(o[a]=n[a],!i)||((t.on||(t.on={}))["update:"+c]=function(t){n[a]=t})}(a)}return t}function ve(t,e){var n=this._staticTrees||(this._staticTrees=[]),r=n[t];return r&&!e?r:(r=n[t]=this.$options.staticRenderFns[t].call(this._renderProxy,null,this),ye(r,"__static__"+t,!1),r)}function me(t,e,n){return ye(t,"__once__"+e+(n?"_"+n:""),!0),t}function ye(t,e,n){if(Array.isArray(t))for(var r=0;r<t.length;r++)t[r]&&"string"!=typeof t[r]&&ge(t[r],e+"_"+r,n);else ge(t,e,n)}function ge(t,e,n){t.isStatic=!0,t.key=e,t.isOnce=n}function be(t,e){if(e&&u(e)){var n=t.on=t.on?x({},t.on):{};for(var r in e){var i=n[r],o=e[r];n[r]=i?[].concat(i,o):o}}return t}function we(t){t._o=me,t._n=d,t._s=f,t._l=ue,t._t=le,t._q=T,t._i=O,t._m=ve,t._f=pe,t._k=de,t._b=he,t._v=M,t._e=Qo,t._u=Mt,t._g=be}function xe(t,e,n,r,i){var a,s=i.options;m(r,"_uid")?(a=Object.create(r),a._original=r):(a=r,r=r._original);var c=o(s._compiled),u=!c;this.data=t,this.props=e,this.children=n,this.parent=r,this.listeners=t.on||lo,this.injections=ce(s.inject,r),this.slots=function(){return jt(n,r)},c&&(this.$options=s,this.$slots=this.slots(),this.$scopedSlots=t.scopedSlots||lo),s._scopeId?this._c=function(t,e,n,i){var o=Pe(a,t,e,n,i,u);return o&&!Array.isArray(o)&&(o.fnScopeId=s._scopeId,o.fnContext=r),o}:this._c=function(t,e,n,r){return Pe(a,t,e,n,r,u)}}function _e(t,e,n,r,o){var a=t.options,s={},c=a.props;if(i(c))for(var u in c)s[u]=Z(u,c,e||lo);else i(n.attrs)&&Te(s,n.attrs),i(n.props)&&Te(s,n.props);var l=new xe(n,s,o,r,t),p=a.render.call(null,l._c,l);if(p instanceof Ko)return ke(p,n,l.parent,a,l);if(Array.isArray(p)){for(var f=gt(p)||[],d=new Array(f.length),h=0;h<f.length;h++)d[h]=ke(f[h],n,l.parent,a,l);return d}}function ke(t,e,n,r,i){var o=$(t);return o.fnContext=n,o.fnOptions=r,e.slot&&((o.data||(o.data={})).slot=e.slot),o}function Te(t,e){for(var n in e)t[yo(n)]=e[n]}function Oe(t,e,n,a,s){if(!r(t)){var u=n.$options._base;if(c(t)&&(t=u.extend(t)),"function"==typeof t){var l;if(r(t.cid)&&(l=t,void 0===(t=kt(l,u,n))))return _t(l,e,n,a,s);e=e||{},Ne(t),i(e.model)&&Se(t.options,e);var p=vt(e,t,s);if(o(t.options.functional))return _e(t,p,e,n,a);var f=e.on;if(e.on=e.nativeOn,o(t.options.abstract)){var d=e.slot;e={},d&&(e.slot=d)}Ce(e);var h=t.options.name||s;return new Ko("vue-component-"+t.cid+(h?"-"+h:""),e,void 0,void 0,void 0,n,{Ctor:t,propsData:p,listeners:f,tag:s,children:a},l)}}}function Ee(t,e){var n={_isComponent:!0,_parentVnode:t,parent:e},r=t.data.inlineTemplate;return i(r)&&(n.render=r.render,n.staticRenderFns=r.staticRenderFns),new t.componentOptions.Ctor(n)}function Ce(t){for(var e=t.hook||(t.hook={}),n=0;n<Sa.length;n++){var r=Sa[n],i=e[r],o=Aa[r];i===o||i&&i._merged||(e[r]=i?Ae(o,i):o)}}function Ae(t,e){var n=function(n,r){t(n,r),e(n,r)};return n._merged=!0,n}function Se(t,e){var n=t.model&&t.model.prop||"value",r=t.model&&t.model.event||"input";(e.props||(e.props={}))[n]=e.model.value;var o=e.on||(e.on={}),a=o[r],s=e.model.callback;i(a)?(Array.isArray(a)?-1===a.indexOf(s):a!==s)&&(o[r]=[s].concat(a)):o[r]=s}function Pe(t,e,n,r,i,a){return(Array.isArray(n)||s(n))&&(i=r,r=n,n=void 0),o(a)&&(i=ja),je(t,e,n,r,i)}function je(t,e,n,r,o){if(i(n)&&i(n.__ob__))return Qo();if(i(n)&&i(n.is)&&(e=n.is),!e)return Qo();Array.isArray(r)&&"function"==typeof r[0]&&(n=n||{},n.scopedSlots={default:r[0]},r.length=0),o===ja?r=gt(r):o===Pa&&(r=yt(r));var a,s;if("string"==typeof e){var c;s=t.$vnode&&t.$vnode.ns||Co.getTagNamespace(e),a=Co.isReservedTag(e)?new Ko(Co.parsePlatformTagName(e),n,r,void 0,void 0,t):n&&n.pre||!i(c=Q(t.$options,"components",e))?new Ko(e,n,r,void 0,void 0,t):Oe(c,n,t,r,e)}else a=Oe(e,n,t,r);return Array.isArray(a)?a:i(a)?(i(s)&&Le(a,s),i(n)&&Me(n),a):Qo()}function Le(t,e,n){if(t.ns=e,"foreignObject"===t.tag&&(e=void 0,n=!0),i(t.children))for(var a=0,s=t.children.length;a<s;a++){var c=t.children[a];i(c.tag)&&(r(c.ns)||o(n)&&"svg"!==c.tag)&&Le(c,e,n)}}function Me(t){c(t.style)&&lt(t.style),c(t.class)&&lt(t.class)}function $e(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,r=n&&n.context;t.$slots=jt(e._renderChildren,r),t.$scopedSlots=lo,t._c=function(e,n,r,i){return Pe(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return Pe(t,e,n,r,i,!0)};var i=n&&n.data;F(t,"$attrs",i&&i.attrs||lo,null,!0),F(t,"$listeners",e._parentListeners||lo,null,!0)}function Ie(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}function Ne(t){var e=t.options;if(t.super){var n=Ne(t.super);if(n!==t.superOptions){t.superOptions=n;var r=De(t);r&&x(t.extendOptions,r),e=t.options=J(n,t.extendOptions),e.name&&(e.components[e.name]=t)}}return e}function De(t){var e,n=t.options,r=t.sealedOptions;for(var i in n)n[i]!==r[i]&&(e||(e={}),e[i]=n[i]);return e}function Re(t){this._init(t)}function Fe(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=w(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}function Be(t){t.mixin=function(t){return this.options=J(this.options,t),this}}function Ue(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i[r])return i[r];var o=t.name||n.options.name,a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=J(n.options,t),a.super=n,a.options.props&&He(a),a.options.computed&&Xe(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,Oo.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=x({},a.options),i[r]=a,a}}function He(t){var e=t.options.props;for(var n in e)Wt(t.prototype,"_props",n)}function Xe(t){var e=t.options.computed;for(var n in e)te(t.prototype,n,e[n])}function ze(t){Oo.forEach(function(e){t[e]=function(t,n){return n?("component"===e&&u(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}})}function Ye(t){return t&&(t.Ctor.options.name||t.tag)}function qe(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!l(t)&&t.test(e)}function Ve(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var s=Ye(a.componentOptions);s&&!e(s)&&We(n,o,r,i)}}}function We(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,v(n,e)}function Ge(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=Ke(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=Ke(e,n.data));return Je(e.staticClass,e.class)}function Ke(t,e){return{staticClass:Qe(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function Je(t,e){return i(t)||i(e)?Qe(t,Ze(e)):""}function Qe(t,e){return t?e?t+" "+e:t:e||""}function Ze(t){return Array.isArray(t)?tn(t):c(t)?en(t):"string"==typeof t?t:""}function tn(t){for(var e,n="",r=0,o=t.length;r<o;r++)i(e=Ze(t[r]))&&""!==e&&(n&&(n+=" "),n+=e);return n}function en(t){var e="";for(var n in t)t[n]&&(e&&(e+=" "),e+=n);return e}function nn(t){return ns(t)?"svg":"math"===t?"math":void 0}function rn(t){if(!Po)return!0;if(is(t))return!1;if(t=t.toLowerCase(),null!=os[t])return os[t];var e=document.createElement(t);return t.indexOf("-")>-1?os[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:os[t]=/HTMLUnknownElement/.test(e.toString())}function on(t){if("string"==typeof t){return document.querySelector(t)||document.createElement("div")}return t}function an(t,e){var n=document.createElement(t);return"select"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute("multiple","multiple"),n)}function sn(t,e){return document.createElementNS(ts[t],e)}function cn(t){return document.createTextNode(t)}function un(t){return document.createComment(t)}function ln(t,e,n){t.insertBefore(e,n)}function pn(t,e){t.removeChild(e)}function fn(t,e){t.appendChild(e)}function dn(t){return t.parentNode}function hn(t){return t.nextSibling}function vn(t){return t.tagName}function mn(t,e){t.textContent=e}function yn(t,e){t.setAttribute(e,"")}function gn(t,e){var n=t.data.ref;if(i(n)){var r=t.context,o=t.componentInstance||t.elm,a=r.$refs;e?Array.isArray(a[n])?v(a[n],o):a[n]===o&&(a[n]=void 0):t.data.refInFor?Array.isArray(a[n])?a[n].indexOf(o)<0&&a[n].push(o):a[n]=[o]:a[n]=o}}function bn(t,e){return t.key===e.key&&(t.tag===e.tag&&t.isComment===e.isComment&&i(t.data)===i(e.data)&&wn(t,e)||o(t.isAsyncPlaceholder)&&t.asyncFactory===e.asyncFactory&&r(e.asyncFactory.error))}function wn(t,e){if("input"!==t.tag)return!0;var n,r=i(n=t.data)&&i(n=n.attrs)&&n.type,o=i(n=e.data)&&i(n=n.attrs)&&n.type;return r===o||as(r)&&as(o)}function xn(t,e,n){var r,o,a={};for(r=e;r<=n;++r)o=t[r].key,i(o)&&(a[o]=r);return a}function _n(t,e){(t.data.directives||e.data.directives)&&kn(t,e)}function kn(t,e){var n,r,i,o=t===us,a=e===us,s=Tn(t.data.directives,t.context),c=Tn(e.data.directives,e.context),u=[],l=[];for(n in c)r=s[n],i=c[n],r?(i.oldValue=r.value,En(i,"update",e,t),i.def&&i.def.componentUpdated&&l.push(i)):(En(i,"bind",e,t),i.def&&i.def.inserted&&u.push(i));if(u.length){var p=function(){for(var n=0;n<u.length;n++)En(u[n],"inserted",e,t)};o?ht(e,"insert",p):p()}if(l.length&&ht(e,"postpatch",function(){for(var n=0;n<l.length;n++)En(l[n],"componentUpdated",e,t)}),!o)for(n in s)c[n]||En(s[n],"unbind",t,t,a)}function Tn(t,e){var n=Object.create(null);if(!t)return n;var r,i;for(r=0;r<t.length;r++)i=t[r],i.modifiers||(i.modifiers=fs),n[On(i)]=i,i.def=Q(e.$options,"directives",i.name,!0);return n}function On(t){return t.rawName||t.name+"."+Object.keys(t.modifiers||{}).join(".")}function En(t,e,n,r,i){var o=t.def&&t.def[e];if(o)try{o(n.elm,t,n,r,i)}catch(r){it(r,n.context,"directive "+t.name+" "+e+" hook")}}function Cn(t,e){var n=e.componentOptions;if(!(i(n)&&!1===n.Ctor.options.inheritAttrs||r(t.data.attrs)&&r(e.data.attrs))){var o,a,s=e.elm,c=t.data.attrs||{},u=e.data.attrs||{};i(u.__ob__)&&(u=e.data.attrs=x({},u));for(o in u)a=u[o],c[o]!==a&&An(s,o,a);($o||No)&&u.value!==c.value&&An(s,"value",u.value);for(o in c)r(u[o])&&(Ja(o)?s.removeAttributeNS(Ka,Qa(o)):Wa(o)||s.removeAttribute(o))}}function An(t,e,n){t.tagName.indexOf("-")>-1?Sn(t,e,n):Ga(e)?Za(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):Wa(e)?t.setAttribute(e,Za(n)||"false"===n?"false":"true"):Ja(e)?Za(n)?t.removeAttributeNS(Ka,Qa(e)):t.setAttributeNS(Ka,e,n):Sn(t,e,n)}function Sn(t,e,n){if(Za(n))t.removeAttribute(e);else{if($o&&!Io&&("TEXTAREA"===t.tagName||"INPUT"===t.tagName)&&"placeholder"===e&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}function Pn(t,e){var n=e.elm,o=e.data,a=t.data;if(!(r(o.staticClass)&&r(o.class)&&(r(a)||r(a.staticClass)&&r(a.class)))){var s=Ge(e),c=n._transitionClasses;i(c)&&(s=Qe(s,Ze(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}function jn(t){function e(){(a||(a=[])).push(t.slice(h,i).trim()),h=i+1}var n,r,i,o,a,s=!1,c=!1,u=!1,l=!1,p=0,f=0,d=0,h=0;for(i=0;i<t.length;i++)if(r=n,n=t.charCodeAt(i),s)39===n&&92!==r&&(s=!1);else if(c)34===n&&92!==r&&(c=!1);else if(u)96===n&&92!==r&&(u=!1);else if(l)47===n&&92!==r&&(l=!1);else if(124!==n||124===t.charCodeAt(i+1)||124===t.charCodeAt(i-1)||p||f||d){switch(n){case 34:c=!0;break;case 39:s=!0;break;case 96:u=!0;break;case 40:d++;break;case 41:d--;break;case 91:f++;break;case 93:f--;break;case 123:p++;break;case 125:p--}if(47===n){for(var v=i-1,m=void 0;v>=0&&" "===(m=t.charAt(v));v--);m&&ms.test(m)||(l=!0)}}else void 0===o?(h=i+1,o=t.slice(0,i).trim()):e();if(void 0===o?o=t.slice(0,i).trim():0!==h&&e(),a)for(i=0;i<a.length;i++)o=Ln(o,a[i]);return o}function Ln(t,e){var n=e.indexOf("(");if(n<0)return'_f("'+e+'")('+t+")";var r=e.slice(0,n),i=e.slice(n+1);return'_f("'+r+'")('+t+(")"!==i?","+i:i)}function Mn(t){console.error("[Vue compiler]: "+t)}function $n(t,e){return t?t.map(function(t){return t[e]}).filter(function(t){return t}):[]}function In(t,e,n){(t.props||(t.props=[])).push({name:e,value:n}),t.plain=!1}function Nn(t,e,n){(t.attrs||(t.attrs=[])).push({name:e,value:n}),t.plain=!1}function Dn(t,e,n){t.attrsMap[e]=n,t.attrsList.push({name:e,value:n})}function Rn(t,e,n,r,i,o){(t.directives||(t.directives=[])).push({name:e,rawName:n,value:r,arg:i,modifiers:o}),t.plain=!1}function Fn(t,e,n,r,i,o){r=r||lo,"click"===e&&(r.right?(e="contextmenu",delete r.right):r.middle&&(e="mouseup")),r.capture&&(delete r.capture,e="!"+e),r.once&&(delete r.once,e="~"+e),r.passive&&(delete r.passive,e="&"+e);var a;r.native?(delete r.native,a=t.nativeEvents||(t.nativeEvents={})):a=t.events||(t.events={});var s={value:n.trim()};r!==lo&&(s.modifiers=r);var c=a[e];Array.isArray(c)?i?c.unshift(s):c.push(s):a[e]=c?i?[s,c]:[c,s]:s,t.plain=!1}function Bn(t,e,n){var r=Un(t,":"+e)||Un(t,"v-bind:"+e);if(null!=r)return jn(r);if(!1!==n){var i=Un(t,e);if(null!=i)return JSON.stringify(i)}}function Un(t,e,n){var r;if(null!=(r=t.attrsMap[e]))for(var i=t.attrsList,o=0,a=i.length;o<a;o++)if(i[o].name===e){i.splice(o,1);break}return n&&delete t.attrsMap[e],r}function Hn(t,e,n){var r=n||{},i=r.number,o=r.trim,a="$$v";o&&(a="(typeof $$v === 'string'? $$v.trim(): $$v)"),i&&(a="_n("+a+")");var s=Xn(e,a);t.model={value:"("+e+")",expression:JSON.stringify(e),callback:"function ($$v) {"+s+"}"}}function Xn(t,e){var n=zn(t);return null===n.key?t+"="+e:"$set("+n.exp+", "+n.key+", "+e+")"}function zn(t){if(t=t.trim(),Na=t.length,t.indexOf("[")<0||t.lastIndexOf("]")<Na-1)return Fa=t.lastIndexOf("."),Fa>-1?{exp:t.slice(0,Fa),key:'"'+t.slice(Fa+1)+'"'}:{exp:t,key:null};for(Da=t,Fa=Ba=Ua=0;!qn();)Ra=Yn(),Vn(Ra)?Gn(Ra):91===Ra&&Wn(Ra);return{exp:t.slice(0,Ba),key:t.slice(Ba+1,Ua)}}function Yn(){return Da.charCodeAt(++Fa)}function qn(){return Fa>=Na}function Vn(t){return 34===t||39===t}function Wn(t){var e=1;for(Ba=Fa;!qn();)if(t=Yn(),Vn(t))Gn(t);else if(91===t&&e++,93===t&&e--,0===e){Ua=Fa;break}}function Gn(t){for(var e=t;!qn()&&(t=Yn())!==e;);}function Kn(t,e,n){Ha=n;var r=e.value,i=e.modifiers,o=t.tag,a=t.attrsMap.type;if(t.component)return Hn(t,r,i),!1;if("select"===o)Zn(t,r,i);else if("input"===o&&"checkbox"===a)Jn(t,r,i);else if("input"===o&&"radio"===a)Qn(t,r,i);else if("input"===o||"textarea"===o)tr(t,r,i);else if(!Co.isReservedTag(o))return Hn(t,r,i),!1;return!0}function Jn(t,e,n){var r=n&&n.number,i=Bn(t,"value")||"null",o=Bn(t,"true-value")||"true",a=Bn(t,"false-value")||"false";In(t,"checked","Array.isArray("+e+")?_i("+e+","+i+")>-1"+("true"===o?":("+e+")":":_q("+e+","+o+")")),Fn(t,"change","var $$a="+e+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Xn(e,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Xn(e,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Xn(e,"$$c")+"}",null,!0)}function Qn(t,e,n){var r=n&&n.number,i=Bn(t,"value")||"null";i=r?"_n("+i+")":i,In(t,"checked","_q("+e+","+i+")"),Fn(t,"change",Xn(e,i),null,!0)}function Zn(t,e,n){var r=n&&n.number,i='Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = "_value" in o ? o._value : o.value;return '+(r?"_n(val)":"val")+"})",o="var $$selectedVal = "+i+";";o=o+" "+Xn(e,"$event.target.multiple ? $$selectedVal : $$selectedVal[0]"),Fn(t,"change",o,null,!0)}function tr(t,e,n){var r=t.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?ys:"input",l="$event.target.value";s&&(l="$event.target.value.trim()"),a&&(l="_n("+l+")");var p=Xn(e,l);c&&(p="if($event.target.composing)return;"+p),In(t,"value","("+e+")"),Fn(t,u,p,null,!0),(s||a)&&Fn(t,"blur","$forceUpdate()")}function er(t){if(i(t[ys])){var e=$o?"change":"input";t[e]=[].concat(t[ys],t[e]||[]),delete t[ys]}i(t[gs])&&(t.change=[].concat(t[gs],t.change||[]),delete t[gs])}function nr(t,e,n){var r=Xa;return function i(){null!==e.apply(null,arguments)&&ir(t,i,n,r)}}function rr(t,e,n,r){e=ct(e),Xa.addEventListener(t,e,Fo?{capture:n,passive:r}:n)}function ir(t,e,n,r){(r||Xa).removeEventListener(t,e._withTask||e,n)}function or(t,e){if(!r(t.data.on)||!r(e.data.on)){var n=e.data.on||{},i=t.data.on||{};Xa=e.elm,er(n),dt(n,i,rr,ir,nr,e.context),Xa=void 0}}function ar(t,e){if(!r(t.data.domProps)||!r(e.data.domProps)){var n,o,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};i(c.__ob__)&&(c=e.data.domProps=x({},c));for(n in s)r(c[n])&&(a[n]="");for(n in c){if(o=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),o===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n){a._value=o;var u=r(o)?"":String(o);sr(a,u)&&(a.value=u)}else a[n]=o}}}function sr(t,e){return!t.composing&&("OPTION"===t.tagName||cr(t,e)||ur(t,e))}function cr(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}function ur(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.lazy)return!1;if(r.number)return d(n)!==d(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}function lr(t){var e=pr(t.style);return t.staticStyle?x(t.staticStyle,e):e}function pr(t){return Array.isArray(t)?_(t):"string"==typeof t?xs(t):t}function fr(t,e){var n,r={};if(e)for(var i=t;i.componentInstance;)(i=i.componentInstance._vnode)&&i.data&&(n=lr(i.data))&&x(r,n);(n=lr(t.data))&&x(r,n);for(var o=t;o=o.parent;)o.data&&(n=lr(o.data))&&x(r,n);return r}function dr(t,e){var n=e.data,o=t.data;if(!(r(n.staticStyle)&&r(n.style)&&r(o.staticStyle)&&r(o.style))){var a,s,c=e.elm,u=o.staticStyle,l=o.normalizedStyle||o.style||{},p=u||l,f=pr(e.data.style)||{};e.data.normalizedStyle=i(f.__ob__)?x({},f):f;var d=fr(e,!0);for(s in p)r(d[s])&&Ts(c,s,"");for(s in d)(a=d[s])!==p[s]&&Ts(c,s,null==a?"":a)}}function hr(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(As).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function vr(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(As).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");n=n.trim(),n?t.setAttribute("class",n):t.removeAttribute("class")}}function mr(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&x(e,Ss(t.name||"v")),x(e,t),e}return"string"==typeof t?Ss(t):void 0}}function yr(t){Ds(function(){Ds(t)})}function gr(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),hr(t,e))}function br(t,e){t._transitionClasses&&v(t._transitionClasses,e),vr(t,e)}function wr(t,e,n){var r=xr(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===js?$s:Ns,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c<a&&u()},o+1),t.addEventListener(s,l)}function xr(t,e){var n,r=window.getComputedStyle(t),i=(r[Ms+"Delay"]||"").split(", "),o=(r[Ms+"Duration"]||"").split(", "),a=_r(i,o),s=(r[Is+"Delay"]||"").split(", "),c=(r[Is+"Duration"]||"").split(", "),u=_r(s,c),l=0,p=0;return e===js?a>0&&(n=js,l=a,p=o.length):e===Ls?u>0&&(n=Ls,l=u,p=c.length):(l=Math.max(a,u),n=l>0?a>u?js:Ls:null,p=n?n===js?o.length:c.length:0),{type:n,timeout:l,propCount:p,hasTransform:n===js&&Rs.test(r[Ms+"Property"])}}function _r(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max.apply(null,e.map(function(e,n){return kr(e)+kr(t[n])}))}function kr(t){return 1e3*Number(t.slice(0,-1).replace(",","."))}function Tr(t,e){var n=t.elm;i(n._leaveCb)&&(n._leaveCb.cancelled=!0,n._leaveCb());var o=mr(t.data.transition);if(!r(o)&&!i(n._enterCb)&&1===n.nodeType){for(var a=o.css,s=o.type,u=o.enterClass,l=o.enterToClass,p=o.enterActiveClass,f=o.appearClass,h=o.appearToClass,v=o.appearActiveClass,m=o.beforeEnter,y=o.enter,g=o.afterEnter,b=o.enterCancelled,w=o.beforeAppear,x=o.appear,_=o.afterAppear,k=o.appearCancelled,T=o.duration,O=ya,C=ya.$vnode;C&&C.parent;)C=C.parent,O=C.context;var A=!O._isMounted||!t.isRootInsert;if(!A||x||""===x){var S=A&&f?f:u,P=A&&v?v:p,j=A&&h?h:l,L=A?w||m:m,M=A&&"function"==typeof x?x:y,$=A?_||g:g,I=A?k||b:b,N=d(c(T)?T.enter:T),D=!1!==a&&!Io,R=Cr(M),F=n._enterCb=E(function(){D&&(br(n,j),br(n,P)),F.cancelled?(D&&br(n,S),I&&I(n)):$&&$(n),n._enterCb=null});t.data.show||ht(t,"insert",function(){var e=n.parentNode,r=e&&e._pending&&e._pending[t.key];r&&r.tag===t.tag&&r.elm._leaveCb&&r.elm._leaveCb(),M&&M(n,F)}),L&&L(n),D&&(gr(n,S),gr(n,P),yr(function(){br(n,S),F.cancelled||(gr(n,j),R||(Er(N)?setTimeout(F,N):wr(n,s,F)))})),t.data.show&&(e&&e(),M&&M(n,F)),D||R||F()}}}function Or(t,e){function n(){k.cancelled||(!t.data.show&&o.parentNode&&((o.parentNode._pending||(o.parentNode._pending={}))[t.key]=t),h&&h(o),w&&(gr(o,l),gr(o,f),yr(function(){br(o,l),k.cancelled||(gr(o,p),x||(Er(_)?setTimeout(k,_):wr(o,u,k)))})),v&&v(o,k),w||x||k())}var o=t.elm;i(o._enterCb)&&(o._enterCb.cancelled=!0,o._enterCb());var a=mr(t.data.transition);if(r(a)||1!==o.nodeType)return e();if(!i(o._leaveCb)){var s=a.css,u=a.type,l=a.leaveClass,p=a.leaveToClass,f=a.leaveActiveClass,h=a.beforeLeave,v=a.leave,m=a.afterLeave,y=a.leaveCancelled,g=a.delayLeave,b=a.duration,w=!1!==s&&!Io,x=Cr(v),_=d(c(b)?b.leave:b),k=o._leaveCb=E(function(){o.parentNode&&o.parentNode._pending&&(o.parentNode._pending[t.key]=null),w&&(br(o,p),br(o,f)),k.cancelled?(w&&br(o,l),y&&y(o)):(e(),m&&m(o)),o._leaveCb=null});g?g(n):n()}}function Er(t){return"number"==typeof t&&!isNaN(t)}function Cr(t){if(r(t))return!1;var e=t.fns;return i(e)?Cr(Array.isArray(e)?e[0]:e):(t._length||t.length)>1}function Ar(t,e){!0!==e.data.show&&Tr(e)}function Sr(t,e,n){Pr(t,e,n),($o||No)&&setTimeout(function(){Pr(t,e,n)},0)}function Pr(t,e,n){var r=e.value,i=t.multiple;if(!i||Array.isArray(r)){for(var o,a,s=0,c=t.options.length;s<c;s++)if(a=t.options[s],i)o=O(r,Lr(a))>-1,a.selected!==o&&(a.selected=o);else if(T(Lr(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));i||(t.selectedIndex=-1)}}function jr(t,e){return e.every(function(e){return!T(e,t)})}function Lr(t){return"_value"in t?t._value:t.value}function Mr(t){t.target.composing=!0}function $r(t){t.target.composing&&(t.target.composing=!1,Ir(t.target,"input"))}function Ir(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function Nr(t){return!t.componentInstance||t.data&&t.data.transition?t:Nr(t.componentInstance._vnode)}function Dr(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Dr(Ot(e.children)):t}function Rr(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[yo(o)]=i[o];return e}function Fr(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}function Br(t){for(;t=t.parent;)if(t.data.transition)return!0}function Ur(t,e){return e.key===t.key&&e.tag===t.tag}function Hr(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function Xr(t){t.data.newPos=t.elm.getBoundingClientRect()}function zr(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}function Yr(t,e){var n=e?dc(e):pc;if(n.test(t)){for(var r,i,o,a=[],s=[],c=n.lastIndex=0;r=n.exec(t);){(i=r.index)>c&&(s.push(o=t.slice(c,i)),a.push(JSON.stringify(o)));var u=jn(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c<t.length&&(s.push(o=t.slice(c)),a.push(JSON.stringify(o))),{expression:a.join("+"),tokens:s}}}function qr(t,e){var n=(e.warn,Un(t,"class"));n&&(t.staticClass=JSON.stringify(n));var r=Bn(t,"class",!1);r&&(t.classBinding=r)}function Vr(t){var e="";return t.staticClass&&(e+="staticClass:"+t.staticClass+","),t.classBinding&&(e+="class:"+t.classBinding+","),e}function Wr(t,e){var n=(e.warn,Un(t,"style"));n&&(t.staticStyle=JSON.stringify(xs(n)));var r=Bn(t,"style",!1);r&&(t.styleBinding=r)}function Gr(t){var e="";return t.staticStyle&&(e+="staticStyle:"+t.staticStyle+","),t.styleBinding&&(e+="style:("+t.styleBinding+"),"),e}function Kr(t,e){var n=e?Mc:Lc;return t.replace(n,function(t){return jc[t]})}function Jr(t,e){function n(e){l+=e,t=t.substring(e)}function r(t,n,r){var i,s;if(null==n&&(n=l),null==r&&(r=l),t)for(s=t.toLowerCase(),i=a.length-1;i>=0&&a[i].lowerCasedTag!==s;i--);else i=0;if(i>=0){for(var c=a.length-1;c>=i;c--)e.end&&e.end(a[c].tag,n,r);a.length=i,o=i&&a[i-1].tag}else"br"===s?e.start&&e.start(t,[],!0,n,r):"p"===s&&(e.start&&e.start(t,[],!1,n,r),e.end&&e.end(t,n,r))}for(var i,o,a=[],s=e.expectHTML,c=e.isUnaryTag||_o,u=e.canBeLeftOpenTag||_o,l=0;t;){if(i=t,o&&Sc(o)){var p=0,f=o.toLowerCase(),d=Pc[f]||(Pc[f]=new RegExp("([\\s\\S]*?)(</"+f+"[^>]*>)","i")),h=t.replace(d,function(t,n,r){return p=r.length,Sc(f)||"noscript"===f||(n=n.replace(/<!\--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)]]>/g,"$1")),Ic(f,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""});l+=t.length-h.length,t=h,r(f,l-p,l)}else{var v=t.indexOf("<");if(0===v){if(Cc.test(t)){var m=t.indexOf("--\x3e");if(m>=0){e.shouldKeepComment&&e.comment(t.substring(4,m)),n(m+3);continue}}if(Ac.test(t)){var y=t.indexOf("]>");if(y>=0){n(y+2);continue}}var g=t.match(Ec);if(g){n(g[0].length);continue}var b=t.match(Oc);if(b){var w=l;n(b[0].length),r(b[1],w,l);continue}var x=function(){var e=t.match(kc);if(e){var r={tagName:e[1],attrs:[],start:l};n(e[0].length);for(var i,o;!(i=t.match(Tc))&&(o=t.match(wc));)n(o[0].length),r.attrs.push(o);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=l,r}}();if(x){!function(t){var n=t.tagName,i=t.unarySlash;s&&("p"===o&&bc(n)&&r(o),u(n)&&o===n&&r(n));for(var l=c(n)||!!i,p=t.attrs.length,f=new Array(p),d=0;d<p;d++){var h=t.attrs[d],v=h[3]||h[4]||h[5]||"",m="a"===n&&"href"===h[1]?e.shouldDecodeNewlinesForHref:e.shouldDecodeNewlines;f[d]={name:h[1],value:Kr(v,m)}}l||(a.push({tag:n,lowerCasedTag:n.toLowerCase(),attrs:f}),o=n),e.start&&e.start(n,f,l,t.start,t.end)}(x),Ic(x.tagName,t)&&n(1);continue}}var _=void 0,k=void 0,T=void 0;if(v>=0){for(k=t.slice(v);!(Oc.test(k)||kc.test(k)||Cc.test(k)||Ac.test(k)||(T=k.indexOf("<",1))<0);)v+=T,k=t.slice(v);_=t.substring(0,v),n(v)}v<0&&(_=t,t=""),e.chars&&_&&e.chars(_)}if(t===i){e.chars&&e.chars(t);break}}r()}function Qr(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:yi(e),parent:n,children:[]}}function Zr(t,e){function n(t){t.pre&&(s=!1),oc(t.tag)&&(c=!1);for(var n=0;n<ic.length;n++)ic[n](t,e)}tc=e.warn||Mn,oc=e.isPreTag||_o,ac=e.mustUseProp||_o,sc=e.getTagNamespace||_o,nc=$n(e.modules,"transformNode"),rc=$n(e.modules,"preTransformNode"),ic=$n(e.modules,"postTransformNode"),ec=e.delimiters;var r,i,o=[],a=!1!==e.preserveWhitespace,s=!1,c=!1;return Jr(t,{warn:tc,expectHTML:e.expectHTML,isUnaryTag:e.isUnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecodeNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,start:function(t,a,u){var l=i&&i.ns||sc(t);$o&&"svg"===l&&(a=wi(a));var p=Qr(t,a,i);l&&(p.ns=l),bi(p)&&!Xo()&&(p.forbidden=!0);for(var f=0;f<rc.length;f++)p=rc[f](p,e)||p;if(s||(ti(p),p.pre&&(s=!0)),oc(p.tag)&&(c=!0),s?ei(p):p.processed||(oi(p),si(p),pi(p),ni(p,e)),r?o.length||r.if&&(p.elseif||p.else)&&li(r,{exp:p.elseif,block:p}):r=p,i&&!p.forbidden)if(p.elseif||p.else)ci(p,i);else if(p.slotScope){i.plain=!1;var d=p.slotTarget||'"default"';(i.scopedSlots||(i.scopedSlots={}))[d]=p}else i.children.push(p),p.parent=i;u?n(p):(i=p,o.push(p))},end:function(){var t=o[o.length-1],e=t.children[t.children.length-1];e&&3===e.type&&" "===e.text&&!c&&t.children.pop(),o.length-=1,i=o[o.length-1],n(t)},chars:function(t){if(i&&(!$o||"textarea"!==i.tag||i.attrsMap.placeholder!==t)){var e=i.children;if(t=c||t.trim()?gi(i)?t:zc(t):a&&e.length?" ":""){var n;!s&&" "!==t&&(n=Yr(t,ec))?e.push({type:2,expression:n.expression,tokens:n.tokens,text:t}):" "===t&&e.length&&" "===e[e.length-1].text||e.push({type:3,text:t})}}},comment:function(t){i.children.push({type:3,text:t,isComment:!0})}}),r}function ti(t){null!=Un(t,"v-pre")&&(t.pre=!0)}function ei(t){var e=t.attrsList.length;if(e)for(var n=t.attrs=new Array(e),r=0;r<e;r++)n[r]={name:t.attrsList[r].name,value:JSON.stringify(t.attrsList[r].value)};else t.pre||(t.plain=!0)}function ni(t,e){ri(t),t.plain=!t.key&&!t.attrsList.length,ii(t),fi(t),di(t);for(var n=0;n<nc.length;n++)t=nc[n](t,e)||t;hi(t)}function ri(t){var e=Bn(t,"key");e&&(t.key=e)}function ii(t){var e=Bn(t,"ref");e&&(t.ref=e,t.refInFor=vi(t))}function oi(t){var e;if(e=Un(t,"v-for")){var n=ai(e);n&&x(t,n)}}function ai(t){var e=t.match(Rc);if(e){var n={};n.for=e[2].trim();var r=e[1].trim().replace(Bc,""),i=r.match(Fc);return i?(n.alias=r.replace(Fc,"").trim(),n.iterator1=i[1].trim(),i[2]&&(n.iterator2=i[2].trim())):n.alias=r,n}}function si(t){var e=Un(t,"v-if");if(e)t.if=e,li(t,{exp:e,block:t});else{null!=Un(t,"v-else")&&(t.else=!0);var n=Un(t,"v-else-if");n&&(t.elseif=n)}}function ci(t,e){var n=ui(e.children);n&&n.if&&li(n,{exp:t.elseif,block:t})}function ui(t){for(var e=t.length;e--;){if(1===t[e].type)return t[e];t.pop()}}function li(t,e){t.ifConditions||(t.ifConditions=[]),t.ifConditions.push(e)}function pi(t){null!=Un(t,"v-once")&&(t.once=!0)}function fi(t){if("slot"===t.tag)t.slotName=Bn(t,"name");else{var e;"template"===t.tag?(e=Un(t,"scope"),t.slotScope=e||Un(t,"slot-scope")):(e=Un(t,"slot-scope"))&&(t.slotScope=e);var n=Bn(t,"slot");n&&(t.slotTarget='""'===n?'"default"':n,"template"===t.tag||t.slotScope||Nn(t,"slot",n))}}function di(t){var e;(e=Bn(t,"is"))&&(t.component=e),null!=Un(t,"inline-template")&&(t.inlineTemplate=!0)}function hi(t){var e,n,r,i,o,a,s,c=t.attrsList;for(e=0,n=c.length;e<n;e++)if(r=i=c[e].name,o=c[e].value,Dc.test(r))if(t.hasBindings=!0,a=mi(r),a&&(r=r.replace(Xc,"")),Hc.test(r))r=r.replace(Hc,""),o=jn(o),s=!1,a&&(a.prop&&(s=!0,"innerHtml"===(r=yo(r))&&(r="innerHTML")),a.camel&&(r=yo(r)),a.sync&&Fn(t,"update:"+yo(r),Xn(o,"$event"))),s||!t.component&&ac(t.tag,t.attrsMap.type,r)?In(t,r,o):Nn(t,r,o);else if(Nc.test(r))r=r.replace(Nc,""),Fn(t,r,o,a,!1,tc);else{r=r.replace(Dc,"");var u=r.match(Uc),l=u&&u[1];l&&(r=r.slice(0,-(l.length+1))),Rn(t,r,i,o,l,a)}else Nn(t,r,JSON.stringify(o)),!t.component&&"muted"===r&&ac(t.tag,t.attrsMap.type,r)&&In(t,r,"true")}function vi(t){for(var e=t;e;){if(void 0!==e.for)return!0;e=e.parent}return!1}function mi(t){var e=t.match(Xc);if(e){var n={};return e.forEach(function(t){n[t.slice(1)]=!0}),n}}function yi(t){for(var e={},n=0,r=t.length;n<r;n++)e[t[n].name]=t[n].value;return e}function gi(t){return"script"===t.tag||"style"===t.tag}function bi(t){return"style"===t.tag||"script"===t.tag&&(!t.attrsMap.type||"text/javascript"===t.attrsMap.type)}function wi(t){for(var e=[],n=0;n<t.length;n++){var r=t[n];Yc.test(r.name)||(r.name=r.name.replace(qc,""),e.push(r))}return e}function xi(t,e){if("input"===t.tag){var n=t.attrsMap;if(!n["v-model"])return;var r;if((n[":type"]||n["v-bind:type"])&&(r=Bn(t,"type")),n.type||r||!n["v-bind"]||(r="("+n["v-bind"]+").type"),r){var i=Un(t,"v-if",!0),o=i?"&&("+i+")":"",a=null!=Un(t,"v-else",!0),s=Un(t,"v-else-if",!0),c=_i(t);oi(c),Dn(c,"type","checkbox"),ni(c,e),c.processed=!0,c.if="("+r+")==='checkbox'"+o,li(c,{exp:c.if,block:c});var u=_i(t);Un(u,"v-for",!0),Dn(u,"type","radio"),ni(u,e),li(c,{exp:"("+r+")==='radio'"+o,block:u});var l=_i(t);return Un(l,"v-for",!0),Dn(l,":type",r),ni(l,e),li(c,{exp:i,block:l}),a?c.else=!0:s&&(c.elseif=s),c}}}function _i(t){return Qr(t.tag,t.attrsList.slice(),t.parent)}function ki(t,e){e.value&&In(t,"textContent","_s("+e.value+")")}function Ti(t,e){e.value&&In(t,"innerHTML","_s("+e.value+")")}function Oi(t,e){t&&(cc=Jc(e.staticKeys||""),uc=e.isReservedTag||_o,Ci(t),Ai(t,!1))}function Ei(t){return h("type,tag,attrsList,attrsMap,plain,parent,children,attrs"+(t?","+t:""))}function Ci(t){if(t.static=Si(t),1===t.type){if(!uc(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var e=0,n=t.children.length;e<n;e++){var r=t.children[e];Ci(r),r.static||(t.static=!1)}if(t.ifConditions)for(var i=1,o=t.ifConditions.length;i<o;i++){var a=t.ifConditions[i].block;Ci(a),a.static||(t.static=!1)}}}function Ai(t,e){if(1===t.type){if((t.static||t.once)&&(t.staticInFor=e),t.static&&t.children.length&&(1!==t.children.length||3!==t.children[0].type))return void(t.staticRoot=!0);if(t.staticRoot=!1,t.children)for(var n=0,r=t.children.length;n<r;n++)Ai(t.children[n],e||!!t.for);if(t.ifConditions)for(var i=1,o=t.ifConditions.length;i<o;i++)Ai(t.ifConditions[i].block,e)}}function Si(t){return 2!==t.type&&(3===t.type||!(!t.pre&&(t.hasBindings||t.if||t.for||fo(t.tag)||!uc(t.tag)||Pi(t)||!Object.keys(t).every(cc))))}function Pi(t){for(;t.parent;){if(t=t.parent,"template"!==t.tag)return!1;if(t.for)return!0}return!1}function ji(t,e){var n=e?"nativeOn:{":"on:{";for(var r in t)n+='"'+r+'":'+Li(r,t[r])+",";return n.slice(0,-1)+"}"}function Li(t,e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return Li(t,e)}).join(",")+"]";var n=Zc.test(e.value),r=Qc.test(e.value);if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(ru[s])o+=ru[s],tu[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=nu(["ctrl","shift","alt","meta"].filter(function(t){return!c[t]}).map(function(t){return"$event."+t+"Key"}).join("||"))}else a.push(s);return a.length&&(i+=Mi(a)),o&&(i+=o),"function($event){"+i+(n?"return "+e.value+"($event)":r?"return ("+e.value+")($event)":e.value)+"}"}return n||r?e.value:"function($event){"+e.value+"}"}function Mi(t){return"if(!('button' in $event)&&"+t.map($i).join("&&")+")return null;"}function $i(t){var e=parseInt(t,10);if(e)return"$event.keyCode!=="+e;var n=tu[t],r=eu[t];return"_k($event.keyCode,"+JSON.stringify(t)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}function Ii(t,e){t.wrapListeners=function(t){return"_g("+t+","+e.value+")"}}function Ni(t,e){t.wrapData=function(n){return"_b("+n+",'"+t.tag+"',"+e.value+","+(e.modifiers&&e.modifiers.prop?"true":"false")+(e.modifiers&&e.modifiers.sync?",true":"")+")"}}function Di(t,e){var n=new ou(e);return{render:"with(this){return "+(t?Ri(t,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Ri(t,e){if(t.parent&&(t.pre=t.pre||t.parent.pre),t.staticRoot&&!t.staticProcessed)return Fi(t,e);if(t.once&&!t.onceProcessed)return Bi(t,e);if(t.for&&!t.forProcessed)return Xi(t,e);if(t.if&&!t.ifProcessed)return Ui(t,e);if("template"!==t.tag||t.slotTarget||e.pre){if("slot"===t.tag)return no(t,e);var n;if(t.component)n=ro(t.component,t,e);else{var r;(!t.plain||t.pre&&e.maybeComponent(t))&&(r=zi(t,e));var i=t.inlineTemplate?null:Ki(t,e,!0);n="_c('"+t.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o<e.transforms.length;o++)n=e.transforms[o](t,n);return n}return Ki(t,e)||"void 0"}function Fi(t,e){t.staticProcessed=!0;var n=e.pre;return t.pre&&(e.pre=t.pre),e.staticRenderFns.push("with(this){return "+Ri(t,e)+"}"),e.pre=n,"_m("+(e.staticRenderFns.length-1)+(t.staticInFor?",true":"")+")"}function Bi(t,e){if(t.onceProcessed=!0,t.if&&!t.ifProcessed)return Ui(t,e);if(t.staticInFor){for(var n="",r=t.parent;r;){if(r.for){n=r.key;break}r=r.parent}return n?"_o("+Ri(t,e)+","+e.onceId+++","+n+")":Ri(t,e)}return Fi(t,e)}function Ui(t,e,n,r){return t.ifProcessed=!0,Hi(t.ifConditions.slice(),e,n,r)}function Hi(t,e,n,r){function i(t){return n?n(t,e):t.once?Bi(t,e):Ri(t,e)}if(!t.length)return r||"_e()";var o=t.shift();return o.exp?"("+o.exp+")?"+i(o.block)+":"+Hi(t,e,n,r):""+i(o.block)}function Xi(t,e,n,r){var i=t.for,o=t.alias,a=t.iterator1?","+t.iterator1:"",s=t.iterator2?","+t.iterator2:"";return t.forProcessed=!0,(r||"_l")+"(("+i+"),function("+o+a+s+"){return "+(n||Ri)(t,e)+"})"}function zi(t,e){var n="{",r=Yi(t,e);r&&(n+=r+","),t.key&&(n+="key:"+t.key+","),t.ref&&(n+="ref:"+t.ref+","),t.refInFor&&(n+="refInFor:true,"),t.pre&&(n+="pre:true,"),t.component&&(n+='tag:"'+t.tag+'",');for(var i=0;i<e.dataGenFns.length;i++)n+=e.dataGenFns[i](t);if(t.attrs&&(n+="attrs:{"+io(t.attrs)+"},"),t.props&&(n+="domProps:{"+io(t.props)+"},"),t.events&&(n+=ji(t.events,!1)+","),t.nativeEvents&&(n+=ji(t.nativeEvents,!0)+","),t.slotTarget&&!t.slotScope&&(n+="slot:"+t.slotTarget+","),t.scopedSlots&&(n+=Vi(t.scopedSlots,e)+","),t.model&&(n+="model:{value:"+t.model.value+",callback:"+t.model.callback+",expression:"+t.model.expression+"},"),t.inlineTemplate){var o=qi(t,e);o&&(n+=o+",")}return n=n.replace(/,$/,"")+"}",t.wrapData&&(n=t.wrapData(n)),t.wrapListeners&&(n=t.wrapListeners(n)),n}function Yi(t,e){var n=t.directives;if(n){var r,i,o,a,s="directives:[",c=!1;for(r=0,i=n.length;r<i;r++){o=n[r],a=!0;var u=e.directives[o.name];u&&(a=!!u(t,o,e.warn)),a&&(c=!0,s+='{name:"'+o.name+'",rawName:"'+o.rawName+'"'+(o.value?",value:("+o.value+"),expression:"+JSON.stringify(o.value):"")+(o.arg?',arg:"'+o.arg+'"':"")+(o.modifiers?",modifiers:"+JSON.stringify(o.modifiers):"")+"},")}return c?s.slice(0,-1)+"]":void 0}}function qi(t,e){var n=t.children[0];if(1===n.type){var r=Di(n,e.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map(function(t){return"function(){"+t+"}"}).join(",")+"]}"}}function Vi(t,e){return"scopedSlots:_u(["+Object.keys(t).map(function(n){return Wi(n,t[n],e)}).join(",")+"])"}function Wi(t,e,n){return e.for&&!e.forProcessed?Gi(t,e,n):"{key:"+t+",fn:function("+String(e.slotScope)+"){return "+("template"===e.tag?e.if?"("+e.if+")?"+(Ki(e,n)||"undefined")+":undefined":Ki(e,n)||"undefined":Ri(e,n))+"}}"}function Gi(t,e,n){var r=e.for,i=e.alias,o=e.iterator1?","+e.iterator1:"",a=e.iterator2?","+e.iterator2:"";return e.forProcessed=!0,"_l(("+r+"),function("+i+o+a+"){return "+Wi(t,e,n)+"})"}function Ki(t,e,n,r,i){var o=t.children;if(o.length){var a=o[0];if(1===o.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?e.maybeComponent(a)?",1":",0":"";return""+(r||Ri)(a,e)+s}var c=n?Ji(o,e.maybeComponent):0,u=i||Zi;return"["+o.map(function(t){return u(t,e)}).join(",")+"]"+(c?","+c:"")}}function Ji(t,e){for(var n=0,r=0;r<t.length;r++){var i=t[r];if(1===i.type){if(Qi(i)||i.ifConditions&&i.ifConditions.some(function(t){return Qi(t.block)})){n=2;break}(e(i)||i.ifConditions&&i.ifConditions.some(function(t){return e(t.block)}))&&(n=1)}}return n}function Qi(t){return void 0!==t.for||"template"===t.tag||"slot"===t.tag}function Zi(t,e){return 1===t.type?Ri(t,e):3===t.type&&t.isComment?eo(t):to(t)}function to(t){return"_v("+(2===t.type?t.expression:oo(JSON.stringify(t.text)))+")"}function eo(t){return"_e("+JSON.stringify(t.text)+")"}function no(t,e){var n=t.slotName||'"default"',r=Ki(t,e),i="_t("+n+(r?","+r:""),o=t.attrs&&"{"+t.attrs.map(function(t){return yo(t.name)+":"+t.value}).join(",")+"}",a=t.attrsMap["v-bind"];return!o&&!a||r||(i+=",null"),o&&(i+=","+o),a&&(i+=(o?"":",null")+","+a),i+")"}function ro(t,e,n){var r=e.inlineTemplate?null:Ki(e,n,!0);return"_c("+t+","+zi(e,n)+(r?","+r:"")+")"}function io(t){for(var e="",n=0;n<t.length;n++){var r=t[n];e+='"'+r.name+'":'+oo(r.value)+","}return e.slice(0,-1)}function oo(t){return t.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function ao(t,e){try{return new Function(t)}catch(n){return e.push({err:n,code:t}),k}}function so(t){var e=Object.create(null);return function(n,r,i){r=x({},r),r.warn,delete r.warn;var o=r.delimiters?String(r.delimiters)+n:n;if(e[o])return e[o];var a=t(n,r),s={},c=[];return s.render=ao(a.render,c),s.staticRenderFns=a.staticRenderFns.map(function(t){return ao(t,c)}),e[o]=s}}function co(t){return lc=lc||document.createElement("div"),lc.innerHTML=t?'<a href="\n"/>':'<div a="\n"/>',lc.innerHTML.indexOf("&#10;")>0}function uo(t){if(t.outerHTML)return t.outerHTML;var e=document.createElement("div");return e.appendChild(t.cloneNode(!0)),e.innerHTML}/*!
2
+ * Vue.js v2.5.22
3
+ * (c) 2014-2019 Evan You
4
  * Released under the MIT License.
5
  */