Version Description
(2018-12-11) = * Added handling of lifetime licenses. * License renewal link and expiry are not shown if they are not applicable.
Download this release
Release Info
Developer | markzahra |
Plugin | WP RSS Aggregator |
Version | 4.11.4 |
Comparing to | |
See all releases |
Code changes from version 4.11.3 to 4.11.4
- includes/Aventura/Wprss/Core/Licensing/Manager.php +620 -567
- includes/Aventura/Wprss/Core/Licensing/Settings.php +347 -340
- nbproject/project.properties +7 -0
- nbproject/project.xml +9 -0
- readme.txt +92 -69
- vendor/autoload.php +1 -1
- vendor/composer/autoload_real.php +4 -4
- vendor/composer/autoload_static.php +3 -3
- wp-rss-aggregator.php +5 -5
includes/Aventura/Wprss/Core/Licensing/Manager.php
CHANGED
@@ -2,10 +2,10 @@
|
|
2 |
|
3 |
namespace Aventura\Wprss\Core\Licensing;
|
4 |
|
5 |
-
use
|
6 |
-
use
|
7 |
-
use
|
8 |
-
use
|
9 |
|
10 |
/**
|
11 |
* Manager class for license handling.
|
@@ -15,85 +15,89 @@ use \Aventura\Wprss\Core\Licensing\Plugin\UpdaterException;
|
|
15 |
*/
|
16 |
class Manager {
|
17 |
|
18 |
-
|
19 |
-
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
|
30 |
// Lifetime expiration value
|
31 |
const EXPIRATION_LIFETIME = 'lifetime';
|
|
|
|
|
|
|
|
|
32 |
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
|
54 |
protected $_licenseKeysOptionName;
|
55 |
protected $_licenseStatusesOptionName;
|
56 |
protected $_expirationNoticePeriod;
|
57 |
protected $_defaultAuthorName;
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
if ( is_null($this->_updaterClass) ) {
|
81 |
return self::DEFAULT_UPDATER_CLASS;
|
82 |
}
|
83 |
|
84 |
-
|
85 |
-
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
|
98 |
|
99 |
/**
|
@@ -146,341 +150,377 @@ class Manager {
|
|
146 |
}
|
147 |
|
148 |
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
if ($expires === static::EXPIRATION_LIFETIME) {
|
360 |
return false;
|
361 |
}
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
|
454 |
try {
|
455 |
-
$licenseData = $this->api($storeUrl, array(
|
456 |
'edd_action' => $action,
|
457 |
'license' => $license,
|
458 |
'item_name' => $itemName,
|
459 |
));
|
460 |
}
|
461 |
catch ( RequestException $e ) {
|
462 |
-
|
463 |
-
|
464 |
}
|
465 |
catch ( ResponseException $e ) {
|
466 |
-
|
467 |
-
|
468 |
}
|
469 |
|
470 |
-
|
471 |
-
|
472 |
if (isset($licenseData->expires)) {
|
473 |
$license->setExpiry( $licenseData->expires );
|
474 |
}
|
475 |
-
|
476 |
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
|
485 |
|
486 |
/**
|
@@ -512,17 +552,17 @@ class Manager {
|
|
512 |
if ( $params['license'] ) $params['license'] = sanitize_text_field ( $params['license']);
|
513 |
if ( $params['item_name'] ) $params['item_name'] = sanitize_text_field ( $params['item_name']);
|
514 |
|
515 |
-
|
516 |
-
|
517 |
|
518 |
// Request failed
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
|
523 |
$body = wp_remote_retrieve_body( $response );
|
524 |
if ( empty( $body ) ) {
|
525 |
-
|
526 |
}
|
527 |
|
528 |
if ( ($licenseData = json_decode( $body )) === null ) {
|
@@ -541,47 +581,60 @@ class Manager {
|
|
541 |
* @return mixed The sanitized param value.
|
542 |
*/
|
543 |
public function sanitizeApiParams( &$value, $key ) {
|
544 |
-
|
545 |
-
}
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
585 |
|
586 |
|
587 |
/**
|
@@ -598,8 +651,8 @@ class Manager {
|
|
598 |
* @throws \Aventura\Wprss\Core\Licensing\Plugin\Updater\InstanceException If the updater instance class is not a valid updater class.
|
599 |
*/
|
600 |
public function newUpdater($url, $path, $params = array()) {
|
601 |
-
|
602 |
-
|
603 |
|
604 |
$defaultParams = array(
|
605 |
'author' => $this->getDefaultAuthorName(),
|
@@ -617,94 +670,94 @@ class Manager {
|
|
617 |
}
|
618 |
|
619 |
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
|
632 |
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
|
643 |
return $this;
|
644 |
-
|
645 |
|
646 |
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
|
654 |
return $this;
|
655 |
-
|
656 |
|
657 |
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
|
669 |
return $this;
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
|
686 |
return $this;
|
687 |
-
|
688 |
|
689 |
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
|
699 |
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
|
709 |
|
710 |
/**
|
@@ -751,78 +804,78 @@ class Manager {
|
|
751 |
}
|
752 |
|
753 |
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
$normalized[ $_addonId ]['addon_code'] = $_addonId;
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
$period = $this->getExpirationNoticePeriod();
|
819 |
if ( is_null( $period ) ) {
|
820 |
return null;
|
821 |
}
|
822 |
|
823 |
-
|
824 |
? time() + $period
|
825 |
: strtotime( sprintf( '+%s', $period ) );
|
826 |
-
|
827 |
|
828 |
}
|
2 |
|
3 |
namespace Aventura\Wprss\Core\Licensing;
|
4 |
|
5 |
+
use Aventura\Wprss\Core\Licensing\Api\RequestException;
|
6 |
+
use Aventura\Wprss\Core\Licensing\Api\ResponseException;
|
7 |
+
use Aventura\Wprss\Core\Licensing\License\Status;
|
8 |
+
use Aventura\Wprss\Core\Licensing\Plugin\UpdaterException;
|
9 |
|
10 |
/**
|
11 |
* Manager class for license handling.
|
15 |
*/
|
16 |
class Manager {
|
17 |
|
18 |
+
// The default updater class
|
19 |
+
const DEFAULT_UPDATER_CLASS = '\\Aventura\\Wprss\\Core\\Licensing\\Plugin\\Updater';
|
20 |
|
21 |
+
// Name of license keys option in DB
|
22 |
+
const DB_LICENSE_KEYS_OPTION_NAME = 'wprss_settings_license_keys';
|
23 |
+
// Name of license statuses option in DB
|
24 |
+
const DB_LICENSE_STATUSES_OPTION_NAME = 'wprss_settings_license_statuses';
|
25 |
+
// Regex pattern for keys in license option
|
26 |
+
const DB_LICENSE_KEYS_OPTION_PATTERN = '%s_license_key';
|
27 |
+
// Regex pattern for statuses in license option
|
28 |
+
const DB_LICENSE_STATUSES_OPTION_PATTERN = '%s_license_%s';
|
29 |
|
30 |
// Lifetime expiration value
|
31 |
const EXPIRATION_LIFETIME = 'lifetime';
|
32 |
+
// Addon ID suffix for the lifetime-variant licenses
|
33 |
+
const LIFETIME_ADDON_ID_SUFFIX = '_lf';
|
34 |
+
// The EDD SL item name pattern for lifetime variants
|
35 |
+
const LIFETIME_ITEM_NAME_PATTERN = '%s (Lifetime)';
|
36 |
|
37 |
+
/**
|
38 |
+
* License instance.
|
39 |
+
*
|
40 |
+
* @var array
|
41 |
+
*/
|
42 |
+
protected $_licenses;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* The class to use for updating addons.
|
46 |
+
*
|
47 |
+
* @var string
|
48 |
+
*/
|
49 |
+
protected $_updaterClass;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* The updater instances for the addons.
|
53 |
+
*
|
54 |
+
* @var array
|
55 |
+
*/
|
56 |
+
protected $_updaterInstances;
|
57 |
|
58 |
protected $_licenseKeysOptionName;
|
59 |
protected $_licenseStatusesOptionName;
|
60 |
protected $_expirationNoticePeriod;
|
61 |
protected $_defaultAuthorName;
|
62 |
|
63 |
+
/**
|
64 |
+
* Constructor.
|
65 |
+
*/
|
66 |
+
public function __construct() {
|
67 |
+
// Reset the updater instances
|
68 |
+
$this->_updaterInstances = array();
|
69 |
+
$this->_loadLicenses();
|
70 |
+
$this->_construct();
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Internal secondary constructor, used by classes that extend this class.
|
75 |
+
*/
|
76 |
+
protected function _construct() {}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Gets the name of the class used to update the addons.
|
80 |
+
*
|
81 |
+
* @return string
|
82 |
+
*/
|
83 |
+
public function getUpdaterClass() {
|
84 |
if ( is_null($this->_updaterClass) ) {
|
85 |
return self::DEFAULT_UPDATER_CLASS;
|
86 |
}
|
87 |
|
88 |
+
return $this->_updaterClass;
|
89 |
+
}
|
90 |
|
91 |
+
/**
|
92 |
+
* Sets the class used to update the addons.
|
93 |
+
*
|
94 |
+
* @param string $updaterClass The name of the updater class.
|
95 |
+
* @return self
|
96 |
+
*/
|
97 |
+
public function setUpdaterClass( $updaterClass ) {
|
98 |
+
$this->_updaterClass = $updaterClass;
|
99 |
+
return self;
|
100 |
+
}
|
101 |
|
102 |
|
103 |
/**
|
150 |
}
|
151 |
|
152 |
|
153 |
+
/**
|
154 |
+
* Gets a list of registered addons.
|
155 |
+
*
|
156 |
+
* @return array An assoc array containing addon IDs as array keys and the addon names as array values.
|
157 |
+
*/
|
158 |
+
public function getAddons() {
|
159 |
+
return wprss_get_addons();
|
160 |
+
}
|
161 |
+
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Gets all of the updater instances.
|
165 |
+
*
|
166 |
+
* Alias for self#getUpdaterInstance()
|
167 |
+
*
|
168 |
+
* @see self::getUpdaterInstance
|
169 |
+
* @uses self::getUpdaterInstance
|
170 |
+
* @return array
|
171 |
+
*/
|
172 |
+
public function getUpdaterInstances() {
|
173 |
+
return $this->getUpdaterInstance();
|
174 |
+
}
|
175 |
+
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Gets the updater instance for a single addon, or all the updater instances if no param or null is passed.#
|
179 |
+
*
|
180 |
+
* @param mixed $addonId The addon ID for which to return the updater instance, or null to return all instances. Default: null
|
181 |
+
* @return mixed An instance of \Aventura\Wprss\Core\Licensing\Plugin\UpdaterInterface if an addon ID is given, or an array of instances is null is given.
|
182 |
+
*/
|
183 |
+
public function getUpdaterInstance( $addonId = null ) {
|
184 |
+
return is_null($addonId)
|
185 |
+
? $this->_updaterInstances
|
186 |
+
: $this->_getUpdaterInstance($addonId);
|
187 |
+
}
|
188 |
+
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Internally used to get a single updater instance for a particular addon.
|
192 |
+
*
|
193 |
+
* @param string $addonId The addon ID.
|
194 |
+
* @return \Aventura\Wprss\Core\Licensing\Plugin\UpdaterInterface
|
195 |
+
*/
|
196 |
+
protected function _getUpdaterInstance( $addonId ) {
|
197 |
+
return $this->hasUpdaterInsantance($addonId)
|
198 |
+
? $this->_updaterInstances[$addonId]
|
199 |
+
: null;
|
200 |
+
}
|
201 |
+
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Checks if an updater instance exists for a specific addon.
|
205 |
+
*
|
206 |
+
* @param string $addonId The addon ID.
|
207 |
+
* @return boolean True if the updater instance exists, false if not.
|
208 |
+
*/
|
209 |
+
public function hasUpdaterInsantance($addonId) {
|
210 |
+
return isset($this->_updaterInstances[$addonId]);
|
211 |
+
}
|
212 |
+
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Sets the updater instance for an addon.
|
216 |
+
*
|
217 |
+
* @param string $addonId The addon ID.
|
218 |
+
* @param \Aventura\Wprss\Core\Licensing\Plugin\UpdaterInterface The updater instance.
|
219 |
+
*/
|
220 |
+
protected function _setUpdaterInstance($addonId, $instance) {
|
221 |
+
$this->_updaterInstances[ $addonId ] = $instance;
|
222 |
+
return $this;
|
223 |
+
}
|
224 |
+
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Creates a new license.
|
228 |
+
*
|
229 |
+
* This does not save the license to the database. You will need to call Manager::saveLicenses() to save to db.
|
230 |
+
*
|
231 |
+
* @param string $addonId The addon ID
|
232 |
+
* @return License The created license
|
233 |
+
*/
|
234 |
+
public function createLicense( $addonId ) {
|
235 |
+
return $this->_licenses[ $addonId ] = new License( array('addon_code' => $addonId) );
|
236 |
+
}
|
237 |
+
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Gets all license key settings.
|
241 |
+
*
|
242 |
+
* @return array
|
243 |
+
*/
|
244 |
+
public function getLicenses() {
|
245 |
+
return $this->_licenses;
|
246 |
+
}
|
247 |
+
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Gets the license key for a specific addon.
|
251 |
+
*
|
252 |
+
* @param string $addonId The addon id.
|
253 |
+
* @return License
|
254 |
+
*/
|
255 |
+
public function getLicense( $addonId ) {
|
256 |
+
if ( ! $this->licenseExists( $addonId ) ) {
|
257 |
+
return null;
|
258 |
+
}
|
259 |
+
return $this->_licenses[ $addonId ];
|
260 |
+
}
|
261 |
+
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Checks if an addon license key
|
265 |
+
*
|
266 |
+
* @param string $addonId The addon id
|
267 |
+
* @return boolean True if the license key for the given addon id exists, false if not.
|
268 |
+
*/
|
269 |
+
public function licenseExists( $addonId ) {
|
270 |
+
return isset( $this->_licenses[ $addonId ] );
|
271 |
+
}
|
272 |
+
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Gets all licenses with the given status.
|
276 |
+
*
|
277 |
+
* @param mixed $status The status to search for, or an array of statuses.
|
278 |
+
* @param boolean $negation If true, the method will search for licenses that do NOT have the given status.
|
279 |
+
* If false, the method will search for licenses with the given status.
|
280 |
+
* Default: false
|
281 |
+
* @return array An array of matching licenses. Array keys contain the addon IDs and array values contain the license objects.
|
282 |
+
*/
|
283 |
+
public function getLicensesWithStatus( $status, $negation = false ) {
|
284 |
+
$licenses = array();
|
285 |
+
foreach ( $this->_licenses as $_addonId => $_license ) {
|
286 |
+
$_isStatus = is_array($status)
|
287 |
+
? in_array($_license->getStatus())
|
288 |
+
: $_license->getStatus() === $status;
|
289 |
+
if ( $_isStatus xor $negation === true ) {
|
290 |
+
$licenses[ $_addonId ] = $_license;
|
291 |
+
}
|
292 |
+
}
|
293 |
+
return $licenses;
|
294 |
+
}
|
295 |
+
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Checks if a license with the given status exists, stopping at the first match.
|
299 |
+
*
|
300 |
+
* @param mixed $status The status to search for, or an array of statuses.
|
301 |
+
* @param boolean $negation If true, the method will search for licenses that do NOT have the given status.
|
302 |
+
* If false, the method will search for licenses with the given status.
|
303 |
+
* Default: false
|
304 |
+
* @return boolean True if a license with or without (depending on $negation) the given status exists, false otherwise.
|
305 |
+
*/
|
306 |
+
public function licenseWithStatusExists( $status, $negation = false ) {
|
307 |
+
return count( $this->getLicensesWithStatus( $status, $negation ) ) > 0;
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Gets inactive licenses.
|
313 |
+
*
|
314 |
+
* @uses self::getLicensesWithStatus
|
315 |
+
* @return array
|
316 |
+
*/
|
317 |
+
public function getInactiveLicenses() {
|
318 |
+
$licenses = array();
|
319 |
+
foreach ( $this->_licenses as $_addonId => $_license ) {
|
320 |
+
if ($_license->isInactive()) {
|
321 |
+
$licenses[ $_addonId ] = $_license;
|
322 |
+
}
|
323 |
+
}
|
324 |
+
return $licenses;
|
325 |
+
}
|
326 |
+
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Gets the licenses that are soon to be expired.
|
330 |
+
*
|
331 |
+
* @uses self::_calculateSteTimestamp To calculate the minimum date for classifying licenses as "soon-to-expire".
|
332 |
+
*
|
333 |
+
* @return array An assoc array with addon IDs as array keys and License instances as array values.
|
334 |
+
*/
|
335 |
+
public function getExpiringLicenses() {
|
336 |
+
// Calculate soon-to-expiry (ste) date
|
337 |
+
$ste = $this->getSteTimestamp();
|
338 |
+
// Prepare the list
|
339 |
+
$expiringLicences = array();
|
340 |
+
// Iterate all licenses
|
341 |
+
foreach ( $this->_licenses as $_addonId => $_license ) {
|
342 |
+
if ($this->isLicenseExpiring($_addonId)) {
|
343 |
+
$expiringLicences[ $_addonId ] = $_license;
|
344 |
+
}
|
345 |
+
}
|
346 |
+
return $expiringLicences;
|
347 |
+
}
|
348 |
+
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Checks if a license is about to expire, according to the expiration period.
|
352 |
+
*
|
353 |
+
* @param string $addonId The ID of the addon whose license is to be checked for expiry.
|
354 |
+
* @return boolean True if the addon's license is about to expire, false if the addon license does not exist or is not about to expire.
|
355 |
+
*/
|
356 |
+
public function isLicenseExpiring( $addonId ) {
|
357 |
+
if (!$this->licenseExists($addonId)) {
|
358 |
+
return false;
|
359 |
+
}
|
360 |
+
$license = $this->getLicense($addonId);
|
361 |
+
// Get expiry
|
362 |
+
$expires = $license->getExpiry();
|
363 |
if ($expires === static::EXPIRATION_LIFETIME) {
|
364 |
return false;
|
365 |
}
|
366 |
+
// Split using space and get first part only (date only)
|
367 |
+
$parts = explode( ' ', $expires );
|
368 |
+
$dateOnly = strtotime( $parts[0] );
|
369 |
+
// Check if the expiry date is zero, or is within the expiration notice period
|
370 |
+
return $dateOnly == 0 || $dateOnly < $this->getSteTimestamp();
|
371 |
+
}
|
372 |
+
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Checks if there are licenses that will soon expire.
|
376 |
+
*
|
377 |
+
* @uses self::_calculateSteTimestamp To calculate the minimum date for classifying licenses as "soon-to-expire".
|
378 |
+
*
|
379 |
+
* @return bool True if there are licenses that will soon expire, false otherwise.
|
380 |
+
*/
|
381 |
+
public function expiringLicensesExist() {
|
382 |
+
return count( $this->getExpiringLicenses() ) > 0;
|
383 |
+
}
|
384 |
+
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Activates an add-on's license.
|
388 |
+
*
|
389 |
+
* @uses self::sendDualApiRequest() Sends the request with $action set as 'activate_license'.
|
390 |
+
*
|
391 |
+
* @param string $addonId The ID of the addon.
|
392 |
+
* @param string $return What to return from the response.
|
393 |
+
* @return mixed
|
394 |
+
*/
|
395 |
+
public function activateLicense( $addonId, $return = 'license') {
|
396 |
+
return $this->sendDualApiRequest( $addonId, 'activate_license', $return );
|
397 |
+
}
|
398 |
+
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Deactivates an add-on's license.
|
402 |
+
*
|
403 |
+
* @uses self::sendDualApiRequest() Sends the request with $action set as 'deactivate_license'.
|
404 |
+
*
|
405 |
+
* @param string $addonId The ID of the addon.
|
406 |
+
* @param string $return What to return from the response.
|
407 |
+
* @return mixed
|
408 |
+
*/
|
409 |
+
public function deactivateLicense( $addonId, $return = 'license') {
|
410 |
+
return $this->sendDualApiRequest( $addonId, 'deactivate_license', $return );
|
411 |
+
}
|
412 |
+
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Checks an add-on's license's status with the server.
|
416 |
+
*
|
417 |
+
* @uses self::sendDualApiRequest() Sends the request with $action set as 'check_license'.
|
418 |
+
*
|
419 |
+
* @param string $addonId The ID of the addon.
|
420 |
+
* @param string $return What to return from the response.
|
421 |
+
* @return mixed
|
422 |
+
*/
|
423 |
+
public function checkLicense( $addonId, $return = 'license') {
|
424 |
+
return $this->sendDualApiRequest( $addonId, 'check_license', $return );
|
425 |
+
}
|
426 |
+
|
427 |
+
/**
|
428 |
+
* Calls the EDD Software Licensing API for a specified addon, falling back to the lifetime variant if required.
|
429 |
+
*
|
430 |
+
* @uses self::sendApiRequest To send the individual requests.
|
431 |
+
*
|
432 |
+
* @param string $addonId The ID of the addon
|
433 |
+
* @param string $action The action to perform on the license.
|
434 |
+
* @param string $return What to return from the response. If 'ALL', the entire license status object is returned,
|
435 |
+
* Otherwise, the property with name $return will be returned, or null if it doesn't exist.
|
436 |
+
* @return mixed
|
437 |
+
*/
|
438 |
+
public function sendDualApiRequest( $addonId, $action = 'check_license', $return = 'license' ) {
|
439 |
+
$data = $this->sendApiRequest( $addonId, $action, $return );
|
440 |
+
$status = is_object( $data ) ? $data->license : $data;
|
441 |
+
|
442 |
+
return ( in_array($status, ['invalid', 'item_name_mismatch', 'failed']) )
|
443 |
+
? $this->sendApiRequest( $addonId . static::LIFETIME_ADDON_ID_SUFFIX, $action, $return )
|
444 |
+
: $data;
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* Calls the EDD Software Licensing API to perform licensing tasks on the addon's store server.
|
449 |
+
*
|
450 |
+
* @param string $addonId The ID of the addon
|
451 |
+
* @param string $action The action to perform on the license.
|
452 |
+
* @param string $return What to return from the response. If 'ALL', the entire license status object is returned,
|
453 |
+
* Otherwise, the property with name $return will be returned, or null if it doesn't exist.
|
454 |
+
* @return mixed
|
455 |
+
*/
|
456 |
+
public function sendApiRequest( $addonId, $action = 'check_license', $return = 'license' ) {
|
457 |
+
$lfSuffix = static::LIFETIME_ADDON_ID_SUFFIX;
|
458 |
+
$lfSuffixLen = strlen($lfSuffix);
|
459 |
+
|
460 |
+
// Check if a lifetime license (ends with lifetime suffix)
|
461 |
+
$isLifetime = (substr($addonId, -$lfSuffixLen) === $lfSuffix);
|
462 |
+
// Get the "real" addon ID (without the lifetime suffix)
|
463 |
+
$addonRid = $isLifetime
|
464 |
+
? substr($addonId, 0, -$lfSuffixLen)
|
465 |
+
: $addonId;
|
466 |
+
|
467 |
+
// Get the license for the addon
|
468 |
+
$license = $this->getLicense( $addonRid );
|
469 |
+
// Use blank license if addon license does not exist
|
470 |
+
if ( $license === null ) {
|
471 |
+
$license = new License();
|
472 |
+
}
|
473 |
+
|
474 |
+
// Uppercase the addon ID
|
475 |
+
$addonUid = strtoupper( $addonRid );
|
476 |
+
|
477 |
+
// Prepare constants names
|
478 |
+
$itemNameConstant = sprintf( 'WPRSS_%s_SL_ITEM_NAME', $addonUid );
|
479 |
+
$storeUrlConstant = sprintf( 'WPRSS_%s_SL_STORE_URL', $addonUid );
|
480 |
+
|
481 |
+
// Check for existence of constants
|
482 |
+
if ( !defined($itemNameConstant) || !defined($storeUrlConstant) ) {
|
483 |
+
return null;
|
484 |
+
}
|
485 |
+
|
486 |
+
// Get constant values
|
487 |
+
$itemName = constant( $itemNameConstant );
|
488 |
+
$storeUrl = constant( $storeUrlConstant );
|
489 |
+
// Correct item name for lifetime variants
|
490 |
+
$itemName = ($isLifetime)
|
491 |
+
? sprintf(static::LIFETIME_ITEM_NAME_PATTERN, $itemName)
|
492 |
+
: $itemName;
|
493 |
|
494 |
try {
|
495 |
+
$licenseData = $this->api($storeUrl, $requestData = array(
|
496 |
'edd_action' => $action,
|
497 |
'license' => $license,
|
498 |
'item_name' => $itemName,
|
499 |
));
|
500 |
}
|
501 |
catch ( RequestException $e ) {
|
502 |
+
wprss_log( sprintf( 'Could not retrieve licensing data from "%1$s": %2$s', $storeUrl, $e->getMessage() ), __FUNCTION__, WPRSS_LOG_LEVEL_WARNING );
|
503 |
+
return $license->getStatus();
|
504 |
}
|
505 |
catch ( ResponseException $e ) {
|
506 |
+
wprss_log( sprintf( 'Received invalid licensing data from "%1$s": %2$s', $storeUrl, $e->getMessage() ), __FUNCTION__, WPRSS_LOG_LEVEL_WARNING );
|
507 |
+
return $license->getStatus();
|
508 |
}
|
509 |
|
510 |
+
// Update the DB option
|
511 |
+
$license->setStatus( $licenseData->license );
|
512 |
if (isset($licenseData->expires)) {
|
513 |
$license->setExpiry( $licenseData->expires );
|
514 |
}
|
515 |
+
$this->saveLicenseStatuses();
|
516 |
|
517 |
+
// Return the data
|
518 |
+
if ( strtoupper( $return ) === 'ALL' ) {
|
519 |
+
return $licenseData;
|
520 |
+
} else {
|
521 |
+
return isset( $licenseData->{$return} ) ? $licenseData->{$return} : null;
|
522 |
+
}
|
523 |
+
}
|
524 |
|
525 |
|
526 |
/**
|
552 |
if ( $params['license'] ) $params['license'] = sanitize_text_field ( $params['license']);
|
553 |
if ( $params['item_name'] ) $params['item_name'] = sanitize_text_field ( $params['item_name']);
|
554 |
|
555 |
+
// Send the request to the API
|
556 |
+
$response = wp_remote_post( add_query_arg( $params, $storeUrl ) );
|
557 |
|
558 |
// Request failed
|
559 |
+
if ( is_wp_error( $response ) ) {
|
560 |
+
throw new RequestException( $response->get_error_message() );
|
561 |
+
}
|
562 |
|
563 |
$body = wp_remote_retrieve_body( $response );
|
564 |
if ( empty( $body ) ) {
|
565 |
+
throw new ResponseException( 'Response body is empty' );
|
566 |
}
|
567 |
|
568 |
if ( ($licenseData = json_decode( $body )) === null ) {
|
581 |
* @return mixed The sanitized param value.
|
582 |
*/
|
583 |
public function sanitizeApiParams( &$value, $key ) {
|
584 |
+
$value = is_string($value)? urlencode($value) : $value;
|
585 |
+
}
|
586 |
+
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Creates an updater instance for an addon.
|
590 |
+
*
|
591 |
+
* @param string $id The ID of the addon.
|
592 |
+
* @param string $itemName The name of the addon as registered in EDD on our servers.
|
593 |
+
* @param string $version The current version of the addon.
|
594 |
+
* @param string $path The path to the addon's main file.
|
595 |
+
* @param string $storeUrl The URL of the server that handles the licensing and serves the updates.
|
596 |
+
* @return boolean True if the updater was initialized, false on failure due to an invalid license.
|
597 |
+
*/
|
598 |
+
public function initUpdaterInstance($id, $itemName, $version, $path, $storeUrl = WPRSS_SL_STORE_URL) {
|
599 |
+
// Generate the lifetime-variant item ID and name
|
600 |
+
$lfId = sprintf('%s%s', $id, static::LIFETIME_ADDON_ID_SUFFIX);
|
601 |
+
$lfItemName = sprintf('%s%s', $itemName, static::LIFETIME_ADDON_ID_SUFFIX);
|
602 |
+
|
603 |
+
// Prepare the data
|
604 |
+
$license = $this->getLicense( $id );
|
605 |
+
// If the addon doesn't have a license or the license is not valid, do not set the updater.
|
606 |
+
// Returns false to indicate this failure.
|
607 |
+
if ( $license === null || $license->getStatus() !== Status::VALID ) {
|
608 |
+
return false;
|
609 |
+
}
|
610 |
+
|
611 |
+
try {
|
612 |
+
// Create an updater
|
613 |
+
$updater = $this->newUpdater($storeUrl, $path, array(
|
614 |
+
'version' => $version, // current version number
|
615 |
+
'license' => $license, // license key (used get_option above to retrieve from DB)
|
616 |
+
'item_name' => $itemName, // name of this plugin
|
617 |
+
));
|
618 |
+
|
619 |
+
// Create an updater for the lifetime-variant of the license
|
620 |
+
$lfUpdater = $this->newUpdater($storeUrl, $path, array(
|
621 |
+
'version' => $version,
|
622 |
+
'license' => $license,
|
623 |
+
'item_name' => $lfItemName,
|
624 |
+
));
|
625 |
+
|
626 |
+
// Register the updater
|
627 |
+
$this->_setUpdaterInstance($id, $updater);
|
628 |
+
// Register the updater for the lifetime variant
|
629 |
+
$this->_setUpdaterInstance($lfId, $lfUpdater);
|
630 |
+
|
631 |
+
// Return true to indicate success
|
632 |
+
return true;
|
633 |
+
} catch ( UpdaterException $e ) {
|
634 |
+
wprss_log( sprintf( 'Could not create new updater:: %1$s', $e->getMessage() ), __FUNCTION__, WPRSS_LOG_LEVEL_WARNING );
|
635 |
+
return false;
|
636 |
+
}
|
637 |
+
}
|
638 |
|
639 |
|
640 |
/**
|
651 |
* @throws \Aventura\Wprss\Core\Licensing\Plugin\Updater\InstanceException If the updater instance class is not a valid updater class.
|
652 |
*/
|
653 |
public function newUpdater($url, $path, $params = array()) {
|
654 |
+
// Get the updater class
|
655 |
+
$updaterClass = $this->getUpdaterClass();
|
656 |
|
657 |
$defaultParams = array(
|
658 |
'author' => $this->getDefaultAuthorName(),
|
670 |
}
|
671 |
|
672 |
|
673 |
+
/**
|
674 |
+
* Normalizes the license status received by the API into the license statuses that we use locally in our code.
|
675 |
+
*
|
676 |
+
* @param string $status The status to normalize.
|
677 |
+
* @return string The normalized status.
|
678 |
+
*/
|
679 |
+
public function normalizeLicenseApiStatus( $status ) {
|
680 |
+
if ( $status === 'site_inactive' ) $status = 'inactive';
|
681 |
+
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
682 |
+
return $status;
|
683 |
+
}
|
684 |
|
685 |
|
686 |
+
/**
|
687 |
+
* Loads the licenses from db and prepares the internal licenses array
|
688 |
+
*/
|
689 |
+
protected function _loadLicenses() {
|
690 |
+
$this->_licenses = array();
|
691 |
+
$options = self::_normalizeLicenseOptions( $this->getLicenseKeysDbOption(), $this->getLicenseStatusesDbOption() );
|
692 |
+
foreach ( $options as $addonId => $_data ) {
|
693 |
+
$this->_licenses[ $addonId ] = new License( $_data );
|
694 |
+
}
|
695 |
|
696 |
return $this;
|
697 |
+
}
|
698 |
|
699 |
|
700 |
+
/**
|
701 |
+
* Saves the licenses and their statuses to the db.
|
702 |
+
*/
|
703 |
+
public function saveLicenses() {
|
704 |
+
$this->saveLicenseKeys();
|
705 |
+
$this->saveLicenseStatuses();
|
706 |
|
707 |
return $this;
|
708 |
+
}
|
709 |
|
710 |
|
711 |
+
/**
|
712 |
+
* Saves the license keys to the db.
|
713 |
+
*/
|
714 |
+
public function saveLicenseKeys() {
|
715 |
+
$keys = array();
|
716 |
+
foreach ( $this->_licenses as $_addonId => $_license ) {
|
717 |
+
$_key = sprintf( self::DB_LICENSE_KEYS_OPTION_PATTERN, $_addonId );
|
718 |
+
$keys[ $_key ] = $_license->getKey();
|
719 |
+
}
|
720 |
+
update_option( self::DB_LICENSE_KEYS_OPTION_NAME, $keys );
|
721 |
|
722 |
return $this;
|
723 |
+
}
|
724 |
+
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Saves the license statuses (and expirations) to the db.
|
728 |
+
*/
|
729 |
+
public function saveLicenseStatuses() {
|
730 |
+
$statuses = array();
|
731 |
+
foreach ( $this->_licenses as $_addonId => $_license ) {
|
732 |
+
$_status = sprintf( self::DB_LICENSE_STATUSES_OPTION_PATTERN, $_addonId, 'status' );
|
733 |
+
$_expires = sprintf( self::DB_LICENSE_STATUSES_OPTION_PATTERN, $_addonId, 'expires' );
|
734 |
+
$statuses[ $_status ] = $_license->getStatus();
|
735 |
+
$statuses[ $_expires ] = $_license->getExpiry();
|
736 |
+
}
|
737 |
+
update_option( self::DB_LICENSE_STATUSES_OPTION_NAME, $statuses );
|
738 |
|
739 |
return $this;
|
740 |
+
}
|
741 |
|
742 |
|
743 |
+
/**
|
744 |
+
* Retrieves the licenses keys db option.
|
745 |
+
*
|
746 |
+
* @return array
|
747 |
+
*/
|
748 |
+
public function getLicenseKeysDbOption() {
|
749 |
+
return get_option( $this->getLicenseKeysOptionName(), array() );
|
750 |
+
}
|
751 |
|
752 |
|
753 |
+
/**
|
754 |
+
* Retrieves the licenses statuses db option.
|
755 |
+
*
|
756 |
+
* @return array
|
757 |
+
*/
|
758 |
+
public function getLicenseStatusesDbOption() {
|
759 |
+
return get_option( $this->getLicenseStatusesOptionName(), array() );
|
760 |
+
}
|
761 |
|
762 |
|
763 |
/**
|
804 |
}
|
805 |
|
806 |
|
807 |
+
/**
|
808 |
+
* Normalizes the given db options into a format that the Manager can use to compile a list of License instances.
|
809 |
+
*
|
810 |
+
* @return array
|
811 |
+
*/
|
812 |
+
protected static function _normalizeLicenseOptions( $keys, $statuses ) {
|
813 |
+
// Prepare result array
|
814 |
+
$normalized = array();
|
815 |
+
// Prepare regex pattern outside of iterations
|
816 |
+
$licenseKeysOptionPattern = self::_formatStringToDbOptionPattern( self::DB_LICENSE_KEYS_OPTION_PATTERN );
|
817 |
+
$licenseStatusesOptionPattern = self::_formatStringToDbOptionPattern( self::DB_LICENSE_STATUSES_OPTION_PATTERN );
|
818 |
+
|
819 |
+
// Prepare the license keys into the normalized array
|
820 |
+
foreach ( $keys as $_key => $_value ) {
|
821 |
+
// Regex match for pattern of array keys
|
822 |
+
preg_match( $licenseKeysOptionPattern, $_key, $_matches );
|
823 |
+
if ( count( $_matches ) < 2 ) continue;
|
824 |
+
// Addon id is the first match (excluding whole string match at $_matches[0])
|
825 |
+
$_addonId = $_matches[1];
|
826 |
+
// check if entry for add-on exists in normalized array, otherwise create it
|
827 |
+
if ( ! isset( $normalized[ $_addonId ] ) )
|
828 |
+
$normalized[ $_addonId ] = array();
|
829 |
+
// Insert the license key inot the normalized array
|
830 |
+
$normalized[ $_addonId ]['key'] = $_value;
|
831 |
$normalized[ $_addonId ]['addon_code'] = $_addonId;
|
832 |
+
}
|
833 |
+
// Now iterate and insert the statuses
|
834 |
+
foreach ( $statuses as $_key => $_value ) {
|
835 |
+
// Regex match for pattern of array keys
|
836 |
+
preg_match( $licenseStatusesOptionPattern, $_key, $_matches );
|
837 |
+
// continue to next iteration if there are no matches
|
838 |
+
if ( count( $_matches ) < 3 ) continue;
|
839 |
+
// The addon ID: first match
|
840 |
+
$_addonId = $_matches[1];
|
841 |
+
// Property name: second match
|
842 |
+
$_property = $_matches[2];
|
843 |
+
// if entry for add-on doesn't exist in normalized array, continue
|
844 |
+
if ( ! isset( $normalized[ $_addonId ] ) ) continue;
|
845 |
+
// Add the property to the normalized array for the addon's entry
|
846 |
+
$normalized[ $_addonId ][ $_property ] = $_value;
|
847 |
+
}
|
848 |
+
|
849 |
+
return $normalized;
|
850 |
+
}
|
851 |
+
|
852 |
+
|
853 |
+
/**
|
854 |
+
* Converts the given format string into a regex pattern, replacing all instances of '%s' with
|
855 |
+
* '([^_]+)'. The pattern can be used by PHP regex functions to match db license options.
|
856 |
+
*
|
857 |
+
* @param string $formatString
|
858 |
+
* @return string
|
859 |
+
*/
|
860 |
+
protected static function _formatStringToDbOptionPattern( $formatString ) {
|
861 |
+
return sprintf( '/\\A%s\\Z/', str_replace( '%s', '([^_\s]+)', $formatString ) );
|
862 |
+
}
|
863 |
+
|
864 |
+
|
865 |
+
/**
|
866 |
+
* Calculates the "soon-to-expire" timestamp.
|
867 |
+
*
|
868 |
+
* @return integer The timestamp for a future date, for which addons whose license's expiry lies between this date and the present are considered "soon-to-expire".
|
869 |
+
*/
|
870 |
+
public function getSteTimestamp() {
|
871 |
$period = $this->getExpirationNoticePeriod();
|
872 |
if ( is_null( $period ) ) {
|
873 |
return null;
|
874 |
}
|
875 |
|
876 |
+
return is_numeric( $period )
|
877 |
? time() + $period
|
878 |
: strtotime( sprintf( '+%s', $period ) );
|
879 |
+
}
|
880 |
|
881 |
}
|
includes/Aventura/Wprss/Core/Licensing/Settings.php
CHANGED
@@ -12,39 +12,39 @@ use \WPRSS_MBString;
|
|
12 |
*/
|
13 |
class Settings {
|
14 |
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
|
49 |
/**
|
50 |
* Sets the license manager for this settings controller to use.
|
@@ -66,17 +66,17 @@ class Settings {
|
|
66 |
return $this->_manager;
|
67 |
}
|
68 |
|
69 |
-
|
70 |
-
|
71 |
*
|
72 |
* @return \Aventura\Wprss\Core\Licensing\Settings
|
73 |
-
|
74 |
-
|
75 |
$factory = wprss_core_container()->get(sprintf('%sfactory', WPRSS_SERVICE_ID_PREFIX));
|
76 |
$noticesComponent = wprss()->getAdminAjaxNotices();
|
77 |
|
78 |
-
|
79 |
-
|
80 |
$emptyLicenseNotice = $factory->make(sprintf('%saddon_empty_license', WPRSS_NOTICE_SERVICE_ID_PREFIX), array(
|
81 |
'addon_id' => $_addonId,
|
82 |
'addon_name' => $_addonName,
|
@@ -98,318 +98,325 @@ class Settings {
|
|
98 |
'year' => $_year
|
99 |
));
|
100 |
$noticesComponent->addNotice($expiringLicenseNotice);
|
101 |
-
|
102 |
|
103 |
return $this;
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
$manager = $this->getManager();
|
143 |
if ( !($license = $manager->getLicense( $args['addon'] )) ) {
|
144 |
return false;
|
145 |
}
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
|
183 |
return $this;
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
$manager = $this->getManager();
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
$manager = $this->getManager();
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
|
400 |
return $this;
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
|
415 |
}
|
12 |
*/
|
13 |
class Settings {
|
14 |
|
15 |
+
/**
|
16 |
+
* What to print in place of license code chars.
|
17 |
+
* This must not be a symbol that is considered to be a valid license key char.
|
18 |
+
*
|
19 |
+
* @since 4.6.10
|
20 |
+
*/
|
21 |
+
const LICENSE_KEY_MASK_CHAR = '•';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* How many characters of the license code to print as is.
|
25 |
+
* Use negative value to indicate that characters at the end of the key are excluded.
|
26 |
+
*
|
27 |
+
* @since 4.6.10
|
28 |
+
*/
|
29 |
+
const LICENSE_KEY_MASK_EXCLUDE_AMOUNT = -4;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* The Licensing Manager instance.
|
33 |
+
*
|
34 |
+
* @var Manager
|
35 |
+
*/
|
36 |
+
protected $_manager;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Constructor.
|
40 |
+
*/
|
41 |
+
public function __construct() {
|
42 |
+
$this->_setManager( wprss_licensing_get_manager() );
|
43 |
+
// Only load notices if on admin side
|
44 |
+
if ( is_main_site() && is_admin() ) {
|
45 |
+
$this->_initNotices();
|
46 |
+
}
|
47 |
+
}
|
48 |
|
49 |
/**
|
50 |
* Sets the license manager for this settings controller to use.
|
66 |
return $this->_manager;
|
67 |
}
|
68 |
|
69 |
+
/**
|
70 |
+
* Initializes the admin notices.
|
71 |
*
|
72 |
* @return \Aventura\Wprss\Core\Licensing\Settings
|
73 |
+
*/
|
74 |
+
protected function _initNotices() {
|
75 |
$factory = wprss_core_container()->get(sprintf('%sfactory', WPRSS_SERVICE_ID_PREFIX));
|
76 |
$noticesComponent = wprss()->getAdminAjaxNotices();
|
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,
|
98 |
'year' => $_year
|
99 |
));
|
100 |
$noticesComponent->addNotice($expiringLicenseNotice);
|
101 |
+
}
|
102 |
|
103 |
return $this;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Condition callback for the "invalid license notice".
|
108 |
+
*
|
109 |
+
* @return boolean True if the notice is to be shown, false if not.
|
110 |
+
*/
|
111 |
+
public function emptyLicenseKeyNoticeCondition( $args ) {
|
112 |
+
if ( ! isset( $args['addon'] ) ) {
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
$license = $this->getManager()->getLicense( $args['addon'] );
|
116 |
+
|
117 |
+
return is_null($license) || strlen( $license->getKey() ) === 0;
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Condition callback for the "inactive saved license" notice.
|
123 |
+
*
|
124 |
+
* @return boolean True if the notice is to be shown, false if not.
|
125 |
+
*/
|
126 |
+
public function savedInactiveLicenseNoticeCondition( $args ) {
|
127 |
+
if ( ! isset( $args['addon'] ) ) {
|
128 |
+
return false;
|
129 |
+
}
|
130 |
+
$license = $this->getManager()->getLicense( $args['addon'] );
|
131 |
+
return $license !== null && strlen( $license->getKey() ) > 0 && ! $license->isValid();
|
132 |
+
}
|
133 |
+
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Condition callback for the "soon to expire license" notice.
|
137 |
+
*
|
138 |
+
* @return boolean True if the notice is to be shown, false if not.
|
139 |
+
*/
|
140 |
+
public function soonToExpireLicenseNoticeCondition( $args ) {
|
141 |
+
if ( ! isset( $args['addon'] ) ) return false;
|
142 |
$manager = $this->getManager();
|
143 |
if ( !($license = $manager->getLicense( $args['addon'] )) ) {
|
144 |
return false;
|
145 |
}
|
146 |
+
return $license->isValid() && $manager->isLicenseExpiring($args['addon']);
|
147 |
+
}
|
148 |
+
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Registers the WordPress settings.
|
152 |
+
*/
|
153 |
+
public function registerSettings() {
|
154 |
+
// Iterate all addon IDs and register a settings section with 2 fields for each.
|
155 |
+
foreach( $this->getManager()->getAddons() as $_addonId => $_addonName ) {
|
156 |
+
// Settings Section
|
157 |
+
add_settings_section(
|
158 |
+
sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
|
159 |
+
sprintf( '%s %s', $_addonName, __( 'License', WPRSS_TEXT_DOMAIN ) ),
|
160 |
+
'__return_empty_string',
|
161 |
+
'wprss_settings_license_keys'
|
162 |
+
);
|
163 |
+
// License key field
|
164 |
+
add_settings_field(
|
165 |
+
sprintf( 'wprss_settings_%s_license', $_addonId ),
|
166 |
+
__( 'License Key', WPRSS_TEXT_DOMAIN ),
|
167 |
+
array( $this, 'renderLicenseKeyField' ),
|
168 |
+
'wprss_settings_license_keys',
|
169 |
+
sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
|
170 |
+
array( $_addonId )
|
171 |
+
);
|
172 |
+
// Activate license button
|
173 |
+
add_settings_field(
|
174 |
+
sprintf( 'wprss_settings_%s_activate_license', $_addonId ),
|
175 |
+
__( 'Activate License', WPRSS_TEXT_DOMAIN ),
|
176 |
+
array( $this, 'renderActivateLicenseButton' ),
|
177 |
+
'wprss_settings_license_keys',
|
178 |
+
sprintf( 'wprss_settings_%s_licenses_section', $_addonId ),
|
179 |
+
array( $_addonId )
|
180 |
+
);
|
181 |
+
}
|
182 |
|
183 |
return $this;
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Renders the license field for a particular add-on.
|
188 |
+
*
|
189 |
+
* @since 4.4.5
|
190 |
+
*/
|
191 |
+
public function renderLicenseKeyField( $args ) {
|
192 |
+
if ( count( $args ) < 1 ) return;
|
193 |
+
// Addon ID is the first arg
|
194 |
+
$addonId = $args[0];
|
195 |
+
// Get the addon's license
|
196 |
+
$license = $this->getManager()->getLicense( $addonId );
|
197 |
+
// Mask it - if the license exists
|
198 |
+
$displayedKey = is_null( $license )? '' : self::obfuscateLicenseKey( $license->getKey() );
|
199 |
+
// Render the markup ?>
|
200 |
+
<input id="wprss-<?php echo $addonId ?>-license-key" name="wprss_settings_license_keys[<?php echo $addonId ?>_license_key]"
|
201 |
+
class="wprss-license-input" type="text" value="<?php echo esc_attr( $displayedKey ) ?>" style="width: 300px;"
|
202 |
+
/>
|
203 |
+
<label class="description" for="wprss-<?php echo $addonId ?>-license-key">
|
204 |
+
<?php _e( 'Enter your license key', WPRSS_TEXT_DOMAIN ) ?>
|
205 |
+
</label><?php
|
206 |
+
}
|
207 |
+
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Masks a license key.
|
211 |
+
*
|
212 |
+
* @param string $licenseKey The license key to mask
|
213 |
+
* @param string $maskChar The masking character(s)
|
214 |
+
* @param integer $maskExcludeAmount The amount of characyers to exclude from the mask. If negative, the exluded characters will begin from the end of the string
|
215 |
+
* @return string The masked license key
|
216 |
+
*/
|
217 |
+
public static function obfuscateLicenseKey( $licenseKey, $maskChar = self::LICENSE_KEY_MASK_CHAR, $maskExcludeAmount = self::LICENSE_KEY_MASK_EXCLUDE_AMOUNT ) {
|
218 |
+
// Pre-calculate license key length
|
219 |
+
$licenseKeyLength = strlen( $licenseKey );
|
220 |
+
// In case the mask exclude amount is greater than the license key length
|
221 |
+
$actualMaskExcludeAmount = abs( $maskExcludeAmount ) > ( $licenseKeyLength - 1 )
|
222 |
+
? ( $licenseKeyLength - 1 ) * ( $maskExcludeAmount < 0 ? -1 : 1 ) // Making sure to preserve position of mask
|
223 |
+
: $maskExcludeAmount;
|
224 |
+
// How many chars to mask. Always at least one char will be masked.
|
225 |
+
$maskLength = $licenseKeyLength - abs( $actualMaskExcludeAmount );
|
226 |
+
// Create the mask
|
227 |
+
$mask = $maskLength > 0 ? str_repeat( $maskChar, $maskLength ) : '';
|
228 |
+
// The starting index: if negative mask exclude amount, start from the back. otherwise start from 0
|
229 |
+
$startIndex = $actualMaskExcludeAmount < 0 ? $maskLength : 0;
|
230 |
+
// Extract the excluded characters
|
231 |
+
$excludedChars = WPRSS_MBString::mb_substr( $licenseKey, $startIndex, abs( $actualMaskExcludeAmount ) );
|
232 |
+
// Generate the displayed key and return it
|
233 |
+
return sprintf( $actualMaskExcludeAmount > 0 ? '%1$s%2$s' : '%2$s%1$s', $excludedChars, $mask );
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Determines whether or not the license key in question is obfuscated.
|
238 |
+
*
|
239 |
+
* This is achieved by searching for the mask character in the key. Because the
|
240 |
+
* mask character cannot be a valid license character, the presence of at least
|
241 |
+
* one such character indicates that the key is obfuscated.
|
242 |
+
*
|
243 |
+
* @param string $key The license key in question.
|
244 |
+
* @param string $maskChar The masking character(s).
|
245 |
+
* @return bool Whether or not this key is obfuscated.
|
246 |
+
*/
|
247 |
+
public function isLicenseKeyObfuscated( $key, $maskChar = self::LICENSE_KEY_MASK_CHAR ) {
|
248 |
+
return WPRSS_MBString::mb_strpos( $key, $maskChar ) !== false;
|
249 |
+
}
|
250 |
+
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Invalidates the key if it is obfuscated, causing the saved version to be used.
|
254 |
+
* This meanst that the new key will not be saved, as it is considered then to be unchanged.
|
255 |
+
*
|
256 |
+
* @since 4.6.10
|
257 |
+
* @param bool $is_valid Indicates whether the key is currently considered to be valid.
|
258 |
+
* @param string $key The license key in question
|
259 |
+
* @return Whether or not the key is still to be considered valid.
|
260 |
+
*/
|
261 |
+
public function validateLicenseKeyForSave( $is_valid, $key ) {
|
262 |
+
if ( $this->isLicenseKeyObfuscated( $key ) )
|
263 |
+
return false;
|
264 |
+
|
265 |
+
return $is_valid;
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Renders the activate/deactivate license button for a particular add-on.
|
270 |
+
*
|
271 |
+
* @since 4.4.5
|
272 |
+
*/
|
273 |
+
public function renderActivateLicenseButton( $args ) {
|
274 |
+
$addonId = $args[0];
|
275 |
$manager = $this->getManager();
|
276 |
+
$data = $manager->checkLicense( $addonId, 'ALL' );
|
277 |
+
$status = is_string( $data ) ? $data : $data->license;
|
278 |
+
if ( $status === 'site_inactive' ) $status = 'inactive';
|
279 |
+
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
280 |
+
|
281 |
+
$valid = $status == 'valid';
|
282 |
+
$btnText = $valid ? 'Deactivate License' : 'Activate License';
|
283 |
+
$btnName = "wprss_{$addonId}_license_" . ( $valid? 'deactivate' : 'activate' );
|
284 |
+
$btnClass = "button-" . ( $valid ? 'deactivate' : 'activate' ) . "-license";
|
285 |
+
wp_nonce_field( "wprss_{$addonId}_license_nonce", "wprss_{$addonId}_license_nonce", false ); ?>
|
286 |
+
|
287 |
+
<input type="button" class="<?php echo $btnClass; ?> button-process-license button-secondary" name="<?php echo $btnName; ?>" value="<?php _e( $btnText, WPRSS_TEXT_DOMAIN ); ?>" />
|
288 |
+
<span id="wprss-<?php echo $addonId; ?>-license-status-text">
|
289 |
+
<strong><?php _e('Status', WPRSS_TEXT_DOMAIN); ?>:
|
290 |
+
<span class="wprss-<?php echo $addonId; ?>-license-<?php echo $status; ?>">
|
291 |
+
<?php _e( ucfirst($status), WPRSS_TEXT_DOMAIN ); ?>
|
292 |
+
<?php if ( $status === 'valid' ) : ?>
|
293 |
+
<i class="fa fa-check"></i>
|
294 |
+
<?php elseif( $status === 'invalid' || $status === 'expired' ): ?>
|
295 |
+
<i class="fa fa-times"></i>
|
296 |
+
<?php elseif( $status === 'inactive' ): ?>
|
297 |
+
<i class="fa fa-warning"></i>
|
298 |
+
<?php endif; ?>
|
299 |
+
</strong>
|
300 |
+
</span>
|
301 |
+
</span>
|
302 |
+
|
303 |
+
<p>
|
304 |
+
<?php
|
305 |
+
$license = $manager->getLicense( $addonId );
|
306 |
+
if ( $license !== null && !$license->isInvalid() && ($licenseKey = $license->getKey()) && !empty( $licenseKey ) ) :
|
307 |
+
if ( is_object( $data ) ) :
|
308 |
+
$currentActivations = $data->site_count;
|
309 |
+
$activationsLeft = $data->activations_left;
|
310 |
+
$activationsLimit = $data->license_limit;
|
311 |
+
$expires = $data->expires;
|
312 |
+
$expiresSpace = strpos($expires, ' ');
|
313 |
+
// if expiry has space, get only first word
|
314 |
+
$expires = ( $expiresSpace !== false ) ? substr( $expires, 0, $expiresSpace ) : $expires;
|
315 |
+
$expires = trim($expires);
|
316 |
+
// change lifetime expiry to never
|
317 |
+
$expires = ($expires === Manager::EXPIRATION_LIFETIME) ? __('never', WPRSS_TEXT_DOMAIN) : $expires;
|
318 |
+
|
319 |
+
// If the license key is garbage, don't show any of the data.
|
320 |
+
if ( !empty($data->payment_id) && !empty($data->license_limit ) ) :
|
321 |
+
?>
|
322 |
+
<small>
|
323 |
+
<?php if ( $status !== 'valid' && $activationsLeft === 0 ) : ?>
|
324 |
+
<?php $accountUrl = 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=' . $data->payment_id; ?>
|
325 |
+
<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>
|
326 |
+
<br/>
|
327 |
+
<?php endif; ?>
|
328 |
+
<?php if ( !empty($expires) && $expires !== 'never' && strtotime($expires) < strtotime("+2 weeks") ) : ?>
|
329 |
+
<?php $renewalUrl = esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $licenseKey); ?>
|
330 |
+
<a href="<?php echo $renewalUrl; ?>"><?php _e('Renew your license to continue receiving updates and support.', WPRSS_TEXT_DOMAIN); ?></a>
|
331 |
+
<br/>
|
332 |
+
<?php endif; ?>
|
333 |
+
<strong><?php _e('Activations', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
334 |
+
<?php echo $currentActivations.'/'.$activationsLimit; ?> (<?php echo $activationsLeft; ?> left)
|
335 |
+
<br/>
|
336 |
+
<?php if ( !empty($expires) ) : ?>
|
337 |
+
<strong><?php _e('Expires', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
338 |
+
<code><?php echo $expires; ?></code>
|
339 |
+
<br/>
|
340 |
+
<?php endif; ?>
|
341 |
+
<strong><?php _e('Registered to', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
342 |
+
<?php echo $data->customer_name; ?> (<code><?php echo $data->customer_email; ?></code>)
|
343 |
+
</small>
|
344 |
+
<?php endif; ?>
|
345 |
+
<?php else: ?>
|
346 |
+
<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>
|
347 |
+
<?php endif; ?>
|
348 |
+
<?php endif;
|
349 |
+
?>
|
350 |
+
</p>
|
351 |
+
|
352 |
+
<style type="text/css">
|
353 |
+
.wprss-<?php echo $addonId; ?>-license-valid {
|
354 |
+
color: green;
|
355 |
+
}
|
356 |
+
.wprss-<?php echo $addonId; ?>-license-invalid, .wprss-<?php echo $addonId; ?>-license-expired {
|
357 |
+
color: #b71919;
|
358 |
+
}
|
359 |
+
.wprss-<?php echo $addonId; ?>-license-inactive {
|
360 |
+
color: #d19e5b;
|
361 |
+
}
|
362 |
+
#wprss-<?php echo $addonId; ?>-license-status-text {
|
363 |
+
margin-left: 8px;
|
364 |
+
line-height: 27px;
|
365 |
+
vertical-align: middle;
|
366 |
+
}
|
367 |
+
</style>
|
368 |
+
<?php
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Handles the activation/deactivation process
|
373 |
+
*
|
374 |
+
* @since 1.0
|
375 |
+
*/
|
376 |
+
public function handleLicenseStatusChange() {
|
377 |
$manager = $this->getManager();
|
378 |
+
$addons = $manager->getAddons();
|
379 |
+
|
380 |
+
// Get for each registered addon
|
381 |
+
foreach( $addons as $id => $name ) {
|
382 |
+
// listen for our activate button to be clicked
|
383 |
+
if( isset( $_POST["wprss_{$id}_license_activate"] ) || isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
384 |
+
// run a quick security check
|
385 |
+
if ( ! check_admin_referer( "wprss_{$id}_license_nonce", "wprss_{$id}_license_nonce" ) )
|
386 |
+
continue; // get out if we didn't click the Activate/Deactivate button
|
387 |
+
}
|
388 |
+
|
389 |
+
// retrieve the license
|
390 |
+
$license = $manager->getLicense( $id );
|
391 |
+
|
392 |
+
// If the license is not saved in DB, but is included in POST
|
393 |
+
if ( $license == '' && ! empty( $_POST['wprss_settings_license_keys'][$id.'_license_key'] ) ) {
|
394 |
+
// Use the license given in POST
|
395 |
+
$license->setKey( $_POST['wprss_settings_license_keys'][ $id.'_license_key' ] );
|
396 |
+
}
|
397 |
+
|
398 |
+
// Prepare the action to take
|
399 |
+
if ( isset( $_POST["wprss_{$id}_license_activate"] ) ) {
|
400 |
+
$manager->activateLicense( $id );
|
401 |
+
}
|
402 |
+
elseif ( isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
403 |
+
$manager->deactivateLicense( $id );
|
404 |
+
}
|
405 |
+
}
|
406 |
|
407 |
return $this;
|
408 |
+
}
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Gets the HTML markup for the activate license button.
|
412 |
+
*
|
413 |
+
* @param string $addonId The ID of the addon for which the button will be related to.
|
414 |
+
* @return string The HTML markup of the button.
|
415 |
+
*/
|
416 |
+
public function getActivateLicenseButtonHtml( $addonId ) {
|
417 |
+
ob_start();
|
418 |
+
$this->renderActivateLicenseButton( array( $addonId ) );
|
419 |
+
return ob_get_clean();
|
420 |
+
}
|
421 |
|
422 |
}
|
nbproject/project.properties
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
include.path=${php.global.include.path}
|
2 |
+
php.version=PHP_53
|
3 |
+
source.encoding=UTF-8
|
4 |
+
src.dir=.
|
5 |
+
tags.asp=false
|
6 |
+
tags.short=false
|
7 |
+
web.root=.
|
nbproject/project.xml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project xmlns="http://www.netbeans.org/ns/project/1">
|
3 |
+
<type>org.netbeans.modules.php.project</type>
|
4 |
+
<configuration>
|
5 |
+
<data xmlns="http://www.netbeans.org/ns/php-project/1">
|
6 |
+
<name>WPRACORE</name>
|
7 |
+
</data>
|
8 |
+
</configuration>
|
9 |
+
</project>
|
readme.txt
CHANGED
@@ -1,100 +1,121 @@
|
|
1 |
=== WP RSS Aggregator ===
|
2 |
-
Contributors: RebelCode, jeangalea, Mekku, xedin.unknown,
|
3 |
Plugin URI: https://www.wprssaggregator.com
|
4 |
Tags: RSS import, RSS aggregator, autoblog, content curation, feed to post
|
5 |
-
Requires at least: 4.0
|
6 |
-
Tested up to:
|
7 |
-
Requires PHP: 5.3.9
|
8 |
-
Stable tag: 4.11.
|
9 |
License: GPLv3
|
10 |
|
11 |
-
WP RSS Aggregator is the
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
WP RSS Aggregator is the original and best plugin for easily importing, merging and displaying RSS and Atom feeds on your WordPress site. It's the most comprehensive and elegant RSS feed solution for WordPress.
|
16 |
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
[youtube https://www.youtube.com/watch?v=OgB3veegtz4]
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
*
|
25 |
-
*
|
26 |
-
*
|
27 |
-
*
|
28 |
-
*
|
29 |
-
*
|
30 |
-
*
|
31 |
-
*
|
32 |
-
*
|
33 |
-
* Open YouTube, DailyMotion and Vimeo videos directly.
|
34 |
-
* Create a [custom RSS feed](https://docs.wprssaggregator.com/custom-feed-url/) from imported feed items.
|
35 |
-
* Extendable via [action and filter hooks](https://docs.wprssaggregator.com/category/filters/).
|
36 |
* Integrated with the Simplepie library that comes with WordPress.
|
37 |
-
* Multilingual ready
|
|
|
|
|
38 |
|
39 |
-
|
40 |
|
41 |
-
|
42 |
|
43 |
-
|
44 |
|
45 |
-
|
46 |
|
47 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
-
|
50 |
|
51 |
-
* **[
|
|
|
|
|
52 |
|
53 |
-
|
54 |
|
55 |
-
|
56 |
|
57 |
-
*
|
|
|
58 |
|
59 |
-
|
60 |
|
61 |
-
|
|
|
|
|
62 |
|
63 |
-
|
64 |
|
65 |
-
|
66 |
|
67 |
-
|
68 |
|
69 |
-
|
70 |
-
We offer two free demo sites, each including a different set of add-ons:
|
71 |
|
72 |
-
|
73 |
|
74 |
-
The
|
75 |
|
76 |
-
|
|
|
77 |
|
78 |
-
|
79 |
-
* [Travel Blogger Community](http://travelbloggercommunity.com/)
|
80 |
-
* [Dribbble Me](http://dribbble.wprssaggregator.com/)
|
81 |
|
82 |
-
|
83 |
-
Our comprehensive [documentation](http://docs.wprssaggregator.com/) provides you with everything you need to install, set up and customise the plugin to your needs. You can also browse through a large number of [FAQs](http://docs.wprssaggregator.com/category/faqs/).
|
84 |
|
85 |
-
|
86 |
-
Support for the free version of WP RSS Aggregator is provided via the plugin repo support forum [here](https://wordpress.org/support/plugin/wp-rss-aggregator). Please read and follow the [Support Guidelines](https://wordpress.org/support/topic/support-guidelines-1/) before opening a new ticket.
|
87 |
|
88 |
-
|
89 |
|
90 |
-
|
91 |
|
92 |
-
|
93 |
|
94 |
-
|
95 |
|
96 |
-
|
|
|
|
|
97 |
* [WP Mayor](http://www.wpmayor.com/rss-feeds-review-wp-rss-aggregator/)
|
|
|
98 |
* [WPulsar](http://www.wpulsar.com/wp-rss-aggregator-plugin-feed-to-posts-keyword-filtering-review/)
|
99 |
* [Elegant Themes](https://www.elegantthemes.com/blog/tips-tricks/how-to-get-the-most-from-your-wordpress-rss-feed)
|
100 |
* [Cloudways](https://www.cloudways.com/blog/wp-rss-aggregator-plugin-rss-feed-importer-autoblogging-plugin/)
|
@@ -106,12 +127,6 @@ Terms & conditions can be found [here](https://www.wprssaggregator.com/terms-con
|
|
106 |
* [Torque](http://torquemag.io/wp-rss-aggregator-review-do-more-with-rss-feeds/)
|
107 |
* [IndexWP](http://www.indexwp.com/wp-rss-aggregator-plugin-review/)
|
108 |
|
109 |
-
### Translations ###
|
110 |
-
|
111 |
-
WP RSS Aggregator's core plugin is currently available in a number of languages, all of which can be seen [here](https://translate.wordpress.org/projects/wp-plugins/wp-rss-aggregator).
|
112 |
-
|
113 |
-
We are constantly working on adding new translations every month. Would you like to contribute to a translation for WP RSS Aggregator and its add-ons? [Click here to get started!](https://www.wprssaggregator.com/looking-for-translators/) We offer free licenses for our premium add-ons to all accepted translators.
|
114 |
-
|
115 |
== Installation ==
|
116 |
|
117 |
How to install and set up the core WP RSS Aggregator plugin:
|
@@ -223,26 +238,34 @@ If you need any further help you can [contact our support team](http://www.wprss
|
|
223 |
|
224 |
= Where can I find the documentation for the plugin? =
|
225 |
|
226 |
-
Our complete
|
227 |
|
228 |
== Screenshots ==
|
229 |
|
230 |
-
1. The default display
|
231 |
|
232 |
-
2. A customised display
|
233 |
|
234 |
-
3. Another customised display of the Feed Items using
|
235 |
|
236 |
-
4.
|
237 |
|
238 |
-
5.
|
239 |
|
240 |
-
6.
|
241 |
|
242 |
-
7. The
|
|
|
|
|
|
|
|
|
243 |
|
244 |
== Changelog ==
|
245 |
|
|
|
|
|
|
|
|
|
246 |
= 4.11.3 (2018-05-23) =
|
247 |
* Updated Help & Support page.
|
248 |
|
1 |
=== WP RSS Aggregator ===
|
2 |
+
Contributors: RebelCode, jeangalea, markzahra, Mekku, xedin.unknown,
|
3 |
Plugin URI: https://www.wprssaggregator.com
|
4 |
Tags: RSS import, RSS aggregator, autoblog, content curation, feed to post
|
5 |
+
Requires at least: 4.0 or higher
|
6 |
+
Tested up to: 5.0
|
7 |
+
Requires PHP: 5.3.9 or higher
|
8 |
+
Stable tag: 4.11.4
|
9 |
License: GPLv3
|
10 |
|
11 |
+
WP RSS Aggregator is the original & most popular WordPress solution for importing RSS feeds, auto-blogging, content curation & aggregation.
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
WP RSS Aggregator is the original and best plugin for easily importing, merging and displaying RSS and Atom feeds on your WordPress site. It's the most comprehensive and elegant RSS feed solution for WordPress.
|
16 |
|
17 |
+
WP RSS Aggregator and its premium add-ons are compatible with the new Gutenberg block editor introduced in the revolutionary WordPress 5.0. You can find more information about how the two work together [here](https://kb.wprssaggregator.com/article/444-gutenberg-compatibility-core-plugin).
|
18 |
+
|
19 |
+
== Engage Your Audience with Fresh Content ==
|
20 |
+
|
21 |
+
Content remains king, which is why we provide a reliable solution to share content from any source. Whether you're sharing your own content between sites or importing news, tutorials, videos & more, from top sources around the world, this is the solution you need.
|
22 |
+
|
23 |
+
* No limit on the number of sources you can import from.
|
24 |
+
* No limit on the number of items you can import.
|
25 |
+
* Automate the import of content on a schedule.
|
26 |
+
* Use our [shortcode](http://docs.wprssaggregator.com/shortcodes/) to easily display imported items.
|
27 |
|
28 |
[youtube https://www.youtube.com/watch?v=OgB3veegtz4]
|
29 |
|
30 |
+
== More Free Features ==
|
31 |
+
|
32 |
+
* Feed auto-discovery to add sources without the exact feed URL
|
33 |
+
* Open YouTube, DailyMotion and Vimeo videos directly
|
34 |
+
* Only import feed items with [unique titles](https://kb.wprssaggregator.com/article/52-general-settings) to prevent duplicates
|
35 |
+
* Limit the number of feed items stored to maintain performance
|
36 |
+
* Link the title and source name to the original source to give credit
|
37 |
+
* Choose to hide or show the date and source of each feed item
|
38 |
+
* Choose to display the original author's name with each feed item
|
39 |
+
* Style the shortcode display with [some basic CSS](https://kb.wprssaggregator.com/article/196-shortcode-styles-classes)
|
40 |
+
* Create a [custom RSS feed](https://kb.wprssaggregator.com/article/219-how-to-create-custom-rss-feeds) from imported feed items to use elsewhere
|
41 |
+
* Extendable via [action and filter hooks](https://kb.wprssaggregator.com/collection/72-for-developers)
|
|
|
|
|
|
|
42 |
* Integrated with the Simplepie library that comes with WordPress.
|
43 |
+
* Multilingual ready
|
44 |
+
|
45 |
+
[Click here to learn more about this free core plugin.](https://www.wprssaggregator.com/extension/core-plugin/)
|
46 |
|
47 |
+
== Take It A Step Further - Import Posts ==
|
48 |
|
49 |
+
Grow your WordPress site's credibility and popularity with related posts, job listings, Youtube videos, and more. Build news aggregators, curate articles from around the web, make money from affiliate links and much more.
|
50 |
|
51 |
+
[youtube https://www.youtube.com/watch?v=-2z_bNws2MM]
|
52 |
|
53 |
+
Our **[Advanced Feeds Bundle](https://www.wprssaggregator.com/extension/advanced-feeds-bundle/)** contains our 3 most popular premium add-ons which turn simple RSS feeds into full WordPress posts on your site.
|
54 |
|
55 |
+
* Import as Drafts or set posts to Publish upon import
|
56 |
+
* Import into Posts or any Custom Post Type on your site
|
57 |
+
* Automatically categorise imported posts and assign tags
|
58 |
+
* Import media within the content and set featured images
|
59 |
+
* Import the original author's details or assign a new one
|
60 |
+
* Add you own custom content before or after the imported posts
|
61 |
+
* Custom field mapping for the more experienced among you
|
62 |
+
* Extract unwanted elements from the original source
|
63 |
+
* Import only what you need with keyword, phrase and tag filters
|
64 |
+
* Connect to our premium full text service to automatically import the full content from sources that only provide excerpts or are missing images and/or videos
|
65 |
|
66 |
+
This bundle is a discounted grouping of all 3 add-ons, but each one can also be purchased separately. Get to know the add-ons individually:
|
67 |
|
68 |
+
* **[Feed to Post](https://www.wprssaggregator.com/extension/feed-to-post/)**
|
69 |
+
* **[Full Text RSS Feeds](https://www.wprssaggregator.com/extension/full-text-rss-feeds/)**
|
70 |
+
* **[Keyword Filtering](https://www.wprssaggregator.com/extension/keyword-filtering/)**
|
71 |
|
72 |
+
[Click here for a free demo of the above 3 add-ons.](http://demo.wprssaggregator.com/)
|
73 |
|
74 |
+
You may even use our content spinner integrations with the above add-ons to spin the content upon import.
|
75 |
|
76 |
+
* [WordAi Integration](https://www.wprssaggregator.com/extension/wordai/)
|
77 |
+
* [SpinnerChief Integration](https://www.wprssaggregator.com/extension/spinnerchief/)
|
78 |
|
79 |
+
Have a look at these incredible plugins in action:
|
80 |
|
81 |
+
* [WP News Desk](http://wpnewsdesk.com/)
|
82 |
+
* [Crypto Headlines](http://cryptoheadlines.com/)
|
83 |
+
* [Travel Blogger Community](http://travelbloggercommunity.com/)
|
84 |
|
85 |
+
You can even take things a step further by easily creating a mobile app using the imported content. [Check out this tutorial from MobiLoud](https://www.mobiloud.com/help/knowledge-base/wp-rss-aggregator-mobile-app/) on how we built an app for WP News Desk.
|
86 |
|
87 |
+
== ...Or Enhance Your Feed Lists (Shortcode) ==
|
88 |
|
89 |
+
Sometimes, the shortcode display of a list of feed items is all you need.
|
90 |
|
91 |
+
[youtube https://www.youtube.com/watch?v=Wx2gkEq3MxU]
|
|
|
92 |
|
93 |
+
If this is what you're looking for, we have two add-ons that will enhance your feed item display. For instance, you can include thumbnail images and excerpts alongside the titles for a more modern and colourful look.
|
94 |
|
95 |
+
If you're a more organised person, you can categorise the feed sources as you want. The shortcode parameter for categories then lets you display groups of feed sources together. So you can now set up a page dedicate to world news showing only sources which work for that, another for entertainment, another for sport, and so on.
|
96 |
|
97 |
+
* **[Excerpts & Thumbnails](https://www.wprssaggregator.com/extension/excerpts-thumbnails/)**
|
98 |
+
* **[Categories](https://www.wprssaggregator.com/extension/categories/)**
|
99 |
|
100 |
+
These two add-ons form part of a discounted bundle called the **[Simple Feeds Bundle](https://www.wprssaggregator.com/extension/simple-feeds-bundle/)** which also includes keyword filtering.
|
|
|
|
|
101 |
|
102 |
+
[Click here for a free demo of these 3 add-ons.](http://simple.wprssaggregator.com/)
|
|
|
103 |
|
104 |
+
== We Stand Behind What We Build ==
|
|
|
105 |
|
106 |
+
Our comprehensive [Knowledge Base](https://kb.wprssaggregator.com/) provides you with everything you need to install, set up and customise the plugin to your needs. You can also browse through a number of FAQs to get started.
|
107 |
|
108 |
+
If that doesn't do the trick, we provide support for the free version of WP RSS Aggregator via the plugin repo support forum [here](https://wordpress.org/support/plugin/wp-rss-aggregator), while for premium support (owners of valid premium add-on licenses) and pre-sales questions please contact us via our [premium support channel](https://www.wprssaggregator.com/contact/).
|
109 |
|
110 |
+
== Related Info ==
|
111 |
|
112 |
+
We provide a [Feed Creator](http://createfeed.wprssaggregator.com/) service that allows you to generate RSS feeds from any webpage, even if it doesn't have its own RSS feed.
|
113 |
|
114 |
+
Our terms & conditions can be found [here](https://www.wprssaggregator.com/terms-conditions/).
|
115 |
+
|
116 |
+
== High Praise From Trusted WordPress Leaders ==
|
117 |
* [WP Mayor](http://www.wpmayor.com/rss-feeds-review-wp-rss-aggregator/)
|
118 |
+
* [MobiLoud](https://www.mobiloud.com/blog/wordpress-rss-aggregator/)
|
119 |
* [WPulsar](http://www.wpulsar.com/wp-rss-aggregator-plugin-feed-to-posts-keyword-filtering-review/)
|
120 |
* [Elegant Themes](https://www.elegantthemes.com/blog/tips-tricks/how-to-get-the-most-from-your-wordpress-rss-feed)
|
121 |
* [Cloudways](https://www.cloudways.com/blog/wp-rss-aggregator-plugin-rss-feed-importer-autoblogging-plugin/)
|
127 |
* [Torque](http://torquemag.io/wp-rss-aggregator-review-do-more-with-rss-feeds/)
|
128 |
* [IndexWP](http://www.indexwp.com/wp-rss-aggregator-plugin-review/)
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
== Installation ==
|
131 |
|
132 |
How to install and set up the core WP RSS Aggregator plugin:
|
238 |
|
239 |
= Where can I find the documentation for the plugin? =
|
240 |
|
241 |
+
Our complete Knowledge Base with FAQs included can be found [here](https://kb.wprssaggregator.com/).
|
242 |
|
243 |
== Screenshots ==
|
244 |
|
245 |
+
1. The default shortcode display of Feed items imported by WP RSS Aggregator
|
246 |
|
247 |
+
2. A customised shortcode display using some simple [CSS](https://kb.wprssaggregator.com/article/196-shortcode-styles-classes)
|
248 |
|
249 |
+
3. Another customised display of the Feed Items using CSS styling, but with the [Excerpts & Thumbnails](http://www.wprssaggregator.com/extensions/excerpts-thumbnails) add-on installed
|
250 |
|
251 |
+
4. Posts imported using Feed to Post
|
252 |
|
253 |
+
5. Youtube videos imported using Feed to Post
|
254 |
|
255 |
+
6. Adding/Editing a feed source
|
256 |
|
257 |
+
7. The list of feed sources
|
258 |
+
|
259 |
+
8. The list of imported feeds items
|
260 |
+
|
261 |
+
9. The complete settings page for the core plugin
|
262 |
|
263 |
== Changelog ==
|
264 |
|
265 |
+
= 4.11.4 (2018-12-11) =
|
266 |
+
* Added handling of lifetime licenses.
|
267 |
+
* License renewal link and expiry are not shown if they are not applicable.
|
268 |
+
|
269 |
= 4.11.3 (2018-05-23) =
|
270 |
* Updated Help & Support page.
|
271 |
|
vendor/autoload.php
CHANGED
@@ -4,4 +4,4 @@
|
|
4 |
|
5 |
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
6 |
|
7 |
-
return
|
4 |
|
5 |
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
6 |
|
7 |
+
return ComposerAutoloaderInit76fb642d017d9d3b611d0406aaa162fd::getLoader();
|
vendor/composer/autoload_real.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
-
class
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit752c44451553503fd7f25c101a05281f
|
|
19 |
return self::$loader;
|
20 |
}
|
21 |
|
22 |
-
spl_autoload_register(array('
|
23 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
24 |
-
spl_autoload_unregister(array('
|
25 |
|
26 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
|
27 |
if ($useStaticLoader) {
|
28 |
require_once __DIR__ . '/autoload_static.php';
|
29 |
|
30 |
-
call_user_func(\Composer\Autoload\
|
31 |
} else {
|
32 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
33 |
foreach ($map as $namespace => $path) {
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInit76fb642d017d9d3b611d0406aaa162fd
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
19 |
return self::$loader;
|
20 |
}
|
21 |
|
22 |
+
spl_autoload_register(array('ComposerAutoloaderInit76fb642d017d9d3b611d0406aaa162fd', 'loadClassLoader'), true, true);
|
23 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
24 |
+
spl_autoload_unregister(array('ComposerAutoloaderInit76fb642d017d9d3b611d0406aaa162fd', 'loadClassLoader'));
|
25 |
|
26 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
|
27 |
if ($useStaticLoader) {
|
28 |
require_once __DIR__ . '/autoload_static.php';
|
29 |
|
30 |
+
call_user_func(\Composer\Autoload\ComposerStaticInit76fb642d017d9d3b611d0406aaa162fd::getInitializer($loader));
|
31 |
} else {
|
32 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
33 |
foreach ($map as $namespace => $path) {
|
vendor/composer/autoload_static.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
-
class
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'P' =>
|
@@ -55,8 +55,8 @@ class ComposerStaticInit752c44451553503fd7f25c101a05281f
|
|
55 |
public static function getInitializer(ClassLoader $loader)
|
56 |
{
|
57 |
return \Closure::bind(function () use ($loader) {
|
58 |
-
$loader->prefixLengthsPsr4 =
|
59 |
-
$loader->prefixDirsPsr4 =
|
60 |
|
61 |
}, null, ClassLoader::class);
|
62 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInit76fb642d017d9d3b611d0406aaa162fd
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'P' =>
|
55 |
public static function getInitializer(ClassLoader $loader)
|
56 |
{
|
57 |
return \Closure::bind(function () use ($loader) {
|
58 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInit76fb642d017d9d3b611d0406aaa162fd::$prefixLengthsPsr4;
|
59 |
+
$loader->prefixDirsPsr4 = ComposerStaticInit76fb642d017d9d3b611d0406aaa162fd::$prefixDirsPsr4;
|
60 |
|
61 |
}, null, ClassLoader::class);
|
62 |
}
|
wp-rss-aggregator.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: WP RSS Aggregator
|
4 |
* Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
|
5 |
* Description: Imports and aggregates multiple RSS Feeds.
|
6 |
-
* Version: 4.11.
|
7 |
* Author: RebelCode
|
8 |
* Author URI: https://www.wprssaggregator.com
|
9 |
* Text Domain: wprss
|
@@ -12,7 +12,7 @@
|
|
12 |
*/
|
13 |
|
14 |
/**
|
15 |
-
* Copyright (C) 2012-
|
16 |
*
|
17 |
* This program is free software: you can redistribute it and/or modify
|
18 |
* it under the terms of the GNU General Public License as published by
|
@@ -30,10 +30,10 @@
|
|
30 |
|
31 |
/**
|
32 |
* @package WPRSSAggregator
|
33 |
-
* @version 4.11.
|
34 |
* @since 1.0
|
35 |
* @author RebelCode
|
36 |
-
* @copyright Copyright (c) 2012-
|
37 |
* @link https://www.wprssaggregator.com/
|
38 |
* @license http://www.gnu.org/licenses/gpl.html
|
39 |
*/
|
@@ -44,7 +44,7 @@
|
|
44 |
|
45 |
// Set the version number of the plugin.
|
46 |
if( !defined( 'WPRSS_VERSION' ) )
|
47 |
-
define( 'WPRSS_VERSION', '4.11.
|
48 |
|
49 |
if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
|
50 |
define( 'WPRSS_WP_MIN_VERSION', '4.0', true );
|
3 |
* Plugin Name: WP RSS Aggregator
|
4 |
* Plugin URI: https://www.wprssaggregator.com/#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wpraplugin
|
5 |
* Description: Imports and aggregates multiple RSS Feeds.
|
6 |
+
* Version: 4.11.4
|
7 |
* Author: RebelCode
|
8 |
* Author URI: https://www.wprssaggregator.com
|
9 |
* Text Domain: wprss
|
12 |
*/
|
13 |
|
14 |
/**
|
15 |
+
* Copyright (C) 2012-2018 RebelCode Ltd.
|
16 |
*
|
17 |
* This program is free software: you can redistribute it and/or modify
|
18 |
* it under the terms of the GNU General Public License as published by
|
30 |
|
31 |
/**
|
32 |
* @package WPRSSAggregator
|
33 |
+
* @version 4.11.4
|
34 |
* @since 1.0
|
35 |
* @author RebelCode
|
36 |
+
* @copyright Copyright (c) 2012-2018, RebelCode Ltd.
|
37 |
* @link https://www.wprssaggregator.com/
|
38 |
* @license http://www.gnu.org/licenses/gpl.html
|
39 |
*/
|
44 |
|
45 |
// Set the version number of the plugin.
|
46 |
if( !defined( 'WPRSS_VERSION' ) )
|
47 |
+
define( 'WPRSS_VERSION', '4.11.4', true );
|
48 |
|
49 |
if( !defined( 'WPRSS_WP_MIN_VERSION' ) )
|
50 |
define( 'WPRSS_WP_MIN_VERSION', '4.0', true );
|