WP RSS Aggregator - Version 4.19.2

Version Description

(2021-10-28) Changed - Cleaned up the code significantly. - Consistent permalink normalization between the preview and importing. - Some plugin strings were not internationalized. - Source information is extracted from feed items more reliably. - Audio links in feed items are detected more reliably. - Enclosure images in feed items are detected more reliably.

Fixed - HTML entities caused unique title checks to always fail. - Some request data was not filtered and/or sanitized properly. - Some plugin-generated content was not properly escaped for use in HTML. - URLs added manually to the blacklist are now properly validated. - Feed sources and feed items restored from the trash become "draft" since WordPress 5.6.

Download this release

Release Info

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

Code changes from version 4.19.1 to 4.19.2

Files changed (50) hide show
  1. CHANGELOG.md +19 -3
  2. css/admin-styles.css +18 -0
  3. includes/Aventura/Wprss/Core/Licensing/AjaxController.php +7 -7
  4. includes/Aventura/Wprss/Core/Licensing/Settings.php +186 -136
  5. includes/Aventura/Wprss/Core/Model/AdminAjaxNotice/ServiceProvider.php +13 -4
  6. includes/Aventura/Wprss/Core/ServiceProvider.php +1 -1
  7. includes/OPML.php +4 -1
  8. includes/admin-activate.php +2 -1
  9. includes/admin-ajax-notice.php +51 -41
  10. includes/admin-display.php +640 -592
  11. includes/admin-editor.php +198 -200
  12. includes/admin-heartbeat.php +8 -1
  13. includes/admin-help-metaboxes.php +130 -90
  14. includes/admin-help-settings.php +236 -195
  15. includes/admin-help.php +1229 -1147
  16. includes/admin-intro-page.php +28 -33
  17. includes/admin-log.php +9 -9
  18. includes/admin-metaboxes.php +773 -707
  19. includes/admin-options-legacy.php +3 -3
  20. includes/admin-options.php +991 -953
  21. includes/admin-plugins.php +55 -51
  22. includes/admin-update-page.php +2 -2
  23. includes/admin.php +212 -173
  24. includes/cpt-feeds.php +113 -90
  25. includes/feed-access.php +35 -20
  26. includes/feed-blacklist.php +3 -5
  27. includes/feed-importing-images.php +3 -5
  28. includes/feed-importing.php +64 -27
  29. includes/feed-processing.php +5 -5
  30. includes/feed-states.php +107 -93
  31. includes/legacy-feed-display.php +531 -496
  32. includes/opml-importer.php +39 -32
  33. includes/scripts.php +253 -245
  34. includes/system-info.php +2 -2
  35. includes/update.php +5 -5
  36. js/pointers.js +0 -15
  37. readme.txt +17 -1
  38. src/Data/Wp/WpPostMetaDataSet.php +1 -1
  39. src/ErrorHandler.php +3 -9
  40. src/Modules/BlacklistToolModule.php +17 -0
  41. src/Modules/I18nModule.php +1 -1
  42. src/Modules/LogsToolModule.php +1 -1
  43. src/Templates/Feeds/Types/ListTemplateType.php +1 -1
  44. src/Templates/TwigTemplate.php +3 -3
  45. src/Ui/BlacklistTable.php +2 -2
  46. src/Util/NormalizeWpPostCapableTrait.php +1 -1
  47. vendor/composer/ClassLoader.php +102 -11
  48. vendor/composer/InstalledVersions.php +6 -6
  49. vendor/composer/installed.php +6 -6
  50. wp-rss-aggregator.php +104 -80
CHANGELOG.md CHANGED
@@ -4,12 +4,28 @@ 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.19.1] - 2021-09-14
8
- ## Changed
9
  * More details are now logged when a fatal error occurs during an import.
10
  * Using local versions of images and stylesheets.
11
 
12
- ## Fixed
13
  * Importing would sometimes fail when trying to fetch the media:thumbnail image.
14
  * Some request data was not filtered and/or sanitized properly.
15
  * Some plugin-generated content was not properly escaped for use in HTML.
@@ -18,7 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
18
  ### Added
19
  * Support for importing images from `<image>` tags.
20
 
21
- ## Changed
22
  * Exceptions thrown during an import and caught and logged.
23
 
24
  ## [4.18.2] - 2021-04-26
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.19.2] = 2021-10-28
8
+ ### Changed
9
+ * Cleaned up the code significantly.
10
+ * Consistent permalink normalization between the preview and importing.
11
+ * Some plugin strings were not internationalized.
12
+ * Source information is extracted from feed items more reliably.
13
+ * Audio links in feed items are detected more reliably.
14
+ * Enclosure images in feed items are detected more reliably.
15
+
16
+ ### Fixed
17
+ * HTML entities caused unique title checks to always fail.
18
+ * Some request data was not filtered and/or sanitized properly.
19
+ * Some plugin-generated content was not properly escaped for use in HTML.
20
+ * URLs added manually to the blacklist are now properly validated.
21
+ * Feed sources and feed items restored from the trash become "draft" since WordPress 5.6.
22
+
23
  ## [4.19.1] - 2021-09-14
24
+ ### Changed
25
  * More details are now logged when a fatal error occurs during an import.
26
  * Using local versions of images and stylesheets.
27
 
28
+ ### Fixed
29
  * Importing would sometimes fail when trying to fetch the media:thumbnail image.
30
  * Some request data was not filtered and/or sanitized properly.
31
  * Some plugin-generated content was not properly escaped for use in HTML.
34
  ### Added
35
  * Support for importing images from `<image>` tags.
36
 
37
+ ### Changed
38
  * Exceptions thrown during an import and caught and logged.
39
 
40
  ## [4.18.2] - 2021-04-26
css/admin-styles.css CHANGED
@@ -167,6 +167,24 @@ color: darkGreen;
167
  }
168
  */
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  input#default-thumbnail,
171
  input#wprss-et-license-key,
172
  input#wprss-c-license-key,
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,
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_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,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_TEXT_DOMAIN ), $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_TEXT_DOMAIN ) );
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' ), $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
  $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
  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
includes/Aventura/Wprss/Core/Licensing/Settings.php CHANGED
@@ -1,8 +1,7 @@
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,26 +76,35 @@ class Settings {
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,6 +149,7 @@ class Settings {
141
  return false;
142
  }
143
  $license = $this->getManager()->getLicense( $args['addon'] );
 
144
  return $license !== null && strlen( $license->getKey() ) > 0 && ! $license->isValid();
145
  }
146
 
@@ -155,12 +164,14 @@ class Settings {
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,31 +180,31 @@ class Settings {
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,20 +217,30 @@ class Settings {
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,18 +289,15 @@ class Settings {
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,93 +315,125 @@ class Settings {
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
  /**
1
  <?php
2
 
3
  namespace Aventura\Wprss\Core\Licensing;
4
+ use WPRSS_MBString;
 
5
 
6
  /**
7
  * The licensing settings class.
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
  return false;
150
  }
151
  $license = $this->getManager()->getLicense( $args['addon'] );
152
+
153
  return $license !== null && strlen( $license->getKey() ) > 0 && ! $license->isValid();
154
  }
155
 
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
  */
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
  * @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
 
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
  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
+
353
+ if ($license !== null && !$license->isInvalid() && ($licenseKey = $license->getKey()) && !empty($licenseKey)) {
354
+ if (!is_object($data)) {
355
+ printf(
356
+ '<p><small>%</small></p>',
357
+ __(
358
+ 'Failed to get license information. This is a temporary problem. Check your internet connection and try again later.',
359
+ 'wprss'
360
+ )
361
+ );
362
+ } else {
363
+ $currentActivations = $data->site_count;
364
+ $activationsLeft = $data->activations_left;
365
+ $activationsLimit = $data->license_limit;
366
+ $expires = $data->expires;
367
+ $expiresSpace = strpos($expires, ' ');
368
+ // if expiry has space, get only first word
369
+ $expires = ($expiresSpace !== false)
370
+ ? substr($expires, 0, $expiresSpace)
371
+ : $expires;
372
+ $expires = trim($expires);
373
+ // change lifetime expiry to never
374
+ $expires = ($expires === Manager::EXPIRATION_LIFETIME)
375
+ ? __('never', 'wprss')
376
+ : $expires;
377
+
378
+ if (!empty($data->payment_id) && !empty($data->license_limit)) {
379
+ echo '<p><small>';
380
+
381
+ if ($status !== 'valid' && $activationsLeft === 0) {
382
+ $accountUrl = sprintf(
383
+ 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=%s',
384
+ urlencode($data->payment_id)
385
+ );
386
+ printf(
387
+ '<a href="%s">%s</a>',
388
+ esc_attr($accountUrl),
389
+ __(
390
+ 'No activations left. Click here to manage the sites you\'ve activated licenses on.',
391
+ 'wprss'
392
+ )
393
+ );
394
+
395
+ echo '<br/>';
396
+ }
397
+
398
+ if (!empty($expires) && $expires !== 'never' && strtotime($expires) < strtotime("+2 weeks")) {
399
+ $renewalUrl = sprintf(
400
+ '%s/checkout/?edd_license_key=%s',
401
+ WPRSS_SL_STORE_URL,
402
+ urlencode($licenseKey)
403
+ );
404
+
405
+ printf(
406
+ '<a href="%s">%s</a><br/>',
407
+ esc_attr($renewalUrl),
408
+ __('Renew your license to continue receiving updates and support.', 'wprss')
409
+ );
410
+
411
+ echo '<br/>';
412
+ }
413
+
414
+ printf('<strong>%s</strong> ', __('Activations:', 'wprss'));
415
+ printf(
416
+ '%s/%s (%s)',
417
+ $currentActivations,
418
+ $activationsLimit,
419
+ sprintf(_x('%s left', 'Number of license activations remaining', 'wprss'), $activationsLeft)
420
+ );
421
+
422
+ echo '<br/>';
423
+
424
+ if (!empty($expires)) {
425
+ printf('<strong>%s</strong> ', __('Expires:', 'wprss'));
426
+ printf('<code>%s</code>', esc_html($expires));
427
+ echo '<br/>';
428
+ }
429
+
430
+ printf('<strong>%s</strong> ', __('Registered to:', 'wprss'));
431
+ printf('%s (<code>%s</code>)', $data->customer_name, $data->customer_email);
432
+
433
+ echo '</small></p>';
434
+ }
435
  }
436
+ }
 
437
  }
438
 
439
  /**
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_TEXT_DOMAIN
72
  ));
73
  // Initialize collection
74
  $controller = new \WPRSS_Admin_Notices($config);
@@ -424,7 +424,10 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
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,7 +471,10 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
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,7 +521,10 @@ class ServiceProvider extends AbstractComponentServiceProvider implements Servic
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
  )
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
  '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
  '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
  '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
  )
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_TEXT_DOMAIN;
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';
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,7 +39,10 @@ class WPRSS_OPML {
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
 
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
 
includes/admin-activate.php CHANGED
@@ -22,7 +22,8 @@ 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
- if (is_network_admin() || isset($_GET['activate-multi'])) {
 
26
  return;
27
  }
28
 
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
 
includes/admin-ajax-notice.php CHANGED
@@ -1,8 +1,8 @@
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
 
@@ -85,26 +85,6 @@ define ('WPRSS_NOTICE_SERVICE_ID_PREFIX', WPRSS_SERVICE_ID_PREFIX . 'notice.');
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,22 +1056,49 @@ class WPRSS_Admin_Notices {
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,9 +1118,9 @@ class WPRSS_Admin_Notices {
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,19 +1222,22 @@ add_action( sprintf( 'wp_ajax_%1$s', wprss_admin_notice_get_action_code() ), 'wp
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
 
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
 
85
  add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
86
 
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  /**
89
  * Responsible for tracking and outputting admin notices
90
  *
1056
 
1057
  ob_start();
1058
  $notice = apply_filters( $this->prefix( 'admin_notice_render_before' ), $notice, $this );
1059
+
1060
+ $noticeId = esc_attr($notice['id']);
1061
+ $content = $notice['content'];
1062
+
1063
+ $type = $notice['notice_type'];
1064
+ $baseClass = $this->get_notice_base_class();
1065
+ $elemClass = $notice['notice_element_class'];
1066
+ $dismissMode = $notice['dismiss_mode'];
1067
+ $fullClass = esc_attr("{$type} {$elemClass} {$baseClass} dismiss-mode-{$dismissMode}");
1068
+
1069
+ $nonce = $notice['nonce'];
1070
+ $nonceId = esc_attr($notice['nonce_element_id']);
1071
+ $nonceElemClass = $notice['nonce_element_class'];
1072
+ $nonceBaseClass = $this->get_nonce_base_class();
1073
+ $nonceFullClass = esc_attr("hidden {$nonceElemClass} {$nonceBaseClass}");
1074
  ?>
1075
 
1076
+ <div id="<?= $noticeId ?>" class="<?= $fullClass ?>">
1077
  <div class="notice-inside">
1078
+ <?= $content ?>
1079
  </div>
1080
+ <?php if ($dismissMode !== NoticeInterface::DISMISS_MODE_NONE):
1081
+ $btnId = esc_attr($notice['btn_close_id']);
1082
+ $btnContent = $notice['btn_close_content'];
1083
+ $btnElemClass = $notice['btn_close_class'];
1084
+ $btnBaseClass = $this->get_btn_close_base_class();
1085
+ $btnFullClass = esc_attr("{$btnBaseClass} {$btnElemClass}");
1086
+ ?>
1087
+ <a href="javascript:void(0);" id="<?= $btnId ?>" style="float:right;" class="<?= $btnFullClass ?>">
1088
+ <?= $btnContent ?>
1089
+ </a>
1090
+ <?php endif ?>
1091
+ <span id="<?= $nonceId ?>" class="<?= $nonceFullClass ?>">
1092
+ <?= $helper->resolveValue($nonce) ?>
1093
+ </span>
1094
  </div>
1095
+
1096
  <?php
 
 
1097
 
1098
+ do_action($this->prefix('admin_notice_render_after'), $notice, $this);
1099
+ $output = ob_get_clean();
1100
+
1101
+ return apply_filters($this->prefix('admin_notice_rendered'), $output, $notice, $this);
1102
  }
1103
 
1104
 
1118
 
1119
  $notice_id = $notice;
1120
  if ( is_null( $notice ) )
1121
+ throw new Exception('Could not hide notice: Notice ID must be specified');
1122
  if ( is_null( $nonce ) )
1123
+ throw new Exception('Could not hide notice: nonce must be specified');
1124
  if ( !($notice = $this->get_notices( $notice ) ) )
1125
  throw new Exception( sprintf( 'Could not hide notice: No notice found for ID "%1$s"', $notice_id ) );
1126
 
1222
  * @since 4.7.4
1223
  */
1224
  function wprss_admin_notice_hide() {
1225
+ $notice_id = isset($_REQUEST['notice_id']) ? $_REQUEST['notice_id'] : null;
1226
+ $notice_id = filter_var($notice_id, FILTER_SANITIZE_STRING);
1227
+
1228
+ $nonce = isset($_REQUEST['nonce']) ? $_REQUEST['nonce'] : null;
1229
+ $nonce = filter_var($nonce, FILTER_SANITIZE_STRING);
1230
 
1231
  try {
1232
+ wprss_admin_notice_get_collection()->hide_notice($notice_id, $nonce);
1233
+ } catch (Exception $e) {
1234
+ // Failure
1235
+ echo $e->getMessage();
1236
+ exit();
1237
+ }
1238
 
1239
  // Success
1240
+ exit('1');
1241
  }
1242
 
1243
 
includes/admin-display.php CHANGED
@@ -1,75 +1,70 @@
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,56 +82,68 @@
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,607 +151,648 @@
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
- }
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
  }
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
  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
+ $kFeedSourceId = 'feed_source_id';
487
+ try {
488
+ $kId = 'id';
489
+ if (!isset($_POST[$kId]) || empty($_POST[$kId])) {
490
+ throw new Exception($wprss->__('Could not schedule fetch: source ID must be specified'));
491
  }
492
+ $id = $_POST['id'];
493
+ $response->setAjaxData($kFeedSourceId, $id);
494
+
495
+ if (!current_user_can('edit_feed_sources')) {
496
+ throw new Exception($wprss->__([
497
+ 'Could not schedule fetch for source #%1$s: user must have sufficient privileges',
498
+ $id,
499
+ ]));
500
  }
 
 
 
501
 
502
+ // Verify admin referer
503
+ if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
504
+ throw new Exception($wprss->__(['Could not schedule fetch for source #%1$s: nonce is expired', $id]));
505
+ }
506
 
507
+ update_post_meta($id, 'wprss_force_next_fetch', '1');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
 
509
+ // Prepare the schedule args
510
+ $schedule_args = [strval($id)];
 
 
 
511
 
512
+ // Get the current schedule - do nothing if not scheduled
513
+ $next_scheduled = wp_next_scheduled('wprss_fetch_single_feed_hook', $schedule_args);
514
+ if ($next_scheduled !== false) {
515
+ // If scheduled, unschedule it
516
+ wp_unschedule_event($next_scheduled, 'wprss_fetch_single_feed_hook', $schedule_args);
 
 
 
517
 
518
+ // Get the interval option for the feed source
519
+ $interval = get_post_meta($id, 'wprss_update_interval', true);
520
+ // if the feed source uses its own interval
521
+ if ($interval !== '' && $interval !== wprss_get_default_feed_source_update_interval()) {
522
+ // Add meta in feed source. This is used to notify the source that it needs to reschedule it
523
+ update_post_meta($id, 'wprss_reschedule_event', $next_scheduled);
 
 
 
 
 
524
  }
 
 
525
  }
526
 
527
+ // Schedule the event for 5 seconds from now
528
+ $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
529
+ $success = wp_schedule_single_event(time() + $offset, 'wprss_fetch_single_feed_hook', $schedule_args);
530
+ if (!$success) {
531
+ throw new Exception(__('Failed to schedule cron', 'wprss'));
532
+ }
533
+ wprss_flag_feed_as_updating($id);
534
+ } catch (Exception $e) {
535
+ $response = wprss()->createAjaxErrorResponse($e);
536
+ if (isset($id)) {
537
+ $response->setAjaxData($kFeedSourceId, $id);
538
+ }
539
  echo $response->getBody();
540
  exit();
541
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
 
543
+ $response->setAjaxData('message', $wprss->__(['Fetch for feed source #%1$s successfully scheduled', $id]));
544
+ $response->setAjaxData('success', $success);
545
+ echo $response->getBody();
546
+ exit();
547
+ }
548
+
549
+ add_action('wp_ajax_wprss_delete_items_row_action', 'wprss_delete_items_ajax_action_hook');
550
+ /**
551
+ * The AJAX function for the 'Delete Items' row action on the 'All Feed Sources' page.
552
+ *
553
+ * @since 4.14
554
+ */
555
+ function wprss_delete_items_ajax_action_hook()
556
+ {
557
+ $kFeedSourceId = 'feed_source_id';
558
+ $response = wprss()->createAjaxResponse();
559
+ $wprss = wprss();
560
+ try {
561
+ $id = filter_input(INPUT_POST, 'id');
562
+ if (empty($id)) {
563
+ throw new Exception($wprss->__('Source ID was not specified'));
564
+ }
565
 
566
+ $response->setAjaxData($kFeedSourceId, $id);
 
 
567
 
568
+ if (!current_user_can('edit_feed_sources')) {
569
+ throw new Exception($wprss->__(['User must have sufficient privileges', $id]));
570
+ }
 
571
 
572
+ // Verify admin referer
573
+ if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
574
+ throw new Exception($wprss->__(['Nonce has expired - Please refresh the page.', $id]));
 
 
 
 
 
 
 
 
 
 
 
 
575
  }
576
 
577
+ // Schedule a job that runs this function with the source id parameter
578
+ $offset = floor(count(wpra_get_ready_cron_jobs()) / 2);
579
+ $success = wp_schedule_single_event(time() + $offset, 'wprss_delete_feed_items_from_source_hook', [$id]);
580
+ if (!$success) {
581
+ throw new Exception(__('Failed to schedule cron', 'wprss'));
582
+ }
583
+ // Mark feed as deleting its items
584
+ update_post_meta($id, 'wprss_feed_is_deleting_items', time());
585
+ } catch (Exception $e) {
586
+ $response = wprss()->createAjaxErrorResponse($e);
587
+ if (isset($id)) {
588
+ $response->setAjaxData($kFeedSourceId, $id);
589
+ }
590
  echo $response->getBody();
591
  exit();
592
  }
593
 
594
+ $response->setAjaxData('message', $wprss->__(['Items are being deleted', $id]));
595
+ $response->setAjaxData('success', $success);
596
+ echo $response->getBody();
597
+ exit();
598
+ }
599
+
600
+ add_action('wp_ajax_wprss_toggle_feed_state', 'wprss_ajax_toggle_feed_state');
601
+ /**
602
+ * The AJAX function for toggling a feed's state from the 'All Feed Sources' page.
603
+ *
604
+ * @since 4.14
605
+ */
606
+ function wprss_ajax_toggle_feed_state()
607
+ {
608
+ $kFeedSourceId = 'feed_source_id';
609
+ $response = wprss()->createAjaxResponse();
610
+ $wprss = wprss();
611
+ try {
612
+ $id = filter_input(INPUT_POST, 'id', FILTER_DEFAULT);
613
+ if (empty($id)) {
614
+ throw new Exception($wprss->__('Source ID was not specified'));
615
+ }
616
 
617
+ $response->setAjaxData($kFeedSourceId, $id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
618
 
619
+ if (!current_user_can('edit_feed_sources')) {
620
+ throw new Exception($wprss->__(['User must have sufficient privileges', $id]));
621
+ }
 
622
 
623
+ // Verify admin referer
624
+ if (!wprss_verify_nonce('wprss_feed_source_action', 'wprss_admin_ajax_nonce')) {
625
+ throw new Exception($wprss->__(['Nonce has expired - Please refresh the page.', $id]));
626
+ }
627
 
628
+ $active = wprss_is_feed_source_active($id);
 
 
 
 
629
 
630
+ if ($active) {
631
+ wprss_pause_feed_source($id);
632
+ } else {
633
+ wprss_activate_feed_source($id);
 
 
 
 
634
  }
635
 
636
+ $response->setAjaxData('active', !$active);
637
+ } catch (Exception $e) {
638
+ $response = wprss()->createAjaxErrorResponse($e);
639
+ if (isset($id)) {
640
+ $response->setAjaxData($kFeedSourceId, $id);
641
+ }
642
  echo $response->getBody();
643
  exit();
644
  }
645
 
646
+ $response->setAjaxData('message', $wprss->__(['Feed state changed successfully', $id]));
647
+ echo $response->getBody();
648
+ exit();
649
+ }
 
 
 
650
 
651
+ add_action('manage_posts_extra_tablenav', function ($which) {
652
+ $screen = get_current_screen();
653
+ $postType = $screen->post_type;
654
+ // Only add on feed source list
655
+ if ($postType !== 'wprss_feed') {
656
+ return;
657
+ }
 
658
 
659
+ $nonceEl = new \Aventura\Wprss\Core\Block\Html\Span([
660
+ 'data-value' => wp_create_nonce('wprss_feed_source_action'),
661
+ 'id' => 'wprss_feed_source_action_nonce',
662
+ 'class' => 'hidden',
663
+ ]);
664
+
665
+ echo (string) $nonceEl;
666
+ });
667
+
668
+ add_filter('bulk_actions-edit-wprss_feed_item', 'wprss_custom_feed_item_bulk_actions');
669
+ /**
670
+ * Allow filtering bulk actions for feed items
671
+ *
672
+ * @since 2.0
673
+ */
674
+ function wprss_custom_feed_item_bulk_actions($actions)
675
+ {
676
+ if (!wpra_is_dev_mode()) {
677
+ unset($actions['edit']);
678
+ }
679
 
680
+ return apply_filters('wprss_custom_feed_item_bulk_actions', $actions);
681
+ }
682
+
683
+ add_action('admin_footer-edit.php', 'wprss_remove_a_from_feed_title');
684
+ /**
685
+ * Remove hyperlink from imported feed titles in list posts screen
686
+ *
687
+ * @since 2.0
688
+ */
689
+ function wprss_remove_a_from_feed_title()
690
+ {
691
+ if ('edit-wprss_feed_item' !== get_current_screen()->id) {
692
+ return;
693
+ }
694
 
695
+ ?>
696
+ <script type="text/javascript">
697
+ jQuery('table.wp-list-table a.row-title').contents().unwrap();
698
+ </script>
699
+ <?php
700
+ }
701
+
702
+ add_action('wp_before_admin_bar_render', 'wprss_modify_admin_bar');
703
+ /**
704
+ * Removes the old "View Source" menu item from the admin bar and adds a new
705
+ * "View items" menu bar item, that opens a new tab, showing the items imported
706
+ * from that feed source.
707
+ *
708
+ * Only shown on the wprss_feed edit page.
709
+ *
710
+ * @since 4.2
711
+ */
712
+ function wprss_modify_admin_bar()
713
+ {
714
+ if (!is_admin()) {
715
+ return;
716
  }
717
 
718
+ $screen = get_current_screen();
719
+ $action = filter_input(INPUT_GET, 'action');
720
+ $action = strtolower($action);
721
 
722
+ if (empty($screen) || $screen->base !== 'post' || $screen->post_type !== 'wprss_feed' || $action !== 'edit') {
 
 
 
 
 
 
 
723
  return;
 
 
 
 
 
 
724
  }
725
 
726
+ global $wp_admin_bar;
727
+ // Remove the old 'View Source' menu item
728
+ $wp_admin_bar->remove_node('view');
729
+
730
+ // Prepare the view items link and text
731
+ $view_items_link = apply_filters(
732
+ 'wprss_view_feed_items_row_action_link',
733
+ admin_url('edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID()),
734
+ get_the_ID()
735
+ );
736
+ $view_items_text = apply_filters('wprss_view_feed_items_row_action_text', __('View Items', 'wprss'));
737
+
738
+ // Prepare the link target
739
+ $link_target = 'wprss-view-items-' . get_the_ID();
740
+
741
+ // Add the new menu item
742
+ $wp_admin_bar->add_node([
743
+ 'href' => $view_items_link,
744
+ 'id' => 'view',
745
+ 'title' => $view_items_text,
746
+ 'meta' => [
747
+ 'target' => $link_target,
748
+ ],
749
+ ]);
750
+ }
751
+
752
+ if (is_admin()) {
753
  /**
754
+ * Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
755
+ * The queried items are then filtered down to the items imported by the feed source with
756
+ * the ID given in the wprss_feed GET parameter.
 
 
757
  *
758
  * @since 4.2
759
  */
760
+ add_filter('pre_get_posts', function ($query) {
761
+ // Get the ID from the GET param
762
+ $id = filter_input(INPUT_GET, 'wprss_feed', FILTER_VALIDATE_INT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
 
764
+ // Make sure we are in the admin area, filtering the main query, and the GET param is present
765
+ if (!is_admin() || !$query->is_main_query() || empty($id)) {
766
+ return $query;
767
+ }
768
 
769
+ // Bail if the ID does not correspond to a WPRA feed source
770
+ $feed = get_post($id);
771
+ if ($feed instanceof WP_Post && $feed->post_type !== 'wprss_feed') {
772
+ return $query;
773
+ }
774
 
775
+ // Get the existing meta query
776
+ $mq = $query->get('meta_query');
777
+ // Add a meta query if one is not yet set
778
+ if (!is_array($mq)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  // initialize it
780
+ $mq = ['relation' => 'AND'];
781
+ }
782
+ // Add the custom meta query
783
+ $mq[] = apply_filters(
 
 
784
  'wprss_view_feed_items_meta_query',
785
+ [
786
+ 'key' => 'wprss_feed_id',
787
+ 'value' => $id,
788
+ 'compare' => '=',
789
+ ],
790
  $id
791
+ );
792
+ // Set the new meta query
793
+ $query->set('meta_query', $mq);
794
+
795
  // Return the query
796
  return $query;
797
+ });
798
+ }
includes/admin-editor.php CHANGED
@@ -6,47 +6,39 @@
6
  * @since 3.5
7
  */
8
 
9
- add_action('admin_init', 'wprss_add_editor_button');
10
  /**
11
  * Adds the WPRSS button to WordPress' editor
12
  *
13
  * @since 3.5
14
  */
15
- function wprss_add_editor_button()
16
- {
17
  if (current_user_can('edit_posts') && current_user_can('edit_pages') && get_user_option('rich_editing') == 'true') {
18
- add_filter('mce_external_plugins', 'wpra_register_tinymce_plugin', 0);
19
- add_filter('mce_buttons', 'wpra_register_tinymce_button', 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
- }
22
-
23
- /**
24
- * Adds a separator and the wprss button to the buttons array.
25
- *
26
- * @since 3.5
27
- */
28
- function wpra_register_tinymce_button($buttons)
29
- {
30
- $buttons[] = "|";
31
- $buttons[] = "wprss";
32
-
33
- return $buttons;
34
- }
35
 
36
- /**
37
- * Adds the button action JS file to TinyMCE's plugin list
38
- *
39
- * @since 3.5
40
- * @todo add filter to skip showing the editor button
41
- */
42
- function wpra_register_tinymce_plugin($plugin_array)
43
- {
44
- // add filter here
45
- $plugin_array['wprss'] = WPRSS_JS . 'editor.js';
46
- return $plugin_array;
47
- }
48
-
49
- add_filter('tiny_mce_version', 'wprss_tinymce_version');
50
  /**
51
  * Intercepts TinyMCE's version check and increments its version by 3.
52
  *
@@ -55,177 +47,183 @@ add_filter('tiny_mce_version', 'wprss_tinymce_version');
55
  *
56
  * @since 3.5
57
  */
58
- function wprss_tinymce_version($ver)
59
- {
60
  $ver += 3;
61
  return $ver;
62
- }
63
 
64
  add_action('wp_ajax_wprss_editor_dialog', 'wprss_return_dialog_contents');
65
  /**
66
  * Renders the TinyMCE button dialog contents.
67
  */
68
- function wprss_return_dialog_contents() {
69
- $templates_collection = wpra_get('feeds/templates/collection');
70
- $templates_options = [];
71
- foreach ($templates_collection as $template) {
72
- $template_name = $template['name'];
73
- $template_slug = ($template['type'] === '__built_in')
74
- ? ''
75
- : $template['slug'];
76
-
77
- $templates_options[$template_slug] = $template_name;
78
- }
79
- $templates_select = wprss_settings_render_select(
80
- 'wprss-dialog-templates',
81
- '',
82
- $templates_options,
83
- '',
84
- ['class' => 'widefat']
85
- );
86
-
87
- $feed_sources = get_posts( array(
88
- 'post_type' => 'wprss_feed',
89
- 'post_status' => 'publish',
90
- 'posts_per_page' => -1,
91
- 'no_found_rows' => true
92
- ));
93
- $feed_sources_names = [];
94
- foreach ( $feed_sources as $source ) {
95
- $feed_sources_names[$source->ID] = $source->post_title;
96
- }
97
- $feed_sources_select = wprss_settings_render_select(
98
- 'wprss-dialog-feed-source-list',
99
- '',
100
- $feed_sources_names,
101
- '',
102
- ['multiple' => 'multiple', 'class' => 'widefat']
103
- );
104
- $feed_sources_exclude_select = wprss_settings_render_select(
105
- 'wprss-dialog-exclude-list',
106
- '',
107
- $feed_sources_names,
108
- '',
109
- ['multiple' => 'multiple', 'class' => 'widefat']
110
- );
111
-
112
- $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>';
113
- $feed_sources_select .= $feed_sources_both_select;
114
- $feed_sources_exclude_select .= $feed_sources_both_select;
115
-
116
- ?>
117
- <table cellspacing="20">
118
- <tbody>
119
- <tr>
120
- <td id="wprss-dialog-templates-label">
121
- <label for="wprss-dialog-templates">
122
- <?php _e( 'Template', WPRSS_TEXT_DOMAIN ) ?>
123
- </label>
124
- </td>
125
- <td>
126
- <?php echo $templates_select; ?>
127
- </td>
128
- </tr>
129
- <tr>
130
- <td id="wprss-dialog-all-sources-label">
131
- <?php _e( 'Sources', WPRSS_TEXT_DOMAIN ) ?>
132
- </td>
133
- <td>
134
- <input id="wprss-dialog-all-sources" type="checkbox" checked>
135
- <label for="wprss-dialog-all-sources">
136
- <?php _e( 'All feed sources', WPRSS_TEXT_DOMAIN ) ?>
137
- </label>
138
- </td>
139
- </tr>
140
-
141
- <tr id="wprss-dialog-exclude-row">
142
- <td id="wprss-dialog-exclude-label">
143
- <label id="wprss-dialog-exclude-list-label" for="wprss-dialog-exclude-list">
144
- <?php _e( 'Exclude', WPRSS_TEXT_DOMAIN ) ?>
145
- </label>
146
- </td>
147
- <td>
148
- <div id="wprss-dialog-excludes-container">
149
- <p><?php _e( 'You may choose to exclude some feed sources:', WPRSS_TEXT_DOMAIN ) ?></p>
150
- <?php echo $feed_sources_exclude_select; ?>
151
- </div>
152
-
153
- <div id="wprss-dialog-sources-container" style="display:none">
154
- <p><?php _e( 'Choose which feed sources to show:', WPRSS_TEXT_DOMAIN ) ?></p>
155
- <?php echo $feed_sources_select; ?>
156
- </div>
157
-
158
- <script type="text/javascript">
159
- jQuery('#wprss-dialog-all-sources').click( function(){
160
- if ( jQuery(this).is(':checked') ) {
161
- jQuery( '#wprss-dialog-sources-container' ).hide();
162
- jQuery( '#wprss-dialog-excludes-container' ).show();
163
- jQuery( '#wprss-dialog-exclude-list-label' ).show();
164
- } else {
165
- jQuery( '#wprss-dialog-sources-container' ).show();
166
- jQuery( '#wprss-dialog-excludes-container' ).hide();
167
- jQuery( '#wprss-dialog-exclude-list-label' ).hide();
168
- }
169
- });
170
- jQuery('#wprss-dialog-submit').click( wprss_dialog_submit );
171
- </script>
172
- </td>
173
- </tr>
174
-
175
- <tr>
176
- <td><?php _e( 'Number of items', WPRSS_TEXT_DOMAIN ) ?></td>
177
- <td>
178
- <input id="wprss-dialog-feed-limit"
179
- type="number"
180
- class="wprss-number-roller widefat"
181
- placeholder="<?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?>"
182
- min="0"
183
- />
184
- </td>
185
- </tr>
186
-
187
- <tr>
188
- <td><?php _e( 'Pagination', WPRSS_TEXT_DOMAIN ) ?></td>
189
- <td>
190
- <label>
191
- <select id="wprss-dialog-pagination">
192
- <option value=""><?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?></option>
193
- <option value="on"><?php _e( 'Enabled', WPRSS_TEXT_DOMAIN ) ?></option>
194
- <option value="off"><?php _e( 'Disabled', WPRSS_TEXT_DOMAIN ) ?></option>
195
- </select>
196
- <br/>
197
- <span>
198
- <?php _e( 'Choose whether to show or hide pagination controls', WPRSS_TEXT_DOMAIN ) ?>
199
- </span>
200
- </label>
201
- </td>
202
- </tr>
203
-
204
- <tr>
205
- <td><?php _e( 'Starting page', WPRSS_TEXT_DOMAIN ) ?></td>
206
- <td>
207
- <input id="wprss-dialog-start-page"
208
- type="number"
209
- class="wprss-number-roller widefat"
210
- placeholder="<?php _e( 'Use template setting', WPRSS_TEXT_DOMAIN ) ?>"
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_TEXT_DOMAIN ) ?>
223
- </button>
224
- </td>
225
- </tr>
226
-
227
- </tbody>
228
- </table>
229
- <?php
230
- die();
231
- }
 
 
 
 
 
 
 
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
  *
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_names = [];
86
+ foreach ($feed_sources as $source) {
87
+ $feed_sources_names[$source->ID] = $source->post_title;
88
+ }
89
+ $feed_sources_select = wprss_settings_render_select(
90
+ 'wprss-dialog-feed-source-list',
91
+ '',
92
+ $feed_sources_names,
93
+ '',
94
+ ['multiple' => 'multiple', 'class' => 'widefat']
95
+ );
96
+ $feed_sources_exclude_select = wprss_settings_render_select(
97
+ 'wprss-dialog-exclude-list',
98
+ '',
99
+ $feed_sources_names,
100
+ '',
101
+ ['multiple' => 'multiple', 'class' => 'widefat']
102
+ );
103
+
104
+ $feed_sources_both_select = sprintf(
105
+ '<p>%s</p>',
106
+ __('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.',
107
+ 'wprss')
108
+ );
109
+ $feed_sources_select .= $feed_sources_both_select;
110
+ $feed_sources_exclude_select .= $feed_sources_both_select;
111
+
112
+ ?>
113
+ <table cellspacing="20">
114
+ <tbody>
115
+ <tr>
116
+ <td id="wprss-dialog-templates-label">
117
+ <label for="wprss-dialog-templates">
118
+ <?php _e('Template', 'wprss') ?>
119
+ </label>
120
+ </td>
121
+ <td>
122
+ <?php echo $templates_select; ?>
123
+ </td>
124
+ </tr>
125
+ <tr>
126
+ <td id="wprss-dialog-all-sources-label">
127
+ <?php _e('Sources', 'wprss') ?>
128
+ </td>
129
+ <td>
130
+ <input id="wprss-dialog-all-sources" type="checkbox" checked>
131
+ <label for="wprss-dialog-all-sources">
132
+ <?php _e('All feed sources', 'wprss') ?>
133
+ </label>
134
+ </td>
135
+ </tr>
136
+
137
+ <tr id="wprss-dialog-exclude-row">
138
+ <td id="wprss-dialog-exclude-label">
139
+ <label id="wprss-dialog-exclude-list-label" for="wprss-dialog-exclude-list">
140
+ <?php _e('Exclude', 'wprss') ?>
141
+ </label>
142
+ </td>
143
+ <td>
144
+ <div id="wprss-dialog-excludes-container">
145
+ <p><?php _e('You may choose to exclude some feed sources:', 'wprss') ?></p>
146
+ <?php echo $feed_sources_exclude_select; ?>
147
+ </div>
148
+
149
+ <div id="wprss-dialog-sources-container" style="display:none">
150
+ <p><?php _e('Choose which feed sources to show:', 'wprss') ?></p>
151
+ <?php echo $feed_sources_select; ?>
152
+ </div>
153
+
154
+ <script type="text/javascript">
155
+ jQuery('#wprss-dialog-all-sources').click(function () {
156
+ if (jQuery(this).is(':checked')) {
157
+ jQuery('#wprss-dialog-sources-container').hide();
158
+ jQuery('#wprss-dialog-excludes-container').show();
159
+ jQuery('#wprss-dialog-exclude-list-label').show();
160
+ } else {
161
+ jQuery('#wprss-dialog-sources-container').show();
162
+ jQuery('#wprss-dialog-excludes-container').hide();
163
+ jQuery('#wprss-dialog-exclude-list-label').hide();
164
+ }
165
+ });
166
+ jQuery('#wprss-dialog-submit').click(wprss_dialog_submit);
167
+ </script>
168
+ </td>
169
+ </tr>
170
+
171
+ <tr>
172
+ <td><?php _e('Number of items', 'wprss') ?></td>
173
+ <td>
174
+ <input
175
+ id="wprss-dialog-feed-limit"
176
+ type="number"
177
+ class="wprss-number-roller widefat"
178
+ placeholder="<?php _e('Use template setting', 'wprss') ?>"
179
+ min="0"
180
+ />
181
+ </td>
182
+ </tr>
183
+
184
+ <tr>
185
+ <td><?php _e('Pagination', 'wprss') ?></td>
186
+ <td>
187
+ <label>
188
+ <select id="wprss-dialog-pagination">
189
+ <option value=""><?php _e('Use template setting', 'wprss') ?></option>
190
+ <option value="on"><?php _e('Enabled', 'wprss') ?></option>
191
+ <option value="off"><?php _e('Disabled', 'wprss') ?></option>
192
+ </select>
193
+ <br />
194
+ <span>
195
+ <?php _e('Choose whether to show or hide pagination controls', 'wprss') ?>
196
+ </span>
197
+ </label>
198
+ </td>
199
+ </tr>
200
+
201
+ <tr>
202
+ <td><?php _e('Starting page', 'wprss') ?></td>
203
+ <td>
204
+ <input
205
+ id="wprss-dialog-start-page"
206
+ type="number"
207
+ class="wprss-number-roller widefat"
208
+ placeholder="<?php _e('Use template setting', 'wprss') ?>"
209
+ min="1"
210
+ />
211
+ </td>
212
+ </tr>
213
+
214
+ <?php do_action('wprss_return_dialog_contents'); ?>
215
+
216
+ <tr>
217
+ <td></td>
218
+ <td>
219
+ <button id="wprss-dialog-submit">
220
+ <?php _e('Add shortcode', 'wprss') ?>
221
+ </button>
222
+ </td>
223
+ </tr>
224
+
225
+ </tbody>
226
+ </table>
227
+ <?php
228
+ die();
229
+ }
includes/admin-heartbeat.php CHANGED
@@ -7,9 +7,16 @@ add_action('wp_ajax_wprss_feed_source_table_ajax', function () {
7
  return [];
8
  }
9
 
10
- $request = $_POST['wprss_heartbeat'];
 
 
 
 
11
  $action = isset($request['action']) ? $request['action'] : '';
 
 
12
  $params = isset($request['params']) ? $request['params'] : '';
 
13
 
14
  switch ($action) {
15
  case 'feed_sources':
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':
includes/admin-help-metaboxes.php CHANGED
@@ -1,92 +1,132 @@
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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_import_source' => __(
60
+ 'Tick this box to get the site name and URL from the RSS feed, for each item individually.' .
61
+ "\n\n" .
62
+ 'This option is useful when importing from aggregated RSS feeds that have items from different sources.' .
63
+ "\n\n" .
64
+ '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.',
65
+ 'wprss'
66
+ ),
67
+
68
+ /* -------------------------
69
+ * Feed Processing Metabox
70
+ * -------------------------
71
+ */
72
+ // Feed State
73
+ 'wprss_state' => __(
74
+ 'State of the feed, active or paused.' .
75
+ "\n\n" .
76
+ 'If active, the feed source will fetch items periodically, according to the settings below.' .
77
+ "\n\n" .
78
+ 'If paused, the feed source will not fetch feed items periodically.',
79
+ 'wprss'
80
+ ),
81
+
82
+ // Activate Feed: [date]
83
+ 'wprss_activate_feed' => __(
84
+ 'You can set a time, in UTC, in the future when the feed source will become active, if it is paused.' .
85
+ "\n\n" .
86
+ 'Leave blank to activate immediately.',
87
+ 'wprss'
88
+ ),
89
+
90
+ // Pause Feed: [date]
91
+ 'wprss_pause_feed' => __(
92
+ 'You can set a time, in UTC, in the future when the feed source will become paused, if it is active.' .
93
+ "\n\n" .
94
+ 'Leave blank to never pause.',
95
+ 'wprss'
96
+ ),
97
+
98
+ // Update Interval
99
+ 'wprss_update_interval' => __(
100
+ 'How frequently the feed source should check for new items and fetch if needed.' .
101
+ "\n\n" .
102
+ 'If left as <em>Default</em>, the interval in the global settings is used.',
103
+ 'wprss'
104
+ ),
105
+
106
+ // Delete items older than: [date]
107
+ 'wprss_age_limit' => __(
108
+ 'The maximum age allowed for feed items. Very useful if you are only concerned with, say, last week\'s news.' .
109
+ "\n\n" .
110
+ 'Items already imported will be deleted if they eventually exceed this age limit.' .
111
+ "\n\n" .
112
+ 'Also, items in the RSS feed that are already older than this age will not be imported at all.' .
113
+ "\n\n" .
114
+ 'Leave empty to use the <em>Limit feed items by age</em> option in the general settings.',
115
+ 'wprss'
116
+ ),
117
+
118
+ /* ----------------------
119
+ * Feed Preview Metabox
120
+ * ----------------------
121
+ */
122
+ // Force Feed
123
+ 'wprss_force_feed' => __(
124
+ '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.' .
125
+ "\n\n" .
126
+ '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.',
127
+ 'wprss'
128
+ ),
129
+ ];
130
+
131
+ $help->add_tooltips($tooltips, $prefix);
132
+ }, 11);
includes/admin-help-settings.php CHANGED
@@ -1,197 +1,238 @@
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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
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,86 +13,90 @@
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,254 +108,301 @@
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,861 +439,892 @@
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();
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' ); ?></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
  * @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
  * 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();
includes/admin-intro-page.php CHANGED
@@ -4,18 +4,18 @@ if (!defined('ABSPATH')) {
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,10 +37,6 @@ add_action('admin_menu', function () {
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
  {
@@ -95,7 +91,7 @@ add_action('wp_ajax_wprss_set_intro_step', function () {
95
 
96
  if ($step === null) {
97
  wprss_ajax_error_response(
98
- sprintf(__('Missing intro step param "%s"', WPRSS_TEXT_DOMAIN), WPRSS_INTRO_STEP_POST_PARAM)
99
  );
100
  }
101
 
@@ -122,12 +118,12 @@ add_action('wp_ajax_wprss_create_intro_feed', function () {
122
 
123
  if ($url === null) {
124
  wprss_ajax_error_response(
125
- __('Missing feed URL parameter', WPRSS_TEXT_DOMAIN)
126
  );
127
  }
128
  if ($url === false) {
129
  wprss_ajax_error_response(
130
- __('The given feed URL is invalid', WPRSS_TEXT_DOMAIN)
131
  );
132
  }
133
 
@@ -137,7 +133,7 @@ add_action('wp_ajax_wprss_create_intro_feed', function () {
137
  $data = array(
138
  'feed_items' => $items,
139
  );
140
- wprss_set_intro_done(true);
141
  wprss_ajax_success_response($data);
142
  } catch (Exception $e) {
143
  wprss_ajax_error_response($e->getMessage(), 500);
@@ -222,7 +218,7 @@ function wprss_preview_feed_items($url, $max = 10)
222
 
223
  add_action('wprss_create_intro_feed_source', 'wprss_create_intro_feed_source');
224
  /**
225
- * Creates the feed source for the onboarding introduction process.
226
  *
227
  * @since 4.12
228
  *
@@ -235,7 +231,7 @@ add_action('wprss_create_intro_feed_source', 'wprss_create_intro_feed_source');
235
  function wprss_create_intro_feed_source($url)
236
  {
237
  $feedId = get_option(WPRSS_INTRO_FEED_ID_OPTION, 0);
238
- $feed = get_post($feedId, OBJECT);
239
 
240
  if ($feed === null || $feed->post_status != 'publish') {
241
  $newId = wprss_create_feed_source_with_url($url);
@@ -246,15 +242,15 @@ function wprss_create_intro_feed_source($url)
246
  }
247
 
248
  // Update the existing feed source with a new generated name and new URL
249
- wp_update_post(array(
250
  'ID' => $feedId,
251
  'post_title' => wprss_feed_source_name_from_url($url),
252
  'post_status' => 'publish',
253
- 'meta_input' => array(
254
  'wprss_url' => $url,
255
  'wprss_limit' => WPRSS_INTRO_FEED_LIMIT
256
- )
257
- ));
258
 
259
  // Re-import the items for this feed
260
  wprss_delete_feed_items($feedId);
@@ -277,11 +273,11 @@ function wprss_create_intro_feed_source($url)
277
  function wprss_create_feed_source_with_url($url)
278
  {
279
  $name = wprss_feed_source_name_from_url($url);
280
- $result = wprss_import_feed_sources_array(array($url => $name));
281
 
282
  if (empty($result)) {
283
  throw new Exception(
284
- sprintf(__('Failed to import the feed source "%s" with URL "%s"', WPRSS_TEXT_DOMAIN), $name, $url)
285
  );
286
  }
287
 
@@ -306,7 +302,7 @@ function wprss_create_feed_source_with_url($url)
306
  function wprss_import_feed_sources_array($array)
307
  {
308
  /* @var $importer Aventura\Wprss\Core\Component\BulkSourceImport */
309
- $importer = wprss_wp_container()->get(\WPRSS_SERVICE_ID_PREFIX . 'array_source_importer');
310
 
311
  return $importer->import($array);
312
  }
@@ -333,9 +329,8 @@ function wprss_feed_source_name_from_url($url)
333
  }
334
 
335
  $name = parse_url($url, PHP_URL_HOST);
336
- $name = ($name === null) ? $url : $name;
337
 
338
- return $name;
339
  }
340
 
341
  /**
@@ -375,7 +370,7 @@ function wprss_get_intro_shortcode_page()
375
  function wprss_create_shortcode_page($title = null, $status = 'draft')
376
  {
377
  $title = ($title === null)
378
- ? _x('Feeds', 'default name of shortcode page', WPRSS_TEXT_DOMAIN)
379
  : $title;
380
 
381
  $id = wp_insert_post(array(
@@ -450,7 +445,7 @@ function wprss_should_do_intro_page()
450
  */
451
  function wprss_set_intro_done($done = true)
452
  {
453
- update_option(WPRSS_INTRO_DID_INTRO_OPTION, '1', false);
454
  }
455
 
456
  /**
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
  * Renders the intro page.
38
  *
39
  * @since 4.12
 
 
 
 
40
  */
41
  function wprss_render_intro_page()
42
  {
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
 
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
  $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
 
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
  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
  }
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
  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
  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
  }
330
 
331
  $name = parse_url($url, PHP_URL_HOST);
 
332
 
333
+ return ($name === null) ? $url : $name;
334
  }
335
 
336
  /**
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
  */
446
  function wprss_set_intro_done($done = true)
447
  {
448
+ update_option(WPRSS_INTRO_DID_INTRO_OPTION, $done ? '1' : '0', false);
449
  }
450
 
451
  /**
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
- 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.
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.
includes/admin-metaboxes.php CHANGED
@@ -1,783 +1,849 @@
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
- (function($){
309
- // When the DOM is ready
310
- $(document).ready( function(){
311
- // Move the link immediately after the url text field, and add the click event handler
312
- $('#validate-feed-link').click(function(e){
313
- // Get the url and proceed only if the url is not empty
314
- var url = $('#wprss_url').val();
315
- if ( url.trim().length > 0 ) {
316
- // Encode the url and generate the full url to the w3 feed validator
317
- var encodedUrl = encodeURIComponent( url );
318
- var fullURL = 'https://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
319
- // Open the window / tab
320
- window.open( fullURL, 'wprss-feed-validator' );
321
- }
322
- // Suppress the default link click behaviour
323
- e.preventDefault();
324
- e.stopPropagation();
325
- return false;
326
- });
327
- });
328
- })(jQuery);
329
- </script>
330
- <?php
331
  }
332
 
 
 
 
 
 
 
 
 
333
 
 
 
 
334
 
335
- add_action( 'save_post', 'wprss_save_custom_fields', 10, 2 );
336
- /**
337
- * Save the custom fields
338
- *
339
- * @since 2.0
340
- */
341
- function wprss_save_custom_fields( $post_id, $post ) {
342
- $meta_fields = wprss_get_custom_fields();
343
 
344
- /* Verify the nonce before proceeding. */
345
- if ( !isset( $_POST['wprss_meta_box_nonce'] ) ||
346
- !wp_verify_nonce( $_POST['wprss_meta_box_nonce'], 'wpra_feed_source' ) ) {
347
- return $post_id;
 
348
  }
 
349
 
350
- /* Get the post type object. */
351
- $post_type = get_post_type_object( $post->post_type );
352
-
353
- /* Check if the current user has permission to edit the post. */
354
- if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
355
- return $post_id;
356
-
357
- /* // Stop WP from clearing custom fields on autosave - maybe not needed
358
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
359
- return;
360
-
361
- // Prevent quick edit from clearing custom fields - maybe not needed
362
- if (defined('DOING_AJAX') && DOING_AJAX)
363
- return; */
364
-
365
- /** Bail out if running an autosave, ajax or a cron */
366
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
367
- return;
368
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
369
- return;
370
- if ( defined( 'DOING_CRON' ) && DOING_CRON )
371
- return;
372
-
373
- $postType = class_exists('WPRSS_FTP_Meta')
374
- ? WPRSS_FTP_Meta::get_instance()->get($post_id, 'post_type')
375
- : 'wprss_feed_item';
376
-
377
- if ($postType === 'wprss_feed_item' && isset($_POST['wpra_feed_def_ft_image']) ) {
378
- $def_ft_image_id = $_POST['wpra_feed_def_ft_image'];
379
-
380
- if (empty($def_ft_image_id)) {
381
- // Does not actually delete the image
382
- delete_post_thumbnail( $post_id );
383
- } else {
384
- set_post_thumbnail( $post_id, $def_ft_image_id );
385
- }
386
- }
387
 
388
- // Change the limit, if it is zero, to an empty string
389
- if ( isset( $_POST['wprss_limit'] ) && strval( $_POST['wprss_limit'] ) == '0' ) {
390
- $_POST['wprss_limit'] = '';
 
 
 
 
 
391
  }
 
392
 
393
- // loop through fields and save the data
394
- foreach ( $meta_fields as $field ) {
395
- $old = get_post_meta( $post_id, $field[ 'id' ], true );
396
- $new = trim( $_POST[ $field[ 'id' ] ] );
397
- if ( $new !== $old || empty($old) ) {
398
- update_post_meta( $post_id, $field[ 'id' ], $new );
399
- } elseif ( empty($new) && !empty($old) ) {
400
- delete_post_meta( $post_id, $field[ 'id' ], $old );
401
- }
402
- } // end foreach
403
-
404
- $force_feed = filter_input(INPUT_POST, 'wprss_force_feed', FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false';
405
 
406
- $state = filter_input(INPUT_POST, 'wprss_state', FILTER_SANITIZE_STRING);
407
- $state = strtolower(trim($state)) === 'paused' ? 'paused' : 'active';
408
 
409
- $activate = filter_input(INPUT_POST, 'wprss_activate_feed', FILTER_SANITIZE_STRING);
410
- $activate = $activate ? : '';
411
 
412
- $pause = filter_input(INPUT_POST, 'wprss_pause_feed', FILTER_SANITIZE_STRING);
413
- $pause = $pause ? : '';
414
 
415
- $age_limit = filter_input(INPUT_POST, 'wprss_age_limit', FILTER_VALIDATE_INT);
416
- $age_limit = (is_int($age_limit) && $age_limit > 0) ? (string) $age_limit : '';
417
 
418
- $age_unit = filter_input(INPUT_POST, 'wprss_age_unit', FILTER_SANITIZE_STRING);
419
- $age_unit = $age_unit ? strtolower($age_unit) : '';
420
- $age_unit = in_array($age_unit, wprss_age_limit_units()) ? $age_unit : '';
421
 
422
- $update_interval = filter_input(INPUT_POST, 'wprss_update_interval', FILTER_SANITIZE_STRING);
423
- $update_interval = $update_interval ? $update_interval : wprss_get_default_feed_source_update_interval();
424
- $old_update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
425
 
426
- // Update the feed source meta
427
- update_post_meta( $post_id, 'wprss_force_feed', $force_feed );
428
- update_post_meta( $post_id, 'wprss_activate_feed', $activate );
429
- update_post_meta( $post_id, 'wprss_pause_feed', $pause );
430
- update_post_meta( $post_id, 'wprss_age_limit', $age_limit );
431
- update_post_meta( $post_id, 'wprss_age_unit', $age_unit );
432
- update_post_meta( $post_id, 'wprss_update_interval', $update_interval );
433
 
434
- // Check if the state or the update interval has changed
435
- if ( get_post_meta( $post_id, 'wprss_state', TRUE ) !== $state || $old_update_interval !== $update_interval ) {
436
- // Pause the feed source, and if it is active, re-activate it.
437
- // This should update the feed's scheduling
438
- wprss_pause_feed_source( $post_id );
439
- if ( $state === 'active' )
440
- wprss_activate_feed_source( $post_id );
441
  }
 
442
 
443
- // Update the schedules
444
- wprss_update_feed_processing_schedules( $post_id );
445
 
446
- // If the feed source uses the global updating system, update the feed on publish
447
- if ( $update_interval === wprss_get_default_feed_source_update_interval() ) {
448
- wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
449
- }
450
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
 
452
-
453
- /**
454
- * Generate a preview of the latest 5 posts from the feed source being added/edited
455
- *
456
- * @since 2.0
457
- */
458
- function wprss_preview_meta_box_callback() {
459
- global $post;
460
- $feed_url = get_post_meta( $post->ID, 'wprss_url', true );
461
-
462
- $help = WPRSS_Help::get_instance();
463
- /* @var $help WPRSS_Help */
464
-
465
- echo '<div id="feed-preview-container">';
466
-
467
- if ( ! empty( $feed_url ) ) {
468
- $feed = wprss_fetch_feed( $feed_url, $post->ID );
469
- if ( ! is_wp_error( $feed ) ) {
470
- ob_start();
471
- // Figure out how many total items there are
472
- $total = @$feed->get_item_quantity();
473
- // Get the number of items again, but limit it to 5.
474
- $maxitems = $feed->get_item_quantity(5);
475
-
476
- // Build an array of all the items, starting with element 0 (first element).
477
- $items = $feed->get_items( 0, $maxitems );
478
- ob_clean();
 
479
  ?>
480
- <h4><?php echo sprintf( __( 'Latest %1$s feed items out of %2$s available from %3$s' ), $maxitems, $total, get_the_title() ) ?></h4>
481
- <ul>
482
- <?php
483
- foreach ( $items as $item ) {
484
- $date = $item->get_date( 'U' );
485
- $has_date = $date ? true : false;
486
-
487
- // Get human date
488
- if ( $has_date ) {
489
- $item_date = human_time_diff( $date, current_time('timestamp')).' '.__( 'ago', 'wprss' );
490
- } else {
491
- $item_date = '<em>[' . __( 'No Date', WPRSS_TEXT_DOMAIN ) . ']</em>';
492
- }
493
-
494
- // Start displaying item content within a <li> tag
495
- echo '<li>';
496
- // create item link
497
- //echo '<a href="'.esc_url( $item->get_permalink() ).'" title="'.$item_date.'">';
498
- // Get item title
499
- echo esc_html( $item->get_title() );
500
- //echo '</a>';
501
- // Display date
502
- echo ' <div class="rss-date"><small>'.$item_date.'</small></div>';
503
- // End <li> tag
504
- echo '</li>';
505
  }
506
  ?>
507
- </ul>
508
- <?php
509
- }
510
- else {
511
- ?>
512
- <span class="invalid-feed-url">
513
- <?php _e( '<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', WPRSS_TEXT_DOMAIN ) ?>
514
- <?php wprss_log_obj( 'Failed to preview feed.', $feed->get_error_message(), NULL, WPRSS_LOG_LEVEL_INFO ); ?>
515
- </span>
516
- <?php
517
- echo wpautop(
518
- sprintf(
519
- __('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'),
520
- 'https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed'
521
- )
522
- );
523
- }
524
-
525
- }
526
- else {
527
- echo '<p>' . __( 'No feed URL defined yet', WPRSS_TEXT_DOMAIN ) . '</p>';
528
  }
529
- echo '</div>';
530
-
531
- echo '<div id="force-feed-container">';
532
- wprss_render_force_feed_option( $post->ID, TRUE );
533
- echo '</div>';
534
  }
535
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
 
537
- /**
538
- * Renders the Force Feed option for the Feed Preview.
539
- *
540
- * @param int|string $feed_source_id (Optional) The ID of the feed source for the option will be rendered. If not given or
541
- * its value is null, the option will not be checked.
542
- * @param bool $echo (Optional) If set to true, the function will immediately echo the option,
543
- * rather than return a string of the option's markup. Default: False.
544
- * @return string|null A string containing the HTML for the rendered option if $echo is set to false,
545
- * or null if $echo is set to true.
546
- * @since 4.6.12
547
- */
548
- function wprss_render_force_feed_option( $feed_source_id = NULL, $echo = FALSE ) {
549
- if ( ! $echo ) ob_start();
550
- $force_feed = $feed_source_id === NULL ? '' : get_post_meta( $feed_source_id, 'wprss_force_feed', TRUE ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  <p>
552
- <label for="wprss-force-feed"><?php _e('Force the feed') ?></label>
553
- <input type="hidden" name="wprss_force_feed" value="false" />
554
- <input type="checkbox" name="wprss_force_feed" id="wprss-force-feed" value="true" <?php echo checked( $force_feed, 'true' ); ?> />
555
- <?php echo WPRSS_Help::get_instance()->tooltip( 'field_wprss_force_feed' ) ?>
 
 
556
  </p>
557
- <?php
558
- if ( ! $echo ) return ob_get_clean();
559
- return NULL;
560
- }
561
-
562
-
563
- /**
564
- * Renders the Feed Processing metabox
565
- *
566
- * @since 3.7
567
- */
568
- function wprss_feed_processing_meta_box_callback() {
569
- global $post;
570
- // Get the post meta
571
- $state = get_post_meta( $post->ID, 'wprss_state', TRUE );
572
- $activate = get_post_meta( $post->ID, 'wprss_activate_feed', TRUE );
573
- $pause = get_post_meta( $post->ID, 'wprss_pause_feed', TRUE );
574
- $update_interval = get_post_meta( $post->ID, 'wprss_update_interval', TRUE );
575
- $update_time = get_post_meta( $post->ID, 'wprss_update_time', TRUE );
576
-
577
- $age_limit = get_post_meta( $post->ID, 'wprss_age_limit', true );
578
- $age_unit = get_post_meta( $post->ID, 'wprss_age_unit', true );
579
-
580
- // Set default strings for activate and pause times
581
- $default_activate = 'immediately';
582
- $default_pause = 'never';
583
-
584
- // Prepare the states
585
- $states = array(
586
- 'active' => __( 'Active', WPRSS_TEXT_DOMAIN ),
587
- 'paused' => __( 'Paused', WPRSS_TEXT_DOMAIN ),
588
- );
589
-
590
- // Prepare the schedules
591
- $default_interval = __( 'Default', WPRSS_TEXT_DOMAIN );
592
- $wprss_schedules = apply_filters( 'wprss_schedules', wprss_get_schedules() );
593
- $default_interval_key = wprss_get_default_feed_source_update_interval();
594
- $schedules = array_merge(
595
- array(
596
- $default_interval_key => array(
597
- 'display' => $default_interval,
598
- 'interval' => $default_interval,
599
- ),
600
- ),
601
- $wprss_schedules
602
- );
603
-
604
- // Inline help
605
- $help = WPRSS_Help::get_instance();
606
- $help_options = array('tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-side');
607
-
608
- ?>
609
-
610
- <div class="wprss-meta-side-setting">
611
- <label for="wprss_state">Feed state:</label>
612
- <select id="wprss_state" name="wprss_state">
613
- <?php foreach( $states as $value => $label ) : ?>
614
- <option value="<?php echo $value; ?>" <?php selected( $state, $value ) ?> ><?php echo $label; ?></option>
615
- <?php endforeach; ?>
616
- </select>
617
- <?php echo $help->tooltip( 'field_wprss_state', null, $help_options ) ?>
618
- </div>
619
-
620
- <div class="wprss-meta-side-setting">
621
- <p>
622
- <label for="">Activate feed: </label>
623
- <strong id="wprss-activate-feed-viewer"><?php echo ( ( $activate !== '' )? $activate : $default_activate ); ?></strong>
624
- <a href="#">Edit</a>
625
- <?php echo $help->tooltip( 'field_wprss_activate_feed', null, $help_options ) ?>
626
- </p>
627
- <div class="wprss-meta-slider" data-collapse-viewer="wprss-activate-feed-viewer" data-default-value="<?php echo $default_activate; ?>">
628
- <input id="wprss_activate_feed" class="wprss-datetimepicker-from-today" name="wprss_activate_feed" value="<?php echo $activate; ?>" />
629
- <span class="description">
630
- Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
631
- </span>
632
- </div>
633
  </div>
 
634
 
635
- <div class="wprss-meta-side-setting">
636
- <p>
637
- <label for="">Pause feed: </label>
638
- <strong id="wprss-pause-feed-viewer"><?php echo ( ( $pause !== '' )? $pause : $default_pause ); ?></strong>
639
- <a href="#">Edit</a>
640
- <?php echo $help->tooltip( 'field_wprss_pause_feed', null, $help_options ) ?>
641
- </p>
642
- <div class="wprss-meta-slider" data-collapse-viewer="wprss-pause-feed-viewer" data-default-value="<?php echo $default_pause; ?>">
643
- <input id="wprss_pause_feed" class="wprss-datetimepicker-from-today" name="wprss_pause_feed" value="<?php echo $pause; ?>" />
644
- <span class="description">
645
- Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
646
- </span>
647
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
648
  </div>
 
649
 
650
 
651
- <div class="wprss-meta-side-setting">
652
- <p>
653
- <label for="">Update interval: </label>
654
- <strong id="wprss-feed-update-interval-viewer">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  <?php
656
- if ( $update_interval === '' || $update_interval === wprss_get_default_feed_source_update_interval() ) {
657
- echo $default_interval;
658
- }
659
- else {
660
- echo wprss_interval( $schedules[$update_interval]['interval'] );
661
- }
662
  ?>
663
- </strong>
664
- <a href="#">Edit</a>
665
- <?php echo $help->tooltip( 'field_wprss_update_interval', null, $help_options ) ?>
666
- </p>
667
- <div class="wprss-meta-slider" data-collapse-viewer="wprss-feed-update-interval-viewer" data-default-value="<?php echo $default_interval; ?>">
668
- <select id="feed-update-interval" name="wprss_update_interval">
669
- <?php foreach ( $schedules as $value => $schedule ) : ?>
670
- <?php $text = ( $value === wprss_get_default_feed_source_update_interval() )? $default_interval : wprss_interval( $schedule['interval'] ); ?>
671
- <option value="<?php echo $value; ?>" <?php selected( $update_interval, $value ); ?> ><?php echo $text; ?></option>
672
  <?php endforeach; ?>
673
- </select>
674
- <label>
675
- <input type="time" name="wpra_feed[update_time]" value="<?php echo esc_attr($update_time); ?>">
676
- </label>
677
- </div>
678
  </div>
 
679
 
680
 
681
- <div class="wprss-meta-side-setting">
682
- <p>
683
- <label id="wprss-age-limit-feed-label" for="" data-when-empty="Limit items by age:">
684
- <?php _e( 'Limit items by age:', 'wprss' ); ?>
685
- </label>
686
- <strong id="wprss-age-limit-feed-viewer">
687
- <?php _e( 'Default', WPRSS_TEXT_DOMAIN ); ?>
688
- </strong>
689
- <a href="#">Edit</a>
690
- <?php echo $help->tooltip( 'field_wprss_age_limit', null, $help_options ) ?>
691
- </p>
692
- <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">
693
- <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; ?>" />
694
-
695
- <select id="limit-feed-items-age-unit" name="wprss_age_unit">
696
- <?php foreach ( wprss_age_limit_units() as $unit ) : ?>
697
- <option value="<?php echo $unit; ?>" <?php selected( $age_unit, $unit ); ?> ><?php echo $unit; ?></option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
698
  <?php endforeach; ?>
699
- </select>
700
- </div>
701
  </div>
702
-
703
-
704
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  }
706
 
707
-
708
-
709
- /**
710
- * Generate Help meta box
711
- *
712
- * @since 2.0
713
- *
714
- */
715
- function wprss_help_meta_box_callback() {
716
- echo '<p><a href="https://www.wprssaggregator.com/documentation/">View the documentation</p>';
717
- echo '<p><strong>';
718
- _e( 'Need help?', WPRSS_TEXT_DOMAIN );
719
- echo '</strong> <a target="_blank" href="https://wordpress.org/support/plugin/wp-rss-aggregator">';
720
- _e( 'Check out the support forum', WPRSS_TEXT_DOMAIN );
721
- echo '</a></p>';
722
- echo '</strong> <a target="_blank" href="https://www.wprssaggregator.com/feature-requests/">';
723
- _e( 'Suggest a new feature', WPRSS_TEXT_DOMAIN );
724
- echo '</a></p>';
725
- }
726
-
727
- /**
728
- * Generate Like this plugin meta box
729
- *
730
- * @since 2.0
731
- *
732
- */
733
- function wprss_like_meta_box_callback()
734
- {
735
- ?>
736
- <ul>
737
- <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>
738
- </ul>
739
- <?php
740
- do_action('wpra_share_the_love_metabox');
741
- }
742
-
743
-
744
- /**
745
- * Generate Follow us plugin meta box
746
- *
747
- * @since 2.0
748
- *
749
- */
750
- function wprss_follow_meta_box_callback() {
751
- ?>
752
- <ul>
753
- <li class="twitter"><a href="https://twitter.com/wpmayor"><?php _e( 'Follow WP Mayor on Twitter.', WPRSS_TEXT_DOMAIN ) ?></a></li>
754
- <li class="facebook"><a href="https://www.facebook.com/wpmayor"><?php _e( 'Like WP Mayor on Facebook.', WPRSS_TEXT_DOMAIN ) ?></a></li>
755
- </ul>
756
- <?php }
757
-
758
-
759
- add_action( 'add_meta_boxes', 'wprss_remove_meta_boxes', 100 );
760
- /**
761
- * Remove unneeded meta boxes from add feed source screen
762
- *
763
- * @since 2.0
764
- */
765
- function wprss_remove_meta_boxes() {
766
- if ( 'wprss_feed' !== get_current_screen()->id ) return;
767
- // Remove meta boxes of other plugins that tend to appear on all posts
768
- //remove_meta_box( 'wpseo_meta', 'wprss_feed' ,'normal' );
769
- remove_meta_box( 'postpsp', 'wprss_feed' ,'normal' );
770
- remove_meta_box( 'su_postmeta', 'wprss_feed' ,'normal' );
771
- remove_meta_box( 'woothemes-settings', 'wprss_feed' ,'normal' );
772
- remove_meta_box( 'wpcf-post-relationship', 'wprss_feed' ,'normal' );
773
- remove_meta_box( 'wpar_plugin_meta_box ', 'wprss_feed' ,'normal' );
774
- remove_meta_box( 'sharing_meta', 'wprss_feed' ,'advanced' );
775
- remove_meta_box( 'content-permissions-meta-box', 'wprss_feed' ,'advanced' );
776
- remove_meta_box( 'theme-layouts-post-meta-box', 'wprss_feed' ,'side' );
777
- remove_meta_box( 'post-stylesheets', 'wprss_feed' ,'side' );
778
- remove_meta_box( 'hybrid-core-post-template', 'wprss_feed' ,'side' );
779
- remove_meta_box( 'wpcf-marketing', 'wprss_feed' ,'side' );
780
- remove_meta_box( 'trackbacksdiv22', 'wprss_feed' ,'advanced' );
781
- remove_meta_box( 'aiosp', 'wprss_feed' ,'advanced' );
782
- remove_action( 'post_submitbox_start', 'fpp_post_submitbox_start_action' );
783
- }
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
+ // for extensibility, allows more meta fields to be added
126
+ return apply_filters('wprss_fields', $wprss_meta_fields);
127
+ }
128
+
129
+ /**
130
+ * Set up the meta box for the wprss_feed post type
131
+ *
132
+ * @since 2.0
133
+ */
134
+ function wprss_show_meta_box_callback()
135
+ {
136
+ global $post;
137
+ $meta_fields = wprss_get_custom_fields();
138
+ $field_tooltip_id_prefix = 'field_';
139
+ $help = WPRSS_Help::get_instance();
140
+
141
+ // Use nonce for verification
142
+ wp_nonce_field('wpra_feed_source', 'wprss_meta_box_nonce');
143
+
144
+ // Fix for WordPress SEO JS issue
145
+ echo '<input type="hidden" id="content" value="" />';
146
+
147
+ // Begin form table
148
+ echo '<table class="form-table wprss-form-table">';
149
+
150
+ foreach ($meta_fields as $field) {
151
+ $meta = get_post_meta($post->ID, $field['id'], true);
152
+
153
+ // Add default placeholder value
154
+ $field = wp_parse_args($field, [
155
+ 'desc' => '',
156
+ 'placeholder' => '',
157
+ 'type' => 'text',
158
+ ]);
159
+
160
+ $fieldId = $field['id'];
161
+ $fieldLabel = $field['label'];
162
+ $fieldType = $field['type'];
163
+ $fieldDesc = $field['desc'];
164
+ $placeholder = isset($field['placeholder']) ? trim($field['placeholder']) : '';
165
+
166
+ $tooltip = isset($field['tooltip']) ? trim($field['tooltip']) : null;
167
+ $tooltip_id = isset($field['id']) ? $field_tooltip_id_prefix . $field['id'] : uniqid($field_tooltip_id_prefix);
168
+
169
+ // Begin row
170
+ echo '<tr>';
171
+
172
+ // Label
173
+ printf('<th><label for="%s">%s</label></th>', esc_attr($fieldId), esc_html($fieldLabel));
174
+
175
+ // Begin field
176
+ echo '<td>';
177
+
178
+ if (isset($field['before']) && !empty($field['before'])) {
179
+ call_user_func($field['before']);
180
+ }
181
 
182
+ switch ($fieldType) {
183
+ // text/url
184
+ case 'url':
185
+ case 'text':
186
+ {
187
+ printf(
188
+ '<input id="%1$s" type="%2$s" name="%1$s" value="%3$s" placeholder="%4$s" class="wprss-text-input />"',
189
+ esc_attr($fieldId),
190
+ esc_attr($fieldType),
191
+ esc_attr($meta),
192
+ esc_attr($placeholder)
193
+ );
194
 
195
+ echo $help->tooltip($tooltip_id, $tooltip);
196
+ echo wprss_render_option_desc($fieldDesc, $fieldId);
197
+ break;
198
+ }
 
 
 
 
 
 
199
 
200
+ // textarea
201
+ case 'textarea':
202
+ {
203
+ printf(
204
+ '<textarea id="%1$s" name="%1$s" cols="60" rows="4">%2$s</textarea>',
205
+ esc_attr($fieldId),
206
+ esc_textarea($meta)
207
+ );
208
 
209
+ echo $help->tooltip($tooltip_id, $tooltip);
210
+ echo wprss_render_option_desc($fieldDesc, $fieldId);
211
+ break;
212
+ }
213
 
214
+ // checkbox
215
+ case 'checkbox2':
216
+ case 'checkbox':
217
+ {
218
+ $trueValue = $fieldType === 'checkbox' ? 'true' : '1';
219
+ $falseValue = $fieldType === 'checkbox' ? 'false' : '0';
220
+
221
+ printf('<input type="hidden" name="%s" value="%s" />', esc_attr($fieldId), esc_attr($falseValue));
222
+ printf(
223
+ '<input type="checkbox" name="%1$s" id="%1$s" value="%2$s" %3$s />',
224
+ esc_attr($fieldId),
225
+ esc_attr($trueValue),
226
+ checked($meta, $trueValue, false)
227
+ );
228
 
229
+ echo $help->tooltip($tooltip_id, $tooltip);
230
+ echo wprss_render_option_desc($fieldDesc, $fieldId);
231
+ break;
232
+ }
 
 
 
 
 
 
 
233
 
234
+ // select
235
+ case 'select':
236
+ printf('<select name="%1$s" id="%1$s">', esc_attr($fieldId));
237
+
238
+ foreach ($field['options'] as $option) {
239
+ printf(
240
+ '<option %1$s value="%2$s">%3$s</option>',
241
+ selected($option['value'], $meta, false),
242
+ esc_attr($option['value']),
243
+ esc_html($option['label'])
244
+ );
245
+ }
246
 
247
+ echo '</select>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
+ echo $help->tooltip($tooltip_id, $tooltip);
250
+ echo wprss_render_option_desc($fieldDesc, $fieldId);
251
+ break;
 
 
252
 
253
+ // A select with "On" and "Off" values, and a special option to fall back to General setting
254
+ case 'boolean_fallback':
255
+ {
256
+ $options = wprss_settings_get_feed_source_boolean_options();
257
+ if ($meta === '') {
258
+ $meta = -1;
259
+ }
260
+ echo wprss_settings_render_select($field['id'], $field['id'], $options, $meta);
261
+ echo $help->tooltip($tooltip_id, $tooltip);
262
+ break;
263
+ }
264
 
265
+ // number
266
+ case 'number':
267
+ {
268
+ printf(
269
+ '<input id="%1$s" name="%1$s" class="wprss-number-roller" type="number" min="0" value="%2$s" placeholder="%3$s" />',
270
+ esc_attr($fieldId),
271
+ esc_attr($meta),
272
+ __('Default', 'wprss')
273
+ );
274
 
275
+ echo $help->tooltip($tooltip_id, $tooltip);
276
+ echo wprss_render_option_desc($fieldDesc, $fieldId);
277
+ break;
278
+ }
 
 
279
  }
280
 
281
+ if (isset($field['after']) && !empty($field['after'])) {
282
+ call_user_func($field['after']);
283
+ }
 
 
284
 
285
+ // End field
286
+ echo '</td>';
287
+
288
+ // End row
289
+ echo '</tr>';
290
  }
291
 
292
+ echo '</table>';
293
+ }
294
+
295
+ /** @deprecated There shouldn't be any options that still use a description. All help text was moved to tooltips. */
296
+ function wprss_render_option_desc($desc, $id)
297
+ {
298
+ if (strlen($desc) === 0) {
299
+ return '';
300
+ }
301
 
302
+ ob_start();
303
+ ?>
304
+ <br />
305
+ <label for="<?= esc_attr($id) ?>">
306
+ <span class="description">
307
+ <?= esc_html($desc) ?>
308
+ </span>
309
+ </label>
310
+ <?php
311
+ return ob_get_clean();
312
+ }
313
+
314
+ /**
315
+ * Renders content after the URL field
316
+ *
317
+ * @since 3.9.5
318
+ */
319
+ function wprss_after_url()
320
+ {
321
+ ?>
322
+ <i
323
+ id="wprss-url-spinner"
324
+ class="fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon"
325
+ title="<?= __('Updating feed source', 'wprss') ?>">
326
+ </i>
327
+
328
+ <div id="wprss-url-error" style="color:red"></div>
329
+
330
+ <a href="#" id="validate-feed-link" class="wprss-after-url-link">
331
+ Validate feed
332
+ </a>
333
+
334
+ <span> | </span>
335
+
336
+ <a
337
+ href="https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed"
338
+ class="wprss-after-url-link"
339
+ target="_blank"
340
+ >
341
+ <?= __('How to find an RSS feed', 'wprss') ?>
342
+ </a>
343
+
344
+ <script type="text/javascript">
345
+ (function ($) {
346
+ // When the DOM is ready
347
+ $(document).ready(function () {
348
+ // Move the link immediately after the url text field, and add the click event handler
349
+ $('#validate-feed-link').on('click', function (e) {
350
+ // Get the url and proceed only if the url is not empty
351
+ var url = $('#wprss_url').val();
352
+ if (url.trim().length > 0) {
353
+ // Encode the url and generate the full url to the w3 feed validator
354
+ var encodedUrl = encodeURIComponent(url);
355
+ var fullURL = 'https://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
356
+ // Open the window / tab
357
+ window.open(fullURL, 'wprss-feed-validator');
358
+ }
359
+ // Suppress the default link click behaviour
360
+ e.preventDefault();
361
+ e.stopPropagation();
362
+ return false;
363
+ });
364
+ });
365
+ })(jQuery);
366
+ </script>
367
+ <?php
368
+ }
369
+
370
+ /**
371
+ * Save the custom fields
372
+ *
373
+ * @since 2.0
374
+ */
375
+ add_action('save_post', function ($post_id, $post) {
376
+ $meta_fields = wprss_get_custom_fields();
377
+
378
+ /* Verify the nonce before proceeding. */
379
+ if (!isset($_POST['wprss_meta_box_nonce']) ||
380
+ !wp_verify_nonce($_POST['wprss_meta_box_nonce'], 'wpra_feed_source')) {
381
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
383
 
384
+ /* Get the post type object. */
385
+ $post_type = get_post_type_object($post->post_type);
386
 
387
+ /* Check if the current user has permission to edit the post. */
388
+ if (!current_user_can($post_type->cap->edit_post, $post_id)) {
389
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  }
391
 
392
+ /** Bail out if running an autosave, ajax or a cron */
393
+ if (
394
+ (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) ||
395
+ (defined('DOING_AJAX') && DOING_AJAX) ||
396
+ (defined('DOING_CRON') && DOING_CRON)
397
+ ) {
398
+ return;
399
+ }
400
 
401
+ $postType = class_exists('WPRSS_FTP_Meta')
402
+ ? WPRSS_FTP_Meta::get_instance()->get($post_id, 'post_type')
403
+ : 'wprss_feed_item';
404
 
405
+ if ($postType === 'wprss_feed_item' && isset($_POST['wpra_feed_def_ft_image'])) {
406
+ $def_ft_image_id = $_POST['wpra_feed_def_ft_image'];
 
 
 
 
 
 
407
 
408
+ if (empty($def_ft_image_id)) {
409
+ // Does not actually delete the image
410
+ delete_post_thumbnail($post_id);
411
+ } else {
412
+ set_post_thumbnail($post_id, $def_ft_image_id);
413
  }
414
+ }
415
 
416
+ // Change the limit, if it is zero, to an empty string
417
+ if (isset($_POST['wprss_limit']) && strval($_POST['wprss_limit']) == '0') {
418
+ $_POST['wprss_limit'] = '';
419
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
+ // loop through fields and save the data
422
+ foreach ($meta_fields as $field) {
423
+ $old = get_post_meta($post_id, $field['id'], true);
424
+ $new = trim($_POST[$field['id']]);
425
+ if ($new !== $old || empty($old)) {
426
+ update_post_meta($post_id, $field['id'], $new);
427
+ } elseif (empty($new) && !empty($old)) {
428
+ delete_post_meta($post_id, $field['id'], $old);
429
  }
430
+ } // end foreach
431
 
432
+ $force_feed = filter_input(INPUT_POST, 'wprss_force_feed', FILTER_VALIDATE_BOOLEAN) ? 'true' : 'false';
 
 
 
 
 
 
 
 
 
 
 
433
 
434
+ $state = filter_input(INPUT_POST, 'wprss_state', FILTER_SANITIZE_STRING);
435
+ $state = strtolower(trim($state)) === 'paused' ? 'paused' : 'active';
436
 
437
+ $activate = filter_input(INPUT_POST, 'wprss_activate_feed', FILTER_SANITIZE_STRING);
438
+ $activate = $activate ? : '';
439
 
440
+ $pause = filter_input(INPUT_POST, 'wprss_pause_feed', FILTER_SANITIZE_STRING);
441
+ $pause = $pause ? : '';
442
 
443
+ $age_limit = filter_input(INPUT_POST, 'wprss_age_limit', FILTER_VALIDATE_INT);
444
+ $age_limit = (is_int($age_limit) && $age_limit > 0) ? (string) $age_limit : '';
445
 
446
+ $age_unit = filter_input(INPUT_POST, 'wprss_age_unit', FILTER_SANITIZE_STRING);
447
+ $age_unit = $age_unit ? strtolower($age_unit) : '';
448
+ $age_unit = in_array($age_unit, wprss_age_limit_units()) ? $age_unit : '';
449
 
450
+ $update_interval = filter_input(INPUT_POST, 'wprss_update_interval', FILTER_SANITIZE_STRING);
451
+ $update_interval = $update_interval ? $update_interval : wprss_get_default_feed_source_update_interval();
452
+ $old_update_interval = get_post_meta($post_id, 'wprss_update_interval', true);
453
 
454
+ // Update the feed source meta
455
+ update_post_meta($post_id, 'wprss_force_feed', $force_feed);
456
+ update_post_meta($post_id, 'wprss_activate_feed', $activate);
457
+ update_post_meta($post_id, 'wprss_pause_feed', $pause);
458
+ update_post_meta($post_id, 'wprss_age_limit', $age_limit);
459
+ update_post_meta($post_id, 'wprss_age_unit', $age_unit);
460
+ update_post_meta($post_id, 'wprss_update_interval', $update_interval);
461
 
462
+ // Check if the state or the update interval has changed
463
+ if (get_post_meta($post_id, 'wprss_state', true) !== $state || $old_update_interval !== $update_interval) {
464
+ // Pause the feed source, and if it is active, re-activate it.
465
+ // This should update the feed's scheduling
466
+ wprss_pause_feed_source($post_id);
467
+ if ($state === 'active') {
468
+ wprss_activate_feed_source($post_id);
469
  }
470
+ }
471
 
472
+ // Update the schedules
473
+ wprss_update_feed_processing_schedules($post_id);
474
 
475
+ // If the feed source uses the global updating system, update the feed on publish
476
+ if ($update_interval === wprss_get_default_feed_source_update_interval()) {
477
+ wp_schedule_single_event(time(), 'wprss_fetch_single_feed_hook', [$post_id]);
 
478
  }
479
+ }, 10, 2);
480
+
481
+ /**
482
+ * Generate a preview of the latest 5 posts from the feed source being added/edited
483
+ *
484
+ * @since 2.0
485
+ */
486
+ function wprss_preview_meta_box_callback()
487
+ {
488
+ global $post;
489
+ $feed_url = get_post_meta($post->ID, 'wprss_url', true);
490
+
491
+ echo '<div id="feed-preview-container">';
492
+
493
+ if (empty($feed_url)) {
494
+ echo '<p>' . __('No feed URL defined yet', 'wprss') . '</p>';
495
+ } else {
496
+ $feed = wprss_fetch_feed($feed_url, $post->ID);
497
+
498
+ // Check if failed to fetch the feed
499
+ if (is_wp_error($feed)) {
500
+ // Log the error
501
+ wprss_log_obj('Failed to preview feed.', $feed->get_error_message(), null, WPRSS_LOG_LEVEL_INFO);
502
+ printf(
503
+ '<span class="invalid-feed-url">%s</span>',
504
+ __('<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', 'wprss')
505
+ );
506
 
507
+ echo wpautop(
508
+ sprintf(
509
+ __(
510
+ 'Not sure where to find the RSS feed on a website? <a target="_blank" href="%1$s">Click here</a> for a visual guide.',
511
+ 'wprss'
512
+ ),
513
+ 'https://kb.wprssaggregator.com/article/55-how-to-find-an-rss-feed'
514
+ )
515
+ );
516
+ } else {
517
+ ob_start();
518
+ // Figure out how many total items there are
519
+ $total = @$feed->get_item_quantity();
520
+ // Get the number of items again, but limit it to 5.
521
+ $maxItems = $feed->get_item_quantity(5);
522
+
523
+ // Build an array of all the items, starting with element 0 (first element).
524
+ $items = $feed->get_items(0, $maxItems);
525
+ ob_clean();
526
+ ?>
527
+ <h4>
528
+ <?php
529
+ printf(
530
+ __('Latest %1$s feed items out of %2$s available from %3$s'),
531
+ $maxItems,
532
+ $total,
533
+ get_the_title()
534
+ )
535
  ?>
536
+ </h4>
537
+ <ul>
538
+ <?php
539
+ foreach ($items as $item) {
540
+ $date = $item->get_date('U');
541
+ $has_date = !!$date;
542
+
543
+ // Get human readable date
544
+ $item_date = ($has_date)
545
+ ? human_time_diff($date, current_time('timestamp')) . ' ' . __('ago', 'wprss')
546
+ : sprintf('<em>[%s]</em>', esc_html(__('No Date', 'wprss')));
547
+
548
+ printf(
549
+ '<li>%s<div class="rss-date"><small>%s</small></div></li>',
550
+ esc_html($item->get_title()),
551
+ $item_date
552
+ );
 
 
 
 
 
 
 
 
553
  }
554
  ?>
555
+ </ul>
556
+ <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  }
 
 
 
 
 
558
  }
559
 
560
+ echo '</div>';
561
+ echo '<div id="force-feed-container">';
562
+
563
+ wprss_render_force_feed_option($post->ID, true);
564
+
565
+ echo '</div>';
566
+ }
567
+
568
+ /**
569
+ * Renders the Force Feed option for the Feed Preview.
570
+ *
571
+ * @since 4.6.12
572
+ *
573
+ * @param bool $echo (Optional) If set to true, the function will immediately echo the option,
574
+ * rather than return a string of the option's markup. Default: False.
575
+ * @param int|string $feed_source_id (Optional) The ID of the feed source for the option will be rendered. If not given
576
+ * or its value is null, the option will not be checked.
577
+ *
578
+ * @return string|null A string containing the HTML for the rendered option if $echo is set to false,
579
+ * or null if $echo is set to true.
580
+ */
581
+ function wprss_render_force_feed_option($feed_source_id = null, $echo = false)
582
+ {
583
+ if (!$echo) {
584
+ ob_start();
585
+ }
586
 
587
+ $force_feed = $feed_source_id !== null
588
+ ? get_post_meta($feed_source_id, 'wprss_force_feed', true)
589
+ : '';
590
+
591
+ echo '<p>';
592
+ echo '<label for="wprss-force-feed">' . __('Force the feed', 'wprss') . '</label>';
593
+ echo '<input type="hidden" name="wprss_force_feed" value="false" />';
594
+
595
+ printf(
596
+ '<input type="checkbox" name="wprss_force_feed" id="wprss-force-feed" value="true" %s />',
597
+ checked($force_feed, 'true', false)
598
+ );
599
+
600
+ echo WPRSS_Help::get_instance()->tooltip('field_wprss_force_feed');
601
+ echo '</p>';
602
+
603
+ return $echo ? null : ob_get_clean();
604
+ }
605
+
606
+ /**
607
+ * Renders the Feed Processing metabox
608
+ *
609
+ * @since 3.7
610
+ */
611
+ function wprss_feed_processing_meta_box_callback()
612
+ {
613
+ global $post;
614
+
615
+ // Get the post meta
616
+ $state = get_post_meta($post->ID, 'wprss_state', true);
617
+ $activate = get_post_meta($post->ID, 'wprss_activate_feed', true);
618
+ $pause = get_post_meta($post->ID, 'wprss_pause_feed', true);
619
+ $update_interval = get_post_meta($post->ID, 'wprss_update_interval', true);
620
+ $update_time = get_post_meta($post->ID, 'wprss_update_time', true);
621
+
622
+ $age_limit = get_post_meta($post->ID, 'wprss_age_limit', true);
623
+ $age_unit = get_post_meta($post->ID, 'wprss_age_unit', true);
624
+
625
+ // Set default strings for activate and pause times
626
+ $default_activate = 'immediately';
627
+ $default_pause = 'never';
628
+
629
+ // Prepare the states
630
+ $states = [
631
+ 'active' => __('Active', 'wprss'),
632
+ 'paused' => __('Paused', 'wprss'),
633
+ ];
634
+
635
+ // Prepare the schedules
636
+ $default_interval = __('Default', 'wprss');
637
+ $wprss_schedules = apply_filters('wprss_schedules', wprss_get_schedules());
638
+ $default_interval_key = wprss_get_default_feed_source_update_interval();
639
+ $schedules = array_merge(
640
+ [
641
+ $default_interval_key => [
642
+ 'display' => $default_interval,
643
+ 'interval' => $default_interval,
644
+ ],
645
+ ],
646
+ $wprss_schedules
647
+ );
648
+
649
+ // Inline help
650
+ $help = WPRSS_Help::get_instance();
651
+ $help_options = [
652
+ 'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-side',
653
+ ];
654
+
655
+ ?>
656
+
657
+ <div class="wprss-meta-side-setting">
658
+ <label for="wprss_state">Feed state:</label>
659
+ <select id="wprss_state" name="wprss_state">
660
+ <?php foreach ($states as $value => $label) : ?>
661
+ <option value="<?= esc_attr($value) ?>" <?php selected($state, $value) ?> >
662
+ <?= esc_html($label) ?>
663
+ </option>
664
+ <?php endforeach; ?>
665
+ </select>
666
+ <?= $help->tooltip('field_wprss_state', null, $help_options) ?>
667
+ </div>
668
+
669
+ <div class="wprss-meta-side-setting">
670
  <p>
671
+ <label for="">Activate feed: </label>
672
+ <strong id="wprss-activate-feed-viewer">
673
+ <?= empty($activate) ? $default_activate : esc_attr($activate) ?>
674
+ </strong>
675
+ <a href="#">Edit</a>
676
+ <?= $help->tooltip('field_wprss_activate_feed', null, $help_options) ?>
677
  </p>
678
+ <div
679
+ class="wprss-meta-slider"
680
+ data-collapse-viewer="wprss-activate-feed-viewer"
681
+ data-default-value="<?php echo $default_activate; ?>">
682
+ <input
683
+ id="wprss_activate_feed"
684
+ class="wprss-datetimepicker-from-today"
685
+ name="wprss_activate_feed"
686
+ value="<?= esc_attr($activate) ?>"
687
+ />
688
+ <span class="description">
689
+ Current UTC time is:
690
+ <br />
691
+ <code>
692
+ <?= date('d/m/Y H:i:s', current_time('timestamp', 1)) ?>
693
+ </code>
694
+ </span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  </div>
696
+ </div>
697
 
698
+ <div class="wprss-meta-side-setting">
699
+ <p>
700
+ <label for="">Pause feed: </label>
701
+ <strong id="wprss-pause-feed-viewer">
702
+ <?= empty($pause) ? $default_pause : $pause ?>
703
+ </strong>
704
+ <a href="#">Edit</a>
705
+ <?= $help->tooltip('field_wprss_pause_feed', null, $help_options) ?>
706
+ </p>
707
+ <div
708
+ class="wprss-meta-slider"
709
+ data-collapse-viewer="wprss-pause-feed-viewer"
710
+ data-default-value="<?= esc_attr($default_pause) ?>">
711
+ <input
712
+ id="wprss_pause_feed"
713
+ class="wprss-datetimepicker-from-today"
714
+ name="wprss_pause_feed"
715
+ value="<?= esc_attr($pause) ?>"
716
+ />
717
+ <span class="description">
718
+ Current UTC time is:
719
+ <br />
720
+ <code>
721
+ <?= date('d/m/Y H:i:s', current_time('timestamp', 1)) ?>
722
+ </code>
723
+ </span>
724
  </div>
725
+ </div>
726
 
727
 
728
+ <div class="wprss-meta-side-setting">
729
+ <p>
730
+ <label for="">Update interval: </label>
731
+ <strong id="wprss-feed-update-interval-viewer">
732
+ <?php
733
+ if ($update_interval === '' || $update_interval === wprss_get_default_feed_source_update_interval()) {
734
+ echo $default_interval;
735
+ } else {
736
+ echo wprss_interval($schedules[$update_interval]['interval']);
737
+ }
738
+ ?>
739
+ </strong>
740
+ <a href="#">Edit</a>
741
+ <?= $help->tooltip('field_wprss_update_interval', null, $help_options) ?>
742
+ </p>
743
+ <div
744
+ class="wprss-meta-slider"
745
+ data-collapse-viewer="wprss-feed-update-interval-viewer"
746
+ data-default-value="<?= esc_attr($default_interval) ?>">
747
+ <select id="feed-update-interval" name="wprss_update_interval">
748
+ <?php foreach ($schedules as $value => $schedule) : ?>
749
  <?php
750
+ $text = ($value === wprss_get_default_feed_source_update_interval())
751
+ ? $default_interval
752
+ : wprss_interval($schedule['interval']);
 
 
 
753
  ?>
754
+ <option value="<?= esc_attr($value) ?>" <?php selected($update_interval, $value) ?>>
755
+ <?= esc_html($text) ?>
756
+ </option>
 
 
 
 
 
 
757
  <?php endforeach; ?>
758
+ </select>
759
+ <label>
760
+ <input type="time" name="wpra_feed[update_time]" value="<?= esc_attr($update_time) ?>">
761
+ </label>
 
762
  </div>
763
+ </div>
764
 
765
 
766
+ <div class="wprss-meta-side-setting">
767
+ <p>
768
+ <label id="wprss-age-limit-feed-label" for="" data-when-empty="Limit items by age:">
769
+ <?= __('Limit items by age:', 'wprss'); ?>
770
+ </label>
771
+ <strong id="wprss-age-limit-feed-viewer">
772
+ <?= __('Default', 'wprss'); ?>
773
+ </strong>
774
+ <a href="#">Edit</a>
775
+ <?php echo $help->tooltip('field_wprss_age_limit', null, $help_options) ?>
776
+ </p>
777
+ <div
778
+ class="wprss-meta-slider"
779
+ data-collapse-viewer="wprss-age-limit-feed-viewer"
780
+ data-label="#wprss-age-limit-feed-label"
781
+ data-default-value=""
782
+ data-empty-controller="#limit-feed-items-age"
783
+ data-hybrid="#limit-feed-items-age, #limit-feed-items-age-unit">
784
+ <input
785
+ id="limit-feed-items-age"
786
+ name="wprss_age_limit"
787
+ type="number"
788
+ min="0"
789
+ class="wprss-number-roller"
790
+ placeholder="No limit"
791
+ value="<?= esc_attr($age_limit) ?>" />
792
+
793
+ <select id="limit-feed-items-age-unit" name="wprss_age_unit">
794
+ <?php foreach (wprss_age_limit_units() as $unit) : ?>
795
+ <option value="<?= esc_attr($unit) ?>" <?php selected($age_unit, $unit) ?> >
796
+ <?= esc_html($unit) ?>
797
+ </option>
798
  <?php endforeach; ?>
799
+ </select>
 
800
  </div>
801
+ </div>
802
+
803
+
804
+ <?php
805
+ }
806
+
807
+ /**
808
+ * Generate Like this plugin meta box
809
+ *
810
+ * @since 2.0
811
+ *
812
+ */
813
+ function wprss_like_meta_box_callback()
814
+ {
815
+ printf(
816
+ '<ul><li><a href="%s" target="_blank">%s</a></li></ul>',
817
+ 'https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?rate=5#postform',
818
+ __('Give it a 5 star rating on WordPress.org', 'wprss')
819
+ );
820
+
821
+ do_action('wpra_share_the_love_metabox');
822
+ }
823
+
824
+ /**
825
+ * Remove meta boxes from add feed source screen that tend to appear for all post types.
826
+ *
827
+ * @since 2.0
828
+ */
829
+ add_action('add_meta_boxes', function () {
830
+ if ('wprss_feed' !== get_current_screen()->id) {
831
+ return;
832
  }
833
 
834
+ //remove_meta_box( 'wpseo_meta', 'wprss_feed' ,'normal' );
835
+ remove_meta_box('postpsp', 'wprss_feed', 'normal');
836
+ remove_meta_box('su_postmeta', 'wprss_feed', 'normal');
837
+ remove_meta_box('woothemes-settings', 'wprss_feed', 'normal');
838
+ remove_meta_box('wpcf-post-relationship', 'wprss_feed', 'normal');
839
+ remove_meta_box('wpar_plugin_meta_box ', 'wprss_feed', 'normal');
840
+ remove_meta_box('sharing_meta', 'wprss_feed', 'advanced');
841
+ remove_meta_box('content-permissions-meta-box', 'wprss_feed', 'advanced');
842
+ remove_meta_box('theme-layouts-post-meta-box', 'wprss_feed', 'side');
843
+ remove_meta_box('post-stylesheets', 'wprss_feed', 'side');
844
+ remove_meta_box('hybrid-core-post-template', 'wprss_feed', 'side');
845
+ remove_meta_box('wpcf-marketing', 'wprss_feed', 'side');
846
+ remove_meta_box('trackbacksdiv22', 'wprss_feed', 'advanced');
847
+ remove_meta_box('aiosp', 'wprss_feed', 'advanced');
848
+ remove_action('post_submitbox_start', 'fpp_post_submitbox_start_action');
849
+ }, 100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- __('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
- 'https://codex.wordpress.org/Formatting_Date_and_Time',
421
- __('PHP Date Format Reference', 'wprss')
422
  );
423
  }
424
 
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
 
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
 
includes/admin-options.php CHANGED
@@ -1,1035 +1,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
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 name="%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
+ }
includes/admin-plugins.php CHANGED
@@ -24,94 +24,98 @@ 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', 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
  });
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
  });
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_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'
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'
includes/admin.php CHANGED
@@ -1,191 +1,230 @@
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 .= ' post-'.$_GET['post'];
56
- }
57
- // New post type & listing page
58
- if ( isset($_GET['post_type']) ) $post_type = $_GET['post_type'];
59
- if ( isset($post_type) ) {
60
- $classes .= ' post-type-'.$post_type;
61
- }
62
- // Editting a post type
63
- if ( isset( $_GET['post'] ) ) {
64
- $post_query = $_GET['post'];
65
- }
66
- if ( isset($post_query) ) {
67
- $current_post_edit = get_post($post_query);
68
- $current_post_type = $current_post_edit->post_type;
69
- if ( !empty($current_post_type) ) {
70
- $classes .= ' post-type-'.$current_post_type;
71
- }
72
- }
73
- // Return the $classes array
74
- return $classes;
75
  }
76
 
 
 
 
 
77
 
78
- /**
79
- * Change title on wprss_feed post type screen
80
- *
81
- * @since 2.0
82
- *
83
- * @param string $original The original title placeholder.
84
- *
85
- * @return string
86
- */
87
- function wprss_change_title_text($original) {
88
- if (get_post_type() === 'wprss_feed') {
89
- return __('Name this feed', WPRSS_TEXT_DOMAIN);
90
  }
 
91
 
92
- return $original;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- add_filter( 'plugin_action_links', 'wprss_plugin_action_links', 10, 2 );
97
- /**
98
- * Add Settings action link in plugin listing
99
- *
100
- * @since 3.0
101
- * @param array $action_links
102
- * @param string $plugin_file
103
- * @return array
104
- */
105
- function wprss_plugin_action_links( $action_links, $plugin_file ) {
106
- // check to make sure we are on the correct plugin
107
- if ( $plugin_file == 'wp-rss-aggregator/wp-rss-aggregator.php' ) {
108
- // the anchor tag and href to the URLs we want.
109
- $settings_link = '<a href="' . admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings">' . __( 'Settings', WPRSS_TEXT_DOMAIN ) . '</a>';
110
- $docs_link = '<a href="https://www.wprssaggregator.com/documentation/">' . __( 'Documentation', WPRSS_TEXT_DOMAIN ) . '</a>';
111
- // add the links to the beginning of the list
112
- array_unshift( $action_links, $settings_link, $docs_link );
113
- }
114
- return $action_links;
115
  }
116
 
117
- /**
118
- * Function for registering application's scripts that depends on advanced libraries.
119
- * It will enqueue manifest and vendor scripts, which contains all required logic
120
- * for bootstrapping application and dependencies.
121
- *
122
- * Use only for Vue-related apps that use Webpack for being built.
123
- *
124
- * @since 4.12.1
125
- *
126
- * @param $handle
127
- * @param string $src
128
- * @param array $deps
129
- * @param bool $ver
130
- * @param bool $in_footer
 
 
 
 
 
 
 
 
 
131
  */
132
- function wprss_plugin_enqueue_app_scripts( $handle, $src = '', $deps = array(), $ver = false, $in_footer = false ) {
133
- /*
134
- * Manifest file holds function used for bootstrapping and ordered
135
- * loading of dependencies and application.
136
- */
137
- wp_enqueue_script('wpra-manifest', WPRSS_APP_JS . 'wpra-manifest.min.js', array(), '0.1', true);
138
-
139
- /*
140
- * Vendor file holds all common dependencies for "compilable" applications.
141
- *
142
- * For example, `intro` pages application's and plugin's page application's files
143
- * holds only logic for that particular application. Common dependencies like Vue
144
- * live in this file and loaded before that application.
145
- */
146
- wp_enqueue_script('wpra-vendor', WPRSS_APP_JS . 'wpra-vendor.min.js', array(
147
- 'wpra-manifest'
148
- ), '0.1', true);
149
-
150
- /*
151
- * Enqueue requested script.
152
- */
153
- $deps = array_merge(array(
154
- 'wpra-manifest',
155
- 'wpra-vendor',
156
- ), $deps);
157
- wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
158
- }
159
 
160
- add_filter('admin_footer_text', 'wprss_admin_footer');
161
- /**
162
- * Adds footer text on the plugin pages.
163
- *
164
- * @param string $footer The footer text to filter
165
  *
166
- * @return string The filtered footer text with added plugin text, or the param
167
- * value if the page is not specific to the plugin.
 
168
  */
169
- function wprss_admin_footer($footer)
170
- {
171
- // Current post type
172
- global $typenow;
173
- // Check if type is a plugin type. If not, stop
174
- // Plugin type is in the form 'wprss_*'' where * is 'feed', 'blacklist', etc)
175
- if (stripos($typenow, 'wprss_') !== 0) {
176
- return $footer;
177
- }
178
-
179
- // Prepare fragments of the message
180
- $thank_you = sprintf(
181
- __('Thank you for using <a href="%1$s" target="_blank">WP RSS Aggregator</a>.', 'wprss'),
182
- 'https://www.wprssaggregator.com/'
183
- );
184
- $rate_us = sprintf(
185
- __('Please <a href="%1$s" target="_blank">rate us</a>!', 'wprss'),
186
- 'https://wordpress.org/support/view/plugin-reviews/wp-rss-aggregator?filter=5#postform'
187
- );
188
 
189
- // Return the final text
190
- return sprintf('<span class="wp-rss-footer-text">%1$s %2$s</span>', $thank_you, $rate_us);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
includes/cpt-feeds.php CHANGED
@@ -1,101 +1,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
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
includes/feed-access.php CHANGED
@@ -200,17 +200,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_TEXT_DOMAIN ),
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_TEXT_DOMAIN ),
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_TEXT_DOMAIN ),
214
  'callback' => array( $this, 'render_feed_cache_setting' )
215
  );
216
 
@@ -245,10 +245,15 @@ 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
- <input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[<?php echo $field['field_id'] ?>]" type="text" value="<?php echo $feed_limit ?>" />
251
- <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
252
  }
253
 
254
  /**
@@ -260,10 +265,16 @@ class WPRSS_Feed_Access
260
  */
261
  public function render_feed_request_useragent_setting( $field )
262
  {
263
- $value = wprss_get_general_setting( $field['field_id'] );
264
- ?>
265
- <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) ?>" />
266
- <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
 
 
267
  }
268
 
269
  /**
@@ -276,15 +287,19 @@ class WPRSS_Feed_Access
276
  public function render_feed_cache_setting( $field )
277
  {
278
  $value = (int) wprss_get_general_setting($field['field_id']);
279
- ?>
280
- <input name="wprss_settings_general[<?= $field['field_id'] ?>]" type="hidden" value="0" />
281
- <input id="<?= $field['field_id'] ?>"
282
- name="wprss_settings_general[<?= $field['field_id'] ?>]"
283
- type="checkbox"
284
- value="1"
285
- <?= checked(1, $value, false) ?>
286
- />
287
- <?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
 
 
 
 
288
  }
289
 
290
  /**
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
  * @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
  */
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
  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
  /**
includes/feed-blacklist.php CHANGED
@@ -82,13 +82,11 @@ function wprss_is_blacklisted($permalink)
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 = filter_input(INPUT_GET, 'wprss_blacklist', FILTER_VALIDATE_INT);
 
 
 
92
 
93
  // If the post does not exist, stop. Show a message
94
  $post = (is_int($id) && $id > 0)
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)
includes/feed-importing-images.php CHANGED
@@ -464,15 +464,13 @@ function wpra_get_item_enclosure_images($item)
464
  {
465
  $enclosure = $item->get_enclosure();
466
 
467
- // Stop if item has no enclosure
468
- if (is_null($enclosure)) {
469
  return [];
470
  }
471
 
472
  // Get all the thumbnails from the enclosure
473
- $thumbnails = (array) $enclosure->get_thumbnails();
474
-
475
- return $thumbnails;
476
  }
477
 
478
  /**
464
  {
465
  $enclosure = $item->get_enclosure();
466
 
467
+ // Stop if item has no enclosure image
468
+ if (is_null($enclosure) || stripos($enclosure->get_type(), 'image') === false) {
469
  return [];
470
  }
471
 
472
  // Get all the thumbnails from the enclosure
473
+ return (array) $enclosure->get_thumbnails();
 
 
474
  }
475
 
476
  /**
includes/feed-importing.php CHANGED
@@ -71,7 +71,7 @@ function wprss_fetch_insert_single_feed_items( $feed_ID ) {
71
  else $feed_limit = $global_limit;
72
  }
73
 
74
- // Filter the URL for validaty
75
  if ( ! wprss_validate_url( $feed_url ) ) {
76
  $logger->error('Feed URL is not valid!');
77
  } else {
@@ -113,7 +113,8 @@ function wprss_fetch_insert_single_feed_items( $feed_ID ) {
113
  $new_items = array();
114
  foreach ( $items_to_insert as $item ) {
115
  $item_title = $item->get_title();
116
- $permalink = wprss_normalize_permalink( $item->get_permalink(), $item, $feed_ID );
 
117
 
118
  // Check if blacklisted
119
  if (wprss_is_blacklisted($permalink)) {
@@ -260,29 +261,34 @@ function wprss_get_feed_items( $feed_url, $source, $force_feed = FALSE ) {
260
  }
261
 
262
  if (defined('WP_DEBUG') && WP_DEBUG) {
263
- add_action ('cron_request', 'wpse_cron_add_xdebug_cookie', 10) ;
264
  }
265
 
266
  /**
267
- * Allow debugging of wp_cron jobs
268
  *
269
- * @param array $cron_request_array
270
- * @param string $doing_wp_cron
 
 
271
  *
272
  * @return array $cron_request_array with the current XDEBUG_SESSION cookie added if set
273
  */
274
- function wpse_cron_add_xdebug_cookie ($cron_request_array)
275
  {
276
- if (empty ($_COOKIE['XDEBUG_SESSION'])) {
277
- return ($cron_request_array) ;
278
  }
279
 
280
- if (empty ($cron_request_array['args']['cookies'])) {
281
- $cron_request_array['args']['cookies'] = array () ;
 
 
282
  }
283
- $cron_request_array['args']['cookies']['XDEBUG_SESSION'] = $_COOKIE['XDEBUG_SESSION'] ;
284
 
285
- return ($cron_request_array) ;
 
 
286
  }
287
 
288
  /**
@@ -391,7 +397,10 @@ function wprss_fetch_feed($url, $source = null, $param_force_feed = false)
391
  // Convert the feed error into a WP_Error, if applicable
392
  if ($feed->error()) {
393
  if ($source !== null) {
394
- $msg = sprintf(__('Failed to fetch the RSS feed. Error: %s', WPRSS_TEXT_DOMAIN), $feed->error());
 
 
 
395
  update_post_meta($source, 'wprss_error_last_import', $msg);
396
  }
397
  return new WP_Error('simplepie-error', $feed->error(), array('feed' => $feed));
@@ -412,6 +421,7 @@ function wprss_fetch_feed($url, $source = null, $param_force_feed = false)
412
  function wprss_normalize_permalink( $permalink, $item, $feed_ID) {
413
  // Apply normalization functions on the permalink
414
  $permalink = trim( $permalink );
 
415
  $permalink = apply_filters( 'wprss_normalize_permalink', $permalink, $item, $feed_ID);
416
  // Return the normalized permalink
417
  return $permalink;
@@ -572,12 +582,10 @@ function wprss_items_insert_post( $items, $feed_ID ) {
572
 
573
  // Normalize the URL
574
  $permalink = $item->get_permalink(); // Link or enclosure URL
575
- $permalink = htmlspecialchars_decode( $permalink ); // SimplePie encodes HTML special chars
576
 
577
  $logger->debug('Beginning import for item "{0}"', [$item->get_title()]);
578
 
579
- $permalink = wprss_normalize_permalink( $permalink, $item, $feed_ID );
580
-
581
  // Save the enclosure URL
582
  $enclosure_url = '';
583
  $enclosure = $item->get_enclosure(0);
@@ -781,7 +789,7 @@ function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink
781
  update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosureUrl );
782
  update_post_meta( $inserted_ID, 'wprss_item_enclosure_type', $enclosureType );
783
 
784
- if (stripos($enclosureType, 'audio')) {
785
  update_post_meta( $inserted_ID, 'wprss_item_audio', $enclosureUrl );
786
  }
787
  }
@@ -790,18 +798,14 @@ function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink
790
  $feed = $item->get_feed();
791
 
792
  // Get the source from the RSS item
793
- $source = $item->get_source();
794
-
795
  // Get the source name if available. If empty, default to the feed source CPT title
796
- $source_name = ($source === null) ? '' : $source->get_title();
797
- $source_name = empty($source_name) ? $feed->get_title() : $source_name;
798
-
799
  // Get the source URL if available. If empty, default to the RSS feed's URL
800
- $source_url = ($source === null) ? '' : $source->get_permalink();
801
- $source_url = empty($source_url) ? $feed->get_permalink() : $source_url;
802
 
803
- update_post_meta( $inserted_ID, 'wprss_item_source_name', $source_name);
804
- update_post_meta( $inserted_ID, 'wprss_item_source_url', $source_url);
805
 
806
  $author = $item->get_author();
807
  if ($author instanceof SimplePie_Author) {
@@ -814,6 +818,39 @@ function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink
814
  do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
815
  }
816
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
 
818
  /**
819
  * Returns the time limit for the importing of a single feed item.
71
  else $feed_limit = $global_limit;
72
  }
73
 
74
+ // Filter the URL for validity
75
  if ( ! wprss_validate_url( $feed_url ) ) {
76
  $logger->error('Feed URL is not valid!');
77
  } else {
113
  $new_items = array();
114
  foreach ( $items_to_insert as $item ) {
115
  $item_title = $item->get_title();
116
+ $permalink = $item->get_permalink();
117
+ $permalink = wprss_normalize_permalink( $permalink, $item, $feed_ID );
118
 
119
  // Check if blacklisted
120
  if (wprss_is_blacklisted($permalink)) {
261
  }
262
 
263
  if (defined('WP_DEBUG') && WP_DEBUG) {
264
+ add_action('cron_request', 'wprss_cron_add_xdebug_cookie', 10);
265
  }
266
 
267
  /**
268
+ * Allow debugging of wp_cron jobs using xDebug.
269
  *
270
+ * This is done by taking the XDEBUG cookie received from the browser (which enables an xDebug session) and passing it
271
+ * to WP Cron. That way, code initiated from a cron job will be debuggable.
272
+ *
273
+ * @param array $cronRequest
274
  *
275
  * @return array $cron_request_array with the current XDEBUG_SESSION cookie added if set
276
  */
277
+ function wprss_cron_add_xdebug_cookie($cronRequest)
278
  {
279
+ if (empty($_COOKIE['XDEBUG_SESSION'])) {
280
+ return ($cronRequest);
281
  }
282
 
283
+ $cookie = filter_var($_COOKIE['XDEBUG_SESSION'], FILTER_SANITIZE_STRING);
284
+
285
+ if (empty($cronRequest['args']['cookies'])) {
286
+ $cronRequest['args']['cookies'] = [];
287
  }
 
288
 
289
+ $cronRequest['args']['cookies']['XDEBUG_SESSION'] = $cookie;
290
+
291
+ return $cronRequest;
292
  }
293
 
294
  /**
397
  // Convert the feed error into a WP_Error, if applicable
398
  if ($feed->error()) {
399
  if ($source !== null) {
400
+ $msg = sprintf(
401
+ __('Failed to fetch the RSS feed. Error: %s', 'wprss'),
402
+ $feed->error()
403
+ );
404
  update_post_meta($source, 'wprss_error_last_import', $msg);
405
  }
406
  return new WP_Error('simplepie-error', $feed->error(), array('feed' => $feed));
421
  function wprss_normalize_permalink( $permalink, $item, $feed_ID) {
422
  // Apply normalization functions on the permalink
423
  $permalink = trim( $permalink );
424
+ $permalink = htmlspecialchars_decode($permalink);
425
  $permalink = apply_filters( 'wprss_normalize_permalink', $permalink, $item, $feed_ID);
426
  // Return the normalized permalink
427
  return $permalink;
582
 
583
  // Normalize the URL
584
  $permalink = $item->get_permalink(); // Link or enclosure URL
585
+ $permalink = wprss_normalize_permalink( $permalink, $item, $feed_ID );
586
 
587
  $logger->debug('Beginning import for item "{0}"', [$item->get_title()]);
588
 
 
 
589
  // Save the enclosure URL
590
  $enclosure_url = '';
591
  $enclosure = $item->get_enclosure(0);
789
  update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosureUrl );
790
  update_post_meta( $inserted_ID, 'wprss_item_enclosure_type', $enclosureType );
791
 
792
+ if (stripos($enclosureType, 'audio') !== false) {
793
  update_post_meta( $inserted_ID, 'wprss_item_audio', $enclosureUrl );
794
  }
795
  }
798
  $feed = $item->get_feed();
799
 
800
  // Get the source from the RSS item
801
+ $source = wprss_get_item_source_info($item);
 
802
  // Get the source name if available. If empty, default to the feed source CPT title
803
+ $sourceName = empty($source->name) ? $feed->get_title() : $source->name;
 
 
804
  // Get the source URL if available. If empty, default to the RSS feed's URL
805
+ $sourceUrl = empty($source->link) ? $feed->get_permalink() : $source->link;
 
806
 
807
+ update_post_meta( $inserted_ID, 'wprss_item_source_name', $sourceName);
808
+ update_post_meta( $inserted_ID, 'wprss_item_source_url', $sourceUrl);
809
 
810
  $author = $item->get_author();
811
  if ($author instanceof SimplePie_Author) {
818
  do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
819
  }
820
 
821
+ /**
822
+ * Gets the source info from a feed item.
823
+ *
824
+ * @param SimplePie_Item $item
825
+ *
826
+ * @return object An object with 2 properties: 'name' and 'link'.
827
+ */
828
+ function wprss_get_item_source_info(SimplePie_Item $item)
829
+ {
830
+ $source = $item->get_source();
831
+
832
+ if ($source === null) {
833
+ // Attempt to get RSS 2.0 <source>
834
+ $rss2Source = $item->get_item_tags('', 'source');
835
+
836
+ $rss2Source = is_array($rss2Source) ? $rss2Source : [];
837
+ $name = isset($rss2Source[0]['data']) ? $rss2Source[0]['data'] : '';
838
+ $link = isset($rss2Source[0]['attribs']['']['url']) ? $rss2Source[0]['attribs']['']['url'] : '';
839
+
840
+ $source = (object) [
841
+ 'name' => $name,
842
+ 'link' => $link,
843
+ ];
844
+ } else {
845
+ $source = (object) [
846
+ 'name' => $source->get_title(),
847
+ 'link' => $source->get_permalink(),
848
+ ];
849
+ }
850
+
851
+ return $source;
852
+ }
853
+
854
 
855
  /**
856
  * Returns the time limit for the importing of a single feed item.
includes/feed-processing.php CHANGED
@@ -172,16 +172,16 @@
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
 
172
  function wprss_item_title_exists( $title ) {
173
  global $wpdb;
174
 
175
+ $query = $wpdb->prepare(
176
+ "SELECT *
 
177
  FROM `{$wpdb->posts}` AS p
178
  JOIN `{$wpdb->postmeta}` AS q ON p.`ID` = q.`post_id`
179
  WHERE q.`meta_key` = 'wprss_feed_id' AND p.`post_title` = %s",
180
+ [html_entity_decode($title)]
 
181
  );
182
 
183
+ $cols = $wpdb->get_col($query);
184
+
185
  return count($cols) > 0;
186
  }
187
 
includes/feed-states.php CHANGED
@@ -1,122 +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
- }
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
+ }
 
 
 
 
 
 
 
 
includes/legacy-feed-display.php CHANGED
@@ -1,548 +1,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 = wprss_shorten_title($feed_item_title, $ID);
119
- $feed_item_title_link = ( $link_enclosure === 'true' && $enclosure !== '' )? $enclosure : $permalink;
120
-
121
- // Prepare the text that precedes the source
122
- $text_preceding_source = wprss_get_general_setting('text_preceding_source');
123
- $text_preceding_source = ltrim( __( $text_preceding_source, WPRSS_TEXT_DOMAIN ) . ' ' );
124
-
125
- $text_preceding_date = wprss_get_general_setting('text_preceding_date');
126
- $text_preceding_date = ltrim( __( $text_preceding_date, WPRSS_TEXT_DOMAIN ) . ' ' );
127
-
128
- do_action( 'wprss_get_post_data' );
129
-
130
- $meta = $extra_options;
131
- $extra_meta = apply_filters( 'wprss_template_extra_meta', $meta, $args, $ID );
132
-
133
- ///////////////////////////////////////////////////////////////
134
- // BEGIN TEMPLATE
135
-
136
- // Prepare the output
137
- $output = '';
138
- // Begin output buffering
139
- ob_start();
140
- // Print the links before
141
- echo $link_before;
142
-
143
- // The Title
144
- $item_title = wprss_link_display( $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link') );
145
- $item_title = apply_filters('wprss_item_title', $item_title, $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link'));
146
- echo $item_title;
147
-
148
- do_action( 'wprss_after_feed_item_title', $extra_meta, $display_settings, $ID );
149
-
150
- // FEED ITEM META
151
- echo '<div class="wprss-feed-meta">';
152
-
153
- // SOURCE
154
- if ( wprss_get_general_setting('source_enable') == 1 ) {
155
- echo '<span class="feed-source">';
156
- $source_link_text = apply_filters('wprss_item_source_link', wprss_link_display( $source_url, $source_name, $source_link ) );
157
- $source_link_text = $text_preceding_source . $source_link_text;
158
- echo $source_link_text;
159
- echo '</span>';
160
- }
161
 
162
- // DATE
163
- if ( wprss_get_general_setting('date_enable') == 1 ) {
164
- echo '<span class="feed-date">';
165
- $date_text = apply_filters( 'wprss_item_date', $date );
166
- $date_text = $text_preceding_date . $date_text;
167
- echo $date_text;
168
- echo '</span>';
169
- }
170
 
171
- // AUTHOR
172
- $author = get_post_meta( $ID, 'wprss_item_author', TRUE );
173
- if ( wprss_get_general_setting('authors_enable') == 1 && $author !== NULL && is_string( $author ) && $author !== '' ) {
174
- echo '<span class="feed-author">';
175
- $author_text = apply_filters( 'wprss_item_author', $author );
176
- $author_prefix_text = apply_filters( 'wprss_author_prefix_text', 'By' );
177
- _e( $author_prefix_text, WPRSS_TEXT_DOMAIN );
178
- echo ' ' . $author_text;
179
- echo '</span>';
180
- }
181
 
182
- echo '</div>';
183
 
184
- // TIME AGO
185
- if ( wprss_get_general_setting('date_enable') == 1 && wprss_get_general_setting('time_ago_format_enable') == 1 ) {
186
- $time_ago = human_time_diff( $timestamp, time() );
187
- echo '<div class="wprss-time-ago">';
188
- $time_ago_text = apply_filters( 'wprss_item_time_ago', $time_ago );
189
- printf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), $time_ago_text );
190
- echo '</div>';
191
- }
192
 
193
- // END TEMPLATE - Retrieve buffered output
194
- $output .= ob_get_clean();
195
- $output = apply_filters( 'wprss_single_feed_output', $output, $permalink );
196
- $output .= "$link_after";
197
 
198
- // Print the output
199
- return $output;
200
- }
 
 
 
201
 
 
 
 
 
202
 
203
- /**
204
- * Retrieve settings and prepare them for use in the display function
205
- *
206
- * @since 3.0
207
- */
208
- function wprss_get_display_settings( $settings = NULL ) {
209
- if ( $settings === NULL ) {
210
- $settings = get_option( 'wprss_settings_general' );
211
- }
212
- // Parse the arguments together with their default values
213
- $args = wp_parse_args(
214
- $settings,
215
- array(
216
- 'open_dd' => 'blank',
217
- 'follow_dd' => '',
218
- )
219
- );
220
 
221
- // Prepare the 'open' setting - how to open links for feed items
222
- $open = '';
223
- switch ( $args['open_dd'] ) {
224
- case 'lightbox' :
225
- $open = 'class="colorbox"';
226
- break;
227
- case 'blank' :
228
- $open = 'target="_blank"';
229
- break;
230
- }
 
231
 
232
- // Prepare the 'follow' setting - whether links marked as nofollow or not
233
- $follow = ( $args['follow_dd'] == 'no_follow' )? 'rel="nofollow"' : '';
 
 
 
 
 
 
234
 
235
- // Prepare the final settings array
236
- $display_settings = array(
237
- 'open' => $open,
238
- 'follow' => $follow
 
 
 
 
239
  );
 
 
 
240
 
241
- do_action( 'wprss_get_settings' );
242
 
243
- return $display_settings;
 
 
 
 
 
 
244
  }
245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
- /**
248
- * Merges the default arguments with the user set arguments
249
- *
250
- * @since 3.0
251
- */
252
- function wprss_get_shortcode_default_args( $args ) {
253
- // Default shortcode/function arguments for displaying feed items
254
- $shortcode_args = apply_filters(
255
- 'wprss_shortcode_args',
256
- array(
257
- 'links_before' => '<ul class="rss-aggregator">',
258
- 'links_after' => '</ul>',
259
- 'link_before' => '<li class="feed-item">',
260
- 'link_after' => '</li>'
261
- )
262
- );
263
-
264
- // Parse incoming $args into an array and merge it with $shortcode_args
265
- $args = wp_parse_args( $args, $shortcode_args );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
- return $args;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  }
269
 
 
 
 
270
 
271
- /**
272
- * Prepares and builds the query for fetching the feed items
273
- *
274
- * @since 3.0
275
- */
276
- function wprss_get_feed_items_query( $settings ) {
277
- if( isset( $settings['feed_limit'] ) ) {
278
- $posts_per_page = $settings['feed_limit'];
279
- } else {
280
- $posts_per_page = wprss_get_general_setting('feed_limit');
281
- }
282
- global $paged;
283
- if ( get_query_var('paged') ) {
284
- $paged = get_query_var('paged');
285
- } elseif ( get_query_var('page') ) {
286
- $paged = get_query_var('page');
287
- } else {
288
- $paged = 1;
289
  }
290
-
291
- $feed_items_args = array(
292
- 'post_type' => get_post_types(),
293
- 'posts_per_page' => $posts_per_page,
294
- 'orderby' => 'date',
295
- 'order' => 'DESC',
296
- 'paged' => $paged,
297
- 'suppress_filters' => true,
298
- 'ignore_sticky_posts' => true,
299
- 'meta_query' => array(
300
- 'relation' => 'AND',
301
- array(
302
  'key' => 'wprss_feed_id',
303
- 'compare' => 'EXISTS',
304
- )
305
- )
306
- );
307
-
308
- if ( isset($settings['pagination']) ) {
309
- $pagination = strtolower( $settings['pagination'] );
310
- if ( in_array( $pagination, array('false','off','0') ) ) {
311
- unset( $feed_items_args['paged'] );
312
- }
313
  }
 
314
 
315
- if ( isset( $settings['no-paged'] ) && $settings['no-paged'] === TRUE ) {
316
- unset( $feed_items_args['no-paged'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  }
318
 
319
- // If either the source or exclude arguments are set (but not both), prepare a meta query
320
- if ( isset( $settings['source'] ) xor isset( $settings['exclude'] ) ) {
321
- // Set the appropriate setting and operator
322
- $setting = 'source';
323
- $operator = 'IN';
324
- if ( isset( $settings['exclude'] ) ) {
325
- $setting = 'exclude';
326
- $operator = 'NOT IN';
327
- }
328
- $feeds = array_filter( array_map( 'intval', explode( ',', $settings[$setting] ) ) );
329
- foreach ( $feeds as $feed )
330
- trim( $feed );
331
- if ( !empty( $feeds ) ) {
332
- $feed_items_args['meta_query'] = array(
333
- array(
334
- 'key' => 'wprss_feed_id',
335
- 'value' => $feeds,
336
- 'type' => 'numeric',
337
- 'compare' => $operator,
338
- ),
339
- );
340
- }
341
- }
342
-
343
- // Arguments for the next query to fetch all feed items
344
- $feed_items_args = apply_filters( 'wprss_display_feed_items_query', $feed_items_args, $settings );
345
-
346
- // Query to get all feed items for display
347
- $feed_items = new WP_Query( $feed_items_args );
348
-
349
- if ( isset( $settings['get-args'] ) && $settings['get-args'] === TRUE ) {
350
- return $feed_items_args;
351
- } else return $feed_items;
352
- }
353
-
354
 
355
- add_action( 'wprss_display_template', 'wprss_default_display_template', 10, 3 );
356
- /**
357
- * Default template for feed items display
358
- *
359
- * @since 3.0
360
- * @param $args array The shortcode arguments
361
- * @param $feed_items WP_Query The feed items to display
362
- */
363
- function wprss_default_display_template( $args, $feed_items ) {
364
- global $wp_query;
365
- global $paged;
366
-
367
- // Swap the current WordPress Query with our own
368
- $old_wp_query = $wp_query;
369
- $wp_query = $feed_items;
370
-
371
- // Prepare the output
372
- $output = '';
373
-
374
- // Check if our current query returned any feed items
375
- if ( $feed_items->have_posts() ) {
376
- // PRINT LINKS BEFORE LIST OF FEED ITEMS
377
- $output .= $args['links_before'];
378
-
379
- // FOR EACH ITEM
380
- while ( $feed_items->have_posts() ) {
381
- // Get the item
382
- $feed_items->the_post();
383
- // Add the output
384
- $output .= wprss_render_feed_item( NULL, '', $args );
385
- }
386
-
387
- // OUTPUT LINKS AFTER LIST OF FEED ITEMS
388
- $output .= $args['links_after'];
389
-
390
- // Add pagination if needed
391
- if ( !isset( $args['pagination'] ) || !in_array( $args['pagination'], array('off','false','0',0) ) ) {
392
- $output = apply_filters( 'wprss_pagination', $output );
393
- }
394
-
395
- // Filter the final output, and print it
396
- echo apply_filters( 'feed_output', $output );
397
- } else {
398
- // No items found message
399
- echo apply_filters( 'no_feed_items_found', __( 'No feed items found.', WPRSS_TEXT_DOMAIN ) );
400
  }
401
 
402
- // Reset the WordPress query
403
- $wp_query = $old_wp_query;
404
- wp_reset_postdata();
 
 
405
  }
406
 
407
-
408
- /**
409
- * Generates an HTML link, using the saved display settings.
410
- *
411
- * @param string $link The link URL
412
- * @param string $text The link text to display
413
- * @param string $bool Optional boolean. If FALSE, the text is returned unlinked. Default: TRUE.
414
- * @return string The generated link
415
- * @since 4.2.4
416
- */
417
- function wprss_link_display( $link, $text, $bool = TRUE ) {
418
- $display_settings = wprss_get_display_settings( get_option( 'wprss_settings_general' ) );
419
- $a = $bool ? "<a {$display_settings['open']} {$display_settings['follow']} href='$link'>$text</a>" : $text;
420
- return $a;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
422
 
423
-
424
- add_filter( 'wprss_pagination', 'wprss_pagination_links' );
425
- /**
426
- * Display pagination links
427
- *
428
- * @since 3.5
429
- */
430
- function wprss_pagination_links( $output ) {
431
- // Get the general setting
432
- $pagination = wprss_get_general_setting( 'pagination' );;
433
-
434
- // Check the pagination setting, if using page numbers
435
- if ( $pagination === 'numbered' ) {
436
- global $wp_query;
437
- $big = 999999999; // need an unlikely integer
438
- $output .= paginate_links( array(
439
- 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
440
- 'format' => '?paged=%#%',
441
- 'current' => max( 1, get_query_var('paged') ),
442
- 'total' => $wp_query->max_num_pages
443
- ) );
444
- return $output;
445
- }
446
- // Otherwise, using default paginations
447
- else {
448
- $output .= '<div class="nav-links">';
449
- $output .= ' <div class="nav-previous alignleft">' . get_next_posts_link( __( 'Older posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
450
- $output .= ' <div class="nav-next alignright">' . get_previous_posts_link( __( 'Newer posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
451
- $output .= '</div>';
452
- return $output;
453
- }
454
  }
455
-
456
-
457
- /**
458
- * Checks the title limit option and shortens the title when necessary.
459
- *
460
- * @since 1.0
461
- *
462
- * @param string $title The title of tge feed item.
463
- * @param int|string|null $id The ID of the feed item.
464
- *
465
- * @return string
466
- */
467
- function wprss_shorten_title( $title, $id = null ) {
468
- if (isset($id) && get_post_type($id) === 'wprss_feed_item') {
469
- $settings = get_option('wprss_settings_general');
470
- $limit = isset($settings['title_limit'])
471
- ? intval($settings['title_limit'])
472
- : 0;
473
-
474
- if ($limit > 0 && strlen($title) > $limit) {
475
- $suffix = apply_filters('wprss_shortened_title_ending', '...');
476
- $title = substr($title, 0, $limit) . $suffix;
477
- }
478
  }
479
-
480
- return $title;
481
  }
482
 
483
-
484
- /**
485
- * Display feed items on the front end (via shortcode or function)
486
- *
487
- * @since 2.0
488
- */
489
- function wprss_display_feed_items( $args = array() ) {
490
- $settings = get_option( 'wprss_settings_general' );
491
- $args = wprss_get_shortcode_default_args( $args );
492
-
493
- $args = apply_filters( 'wprss_shortcode_args', $args );
494
-
495
- $query_args = $settings;
496
- if ( isset( $args['limit'] ) ) {
497
- $query_args['feed_limit'] = filter_var( $args['limit'], FILTER_VALIDATE_INT, array(
498
- 'options' => array(
499
- 'min_range' => 1,
500
- 'default' => $query_args['feed_limit'],
501
- ),
502
- ) );
503
- }
504
-
505
- if ( isset( $args['pagination'] ) ) {
506
- $query_args['pagination'] = $args['pagination'];
507
- }
508
-
509
- if ( isset( $args['source'] ) ) {
510
- $query_args['source'] = $args['source'];
511
- }
512
- elseif ( isset( $args['exclude'] ) ) {
513
- $query_args['exclude'] = $args['exclude'];
514
- }
515
-
516
- $query_args = apply_filters( 'wprss_process_shortcode_args', $query_args, $args );
517
-
518
- $feed_items = wprss_get_feed_items_query( $query_args );
519
-
520
- do_action( 'wprss_display_template', $args, $feed_items );
521
  }
522
 
 
 
 
523
 
524
- /**
525
- * Limits a phrase/content to a defined number of words
526
- *
527
- * NOT BEING USED as we're using the native WP function, although the native one strips tags, so I'll
528
- * probably revisit this one again soon.
529
- *
530
- * @since 3.0
531
- * @param string $words
532
- * @param integer $limit
533
- * @param string $append
534
- * @return string
535
- */
536
- function wprss_limit_words( $words, $limit, $append = '' ) {
537
- /* Add 1 to the specified limit becuase arrays start at 0 */
538
- $limit = $limit + 1;
539
- /* Store each individual word as an array element
540
- up to the limit */
541
- $words = explode( ' ', $words, $limit );
542
- /* Shorten the array by 1 because that final element will be the sum of all the words after the limit */
543
- array_pop( $words );
544
- /* Implode the array for output, and append an ellipse */
545
- $words = implode( ' ', $words ) . $append;
546
- /* Return the result */
547
- return rtrim( $words );
548
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
includes/opml-importer.php CHANGED
@@ -59,22 +59,21 @@
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,8 +92,8 @@
93
  }
94
  break;
95
  }
96
-
97
- ?></div><?php
98
  }
99
 
100
 
@@ -104,18 +103,26 @@
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,16 +191,16 @@
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,9 +229,9 @@
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,7 +240,7 @@
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,8 +261,8 @@
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
 
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
  }
93
  break;
94
  }
95
+
96
+ echo '</div>';
97
  }
98
 
99
 
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
  $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
 
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
 
241
  } catch (Exception $e) {
242
  // Show Error Message
243
+ ?><div class="error"><?php echo wpautop( __( $e->getMessage(), 'wprss' ) ) ?></div><?php
244
  }
245
  }
246
 
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
 
includes/scripts.php CHANGED
@@ -1,258 +1,266 @@
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' => trailingslashit(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
-
120
- // On all admin screens
121
- wp_enqueue_style( 'wprss-admin-editor-styles' );
122
- wp_enqueue_style( 'wprss-admin-tracking-styles' );
123
- wp_enqueue_style( 'wprss-admin-general-styles' );
124
-
125
- // Only on WPRA-related admin screens
126
- if ($isWpraScreen) {
127
- wprss_admin_exclusive_scripts_styles();
128
- }
129
-
130
- do_action( 'wprss_admin_scripts_styles' );
131
- } // end wprss_admin_scripts_styles
132
-
133
- /**
134
- * Enqueues backend scripts on WPRA-related pages only
135
- *
136
- * @since 4.10
137
- */
138
- function wprss_admin_exclusive_scripts_styles()
139
- {
140
- $screen = get_current_screen();
141
- $pageBase = $screen->base;
142
- $postType = $screen->post_type;
143
-
144
- wp_enqueue_style( 'wprss-admin-styles' );
145
- wp_enqueue_style( 'wprss-fa' );
146
- wp_enqueue_style( 'wprss-admin-3.8-styles' );
147
-
148
- wp_enqueue_script( 'wprss-xdn-class' );
149
- wp_enqueue_script( 'wprss-xdn-lib' );
150
- wp_enqueue_script( 'aventura' );
151
-
152
- wp_enqueue_script( 'wprss-admin-addon-ajax' );
153
-
154
- wp_enqueue_script( 'wprss-admin-custom' );
155
-
156
- wp_enqueue_script( 'jquery-ui-timepicker-addon' );
157
- wp_enqueue_style( 'jquery-style' );
158
-
159
- if ($pageBase === 'post' && $postType = 'wprss_feed') {
160
- // Change text on post screen from 'Enter title here' to 'Enter feed name here'
161
- add_filter( 'enter_title_here', 'wprss_change_title_text' );
162
- wp_enqueue_media();
163
- wp_enqueue_script( 'wprss-gallery-js' );
164
- }
165
- if ('wprss_feed' === $postType) {
166
- wp_enqueue_script( 'wprss-custom-bulk-actions' );
167
- }
168
- if ('wprss_feed_item' === $postType) {
169
- wp_enqueue_script( 'wprss-custom-bulk-actions-feed-item' );
170
- }
171
-
172
- // Load Heartbeat script and set dependancy for Heartbeat to ensure Heartbeat is loaded
173
- if ($pageBase === 'edit' && $postType === 'wprss_feed' && apply_filters('wprss_ajax_polling', TRUE) === TRUE ) {
174
- wp_enqueue_script( 'wprss-feed-source-table-heartbeat' );
175
- }
176
-
177
- if ($pageBase === 'wprss_feed_page_wprss-aggregator-settings') {
178
- wp_enqueue_script( 'wprss-admin-license-manager' );
179
- wp_enqueue_script( 'wprss-admin-licensing' );
180
- }
181
-
182
- if ($pageBase === 'wprss_feed_page_wprss-help') {
183
- wp_enqueue_script( 'wprss-admin-help' );
184
- }
185
-
186
- if ($pageBase === 'wprss_feed_page_wpra_tools') {
187
- wp_enqueue_script('wpra-tools');
188
- wp_enqueue_script('wpra-logs-tool');
189
- wp_enqueue_script('wpra-blacklist-tool');
190
- wp_enqueue_script('wpra-crons-tool');
191
- wp_enqueue_script('wpra-reset-tool');
192
- }
193
-
194
- if (wprss_is_help_beacon_enabled()) {
195
- wp_enqueue_script('wprss-hs-beacon-js');
196
- wp_enqueue_style('wprss-hs-beacon-css');
197
- }
198
-
199
- do_action('wprss_admin_exclusive_scripts_styles');
200
- }
201
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
- add_action( 'wp_enqueue_scripts', 'wprss_load_scripts' );
204
- /**
205
- * Enqueues the required scripts.
206
- *
207
- * @since 3.0
208
- */
209
- function wprss_load_scripts() {
210
- /* wp_enqueue_script( 'jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', array( 'jquery' ) );
211
- wp_enqueue_script( 'custom', WPRSS_JS . 'custom.js', array( 'jquery', 'jquery.colorbox-min' ) ); */
212
- do_action( 'wprss_register_scripts' );
213
- } // end wprss_head_scripts_styles
214
-
215
-
216
- /**
217
- * Returns the path to the WPRSS templates directory
218
- *
219
- * @since 3.0
220
- * @return string
221
- */
222
- function wprss_get_templates_dir() {
223
- return WPRSS_DIR . 'templates';
224
  }
225
 
 
 
 
 
226
 
227
- /**
228
- * Returns the URL to the WPRSS templates directory
229
- *
230
- * @since 3.0
231
- * @return string
232
- */
233
- function wprss_get_templates_uri() {
234
- return WPRSS_URI . 'templates';
235
  }
236
 
 
 
 
 
 
 
 
237
 
238
- add_action( 'init', 'wprss_register_styles' );
239
- /**
240
- * Registers all WPRA styles.
241
- *
242
- * Does not enqueue anything.
243
- *
244
- * @since 3.0
245
- */
246
- function wprss_register_styles()
247
- {
248
- $version = wprss()->getVersion();
249
-
250
- wp_register_style( 'wprss-admin-styles', WPRSS_CSS . 'admin-styles.css', array(), $version );
251
- wp_register_style( 'wprss-fa', WPRSS_CSS . 'font-awesome.min.css', array(), $version );
252
- wp_register_style( 'wprss-admin-3.8-styles', WPRSS_CSS . 'admin-3.8.css', array(), $version );
253
- wp_register_style( 'wprss-admin-editor-styles', WPRSS_CSS . 'admin-editor.css', array(), $version );
254
- wp_register_style( 'wprss-admin-tracking-styles', WPRSS_CSS . 'admin-tracking-styles.css', array(), $version );
255
- wp_register_style( 'wprss-admin-general-styles', WPRSS_CSS . 'admin-general-styles.css', array(), $version );
256
- wp_register_style( 'wprss-hs-beacon-css', WPRSS_CSS . 'beacon.css', array(), $version );
257
- wp_register_style( 'jquery-style', WPRSS_CSS . 'jquery-ui-smoothness.css', array(), $version );
258
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ]);
22
+
23
+ // Prepare the URL for removing bulk from blacklist, with a nonce
24
+ $blacklist_remove_url = admin_url('edit.php?wprss-bulk=1');
25
+ $blacklist_remove_url = wp_nonce_url($blacklist_remove_url, 'blacklist-remove-selected', 'wprss_blacklist_trash');
26
+ $blacklist_remove_url .= '&wprss-blacklist-remove=';
27
+ wp_register_script('wprss-admin-custom', WPRSS_JS . 'admin-custom.js',
28
+ ['jquery', 'jquery-ui-datepicker', 'jquery-ui-slider'], $version);
29
+ wp_localize_script('wprss-admin-custom', 'wprss_admin_custom', [
30
+ 'failed_to_import' => __('Failed to import', 'wprss'),
31
+ 'items_are_importing' => __('Importing!', 'wprss'),
32
+ 'items_are_deleting' => __('Deleting!', 'wprss'),
33
+ 'please_wait' => __('Please wait ...', 'wprss'),
34
+ 'bulk_add' => __('Bulk Add', 'wprss'),
35
+ 'ok' => __('OK', 'wprss'),
36
+ 'cancel' => __('Cancel', 'wprss'),
37
+ 'blacklist_desc' => __('The feed items listed here will be disregarded when importing new items from your feed sources.',
38
+ 'wprss'),
39
+ 'blacklist_remove' => __('Remove selected from Blacklist', 'wprss'),
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', [
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',
48
+ ['jquery', 'jquery-ui-datepicker'], $version);
49
+ wp_register_script('wprss-custom-bulk-actions', WPRSS_JS . 'admin-custom-bulk-actions.js', ['jquery'], $version);
50
+ wp_localize_script('wprss-custom-bulk-actions', 'wprss_admin_bulk', [
51
+ 'activate' => __('Activate', 'wprss'),
52
+ 'pause' => __('Pause', 'wprss'),
53
+ ]);
54
+
55
+ wp_register_script('wprss-feed-source-table-heartbeat', WPRSS_JS . 'heartbeat.js', [], $version);
56
+ wp_localize_script('wprss-feed-source-table-heartbeat', 'wprss_admin_heartbeat', [
57
+ 'ago' => __('ago', 'wprss'),
58
+ ]);
59
+ wp_register_script('wprss-admin-license-manager', WPRSS_JS . 'admin-license-manager.js', [], $version);
60
+
61
+ wp_register_script('wprss-admin-licensing', WPRSS_JS . 'admin-licensing.js', [], $version);
62
+ wp_localize_script('wprss-admin-licensing', 'wprss_admin_licensing', [
63
+ 'activating' => __('Activating...', 'wprss'),
64
+ 'deactivating' => __('Deactivating...', 'wprss'),
65
+ ]);
66
+
67
+ wp_register_script('wprss-admin-help', WPRSS_JS . 'admin-help.js', [], $version);
68
+ wp_localize_script('wprss-admin-help', 'wprss_admin_help', [
69
+ 'sending' => __('Sending...', 'wprss'),
70
+ 'sent-error' => sprintf(
71
+ __(
72
+ 'There was an error sending the form. Please use the <a href="%s">contact form on our site.</a>',
73
+ 'wprss'
74
+ ),
75
+ esc_attr('https://www.wprssaggregator.com/contact/')
76
+ ),
77
+ 'sent-ok' => __(
78
+ 'Your message has been sent and we\'ll send you a confirmation e-mail when we receive it.',
79
+ 'wprss'
80
+ ),
81
+ ]);
82
+
83
+ wp_register_script('wprss-hs-beacon-js', WPRSS_JS . 'beacon.min.js', [], $version);
84
+ wp_localize_script('wprss-hs-beacon-js', 'WprssHelpBeaconConfig', [
85
+ 'premiumSupport' => (wprss_licensing_get_manager()->licenseWithStatusExists(License_Status::VALID)),
86
+ ]);
87
+
88
+ wp_register_script('wprss-gallery-js', WPRSS_JS . 'gallery.js', ['jquery'], $version, true);
89
+
90
+ wp_register_script('wpra-tools', WPRSS_JS . 'admin/tools/main.js', ['jquery'], $version, true);
91
+ wp_register_script('wpra-logs-tool', WPRSS_JS . 'admin/tools/logs.js', ['jquery'], $version, true);
92
+ wp_register_script('wpra-blacklist-tool', WPRSS_JS . 'admin/tools/blacklist.js', ['jquery'], $version, true);
93
+
94
+ $wpSchedules = wp_get_schedules();
95
+ $globSchedule = wprss_get_general_setting('cron_interval');
96
+ $customSchedule = [
97
+ 'display' => __('Use Global Cron', 'wprss'),
98
+ 'interval' => $wpSchedules[$globSchedule]['interval'],
99
+ ];
100
+ $schedules = array_merge(['global' => $customSchedule], $wpSchedules);
101
+
102
+ wp_register_script('wpra-crons-tool', WPRSS_JS . 'admin/tools/crons.js', ['jquery'], $version, true);
103
+ wp_localize_script('wpra-crons-tool', 'WpraCronsTool', [
104
+ 'restUrl' => trailingslashit(rest_url()),
105
+ 'restApiNonce' => wp_create_nonce('wp_rest'),
106
+ 'globalInterval' => $globSchedule,
107
+ 'globalTime' => wprss_get_global_update_time(),
108
+ 'globalWord' => __('Global', 'wprss'),
109
+ 'perPage' => 30,
110
+ 'schedules' => $schedules,
111
+ ]);
112
+
113
+ wp_register_script('wpra-reset-tool', WPRSS_JS . 'admin/tools/reset.js', ['jquery'], $version, true);
114
+ wp_localize_script('wpra-reset-tool', 'WpraResetTool', [
115
+ 'message' => __('Are you sure you want to do this? This operation cannot be undone.', 'wprss'),
116
+ ]);
117
+ }, 9);
118
+
119
+ add_action('admin_enqueue_scripts', 'wprss_admin_scripts_styles');
120
+ /**
121
+ * Insert required scripts, styles and filters on the admin side
122
+ *
123
+ * @since 2.0
124
+ */
125
+ function wprss_admin_scripts_styles()
126
+ {
127
+ $isWpraScreen = wprss_is_wprss_page();
128
+
129
+ // On all admin screens
130
+ wp_enqueue_style('wprss-admin-editor-styles');
131
+ wp_enqueue_style('wprss-admin-tracking-styles');
132
+ wp_enqueue_style('wprss-admin-general-styles');
133
+
134
+ // Only on WPRA-related admin screens
135
+ if ($isWpraScreen) {
136
+ wprss_admin_exclusive_scripts_styles();
137
  }
138
 
139
+ do_action('wprss_admin_scripts_styles');
140
+ } // end wprss_admin_scripts_styles
141
 
142
+ /**
143
+ * Enqueues backend scripts on WPRA-related pages only
144
+ *
145
+ * @since 4.10
146
+ */
147
+ function wprss_admin_exclusive_scripts_styles()
148
+ {
149
+ $screen = get_current_screen();
150
+ $pageBase = $screen->base;
151
+ $postType = $screen->post_type;
152
+
153
+ wp_enqueue_style('wprss-admin-styles');
154
+ wp_enqueue_style('wprss-fa');
155
+ wp_enqueue_style('wprss-admin-3.8-styles');
156
+
157
+ wp_enqueue_script('wprss-xdn-class');
158
+ wp_enqueue_script('wprss-xdn-lib');
159
+ wp_enqueue_script('aventura');
160
+
161
+ wp_enqueue_script('wprss-admin-addon-ajax');
162
+
163
+ wp_enqueue_script('wprss-admin-custom');
164
+
165
+ wp_enqueue_script('jquery-ui-timepicker-addon');
166
+ wp_enqueue_style('jquery-style');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
+ if ($pageBase === 'post' && $postType = 'wprss_feed') {
169
+ // Change text on post screen from 'Enter title here' to 'Enter feed name here'
170
+ add_filter('enter_title_here', 'wprss_change_title_text');
171
+ wp_enqueue_media();
172
+ wp_enqueue_script('wprss-gallery-js');
173
+ }
174
+ if ('wprss_feed' === $postType) {
175
+ wp_enqueue_script('wprss-custom-bulk-actions');
176
+ }
177
+ if ('wprss_feed_item' === $postType) {
178
+ wp_enqueue_script('wprss-custom-bulk-actions-feed-item');
179
+ }
180
 
181
+ // Load Heartbeat script and set dependancy for Heartbeat to ensure Heartbeat is loaded
182
+ if ($pageBase === 'edit' && $postType === 'wprss_feed' && apply_filters('wprss_ajax_polling', true) === true) {
183
+ wp_enqueue_script('wprss-feed-source-table-heartbeat');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
185
 
186
+ if ($pageBase === 'wprss_feed_page_wprss-aggregator-settings') {
187
+ wp_enqueue_script('wprss-admin-license-manager');
188
+ wp_enqueue_script('wprss-admin-licensing');
189
+ }
190
 
191
+ if ($pageBase === 'wprss_feed_page_wprss-help') {
192
+ wp_enqueue_script('wprss-admin-help');
 
 
 
 
 
 
193
  }
194
 
195
+ if ($pageBase === 'wprss_feed_page_wpra_tools') {
196
+ wp_enqueue_script('wpra-tools');
197
+ wp_enqueue_script('wpra-logs-tool');
198
+ wp_enqueue_script('wpra-blacklist-tool');
199
+ wp_enqueue_script('wpra-crons-tool');
200
+ wp_enqueue_script('wpra-reset-tool');
201
+ }
202
 
203
+ if (wprss_is_help_beacon_enabled()) {
204
+ wp_enqueue_script('wprss-hs-beacon-js');
205
+ wp_enqueue_style('wprss-hs-beacon-css');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  }
207
+
208
+ do_action('wprss_admin_exclusive_scripts_styles');
209
+ }
210
+
211
+ add_action('wp_enqueue_scripts', 'wprss_load_scripts');
212
+ /**
213
+ * Enqueues the required scripts.
214
+ *
215
+ * @since 3.0
216
+ */
217
+ function wprss_load_scripts()
218
+ {
219
+ /* wp_enqueue_script( 'jquery.colorbox-min', WPRSS_JS . 'jquery.colorbox-min.js', array( 'jquery' ) );
220
+ wp_enqueue_script( 'custom', WPRSS_JS . 'custom.js', array( 'jquery', 'jquery.colorbox-min' ) ); */
221
+ do_action('wprss_register_scripts');
222
+ } // end wprss_head_scripts_styles
223
+
224
+ /**
225
+ * Returns the path to the WPRSS templates directory
226
+ *
227
+ * @since 3.0
228
+ * @return string
229
+ */
230
+ function wprss_get_templates_dir()
231
+ {
232
+ return WPRSS_DIR . 'templates';
233
+ }
234
+
235
+ /**
236
+ * Returns the URL to the WPRSS templates directory
237
+ *
238
+ * @since 3.0
239
+ * @return string
240
+ */
241
+ function wprss_get_templates_uri()
242
+ {
243
+ return WPRSS_URI . 'templates';
244
+ }
245
+
246
+ add_action('init', 'wprss_register_styles');
247
+ /**
248
+ * Registers all WPRA styles.
249
+ *
250
+ * Does not enqueue anything.
251
+ *
252
+ * @since 3.0
253
+ */
254
+ function wprss_register_styles()
255
+ {
256
+ $version = wprss()->getVersion();
257
+
258
+ wp_register_style('wprss-admin-styles', WPRSS_CSS . 'admin-styles.css', [], $version);
259
+ wp_register_style('wprss-fa', WPRSS_CSS . 'font-awesome.min.css', [], $version);
260
+ wp_register_style('wprss-admin-3.8-styles', WPRSS_CSS . 'admin-3.8.css', [], $version);
261
+ wp_register_style('wprss-admin-editor-styles', WPRSS_CSS . 'admin-editor.css', [], $version);
262
+ wp_register_style('wprss-admin-tracking-styles', WPRSS_CSS . 'admin-tracking-styles.css', [], $version);
263
+ wp_register_style('wprss-admin-general-styles', WPRSS_CSS . 'admin-general-styles.css', [], $version);
264
+ wp_register_style('wprss-hs-beacon-css', WPRSS_CSS . 'beacon.css', [], $version);
265
+ wp_register_style('jquery-style', WPRSS_CSS . 'jquery-ui-smoothness.css', [], $version);
266
+ }
includes/system-info.php CHANGED
@@ -61,7 +61,7 @@ MySQL Version: <?php $server_info = wprss_sysinfo_get_db_server();
61
  );
62
  }
63
  } else {
64
- _e( 'Could not determine database driver version', WPRSS_TEXT_DOMAIN );
65
  }
66
  ?>
67
 
@@ -103,7 +103,7 @@ 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_TEXT_DOMAIN ) : __( 'Your server does not support fsockopen.', WPRSS_TEXT_DOMAIN ); ?><?php echo "\n"; ?>
107
 
108
  PLUGIN MODULES:
109
 
61
  );
62
  }
63
  } else {
64
+ _e( 'Could not determine database driver version', 'wprss' );
65
  }
66
  ?>
67
 
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
 
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_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,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_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
 
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
  // 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
 
js/pointers.js DELETED
@@ -1,15 +0,0 @@
1
- function wprssTrackingOptAJAX( opted ) {
2
- jQuery.ajax({
3
- url: ajaxurl,
4
- type: 'POST',
5
- data: {
6
- action: 'wprss_tracking_ajax_opt',
7
- opted: opted
8
- },
9
- success: function( data, t, f ) {
10
- console.log( data );
11
- console.log( t );
12
- console.log( f );
13
- }
14
- });
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: RSS import, RSS aggregator, autoblog, feed to post, news aggregator, rss t
5
  Requires at least: 4.0 or higher
6
  Tested up to: 5.8
7
  Requires PHP: 5.4
8
- Stable tag: 4.19.1
9
  License: GPLv3
10
 
11
  The most powerful and reliable RSS aggregator for WordPress. Build a news aggregator, autoblog and more in minutes with unlimited RSS feeds.
@@ -254,6 +254,22 @@ Our complete Knowledge Base with FAQs can be found [here](https://kb.wprssaggreg
254
 
255
  == Changelog ==
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  = 4.19.1 (2021-09-14)
258
  **Changed**
259
  - More details are now logged when a fatal error occurs during an import.
5
  Requires at least: 4.0 or higher
6
  Tested up to: 5.8
7
  Requires PHP: 5.4
8
+ Stable tag: 4.19.2
9
  License: GPLv3
10
 
11
  The most powerful and reliable RSS aggregator for WordPress. Build a news aggregator, autoblog and more in minutes with unlimited RSS feeds.
254
 
255
  == Changelog ==
256
 
257
+ = 4.19.2 (2021-10-28)
258
+ **Changed**
259
+ - Cleaned up the code significantly.
260
+ - Consistent permalink normalization between the preview and importing.
261
+ - Some plugin strings were not internationalized.
262
+ - Source information is extracted from feed items more reliably.
263
+ - Audio links in feed items are detected more reliably.
264
+ - Enclosure images in feed items are detected more reliably.
265
+
266
+ **Fixed**
267
+ - HTML entities caused unique title checks to always fail.
268
+ - Some request data was not filtered and/or sanitized properly.
269
+ - Some plugin-generated content was not properly escaped for use in HTML.
270
+ - URLs added manually to the blacklist are now properly validated.
271
+ - Feed sources and feed items restored from the trash become "draft" since WordPress 5.6.
272
+
273
  = 4.19.1 (2021-09-14)
274
  **Changed**
275
  - More details are now logged when a fatal error occurs during an import.
src/Data/Wp/WpPostMetaDataSet.php CHANGED
@@ -48,7 +48,7 @@ class WpPostMetaDataSet extends AbstractDataSet
48
 
49
  if (!($this->post instanceof WP_Post)) {
50
  throw new OutOfRangeException(
51
- sprintf(__('Post with ID %s does not exist', WPRSS_TEXT_DOMAIN), $post)
52
  );
53
  }
54
 
48
 
49
  if (!($this->post instanceof WP_Post)) {
50
  throw new OutOfRangeException(
51
+ sprintf(__('Post with ID %s does not exist', 'wprss'), $post)
52
  );
53
  }
54
 
src/ErrorHandler.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace RebelCode\Wpra\Core;
4
 
@@ -55,7 +55,7 @@ class ErrorHandler
55
  * @param callable $callback The callback to invoke when an exception is handled. The callback will receive the
56
  * exception or PHP7 {@see \Throwable} as argument.
57
  */
58
- public function __construct($rootDir, $callback)
59
  {
60
  $this->rootDir = $rootDir;
61
  $this->callback = $callback;
@@ -83,8 +83,6 @@ class ErrorHandler
83
  }
84
 
85
  /**
86
- * {@inheritdoc}
87
- *
88
  * @since 4.14
89
  */
90
  public function __invoke()
@@ -136,7 +134,7 @@ class ErrorHandler
136
  */
137
  protected function handleError($throwable)
138
  {
139
- // Attemt to log the error
140
  try {
141
  wpra_get_logger()->log(
142
  LogLevel::ERROR,
@@ -159,10 +157,6 @@ class ErrorHandler
159
 
160
  if (is_callable($this->callback)) {
161
  call_user_func_array($this->callback, [$throwable]);
162
-
163
- return;
164
  }
165
-
166
- return;
167
  }
168
  }
1
+ <?php /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
2
 
3
  namespace RebelCode\Wpra\Core;
4
 
55
  * @param callable $callback The callback to invoke when an exception is handled. The callback will receive the
56
  * exception or PHP7 {@see \Throwable} as argument.
57
  */
58
+ public function __construct($rootDir, callable $callback)
59
  {
60
  $this->rootDir = $rootDir;
61
  $this->callback = $callback;
83
  }
84
 
85
  /**
 
 
86
  * @since 4.14
87
  */
88
  public function __invoke()
134
  */
135
  protected function handleError($throwable)
136
  {
137
+ // Attempt to log the error
138
  try {
139
  wpra_get_logger()->log(
140
  LogLevel::ERROR,
157
 
158
  if (is_callable($this->callback)) {
159
  call_user_func_array($this->callback, [$throwable]);
 
 
160
  }
 
 
161
  }
162
  }
src/Modules/BlacklistToolModule.php CHANGED
@@ -71,6 +71,13 @@ class BlacklistToolModule implements ModuleInterface
71
  __('The blacklist item URL is empty. Please enter the URL to blacklist.', 'wprss')
72
  );
73
  },
 
 
 
 
 
 
 
74
  /*
75
  * The notice to show when a URL has been added to the blacklist.
76
  *
@@ -107,6 +114,16 @@ class BlacklistToolModule implements ModuleInterface
107
  return;
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
110
  // Empty titles default to the URL
111
  if (empty($title)) {
112
  $title = $url;
71
  __('The blacklist item URL is empty. Please enter the URL to blacklist.', 'wprss')
72
  );
73
  },
74
+ /* The notice to show when a URL is being added to the blacklist and it is invalid. */
75
+ 'wpra/admin/tools/blacklist/invalid_url_notice' => function () {
76
+ return sprintf(
77
+ '<div class="notice notice-error is-dismissable"><p>%s</p></div>',
78
+ __('The blacklisted item does not have a valid URL.', 'wprss')
79
+ );
80
+ },
81
  /*
82
  * The notice to show when a URL has been added to the blacklist.
83
  *
114
  return;
115
  }
116
 
117
+ $url = sanitize_text_field($url);
118
+
119
+ // URL cannot be empty
120
+ if (empty($url)) {
121
+ $notice = $c->get('wpra/admin/tools/blacklist/invalid_url_notice');
122
+ add_action('admin_notices', new EchoHandler($notice));
123
+
124
+ return;
125
+ }
126
+
127
  // Empty titles default to the URL
128
  if (empty($title)) {
129
  $title = $url;
src/Modules/I18nModule.php CHANGED
@@ -26,7 +26,7 @@ class I18nModule implements ModuleInterface
26
  * @since 4.13
27
  */
28
  'wpra/i18n/domain' => function () {
29
- return WPRSS_TEXT_DOMAIN;
30
  },
31
  /*
32
  * The name of the languages' parent directory.
26
  * @since 4.13
27
  */
28
  'wpra/i18n/domain' => function () {
29
+ return 'wprss';
30
  },
31
  /*
32
  * The name of the languages' parent directory.
src/Modules/LogsToolModule.php CHANGED
@@ -42,7 +42,7 @@ class LogsToolModule implements ModuleInterface
42
  * @since 4.17
43
  */
44
  'wpra/admin/tools/logs/num_logs' => function () {
45
- return 200;
46
  },
47
  /*
48
  * Additional context to add to the "Tools" page.
42
  * @since 4.17
43
  */
44
  'wpra/admin/tools/logs/num_logs' => function () {
45
+ return 500;
46
  },
47
  /*
48
  * Additional context to add to the "Tools" page.
src/Templates/Feeds/Types/ListTemplateType.php CHANGED
@@ -26,7 +26,7 @@ class ListTemplateType extends AbstractWpraFeedTemplateType
26
  */
27
  public function getName()
28
  {
29
- return __('List', WPRSS_TEXT_DOMAIN);
30
  }
31
 
32
  /**
26
  */
27
  public function getName()
28
  {
29
+ return __('List', 'wprss');
30
  }
31
 
32
  /**
src/Templates/TwigTemplate.php CHANGED
@@ -67,12 +67,12 @@ class TwigTemplate implements TemplateInterface
67
  return $this->env->load($this->path)->render($ctx);
68
  } catch (LoaderError $loaderEx) {
69
  throw new TemplateRenderException(
70
- __('Could not load template', WPRSS_TEXT_DOMAIN), null, $loaderEx, $this, $ctx
71
  );
72
  } catch (SyntaxError $synEx) {
73
  throw new TemplateRenderException(
74
  sprintf(
75
- __('Syntax error in template at line %d: %s', WPRSS_TEXT_DOMAIN),
76
  $synEx->getTemplateLine(),
77
  $synEx->getMessage()
78
  ),
@@ -80,7 +80,7 @@ class TwigTemplate implements TemplateInterface
80
  );
81
  } catch (Exception $ex) {
82
  throw new TemplateRenderException(
83
- __('Could not render twig template: ', WPRSS_TEXT_DOMAIN) . $ex->getMessage(),
84
  null,
85
  $ex,
86
  $this,
67
  return $this->env->load($this->path)->render($ctx);
68
  } catch (LoaderError $loaderEx) {
69
  throw new TemplateRenderException(
70
+ __('Could not load template', 'wprss'), null, $loaderEx, $this, $ctx
71
  );
72
  } catch (SyntaxError $synEx) {
73
  throw new TemplateRenderException(
74
  sprintf(
75
+ __('Syntax error in template at line %d: %s', 'wprss'),
76
  $synEx->getTemplateLine(),
77
  $synEx->getMessage()
78
  ),
80
  );
81
  } catch (Exception $ex) {
82
  throw new TemplateRenderException(
83
+ __('Could not render twig template: ', 'wprss') . $ex->getMessage(),
84
  null,
85
  $ex,
86
  $this,
src/Ui/BlacklistTable.php CHANGED
@@ -122,7 +122,7 @@ class BlacklistTable extends WP_List_Table
122
  $title = $item['title'];
123
 
124
  $editUrl = sprintf(admin_url('post.php?post=%s&action=edit'), $id);
125
- $title = sprintf('<strong><a href="%s">%s</a></strong>', $editUrl, $title);
126
 
127
  $actions = [
128
  'edit' => sprintf(
@@ -147,7 +147,7 @@ class BlacklistTable extends WP_List_Table
147
  */
148
  public function column_url($item)
149
  {
150
- return sprintf('<a href="%1$s" target="_blank">%1$s</a>', $item['url']);
151
  }
152
 
153
  /**
122
  $title = $item['title'];
123
 
124
  $editUrl = sprintf(admin_url('post.php?post=%s&action=edit'), $id);
125
+ $title = sprintf('<strong><a href="%s">%s</a></strong>', $editUrl, esc_html($title));
126
 
127
  $actions = [
128
  'edit' => sprintf(
147
  */
148
  public function column_url($item)
149
  {
150
+ return sprintf('<a href="%1$s" target="_blank">%1$s</a>', esc_html($item['url']));
151
  }
152
 
153
  /**
src/Util/NormalizeWpPostCapableTrait.php CHANGED
@@ -29,7 +29,7 @@ trait NormalizeWpPostCapableTrait
29
 
30
  if (!($post instanceof WP_Post)) {
31
  throw new OutOfRangeException(
32
- sprintf(__('Post with ID %s does not exist', WPRSS_TEXT_DOMAIN), $post)
33
  );
34
  }
35
 
29
 
30
  if (!($post instanceof WP_Post)) {
31
  throw new OutOfRangeException(
32
+ sprintf(__('Post with ID %s does not exist', 'wprss'), $post)
33
  );
34
  }
35
 
vendor/composer/ClassLoader.php CHANGED
@@ -42,30 +42,75 @@ namespace Composer\Autoload;
42
  */
43
  class ClassLoader
44
  {
 
45
  private $vendorDir;
46
 
47
  // PSR-4
 
 
 
 
48
  private $prefixLengthsPsr4 = array();
 
 
 
 
49
  private $prefixDirsPsr4 = array();
 
 
 
 
50
  private $fallbackDirsPsr4 = array();
51
 
52
  // PSR-0
 
 
 
 
53
  private $prefixesPsr0 = array();
 
 
 
 
54
  private $fallbackDirsPsr0 = array();
55
 
 
56
  private $useIncludePath = false;
 
 
 
 
 
57
  private $classMap = array();
 
 
58
  private $classMapAuthoritative = false;
 
 
 
 
 
59
  private $missingClasses = array();
 
 
60
  private $apcuPrefix;
61
 
 
 
 
62
  private static $registeredLoaders = array();
63
 
 
 
 
64
  public function __construct($vendorDir = null)
65
  {
66
  $this->vendorDir = $vendorDir;
67
  }
68
 
 
 
 
69
  public function getPrefixes()
70
  {
71
  if (!empty($this->prefixesPsr0)) {
@@ -75,28 +120,47 @@ class ClassLoader
75
  return array();
76
  }
77
 
 
 
 
 
78
  public function getPrefixesPsr4()
79
  {
80
  return $this->prefixDirsPsr4;
81
  }
82
 
 
 
 
 
83
  public function getFallbackDirs()
84
  {
85
  return $this->fallbackDirsPsr0;
86
  }
87
 
 
 
 
 
88
  public function getFallbackDirsPsr4()
89
  {
90
  return $this->fallbackDirsPsr4;
91
  }
92
 
 
 
 
 
93
  public function getClassMap()
94
  {
95
  return $this->classMap;
96
  }
97
 
98
  /**
99
- * @param array $classMap Class to filename map
 
 
 
100
  */
101
  public function addClassMap(array $classMap)
102
  {
@@ -111,9 +175,11 @@ class ClassLoader
111
  * Registers a set of PSR-0 directories for a given prefix, either
112
  * appending or prepending to the ones previously set for this prefix.
113
  *
114
- * @param string $prefix The prefix
115
- * @param array|string $paths The PSR-0 root directories
116
- * @param bool $prepend Whether to prepend the directories
 
 
117
  */
118
  public function add($prefix, $paths, $prepend = false)
119
  {
@@ -156,11 +222,13 @@ class ClassLoader
156
  * Registers a set of PSR-4 directories for a given namespace, either
157
  * appending or prepending to the ones previously set for this namespace.
158
  *
159
- * @param string $prefix The prefix/namespace, with trailing '\\'
160
- * @param array|string $paths The PSR-4 base directories
161
- * @param bool $prepend Whether to prepend the directories
162
  *
163
  * @throws \InvalidArgumentException
 
 
164
  */
165
  public function addPsr4($prefix, $paths, $prepend = false)
166
  {
@@ -204,8 +272,10 @@ class ClassLoader
204
  * Registers a set of PSR-0 directories for a given prefix,
205
  * replacing any others previously set for this prefix.
206
  *
207
- * @param string $prefix The prefix
208
- * @param array|string $paths The PSR-0 base directories
 
 
209
  */
210
  public function set($prefix, $paths)
211
  {
@@ -220,10 +290,12 @@ class ClassLoader
220
  * Registers a set of PSR-4 directories for a given namespace,
221
  * replacing any others previously set for this namespace.
222
  *
223
- * @param string $prefix The prefix/namespace, with trailing '\\'
224
- * @param array|string $paths The PSR-4 base directories
225
  *
226
  * @throws \InvalidArgumentException
 
 
227
  */
228
  public function setPsr4($prefix, $paths)
229
  {
@@ -243,6 +315,8 @@ class ClassLoader
243
  * Turns on searching the include path for class files.
244
  *
245
  * @param bool $useIncludePath
 
 
246
  */
247
  public function setUseIncludePath($useIncludePath)
248
  {
@@ -265,6 +339,8 @@ class ClassLoader
265
  * that have not been registered with the class map.
266
  *
267
  * @param bool $classMapAuthoritative
 
 
268
  */
269
  public function setClassMapAuthoritative($classMapAuthoritative)
270
  {
@@ -285,6 +361,8 @@ class ClassLoader
285
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
286
  *
287
  * @param string|null $apcuPrefix
 
 
288
  */
289
  public function setApcuPrefix($apcuPrefix)
290
  {
@@ -305,6 +383,8 @@ class ClassLoader
305
  * Registers this instance as an autoloader.
306
  *
307
  * @param bool $prepend Whether to prepend the autoloader or not
 
 
308
  */
309
  public function register($prepend = false)
310
  {
@@ -324,6 +404,8 @@ class ClassLoader
324
 
325
  /**
326
  * Unregisters this instance as an autoloader.
 
 
327
  */
328
  public function unregister()
329
  {
@@ -403,6 +485,11 @@ class ClassLoader
403
  return self::$registeredLoaders;
404
  }
405
 
 
 
 
 
 
406
  private function findFileWithExtension($class, $ext)
407
  {
408
  // PSR-4 lookup
@@ -474,6 +561,10 @@ class ClassLoader
474
  * Scope isolated include.
475
  *
476
  * Prevents access to $this/self from included files.
 
 
 
 
477
  */
478
  function includeFile($file)
479
  {
42
  */
43
  class ClassLoader
44
  {
45
+ /** @var ?string */
46
  private $vendorDir;
47
 
48
  // PSR-4
49
+ /**
50
+ * @var array[]
51
+ * @psalm-var array<string, array<string, int>>
52
+ */
53
  private $prefixLengthsPsr4 = array();
54
+ /**
55
+ * @var array[]
56
+ * @psalm-var array<string, array<int, string>>
57
+ */
58
  private $prefixDirsPsr4 = array();
59
+ /**
60
+ * @var array[]
61
+ * @psalm-var array<string, string>
62
+ */
63
  private $fallbackDirsPsr4 = array();
64
 
65
  // PSR-0
66
+ /**
67
+ * @var array[]
68
+ * @psalm-var array<string, array<string, string[]>>
69
+ */
70
  private $prefixesPsr0 = array();
71
+ /**
72
+ * @var array[]
73
+ * @psalm-var array<string, string>
74
+ */
75
  private $fallbackDirsPsr0 = array();
76
 
77
+ /** @var bool */
78
  private $useIncludePath = false;
79
+
80
+ /**
81
+ * @var string[]
82
+ * @psalm-var array<string, string>
83
+ */
84
  private $classMap = array();
85
+
86
+ /** @var bool */
87
  private $classMapAuthoritative = false;
88
+
89
+ /**
90
+ * @var bool[]
91
+ * @psalm-var array<string, bool>
92
+ */
93
  private $missingClasses = array();
94
+
95
+ /** @var ?string */
96
  private $apcuPrefix;
97
 
98
+ /**
99
+ * @var self[]
100
+ */
101
  private static $registeredLoaders = array();
102
 
103
+ /**
104
+ * @param ?string $vendorDir
105
+ */
106
  public function __construct($vendorDir = null)
107
  {
108
  $this->vendorDir = $vendorDir;
109
  }
110
 
111
+ /**
112
+ * @return string[]
113
+ */
114
  public function getPrefixes()
115
  {
116
  if (!empty($this->prefixesPsr0)) {
120
  return array();
121
  }
122
 
123
+ /**
124
+ * @return array[]
125
+ * @psalm-return array<string, array<int, string>>
126
+ */
127
  public function getPrefixesPsr4()
128
  {
129
  return $this->prefixDirsPsr4;
130
  }
131
 
132
+ /**
133
+ * @return array[]
134
+ * @psalm-return array<string, string>
135
+ */
136
  public function getFallbackDirs()
137
  {
138
  return $this->fallbackDirsPsr0;
139
  }
140
 
141
+ /**
142
+ * @return array[]
143
+ * @psalm-return array<string, string>
144
+ */
145
  public function getFallbackDirsPsr4()
146
  {
147
  return $this->fallbackDirsPsr4;
148
  }
149
 
150
+ /**
151
+ * @return string[] Array of classname => path
152
+ * @psalm-var array<string, string>
153
+ */
154
  public function getClassMap()
155
  {
156
  return $this->classMap;
157
  }
158
 
159
  /**
160
+ * @param string[] $classMap Class to filename map
161
+ * @psalm-param array<string, string> $classMap
162
+ *
163
+ * @return void
164
  */
165
  public function addClassMap(array $classMap)
166
  {
175
  * Registers a set of PSR-0 directories for a given prefix, either
176
  * appending or prepending to the ones previously set for this prefix.
177
  *
178
+ * @param string $prefix The prefix
179
+ * @param string[]|string $paths The PSR-0 root directories
180
+ * @param bool $prepend Whether to prepend the directories
181
+ *
182
+ * @return void
183
  */
184
  public function add($prefix, $paths, $prepend = false)
185
  {
222
  * Registers a set of PSR-4 directories for a given namespace, either
223
  * appending or prepending to the ones previously set for this namespace.
224
  *
225
+ * @param string $prefix The prefix/namespace, with trailing '\\'
226
+ * @param string[]|string $paths The PSR-4 base directories
227
+ * @param bool $prepend Whether to prepend the directories
228
  *
229
  * @throws \InvalidArgumentException
230
+ *
231
+ * @return void
232
  */
233
  public function addPsr4($prefix, $paths, $prepend = false)
234
  {
272
  * Registers a set of PSR-0 directories for a given prefix,
273
  * replacing any others previously set for this prefix.
274
  *
275
+ * @param string $prefix The prefix
276
+ * @param string[]|string $paths The PSR-0 base directories
277
+ *
278
+ * @return void
279
  */
280
  public function set($prefix, $paths)
281
  {
290
  * Registers a set of PSR-4 directories for a given namespace,
291
  * replacing any others previously set for this namespace.
292
  *
293
+ * @param string $prefix The prefix/namespace, with trailing '\\'
294
+ * @param string[]|string $paths The PSR-4 base directories
295
  *
296
  * @throws \InvalidArgumentException
297
+ *
298
+ * @return void
299
  */
300
  public function setPsr4($prefix, $paths)
301
  {
315
  * Turns on searching the include path for class files.
316
  *
317
  * @param bool $useIncludePath
318
+ *
319
+ * @return void
320
  */
321
  public function setUseIncludePath($useIncludePath)
322
  {
339
  * that have not been registered with the class map.
340
  *
341
  * @param bool $classMapAuthoritative
342
+ *
343
+ * @return void
344
  */
345
  public function setClassMapAuthoritative($classMapAuthoritative)
346
  {
361
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
362
  *
363
  * @param string|null $apcuPrefix
364
+ *
365
+ * @return void
366
  */
367
  public function setApcuPrefix($apcuPrefix)
368
  {
383
  * Registers this instance as an autoloader.
384
  *
385
  * @param bool $prepend Whether to prepend the autoloader or not
386
+ *
387
+ * @return void
388
  */
389
  public function register($prepend = false)
390
  {
404
 
405
  /**
406
  * Unregisters this instance as an autoloader.
407
+ *
408
+ * @return void
409
  */
410
  public function unregister()
411
  {
485
  return self::$registeredLoaders;
486
  }
487
 
488
+ /**
489
+ * @param string $class
490
+ * @param string $ext
491
+ * @return string|false
492
+ */
493
  private function findFileWithExtension($class, $ext)
494
  {
495
  // PSR-4 lookup
561
  * Scope isolated include.
562
  *
563
  * Prevents access to $this/self from included files.
564
+ *
565
+ * @param string $file
566
+ * @return void
567
+ * @private
568
  */
569
  function includeFile($file)
570
  {
vendor/composer/InstalledVersions.php CHANGED
@@ -20,7 +20,7 @@ use Composer\Semver\VersionParser;
20
  *
21
  * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22
  *
23
- * To require it's presence, you can require `composer-runtime-api ^2.0`
24
  */
25
  class InstalledVersions
26
  {
@@ -228,7 +228,7 @@ class InstalledVersions
228
 
229
  /**
230
  * @return array
231
- * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
232
  */
233
  public static function getRootPackage()
234
  {
@@ -242,7 +242,7 @@ class InstalledVersions
242
  *
243
  * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
244
  * @return array[]
245
- * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
246
  */
247
  public static function getRawData()
248
  {
@@ -265,7 +265,7 @@ class InstalledVersions
265
  * Returns the raw data of all installed.php which are currently loaded for custom implementations
266
  *
267
  * @return array[]
268
- * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
269
  */
270
  public static function getAllRawData()
271
  {
@@ -288,7 +288,7 @@ class InstalledVersions
288
  * @param array[] $data A vendor/composer/installed.php data set
289
  * @return void
290
  *
291
- * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
292
  */
293
  public static function reload($data)
294
  {
@@ -298,7 +298,7 @@ class InstalledVersions
298
 
299
  /**
300
  * @return array[]
301
- * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
302
  */
303
  private static function getInstalled()
304
  {
20
  *
21
  * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22
  *
23
+ * To require its presence, you can require `composer-runtime-api ^2.0`
24
  */
25
  class InstalledVersions
26
  {
228
 
229
  /**
230
  * @return array
231
+ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
232
  */
233
  public static function getRootPackage()
234
  {
242
  *
243
  * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
244
  * @return array[]
245
+ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
246
  */
247
  public static function getRawData()
248
  {
265
  * Returns the raw data of all installed.php which are currently loaded for custom implementations
266
  *
267
  * @return array[]
268
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
269
  */
270
  public static function getAllRawData()
271
  {
288
  * @param array[] $data A vendor/composer/installed.php data set
289
  * @return void
290
  *
291
+ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
292
  */
293
  public static function reload($data)
294
  {
298
 
299
  /**
300
  * @return array[]
301
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
302
  */
303
  private static function getInstalled()
304
  {
vendor/composer/installed.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php return array(
2
  'root' => array(
3
- 'pretty_version' => 'dev-master',
4
- 'version' => 'dev-master',
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => '653d975c97188f8f072f87b4ff5c4b0b5700df24',
9
  'name' => 'wprss/core',
10
  'dev' => false,
11
  ),
@@ -338,12 +338,12 @@
338
  'dev_requirement' => false,
339
  ),
340
  'wprss/core' => array(
341
- 'pretty_version' => 'dev-master',
342
- 'version' => 'dev-master',
343
  'type' => 'wordpress-plugin',
344
  'install_path' => __DIR__ . '/../../',
345
  'aliases' => array(),
346
- 'reference' => '653d975c97188f8f072f87b4ff5c4b0b5700df24',
347
  'dev_requirement' => false,
348
  ),
349
  ),
1
  <?php return array(
2
  'root' => array(
3
+ 'pretty_version' => 'dev-develop',
4
+ 'version' => 'dev-develop',
5
  'type' => 'wordpress-plugin',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '8b106ef99bd494492820d3d92a9a07a5af672dcf',
9
  'name' => 'wprss/core',
10
  'dev' => false,
11
  ),
338
  'dev_requirement' => false,
339
  ),
340
  'wprss/core' => array(
341
+ 'pretty_version' => 'dev-develop',
342
+ 'version' => 'dev-develop',
343
  'type' => 'wordpress-plugin',
344
  'install_path' => __DIR__ . '/../../',
345
  'aliases' => array(),
346
+ 'reference' => '8b106ef99bd494492820d3d92a9a07a5af672dcf',
347
  'dev_requirement' => false,
348
  ),
349
  ),
wp-rss-aggregator.php CHANGED
@@ -1,10 +1,10 @@
1
- <?php
2
 
3
  /**
4
  * Plugin Name: WP RSS Aggregator
5
  * Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
6
  * Description: Imports and aggregates multiple RSS Feeds.
7
- * Version: 4.19.1
8
  * Author: RebelCode
9
  * Author URI: https://www.wprssaggregator.com
10
  * Text Domain: wprss
@@ -76,7 +76,7 @@ use RebelCode\Wpra\Core\Plugin;
76
 
77
  // Set the version number of the plugin.
78
  if( !defined( 'WPRSS_VERSION' ) )
79
- define( 'WPRSS_VERSION', '4.19.1' );
80
 
81
  if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
82
  define( 'WPRSS_WP_MIN_VERSION', '4.8' );
@@ -98,7 +98,7 @@ if( !defined( 'WPRSS_FILE_CONSTANT' ) )
98
 
99
  // Set constant path to the plugin directory.
100
  if( !defined( 'WPRSS_DIR' ) )
101
- define( 'WPRSS_DIR', plugin_dir_path( __FILE__ ) );
102
 
103
  // Set constant URI to the plugin URL.
104
  if( !defined( 'WPRSS_URI' ) )
@@ -106,30 +106,30 @@ if( !defined( 'WPRSS_URI' ) )
106
 
107
  // Set the constant path to the plugin's javascript directory.
108
  if( !defined( 'WPRSS_JS' ) )
109
- define( 'WPRSS_JS', WPRSS_URI . trailingslashit( 'js' ) );
110
 
111
  // Set the constant path to the plugin's CSS directory.
112
  if( !defined( 'WPRSS_CSS' ) )
113
- define( 'WPRSS_CSS', WPRSS_URI . trailingslashit( 'css' ) );
114
 
115
  // Set the constant path to the plugin's javascript build directory.
116
  if( !defined( 'WPRSS_APP_JS' ) )
117
- define( 'WPRSS_APP_JS', WPRSS_URI . trailingslashit( 'js/build' ) );
118
 
119
  // Set the constant path to the plugin's CSS build directory.
120
  if( !defined( 'WPRSS_APP_CSS' ) )
121
- define( 'WPRSS_APP_CSS', WPRSS_URI . trailingslashit( 'css/build' ) );
122
 
123
  // Set the constant path to the plugin's images directory.
124
  if( !defined( 'WPRSS_IMG' ) )
125
- define( 'WPRSS_IMG', WPRSS_URI . trailingslashit( 'images' ) );
126
 
127
  // Set the constant path to the plugin's includes directory.
128
  if( !defined( 'WPRSS_INC' ) )
129
- define( 'WPRSS_INC', WPRSS_DIR . trailingslashit( 'includes' ) );
130
 
131
  if( !defined( 'WPRSS_LANG' ) )
132
- define( 'WPRSS_LANG', WPRSS_DIR . trailingslashit( 'languages' ) );
133
 
134
  // Set the constant path to the plugin's log file.
135
  if( !defined( 'WPRSS_LOG_FILE' ) )
@@ -159,28 +159,28 @@ if ( !defined( 'WPRACORE_DIAG_TESTS_DIR' ) ) {
159
  define( 'WPRACORE_DIAG_TESTS_DIR', WPRSS_DIR . 'test/diag' );
160
  }
161
 
162
- define('WPRSS_CORE_PLUGIN_NAME', 'WP RSS Aggregator');
163
 
164
  /**
165
  * Code of the Core plugin.
166
  *
167
  * @since 4.11
168
  */
169
- define('WPRSS_PLUGIN_CODE', 'wprss');
170
 
171
  /**
172
  * Prefix for events used by this plugin.
173
  *
174
  * @since 4.11
175
  */
176
- define('WPRSS_EVENT_PREFIX', \WPRSS_PLUGIN_CODE . '_');
177
 
178
  /**
179
  * Whether this plugin is in debug mode.
180
  *
181
  * @since 4.11
182
  */
183
- define('WPRSS_DEBUG', \WP_DEBUG);
184
 
185
  /**
186
  * Load required files.
@@ -497,11 +497,11 @@ function wpra_error_handler($error)
497
  '<b>WP RSS Aggregator</b> has encountered an error. If this problem persists, kindly contact customer support and provide the following details:',
498
  'wprss'
499
  );
500
- ?>
501
- <div class="notice notice-error">
502
- <?php echo wpra_display_error($message, $error) ?>
503
- </div>
504
- <?php
505
  });
506
 
507
  do_action('wpra_error', $error);
@@ -519,32 +519,34 @@ function wpra_error_handler($error)
519
  function wpra_critical_error_handler($error)
520
  {
521
  $hasAddons = count(wpra_get_addon_paths()) > 0;
522
- ob_start();
523
- ?>
524
-
525
- <br/>
526
- <form method="POST" action="<?php echo esc_attr(admin_url()) ?>">
527
- <?php wp_nonce_field('wprss_safe_deactivate', 'wprss_safe_deactivate_nonce'); ?>
528
- <button type="submit" class="button button-secondary">
529
- <?php echo $hasAddons
530
- ? __('Deactivate WP RSS Aggregator and its addons', 'wprss')
531
- : __('Deactivate WP RSS Aggregator', 'wprss')
532
- ?>
533
- </button>
534
- </form>
 
 
 
 
535
 
536
- <?php
537
- $deactivateForm = ob_get_clean();
538
  $message = __(
539
  '<b>WP RSS Aggregator</b> has encountered a critical error. The safest course of action is to deactivate the plugin and any of its add-ons on this site using the button below. Once you’ve done that, you may reactivate them and start using the plugins again. If the problem persists, please copy the below error and send it to our support team with an explanation of when and how it happened.',
540
  'wprss'
541
  );
542
- $errorDisplay = wpra_display_error($message, $error);
543
 
544
  do_action('wpra_critical_error', $error);
545
 
546
  wp_die(
547
- $errorDisplay . $deactivateForm,
548
  __('WP RSS Aggregator Error', 'wprss')
549
  );
550
  }
@@ -554,43 +556,61 @@ function wpra_critical_error_handler($error)
554
  *
555
  * @since 4.15
556
  *
557
- * @param string $message The message to show.
558
- * @param Exception|Throwable $error The error.
559
  *
560
  * @return string
561
  */
562
  function wpra_display_error($message, $error)
563
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
  ob_start(); ?>
565
 
566
  <p>
567
- <?php echo $message ?>
568
  </p>
569
  <div style="background-color: rgba(0,0,0,.07); padding: 5px;">
570
  <details>
571
  <summary style="cursor: pointer;">
572
- <?php _e('Click to show error details', 'wprss') ?>
573
  </summary>
574
  <div style="padding-top: 10px; overflow-x: scroll;">
575
- <strong><?php _e('Error Message:', 'wprss'); ?></strong>
576
- <br/>
577
- <pre><?= $error->getMessage(); ?> (<?= wprss_error_path($error) ?>)</pre>
578
-
579
- <?php
580
- $prev = $error;
581
- while ($prev = $prev->getPrevious()) : ?>
582
- <strong><?php _e('Caused by:', 'wprss'); ?></strong>
583
- <br/>
584
- <pre><?= $prev->getMessage(); ?> (<?= wprss_error_path($prev) ?>)</pre>
585
- <?php endwhile; ?>
586
-
587
- <strong><?php _e('Stack trace:', 'wprss'); ?></strong>
588
- <br/>
589
- <pre><?php echo $error->getTraceAsString(); ?></pre>
590
  </div>
591
  </details>
592
  </div>
593
- <br/>
594
  <?php
595
 
596
  return ob_get_clean();
@@ -635,11 +655,7 @@ function wpra_safe_deactivate()
635
  {
636
  $nonce = filter_input(INPUT_POST, 'wprss_safe_deactivate_nonce', FILTER_DEFAULT);
637
 
638
- if (empty($nonce)) {
639
- return;
640
- }
641
-
642
- if (!wp_verify_nonce($nonce, 'wprss_safe_deactivate')) {
643
  return;
644
  }
645
 
@@ -732,9 +748,12 @@ add_action('after_plugin_row', function($plugin_file) {
732
 
733
  $message = __(
734
  'As of version 4.13, WP RSS Aggregator will stop supporting PHP 5.3 and will require PHP 5.4 or later. Kindly contact your site\'s hosting provider for PHP version update options.',
735
- WPRSS_TEXT_DOMAIN
 
 
 
 
736
  );
737
- $notice = sprintf('<div class="update-notice notice inline notice-error notice-alt"><p>%s</p></div>', $message);
738
  $td = sprintf('<td colspan="3" class="plugin-update colspanchange">%s</td>', $notice);
739
  printf('<tr class="plugin-update-tr active">%s</tr>', $td);
740
  }, 5, 2);
@@ -747,18 +766,23 @@ function wprss_wp_min_version_satisfied() {
747
 
748
  add_action( 'init', 'wprss_add_wp_version_warning' );
749
  function wprss_add_wp_version_warning() {
750
- if ( wprss_wp_min_version_satisfied() )
751
  return;
 
752
 
753
- wprss_admin_notice_add(array(
754
- 'id' => 'wp_version_warning',
755
- 'content' => sprintf( __(
756
- '<p><strong>%2$s requires WordPress to be of version %1$s or higher.</strong></br>'
757
- . 'Older versions of WordPress are no longer supported by %2$s. Please upgrade your WordPress core to continue benefiting from %2$s support services.</p>',
758
- WPRSS_TEXT_DOMAIN ), WPRSS_WP_MIN_VERSION, WPRSS_CORE_PLUGIN_NAME ),
759
- 'notice_type' => 'error'
760
- ));
761
-
 
 
 
 
762
  }
763
 
764
 
@@ -775,20 +799,20 @@ function wprss_add_php_version_warning() {
775
  deactivate_plugins(plugin_basename(__FILE__));
776
 
777
  $firstLine = get_transient('_wprss_activation_redirect')
778
- ? __('WP RSS Aggregator cannot be activated.', WPRSS_TEXT_DOMAIN)
779
- : __('WP RSS Aggregator has been deactivated.', WPRSS_TEXT_DOMAIN);
780
 
781
  $supportLink = sprintf(
782
  '<a href="%2$s" target="_blank">%1$s</a>',
783
  _x(
784
  'contact support',
785
  'Used like "Kindly contact your hosting provider or contact support for more information."',
786
- WPRSS_TEXT_DOMAIN
787
  ),
788
  'https://wordpress.org/support/plugin/wp-rss-aggregator'
789
  );
790
  $secondLine = sprintf(
791
- __("The plugin requires version %s or later and your site's PHP version is %s.", WPRSS_TEXT_DOMAIN),
792
  '<strong>' . WPRSS_MIN_PHP_VERSION . '</strong>',
793
  '<strong>' . PHP_VERSION . '</strong>'
794
  );
@@ -796,7 +820,7 @@ function wprss_add_php_version_warning() {
796
  _x(
797
  'Kindly contact your hosting provider to upgrade your PHP version or %s for more information.',
798
  'the "%s" part is a link with text = "contact support"',
799
- WPRSS_TEXT_DOMAIN
800
  ),
801
  $supportLink
802
  );
@@ -826,7 +850,7 @@ add_action('after_plugin_row', function($plugin_file) {
826
 
827
  $message = __(
828
  'As of version 4.13, WP RSS Aggregator will stop supporting PHP 5.3 and will require PHP 5.4 or later. Kindly contact your site\'s hosting provider for PHP version update options.',
829
- WPRSS_TEXT_DOMAIN
830
  );
831
  $notice = sprintf('<div class="update-notice notice inline notice-error notice-alt"><p>%s</p></div>', $message);
832
  $td = sprintf('<td colspan="3" class="plugin-update colspanchange">%s</td>', $notice);
1
+ <?php /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
2
 
3
  /**
4
  * Plugin Name: WP RSS Aggregator
5
  * Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
6
  * Description: Imports and aggregates multiple RSS Feeds.
7
+ * Version: 4.19.2
8
  * Author: RebelCode
9
  * Author URI: https://www.wprssaggregator.com
10
  * Text Domain: wprss
76
 
77
  // Set the version number of the plugin.
78
  if( !defined( 'WPRSS_VERSION' ) )
79
+ define( 'WPRSS_VERSION', '4.19.2' );
80
 
81
  if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
82
  define( 'WPRSS_WP_MIN_VERSION', '4.8' );
98
 
99
  // Set constant path to the plugin directory.
100
  if( !defined( 'WPRSS_DIR' ) )
101
+ define( 'WPRSS_DIR', __DIR__ . '/' );
102
 
103
  // Set constant URI to the plugin URL.
104
  if( !defined( 'WPRSS_URI' ) )
106
 
107
  // Set the constant path to the plugin's javascript directory.
108
  if( !defined( 'WPRSS_JS' ) )
109
+ define( 'WPRSS_JS', WPRSS_URI . 'js/' );
110
 
111
  // Set the constant path to the plugin's CSS directory.
112
  if( !defined( 'WPRSS_CSS' ) )
113
+ define( 'WPRSS_CSS', WPRSS_URI . 'css/' );
114
 
115
  // Set the constant path to the plugin's javascript build directory.
116
  if( !defined( 'WPRSS_APP_JS' ) )
117
+ define( 'WPRSS_APP_JS', WPRSS_URI . 'js/build/' );
118
 
119
  // Set the constant path to the plugin's CSS build directory.
120
  if( !defined( 'WPRSS_APP_CSS' ) )
121
+ define( 'WPRSS_APP_CSS', WPRSS_URI . 'css/build/' );
122
 
123
  // Set the constant path to the plugin's images directory.
124
  if( !defined( 'WPRSS_IMG' ) )
125
+ define( 'WPRSS_IMG', WPRSS_URI . 'images/' );
126
 
127
  // Set the constant path to the plugin's includes directory.
128
  if( !defined( 'WPRSS_INC' ) )
129
+ define( 'WPRSS_INC', __DIR__ . '/includes/' );
130
 
131
  if( !defined( 'WPRSS_LANG' ) )
132
+ define( 'WPRSS_LANG', __DIR__ . '/languages/' );
133
 
134
  // Set the constant path to the plugin's log file.
135
  if( !defined( 'WPRSS_LOG_FILE' ) )
159
  define( 'WPRACORE_DIAG_TESTS_DIR', WPRSS_DIR . 'test/diag' );
160
  }
161
 
162
+ const WPRSS_CORE_PLUGIN_NAME = 'WP RSS Aggregator';
163
 
164
  /**
165
  * Code of the Core plugin.
166
  *
167
  * @since 4.11
168
  */
169
+ const WPRSS_PLUGIN_CODE = 'wprss';
170
 
171
  /**
172
  * Prefix for events used by this plugin.
173
  *
174
  * @since 4.11
175
  */
176
+ define('WPRSS_EVENT_PREFIX', WPRSS_PLUGIN_CODE . '_');
177
 
178
  /**
179
  * Whether this plugin is in debug mode.
180
  *
181
  * @since 4.11
182
  */
183
+ const WPRSS_DEBUG = WP_DEBUG;
184
 
185
  /**
186
  * Load required files.
497
  '<b>WP RSS Aggregator</b> has encountered an error. If this problem persists, kindly contact customer support and provide the following details:',
498
  'wprss'
499
  );
500
+
501
+ printf(
502
+ '<div class="notice notice-error">%s</div>',
503
+ wpra_display_error($message, $error)
504
+ );
505
  });
506
 
507
  do_action('wpra_error', $error);
519
  function wpra_critical_error_handler($error)
520
  {
521
  $hasAddons = count(wpra_get_addon_paths()) > 0;
522
+ $buttonText = $hasAddons
523
+ ? __('Deactivate WP RSS Aggregator and its addons', 'wprss')
524
+ : __('Deactivate WP RSS Aggregator', 'wprss');
525
+
526
+ $buttonHtml = sprintf(
527
+ '<button type="submit" class="button button-secondary">%s</button>',
528
+ esc_html($buttonText)
529
+ );
530
+
531
+ $formNonceHtml = wp_nonce_field('wprss_safe_deactivate', 'wprss_safe_deactivate_nonce', true, false);
532
+
533
+ $formHtml = sprintf(
534
+ '<br/><form method="POST" action="%s">%s %s</form>',
535
+ esc_attr(admin_url()),
536
+ $formNonceHtml,
537
+ $buttonHtml
538
+ );
539
 
 
 
540
  $message = __(
541
  '<b>WP RSS Aggregator</b> has encountered a critical error. The safest course of action is to deactivate the plugin and any of its add-ons on this site using the button below. Once you’ve done that, you may reactivate them and start using the plugins again. If the problem persists, please copy the below error and send it to our support team with an explanation of when and how it happened.',
542
  'wprss'
543
  );
544
+ $errorDetailsHtml = wpra_display_error($message, $error);
545
 
546
  do_action('wpra_critical_error', $error);
547
 
548
  wp_die(
549
+ $errorDetailsHtml . $formHtml,
550
  __('WP RSS Aggregator Error', 'wprss')
551
  );
552
  }
556
  *
557
  * @since 4.15
558
  *
559
+ * @param string $message The message to show.
560
+ * @param Exception|Throwable $error The error.
561
  *
562
  * @return string
563
  */
564
  function wpra_display_error($message, $error)
565
  {
566
+ $exceptionMsg = sprintf(
567
+ '<pre>%s (%s)</pre>',
568
+ esc_html($error->getMessage()),
569
+ esc_html(wprss_error_path($error))
570
+ );
571
+
572
+ $exceptionChain = '';
573
+ $prev = $error;
574
+ while ($prev = $prev->getPrevious()) {
575
+ $exceptionChain .= sprintf(
576
+ '<strong>%s</strong>
577
+ <br/>
578
+ <pre>%s (%s)</pre>',
579
+ __('Caused by:', 'wprss'),
580
+ esc_html($prev->getMessage()),
581
+ esc_html(wprss_error_path($prev))
582
+ );
583
+ }
584
+
585
+ $stackTrace = esc_html($error->getTraceAsString());
586
+
587
  ob_start(); ?>
588
 
589
  <p>
590
+ <?= esc_html($message) ?>
591
  </p>
592
  <div style="background-color: rgba(0,0,0,.07); padding: 5px;">
593
  <details>
594
  <summary style="cursor: pointer;">
595
+ <?= __('Click to show error details', 'wprss') ?>
596
  </summary>
597
  <div style="padding-top: 10px; overflow-x: scroll;">
598
+ <strong>
599
+ <?= __('Error Message:', 'wprss'); ?>
600
+ </strong>
601
+
602
+ <br />
603
+
604
+ <?= $exceptionMsg ?>
605
+ <?= $exceptionChain ?>
606
+
607
+ <strong><?= __('Stack trace:', 'wprss'); ?></strong>
608
+ <br />
609
+ <pre><?= $stackTrace ?></pre>
 
 
 
610
  </div>
611
  </details>
612
  </div>
613
+ <br />
614
  <?php
615
 
616
  return ob_get_clean();
655
  {
656
  $nonce = filter_input(INPUT_POST, 'wprss_safe_deactivate_nonce', FILTER_DEFAULT);
657
 
658
+ if (empty($nonce) || !wp_verify_nonce($nonce, 'wprss_safe_deactivate')) {
 
 
 
 
659
  return;
660
  }
661
 
748
 
749
  $message = __(
750
  'As of version 4.13, WP RSS Aggregator will stop supporting PHP 5.3 and will require PHP 5.4 or later. Kindly contact your site\'s hosting provider for PHP version update options.',
751
+ 'wprss'
752
+ );
753
+ $notice = sprintf(
754
+ '<div class="update-notice notice inline notice-error notice-alt"><p>%s</p></div>',
755
+ esc_html($message)
756
  );
 
757
  $td = sprintf('<td colspan="3" class="plugin-update colspanchange">%s</td>', $notice);
758
  printf('<tr class="plugin-update-tr active">%s</tr>', $td);
759
  }, 5, 2);
766
 
767
  add_action( 'init', 'wprss_add_wp_version_warning' );
768
  function wprss_add_wp_version_warning() {
769
+ if (wprss_wp_min_version_satisfied()) {
770
  return;
771
+ }
772
 
773
+ wprss_admin_notice_add([
774
+ 'id' => 'wp_version_warning',
775
+ 'content' => sprintf(
776
+ __(
777
+ '<p><strong>%2$s requires WordPress to be of version %1$s or higher.</strong></br>' .
778
+ 'Older versions of WordPress are no longer supported by %2$s. Please upgrade your WordPress core to continue benefiting from %2$s support services.</p>',
779
+ 'wprss'
780
+ ),
781
+ esc_html(WPRSS_WP_MIN_VERSION),
782
+ esc_html(WPRSS_CORE_PLUGIN_NAME)
783
+ ),
784
+ 'notice_type' => 'error',
785
+ ]);
786
  }
787
 
788
 
799
  deactivate_plugins(plugin_basename(__FILE__));
800
 
801
  $firstLine = get_transient('_wprss_activation_redirect')
802
+ ? __('WP RSS Aggregator cannot be activated.', 'wprss')
803
+ : __('WP RSS Aggregator has been deactivated.', 'wprss');
804
 
805
  $supportLink = sprintf(
806
  '<a href="%2$s" target="_blank">%1$s</a>',
807
  _x(
808
  'contact support',
809
  'Used like "Kindly contact your hosting provider or contact support for more information."',
810
+ 'wprss'
811
  ),
812
  'https://wordpress.org/support/plugin/wp-rss-aggregator'
813
  );
814
  $secondLine = sprintf(
815
+ __("The plugin requires version %s or later and your site's PHP version is %s.", 'wprss'),
816
  '<strong>' . WPRSS_MIN_PHP_VERSION . '</strong>',
817
  '<strong>' . PHP_VERSION . '</strong>'
818
  );
820
  _x(
821
  'Kindly contact your hosting provider to upgrade your PHP version or %s for more information.',
822
  'the "%s" part is a link with text = "contact support"',
823
+ 'wprss'
824
  ),
825
  $supportLink
826
  );
850
 
851
  $message = __(
852
  'As of version 4.13, WP RSS Aggregator will stop supporting PHP 5.3 and will require PHP 5.4 or later. Kindly contact your site\'s hosting provider for PHP version update options.',
853
+ 'wprss'
854
  );
855
  $notice = sprintf('<div class="update-notice notice inline notice-error notice-alt"><p>%s</p></div>', $message);
856
  $td = sprintf('<td colspan="3" class="plugin-update colspanchange">%s</td>', $notice);