Version Description
(2015-03-09) = * Fixed bug: The "Force feed" option was being removed by the Feed to Post add-on.
Download this release
Release Info
Developer | Mekku |
Plugin | WP RSS Aggregator |
Version | 4.6.12 |
Comparing to | |
See all releases |
Code changes from version 4.6.11 to 4.6.12
- css/admin-3.8.css +46 -46
- css/admin-editor.css +105 -105
- css/admin-tracking-styles.css +41 -41
- css/styles.css +26 -26
- includes/OPML.php +132 -132
- includes/admin-addons.php +91 -91
- includes/admin-ajax-notice.php +140 -140
- includes/admin-dashboard.php +98 -98
- includes/admin-debugging.php +312 -312
- includes/admin-display.php +619 -619
- includes/admin-editor.php +146 -146
- includes/admin-heartbeat.php +77 -77
- includes/admin-help-metaboxes.php +70 -70
- includes/admin-help-settings.php +115 -115
- includes/admin-help.php +1107 -1107
- includes/admin-import-export.php +238 -238
- includes/admin-log.php +267 -267
- includes/admin-metaboxes.php +680 -665
- includes/admin-options.php +1132 -1132
- includes/admin-statistics.php +151 -151
- includes/admin-welcome.php +168 -168
- includes/admin.php +143 -143
- includes/cpt-feeds.php +100 -100
- includes/custom-feed.php +167 -167
- includes/deprecated-functions.php +83 -83
- includes/feed-blacklist.php +352 -352
- includes/feed-display.php +509 -509
- includes/feed-importing.php +660 -660
- includes/feed-processing.php +704 -704
- includes/feed-states.php +177 -177
- includes/image-caching.php +289 -289
- includes/libraries/EDD_licensing/EDD_SL_Plugin_Updater.php +313 -313
- includes/libraries/WordPress-Readme-Parser/ReadmeParser.php +328 -328
- includes/libraries/browser.php +1082 -1082
- includes/libraries/php-markdown/markdown.php +2931 -2931
- includes/licensing.php +771 -771
- includes/misc-functions.php +0 -308
css/admin-3.8.css
CHANGED
@@ -1,47 +1,47 @@
|
|
1 |
-
#menu-posts-wprss_feed .menu-icon-post div.wp-menu-image:before {
|
2 |
-
content: "\f303" !important;
|
3 |
-
}
|
4 |
-
.welcome-page-tile {
|
5 |
-
display: inline-block;
|
6 |
-
padding: 15px 0;
|
7 |
-
margin: 15px 0;
|
8 |
-
width: 30%;
|
9 |
-
text-align: left;
|
10 |
-
vertical-align: top;
|
11 |
-
box-sizing: border-box;
|
12 |
-
-moz-box-sizing: border-box;
|
13 |
-
}
|
14 |
-
.welcome-page-tile:first-child {
|
15 |
-
margin-left: 0;
|
16 |
-
}
|
17 |
-
.welcome-page-tile:last-child {
|
18 |
-
margin-right: 0;
|
19 |
-
}
|
20 |
-
.welcome-page-tile > h4 {
|
21 |
-
margin: 1.4em 0 .6em;
|
22 |
-
font-size: 1.2em;
|
23 |
-
}
|
24 |
-
.welcome-page-tile > p {
|
25 |
-
margin: 0;
|
26 |
-
}
|
27 |
-
.wprss-about-text {
|
28 |
-
color: #777;
|
29 |
-
line-height: 1.6em;
|
30 |
-
margin: 15px 0;
|
31 |
-
font-size: 1.2em;
|
32 |
-
}
|
33 |
-
|
34 |
-
#check-out-addons {
|
35 |
-
margin-top: 15px;
|
36 |
-
}
|
37 |
-
|
38 |
-
/* WP 3.8+ Settings Page */
|
39 |
-
|
40 |
-
body.wprss_feed_page_wprss-aggregator-settings .wrap h3 {
|
41 |
-
font-size: 1.5em;
|
42 |
-
margin-top: 1.8em;
|
43 |
-
margin-bottom: 0.6em;
|
44 |
-
}
|
45 |
-
body.wprss_feed_page_wprss-aggregator-settings .wrap h3 + p {
|
46 |
-
margin-top: 0.4em;
|
47 |
}
|
1 |
+
#menu-posts-wprss_feed .menu-icon-post div.wp-menu-image:before {
|
2 |
+
content: "\f303" !important;
|
3 |
+
}
|
4 |
+
.welcome-page-tile {
|
5 |
+
display: inline-block;
|
6 |
+
padding: 15px 0;
|
7 |
+
margin: 15px 0;
|
8 |
+
width: 30%;
|
9 |
+
text-align: left;
|
10 |
+
vertical-align: top;
|
11 |
+
box-sizing: border-box;
|
12 |
+
-moz-box-sizing: border-box;
|
13 |
+
}
|
14 |
+
.welcome-page-tile:first-child {
|
15 |
+
margin-left: 0;
|
16 |
+
}
|
17 |
+
.welcome-page-tile:last-child {
|
18 |
+
margin-right: 0;
|
19 |
+
}
|
20 |
+
.welcome-page-tile > h4 {
|
21 |
+
margin: 1.4em 0 .6em;
|
22 |
+
font-size: 1.2em;
|
23 |
+
}
|
24 |
+
.welcome-page-tile > p {
|
25 |
+
margin: 0;
|
26 |
+
}
|
27 |
+
.wprss-about-text {
|
28 |
+
color: #777;
|
29 |
+
line-height: 1.6em;
|
30 |
+
margin: 15px 0;
|
31 |
+
font-size: 1.2em;
|
32 |
+
}
|
33 |
+
|
34 |
+
#check-out-addons {
|
35 |
+
margin-top: 15px;
|
36 |
+
}
|
37 |
+
|
38 |
+
/* WP 3.8+ Settings Page */
|
39 |
+
|
40 |
+
body.wprss_feed_page_wprss-aggregator-settings .wrap h3 {
|
41 |
+
font-size: 1.5em;
|
42 |
+
margin-top: 1.8em;
|
43 |
+
margin-bottom: 0.6em;
|
44 |
+
}
|
45 |
+
body.wprss_feed_page_wprss-aggregator-settings .wrap h3 + p {
|
46 |
+
margin-top: 0.4em;
|
47 |
}
|
css/admin-editor.css
CHANGED
@@ -1,106 +1,106 @@
|
|
1 |
-
/* EDITOR BUTTON AND DIALOG STYLES */
|
2 |
-
|
3 |
-
#wprss-overlay {
|
4 |
-
position: fixed;
|
5 |
-
top: 0;
|
6 |
-
left: 0;
|
7 |
-
right: 0;
|
8 |
-
bottom: 0;
|
9 |
-
background: rgba(0,0,0,0.6);
|
10 |
-
z-index: 1000;
|
11 |
-
}
|
12 |
-
|
13 |
-
#wprss-editor-dialog {
|
14 |
-
position: absolute;
|
15 |
-
top: 0;
|
16 |
-
bottom: 0;
|
17 |
-
left: 0;
|
18 |
-
right: 0;
|
19 |
-
width: 500px;
|
20 |
-
height: 450px;
|
21 |
-
margin: auto;
|
22 |
-
}
|
23 |
-
|
24 |
-
.wprss-dialog-header {
|
25 |
-
background: #464646;
|
26 |
-
position: absolute;
|
27 |
-
top: 0;
|
28 |
-
left: 0;
|
29 |
-
right: 0;
|
30 |
-
height: 30px;
|
31 |
-
}
|
32 |
-
|
33 |
-
.wprss-dialog-header h1 {
|
34 |
-
color: #ddd;
|
35 |
-
text-shadow: rgb(68, 68, 68) 0px -1px 0px;
|
36 |
-
font-size: 16px;
|
37 |
-
font-weight: normal;
|
38 |
-
margin: 7px 0 15px 6px;
|
39 |
-
}
|
40 |
-
|
41 |
-
.wprss-dialog-header .close-btn {
|
42 |
-
position: absolute;
|
43 |
-
top: 4px;
|
44 |
-
right: 10px;
|
45 |
-
color: #ccc;
|
46 |
-
font-size: 18px;
|
47 |
-
font-weight: bold;
|
48 |
-
padding: 0px 6px 2px;
|
49 |
-
border-radius: 20px;
|
50 |
-
cursor: pointer;
|
51 |
-
}
|
52 |
-
.wprss-dialog-header .close-btn:hover {
|
53 |
-
background: white;
|
54 |
-
color: black;
|
55 |
-
}
|
56 |
-
|
57 |
-
|
58 |
-
.wprss-dialog-inside {
|
59 |
-
position: absolute;
|
60 |
-
top: 30px;
|
61 |
-
bottom: 0;
|
62 |
-
left: 0;
|
63 |
-
right: 0;
|
64 |
-
overflow: auto;
|
65 |
-
}
|
66 |
-
|
67 |
-
.wprss-dialog-inside table {
|
68 |
-
position: absolute;
|
69 |
-
display: inline-block;
|
70 |
-
top: 0;
|
71 |
-
left: 0;
|
72 |
-
right: 0;
|
73 |
-
height: auto;
|
74 |
-
padding: 10px;
|
75 |
-
box-sizing: border-box;
|
76 |
-
-moz-box-sizing: border-box;
|
77 |
-
}
|
78 |
-
|
79 |
-
.wprss-dialog-inside table tr td:first-child {
|
80 |
-
font-weight: bold;
|
81 |
-
}
|
82 |
-
|
83 |
-
|
84 |
-
#wprss-dialog-sources-container {
|
85 |
-
margin-top: 10px;
|
86 |
-
}
|
87 |
-
|
88 |
-
#wprss-dialog-feed-source-list,
|
89 |
-
#wprss-dialog-exclude-list {
|
90 |
-
min-width: 100px;
|
91 |
-
min-height: 100px;
|
92 |
-
}
|
93 |
-
|
94 |
-
#wprss-dialog-exclude-row td p:first-child {
|
95 |
-
margin-top: 0;
|
96 |
-
}
|
97 |
-
|
98 |
-
#wprss-dialog-exclude-label {
|
99 |
-
vertical-align: top;
|
100 |
-
}
|
101 |
-
|
102 |
-
#validate-feed-link {
|
103 |
-
font-size: 0.85em;
|
104 |
-
text-decoration: none;
|
105 |
-
margin-left: 3px;
|
106 |
}
|
1 |
+
/* EDITOR BUTTON AND DIALOG STYLES */
|
2 |
+
|
3 |
+
#wprss-overlay {
|
4 |
+
position: fixed;
|
5 |
+
top: 0;
|
6 |
+
left: 0;
|
7 |
+
right: 0;
|
8 |
+
bottom: 0;
|
9 |
+
background: rgba(0,0,0,0.6);
|
10 |
+
z-index: 1000;
|
11 |
+
}
|
12 |
+
|
13 |
+
#wprss-editor-dialog {
|
14 |
+
position: absolute;
|
15 |
+
top: 0;
|
16 |
+
bottom: 0;
|
17 |
+
left: 0;
|
18 |
+
right: 0;
|
19 |
+
width: 500px;
|
20 |
+
height: 450px;
|
21 |
+
margin: auto;
|
22 |
+
}
|
23 |
+
|
24 |
+
.wprss-dialog-header {
|
25 |
+
background: #464646;
|
26 |
+
position: absolute;
|
27 |
+
top: 0;
|
28 |
+
left: 0;
|
29 |
+
right: 0;
|
30 |
+
height: 30px;
|
31 |
+
}
|
32 |
+
|
33 |
+
.wprss-dialog-header h1 {
|
34 |
+
color: #ddd;
|
35 |
+
text-shadow: rgb(68, 68, 68) 0px -1px 0px;
|
36 |
+
font-size: 16px;
|
37 |
+
font-weight: normal;
|
38 |
+
margin: 7px 0 15px 6px;
|
39 |
+
}
|
40 |
+
|
41 |
+
.wprss-dialog-header .close-btn {
|
42 |
+
position: absolute;
|
43 |
+
top: 4px;
|
44 |
+
right: 10px;
|
45 |
+
color: #ccc;
|
46 |
+
font-size: 18px;
|
47 |
+
font-weight: bold;
|
48 |
+
padding: 0px 6px 2px;
|
49 |
+
border-radius: 20px;
|
50 |
+
cursor: pointer;
|
51 |
+
}
|
52 |
+
.wprss-dialog-header .close-btn:hover {
|
53 |
+
background: white;
|
54 |
+
color: black;
|
55 |
+
}
|
56 |
+
|
57 |
+
|
58 |
+
.wprss-dialog-inside {
|
59 |
+
position: absolute;
|
60 |
+
top: 30px;
|
61 |
+
bottom: 0;
|
62 |
+
left: 0;
|
63 |
+
right: 0;
|
64 |
+
overflow: auto;
|
65 |
+
}
|
66 |
+
|
67 |
+
.wprss-dialog-inside table {
|
68 |
+
position: absolute;
|
69 |
+
display: inline-block;
|
70 |
+
top: 0;
|
71 |
+
left: 0;
|
72 |
+
right: 0;
|
73 |
+
height: auto;
|
74 |
+
padding: 10px;
|
75 |
+
box-sizing: border-box;
|
76 |
+
-moz-box-sizing: border-box;
|
77 |
+
}
|
78 |
+
|
79 |
+
.wprss-dialog-inside table tr td:first-child {
|
80 |
+
font-weight: bold;
|
81 |
+
}
|
82 |
+
|
83 |
+
|
84 |
+
#wprss-dialog-sources-container {
|
85 |
+
margin-top: 10px;
|
86 |
+
}
|
87 |
+
|
88 |
+
#wprss-dialog-feed-source-list,
|
89 |
+
#wprss-dialog-exclude-list {
|
90 |
+
min-width: 100px;
|
91 |
+
min-height: 100px;
|
92 |
+
}
|
93 |
+
|
94 |
+
#wprss-dialog-exclude-row td p:first-child {
|
95 |
+
margin-top: 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
#wprss-dialog-exclude-label {
|
99 |
+
vertical-align: top;
|
100 |
+
}
|
101 |
+
|
102 |
+
#validate-feed-link {
|
103 |
+
font-size: 0.85em;
|
104 |
+
text-decoration: none;
|
105 |
+
margin-left: 3px;
|
106 |
}
|
css/admin-tracking-styles.css
CHANGED
@@ -1,42 +1,42 @@
|
|
1 |
-
#wprss_tracking_notice {
|
2 |
-
position: fixed;
|
3 |
-
display: inline-block;
|
4 |
-
|
5 |
-
top: 45px;
|
6 |
-
left: 50%;
|
7 |
-
|
8 |
-
width: 300px;
|
9 |
-
height: auto;
|
10 |
-
padding: 40px 10px 10px;
|
11 |
-
margin-left: -150px;
|
12 |
-
|
13 |
-
background: white;
|
14 |
-
border: 1px solid #ccc;
|
15 |
-
border-radius: 3px;
|
16 |
-
box-shadow: 0px 0px 6px rgba(0,0,0,0.2);
|
17 |
-
z-index: 20000;
|
18 |
-
|
19 |
-
box-sizing: border-box;
|
20 |
-
-moz-box-sizing: border-box;
|
21 |
-
-o-box-sizing: border-box;
|
22 |
-
}
|
23 |
-
|
24 |
-
#wprss_tracking_notice > p {
|
25 |
-
margin: 0;
|
26 |
-
}
|
27 |
-
#wprss_tracking_notice > p:first-child {
|
28 |
-
position: absolute;
|
29 |
-
top: 0;
|
30 |
-
left: 0;
|
31 |
-
right: 0;
|
32 |
-
padding: 6px 10px;
|
33 |
-
font-weight: bold;
|
34 |
-
background: #008BC2;
|
35 |
-
color: white;
|
36 |
-
}
|
37 |
-
|
38 |
-
#wprss_tracking_notice > p:nth-child(2) {
|
39 |
-
padding-bottom: 5px;
|
40 |
-
margin-bottom: 12px;
|
41 |
-
border-bottom: 1px solid #ccc;
|
42 |
}
|
1 |
+
#wprss_tracking_notice {
|
2 |
+
position: fixed;
|
3 |
+
display: inline-block;
|
4 |
+
|
5 |
+
top: 45px;
|
6 |
+
left: 50%;
|
7 |
+
|
8 |
+
width: 300px;
|
9 |
+
height: auto;
|
10 |
+
padding: 40px 10px 10px;
|
11 |
+
margin-left: -150px;
|
12 |
+
|
13 |
+
background: white;
|
14 |
+
border: 1px solid #ccc;
|
15 |
+
border-radius: 3px;
|
16 |
+
box-shadow: 0px 0px 6px rgba(0,0,0,0.2);
|
17 |
+
z-index: 20000;
|
18 |
+
|
19 |
+
box-sizing: border-box;
|
20 |
+
-moz-box-sizing: border-box;
|
21 |
+
-o-box-sizing: border-box;
|
22 |
+
}
|
23 |
+
|
24 |
+
#wprss_tracking_notice > p {
|
25 |
+
margin: 0;
|
26 |
+
}
|
27 |
+
#wprss_tracking_notice > p:first-child {
|
28 |
+
position: absolute;
|
29 |
+
top: 0;
|
30 |
+
left: 0;
|
31 |
+
right: 0;
|
32 |
+
padding: 6px 10px;
|
33 |
+
font-weight: bold;
|
34 |
+
background: #008BC2;
|
35 |
+
color: white;
|
36 |
+
}
|
37 |
+
|
38 |
+
#wprss_tracking_notice > p:nth-child(2) {
|
39 |
+
padding-bottom: 5px;
|
40 |
+
margin-bottom: 12px;
|
41 |
+
border-bottom: 1px solid #ccc;
|
42 |
}
|
css/styles.css
CHANGED
@@ -1,27 +1,27 @@
|
|
1 |
-
li.feed-item { margin-bottom: 10px; }
|
2 |
-
|
3 |
-
.thumbnail-excerpt {
|
4 |
-
overflow:hidden;
|
5 |
-
margin-bottom: 5px;
|
6 |
-
}
|
7 |
-
|
8 |
-
.thumbnail-excerpt img {
|
9 |
-
max-width:100%; float:left; margin-top: 0.5em; margin-right:10px;
|
10 |
-
}
|
11 |
-
|
12 |
-
.green {
|
13 |
-
color: #0BD600;
|
14 |
-
}
|
15 |
-
|
16 |
-
.nav-links {
|
17 |
-
overflow: hidden;
|
18 |
-
margin-bottom: 20px;
|
19 |
-
}
|
20 |
-
|
21 |
-
div.wprss-feed-meta > span {
|
22 |
-
font-size: 90%;
|
23 |
-
clear: both;
|
24 |
-
}
|
25 |
-
div.wprss-feed-meta > span:not(:last-child):after {
|
26 |
-
content: ' | ';
|
27 |
}
|
1 |
+
li.feed-item { margin-bottom: 10px; }
|
2 |
+
|
3 |
+
.thumbnail-excerpt {
|
4 |
+
overflow:hidden;
|
5 |
+
margin-bottom: 5px;
|
6 |
+
}
|
7 |
+
|
8 |
+
.thumbnail-excerpt img {
|
9 |
+
max-width:100%; float:left; margin-top: 0.5em; margin-right:10px;
|
10 |
+
}
|
11 |
+
|
12 |
+
.green {
|
13 |
+
color: #0BD600;
|
14 |
+
}
|
15 |
+
|
16 |
+
.nav-links {
|
17 |
+
overflow: hidden;
|
18 |
+
margin-bottom: 20px;
|
19 |
+
}
|
20 |
+
|
21 |
+
div.wprss-feed-meta > span {
|
22 |
+
font-size: 90%;
|
23 |
+
clear: both;
|
24 |
+
}
|
25 |
+
div.wprss-feed-meta > span:not(:last-child):after {
|
26 |
+
content: ' | ';
|
27 |
}
|
includes/OPML.php
CHANGED
@@ -1,132 +1,132 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* The WPRSS_OPML Class represents an OPML document.
|
5 |
-
* It is constructed using a file, which it parses upon creation.
|
6 |
-
*
|
7 |
-
* @since 3.3
|
8 |
-
* @package WPRSSAggregator
|
9 |
-
*/
|
10 |
-
class WPRSS_OPML {
|
11 |
-
|
12 |
-
|
13 |
-
public $file;
|
14 |
-
public $head;
|
15 |
-
public $body;
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Constructor: Parses the given XML file as an OPML
|
19 |
-
*
|
20 |
-
* @since 3.3
|
21 |
-
* @param $file The file to be parsed into a WPRSS_OPML object
|
22 |
-
*/
|
23 |
-
public function __construct( $file ) {
|
24 |
-
// Initialize Properties
|
25 |
-
$this->file = $file;
|
26 |
-
$this->head = array();
|
27 |
-
$this->body = array();
|
28 |
-
// Begin Parsing
|
29 |
-
try {
|
30 |
-
// Wrap file data in a SimpleXMLElement
|
31 |
-
$xml = simplexml_load_file( $this->file );
|
32 |
-
|
33 |
-
// Check if the head section exists before parsing it
|
34 |
-
if ( $xml->head )
|
35 |
-
$this->head = WPRSS_OPML::parse_opml_head( $xml->head->children() );
|
36 |
-
// Check if the body section exists before parsing it
|
37 |
-
if ( $xml->body )
|
38 |
-
$this->body = WPRSS_OPML::parse_opml_body_element( $xml->body->outline );
|
39 |
-
|
40 |
-
} catch (Exception $e) {
|
41 |
-
// If an exception is caught. Throw an error message
|
42 |
-
throw new Exception( __( 'An error occured: The file might not be a valid OPML file or is corrrupt. ', WPRSS_TEXT_DOMAIN ), 1);
|
43 |
-
}
|
44 |
-
}
|
45 |
-
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Parses the given variable as an OPML head section
|
49 |
-
*
|
50 |
-
* @since 3.3
|
51 |
-
* @param $head The head section of an OPML file ( SimpleXMLElement )
|
52 |
-
* @return array An associative array containing SimpleXMLElements for each tag in the given head section.
|
53 |
-
*/
|
54 |
-
private static function parse_opml_head( $head ) {
|
55 |
-
$parsed_data = array();
|
56 |
-
|
57 |
-
foreach ( $head as $property ) {
|
58 |
-
$parsed_data[ $property->getName() ] = $property;
|
59 |
-
}
|
60 |
-
|
61 |
-
return $parsed_data;
|
62 |
-
}
|
63 |
-
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Iterates through the elements given OPML/XML data and parses
|
67 |
-
* each element, and recurses where necessary, into an associative
|
68 |
-
* array that mimics OPML structure.
|
69 |
-
* @since 1.0
|
70 |
-
* @return array The Parsed OPML as an associative array
|
71 |
-
*/
|
72 |
-
private static function parse_opml_body_element( $element ) {
|
73 |
-
$parsed_data = array();
|
74 |
-
|
75 |
-
// Iterates through each child element in the given element
|
76 |
-
foreach ( $element as $child_element ) {
|
77 |
-
|
78 |
-
// If child element has type attribute set to 'rss' or has the 'xmlUrl' attribute
|
79 |
-
if ( $child_element['type'] === 'rss' || isset( $child_element['xmlUrl'] ) ) {
|
80 |
-
// Parse the child element and add it to the parsed data array
|
81 |
-
$parsed_data[] = WPRSS_OPML::SimpleXMLElement_to_OPMLElement( $child_element );
|
82 |
-
}
|
83 |
-
// Otherwise, if the child element has children 'outline' elements
|
84 |
-
elseif ( $child_element->outline ) {
|
85 |
-
// Recurse using this child element as parameter, and add the result to the parsed data array
|
86 |
-
$parsed_data[ (string) $child_element['text'] ] = WPRSS_OPML::parse_opml_body_element( $child_element->outline );
|
87 |
-
}
|
88 |
-
|
89 |
-
}
|
90 |
-
|
91 |
-
return $parsed_data;
|
92 |
-
}
|
93 |
-
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Parses a SimpleXMLElement Object into an OPML element compliant
|
97 |
-
* associative array.
|
98 |
-
* @since 1.0
|
99 |
-
* @return array An array in OPML element format
|
100 |
-
*/
|
101 |
-
private static function SimpleXMLElement_to_OPMLElement( $element ) {
|
102 |
-
// Copy attribute data from $element to a new associative array
|
103 |
-
$result = array(
|
104 |
-
'text' => (string) $element['text'],
|
105 |
-
'title' => (string) $element['title'],
|
106 |
-
'htmlUrl' => (string) $element['htmlUrl'],
|
107 |
-
'xmlUrl' => (string) $element['xmlUrl'],
|
108 |
-
'description' => (string) $element['description']
|
109 |
-
);
|
110 |
-
|
111 |
-
// Check for category attribute
|
112 |
-
if ( isset( $element['category'] ) ) {
|
113 |
-
// split categories by comma, and trim each category string
|
114 |
-
$result['categories'] = array_map( 'trim', explode(',', $element['category']) );
|
115 |
-
}
|
116 |
-
|
117 |
-
/*
|
118 |
-
* Check for existence of htmlUrl and xmlUrl.
|
119 |
-
* If not found, use lowercased attribute names.
|
120 |
-
*/
|
121 |
-
if ( !isset( $element['htmlUrl'] ) )
|
122 |
-
$result['htmlUrl'] = $element['htmlurl'];
|
123 |
-
if ( !isset( $element['xmlUrl'] ) )
|
124 |
-
$result['xmlUrl'] = $element['xmlurl'];
|
125 |
-
|
126 |
-
// Return the result OPML Element
|
127 |
-
return $result;
|
128 |
-
}
|
129 |
-
|
130 |
-
}
|
131 |
-
|
132 |
-
?>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The WPRSS_OPML Class represents an OPML document.
|
5 |
+
* It is constructed using a file, which it parses upon creation.
|
6 |
+
*
|
7 |
+
* @since 3.3
|
8 |
+
* @package WPRSSAggregator
|
9 |
+
*/
|
10 |
+
class WPRSS_OPML {
|
11 |
+
|
12 |
+
|
13 |
+
public $file;
|
14 |
+
public $head;
|
15 |
+
public $body;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Constructor: Parses the given XML file as an OPML
|
19 |
+
*
|
20 |
+
* @since 3.3
|
21 |
+
* @param $file The file to be parsed into a WPRSS_OPML object
|
22 |
+
*/
|
23 |
+
public function __construct( $file ) {
|
24 |
+
// Initialize Properties
|
25 |
+
$this->file = $file;
|
26 |
+
$this->head = array();
|
27 |
+
$this->body = array();
|
28 |
+
// Begin Parsing
|
29 |
+
try {
|
30 |
+
// Wrap file data in a SimpleXMLElement
|
31 |
+
$xml = simplexml_load_file( $this->file );
|
32 |
+
|
33 |
+
// Check if the head section exists before parsing it
|
34 |
+
if ( $xml->head )
|
35 |
+
$this->head = WPRSS_OPML::parse_opml_head( $xml->head->children() );
|
36 |
+
// Check if the body section exists before parsing it
|
37 |
+
if ( $xml->body )
|
38 |
+
$this->body = WPRSS_OPML::parse_opml_body_element( $xml->body->outline );
|
39 |
+
|
40 |
+
} catch (Exception $e) {
|
41 |
+
// If an exception is caught. Throw an error message
|
42 |
+
throw new Exception( __( 'An error occured: The file might not be a valid OPML file or is corrrupt. ', WPRSS_TEXT_DOMAIN ), 1);
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Parses the given variable as an OPML head section
|
49 |
+
*
|
50 |
+
* @since 3.3
|
51 |
+
* @param $head The head section of an OPML file ( SimpleXMLElement )
|
52 |
+
* @return array An associative array containing SimpleXMLElements for each tag in the given head section.
|
53 |
+
*/
|
54 |
+
private static function parse_opml_head( $head ) {
|
55 |
+
$parsed_data = array();
|
56 |
+
|
57 |
+
foreach ( $head as $property ) {
|
58 |
+
$parsed_data[ $property->getName() ] = $property;
|
59 |
+
}
|
60 |
+
|
61 |
+
return $parsed_data;
|
62 |
+
}
|
63 |
+
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Iterates through the elements given OPML/XML data and parses
|
67 |
+
* each element, and recurses where necessary, into an associative
|
68 |
+
* array that mimics OPML structure.
|
69 |
+
* @since 1.0
|
70 |
+
* @return array The Parsed OPML as an associative array
|
71 |
+
*/
|
72 |
+
private static function parse_opml_body_element( $element ) {
|
73 |
+
$parsed_data = array();
|
74 |
+
|
75 |
+
// Iterates through each child element in the given element
|
76 |
+
foreach ( $element as $child_element ) {
|
77 |
+
|
78 |
+
// If child element has type attribute set to 'rss' or has the 'xmlUrl' attribute
|
79 |
+
if ( $child_element['type'] === 'rss' || isset( $child_element['xmlUrl'] ) ) {
|
80 |
+
// Parse the child element and add it to the parsed data array
|
81 |
+
$parsed_data[] = WPRSS_OPML::SimpleXMLElement_to_OPMLElement( $child_element );
|
82 |
+
}
|
83 |
+
// Otherwise, if the child element has children 'outline' elements
|
84 |
+
elseif ( $child_element->outline ) {
|
85 |
+
// Recurse using this child element as parameter, and add the result to the parsed data array
|
86 |
+
$parsed_data[ (string) $child_element['text'] ] = WPRSS_OPML::parse_opml_body_element( $child_element->outline );
|
87 |
+
}
|
88 |
+
|
89 |
+
}
|
90 |
+
|
91 |
+
return $parsed_data;
|
92 |
+
}
|
93 |
+
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Parses a SimpleXMLElement Object into an OPML element compliant
|
97 |
+
* associative array.
|
98 |
+
* @since 1.0
|
99 |
+
* @return array An array in OPML element format
|
100 |
+
*/
|
101 |
+
private static function SimpleXMLElement_to_OPMLElement( $element ) {
|
102 |
+
// Copy attribute data from $element to a new associative array
|
103 |
+
$result = array(
|
104 |
+
'text' => (string) $element['text'],
|
105 |
+
'title' => (string) $element['title'],
|
106 |
+
'htmlUrl' => (string) $element['htmlUrl'],
|
107 |
+
'xmlUrl' => (string) $element['xmlUrl'],
|
108 |
+
'description' => (string) $element['description']
|
109 |
+
);
|
110 |
+
|
111 |
+
// Check for category attribute
|
112 |
+
if ( isset( $element['category'] ) ) {
|
113 |
+
// split categories by comma, and trim each category string
|
114 |
+
$result['categories'] = array_map( 'trim', explode(',', $element['category']) );
|
115 |
+
}
|
116 |
+
|
117 |
+
/*
|
118 |
+
* Check for existence of htmlUrl and xmlUrl.
|
119 |
+
* If not found, use lowercased attribute names.
|
120 |
+
*/
|
121 |
+
if ( !isset( $element['htmlUrl'] ) )
|
122 |
+
$result['htmlUrl'] = $element['htmlurl'];
|
123 |
+
if ( !isset( $element['xmlUrl'] ) )
|
124 |
+
$result['xmlUrl'] = $element['xmlurl'];
|
125 |
+
|
126 |
+
// Return the result OPML Element
|
127 |
+
return $result;
|
128 |
+
}
|
129 |
+
|
130 |
+
}
|
131 |
+
|
132 |
+
?>
|
includes/admin-addons.php
CHANGED
@@ -1,92 +1,92 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Build the Add-ons page (Code borrowed from the ACF plugin)
|
4 |
-
*
|
5 |
-
* @since 4.2
|
6 |
-
* @link http://www.advancedcustomfields.com/
|
7 |
-
*
|
8 |
-
*/
|
9 |
-
function wprss_addons_page_display() {
|
10 |
-
|
11 |
-
$premium = array();
|
12 |
-
$premium[] = array(
|
13 |
-
'title' => __( "Excerpts & Thumbnails", WPRSS_TEXT_DOMAIN ),
|
14 |
-
'description' => __( "Adds the ability to display thumbnails and excerpts. Perfect for adding some life and color to your feed item display. For more flexibility Feed to Post is a better option.", WPRSS_TEXT_DOMAIN ),
|
15 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
16 |
-
'active' => is_plugin_active( 'wp-rss-excerpts-thumbnails/wp-rss-excerpts-thumbnails.php' ),
|
17 |
-
'url' => 'http://www.wprssaggregator.com/extension/excerpts-thumbnails/'
|
18 |
-
);
|
19 |
-
$premium[] = array(
|
20 |
-
'title' => __( "Categories", WPRSS_TEXT_DOMAIN ),
|
21 |
-
'description' => __( "Assign categories to your feed sources. Then display a particular category or multiple categories on a post or page via shortcodes.", WPRSS_TEXT_DOMAIN ),
|
22 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
23 |
-
'active' => is_plugin_active( 'wp-rss-categories/wp-rss-categories.php' ),
|
24 |
-
'url' => 'http://www.wprssaggregator.com/extension/categories/'
|
25 |
-
);
|
26 |
-
$premium[] = array(
|
27 |
-
'title' => __( "Keyword Filtering", WPRSS_TEXT_DOMAIN ),
|
28 |
-
'description' => __( "Import feeds that contain specific keywords in either the title or their content. Control what gets imported to your blog. You can use keywords, keyphrases and categories.", WPRSS_TEXT_DOMAIN ),
|
29 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
30 |
-
'active' => is_plugin_active( 'wp-rss-keyword-filtering/wp-rss-keyword-filtering.php' ),
|
31 |
-
'url' => 'http://www.wprssaggregator.com/extension/keyword-filtering/'
|
32 |
-
);
|
33 |
-
$premium[] = array(
|
34 |
-
'title' => __( "Feed to Post", WPRSS_TEXT_DOMAIN ),
|
35 |
-
'description' => __( "Allows you to import feed items into posts or any other custom post type that you have created. Takes WP RSS Aggregator to a whole new level of flexibility.", WPRSS_TEXT_DOMAIN ),
|
36 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
37 |
-
'active' => is_plugin_active( 'wp-rss-feed-to-post/wp-rss-feed-to-post.php' ),
|
38 |
-
'url' => 'http://www.wprssaggregator.com/extension/feed-to-post/'
|
39 |
-
);
|
40 |
-
$premium[] = array(
|
41 |
-
'title' => __( "Full Text RSS Feeds", WPRSS_TEXT_DOMAIN ),
|
42 |
-
'description' => __( "This add-ons provides the connectivity to our Full Text Premium service, which gives you unlimited feed items returned per feed source.", WPRSS_TEXT_DOMAIN ),
|
43 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
44 |
-
'active' => is_plugin_active( 'wp-rss-full-text-feeds/wp-rss-full-text.php' ),
|
45 |
-
'url' => 'http://www.wprssaggregator.com/extension/full-text-rss-feeds/'
|
46 |
-
);
|
47 |
-
$premium[] = array(
|
48 |
-
'title' => __( "WordAi", WPRSS_TEXT_DOMAIN ),
|
49 |
-
'description' => __( "Allows you to spin the content for posts imported by Feed to Post using WordAi. Cleverly rewrite your posts without changing their meaning and maintaining human readability.", WPRSS_TEXT_DOMAIN ),
|
50 |
-
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
51 |
-
'active' => is_plugin_active( 'wp-rss-wordai/wp-rss-wordai.php' ),
|
52 |
-
'url' => 'http://www.wprssaggregator.com/extension/wordai/'
|
53 |
-
);
|
54 |
-
|
55 |
-
?>
|
56 |
-
<div class="wrap">
|
57 |
-
<?php screen_icon( 'wprss-aggregator' ); ?>
|
58 |
-
|
59 |
-
<h2><?php _e( 'Add-Ons', WPRSS_TEXT_DOMAIN ); ?></h2>
|
60 |
-
<p><?php _e( "The following Add-ons are available to increase the functionality of the WP RSS Aggregator plugin.", WPRSS_TEXT_DOMAIN ); ?><br />
|
61 |
-
<?php _e( "Each Add-on can be installed as a separate plugin. Note that activating the Feed to Post plugin will deactivate the Categories and Excerpts & Thumbnails add-ons.", WPRSS_TEXT_DOMAIN ); ?></p>
|
62 |
-
|
63 |
-
<div id="add-ons" class="clearfix">
|
64 |
-
|
65 |
-
<div class="add-on-group clearfix">
|
66 |
-
<?php foreach( $premium as $addon ): ?>
|
67 |
-
<div class="add-on wp-box <?php if( $addon['active'] ): ?>add-on-active<?php endif; ?>">
|
68 |
-
<!-- <a target="_blank" href="<?php echo $addon['url']; ?>">
|
69 |
-
<img src="<?php echo $addon['thumbnail']; ?>" />
|
70 |
-
</a> -->
|
71 |
-
<div class="inner">
|
72 |
-
<h3><a target="_blank" href="<?php echo $addon['url']; ?>"><?php echo $addon['title']; ?></a></h3>
|
73 |
-
<p><?php echo $addon['description']; ?></p>
|
74 |
-
</div>
|
75 |
-
<div class="footer">
|
76 |
-
<?php if( $addon['active'] ): ?>
|
77 |
-
<a class="button button-disabled"><span class="wprss-sprite-tick"></span><?php _e( "Installed", WPRSS_TEXT_DOMAIN ); ?></a>
|
78 |
-
<?php else: ?>
|
79 |
-
<a target="_blank" href="<?php echo $addon['url']; ?>" class="button"><?php _e( "Purchase & Install", WPRSS_TEXT_DOMAIN ); ?></a>
|
80 |
-
<?php endif; ?>
|
81 |
-
</div>
|
82 |
-
</div>
|
83 |
-
<?php endforeach; ?>
|
84 |
-
</div>
|
85 |
-
|
86 |
-
</div>
|
87 |
-
|
88 |
-
</div>
|
89 |
-
|
90 |
-
<?php
|
91 |
-
|
92 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Build the Add-ons page (Code borrowed from the ACF plugin)
|
4 |
+
*
|
5 |
+
* @since 4.2
|
6 |
+
* @link http://www.advancedcustomfields.com/
|
7 |
+
*
|
8 |
+
*/
|
9 |
+
function wprss_addons_page_display() {
|
10 |
+
|
11 |
+
$premium = array();
|
12 |
+
$premium[] = array(
|
13 |
+
'title' => __( "Excerpts & Thumbnails", WPRSS_TEXT_DOMAIN ),
|
14 |
+
'description' => __( "Adds the ability to display thumbnails and excerpts. Perfect for adding some life and color to your feed item display. For more flexibility Feed to Post is a better option.", WPRSS_TEXT_DOMAIN ),
|
15 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
16 |
+
'active' => is_plugin_active( 'wp-rss-excerpts-thumbnails/wp-rss-excerpts-thumbnails.php' ),
|
17 |
+
'url' => 'http://www.wprssaggregator.com/extension/excerpts-thumbnails/'
|
18 |
+
);
|
19 |
+
$premium[] = array(
|
20 |
+
'title' => __( "Categories", WPRSS_TEXT_DOMAIN ),
|
21 |
+
'description' => __( "Assign categories to your feed sources. Then display a particular category or multiple categories on a post or page via shortcodes.", WPRSS_TEXT_DOMAIN ),
|
22 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
23 |
+
'active' => is_plugin_active( 'wp-rss-categories/wp-rss-categories.php' ),
|
24 |
+
'url' => 'http://www.wprssaggregator.com/extension/categories/'
|
25 |
+
);
|
26 |
+
$premium[] = array(
|
27 |
+
'title' => __( "Keyword Filtering", WPRSS_TEXT_DOMAIN ),
|
28 |
+
'description' => __( "Import feeds that contain specific keywords in either the title or their content. Control what gets imported to your blog. You can use keywords, keyphrases and categories.", WPRSS_TEXT_DOMAIN ),
|
29 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
30 |
+
'active' => is_plugin_active( 'wp-rss-keyword-filtering/wp-rss-keyword-filtering.php' ),
|
31 |
+
'url' => 'http://www.wprssaggregator.com/extension/keyword-filtering/'
|
32 |
+
);
|
33 |
+
$premium[] = array(
|
34 |
+
'title' => __( "Feed to Post", WPRSS_TEXT_DOMAIN ),
|
35 |
+
'description' => __( "Allows you to import feed items into posts or any other custom post type that you have created. Takes WP RSS Aggregator to a whole new level of flexibility.", WPRSS_TEXT_DOMAIN ),
|
36 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
37 |
+
'active' => is_plugin_active( 'wp-rss-feed-to-post/wp-rss-feed-to-post.php' ),
|
38 |
+
'url' => 'http://www.wprssaggregator.com/extension/feed-to-post/'
|
39 |
+
);
|
40 |
+
$premium[] = array(
|
41 |
+
'title' => __( "Full Text RSS Feeds", WPRSS_TEXT_DOMAIN ),
|
42 |
+
'description' => __( "This add-ons provides the connectivity to our Full Text Premium service, which gives you unlimited feed items returned per feed source.", WPRSS_TEXT_DOMAIN ),
|
43 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
44 |
+
'active' => is_plugin_active( 'wp-rss-full-text-feeds/wp-rss-full-text.php' ),
|
45 |
+
'url' => 'http://www.wprssaggregator.com/extension/full-text-rss-feeds/'
|
46 |
+
);
|
47 |
+
$premium[] = array(
|
48 |
+
'title' => __( "WordAi", WPRSS_TEXT_DOMAIN ),
|
49 |
+
'description' => __( "Allows you to spin the content for posts imported by Feed to Post using WordAi. Cleverly rewrite your posts without changing their meaning and maintaining human readability.", WPRSS_TEXT_DOMAIN ),
|
50 |
+
'thumbnail' => WPRSS_IMG . 'add-ons/wprss.jpg',
|
51 |
+
'active' => is_plugin_active( 'wp-rss-wordai/wp-rss-wordai.php' ),
|
52 |
+
'url' => 'http://www.wprssaggregator.com/extension/wordai/'
|
53 |
+
);
|
54 |
+
|
55 |
+
?>
|
56 |
+
<div class="wrap">
|
57 |
+
<?php screen_icon( 'wprss-aggregator' ); ?>
|
58 |
+
|
59 |
+
<h2><?php _e( 'Add-Ons', WPRSS_TEXT_DOMAIN ); ?></h2>
|
60 |
+
<p><?php _e( "The following Add-ons are available to increase the functionality of the WP RSS Aggregator plugin.", WPRSS_TEXT_DOMAIN ); ?><br />
|
61 |
+
<?php _e( "Each Add-on can be installed as a separate plugin. Note that activating the Feed to Post plugin will deactivate the Categories and Excerpts & Thumbnails add-ons.", WPRSS_TEXT_DOMAIN ); ?></p>
|
62 |
+
|
63 |
+
<div id="add-ons" class="clearfix">
|
64 |
+
|
65 |
+
<div class="add-on-group clearfix">
|
66 |
+
<?php foreach( $premium as $addon ): ?>
|
67 |
+
<div class="add-on wp-box <?php if( $addon['active'] ): ?>add-on-active<?php endif; ?>">
|
68 |
+
<!-- <a target="_blank" href="<?php echo $addon['url']; ?>">
|
69 |
+
<img src="<?php echo $addon['thumbnail']; ?>" />
|
70 |
+
</a> -->
|
71 |
+
<div class="inner">
|
72 |
+
<h3><a target="_blank" href="<?php echo $addon['url']; ?>"><?php echo $addon['title']; ?></a></h3>
|
73 |
+
<p><?php echo $addon['description']; ?></p>
|
74 |
+
</div>
|
75 |
+
<div class="footer">
|
76 |
+
<?php if( $addon['active'] ): ?>
|
77 |
+
<a class="button button-disabled"><span class="wprss-sprite-tick"></span><?php _e( "Installed", WPRSS_TEXT_DOMAIN ); ?></a>
|
78 |
+
<?php else: ?>
|
79 |
+
<a target="_blank" href="<?php echo $addon['url']; ?>" class="button"><?php _e( "Purchase & Install", WPRSS_TEXT_DOMAIN ); ?></a>
|
80 |
+
<?php endif; ?>
|
81 |
+
</div>
|
82 |
+
</div>
|
83 |
+
<?php endforeach; ?>
|
84 |
+
</div>
|
85 |
+
|
86 |
+
</div>
|
87 |
+
|
88 |
+
</div>
|
89 |
+
|
90 |
+
<?php
|
91 |
+
|
92 |
}
|
includes/admin-ajax-notice.php
CHANGED
@@ -1,141 +1,141 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Serves up a notice to leave a review for this plugin
|
5 |
-
*
|
6 |
-
* @link http://wp.tutsplus.com/tutorials/creative-coding/a-primer-on-ajax-in-the-wordpress-dashboard-requesting-and-responding/
|
7 |
-
* @link http://wptheming.com/2011/08/admin-notices-in-wordpress/
|
8 |
-
*
|
9 |
-
* @since 3.0
|
10 |
-
*
|
11 |
-
*/
|
12 |
-
|
13 |
-
add_action( 'admin_notices', 'wprss_display_admin_notice' );
|
14 |
-
/**
|
15 |
-
* Renders the administration notice. Also renders a hidden nonce used for security when processing the Ajax request.
|
16 |
-
*
|
17 |
-
* @since 3.0
|
18 |
-
*/
|
19 |
-
function wprss_display_admin_notice() {
|
20 |
-
// If not an admin, do not show the notification
|
21 |
-
if ( ! current_user_can( 'manage_options' ) ) return;
|
22 |
-
|
23 |
-
global $pagenow, $typenow;
|
24 |
-
if ( empty( $typenow ) && !empty( $_GET['post'] ) ) {
|
25 |
-
$post = get_post( $_GET['post'] );
|
26 |
-
if ( $post !== NULL && !is_wp_error( $post ) )
|
27 |
-
$typenow = $post->post_type;
|
28 |
-
}
|
29 |
-
$notices_settings = get_option( 'wprss_settings_notices' );
|
30 |
-
|
31 |
-
if ( ( false == $notices_settings ) && ( ( $typenow == 'wprss_feed' ) || ( $typenow == 'wprss_feed_item' ) ) ) {
|
32 |
-
$html = '<div id="ajax-notification" class="updated">';
|
33 |
-
$html .= '<p>';
|
34 |
-
$html .= __( 'Did you know that you can get more RSS features? Excerpts, thumbnails, keyword filtering, importing into posts and more... ', WPRSS_TEXT_DOMAIN );
|
35 |
-
$html .= __( 'Check out the', WPRSS_TEXT_DOMAIN ) . ' <a target="_blank" href="http://www.wprssaggregator.com/extensions"><strong>' . __( 'extensions', 'WPRSS_TEXT_DOMAIN' ) . '</strong></a> ' . __( 'page.', WPRSS_TEXT_DOMAIN );
|
36 |
-
$html .= '<a href="javascript:;" id="dismiss-ajax-notification" style="float:right;">' . __( 'Dismiss this notification', WPRSS_TEXT_DOMAIN ) . '</a>';
|
37 |
-
$html .= '</p>';
|
38 |
-
$html .= '<span id="ajax-notification-nonce" class="hidden">' . wp_create_nonce( 'ajax-notification-nonce' ) . '</span>';
|
39 |
-
$html .= '</div>';
|
40 |
-
|
41 |
-
echo $html;
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
|
46 |
-
add_action( 'wp_ajax_wprss_hide_admin_notification', 'wprss_hide_admin_notification' );
|
47 |
-
/**
|
48 |
-
* JavaScript callback used to hide the administration notice when the 'Dismiss' anchor is clicked on the front end.
|
49 |
-
*
|
50 |
-
* @since 3.0
|
51 |
-
*/
|
52 |
-
function wprss_hide_admin_notification() {
|
53 |
-
|
54 |
-
// First, check the nonce to make sure it matches what we created when displaying the message.
|
55 |
-
// If not, we won't do anything.
|
56 |
-
if( wp_verify_nonce( $_REQUEST['nonce'], 'ajax-notification-nonce' ) ) {
|
57 |
-
|
58 |
-
// If the update to the option is successful, send 1 back to the browser;
|
59 |
-
// Otherwise, send 0.
|
60 |
-
$general_settings = get_option( 'wprss_settings_notices' );
|
61 |
-
$general_settings = true;
|
62 |
-
|
63 |
-
if( update_option( 'wprss_settings_notices', $general_settings ) ) {
|
64 |
-
die( '1' );
|
65 |
-
} else {
|
66 |
-
die( '0' );
|
67 |
-
}
|
68 |
-
}
|
69 |
-
}
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Checks if the addon notices option exists in the database, and creates it
|
75 |
-
* if it does not.
|
76 |
-
*
|
77 |
-
* @return The addon notices option
|
78 |
-
* @since 3.4.2
|
79 |
-
*/
|
80 |
-
function wprss_check_addon_notice_option() {
|
81 |
-
$option = get_option( 'wprss_addon_notices' );
|
82 |
-
if ( $option === FALSE ) {
|
83 |
-
update_option( 'wprss_addon_notices', array() );
|
84 |
-
return array();
|
85 |
-
}
|
86 |
-
return $option;
|
87 |
-
}
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
/**
|
92 |
-
* This function is called through AJAX to dismiss a particular addon notification.
|
93 |
-
*
|
94 |
-
* @since 3.4.2
|
95 |
-
*/
|
96 |
-
function wprss_dismiss_addon_notice() {
|
97 |
-
$addon = ( isset( $_POST['addon'] ) === TRUE )? $_POST['addon'] : null;
|
98 |
-
if ( $addon === null ) {
|
99 |
-
echo 'false';
|
100 |
-
die();
|
101 |
-
}
|
102 |
-
$notice = ( isset( $_POST['notice'] ) === TRUE )? $_POST['notice'] : null;
|
103 |
-
if ( $notice === null ){
|
104 |
-
echo 'false';
|
105 |
-
die();
|
106 |
-
}
|
107 |
-
|
108 |
-
$notices = wprss_check_addon_notice_option();
|
109 |
-
if ( isset( $notices[$addon] ) === FALSE ) {
|
110 |
-
$notices[$addon] = array();
|
111 |
-
}
|
112 |
-
if ( isset( $notices[$addon][$addon] ) === FALSE ) {
|
113 |
-
$notices[$addon][$notice] = '1';
|
114 |
-
}
|
115 |
-
update_option( 'wprss_addon_notices', $notices );
|
116 |
-
echo 'true';
|
117 |
-
|
118 |
-
die();
|
119 |
-
}
|
120 |
-
|
121 |
-
add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
/**
|
127 |
-
* AJAX action for the tracking pointer
|
128 |
-
*
|
129 |
-
* @since 3.6
|
130 |
-
*/
|
131 |
-
function wprss_tracking_ajax_opt() {
|
132 |
-
if ( isset( $_POST['opted'] ) ){
|
133 |
-
$opted = $_POST['opted'];
|
134 |
-
$settings = get_option( 'wprss_settings_general' );
|
135 |
-
$settings['tracking'] = $opted;
|
136 |
-
update_option( 'wprss_settings_general', $settings );
|
137 |
-
}
|
138 |
-
die();
|
139 |
-
}
|
140 |
-
|
141 |
add_action( 'wp_ajax_wprss_tracking_ajax_opt', 'wprss_tracking_ajax_opt' );
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Serves up a notice to leave a review for this plugin
|
5 |
+
*
|
6 |
+
* @link http://wp.tutsplus.com/tutorials/creative-coding/a-primer-on-ajax-in-the-wordpress-dashboard-requesting-and-responding/
|
7 |
+
* @link http://wptheming.com/2011/08/admin-notices-in-wordpress/
|
8 |
+
*
|
9 |
+
* @since 3.0
|
10 |
+
*
|
11 |
+
*/
|
12 |
+
|
13 |
+
add_action( 'admin_notices', 'wprss_display_admin_notice' );
|
14 |
+
/**
|
15 |
+
* Renders the administration notice. Also renders a hidden nonce used for security when processing the Ajax request.
|
16 |
+
*
|
17 |
+
* @since 3.0
|
18 |
+
*/
|
19 |
+
function wprss_display_admin_notice() {
|
20 |
+
// If not an admin, do not show the notification
|
21 |
+
if ( ! current_user_can( 'manage_options' ) ) return;
|
22 |
+
|
23 |
+
global $pagenow, $typenow;
|
24 |
+
if ( empty( $typenow ) && !empty( $_GET['post'] ) ) {
|
25 |
+
$post = get_post( $_GET['post'] );
|
26 |
+
if ( $post !== NULL && !is_wp_error( $post ) )
|
27 |
+
$typenow = $post->post_type;
|
28 |
+
}
|
29 |
+
$notices_settings = get_option( 'wprss_settings_notices' );
|
30 |
+
|
31 |
+
if ( ( false == $notices_settings ) && ( ( $typenow == 'wprss_feed' ) || ( $typenow == 'wprss_feed_item' ) ) ) {
|
32 |
+
$html = '<div id="ajax-notification" class="updated">';
|
33 |
+
$html .= '<p>';
|
34 |
+
$html .= __( 'Did you know that you can get more RSS features? Excerpts, thumbnails, keyword filtering, importing into posts and more... ', WPRSS_TEXT_DOMAIN );
|
35 |
+
$html .= __( 'Check out the', WPRSS_TEXT_DOMAIN ) . ' <a target="_blank" href="http://www.wprssaggregator.com/extensions"><strong>' . __( 'extensions', 'WPRSS_TEXT_DOMAIN' ) . '</strong></a> ' . __( 'page.', WPRSS_TEXT_DOMAIN );
|
36 |
+
$html .= '<a href="javascript:;" id="dismiss-ajax-notification" style="float:right;">' . __( 'Dismiss this notification', WPRSS_TEXT_DOMAIN ) . '</a>';
|
37 |
+
$html .= '</p>';
|
38 |
+
$html .= '<span id="ajax-notification-nonce" class="hidden">' . wp_create_nonce( 'ajax-notification-nonce' ) . '</span>';
|
39 |
+
$html .= '</div>';
|
40 |
+
|
41 |
+
echo $html;
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
|
46 |
+
add_action( 'wp_ajax_wprss_hide_admin_notification', 'wprss_hide_admin_notification' );
|
47 |
+
/**
|
48 |
+
* JavaScript callback used to hide the administration notice when the 'Dismiss' anchor is clicked on the front end.
|
49 |
+
*
|
50 |
+
* @since 3.0
|
51 |
+
*/
|
52 |
+
function wprss_hide_admin_notification() {
|
53 |
+
|
54 |
+
// First, check the nonce to make sure it matches what we created when displaying the message.
|
55 |
+
// If not, we won't do anything.
|
56 |
+
if( wp_verify_nonce( $_REQUEST['nonce'], 'ajax-notification-nonce' ) ) {
|
57 |
+
|
58 |
+
// If the update to the option is successful, send 1 back to the browser;
|
59 |
+
// Otherwise, send 0.
|
60 |
+
$general_settings = get_option( 'wprss_settings_notices' );
|
61 |
+
$general_settings = true;
|
62 |
+
|
63 |
+
if( update_option( 'wprss_settings_notices', $general_settings ) ) {
|
64 |
+
die( '1' );
|
65 |
+
} else {
|
66 |
+
die( '0' );
|
67 |
+
}
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Checks if the addon notices option exists in the database, and creates it
|
75 |
+
* if it does not.
|
76 |
+
*
|
77 |
+
* @return The addon notices option
|
78 |
+
* @since 3.4.2
|
79 |
+
*/
|
80 |
+
function wprss_check_addon_notice_option() {
|
81 |
+
$option = get_option( 'wprss_addon_notices' );
|
82 |
+
if ( $option === FALSE ) {
|
83 |
+
update_option( 'wprss_addon_notices', array() );
|
84 |
+
return array();
|
85 |
+
}
|
86 |
+
return $option;
|
87 |
+
}
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
/**
|
92 |
+
* This function is called through AJAX to dismiss a particular addon notification.
|
93 |
+
*
|
94 |
+
* @since 3.4.2
|
95 |
+
*/
|
96 |
+
function wprss_dismiss_addon_notice() {
|
97 |
+
$addon = ( isset( $_POST['addon'] ) === TRUE )? $_POST['addon'] : null;
|
98 |
+
if ( $addon === null ) {
|
99 |
+
echo 'false';
|
100 |
+
die();
|
101 |
+
}
|
102 |
+
$notice = ( isset( $_POST['notice'] ) === TRUE )? $_POST['notice'] : null;
|
103 |
+
if ( $notice === null ){
|
104 |
+
echo 'false';
|
105 |
+
die();
|
106 |
+
}
|
107 |
+
|
108 |
+
$notices = wprss_check_addon_notice_option();
|
109 |
+
if ( isset( $notices[$addon] ) === FALSE ) {
|
110 |
+
$notices[$addon] = array();
|
111 |
+
}
|
112 |
+
if ( isset( $notices[$addon][$addon] ) === FALSE ) {
|
113 |
+
$notices[$addon][$notice] = '1';
|
114 |
+
}
|
115 |
+
update_option( 'wprss_addon_notices', $notices );
|
116 |
+
echo 'true';
|
117 |
+
|
118 |
+
die();
|
119 |
+
}
|
120 |
+
|
121 |
+
add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
|
122 |
+
|
123 |
+
|
124 |
+
|
125 |
+
|
126 |
+
/**
|
127 |
+
* AJAX action for the tracking pointer
|
128 |
+
*
|
129 |
+
* @since 3.6
|
130 |
+
*/
|
131 |
+
function wprss_tracking_ajax_opt() {
|
132 |
+
if ( isset( $_POST['opted'] ) ){
|
133 |
+
$opted = $_POST['opted'];
|
134 |
+
$settings = get_option( 'wprss_settings_general' );
|
135 |
+
$settings['tracking'] = $opted;
|
136 |
+
update_option( 'wprss_settings_general', $settings );
|
137 |
+
}
|
138 |
+
die();
|
139 |
+
}
|
140 |
+
|
141 |
add_action( 'wp_ajax_wprss_tracking_ajax_opt', 'wprss_tracking_ajax_opt' );
|
includes/admin-dashboard.php
CHANGED
@@ -1,99 +1,99 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Adds a dashboard page for the admin
|
4 |
-
* It is triggered on plugin activation and upon
|
5 |
-
* update.
|
6 |
-
*
|
7 |
-
* @since 3.3
|
8 |
-
*/
|
9 |
-
|
10 |
-
|
11 |
-
// Exit if the page is accessed directly
|
12 |
-
if ( ! defined( 'ABSPATH' ) ) exit;
|
13 |
-
|
14 |
-
|
15 |
-
add_action( 'admin_menu', 'wprss_admin_menu' );
|
16 |
-
/**
|
17 |
-
* Adds a dashboard page.
|
18 |
-
* Usde to add the Welcome Page to the dashboard.
|
19 |
-
*
|
20 |
-
* @since 3.3
|
21 |
-
*/
|
22 |
-
function wprss_admin_menu() {
|
23 |
-
// Welcome Page
|
24 |
-
add_dashboard_page(
|
25 |
-
__( 'Welcome to WP RSS Aggregator', WPRSS_TEXT_DOMAIN ),
|
26 |
-
__( 'Welcome to WP RSS Aggregator', WPRSS_TEXT_DOMAIN ),
|
27 |
-
'manage_options',
|
28 |
-
'wprss-welcome',
|
29 |
-
'wprss_show_welcome_screen'
|
30 |
-
);
|
31 |
-
|
32 |
-
}
|
33 |
-
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Callback for the Welcome Dashboard page.
|
37 |
-
* It merely includes the contents of the admin-welcome.php file,
|
38 |
-
* which contains the markup for the welcome screen.
|
39 |
-
*
|
40 |
-
* @since 3.3
|
41 |
-
*/
|
42 |
-
function wprss_show_welcome_screen() {
|
43 |
-
include_once( 'admin-welcome.php' );
|
44 |
-
}
|
45 |
-
|
46 |
-
|
47 |
-
add_action( 'admin_init', 'wprss_welcome' );
|
48 |
-
/**
|
49 |
-
* Detects an activation and redirects the user to
|
50 |
-
* the welcome page.
|
51 |
-
*
|
52 |
-
* @since 3.3
|
53 |
-
*/
|
54 |
-
function wprss_welcome() {
|
55 |
-
// Bail if no activation redirect
|
56 |
-
if ( ! get_transient( '_wprss_activation_redirect' ) )
|
57 |
-
return;
|
58 |
-
|
59 |
-
// Delete the redirect transient
|
60 |
-
delete_transient( '_wprss_activation_redirect' );
|
61 |
-
|
62 |
-
// Bail if activating from network, or bulk
|
63 |
-
if ( is_network_admin() || isset( $_GET['activate-multi'] ) )
|
64 |
-
return;
|
65 |
-
|
66 |
-
wp_safe_redirect( admin_url( 'index.php?page=wprss-welcome' ) );
|
67 |
-
exit;
|
68 |
-
}
|
69 |
-
|
70 |
-
|
71 |
-
add_action( 'admin_head', 'wprss_admin_head' );
|
72 |
-
/**
|
73 |
-
* Removes the dashboard welcome page from the dashboard
|
74 |
-
* menu, and adds some styles for the welcome page.
|
75 |
-
*
|
76 |
-
* @since 3.3
|
77 |
-
*/
|
78 |
-
function wprss_admin_head() {
|
79 |
-
remove_submenu_page( 'index.php', 'wprss-welcome' );
|
80 |
-
?>
|
81 |
-
<style type="text/css" media="screen">
|
82 |
-
/*<![CDATA[*/
|
83 |
-
|
84 |
-
/*.wprss-welcome-table > tbody > tr > td {
|
85 |
-
line-height: 30px;
|
86 |
-
}
|
87 |
-
.wprss-welcome-table > tbody > tr {
|
88 |
-
font-size: 1.3em;
|
89 |
-
font-weight: normal;
|
90 |
-
}
|
91 |
-
.wprss-welcome-table > thead > tr > th{
|
92 |
-
font-size: 2em;
|
93 |
-
border-bottom: 8px solid #999;
|
94 |
-
}*/
|
95 |
-
|
96 |
-
/*]]>*/
|
97 |
-
</style>
|
98 |
-
<?php
|
99 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Adds a dashboard page for the admin
|
4 |
+
* It is triggered on plugin activation and upon
|
5 |
+
* update.
|
6 |
+
*
|
7 |
+
* @since 3.3
|
8 |
+
*/
|
9 |
+
|
10 |
+
|
11 |
+
// Exit if the page is accessed directly
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) exit;
|
13 |
+
|
14 |
+
|
15 |
+
add_action( 'admin_menu', 'wprss_admin_menu' );
|
16 |
+
/**
|
17 |
+
* Adds a dashboard page.
|
18 |
+
* Usde to add the Welcome Page to the dashboard.
|
19 |
+
*
|
20 |
+
* @since 3.3
|
21 |
+
*/
|
22 |
+
function wprss_admin_menu() {
|
23 |
+
// Welcome Page
|
24 |
+
add_dashboard_page(
|
25 |
+
__( 'Welcome to WP RSS Aggregator', WPRSS_TEXT_DOMAIN ),
|
26 |
+
__( 'Welcome to WP RSS Aggregator', WPRSS_TEXT_DOMAIN ),
|
27 |
+
'manage_options',
|
28 |
+
'wprss-welcome',
|
29 |
+
'wprss_show_welcome_screen'
|
30 |
+
);
|
31 |
+
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Callback for the Welcome Dashboard page.
|
37 |
+
* It merely includes the contents of the admin-welcome.php file,
|
38 |
+
* which contains the markup for the welcome screen.
|
39 |
+
*
|
40 |
+
* @since 3.3
|
41 |
+
*/
|
42 |
+
function wprss_show_welcome_screen() {
|
43 |
+
include_once( 'admin-welcome.php' );
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
add_action( 'admin_init', 'wprss_welcome' );
|
48 |
+
/**
|
49 |
+
* Detects an activation and redirects the user to
|
50 |
+
* the welcome page.
|
51 |
+
*
|
52 |
+
* @since 3.3
|
53 |
+
*/
|
54 |
+
function wprss_welcome() {
|
55 |
+
// Bail if no activation redirect
|
56 |
+
if ( ! get_transient( '_wprss_activation_redirect' ) )
|
57 |
+
return;
|
58 |
+
|
59 |
+
// Delete the redirect transient
|
60 |
+
delete_transient( '_wprss_activation_redirect' );
|
61 |
+
|
62 |
+
// Bail if activating from network, or bulk
|
63 |
+
if ( is_network_admin() || isset( $_GET['activate-multi'] ) )
|
64 |
+
return;
|
65 |
+
|
66 |
+
wp_safe_redirect( admin_url( 'index.php?page=wprss-welcome' ) );
|
67 |
+
exit;
|
68 |
+
}
|
69 |
+
|
70 |
+
|
71 |
+
add_action( 'admin_head', 'wprss_admin_head' );
|
72 |
+
/**
|
73 |
+
* Removes the dashboard welcome page from the dashboard
|
74 |
+
* menu, and adds some styles for the welcome page.
|
75 |
+
*
|
76 |
+
* @since 3.3
|
77 |
+
*/
|
78 |
+
function wprss_admin_head() {
|
79 |
+
remove_submenu_page( 'index.php', 'wprss-welcome' );
|
80 |
+
?>
|
81 |
+
<style type="text/css" media="screen">
|
82 |
+
/*<![CDATA[*/
|
83 |
+
|
84 |
+
/*.wprss-welcome-table > tbody > tr > td {
|
85 |
+
line-height: 30px;
|
86 |
+
}
|
87 |
+
.wprss-welcome-table > tbody > tr {
|
88 |
+
font-size: 1.3em;
|
89 |
+
font-weight: normal;
|
90 |
+
}
|
91 |
+
.wprss-welcome-table > thead > tr > th{
|
92 |
+
font-size: 2em;
|
93 |
+
border-bottom: 8px solid #999;
|
94 |
+
}*/
|
95 |
+
|
96 |
+
/*]]>*/
|
97 |
+
</style>
|
98 |
+
<?php
|
99 |
}
|
includes/admin-debugging.php
CHANGED
@@ -1,312 +1,312 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Plugin debugging
|
4 |
-
*
|
5 |
-
* @package WPRSSAggregator
|
6 |
-
* @subpackage Includes
|
7 |
-
* @since 3.0
|
8 |
-
* @author Jean Galea <info@jeangalea.com>
|
9 |
-
* @copyright Copyright(c) 2012-2013, Jean Galea
|
10 |
-
* @link http://www.wpmayor.com
|
11 |
-
* @license http://www.gnu.org/licenses/gpl.html
|
12 |
-
*/
|
13 |
-
|
14 |
-
/*
|
15 |
-
//allow redirection, even if my theme starts to send output to the browser
|
16 |
-
add_action( 'admin_init', 'wprss_do_output_buffer' );
|
17 |
-
function wprss_do_output_buffer() {
|
18 |
-
//ob_start();
|
19 |
-
}*/
|
20 |
-
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Returns the debugging operations array
|
24 |
-
*
|
25 |
-
* @since 3.4.6
|
26 |
-
*/
|
27 |
-
function wprss_get_debug_operations() {
|
28 |
-
$operations = apply_filters(
|
29 |
-
'wprss_debug_operations',
|
30 |
-
array(
|
31 |
-
'update-feeds' => array(
|
32 |
-
'nonce' => 'wprss-update-feed-items',
|
33 |
-
'run' => 'wprss_fetch_insert_all_feed_items',
|
34 |
-
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=1',
|
35 |
-
'render' => 'wprss_debug_update_feeds',
|
36 |
-
),
|
37 |
-
|
38 |
-
'reimport-feeds' => array(
|
39 |
-
'nonce' => 'wprss-delete-import-feed-items',
|
40 |
-
'run' => 'wprss_feed_reset',
|
41 |
-
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=2',
|
42 |
-
'render' => 'wprss_debug_reimport_feeds',
|
43 |
-
),
|
44 |
-
|
45 |
-
)
|
46 |
-
);
|
47 |
-
|
48 |
-
$operations['error-log'] = apply_filters(
|
49 |
-
'wprss_debug_error_log_operation',
|
50 |
-
array(
|
51 |
-
'nonce' => 'wprss-clear-error-log',
|
52 |
-
'run' => 'wprss_clear_log',
|
53 |
-
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=3',
|
54 |
-
'render' => 'wprss_debug_clear_log_button'
|
55 |
-
)
|
56 |
-
);
|
57 |
-
|
58 |
-
$operations ['restore-settings'] = apply_filters(
|
59 |
-
'wprss_debug_restore_settings_operation',
|
60 |
-
array(
|
61 |
-
'nonce' => 'wprss-restore-settings',
|
62 |
-
'run' => 'wprss_restore_settings',
|
63 |
-
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=4',
|
64 |
-
'render' => 'wprss_debug_restore_settings',
|
65 |
-
'pos' => 'bottom'
|
66 |
-
)
|
67 |
-
);
|
68 |
-
|
69 |
-
return $operations;
|
70 |
-
}
|
71 |
-
|
72 |
-
|
73 |
-
add_action( 'admin_init', 'wprss_debug_operations' );
|
74 |
-
/**
|
75 |
-
* Performs debug operations, depending on the POST request.
|
76 |
-
*
|
77 |
-
* @since 3.3
|
78 |
-
*/
|
79 |
-
function wprss_debug_operations(){
|
80 |
-
|
81 |
-
// Define the debugging operations
|
82 |
-
$debug_operations = wprss_get_debug_operations();
|
83 |
-
|
84 |
-
// Check which of the operations needs to be run
|
85 |
-
foreach ( $debug_operations as $id => $operation ) {
|
86 |
-
// If page loading after having clicked 'Update all fields'
|
87 |
-
if ( isset( $_POST[ $id ] ) && check_admin_referer( $operation['nonce'] ) ) {
|
88 |
-
call_user_func( $operation['run'] );
|
89 |
-
wp_redirect( $operation['redirect'] );
|
90 |
-
break;
|
91 |
-
}
|
92 |
-
}
|
93 |
-
}
|
94 |
-
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Build the Update Feeds section
|
98 |
-
*
|
99 |
-
* @since 3.4.6
|
100 |
-
*/
|
101 |
-
function wprss_debug_update_feeds() {
|
102 |
-
?>
|
103 |
-
<h3><?php _e( 'Update All Feeds Now', WPRSS_TEXT_DOMAIN ); ?></h3>
|
104 |
-
<p><?php _e( 'Click the blue button to update all active feed items now. This will check all feed sources for any new feed items.', WPRSS_TEXT_DOMAIN ); ?>
|
105 |
-
<br><?php _e( 'Existing feed items will not be modified.', WPRSS_TEXT_DOMAIN ); ?>
|
106 |
-
</p>
|
107 |
-
<p><?php _e( '<strong>Note:</strong> This might take more than a few seconds if you have many feed sources.', WPRSS_TEXT_DOMAIN ); ?></p>
|
108 |
-
|
109 |
-
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
110 |
-
|
111 |
-
<?php wp_nonce_field( 'wprss-update-feed-items' );
|
112 |
-
submit_button( __( 'Update all feeds', WPRSS_TEXT_DOMAIN ), 'primary', 'update-feeds', true ); ?>
|
113 |
-
|
114 |
-
</form>
|
115 |
-
<?php
|
116 |
-
}
|
117 |
-
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Build the Delete and Re-Import Feeds section
|
121 |
-
*
|
122 |
-
* @since 3.4.6
|
123 |
-
*/
|
124 |
-
function wprss_debug_reimport_feeds() {
|
125 |
-
?>
|
126 |
-
<h3><?php _e( 'Delete and Re-import Feeds', WPRSS_TEXT_DOMAIN ); ?></h3>
|
127 |
-
<p><?php _e( 'Click the red button to delete all imported feed items and re-import them.', WPRSS_TEXT_DOMAIN ); ?></p>
|
128 |
-
<p><?php _e( '<em><strong>Note:</strong> This is a server-intensive process and should only be used when instructed to by support staff.</em>', WPRSS_TEXT_DOMAIN ); ?></p>
|
129 |
-
|
130 |
-
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
131 |
-
|
132 |
-
<?php wp_nonce_field( 'wprss-delete-import-feed-items' );
|
133 |
-
submit_button( __( 'Delete and Re-import all feeds', WPRSS_TEXT_DOMAIN ), 'button-red', 'reimport-feeds', true ); ?>
|
134 |
-
|
135 |
-
</form>
|
136 |
-
<?php
|
137 |
-
}
|
138 |
-
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Render the restore settings button
|
142 |
-
*
|
143 |
-
* @since 4.4
|
144 |
-
*/
|
145 |
-
function wprss_debug_restore_settings() {
|
146 |
-
?>
|
147 |
-
<h3><?php _e( 'Restore Default Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
148 |
-
<p><?php _e( 'Click the red button to reset the plugin settings to default.', WPRSS_TEXT_DOMAIN ); ?></p>
|
149 |
-
<p><?php _e( '<em><strong>Note:</strong> This cannot be undone. Once the settings have been reset, your old settings cannot be restored.</em>', WPRSS_TEXT_DOMAIN ); ?></p>
|
150 |
-
|
151 |
-
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
152 |
-
|
153 |
-
<?php wp_nonce_field( 'wprss-restore-settings' );
|
154 |
-
submit_button( __( 'Restore Default Settings', WPRSS_TEXT_DOMAIN ), 'button-red', 'restore-settings', true ); ?>
|
155 |
-
|
156 |
-
</form>
|
157 |
-
<?php
|
158 |
-
}
|
159 |
-
|
160 |
-
|
161 |
-
/**
|
162 |
-
* Renders the Clear Log button
|
163 |
-
*
|
164 |
-
* @since 3.9.6
|
165 |
-
*/
|
166 |
-
function wprss_debug_clear_log_button() {
|
167 |
-
?>
|
168 |
-
<h3><?php _e( 'Error Log', WPRSS_TEXT_DOMAIN ); ?></h3>
|
169 |
-
|
170 |
-
<textarea readonly="readonly" id="wprss-error-log-textarea"><?php echo wprss_get_log(); ?></textarea>
|
171 |
-
|
172 |
-
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="POST">
|
173 |
-
<?php wp_nonce_field( 'wprss-clear-error-log' );
|
174 |
-
submit_button( __( 'Clear log', WPRSS_TEXT_DOMAIN ), 'button-primary', 'error-log', true ); ?>
|
175 |
-
</form>
|
176 |
-
|
177 |
-
<?php
|
178 |
-
}
|
179 |
-
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Build the debugging page
|
183 |
-
*
|
184 |
-
* @since 3.0
|
185 |
-
*/
|
186 |
-
function wprss_debugging_page_display() {
|
187 |
-
$debug_messages = apply_filters(
|
188 |
-
'wprss_debug_messages',
|
189 |
-
array(
|
190 |
-
'1' => 'wprss_debugging_admin_notice_update_feeds',
|
191 |
-
'2' => 'wprss_debugging_admin_notice_reimport_feeds',
|
192 |
-
'3' => 'wprss_debugging_admin_notice_clear_log',
|
193 |
-
'4' => 'wprss_debugging_admin_notice_reset_settings'
|
194 |
-
)
|
195 |
-
);
|
196 |
-
|
197 |
-
?>
|
198 |
-
|
199 |
-
<div class="wrap">
|
200 |
-
<?php screen_icon( 'wprss-aggregator' ); ?>
|
201 |
-
|
202 |
-
<h2><?php _e( 'Debugging', WPRSS_TEXT_DOMAIN ); ?></h2>
|
203 |
-
<?php
|
204 |
-
if ( isset( $_GET['debug_message'] )) {//&& ( check_admin_referer( 'wprss-delete-import-feed-items' ) || check_admin_referer( 'wprss-update-feed-items' ) ) ) {
|
205 |
-
$message = $_GET['debug_message'];
|
206 |
-
|
207 |
-
foreach ( $debug_messages as $id => $callback) {
|
208 |
-
if ( $message == $id ) {
|
209 |
-
call_user_func( $callback );
|
210 |
-
break;
|
211 |
-
}
|
212 |
-
}
|
213 |
-
}
|
214 |
-
|
215 |
-
do_action( 'wprss_debugging_before' );
|
216 |
-
|
217 |
-
$bottom = array();
|
218 |
-
$debug_operations = wprss_get_debug_operations();
|
219 |
-
foreach( $debug_operations as $id => $data ) {
|
220 |
-
if ( !isset( $data['render'] ) ) continue;
|
221 |
-
$pos = isset( $data['pos'] ) ? $data['pos'] : 'normal';
|
222 |
-
if ( $pos == 'normal' ) {
|
223 |
-
call_user_func( $data['render'] );
|
224 |
-
} elseif( $pos == 'bottom' ) {
|
225 |
-
$bottom[$id] = $data;
|
226 |
-
}
|
227 |
-
}
|
228 |
-
|
229 |
-
do_action( 'wprss_debugging_after' );
|
230 |
-
|
231 |
-
wprss_system_info();
|
232 |
-
|
233 |
-
if ( count($bottom) > 0 ) {
|
234 |
-
foreach( $bottom as $id => $data ) {
|
235 |
-
if ( !isset( $data['render'] ) ) continue;
|
236 |
-
call_user_func( $data['render'] );
|
237 |
-
}
|
238 |
-
}
|
239 |
-
|
240 |
-
?>
|
241 |
-
</div>
|
242 |
-
<?php
|
243 |
-
}
|
244 |
-
|
245 |
-
|
246 |
-
/**
|
247 |
-
* Output admin notice that feeds have been updated successfully
|
248 |
-
*
|
249 |
-
* @since 3.0
|
250 |
-
*/
|
251 |
-
function wprss_debugging_admin_notice_update_feeds() {
|
252 |
-
?><div class="updated"><p><?php _e( 'Feeds are being updated in the background.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
253 |
-
}
|
254 |
-
|
255 |
-
/**
|
256 |
-
* Output admin notice that feeds have been deleted and re-imported successfully
|
257 |
-
*
|
258 |
-
* @since 3.0
|
259 |
-
*/
|
260 |
-
function wprss_debugging_admin_notice_reimport_feeds() {
|
261 |
-
?><div class="updated"><p><?php _e( 'Feeds deleted and are being re-imported in the background.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
262 |
-
}
|
263 |
-
|
264 |
-
|
265 |
-
/**
|
266 |
-
* Output admin notice that log has been cleard
|
267 |
-
*
|
268 |
-
* @since 3.9.6
|
269 |
-
*/
|
270 |
-
function wprss_debugging_admin_notice_clear_log() {
|
271 |
-
?><div class="updated"><p><?php _e( 'The error log has been cleared.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
272 |
-
}
|
273 |
-
|
274 |
-
|
275 |
-
/**
|
276 |
-
* Output admin notice that log has been cleard
|
277 |
-
*
|
278 |
-
* @since 4.4
|
279 |
-
*/
|
280 |
-
function wprss_debugging_admin_notice_reset_settings() {
|
281 |
-
?><div class="updated"><p><?php _e( 'The plugin settings have been reset to default.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
282 |
-
}
|
283 |
-
|
284 |
-
|
285 |
-
/**
|
286 |
-
* Resets the plugin settings to default
|
287 |
-
*
|
288 |
-
* @since 4.4
|
289 |
-
*/
|
290 |
-
function wprss_restore_settings() {
|
291 |
-
// Action Hook
|
292 |
-
do_action( 'wprss_before_restore_settings' );
|
293 |
-
|
294 |
-
// Prepare the settings to reset
|
295 |
-
$settings_to_restore = apply_filters(
|
296 |
-
'wprss_settings_to_restore',
|
297 |
-
array(
|
298 |
-
'wprss_settings_general',
|
299 |
-
'wprss_settings_notices',
|
300 |
-
'wprss_addon_notices',
|
301 |
-
'wprss_pwsv',
|
302 |
-
'wprss_db_version'
|
303 |
-
)
|
304 |
-
);
|
305 |
-
// Delete the settings
|
306 |
-
foreach( $settings_to_restore as $setting ) {
|
307 |
-
delete_option( $setting );
|
308 |
-
}
|
309 |
-
|
310 |
-
// Action Hook
|
311 |
-
do_action( 'wprss_after_restore_settings' );
|
312 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin debugging
|
4 |
+
*
|
5 |
+
* @package WPRSSAggregator
|
6 |
+
* @subpackage Includes
|
7 |
+
* @since 3.0
|
8 |
+
* @author Jean Galea <info@jeangalea.com>
|
9 |
+
* @copyright Copyright(c) 2012-2013, Jean Galea
|
10 |
+
* @link http://www.wpmayor.com
|
11 |
+
* @license http://www.gnu.org/licenses/gpl.html
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*
|
15 |
+
//allow redirection, even if my theme starts to send output to the browser
|
16 |
+
add_action( 'admin_init', 'wprss_do_output_buffer' );
|
17 |
+
function wprss_do_output_buffer() {
|
18 |
+
//ob_start();
|
19 |
+
}*/
|
20 |
+
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Returns the debugging operations array
|
24 |
+
*
|
25 |
+
* @since 3.4.6
|
26 |
+
*/
|
27 |
+
function wprss_get_debug_operations() {
|
28 |
+
$operations = apply_filters(
|
29 |
+
'wprss_debug_operations',
|
30 |
+
array(
|
31 |
+
'update-feeds' => array(
|
32 |
+
'nonce' => 'wprss-update-feed-items',
|
33 |
+
'run' => 'wprss_fetch_insert_all_feed_items',
|
34 |
+
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=1',
|
35 |
+
'render' => 'wprss_debug_update_feeds',
|
36 |
+
),
|
37 |
+
|
38 |
+
'reimport-feeds' => array(
|
39 |
+
'nonce' => 'wprss-delete-import-feed-items',
|
40 |
+
'run' => 'wprss_feed_reset',
|
41 |
+
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=2',
|
42 |
+
'render' => 'wprss_debug_reimport_feeds',
|
43 |
+
),
|
44 |
+
|
45 |
+
)
|
46 |
+
);
|
47 |
+
|
48 |
+
$operations['error-log'] = apply_filters(
|
49 |
+
'wprss_debug_error_log_operation',
|
50 |
+
array(
|
51 |
+
'nonce' => 'wprss-clear-error-log',
|
52 |
+
'run' => 'wprss_clear_log',
|
53 |
+
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=3',
|
54 |
+
'render' => 'wprss_debug_clear_log_button'
|
55 |
+
)
|
56 |
+
);
|
57 |
+
|
58 |
+
$operations ['restore-settings'] = apply_filters(
|
59 |
+
'wprss_debug_restore_settings_operation',
|
60 |
+
array(
|
61 |
+
'nonce' => 'wprss-restore-settings',
|
62 |
+
'run' => 'wprss_restore_settings',
|
63 |
+
'redirect' => 'edit.php?post_type=wprss_feed&page=wprss-debugging&debug_message=4',
|
64 |
+
'render' => 'wprss_debug_restore_settings',
|
65 |
+
'pos' => 'bottom'
|
66 |
+
)
|
67 |
+
);
|
68 |
+
|
69 |
+
return $operations;
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
add_action( 'admin_init', 'wprss_debug_operations' );
|
74 |
+
/**
|
75 |
+
* Performs debug operations, depending on the POST request.
|
76 |
+
*
|
77 |
+
* @since 3.3
|
78 |
+
*/
|
79 |
+
function wprss_debug_operations(){
|
80 |
+
|
81 |
+
// Define the debugging operations
|
82 |
+
$debug_operations = wprss_get_debug_operations();
|
83 |
+
|
84 |
+
// Check which of the operations needs to be run
|
85 |
+
foreach ( $debug_operations as $id => $operation ) {
|
86 |
+
// If page loading after having clicked 'Update all fields'
|
87 |
+
if ( isset( $_POST[ $id ] ) && check_admin_referer( $operation['nonce'] ) ) {
|
88 |
+
call_user_func( $operation['run'] );
|
89 |
+
wp_redirect( $operation['redirect'] );
|
90 |
+
break;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Build the Update Feeds section
|
98 |
+
*
|
99 |
+
* @since 3.4.6
|
100 |
+
*/
|
101 |
+
function wprss_debug_update_feeds() {
|
102 |
+
?>
|
103 |
+
<h3><?php _e( 'Update All Feeds Now', WPRSS_TEXT_DOMAIN ); ?></h3>
|
104 |
+
<p><?php _e( 'Click the blue button to update all active feed items now. This will check all feed sources for any new feed items.', WPRSS_TEXT_DOMAIN ); ?>
|
105 |
+
<br><?php _e( 'Existing feed items will not be modified.', WPRSS_TEXT_DOMAIN ); ?>
|
106 |
+
</p>
|
107 |
+
<p><?php _e( '<strong>Note:</strong> This might take more than a few seconds if you have many feed sources.', WPRSS_TEXT_DOMAIN ); ?></p>
|
108 |
+
|
109 |
+
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
110 |
+
|
111 |
+
<?php wp_nonce_field( 'wprss-update-feed-items' );
|
112 |
+
submit_button( __( 'Update all feeds', WPRSS_TEXT_DOMAIN ), 'primary', 'update-feeds', true ); ?>
|
113 |
+
|
114 |
+
</form>
|
115 |
+
<?php
|
116 |
+
}
|
117 |
+
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Build the Delete and Re-Import Feeds section
|
121 |
+
*
|
122 |
+
* @since 3.4.6
|
123 |
+
*/
|
124 |
+
function wprss_debug_reimport_feeds() {
|
125 |
+
?>
|
126 |
+
<h3><?php _e( 'Delete and Re-import Feeds', WPRSS_TEXT_DOMAIN ); ?></h3>
|
127 |
+
<p><?php _e( 'Click the red button to delete all imported feed items and re-import them.', WPRSS_TEXT_DOMAIN ); ?></p>
|
128 |
+
<p><?php _e( '<em><strong>Note:</strong> This is a server-intensive process and should only be used when instructed to by support staff.</em>', WPRSS_TEXT_DOMAIN ); ?></p>
|
129 |
+
|
130 |
+
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
131 |
+
|
132 |
+
<?php wp_nonce_field( 'wprss-delete-import-feed-items' );
|
133 |
+
submit_button( __( 'Delete and Re-import all feeds', WPRSS_TEXT_DOMAIN ), 'button-red', 'reimport-feeds', true ); ?>
|
134 |
+
|
135 |
+
</form>
|
136 |
+
<?php
|
137 |
+
}
|
138 |
+
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Render the restore settings button
|
142 |
+
*
|
143 |
+
* @since 4.4
|
144 |
+
*/
|
145 |
+
function wprss_debug_restore_settings() {
|
146 |
+
?>
|
147 |
+
<h3><?php _e( 'Restore Default Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
148 |
+
<p><?php _e( 'Click the red button to reset the plugin settings to default.', WPRSS_TEXT_DOMAIN ); ?></p>
|
149 |
+
<p><?php _e( '<em><strong>Note:</strong> This cannot be undone. Once the settings have been reset, your old settings cannot be restored.</em>', WPRSS_TEXT_DOMAIN ); ?></p>
|
150 |
+
|
151 |
+
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="post">
|
152 |
+
|
153 |
+
<?php wp_nonce_field( 'wprss-restore-settings' );
|
154 |
+
submit_button( __( 'Restore Default Settings', WPRSS_TEXT_DOMAIN ), 'button-red', 'restore-settings', true ); ?>
|
155 |
+
|
156 |
+
</form>
|
157 |
+
<?php
|
158 |
+
}
|
159 |
+
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Renders the Clear Log button
|
163 |
+
*
|
164 |
+
* @since 3.9.6
|
165 |
+
*/
|
166 |
+
function wprss_debug_clear_log_button() {
|
167 |
+
?>
|
168 |
+
<h3><?php _e( 'Error Log', WPRSS_TEXT_DOMAIN ); ?></h3>
|
169 |
+
|
170 |
+
<textarea readonly="readonly" id="wprss-error-log-textarea"><?php echo wprss_get_log(); ?></textarea>
|
171 |
+
|
172 |
+
<form action="edit.php?post_type=wprss_feed&page=wprss-debugging" method="POST">
|
173 |
+
<?php wp_nonce_field( 'wprss-clear-error-log' );
|
174 |
+
submit_button( __( 'Clear log', WPRSS_TEXT_DOMAIN ), 'button-primary', 'error-log', true ); ?>
|
175 |
+
</form>
|
176 |
+
|
177 |
+
<?php
|
178 |
+
}
|
179 |
+
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Build the debugging page
|
183 |
+
*
|
184 |
+
* @since 3.0
|
185 |
+
*/
|
186 |
+
function wprss_debugging_page_display() {
|
187 |
+
$debug_messages = apply_filters(
|
188 |
+
'wprss_debug_messages',
|
189 |
+
array(
|
190 |
+
'1' => 'wprss_debugging_admin_notice_update_feeds',
|
191 |
+
'2' => 'wprss_debugging_admin_notice_reimport_feeds',
|
192 |
+
'3' => 'wprss_debugging_admin_notice_clear_log',
|
193 |
+
'4' => 'wprss_debugging_admin_notice_reset_settings'
|
194 |
+
)
|
195 |
+
);
|
196 |
+
|
197 |
+
?>
|
198 |
+
|
199 |
+
<div class="wrap">
|
200 |
+
<?php screen_icon( 'wprss-aggregator' ); ?>
|
201 |
+
|
202 |
+
<h2><?php _e( 'Debugging', WPRSS_TEXT_DOMAIN ); ?></h2>
|
203 |
+
<?php
|
204 |
+
if ( isset( $_GET['debug_message'] )) {//&& ( check_admin_referer( 'wprss-delete-import-feed-items' ) || check_admin_referer( 'wprss-update-feed-items' ) ) ) {
|
205 |
+
$message = $_GET['debug_message'];
|
206 |
+
|
207 |
+
foreach ( $debug_messages as $id => $callback) {
|
208 |
+
if ( $message == $id ) {
|
209 |
+
call_user_func( $callback );
|
210 |
+
break;
|
211 |
+
}
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
do_action( 'wprss_debugging_before' );
|
216 |
+
|
217 |
+
$bottom = array();
|
218 |
+
$debug_operations = wprss_get_debug_operations();
|
219 |
+
foreach( $debug_operations as $id => $data ) {
|
220 |
+
if ( !isset( $data['render'] ) ) continue;
|
221 |
+
$pos = isset( $data['pos'] ) ? $data['pos'] : 'normal';
|
222 |
+
if ( $pos == 'normal' ) {
|
223 |
+
call_user_func( $data['render'] );
|
224 |
+
} elseif( $pos == 'bottom' ) {
|
225 |
+
$bottom[$id] = $data;
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
do_action( 'wprss_debugging_after' );
|
230 |
+
|
231 |
+
wprss_system_info();
|
232 |
+
|
233 |
+
if ( count($bottom) > 0 ) {
|
234 |
+
foreach( $bottom as $id => $data ) {
|
235 |
+
if ( !isset( $data['render'] ) ) continue;
|
236 |
+
call_user_func( $data['render'] );
|
237 |
+
}
|
238 |
+
}
|
239 |
+
|
240 |
+
?>
|
241 |
+
</div>
|
242 |
+
<?php
|
243 |
+
}
|
244 |
+
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Output admin notice that feeds have been updated successfully
|
248 |
+
*
|
249 |
+
* @since 3.0
|
250 |
+
*/
|
251 |
+
function wprss_debugging_admin_notice_update_feeds() {
|
252 |
+
?><div class="updated"><p><?php _e( 'Feeds are being updated in the background.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Output admin notice that feeds have been deleted and re-imported successfully
|
257 |
+
*
|
258 |
+
* @since 3.0
|
259 |
+
*/
|
260 |
+
function wprss_debugging_admin_notice_reimport_feeds() {
|
261 |
+
?><div class="updated"><p><?php _e( 'Feeds deleted and are being re-imported in the background.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
262 |
+
}
|
263 |
+
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Output admin notice that log has been cleard
|
267 |
+
*
|
268 |
+
* @since 3.9.6
|
269 |
+
*/
|
270 |
+
function wprss_debugging_admin_notice_clear_log() {
|
271 |
+
?><div class="updated"><p><?php _e( 'The error log has been cleared.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
272 |
+
}
|
273 |
+
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Output admin notice that log has been cleard
|
277 |
+
*
|
278 |
+
* @since 4.4
|
279 |
+
*/
|
280 |
+
function wprss_debugging_admin_notice_reset_settings() {
|
281 |
+
?><div class="updated"><p><?php _e( 'The plugin settings have been reset to default.', WPRSS_TEXT_DOMAIN ) ?></p></div><?php
|
282 |
+
}
|
283 |
+
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Resets the plugin settings to default
|
287 |
+
*
|
288 |
+
* @since 4.4
|
289 |
+
*/
|
290 |
+
function wprss_restore_settings() {
|
291 |
+
// Action Hook
|
292 |
+
do_action( 'wprss_before_restore_settings' );
|
293 |
+
|
294 |
+
// Prepare the settings to reset
|
295 |
+
$settings_to_restore = apply_filters(
|
296 |
+
'wprss_settings_to_restore',
|
297 |
+
array(
|
298 |
+
'wprss_settings_general',
|
299 |
+
'wprss_settings_notices',
|
300 |
+
'wprss_addon_notices',
|
301 |
+
'wprss_pwsv',
|
302 |
+
'wprss_db_version'
|
303 |
+
)
|
304 |
+
);
|
305 |
+
// Delete the settings
|
306 |
+
foreach( $settings_to_restore as $setting ) {
|
307 |
+
delete_option( $setting );
|
308 |
+
}
|
309 |
+
|
310 |
+
// Action Hook
|
311 |
+
do_action( 'wprss_after_restore_settings' );
|
312 |
+
}
|
includes/admin-display.php
CHANGED
@@ -1,619 +1,619 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Functions for the admin section, columns and row actions
|
4 |
-
*
|
5 |
-
* @package WP RSS Aggregator
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
add_filter( 'manage_wprss_feed_posts_columns', 'wprss_set_feed_custom_columns', 20, 1 );
|
10 |
-
/**
|
11 |
-
* Set up the custom columns for the wprss_feed list
|
12 |
-
*
|
13 |
-
* @since 2.0
|
14 |
-
*/
|
15 |
-
function wprss_set_feed_custom_columns( $columns ) {
|
16 |
-
|
17 |
-
$columns = array(
|
18 |
-
'cb' => '<input type="checkbox" />',
|
19 |
-
'errors' => '',
|
20 |
-
'title' => __( 'Name', WPRSS_TEXT_DOMAIN ),
|
21 |
-
);
|
22 |
-
|
23 |
-
$columns = apply_filters( 'wprss_set_feed_custom_columns', $columns );
|
24 |
-
|
25 |
-
// Columns to add when feed is not trashed
|
26 |
-
if ( !isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'trash' ) {
|
27 |
-
$columns['state'] = __( 'State', WPRSS_TEXT_DOMAIN );
|
28 |
-
$columns['updates'] = __( 'Updates', WPRSS_TEXT_DOMAIN );
|
29 |
-
$columns['feed-count'] = __( apply_filters( 'wprss_feed_items_count_column', 'Imported items' ), WPRSS_TEXT_DOMAIN );
|
30 |
-
}
|
31 |
-
|
32 |
-
return $columns;
|
33 |
-
}
|
34 |
-
|
35 |
-
|
36 |
-
add_action( "manage_wprss_feed_posts_custom_column", "wprss_show_custom_columns", 10, 2 );
|
37 |
-
/**
|
38 |
-
* Show up the custom columns for the wprss_feed list
|
39 |
-
*
|
40 |
-
* @since 2.0
|
41 |
-
*/
|
42 |
-
function wprss_show_custom_columns( $column, $post_id ) {
|
43 |
-
|
44 |
-
switch ( $column ) {
|
45 |
-
case 'errors':
|
46 |
-
$errors = get_post_meta( $post_id, 'wprss_error_last_import', true );
|
47 |
-
$showClass = ( $errors !== '' )? 'wprss-show' : '';
|
48 |
-
$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 );
|
49 |
-
$msg = strlen( $errors ) > 0 ? $errors : $default_msg;
|
50 |
-
echo "<i title=\"$msg\" class=\"fa fa-warning fa-fw wprss-feed-error-symbol $showClass\"></i>";
|
51 |
-
break;
|
52 |
-
case 'state':
|
53 |
-
$active = wprss_is_feed_source_active( $post_id );
|
54 |
-
$text = ( $active )? 'Active' : 'Paused';
|
55 |
-
$button = ( $active )? 'Pause this feed source' : 'Activate this feed source';
|
56 |
-
$icon = ( $active )? 'pause' : 'play';
|
57 |
-
$value = ( $active )? 'paused' : 'active';
|
58 |
-
$indicator = ( $active )? 'green' : 'grey';
|
59 |
-
|
60 |
-
?>
|
61 |
-
<p>
|
62 |
-
<span class="wprss-indicator-<?php echo $indicator; ?>" title="<?php _e( $text, WPRSS_TEXT_DOMAIN ) ?>">
|
63 |
-
<i class="fa fa-circle"></i>
|
64 |
-
</span>
|
65 |
-
<input type="hidden" name="wprss-redirect" value="1" />
|
66 |
-
<button type="submit" class='button-secondary' title="<?php _e( $button, WPRSS_TEXT_DOMAIN ) ?>" name="wprss-feed-id" value="<?php echo $post_id; ?>">
|
67 |
-
<i class='fa fa-<?php echo $icon; ?>'></i>
|
68 |
-
</button>
|
69 |
-
</p>
|
70 |
-
<?php
|
71 |
-
|
72 |
-
break;
|
73 |
-
|
74 |
-
case 'updates':
|
75 |
-
// Get the update interval
|
76 |
-
$update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
|
77 |
-
// Get the last updated and next update data
|
78 |
-
$last_update = get_post_meta( $post_id, 'wprss_last_update', TRUE );
|
79 |
-
$last_update_items = get_post_meta( $post_id, 'wprss_last_update_items', TRUE );
|
80 |
-
$next_update = wprss_get_next_feed_source_update( $post_id );
|
81 |
-
|
82 |
-
// If using the global interval, get the timestamp of the next global update
|
83 |
-
if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
|
84 |
-
$next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
|
85 |
-
}
|
86 |
-
|
87 |
-
// Update the meta field
|
88 |
-
if ( wprss_is_feed_source_active( $post_id ) ) {
|
89 |
-
$next_update_text = $next_update === FALSE ? __( 'None', WPRSS_TEXT_DOMAIN ) : human_time_diff( $next_update, time() );
|
90 |
-
} else {
|
91 |
-
$next_update_text = __( 'Paused', WPRSS_TEXT_DOMAIN );
|
92 |
-
}
|
93 |
-
update_post_meta( $post_id, 'wprss_next_update', $next_update_text );
|
94 |
-
|
95 |
-
?>
|
96 |
-
|
97 |
-
<p>
|
98 |
-
<?php _e( 'Next update:', WPRSS_TEXT_DOMAIN ) ?>
|
99 |
-
<code class="next-update">
|
100 |
-
<?php echo $next_update_text; ?>
|
101 |
-
</code>
|
102 |
-
</p>
|
103 |
-
|
104 |
-
<?php if ( $last_update !== '' ): ?>
|
105 |
-
<p class="last-update-container">
|
106 |
-
<?php _e( 'Last updated:', WPRSS_TEXT_DOMAIN ) ?>
|
107 |
-
<code class="last-update"><?php echo sprintf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), human_time_diff( $last_update, time() ) ) ?></code>
|
108 |
-
<?php if ( $last_update_items !== '' ): ?>
|
109 |
-
<span class="last-update-imported-container"><br/><?php echo sprintf( __( 'Last update imported: <code class="last-update-imported">%1$d</code> items', WPRSS_TEXT_DOMAIN ), $last_update_items ) ?></span>
|
110 |
-
<?php endif; ?>
|
111 |
-
</p>
|
112 |
-
<?php endif;
|
113 |
-
|
114 |
-
break;
|
115 |
-
|
116 |
-
case 'feed-count':
|
117 |
-
$items = wprss_get_feed_items_for_source( $post_id );
|
118 |
-
$seconds_for_next_update = wprss_get_next_feed_source_update( $post_id ) - time();
|
119 |
-
$showClass = ( ( $seconds_for_next_update < 10 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_deleting( $post_id ) )? 'wprss-show' : '';
|
120 |
-
|
121 |
-
?>
|
122 |
-
<p>
|
123 |
-
<span class="items-imported"><?php echo $items->post_count ?></span>
|
124 |
-
<i class="fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon <?php echo $showClass ?>" title="<?php _e( 'Updating feed source', WPRSS_TEXT_DOMAIN ) ?>"></i>
|
125 |
-
</p>
|
126 |
-
<?php
|
127 |
-
|
128 |
-
// Set meta field for items imported
|
129 |
-
update_post_meta( $post_id, 'wprss_items_imported', $items->post_count );
|
130 |
-
|
131 |
-
break;
|
132 |
-
}
|
133 |
-
}
|
134 |
-
|
135 |
-
|
136 |
-
add_filter( "manage_edit-wprss_feed_sortable_columns", "wprss_feed_sortable_columns" );
|
137 |
-
/**
|
138 |
-
* Make the custom columns sortable for wprss_feed post type
|
139 |
-
*
|
140 |
-
* @since 2.0
|
141 |
-
*/
|
142 |
-
function wprss_feed_sortable_columns() {
|
143 |
-
$sortable_columns = array(
|
144 |
-
// meta column id => sortby value used in query
|
145 |
-
'title' => 'title',
|
146 |
-
'updates' => 'updates',
|
147 |
-
'state' => 'state',
|
148 |
-
'feed-count' => 'feed-count'
|
149 |
-
);
|
150 |
-
return apply_filters( 'wprss_feed_sortable_columns', $sortable_columns );
|
151 |
-
}
|
152 |
-
|
153 |
-
|
154 |
-
add_action( 'pre_get_posts', 'wprss_feed_source_order' );
|
155 |
-
/**
|
156 |
-
* Change order of feed sources to alphabetical ascending according to feed name
|
157 |
-
*
|
158 |
-
* @since 2.2
|
159 |
-
*/
|
160 |
-
function wprss_feed_source_order( $query ) {
|
161 |
-
// Check if the query is being processed in WP Admin, is the main query, and is targetted
|
162 |
-
// for the wprss_feed CPT. If not, stop
|
163 |
-
if ( !is_admin() || !$query->is_main_query() || $query->get('post_type') !== 'wprss_feed' ) {
|
164 |
-
return;
|
165 |
-
}
|
166 |
-
// Check if the orderby query variable is set
|
167 |
-
if ( !( $orderby = $query->get( 'orderby' ) ) ) return;
|
168 |
-
|
169 |
-
// We will be sorting using the meta value (unless sorting by title)
|
170 |
-
$query->set('orderby', 'meta_value' );
|
171 |
-
// Get the current order
|
172 |
-
$order = strtoupper( $query->get( 'order' ) );
|
173 |
-
// Check if it is valid
|
174 |
-
$got_order = $order === 'ASC' || $order === 'DESC';
|
175 |
-
|
176 |
-
// Check what we are sorting by
|
177 |
-
switch ( $orderby ) {
|
178 |
-
case 'title':
|
179 |
-
$query->set( 'orderby', 'title' );
|
180 |
-
break;
|
181 |
-
case 'state':
|
182 |
-
$query->set('meta_key', 'wprss_state');
|
183 |
-
break;
|
184 |
-
case 'updates':
|
185 |
-
$query->set('meta_key', 'wprss_next_update');
|
186 |
-
$query->set('orderby', 'meta_value' );
|
187 |
-
if ( !$got_order ) $query->set( 'order', 'ASC' );
|
188 |
-
break;
|
189 |
-
case 'feed-count':
|
190 |
-
$query->set('meta_key', 'wprss_items_imported');
|
191 |
-
$query->set('orderby', 'meta_value_num' );
|
192 |
-
if ( !$got_order ) $query->set( 'order', 'DESC' );
|
193 |
-
break;
|
194 |
-
}
|
195 |
-
|
196 |
-
if ( !$got_order ){
|
197 |
-
$query->set( 'order', 'ASC' );
|
198 |
-
}
|
199 |
-
}
|
200 |
-
|
201 |
-
|
202 |
-
add_filter( 'manage_wprss_feed_item_posts_columns', 'wprss_set_feed_item_custom_columns', 20, 1 );
|
203 |
-
/**
|
204 |
-
* Set up the custom columns for the wprss_feed source list
|
205 |
-
*
|
206 |
-
* @since 2.0
|
207 |
-
*/
|
208 |
-
function wprss_set_feed_item_custom_columns( $columns ) {
|
209 |
-
|
210 |
-
$columns = array (
|
211 |
-
'cb' => '<input type="checkbox" />',
|
212 |
-
'title' => __( 'Name', WPRSS_TEXT_DOMAIN ),
|
213 |
-
'permalink' => __( 'Permalink', WPRSS_TEXT_DOMAIN ),
|
214 |
-
'publishdate' => __( 'Date published', WPRSS_TEXT_DOMAIN ),
|
215 |
-
'source' => __( 'Source', WPRSS_TEXT_DOMAIN )
|
216 |
-
);
|
217 |
-
return apply_filters( 'wprss_set_feed_item_custom_columns', $columns );
|
218 |
-
}
|
219 |
-
|
220 |
-
|
221 |
-
add_action( "manage_wprss_feed_item_posts_custom_column", "wprss_show_feed_item_custom_columns", 10, 2 );
|
222 |
-
/**
|
223 |
-
* Show up the custom columns for the wprss_feed list
|
224 |
-
*
|
225 |
-
* @since 2.0
|
226 |
-
*/
|
227 |
-
function wprss_show_feed_item_custom_columns( $column, $post_id ) {
|
228 |
-
|
229 |
-
switch ( $column ) {
|
230 |
-
case "permalink":
|
231 |
-
$url = get_post_meta( $post_id, 'wprss_item_permalink', true);
|
232 |
-
echo '<a href="' . $url . '">' . $url. '</a>';
|
233 |
-
break;
|
234 |
-
|
235 |
-
case "publishdate":
|
236 |
-
$item_date = get_the_time( 'U', get_the_ID() );
|
237 |
-
$item_date = ( $item_date === '' )? date('U') : $item_date;
|
238 |
-
$publishdate = date( 'Y-m-d H:i:s', $item_date ) ;
|
239 |
-
echo $publishdate;
|
240 |
-
break;
|
241 |
-
|
242 |
-
case "source":
|
243 |
-
$query = new WP_Query();
|
244 |
-
$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>';
|
245 |
-
echo $source;
|
246 |
-
break;
|
247 |
-
}
|
248 |
-
}
|
249 |
-
|
250 |
-
|
251 |
-
add_filter( "manage_edit-wprss_feed_item_sortable_columns", "wprss_feed_item_sortable_columns" );
|
252 |
-
/**
|
253 |
-
* Make the custom columns sortable
|
254 |
-
*
|
255 |
-
* @since 2.0
|
256 |
-
*/
|
257 |
-
function wprss_feed_item_sortable_columns() {
|
258 |
-
$sortable_columns = array(
|
259 |
-
// meta column id => sortby value used in query
|
260 |
-
'publishdate' => 'publishdate',
|
261 |
-
'source' => 'source'
|
262 |
-
);
|
263 |
-
return apply_filters( 'wprss_feed_item_sortable_columns', $sortable_columns );
|
264 |
-
}
|
265 |
-
|
266 |
-
|
267 |
-
add_action( 'pre_get_posts', 'wprss_feed_item_orderby' );
|
268 |
-
/**
|
269 |
-
* Change ordering of posts on wprss_feed_item screen
|
270 |
-
*
|
271 |
-
* @since 2.0
|
272 |
-
*/
|
273 |
-
function wprss_feed_item_orderby( $query ) {
|
274 |
-
if( ! is_admin() )
|
275 |
-
return;
|
276 |
-
|
277 |
-
$post_type = $query->get('post_type');
|
278 |
-
|
279 |
-
// If we're on the feed listing admin page
|
280 |
-
if ( $post_type == 'wprss_feed_item') {
|
281 |
-
// Set general orderby to date the feed item was published
|
282 |
-
$query->set('orderby','publishdate');
|
283 |
-
// If user clicks on the reorder link, implement reordering
|
284 |
-
$orderby = $query->get( 'orderby');
|
285 |
-
if( 'publishdate' == $orderby ) {
|
286 |
-
$query->set( 'order', 'DESC' );
|
287 |
-
$query->set( 'orderby', 'date' );
|
288 |
-
}
|
289 |
-
}
|
290 |
-
}
|
291 |
-
|
292 |
-
|
293 |
-
add_filter( 'post_updated_messages', 'wprss_feed_updated_messages' );
|
294 |
-
/**
|
295 |
-
* Change default notification message when new feed is added or updated
|
296 |
-
*
|
297 |
-
* @since 2.0
|
298 |
-
*/
|
299 |
-
function wprss_feed_updated_messages( $messages ) {
|
300 |
-
global $post, $post_ID;
|
301 |
-
|
302 |
-
$messages[ 'wprss_feed' ] = array(
|
303 |
-
0 => '', // Unused. Messages start at index 1.
|
304 |
-
1 => __( 'Feed source updated. ', WPRSS_TEXT_DOMAIN ),
|
305 |
-
2 => __( 'Custom field updated.', WPRSS_TEXT_DOMAIN ),
|
306 |
-
3 => __( 'Custom field deleted.', WPRSS_TEXT_DOMAIN ),
|
307 |
-
4 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN ),
|
308 |
-
5 => '',
|
309 |
-
6 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
|
310 |
-
7 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
|
311 |
-
8 => __( 'Feed source submitted.', WPRSS_TEXT_DOMAIN ),
|
312 |
-
9 => '',
|
313 |
-
10 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN )
|
314 |
-
);
|
315 |
-
|
316 |
-
return apply_filters( 'wprss_feed_updated_messages', $messages );
|
317 |
-
}
|
318 |
-
|
319 |
-
|
320 |
-
add_filter( 'post_row_actions', 'wprss_remove_row_actions', 10, 2 );
|
321 |
-
/**
|
322 |
-
* Remove actions row for imported feed items, we don't want them to be editable or viewable
|
323 |
-
*
|
324 |
-
* @since 2.0
|
325 |
-
*/
|
326 |
-
function wprss_remove_row_actions( $actions, $post )
|
327 |
-
{
|
328 |
-
|
329 |
-
$page = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
330 |
-
if ( get_post_type($post) === 'wprss_feed_item' ) {
|
331 |
-
unset( $actions[ 'edit' ] );
|
332 |
-
unset( $actions[ 'view' ] );
|
333 |
-
//unset( $actions[ 'trash' ] );
|
334 |
-
unset( $actions[ 'inline hide-if-no-js' ] );
|
335 |
-
}
|
336 |
-
elseif ( get_post_type($post) === 'wprss_feed' ) {
|
337 |
-
$actions = array_reverse( $actions );
|
338 |
-
$actions['id'] = '<span class="wprss-row-id">' . sprintf( __( 'ID: %1$s', WPRSS_TEXT_DOMAIN ), $post->ID ) . '</span>';
|
339 |
-
$actions = array_reverse( $actions );
|
340 |
-
|
341 |
-
unset( $actions[ 'view'] );
|
342 |
-
unset( $actions[ 'inline hide-if-no-js'] );
|
343 |
-
if ( get_post_status( $post->ID ) !== 'trash' ) {
|
344 |
-
$trash = $actions['trash'];
|
345 |
-
unset( $actions['trash'] );
|
346 |
-
|
347 |
-
$view_items_link = apply_filters(
|
348 |
-
'wprss_view_feed_items_row_action_link',
|
349 |
-
admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . $post->ID ),
|
350 |
-
$post->ID
|
351 |
-
);
|
352 |
-
$view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', __( 'View Items', WPRSS_TEXT_DOMAIN ) );
|
353 |
-
$actions['view-items'] = '<a href="' . $view_items_link . '">' . $view_items_text . '</a>';
|
354 |
-
|
355 |
-
$fetch_items_row_action_text = apply_filters( 'wprss_fetch_items_row_action_text', __( 'Fetch Items', WPRSS_TEXT_DOMAIN ) );
|
356 |
-
$actions[ 'fetch' ] = '<a href="javascript:;" class="wprss_ajax_action" pid="'. $post->ID .'" purl="'.home_url().'/wp-admin/admin-ajax.php">' . $fetch_items_row_action_text . '</a>';
|
357 |
-
|
358 |
-
$purge_feeds_row_action_text = apply_filters( 'wprss_purge_feeds_row_action_text', __( 'Delete Items', WPRSS_TEXT_DOMAIN ) );
|
359 |
-
$purge_feeds_row_action_title = apply_filters( 'wprss_purge_feeds_row_action_title', __( 'Delete feed items imported by this feed source', WPRSS_TEXT_DOMAIN ) );
|
360 |
-
$actions['purge-posts'] = "<a href='".admin_url("edit.php?post_type=wprss_feed&purge-feed-items=" . $post->ID . $page ) . "' title='" . $purge_feeds_row_action_title . "' >" . __( $purge_feeds_row_action_text, WPRSS_TEXT_DOMAIN ) . "</a>";
|
361 |
-
|
362 |
-
$actions['trash'] = $trash;
|
363 |
-
}
|
364 |
-
}
|
365 |
-
return apply_filters( 'wprss_remove_row_actions', $actions );
|
366 |
-
}
|
367 |
-
|
368 |
-
|
369 |
-
add_action( 'admin_init', 'check_delete_for_feed_source' );
|
370 |
-
/**
|
371 |
-
* Checks the GET data for the delete per feed source action request
|
372 |
-
*
|
373 |
-
* @since 3.5
|
374 |
-
*/
|
375 |
-
function check_delete_for_feed_source( $source_id = NULL ) {
|
376 |
-
if ( ! current_user_can( 'delete_feeds' ) ) return;
|
377 |
-
// then we need to check the GET data for the request
|
378 |
-
if ( isset( $_GET['purge-feed-items'] ) ) {
|
379 |
-
$source_id = $_GET['purge-feed-items'];
|
380 |
-
// Schedule a job that runs this function with the source id parameter
|
381 |
-
wp_schedule_single_event( time(), 'wprss_delete_feed_items_from_source_hook', array( $source_id ) );
|
382 |
-
// Set a transient
|
383 |
-
set_transient( 'wprss_delete_posts_by_source_notif', 'true', 30 );
|
384 |
-
// Mark feed as deleting its items
|
385 |
-
update_post_meta( $source_id, 'wprss_feed_is_deleting_items', time() );
|
386 |
-
// check pagination
|
387 |
-
$page = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
388 |
-
// Refresh the page without the GET parameter
|
389 |
-
header( 'Location: ' . admin_url( 'edit.php?post_type=wprss_feed' . $page ) );
|
390 |
-
exit();
|
391 |
-
} else {
|
392 |
-
// Get the notification transient
|
393 |
-
$transient = get_transient( 'wprss_delete_posts_by_source_notif' );
|
394 |
-
// If the transient is set and is set to 'true'
|
395 |
-
if ( $transient !== FALSE && $transient === 'true' ) {
|
396 |
-
// delete it
|
397 |
-
delete_transient( 'wprss_delete_posts_by_source_notif' );
|
398 |
-
// Add an action to show the notification
|
399 |
-
add_action( 'all_admin_notices', 'wprss_notify_about_deleting_source_feed_items' );
|
400 |
-
}
|
401 |
-
}
|
402 |
-
}
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
add_action( 'wprss_delete_feed_items_from_source_hook', 'wprss_delete_feed_items_of_feed_source', 10 , 1 );
|
407 |
-
/**
|
408 |
-
* Deletes the feed items of the feed source identified by the given ID.
|
409 |
-
*
|
410 |
-
* @param $source_id The ID of the feed source
|
411 |
-
* @since 3.5
|
412 |
-
*/
|
413 |
-
function wprss_delete_feed_items_of_feed_source( $source_id ) {
|
414 |
-
$force_delete = apply_filters( 'wprss_force_delete_when_by_source', TRUE );
|
415 |
-
// WPML fix: removes the current language from the query WHERE and JOIN clauses
|
416 |
-
global $sitepress;
|
417 |
-
if ( $sitepress !== NULL ) {
|
418 |
-
remove_filter( 'posts_join', array( $sitepress,'posts_join_filter') );
|
419 |
-
remove_filter( 'posts_where', array( $sitepress,'posts_where_filter') );
|
420 |
-
}
|
421 |
-
// Run the query
|
422 |
-
$query = new WP_Query(
|
423 |
-
array(
|
424 |
-
'meta_key' => 'wprss_feed_id',
|
425 |
-
'meta_value' => $source_id,
|
426 |
-
'post_type' => 'wprss_feed_item',
|
427 |
-
'post_status' => 'any',
|
428 |
-
'posts_per_page' => -1
|
429 |
-
)
|
430 |
-
);
|
431 |
-
$query = apply_filters( 'wprss_delete_per_source_query', $query, $source_id );
|
432 |
-
// Delete the results of the query
|
433 |
-
while( $query->have_posts() ) {
|
434 |
-
$query->the_post();
|
435 |
-
wp_delete_post( get_the_ID(), $force_delete );
|
436 |
-
}
|
437 |
-
}
|
438 |
-
|
439 |
-
|
440 |
-
/**
|
441 |
-
* Shows a notification that tells the user that feed items for a particular source are being deleted
|
442 |
-
*
|
443 |
-
* @since 3.5
|
444 |
-
*/
|
445 |
-
function wprss_notify_about_deleting_source_feed_items() {
|
446 |
-
$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 );
|
447 |
-
echo '<div class="updated"><p>' . $message . '</p></div>';
|
448 |
-
}
|
449 |
-
|
450 |
-
|
451 |
-
add_action( 'wp_ajax_wprss_fetch_feeds_row_action', 'wprss_fetch_feeds_action_hook' );
|
452 |
-
/**
|
453 |
-
* The AJAX function for the 'Fetch Feed Items' row action on the
|
454 |
-
* 'All Feed Sources' page.
|
455 |
-
*
|
456 |
-
* @since 3.3
|
457 |
-
*/
|
458 |
-
function wprss_fetch_feeds_action_hook() {
|
459 |
-
if ( isset( $_POST['id'] ) && !empty( $_POST['id'] ) ) {
|
460 |
-
if ( ! current_user_can( 'edit_feed_sources' ) ) die();
|
461 |
-
$id = $_POST['id'];
|
462 |
-
update_post_meta( $id, 'wprss_force_next_fetch', '1' );
|
463 |
-
|
464 |
-
// Prepare the schedule args
|
465 |
-
$schedule_args = array( strval( $id ) );
|
466 |
-
|
467 |
-
// Get the current schedule - do nothing if not scheduled
|
468 |
-
$next_scheduled = wp_next_scheduled( 'wprss_fetch_single_feed_hook', $schedule_args );
|
469 |
-
if ( $next_scheduled !== FALSE ) {
|
470 |
-
// If scheduled, unschedule it
|
471 |
-
wp_unschedule_event( $next_scheduled, 'wprss_fetch_single_feed_hook', $schedule_args );
|
472 |
-
|
473 |
-
// Get the interval option for the feed source
|
474 |
-
$interval = get_post_meta( $id, 'wprss_update_interval', TRUE );
|
475 |
-
// if the feed source uses its own interval
|
476 |
-
if ( $interval !== '' && $interval !== wprss_get_default_feed_source_update_interval() ) {
|
477 |
-
// Add meta in feed source. This is used to notify the source that it needs to reschedule it
|
478 |
-
update_post_meta( $id, 'wprss_reschedule_event', $next_scheduled );
|
479 |
-
}
|
480 |
-
}
|
481 |
-
|
482 |
-
// Schedule the event for 5 seconds from now
|
483 |
-
wp_schedule_single_event( time() + 1, 'wprss_fetch_single_feed_hook', $schedule_args );
|
484 |
-
wprss_flag_feed_as_updating( $id );
|
485 |
-
die();
|
486 |
-
}
|
487 |
-
}
|
488 |
-
|
489 |
-
|
490 |
-
add_filter( 'bulk_actions-edit-wprss_feed_item', 'wprss_custom_feed_item_bulk_actions' );
|
491 |
-
/**
|
492 |
-
* Remove bulk action link to edit imported feed items
|
493 |
-
*
|
494 |
-
* @since 2.0
|
495 |
-
*/
|
496 |
-
function wprss_custom_feed_item_bulk_actions( $actions ){
|
497 |
-
unset( $actions[ 'edit' ] );
|
498 |
-
return apply_filters( 'wprss_custom_feed_item_bulk_actions', $actions );
|
499 |
-
}
|
500 |
-
|
501 |
-
|
502 |
-
add_action( 'admin_footer-edit.php', 'wprss_remove_a_from_feed_title' );
|
503 |
-
/**
|
504 |
-
* Remove hyperlink from imported feed titles in list posts screen
|
505 |
-
*
|
506 |
-
* @since 2.0
|
507 |
-
*/
|
508 |
-
function wprss_remove_a_from_feed_title() {
|
509 |
-
if ( 'edit-wprss_feed_item' !== get_current_screen()->id )
|
510 |
-
return;
|
511 |
-
?>
|
512 |
-
|
513 |
-
<script type="text/javascript">
|
514 |
-
jQuery('table.wp-list-table a.row-title').contents().unwrap();
|
515 |
-
</script>
|
516 |
-
<?php
|
517 |
-
}
|
518 |
-
|
519 |
-
|
520 |
-
add_filter( 'gettext', 'wprss_change_publish_button_text', 10, 2 );
|
521 |
-
/**
|
522 |
-
* Modify 'Publish' button text when adding a new feed source
|
523 |
-
*
|
524 |
-
* @since 2.0
|
525 |
-
*/
|
526 |
-
function wprss_change_publish_button_text( $translation, $text ) {
|
527 |
-
if ( 'wprss_feed' == get_post_type()) {
|
528 |
-
if ( $text == 'Publish' )
|
529 |
-
return __( 'Publish Feed', WPRSS_TEXT_DOMAIN );
|
530 |
-
}
|
531 |
-
return apply_filters( 'wprss_change_publish_button_text', $translation );
|
532 |
-
}
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
add_action( 'wp_before_admin_bar_render', 'wprss_modify_admin_bar' );
|
537 |
-
/**
|
538 |
-
* Removes the old "View Source" menu item from the admin bar and adds a new
|
539 |
-
* "View items" menu bar item, that opens a new tab, showing the items imported
|
540 |
-
* from that feed source.
|
541 |
-
*
|
542 |
-
* Only shown on the wprss_feed edit page.
|
543 |
-
*
|
544 |
-
* @since 4.2
|
545 |
-
*/
|
546 |
-
function wprss_modify_admin_bar() {
|
547 |
-
global $wp_admin_bar;
|
548 |
-
if ( !is_admin() ) return;
|
549 |
-
$screen = get_current_screen();
|
550 |
-
// Check if we are in the wprss_feed edit page
|
551 |
-
if ( $screen->base == 'post' && $screen->post_type == 'wprss_feed' && !empty( $_GET['action'] ) && $_GET['action'] == 'edit' ) {
|
552 |
-
// Remove the old 'View Source' menu item
|
553 |
-
$wp_admin_bar->remove_node( 'view' );
|
554 |
-
|
555 |
-
// Prepare the view items link and text
|
556 |
-
$view_items_link = apply_filters(
|
557 |
-
'wprss_view_feed_items_row_action_link',
|
558 |
-
admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID() ),
|
559 |
-
get_the_ID()
|
560 |
-
);
|
561 |
-
$view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', 'View Items' );
|
562 |
-
|
563 |
-
// Prepare the link target
|
564 |
-
$link_target = 'wprss-view-items-' . get_the_ID();
|
565 |
-
|
566 |
-
// Add the new menu item
|
567 |
-
$wp_admin_bar->add_node( array(
|
568 |
-
'href' => $view_items_link,
|
569 |
-
'id' => 'view',
|
570 |
-
'title' => __( $view_items_text, WPRSS_TEXT_DOMAIN ),
|
571 |
-
'meta' => array(
|
572 |
-
'target' => $link_target
|
573 |
-
)
|
574 |
-
));
|
575 |
-
}
|
576 |
-
}
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
if ( is_admin() ){
|
582 |
-
add_filter('pre_get_posts', 'wprss_view_feed_items_query');
|
583 |
-
/**
|
584 |
-
* Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
|
585 |
-
* The queried items are then filtered down to the items imported by the feed source with
|
586 |
-
* the ID given in the wprss_feed GET parameter.
|
587 |
-
*
|
588 |
-
* @since 4.2
|
589 |
-
*/
|
590 |
-
function wprss_view_feed_items_query( $query ) {
|
591 |
-
if ( is_admin() && $query->is_main_query() && !empty($_GET['wprss_feed']) ) {
|
592 |
-
// Get the ID from the GET param
|
593 |
-
$id = $_GET['wprss_feed'];
|
594 |
-
// Get the existing meta query
|
595 |
-
$mq = $query->get('meta_query');
|
596 |
-
// If the meta query is not yet set
|
597 |
-
if ( !is_array($mq) ) {
|
598 |
-
// initialize it
|
599 |
-
$mq = array(
|
600 |
-
'relation' => 'AND',
|
601 |
-
);
|
602 |
-
}
|
603 |
-
// Add the custom meta query
|
604 |
-
$mq[] = apply_filters(
|
605 |
-
'wprss_view_feed_items_meta_query',
|
606 |
-
array(
|
607 |
-
'key' => 'wprss_feed_id',
|
608 |
-
'value' => $id,
|
609 |
-
'compare' => '='
|
610 |
-
),
|
611 |
-
$id
|
612 |
-
);
|
613 |
-
// Set the new meta query
|
614 |
-
$query->set('meta_query', $mq);
|
615 |
-
}
|
616 |
-
// Return the query
|
617 |
-
return $query;
|
618 |
-
}
|
619 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Functions for the admin section, columns and row actions
|
4 |
+
*
|
5 |
+
* @package WP RSS Aggregator
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
add_filter( 'manage_wprss_feed_posts_columns', 'wprss_set_feed_custom_columns', 20, 1 );
|
10 |
+
/**
|
11 |
+
* Set up the custom columns for the wprss_feed list
|
12 |
+
*
|
13 |
+
* @since 2.0
|
14 |
+
*/
|
15 |
+
function wprss_set_feed_custom_columns( $columns ) {
|
16 |
+
|
17 |
+
$columns = array(
|
18 |
+
'cb' => '<input type="checkbox" />',
|
19 |
+
'errors' => '',
|
20 |
+
'title' => __( 'Name', WPRSS_TEXT_DOMAIN ),
|
21 |
+
);
|
22 |
+
|
23 |
+
$columns = apply_filters( 'wprss_set_feed_custom_columns', $columns );
|
24 |
+
|
25 |
+
// Columns to add when feed is not trashed
|
26 |
+
if ( !isset( $_GET['post_status'] ) || $_GET['post_status'] !== 'trash' ) {
|
27 |
+
$columns['state'] = __( 'State', WPRSS_TEXT_DOMAIN );
|
28 |
+
$columns['updates'] = __( 'Updates', WPRSS_TEXT_DOMAIN );
|
29 |
+
$columns['feed-count'] = __( apply_filters( 'wprss_feed_items_count_column', 'Imported items' ), WPRSS_TEXT_DOMAIN );
|
30 |
+
}
|
31 |
+
|
32 |
+
return $columns;
|
33 |
+
}
|
34 |
+
|
35 |
+
|
36 |
+
add_action( "manage_wprss_feed_posts_custom_column", "wprss_show_custom_columns", 10, 2 );
|
37 |
+
/**
|
38 |
+
* Show up the custom columns for the wprss_feed list
|
39 |
+
*
|
40 |
+
* @since 2.0
|
41 |
+
*/
|
42 |
+
function wprss_show_custom_columns( $column, $post_id ) {
|
43 |
+
|
44 |
+
switch ( $column ) {
|
45 |
+
case 'errors':
|
46 |
+
$errors = get_post_meta( $post_id, 'wprss_error_last_import', true );
|
47 |
+
$showClass = ( $errors !== '' )? 'wprss-show' : '';
|
48 |
+
$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 );
|
49 |
+
$msg = strlen( $errors ) > 0 ? $errors : $default_msg;
|
50 |
+
echo "<i title=\"$msg\" class=\"fa fa-warning fa-fw wprss-feed-error-symbol $showClass\"></i>";
|
51 |
+
break;
|
52 |
+
case 'state':
|
53 |
+
$active = wprss_is_feed_source_active( $post_id );
|
54 |
+
$text = ( $active )? 'Active' : 'Paused';
|
55 |
+
$button = ( $active )? 'Pause this feed source' : 'Activate this feed source';
|
56 |
+
$icon = ( $active )? 'pause' : 'play';
|
57 |
+
$value = ( $active )? 'paused' : 'active';
|
58 |
+
$indicator = ( $active )? 'green' : 'grey';
|
59 |
+
|
60 |
+
?>
|
61 |
+
<p>
|
62 |
+
<span class="wprss-indicator-<?php echo $indicator; ?>" title="<?php _e( $text, WPRSS_TEXT_DOMAIN ) ?>">
|
63 |
+
<i class="fa fa-circle"></i>
|
64 |
+
</span>
|
65 |
+
<input type="hidden" name="wprss-redirect" value="1" />
|
66 |
+
<button type="submit" class='button-secondary' title="<?php _e( $button, WPRSS_TEXT_DOMAIN ) ?>" name="wprss-feed-id" value="<?php echo $post_id; ?>">
|
67 |
+
<i class='fa fa-<?php echo $icon; ?>'></i>
|
68 |
+
</button>
|
69 |
+
</p>
|
70 |
+
<?php
|
71 |
+
|
72 |
+
break;
|
73 |
+
|
74 |
+
case 'updates':
|
75 |
+
// Get the update interval
|
76 |
+
$update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
|
77 |
+
// Get the last updated and next update data
|
78 |
+
$last_update = get_post_meta( $post_id, 'wprss_last_update', TRUE );
|
79 |
+
$last_update_items = get_post_meta( $post_id, 'wprss_last_update_items', TRUE );
|
80 |
+
$next_update = wprss_get_next_feed_source_update( $post_id );
|
81 |
+
|
82 |
+
// If using the global interval, get the timestamp of the next global update
|
83 |
+
if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
|
84 |
+
$next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
|
85 |
+
}
|
86 |
+
|
87 |
+
// Update the meta field
|
88 |
+
if ( wprss_is_feed_source_active( $post_id ) ) {
|
89 |
+
$next_update_text = $next_update === FALSE ? __( 'None', WPRSS_TEXT_DOMAIN ) : human_time_diff( $next_update, time() );
|
90 |
+
} else {
|
91 |
+
$next_update_text = __( 'Paused', WPRSS_TEXT_DOMAIN );
|
92 |
+
}
|
93 |
+
update_post_meta( $post_id, 'wprss_next_update', $next_update_text );
|
94 |
+
|
95 |
+
?>
|
96 |
+
|
97 |
+
<p>
|
98 |
+
<?php _e( 'Next update:', WPRSS_TEXT_DOMAIN ) ?>
|
99 |
+
<code class="next-update">
|
100 |
+
<?php echo $next_update_text; ?>
|
101 |
+
</code>
|
102 |
+
</p>
|
103 |
+
|
104 |
+
<?php if ( $last_update !== '' ): ?>
|
105 |
+
<p class="last-update-container">
|
106 |
+
<?php _e( 'Last updated:', WPRSS_TEXT_DOMAIN ) ?>
|
107 |
+
<code class="last-update"><?php echo sprintf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), human_time_diff( $last_update, time() ) ) ?></code>
|
108 |
+
<?php if ( $last_update_items !== '' ): ?>
|
109 |
+
<span class="last-update-imported-container"><br/><?php echo sprintf( __( 'Last update imported: <code class="last-update-imported">%1$d</code> items', WPRSS_TEXT_DOMAIN ), $last_update_items ) ?></span>
|
110 |
+
<?php endif; ?>
|
111 |
+
</p>
|
112 |
+
<?php endif;
|
113 |
+
|
114 |
+
break;
|
115 |
+
|
116 |
+
case 'feed-count':
|
117 |
+
$items = wprss_get_feed_items_for_source( $post_id );
|
118 |
+
$seconds_for_next_update = wprss_get_next_feed_source_update( $post_id ) - time();
|
119 |
+
$showClass = ( ( $seconds_for_next_update < 10 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_deleting( $post_id ) )? 'wprss-show' : '';
|
120 |
+
|
121 |
+
?>
|
122 |
+
<p>
|
123 |
+
<span class="items-imported"><?php echo $items->post_count ?></span>
|
124 |
+
<i class="fa fa-fw fa-refresh fa-spin wprss-updating-feed-icon <?php echo $showClass ?>" title="<?php _e( 'Updating feed source', WPRSS_TEXT_DOMAIN ) ?>"></i>
|
125 |
+
</p>
|
126 |
+
<?php
|
127 |
+
|
128 |
+
// Set meta field for items imported
|
129 |
+
update_post_meta( $post_id, 'wprss_items_imported', $items->post_count );
|
130 |
+
|
131 |
+
break;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
|
136 |
+
add_filter( "manage_edit-wprss_feed_sortable_columns", "wprss_feed_sortable_columns" );
|
137 |
+
/**
|
138 |
+
* Make the custom columns sortable for wprss_feed post type
|
139 |
+
*
|
140 |
+
* @since 2.0
|
141 |
+
*/
|
142 |
+
function wprss_feed_sortable_columns() {
|
143 |
+
$sortable_columns = array(
|
144 |
+
// meta column id => sortby value used in query
|
145 |
+
'title' => 'title',
|
146 |
+
'updates' => 'updates',
|
147 |
+
'state' => 'state',
|
148 |
+
'feed-count' => 'feed-count'
|
149 |
+
);
|
150 |
+
return apply_filters( 'wprss_feed_sortable_columns', $sortable_columns );
|
151 |
+
}
|
152 |
+
|
153 |
+
|
154 |
+
add_action( 'pre_get_posts', 'wprss_feed_source_order' );
|
155 |
+
/**
|
156 |
+
* Change order of feed sources to alphabetical ascending according to feed name
|
157 |
+
*
|
158 |
+
* @since 2.2
|
159 |
+
*/
|
160 |
+
function wprss_feed_source_order( $query ) {
|
161 |
+
// Check if the query is being processed in WP Admin, is the main query, and is targetted
|
162 |
+
// for the wprss_feed CPT. If not, stop
|
163 |
+
if ( !is_admin() || !$query->is_main_query() || $query->get('post_type') !== 'wprss_feed' ) {
|
164 |
+
return;
|
165 |
+
}
|
166 |
+
// Check if the orderby query variable is set
|
167 |
+
if ( !( $orderby = $query->get( 'orderby' ) ) ) return;
|
168 |
+
|
169 |
+
// We will be sorting using the meta value (unless sorting by title)
|
170 |
+
$query->set('orderby', 'meta_value' );
|
171 |
+
// Get the current order
|
172 |
+
$order = strtoupper( $query->get( 'order' ) );
|
173 |
+
// Check if it is valid
|
174 |
+
$got_order = $order === 'ASC' || $order === 'DESC';
|
175 |
+
|
176 |
+
// Check what we are sorting by
|
177 |
+
switch ( $orderby ) {
|
178 |
+
case 'title':
|
179 |
+
$query->set( 'orderby', 'title' );
|
180 |
+
break;
|
181 |
+
case 'state':
|
182 |
+
$query->set('meta_key', 'wprss_state');
|
183 |
+
break;
|
184 |
+
case 'updates':
|
185 |
+
$query->set('meta_key', 'wprss_next_update');
|
186 |
+
$query->set('orderby', 'meta_value' );
|
187 |
+
if ( !$got_order ) $query->set( 'order', 'ASC' );
|
188 |
+
break;
|
189 |
+
case 'feed-count':
|
190 |
+
$query->set('meta_key', 'wprss_items_imported');
|
191 |
+
$query->set('orderby', 'meta_value_num' );
|
192 |
+
if ( !$got_order ) $query->set( 'order', 'DESC' );
|
193 |
+
break;
|
194 |
+
}
|
195 |
+
|
196 |
+
if ( !$got_order ){
|
197 |
+
$query->set( 'order', 'ASC' );
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
|
202 |
+
add_filter( 'manage_wprss_feed_item_posts_columns', 'wprss_set_feed_item_custom_columns', 20, 1 );
|
203 |
+
/**
|
204 |
+
* Set up the custom columns for the wprss_feed source list
|
205 |
+
*
|
206 |
+
* @since 2.0
|
207 |
+
*/
|
208 |
+
function wprss_set_feed_item_custom_columns( $columns ) {
|
209 |
+
|
210 |
+
$columns = array (
|
211 |
+
'cb' => '<input type="checkbox" />',
|
212 |
+
'title' => __( 'Name', WPRSS_TEXT_DOMAIN ),
|
213 |
+
'permalink' => __( 'Permalink', WPRSS_TEXT_DOMAIN ),
|
214 |
+
'publishdate' => __( 'Date published', WPRSS_TEXT_DOMAIN ),
|
215 |
+
'source' => __( 'Source', WPRSS_TEXT_DOMAIN )
|
216 |
+
);
|
217 |
+
return apply_filters( 'wprss_set_feed_item_custom_columns', $columns );
|
218 |
+
}
|
219 |
+
|
220 |
+
|
221 |
+
add_action( "manage_wprss_feed_item_posts_custom_column", "wprss_show_feed_item_custom_columns", 10, 2 );
|
222 |
+
/**
|
223 |
+
* Show up the custom columns for the wprss_feed list
|
224 |
+
*
|
225 |
+
* @since 2.0
|
226 |
+
*/
|
227 |
+
function wprss_show_feed_item_custom_columns( $column, $post_id ) {
|
228 |
+
|
229 |
+
switch ( $column ) {
|
230 |
+
case "permalink":
|
231 |
+
$url = get_post_meta( $post_id, 'wprss_item_permalink', true);
|
232 |
+
echo '<a href="' . $url . '">' . $url. '</a>';
|
233 |
+
break;
|
234 |
+
|
235 |
+
case "publishdate":
|
236 |
+
$item_date = get_the_time( 'U', get_the_ID() );
|
237 |
+
$item_date = ( $item_date === '' )? date('U') : $item_date;
|
238 |
+
$publishdate = date( 'Y-m-d H:i:s', $item_date ) ;
|
239 |
+
echo $publishdate;
|
240 |
+
break;
|
241 |
+
|
242 |
+
case "source":
|
243 |
+
$query = new WP_Query();
|
244 |
+
$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>';
|
245 |
+
echo $source;
|
246 |
+
break;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
|
251 |
+
add_filter( "manage_edit-wprss_feed_item_sortable_columns", "wprss_feed_item_sortable_columns" );
|
252 |
+
/**
|
253 |
+
* Make the custom columns sortable
|
254 |
+
*
|
255 |
+
* @since 2.0
|
256 |
+
*/
|
257 |
+
function wprss_feed_item_sortable_columns() {
|
258 |
+
$sortable_columns = array(
|
259 |
+
// meta column id => sortby value used in query
|
260 |
+
'publishdate' => 'publishdate',
|
261 |
+
'source' => 'source'
|
262 |
+
);
|
263 |
+
return apply_filters( 'wprss_feed_item_sortable_columns', $sortable_columns );
|
264 |
+
}
|
265 |
+
|
266 |
+
|
267 |
+
add_action( 'pre_get_posts', 'wprss_feed_item_orderby' );
|
268 |
+
/**
|
269 |
+
* Change ordering of posts on wprss_feed_item screen
|
270 |
+
*
|
271 |
+
* @since 2.0
|
272 |
+
*/
|
273 |
+
function wprss_feed_item_orderby( $query ) {
|
274 |
+
if( ! is_admin() )
|
275 |
+
return;
|
276 |
+
|
277 |
+
$post_type = $query->get('post_type');
|
278 |
+
|
279 |
+
// If we're on the feed listing admin page
|
280 |
+
if ( $post_type == 'wprss_feed_item') {
|
281 |
+
// Set general orderby to date the feed item was published
|
282 |
+
$query->set('orderby','publishdate');
|
283 |
+
// If user clicks on the reorder link, implement reordering
|
284 |
+
$orderby = $query->get( 'orderby');
|
285 |
+
if( 'publishdate' == $orderby ) {
|
286 |
+
$query->set( 'order', 'DESC' );
|
287 |
+
$query->set( 'orderby', 'date' );
|
288 |
+
}
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
|
293 |
+
add_filter( 'post_updated_messages', 'wprss_feed_updated_messages' );
|
294 |
+
/**
|
295 |
+
* Change default notification message when new feed is added or updated
|
296 |
+
*
|
297 |
+
* @since 2.0
|
298 |
+
*/
|
299 |
+
function wprss_feed_updated_messages( $messages ) {
|
300 |
+
global $post, $post_ID;
|
301 |
+
|
302 |
+
$messages[ 'wprss_feed' ] = array(
|
303 |
+
0 => '', // Unused. Messages start at index 1.
|
304 |
+
1 => __( 'Feed source updated. ', WPRSS_TEXT_DOMAIN ),
|
305 |
+
2 => __( 'Custom field updated.', WPRSS_TEXT_DOMAIN ),
|
306 |
+
3 => __( 'Custom field deleted.', WPRSS_TEXT_DOMAIN ),
|
307 |
+
4 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN ),
|
308 |
+
5 => '',
|
309 |
+
6 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
|
310 |
+
7 => __( 'Feed source saved.', WPRSS_TEXT_DOMAIN ),
|
311 |
+
8 => __( 'Feed source submitted.', WPRSS_TEXT_DOMAIN ),
|
312 |
+
9 => '',
|
313 |
+
10 => __( 'Feed source updated.', WPRSS_TEXT_DOMAIN )
|
314 |
+
);
|
315 |
+
|
316 |
+
return apply_filters( 'wprss_feed_updated_messages', $messages );
|
317 |
+
}
|
318 |
+
|
319 |
+
|
320 |
+
add_filter( 'post_row_actions', 'wprss_remove_row_actions', 10, 2 );
|
321 |
+
/**
|
322 |
+
* Remove actions row for imported feed items, we don't want them to be editable or viewable
|
323 |
+
*
|
324 |
+
* @since 2.0
|
325 |
+
*/
|
326 |
+
function wprss_remove_row_actions( $actions, $post )
|
327 |
+
{
|
328 |
+
|
329 |
+
$page = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
330 |
+
if ( get_post_type($post) === 'wprss_feed_item' ) {
|
331 |
+
unset( $actions[ 'edit' ] );
|
332 |
+
unset( $actions[ 'view' ] );
|
333 |
+
//unset( $actions[ 'trash' ] );
|
334 |
+
unset( $actions[ 'inline hide-if-no-js' ] );
|
335 |
+
}
|
336 |
+
elseif ( get_post_type($post) === 'wprss_feed' ) {
|
337 |
+
$actions = array_reverse( $actions );
|
338 |
+
$actions['id'] = '<span class="wprss-row-id">' . sprintf( __( 'ID: %1$s', WPRSS_TEXT_DOMAIN ), $post->ID ) . '</span>';
|
339 |
+
$actions = array_reverse( $actions );
|
340 |
+
|
341 |
+
unset( $actions[ 'view'] );
|
342 |
+
unset( $actions[ 'inline hide-if-no-js'] );
|
343 |
+
if ( get_post_status( $post->ID ) !== 'trash' ) {
|
344 |
+
$trash = $actions['trash'];
|
345 |
+
unset( $actions['trash'] );
|
346 |
+
|
347 |
+
$view_items_link = apply_filters(
|
348 |
+
'wprss_view_feed_items_row_action_link',
|
349 |
+
admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . $post->ID ),
|
350 |
+
$post->ID
|
351 |
+
);
|
352 |
+
$view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', __( 'View Items', WPRSS_TEXT_DOMAIN ) );
|
353 |
+
$actions['view-items'] = '<a href="' . $view_items_link . '">' . $view_items_text . '</a>';
|
354 |
+
|
355 |
+
$fetch_items_row_action_text = apply_filters( 'wprss_fetch_items_row_action_text', __( 'Fetch Items', WPRSS_TEXT_DOMAIN ) );
|
356 |
+
$actions[ 'fetch' ] = '<a href="javascript:;" class="wprss_ajax_action" pid="'. $post->ID .'" purl="'.home_url().'/wp-admin/admin-ajax.php">' . $fetch_items_row_action_text . '</a>';
|
357 |
+
|
358 |
+
$purge_feeds_row_action_text = apply_filters( 'wprss_purge_feeds_row_action_text', __( 'Delete Items', WPRSS_TEXT_DOMAIN ) );
|
359 |
+
$purge_feeds_row_action_title = apply_filters( 'wprss_purge_feeds_row_action_title', __( 'Delete feed items imported by this feed source', WPRSS_TEXT_DOMAIN ) );
|
360 |
+
$actions['purge-posts'] = "<a href='".admin_url("edit.php?post_type=wprss_feed&purge-feed-items=" . $post->ID . $page ) . "' title='" . $purge_feeds_row_action_title . "' >" . __( $purge_feeds_row_action_text, WPRSS_TEXT_DOMAIN ) . "</a>";
|
361 |
+
|
362 |
+
$actions['trash'] = $trash;
|
363 |
+
}
|
364 |
+
}
|
365 |
+
return apply_filters( 'wprss_remove_row_actions', $actions );
|
366 |
+
}
|
367 |
+
|
368 |
+
|
369 |
+
add_action( 'admin_init', 'check_delete_for_feed_source' );
|
370 |
+
/**
|
371 |
+
* Checks the GET data for the delete per feed source action request
|
372 |
+
*
|
373 |
+
* @since 3.5
|
374 |
+
*/
|
375 |
+
function check_delete_for_feed_source( $source_id = NULL ) {
|
376 |
+
if ( ! current_user_can( 'delete_feeds' ) ) return;
|
377 |
+
// then we need to check the GET data for the request
|
378 |
+
if ( isset( $_GET['purge-feed-items'] ) ) {
|
379 |
+
$source_id = $_GET['purge-feed-items'];
|
380 |
+
// Schedule a job that runs this function with the source id parameter
|
381 |
+
wp_schedule_single_event( time(), 'wprss_delete_feed_items_from_source_hook', array( $source_id ) );
|
382 |
+
// Set a transient
|
383 |
+
set_transient( 'wprss_delete_posts_by_source_notif', 'true', 30 );
|
384 |
+
// Mark feed as deleting its items
|
385 |
+
update_post_meta( $source_id, 'wprss_feed_is_deleting_items', time() );
|
386 |
+
// check pagination
|
387 |
+
$page = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
388 |
+
// Refresh the page without the GET parameter
|
389 |
+
header( 'Location: ' . admin_url( 'edit.php?post_type=wprss_feed' . $page ) );
|
390 |
+
exit();
|
391 |
+
} else {
|
392 |
+
// Get the notification transient
|
393 |
+
$transient = get_transient( 'wprss_delete_posts_by_source_notif' );
|
394 |
+
// If the transient is set and is set to 'true'
|
395 |
+
if ( $transient !== FALSE && $transient === 'true' ) {
|
396 |
+
// delete it
|
397 |
+
delete_transient( 'wprss_delete_posts_by_source_notif' );
|
398 |
+
// Add an action to show the notification
|
399 |
+
add_action( 'all_admin_notices', 'wprss_notify_about_deleting_source_feed_items' );
|
400 |
+
}
|
401 |
+
}
|
402 |
+
}
|
403 |
+
|
404 |
+
|
405 |
+
|
406 |
+
add_action( 'wprss_delete_feed_items_from_source_hook', 'wprss_delete_feed_items_of_feed_source', 10 , 1 );
|
407 |
+
/**
|
408 |
+
* Deletes the feed items of the feed source identified by the given ID.
|
409 |
+
*
|
410 |
+
* @param $source_id The ID of the feed source
|
411 |
+
* @since 3.5
|
412 |
+
*/
|
413 |
+
function wprss_delete_feed_items_of_feed_source( $source_id ) {
|
414 |
+
$force_delete = apply_filters( 'wprss_force_delete_when_by_source', TRUE );
|
415 |
+
// WPML fix: removes the current language from the query WHERE and JOIN clauses
|
416 |
+
global $sitepress;
|
417 |
+
if ( $sitepress !== NULL ) {
|
418 |
+
remove_filter( 'posts_join', array( $sitepress,'posts_join_filter') );
|
419 |
+
remove_filter( 'posts_where', array( $sitepress,'posts_where_filter') );
|
420 |
+
}
|
421 |
+
// Run the query
|
422 |
+
$query = new WP_Query(
|
423 |
+
array(
|
424 |
+
'meta_key' => 'wprss_feed_id',
|
425 |
+
'meta_value' => $source_id,
|
426 |
+
'post_type' => 'wprss_feed_item',
|
427 |
+
'post_status' => 'any',
|
428 |
+
'posts_per_page' => -1
|
429 |
+
)
|
430 |
+
);
|
431 |
+
$query = apply_filters( 'wprss_delete_per_source_query', $query, $source_id );
|
432 |
+
// Delete the results of the query
|
433 |
+
while( $query->have_posts() ) {
|
434 |
+
$query->the_post();
|
435 |
+
wp_delete_post( get_the_ID(), $force_delete );
|
436 |
+
}
|
437 |
+
}
|
438 |
+
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Shows a notification that tells the user that feed items for a particular source are being deleted
|
442 |
+
*
|
443 |
+
* @since 3.5
|
444 |
+
*/
|
445 |
+
function wprss_notify_about_deleting_source_feed_items() {
|
446 |
+
$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 );
|
447 |
+
echo '<div class="updated"><p>' . $message . '</p></div>';
|
448 |
+
}
|
449 |
+
|
450 |
+
|
451 |
+
add_action( 'wp_ajax_wprss_fetch_feeds_row_action', 'wprss_fetch_feeds_action_hook' );
|
452 |
+
/**
|
453 |
+
* The AJAX function for the 'Fetch Feed Items' row action on the
|
454 |
+
* 'All Feed Sources' page.
|
455 |
+
*
|
456 |
+
* @since 3.3
|
457 |
+
*/
|
458 |
+
function wprss_fetch_feeds_action_hook() {
|
459 |
+
if ( isset( $_POST['id'] ) && !empty( $_POST['id'] ) ) {
|
460 |
+
if ( ! current_user_can( 'edit_feed_sources' ) ) die();
|
461 |
+
$id = $_POST['id'];
|
462 |
+
update_post_meta( $id, 'wprss_force_next_fetch', '1' );
|
463 |
+
|
464 |
+
// Prepare the schedule args
|
465 |
+
$schedule_args = array( strval( $id ) );
|
466 |
+
|
467 |
+
// Get the current schedule - do nothing if not scheduled
|
468 |
+
$next_scheduled = wp_next_scheduled( 'wprss_fetch_single_feed_hook', $schedule_args );
|
469 |
+
if ( $next_scheduled !== FALSE ) {
|
470 |
+
// If scheduled, unschedule it
|
471 |
+
wp_unschedule_event( $next_scheduled, 'wprss_fetch_single_feed_hook', $schedule_args );
|
472 |
+
|
473 |
+
// Get the interval option for the feed source
|
474 |
+
$interval = get_post_meta( $id, 'wprss_update_interval', TRUE );
|
475 |
+
// if the feed source uses its own interval
|
476 |
+
if ( $interval !== '' && $interval !== wprss_get_default_feed_source_update_interval() ) {
|
477 |
+
// Add meta in feed source. This is used to notify the source that it needs to reschedule it
|
478 |
+
update_post_meta( $id, 'wprss_reschedule_event', $next_scheduled );
|
479 |
+
}
|
480 |
+
}
|
481 |
+
|
482 |
+
// Schedule the event for 5 seconds from now
|
483 |
+
wp_schedule_single_event( time() + 1, 'wprss_fetch_single_feed_hook', $schedule_args );
|
484 |
+
wprss_flag_feed_as_updating( $id );
|
485 |
+
die();
|
486 |
+
}
|
487 |
+
}
|
488 |
+
|
489 |
+
|
490 |
+
add_filter( 'bulk_actions-edit-wprss_feed_item', 'wprss_custom_feed_item_bulk_actions' );
|
491 |
+
/**
|
492 |
+
* Remove bulk action link to edit imported feed items
|
493 |
+
*
|
494 |
+
* @since 2.0
|
495 |
+
*/
|
496 |
+
function wprss_custom_feed_item_bulk_actions( $actions ){
|
497 |
+
unset( $actions[ 'edit' ] );
|
498 |
+
return apply_filters( 'wprss_custom_feed_item_bulk_actions', $actions );
|
499 |
+
}
|
500 |
+
|
501 |
+
|
502 |
+
add_action( 'admin_footer-edit.php', 'wprss_remove_a_from_feed_title' );
|
503 |
+
/**
|
504 |
+
* Remove hyperlink from imported feed titles in list posts screen
|
505 |
+
*
|
506 |
+
* @since 2.0
|
507 |
+
*/
|
508 |
+
function wprss_remove_a_from_feed_title() {
|
509 |
+
if ( 'edit-wprss_feed_item' !== get_current_screen()->id )
|
510 |
+
return;
|
511 |
+
?>
|
512 |
+
|
513 |
+
<script type="text/javascript">
|
514 |
+
jQuery('table.wp-list-table a.row-title').contents().unwrap();
|
515 |
+
</script>
|
516 |
+
<?php
|
517 |
+
}
|
518 |
+
|
519 |
+
|
520 |
+
add_filter( 'gettext', 'wprss_change_publish_button_text', 10, 2 );
|
521 |
+
/**
|
522 |
+
* Modify 'Publish' button text when adding a new feed source
|
523 |
+
*
|
524 |
+
* @since 2.0
|
525 |
+
*/
|
526 |
+
function wprss_change_publish_button_text( $translation, $text ) {
|
527 |
+
if ( 'wprss_feed' == get_post_type()) {
|
528 |
+
if ( $text == 'Publish' )
|
529 |
+
return __( 'Publish Feed', WPRSS_TEXT_DOMAIN );
|
530 |
+
}
|
531 |
+
return apply_filters( 'wprss_change_publish_button_text', $translation );
|
532 |
+
}
|
533 |
+
|
534 |
+
|
535 |
+
|
536 |
+
add_action( 'wp_before_admin_bar_render', 'wprss_modify_admin_bar' );
|
537 |
+
/**
|
538 |
+
* Removes the old "View Source" menu item from the admin bar and adds a new
|
539 |
+
* "View items" menu bar item, that opens a new tab, showing the items imported
|
540 |
+
* from that feed source.
|
541 |
+
*
|
542 |
+
* Only shown on the wprss_feed edit page.
|
543 |
+
*
|
544 |
+
* @since 4.2
|
545 |
+
*/
|
546 |
+
function wprss_modify_admin_bar() {
|
547 |
+
global $wp_admin_bar;
|
548 |
+
if ( !is_admin() ) return;
|
549 |
+
$screen = get_current_screen();
|
550 |
+
// Check if we are in the wprss_feed edit page
|
551 |
+
if ( $screen->base == 'post' && $screen->post_type == 'wprss_feed' && !empty( $_GET['action'] ) && $_GET['action'] == 'edit' ) {
|
552 |
+
// Remove the old 'View Source' menu item
|
553 |
+
$wp_admin_bar->remove_node( 'view' );
|
554 |
+
|
555 |
+
// Prepare the view items link and text
|
556 |
+
$view_items_link = apply_filters(
|
557 |
+
'wprss_view_feed_items_row_action_link',
|
558 |
+
admin_url( 'edit.php?post_type=wprss_feed_item&wprss_feed=' . get_the_ID() ),
|
559 |
+
get_the_ID()
|
560 |
+
);
|
561 |
+
$view_items_text = apply_filters( 'wprss_view_feed_items_row_action_text', 'View Items' );
|
562 |
+
|
563 |
+
// Prepare the link target
|
564 |
+
$link_target = 'wprss-view-items-' . get_the_ID();
|
565 |
+
|
566 |
+
// Add the new menu item
|
567 |
+
$wp_admin_bar->add_node( array(
|
568 |
+
'href' => $view_items_link,
|
569 |
+
'id' => 'view',
|
570 |
+
'title' => __( $view_items_text, WPRSS_TEXT_DOMAIN ),
|
571 |
+
'meta' => array(
|
572 |
+
'target' => $link_target
|
573 |
+
)
|
574 |
+
));
|
575 |
+
}
|
576 |
+
}
|
577 |
+
|
578 |
+
|
579 |
+
|
580 |
+
|
581 |
+
if ( is_admin() ){
|
582 |
+
add_filter('pre_get_posts', 'wprss_view_feed_items_query');
|
583 |
+
/**
|
584 |
+
* Alters the main query in the WordPress admin, when the wprss_feed GET parameter is set.
|
585 |
+
* The queried items are then filtered down to the items imported by the feed source with
|
586 |
+
* the ID given in the wprss_feed GET parameter.
|
587 |
+
*
|
588 |
+
* @since 4.2
|
589 |
+
*/
|
590 |
+
function wprss_view_feed_items_query( $query ) {
|
591 |
+
if ( is_admin() && $query->is_main_query() && !empty($_GET['wprss_feed']) ) {
|
592 |
+
// Get the ID from the GET param
|
593 |
+
$id = $_GET['wprss_feed'];
|
594 |
+
// Get the existing meta query
|
595 |
+
$mq = $query->get('meta_query');
|
596 |
+
// If the meta query is not yet set
|
597 |
+
if ( !is_array($mq) ) {
|
598 |
+
// initialize it
|
599 |
+
$mq = array(
|
600 |
+
'relation' => 'AND',
|
601 |
+
);
|
602 |
+
}
|
603 |
+
// Add the custom meta query
|
604 |
+
$mq[] = apply_filters(
|
605 |
+
'wprss_view_feed_items_meta_query',
|
606 |
+
array(
|
607 |
+
'key' => 'wprss_feed_id',
|
608 |
+
'value' => $id,
|
609 |
+
'compare' => '='
|
610 |
+
),
|
611 |
+
$id
|
612 |
+
);
|
613 |
+
// Set the new meta query
|
614 |
+
$query->set('meta_query', $mq);
|
615 |
+
}
|
616 |
+
// Return the query
|
617 |
+
return $query;
|
618 |
+
}
|
619 |
+
}
|
includes/admin-editor.php
CHANGED
@@ -1,147 +1,147 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This file contains code related to the custom button added to Wordpress' TinyMCE editor.
|
4 |
-
*
|
5 |
-
* @since 3.5
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
add_action( 'admin_init', 'wprss_add_editor_button' );
|
11 |
-
/**
|
12 |
-
* Adds the WPRSS button to WordPress' editor
|
13 |
-
*
|
14 |
-
* @since 3.5
|
15 |
-
*/
|
16 |
-
function wprss_add_editor_button() {
|
17 |
-
if ( ! current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) )
|
18 |
-
return;
|
19 |
-
if ( get_user_option( 'rich_editing' ) == 'true') {
|
20 |
-
add_filter( 'mce_external_plugins', 'wprss_register_tinymce_plugin' );
|
21 |
-
add_filter( 'mce_buttons', 'wprss_register_tinymce_button' );
|
22 |
-
}
|
23 |
-
}
|
24 |
-
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Adds a separator and the wprss button to the buttons array.
|
28 |
-
*
|
29 |
-
* @since 3.5
|
30 |
-
*/
|
31 |
-
function wprss_register_tinymce_button( $buttons ) {
|
32 |
-
array_push( $buttons, "|", "wprss" );
|
33 |
-
return $buttons;
|
34 |
-
}
|
35 |
-
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Adds the button action JS file to TinyMCE's plugin list
|
39 |
-
*
|
40 |
-
* @todo add filter to skip showing the editor button
|
41 |
-
* @since 3.5
|
42 |
-
*/
|
43 |
-
function wprss_register_tinymce_plugin($plugin_array) {
|
44 |
-
// add filter here
|
45 |
-
$plugin_array['wprss'] = WPRSS_JS . 'editor.js';
|
46 |
-
return $plugin_array;
|
47 |
-
}
|
48 |
-
|
49 |
-
|
50 |
-
add_filter( 'tiny_mce_version', 'wprss_tinymce_version');
|
51 |
-
/**
|
52 |
-
* Intercepts TinyMCE's version check and increments its version by 3.
|
53 |
-
*
|
54 |
-
* This is a hack used to work around TinyMCE's caching, that might prevent the
|
55 |
-
* new wprss button from appearing on the editor.
|
56 |
-
*
|
57 |
-
* @since 3.5
|
58 |
-
*/
|
59 |
-
function wprss_tinymce_version($ver) {
|
60 |
-
$ver += 3;
|
61 |
-
return $ver;
|
62 |
-
}
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
add_action( 'wp_ajax_wprss_editor_dialog', 'wprss_return_dialog_contents' );
|
70 |
-
/**
|
71 |
-
*
|
72 |
-
*
|
73 |
-
*/
|
74 |
-
function wprss_return_dialog_contents() {
|
75 |
-
$feed_sources = get_posts( array(
|
76 |
-
'post_type' => 'wprss_feed',
|
77 |
-
'post_status' => 'publish',
|
78 |
-
'posts_per_page' => -1,
|
79 |
-
'no_found_rows' => true
|
80 |
-
));
|
81 |
-
$feed_sources_select = '<select id="wprss-dialog-feed-source-list" multiple>';
|
82 |
-
$feed_sources_exclude_select = '<select id="wprss-dialog-exclude-list" multiple>';
|
83 |
-
$feed_sources_both_select = '';
|
84 |
-
foreach ( $feed_sources as $source ) {
|
85 |
-
$feed_sources_both_select .= '<option value="' . $source->ID . '" >' . $source->post_title . '</option>';
|
86 |
-
}
|
87 |
-
$feed_sources_both_select .= '</select><p>' . __( 'Hold Ctrl or Mac Command key when clicking to select more than one feed source.' , WPRSS_TEXT_DOMAIN ) . '</p>';
|
88 |
-
|
89 |
-
$feed_sources_select .= $feed_sources_both_select;
|
90 |
-
$feed_sources_exclude_select .= $feed_sources_both_select;
|
91 |
-
|
92 |
-
?>
|
93 |
-
<table cellspacing="20">
|
94 |
-
<tbody>
|
95 |
-
|
96 |
-
<tr>
|
97 |
-
<td id="wprss-dialog-all-sources-label"><?php _e( 'Feed Sources', WPRSS_TEXT_DOMAIN ) ?></td>
|
98 |
-
<td>
|
99 |
-
<input id="wprss-dialog-all-sources" type="checkbox" checked> <label for="wprss-dialog-all-sources"><?php _e( 'All feed sources', WPRSS_TEXT_DOMAIN ) ?></label>
|
100 |
-
<div id="wprss-dialog-sources-container" style="display:none">
|
101 |
-
<p><?php _e( 'Choose the feed source to display:', WPRSS_TEXT_DOMAIN ) ?></p>
|
102 |
-
<?php echo $feed_sources_select; ?>
|
103 |
-
</div>
|
104 |
-
<script>
|
105 |
-
jQuery('#wprss-dialog-all-sources').click( function(){
|
106 |
-
if ( jQuery(this).is(':checked') ) {
|
107 |
-
jQuery( '#wprss-dialog-sources-container' ).hide();
|
108 |
-
jQuery( '#wprss-dialog-exclude-row' ).show();
|
109 |
-
jQuery( '#wprss-dialog-all-sources-label' ).css('vertical-align', 'middle');
|
110 |
-
} else {
|
111 |
-
jQuery( '#wprss-dialog-sources-container' ).show();
|
112 |
-
jQuery( '#wprss-dialog-exclude-row' ).hide();
|
113 |
-
jQuery( '#wprss-dialog-all-sources-label' ).css('vertical-align', 'top');
|
114 |
-
}
|
115 |
-
});
|
116 |
-
jQuery('#wprss-dialog-submit').click( wprss_dialog_submit );
|
117 |
-
</script>
|
118 |
-
</td>
|
119 |
-
</tr>
|
120 |
-
|
121 |
-
<tr id="wprss-dialog-exclude-row">
|
122 |
-
<td id="wprss-dialog-exclude-label"><?php _e( 'Exclude:', WPRSS_TEXT_DOMAIN ) ?></td>
|
123 |
-
<td>
|
124 |
-
<p><?php _e( 'Choose the feed sources to exclude:', WPRSS_TEXT_DOMAIN ) ?></p>
|
125 |
-
<?php echo $feed_sources_exclude_select; ?>
|
126 |
-
</td>
|
127 |
-
</tr>
|
128 |
-
|
129 |
-
<tr>
|
130 |
-
<td><?php _e( 'Feed Limit:', WPRSS_TEXT_DOMAIN ) ?></td>
|
131 |
-
<td> <input id="wprss-dialog-feed-limit" type="number" class="wprss-number-roller" placeholder="<?php _e( 'Ignore', WPRSS_TEXT_DOMAIN ) ?> " min="0" /> </td>
|
132 |
-
</tr>
|
133 |
-
|
134 |
-
<?php do_action( 'wprss_return_dialog_contents' ); ?>
|
135 |
-
|
136 |
-
<tr>
|
137 |
-
<td></td>
|
138 |
-
<td>
|
139 |
-
<button id="wprss-dialog-submit"><?php _e( 'Add shortcode', WPRSS_TEXT_DOMAIN ) ?></button>
|
140 |
-
</td>
|
141 |
-
</tr>
|
142 |
-
|
143 |
-
</tbody>
|
144 |
-
</table>
|
145 |
-
<?php
|
146 |
-
die();
|
147 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This file contains code related to the custom button added to Wordpress' TinyMCE editor.
|
4 |
+
*
|
5 |
+
* @since 3.5
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
|
10 |
+
add_action( 'admin_init', 'wprss_add_editor_button' );
|
11 |
+
/**
|
12 |
+
* Adds the WPRSS button to WordPress' editor
|
13 |
+
*
|
14 |
+
* @since 3.5
|
15 |
+
*/
|
16 |
+
function wprss_add_editor_button() {
|
17 |
+
if ( ! current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) )
|
18 |
+
return;
|
19 |
+
if ( get_user_option( 'rich_editing' ) == 'true') {
|
20 |
+
add_filter( 'mce_external_plugins', 'wprss_register_tinymce_plugin' );
|
21 |
+
add_filter( 'mce_buttons', 'wprss_register_tinymce_button' );
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Adds a separator and the wprss button to the buttons array.
|
28 |
+
*
|
29 |
+
* @since 3.5
|
30 |
+
*/
|
31 |
+
function wprss_register_tinymce_button( $buttons ) {
|
32 |
+
array_push( $buttons, "|", "wprss" );
|
33 |
+
return $buttons;
|
34 |
+
}
|
35 |
+
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Adds the button action JS file to TinyMCE's plugin list
|
39 |
+
*
|
40 |
+
* @todo add filter to skip showing the editor button
|
41 |
+
* @since 3.5
|
42 |
+
*/
|
43 |
+
function wprss_register_tinymce_plugin($plugin_array) {
|
44 |
+
// add filter here
|
45 |
+
$plugin_array['wprss'] = WPRSS_JS . 'editor.js';
|
46 |
+
return $plugin_array;
|
47 |
+
}
|
48 |
+
|
49 |
+
|
50 |
+
add_filter( 'tiny_mce_version', 'wprss_tinymce_version');
|
51 |
+
/**
|
52 |
+
* Intercepts TinyMCE's version check and increments its version by 3.
|
53 |
+
*
|
54 |
+
* This is a hack used to work around TinyMCE's caching, that might prevent the
|
55 |
+
* new wprss button from appearing on the editor.
|
56 |
+
*
|
57 |
+
* @since 3.5
|
58 |
+
*/
|
59 |
+
function wprss_tinymce_version($ver) {
|
60 |
+
$ver += 3;
|
61 |
+
return $ver;
|
62 |
+
}
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
|
69 |
+
add_action( 'wp_ajax_wprss_editor_dialog', 'wprss_return_dialog_contents' );
|
70 |
+
/**
|
71 |
+
*
|
72 |
+
*
|
73 |
+
*/
|
74 |
+
function wprss_return_dialog_contents() {
|
75 |
+
$feed_sources = get_posts( array(
|
76 |
+
'post_type' => 'wprss_feed',
|
77 |
+
'post_status' => 'publish',
|
78 |
+
'posts_per_page' => -1,
|
79 |
+
'no_found_rows' => true
|
80 |
+
));
|
81 |
+
$feed_sources_select = '<select id="wprss-dialog-feed-source-list" multiple>';
|
82 |
+
$feed_sources_exclude_select = '<select id="wprss-dialog-exclude-list" multiple>';
|
83 |
+
$feed_sources_both_select = '';
|
84 |
+
foreach ( $feed_sources as $source ) {
|
85 |
+
$feed_sources_both_select .= '<option value="' . $source->ID . '" >' . $source->post_title . '</option>';
|
86 |
+
}
|
87 |
+
$feed_sources_both_select .= '</select><p>' . __( 'Hold Ctrl or Mac Command key when clicking to select more than one feed source.' , WPRSS_TEXT_DOMAIN ) . '</p>';
|
88 |
+
|
89 |
+
$feed_sources_select .= $feed_sources_both_select;
|
90 |
+
$feed_sources_exclude_select .= $feed_sources_both_select;
|
91 |
+
|
92 |
+
?>
|
93 |
+
<table cellspacing="20">
|
94 |
+
<tbody>
|
95 |
+
|
96 |
+
<tr>
|
97 |
+
<td id="wprss-dialog-all-sources-label"><?php _e( 'Feed Sources', WPRSS_TEXT_DOMAIN ) ?></td>
|
98 |
+
<td>
|
99 |
+
<input id="wprss-dialog-all-sources" type="checkbox" checked> <label for="wprss-dialog-all-sources"><?php _e( 'All feed sources', WPRSS_TEXT_DOMAIN ) ?></label>
|
100 |
+
<div id="wprss-dialog-sources-container" style="display:none">
|
101 |
+
<p><?php _e( 'Choose the feed source to display:', WPRSS_TEXT_DOMAIN ) ?></p>
|
102 |
+
<?php echo $feed_sources_select; ?>
|
103 |
+
</div>
|
104 |
+
<script>
|
105 |
+
jQuery('#wprss-dialog-all-sources').click( function(){
|
106 |
+
if ( jQuery(this).is(':checked') ) {
|
107 |
+
jQuery( '#wprss-dialog-sources-container' ).hide();
|
108 |
+
jQuery( '#wprss-dialog-exclude-row' ).show();
|
109 |
+
jQuery( '#wprss-dialog-all-sources-label' ).css('vertical-align', 'middle');
|
110 |
+
} else {
|
111 |
+
jQuery( '#wprss-dialog-sources-container' ).show();
|
112 |
+
jQuery( '#wprss-dialog-exclude-row' ).hide();
|
113 |
+
jQuery( '#wprss-dialog-all-sources-label' ).css('vertical-align', 'top');
|
114 |
+
}
|
115 |
+
});
|
116 |
+
jQuery('#wprss-dialog-submit').click( wprss_dialog_submit );
|
117 |
+
</script>
|
118 |
+
</td>
|
119 |
+
</tr>
|
120 |
+
|
121 |
+
<tr id="wprss-dialog-exclude-row">
|
122 |
+
<td id="wprss-dialog-exclude-label"><?php _e( 'Exclude:', WPRSS_TEXT_DOMAIN ) ?></td>
|
123 |
+
<td>
|
124 |
+
<p><?php _e( 'Choose the feed sources to exclude:', WPRSS_TEXT_DOMAIN ) ?></p>
|
125 |
+
<?php echo $feed_sources_exclude_select; ?>
|
126 |
+
</td>
|
127 |
+
</tr>
|
128 |
+
|
129 |
+
<tr>
|
130 |
+
<td><?php _e( 'Feed Limit:', WPRSS_TEXT_DOMAIN ) ?></td>
|
131 |
+
<td> <input id="wprss-dialog-feed-limit" type="number" class="wprss-number-roller" placeholder="<?php _e( 'Ignore', WPRSS_TEXT_DOMAIN ) ?> " min="0" /> </td>
|
132 |
+
</tr>
|
133 |
+
|
134 |
+
<?php do_action( 'wprss_return_dialog_contents' ); ?>
|
135 |
+
|
136 |
+
<tr>
|
137 |
+
<td></td>
|
138 |
+
<td>
|
139 |
+
<button id="wprss-dialog-submit"><?php _e( 'Add shortcode', WPRSS_TEXT_DOMAIN ) ?></button>
|
140 |
+
</td>
|
141 |
+
</tr>
|
142 |
+
|
143 |
+
</tbody>
|
144 |
+
</table>
|
145 |
+
<?php
|
146 |
+
die();
|
147 |
}
|
includes/admin-heartbeat.php
CHANGED
@@ -1,78 +1,78 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
add_action( 'wp_ajax_wprss_feed_source_table_ajax', 'wprss_feed_source_updates');
|
4 |
-
/**
|
5 |
-
*
|
6 |
-
*/
|
7 |
-
function wprss_feed_source_updates() {
|
8 |
-
$response = array();
|
9 |
-
|
10 |
-
if ( ! current_user_can( 'edit_feed_sources' ) ) return $response;
|
11 |
-
|
12 |
-
if ( empty($_POST['wprss_heartbeat']) ) return $response;
|
13 |
-
|
14 |
-
// Get the wprss heartbeat data and extract the data
|
15 |
-
$wprss_heartbeat = $_POST['wprss_heartbeat'];
|
16 |
-
extract( $wprss_heartbeat );
|
17 |
-
|
18 |
-
// Perform the action specified by the heartbeat data
|
19 |
-
switch( $action ) {
|
20 |
-
/* FEED SOURCE UPDATING STATUS
|
21 |
-
* Used to determine whether or not to show the updating icon in the feed source table.
|
22 |
-
*/
|
23 |
-
case 'feed_sources':
|
24 |
-
// Prepare array of IDs for feed sources currently updating
|
25 |
-
$feed_sources_data = array();
|
26 |
-
// Iterate all feed sources
|
27 |
-
foreach ( $params as $feed_id ) {
|
28 |
-
$feed_sources_data[$feed_id] = array();
|
29 |
-
$feed_source_data = &$feed_sources_data[$feed_id];
|
30 |
-
|
31 |
-
// Check if the feed source is updating
|
32 |
-
$seconds_for_next_update = wprss_get_next_feed_source_update( $feed_id ) - time();
|
33 |
-
$feed_source_data['updating'] = ( $seconds_for_next_update < 2 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_updating( $feed_id ) || wprss_is_feed_source_deleting( $feed_id );
|
34 |
-
|
35 |
-
// Add the number of imported items
|
36 |
-
$items = wprss_get_feed_items_for_source( $feed_id );
|
37 |
-
$feed_source_data['items'] = $items->post_count;
|
38 |
-
// Update the meta field
|
39 |
-
update_post_meta( $feed_id, 'wprss_items_imported', $items->post_count );
|
40 |
-
|
41 |
-
// Add the next update time
|
42 |
-
$next_update = wprss_get_next_feed_source_update( $feed_id );
|
43 |
-
$update_interval = get_post_meta( $feed_id, 'wprss_update_interval', TRUE );
|
44 |
-
// If using the global interval, get the timestamp of the next global update
|
45 |
-
if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
|
46 |
-
$next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
|
47 |
-
}
|
48 |
-
// Set the text appropriately
|
49 |
-
if ( ! wprss_is_feed_source_active( $feed_id ) ) {
|
50 |
-
$feed_source_data['next-update'] = __( 'Paused', WPRSS_TEXT_DOMAIN );
|
51 |
-
}
|
52 |
-
elseif( $next_update === FALSE ) {
|
53 |
-
$feed_source_data['next-update'] = __( 'None', WPRSS_TEXT_DOMAIN );
|
54 |
-
}
|
55 |
-
else {
|
56 |
-
$feed_source_data['next-update'] = human_time_diff( $next_update, time() );
|
57 |
-
}
|
58 |
-
// Update the meta field
|
59 |
-
update_post_meta( $feed_id, 'wprss_next_update', $feed_source_data['next-update'] );
|
60 |
-
|
61 |
-
// Add the last update information
|
62 |
-
$last_update = get_post_meta( $feed_id, 'wprss_last_update', TRUE );
|
63 |
-
$last_update_items = get_post_meta( $feed_id, 'wprss_last_update_items', TRUE );
|
64 |
-
|
65 |
-
$feed_source_data['last-update'] = ( $last_update === '' )? '' : human_time_diff( $last_update, time() );
|
66 |
-
$feed_source_data['last-update-imported'] = $last_update_items;
|
67 |
-
|
68 |
-
// Add any error info
|
69 |
-
$errors = get_post_meta( $feed_id, 'wprss_error_last_import', true );
|
70 |
-
$feed_source_data['errors'] = $errors;
|
71 |
-
}
|
72 |
-
// Send back all the IDs
|
73 |
-
$response['wprss_feed_sources_data'] = $feed_sources_data;
|
74 |
-
break;
|
75 |
-
}
|
76 |
-
// Return the response
|
77 |
-
die( json_encode($response) );
|
78 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
add_action( 'wp_ajax_wprss_feed_source_table_ajax', 'wprss_feed_source_updates');
|
4 |
+
/**
|
5 |
+
*
|
6 |
+
*/
|
7 |
+
function wprss_feed_source_updates() {
|
8 |
+
$response = array();
|
9 |
+
|
10 |
+
if ( ! current_user_can( 'edit_feed_sources' ) ) return $response;
|
11 |
+
|
12 |
+
if ( empty($_POST['wprss_heartbeat']) ) return $response;
|
13 |
+
|
14 |
+
// Get the wprss heartbeat data and extract the data
|
15 |
+
$wprss_heartbeat = $_POST['wprss_heartbeat'];
|
16 |
+
extract( $wprss_heartbeat );
|
17 |
+
|
18 |
+
// Perform the action specified by the heartbeat data
|
19 |
+
switch( $action ) {
|
20 |
+
/* FEED SOURCE UPDATING STATUS
|
21 |
+
* Used to determine whether or not to show the updating icon in the feed source table.
|
22 |
+
*/
|
23 |
+
case 'feed_sources':
|
24 |
+
// Prepare array of IDs for feed sources currently updating
|
25 |
+
$feed_sources_data = array();
|
26 |
+
// Iterate all feed sources
|
27 |
+
foreach ( $params as $feed_id ) {
|
28 |
+
$feed_sources_data[$feed_id] = array();
|
29 |
+
$feed_source_data = &$feed_sources_data[$feed_id];
|
30 |
+
|
31 |
+
// Check if the feed source is updating
|
32 |
+
$seconds_for_next_update = wprss_get_next_feed_source_update( $feed_id ) - time();
|
33 |
+
$feed_source_data['updating'] = ( $seconds_for_next_update < 2 && $seconds_for_next_update > 0 ) || wprss_is_feed_source_updating( $feed_id ) || wprss_is_feed_source_deleting( $feed_id );
|
34 |
+
|
35 |
+
// Add the number of imported items
|
36 |
+
$items = wprss_get_feed_items_for_source( $feed_id );
|
37 |
+
$feed_source_data['items'] = $items->post_count;
|
38 |
+
// Update the meta field
|
39 |
+
update_post_meta( $feed_id, 'wprss_items_imported', $items->post_count );
|
40 |
+
|
41 |
+
// Add the next update time
|
42 |
+
$next_update = wprss_get_next_feed_source_update( $feed_id );
|
43 |
+
$update_interval = get_post_meta( $feed_id, 'wprss_update_interval', TRUE );
|
44 |
+
// If using the global interval, get the timestamp of the next global update
|
45 |
+
if ( $update_interval === wprss_get_default_feed_source_update_interval() || $update_interval === '' ) {
|
46 |
+
$next_update = wp_next_scheduled( 'wprss_fetch_all_feeds_hook', array() );
|
47 |
+
}
|
48 |
+
// Set the text appropriately
|
49 |
+
if ( ! wprss_is_feed_source_active( $feed_id ) ) {
|
50 |
+
$feed_source_data['next-update'] = __( 'Paused', WPRSS_TEXT_DOMAIN );
|
51 |
+
}
|
52 |
+
elseif( $next_update === FALSE ) {
|
53 |
+
$feed_source_data['next-update'] = __( 'None', WPRSS_TEXT_DOMAIN );
|
54 |
+
}
|
55 |
+
else {
|
56 |
+
$feed_source_data['next-update'] = human_time_diff( $next_update, time() );
|
57 |
+
}
|
58 |
+
// Update the meta field
|
59 |
+
update_post_meta( $feed_id, 'wprss_next_update', $feed_source_data['next-update'] );
|
60 |
+
|
61 |
+
// Add the last update information
|
62 |
+
$last_update = get_post_meta( $feed_id, 'wprss_last_update', TRUE );
|
63 |
+
$last_update_items = get_post_meta( $feed_id, 'wprss_last_update_items', TRUE );
|
64 |
+
|
65 |
+
$feed_source_data['last-update'] = ( $last_update === '' )? '' : human_time_diff( $last_update, time() );
|
66 |
+
$feed_source_data['last-update-imported'] = $last_update_items;
|
67 |
+
|
68 |
+
// Add any error info
|
69 |
+
$errors = get_post_meta( $feed_id, 'wprss_error_last_import', true );
|
70 |
+
$feed_source_data['errors'] = $errors;
|
71 |
+
}
|
72 |
+
// Send back all the IDs
|
73 |
+
$response['wprss_feed_sources_data'] = $feed_sources_data;
|
74 |
+
break;
|
75 |
+
}
|
76 |
+
// Return the response
|
77 |
+
die( json_encode($response) );
|
78 |
}
|
includes/admin-help-metaboxes.php
CHANGED
@@ -1,71 +1,71 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if( class_exists('WPRSS_Help') ) {
|
4 |
-
$help = WPRSS_Help::get_instance();
|
5 |
-
|
6 |
-
// Feed source setting fields
|
7 |
-
$prefix = 'field_';
|
8 |
-
$tooltips = array(
|
9 |
-
/* -----------------------------
|
10 |
-
* Feed Source Details Metabox
|
11 |
-
* -----------------------------
|
12 |
-
*/
|
13 |
-
// Feed Source URL
|
14 |
-
'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.
|
15 |
-
|
16 |
-
Also include the <code>http://</code> prefix in the URL.', WPRSS_TEXT_DOMAIN),
|
17 |
-
// Feed limit
|
18 |
-
'wprss_limit' => __('The maximum number of imported items from this feed to keep stored.
|
19 |
-
|
20 |
-
When new items are imported and the limit is exceeded, the oldest feed items will be deleted to make room for new ones.
|
21 |
-
|
22 |
-
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),
|
23 |
-
// Link to Enclosure
|
24 |
-
'wprss_enclosure' => __('Tick this box to make feed items link to the URL in the enclosure tag, rather than link to the original article.
|
25 |
-
|
26 |
-
Enclosure tags are RSS tags that may be included with a feed items. These tags typically contain links to images, audio, videos, attachment files or even flash content.
|
27 |
-
|
28 |
-
If you are not sure leave this setting blank.', WPRSS_TEXT_DOMAIN),
|
29 |
-
|
30 |
-
/* -------------------------
|
31 |
-
* Feed Processing Metabox
|
32 |
-
* -------------------------
|
33 |
-
*/
|
34 |
-
// Feed State
|
35 |
-
'wprss_state' => __('State of the feed, active or paused.
|
36 |
-
|
37 |
-
If active, the feed source will fetch items periodically, according to the settings below.
|
38 |
-
|
39 |
-
If paused, the feed source will not fetch feed items periodically.', WPRSS_TEXT_DOMAIN),
|
40 |
-
// Activate Feed: [date]
|
41 |
-
'wprss_activate_feed' => __('You can set a time, in UTC, in the future when the feed source will become active, if it is paused.
|
42 |
-
|
43 |
-
Leave blank to activate immediately.', WPRSS_TEXT_DOMAIN),
|
44 |
-
// Pause Feed: [date]
|
45 |
-
'wprss_pause_feed' => __('You can set a time, in UTC, in the future when the feed source will become paused, if it is active.
|
46 |
-
|
47 |
-
Leave blank to never pause.', WPRSS_TEXT_DOMAIN),
|
48 |
-
// Update Interval
|
49 |
-
'wprss_update_interval' => __('How frequently the feed source should check for new items and fetch if needed.
|
50 |
-
|
51 |
-
If left as <em>Default</em>, the interval in the global settings is used.', WPRSS_TEXT_DOMAIN),
|
52 |
-
// Delete items older than: [date]
|
53 |
-
'wprss_age_limit' => __('The maximum age allowed for feed items. Very useful if you are only concerned with, say, last week\'s news.
|
54 |
-
|
55 |
-
Items already imported will be deleted if they eventually exceed this age limit.
|
56 |
-
|
57 |
-
Also, items in the RSS feed that are already older than this age will not be imported at all.
|
58 |
-
|
59 |
-
Leaving empty to use the <em>Limit feed items by age</em> option in the general settings.', WPRSS_TEXT_DOMAIN),
|
60 |
-
|
61 |
-
/* ----------------------
|
62 |
-
* Feed Preview Metabox
|
63 |
-
* ----------------------
|
64 |
-
*/
|
65 |
-
// Force Feed
|
66 |
-
'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.
|
67 |
-
|
68 |
-
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)
|
69 |
-
);
|
70 |
-
$help->add_tooltips( $tooltips, $prefix );
|
71 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if( class_exists('WPRSS_Help') ) {
|
4 |
+
$help = WPRSS_Help::get_instance();
|
5 |
+
|
6 |
+
// Feed source setting fields
|
7 |
+
$prefix = 'field_';
|
8 |
+
$tooltips = array(
|
9 |
+
/* -----------------------------
|
10 |
+
* Feed Source Details Metabox
|
11 |
+
* -----------------------------
|
12 |
+
*/
|
13 |
+
// Feed Source URL
|
14 |
+
'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.
|
15 |
+
|
16 |
+
Also include the <code>http://</code> prefix in the URL.', WPRSS_TEXT_DOMAIN),
|
17 |
+
// Feed limit
|
18 |
+
'wprss_limit' => __('The maximum number of imported items from this feed to keep stored.
|
19 |
+
|
20 |
+
When new items are imported and the limit is exceeded, the oldest feed items will be deleted to make room for new ones.
|
21 |
+
|
22 |
+
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),
|
23 |
+
// Link to Enclosure
|
24 |
+
'wprss_enclosure' => __('Tick this box to make feed items link to the URL in the enclosure tag, rather than link to the original article.
|
25 |
+
|
26 |
+
Enclosure tags are RSS tags that may be included with a feed items. These tags typically contain links to images, audio, videos, attachment files or even flash content.
|
27 |
+
|
28 |
+
If you are not sure leave this setting blank.', WPRSS_TEXT_DOMAIN),
|
29 |
+
|
30 |
+
/* -------------------------
|
31 |
+
* Feed Processing Metabox
|
32 |
+
* -------------------------
|
33 |
+
*/
|
34 |
+
// Feed State
|
35 |
+
'wprss_state' => __('State of the feed, active or paused.
|
36 |
+
|
37 |
+
If active, the feed source will fetch items periodically, according to the settings below.
|
38 |
+
|
39 |
+
If paused, the feed source will not fetch feed items periodically.', WPRSS_TEXT_DOMAIN),
|
40 |
+
// Activate Feed: [date]
|
41 |
+
'wprss_activate_feed' => __('You can set a time, in UTC, in the future when the feed source will become active, if it is paused.
|
42 |
+
|
43 |
+
Leave blank to activate immediately.', WPRSS_TEXT_DOMAIN),
|
44 |
+
// Pause Feed: [date]
|
45 |
+
'wprss_pause_feed' => __('You can set a time, in UTC, in the future when the feed source will become paused, if it is active.
|
46 |
+
|
47 |
+
Leave blank to never pause.', WPRSS_TEXT_DOMAIN),
|
48 |
+
// Update Interval
|
49 |
+
'wprss_update_interval' => __('How frequently the feed source should check for new items and fetch if needed.
|
50 |
+
|
51 |
+
If left as <em>Default</em>, the interval in the global settings is used.', WPRSS_TEXT_DOMAIN),
|
52 |
+
// Delete items older than: [date]
|
53 |
+
'wprss_age_limit' => __('The maximum age allowed for feed items. Very useful if you are only concerned with, say, last week\'s news.
|
54 |
+
|
55 |
+
Items already imported will be deleted if they eventually exceed this age limit.
|
56 |
+
|
57 |
+
Also, items in the RSS feed that are already older than this age will not be imported at all.
|
58 |
+
|
59 |
+
Leaving empty to use the <em>Limit feed items by age</em> option in the general settings.', WPRSS_TEXT_DOMAIN),
|
60 |
+
|
61 |
+
/* ----------------------
|
62 |
+
* Feed Preview Metabox
|
63 |
+
* ----------------------
|
64 |
+
*/
|
65 |
+
// Force Feed
|
66 |
+
'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.
|
67 |
+
|
68 |
+
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)
|
69 |
+
);
|
70 |
+
$help->add_tooltips( $tooltips, $prefix );
|
71 |
}
|
includes/admin-help-settings.php
CHANGED
@@ -1,116 +1,116 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if( class_exists('WPRSS_Help') ) {
|
4 |
-
$help = WPRSS_Help::get_instance();
|
5 |
-
|
6 |
-
// Feed source setting fields
|
7 |
-
$prefix = 'setting-';
|
8 |
-
$tooltips = array(
|
9 |
-
/* -----------------
|
10 |
-
* General Section
|
11 |
-
* -----------------
|
12 |
-
*/ // Limit feed items by age
|
13 |
-
'limit-feed-items-by-age' => __( 'The maximum age allowed for feed items.
|
14 |
-
<hr/>
|
15 |
-
|
16 |
-
Items already imported will be deleted if they eventually exceed this age limit.
|
17 |
-
|
18 |
-
Also, items in the RSS feed that are already older than this age will not be imported at all.
|
19 |
-
<hr/>
|
20 |
-
|
21 |
-
<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
22 |
-
// Limit feed items per feed
|
23 |
-
'limit-feed-items-imported' => __('The maximum number of imported items to keep stored, for feed sources that do not have their own limit.
|
24 |
-
<hr/>
|
25 |
-
|
26 |
-
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.
|
27 |
-
|
28 |
-
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.
|
29 |
-
<hr/>
|
30 |
-
|
31 |
-
<em>Use 0 or leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
32 |
-
// Feed processing interval
|
33 |
-
'cron-interval' => __('How frequently should the feed sources (that do not have their own update interval) check for updates and fetch items accordingly.
|
34 |
-
|
35 |
-
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),
|
36 |
-
// Custom Feed URL
|
37 |
-
'custom-feed-url' => __('The URL of the custom feed, located at <code>http://yoursite.com/[custom feed url]</code>.
|
38 |
-
<hr/>
|
39 |
-
|
40 |
-
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.
|
41 |
-
|
42 |
-
<hr/>
|
43 |
-
|
44 |
-
<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),
|
45 |
-
// Custom Feed Title
|
46 |
-
'custom-feed-title' => __('The title of the custom feed.
|
47 |
-
|
48 |
-
This title will be included in the RSS source of the custom feed, in a <code><title></code> tag.', WPRSS_TEXT_DOMAIN),
|
49 |
-
// Custom Feed Limit
|
50 |
-
'custom-feed-limit' => __('The maximum number of feed items in the custom feed.', WPRSS_TEXT_DOMAIN),
|
51 |
-
|
52 |
-
/* --------------------------
|
53 |
-
* General Display Settings
|
54 |
-
* --------------------------
|
55 |
-
*/ // Link titles
|
56 |
-
'link-enable' => __('Check this box to make the feed item titles link to the original article.', WPRSS_TEXT_DOMAIN),
|
57 |
-
// Title Maximum length
|
58 |
-
'title-limit' => __('Set the maximum number of characters to show for feed item titles.
|
59 |
-
<hr/>
|
60 |
-
|
61 |
-
<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
62 |
-
// Show Authors
|
63 |
-
'authors-enable' => __('Check this box to show the author for each feed item, if it is available.', WPRSS_TEXT_DOMAIN),
|
64 |
-
// Video Links
|
65 |
-
'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),
|
66 |
-
// Pagination Type
|
67 |
-
'pagination' => __('The type of pagination to use when showing feed items on multiple pages.
|
68 |
-
|
69 |
-
The first shows two links, "Older" and "Newer", which allow you to navigate through the pages.
|
70 |
-
|
71 |
-
The second shows links for all the pages, together with links for the next and previous pages.', WPRSS_TEXT_DOMAIN),
|
72 |
-
// Feed Limit
|
73 |
-
'feed-limit' => __('The maximum number of feed items to display when using the shortcode.
|
74 |
-
|
75 |
-
This enables pagination if set to a number smaller than the number of items to be displayed.', WPRSS_TEXT_DOMAIN),
|
76 |
-
// Open Links Behaviour
|
77 |
-
'open-dd' => __('Choose how you want links to be opened. This applies to the feed item title and the source link.', WPRSS_TEXT_DOMAIN),
|
78 |
-
// Set links as no follow
|
79 |
-
'follow-dd' => __('Enable this option to set all links displayed as "NoFollow".
|
80 |
-
<hr/>
|
81 |
-
|
82 |
-
"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),
|
83 |
-
|
84 |
-
/* -------------------------
|
85 |
-
* Source Display Settings
|
86 |
-
* -------------------------
|
87 |
-
*/ // Source Enabled
|
88 |
-
'source-enable' => __('Enable this option to show the feed source name for each feed item.', WPRSS_TEXT_DOMAIN),
|
89 |
-
// Text preceding source
|
90 |
-
'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),
|
91 |
-
// Source Link
|
92 |
-
'source-link' => __('Enable this option to link the feed source name to the RSS feed\'s source site.', WPRSS_TEXT_DOMAIN),
|
93 |
-
|
94 |
-
/* -------------------------
|
95 |
-
* Date Display Settings
|
96 |
-
* -------------------------
|
97 |
-
*/ // Source Enabled
|
98 |
-
'date-enable' => __('Enable this to show the feed item\'s date.', WPRSS_TEXT_DOMAIN),
|
99 |
-
// Text preceding date
|
100 |
-
'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),
|
101 |
-
// Date Format
|
102 |
-
'date-format' => __('The format to use for the feed item dates, as a PHP date format.', WPRSS_TEXT_DOMAIN),
|
103 |
-
// Time Ago Format Enable
|
104 |
-
'time-ago-format-enable' => __('Enable this option to show the elapsed time from the feed item\'s date and time to the present time.
|
105 |
-
<em>Eg. 2 hours ago</em>', WPRSS_TEXT_DOMAIN),
|
106 |
-
|
107 |
-
/* --------
|
108 |
-
* Styles
|
109 |
-
* --------
|
110 |
-
*/ // Styles Disable
|
111 |
-
'styles-disable' => __('Check this box to disable all plugin styles used for displaying feed items.
|
112 |
-
|
113 |
-
This will allow you to provide your own custom CSS styles for displaying the feed items.', WPRSS_TEXT_DOMAIN)
|
114 |
-
);
|
115 |
-
$help->add_tooltips( $tooltips, $prefix );
|
116 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if( class_exists('WPRSS_Help') ) {
|
4 |
+
$help = WPRSS_Help::get_instance();
|
5 |
+
|
6 |
+
// Feed source setting fields
|
7 |
+
$prefix = 'setting-';
|
8 |
+
$tooltips = array(
|
9 |
+
/* -----------------
|
10 |
+
* General Section
|
11 |
+
* -----------------
|
12 |
+
*/ // Limit feed items by age
|
13 |
+
'limit-feed-items-by-age' => __( 'The maximum age allowed for feed items.
|
14 |
+
<hr/>
|
15 |
+
|
16 |
+
Items already imported will be deleted if they eventually exceed this age limit.
|
17 |
+
|
18 |
+
Also, items in the RSS feed that are already older than this age will not be imported at all.
|
19 |
+
<hr/>
|
20 |
+
|
21 |
+
<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
22 |
+
// Limit feed items per feed
|
23 |
+
'limit-feed-items-imported' => __('The maximum number of imported items to keep stored, for feed sources that do not have their own limit.
|
24 |
+
<hr/>
|
25 |
+
|
26 |
+
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.
|
27 |
+
|
28 |
+
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.
|
29 |
+
<hr/>
|
30 |
+
|
31 |
+
<em>Use 0 or leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
32 |
+
// Feed processing interval
|
33 |
+
'cron-interval' => __('How frequently should the feed sources (that do not have their own update interval) check for updates and fetch items accordingly.
|
34 |
+
|
35 |
+
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),
|
36 |
+
// Custom Feed URL
|
37 |
+
'custom-feed-url' => __('The URL of the custom feed, located at <code>http://yoursite.com/[custom feed url]</code>.
|
38 |
+
<hr/>
|
39 |
+
|
40 |
+
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.
|
41 |
+
|
42 |
+
<hr/>
|
43 |
+
|
44 |
+
<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),
|
45 |
+
// Custom Feed Title
|
46 |
+
'custom-feed-title' => __('The title of the custom feed.
|
47 |
+
|
48 |
+
This title will be included in the RSS source of the custom feed, in a <code><title></code> tag.', WPRSS_TEXT_DOMAIN),
|
49 |
+
// Custom Feed Limit
|
50 |
+
'custom-feed-limit' => __('The maximum number of feed items in the custom feed.', WPRSS_TEXT_DOMAIN),
|
51 |
+
|
52 |
+
/* --------------------------
|
53 |
+
* General Display Settings
|
54 |
+
* --------------------------
|
55 |
+
*/ // Link titles
|
56 |
+
'link-enable' => __('Check this box to make the feed item titles link to the original article.', WPRSS_TEXT_DOMAIN),
|
57 |
+
// Title Maximum length
|
58 |
+
'title-limit' => __('Set the maximum number of characters to show for feed item titles.
|
59 |
+
<hr/>
|
60 |
+
|
61 |
+
<em>Leave empty for no limit.</em>', WPRSS_TEXT_DOMAIN),
|
62 |
+
// Show Authors
|
63 |
+
'authors-enable' => __('Check this box to show the author for each feed item, if it is available.', WPRSS_TEXT_DOMAIN),
|
64 |
+
// Video Links
|
65 |
+
'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),
|
66 |
+
// Pagination Type
|
67 |
+
'pagination' => __('The type of pagination to use when showing feed items on multiple pages.
|
68 |
+
|
69 |
+
The first shows two links, "Older" and "Newer", which allow you to navigate through the pages.
|
70 |
+
|
71 |
+
The second shows links for all the pages, together with links for the next and previous pages.', WPRSS_TEXT_DOMAIN),
|
72 |
+
// Feed Limit
|
73 |
+
'feed-limit' => __('The maximum number of feed items to display when using the shortcode.
|
74 |
+
|
75 |
+
This enables pagination if set to a number smaller than the number of items to be displayed.', WPRSS_TEXT_DOMAIN),
|
76 |
+
// Open Links Behaviour
|
77 |
+
'open-dd' => __('Choose how you want links to be opened. This applies to the feed item title and the source link.', WPRSS_TEXT_DOMAIN),
|
78 |
+
// Set links as no follow
|
79 |
+
'follow-dd' => __('Enable this option to set all links displayed as "NoFollow".
|
80 |
+
<hr/>
|
81 |
+
|
82 |
+
"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),
|
83 |
+
|
84 |
+
/* -------------------------
|
85 |
+
* Source Display Settings
|
86 |
+
* -------------------------
|
87 |
+
*/ // Source Enabled
|
88 |
+
'source-enable' => __('Enable this option to show the feed source name for each feed item.', WPRSS_TEXT_DOMAIN),
|
89 |
+
// Text preceding source
|
90 |
+
'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),
|
91 |
+
// Source Link
|
92 |
+
'source-link' => __('Enable this option to link the feed source name to the RSS feed\'s source site.', WPRSS_TEXT_DOMAIN),
|
93 |
+
|
94 |
+
/* -------------------------
|
95 |
+
* Date Display Settings
|
96 |
+
* -------------------------
|
97 |
+
*/ // Source Enabled
|
98 |
+
'date-enable' => __('Enable this to show the feed item\'s date.', WPRSS_TEXT_DOMAIN),
|
99 |
+
// Text preceding date
|
100 |
+
'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),
|
101 |
+
// Date Format
|
102 |
+
'date-format' => __('The format to use for the feed item dates, as a PHP date format.', WPRSS_TEXT_DOMAIN),
|
103 |
+
// Time Ago Format Enable
|
104 |
+
'time-ago-format-enable' => __('Enable this option to show the elapsed time from the feed item\'s date and time to the present time.
|
105 |
+
<em>Eg. 2 hours ago</em>', WPRSS_TEXT_DOMAIN),
|
106 |
+
|
107 |
+
/* --------
|
108 |
+
* Styles
|
109 |
+
* --------
|
110 |
+
*/ // Styles Disable
|
111 |
+
'styles-disable' => __('Check this box to disable all plugin styles used for displaying feed items.
|
112 |
+
|
113 |
+
This will allow you to provide your own custom CSS styles for displaying the feed items.', WPRSS_TEXT_DOMAIN)
|
114 |
+
);
|
115 |
+
$help->add_tooltips( $tooltips, $prefix );
|
116 |
}
|
includes/admin-help.php
CHANGED
@@ -1,1107 +1,1107 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Build the Help page
|
4 |
-
*
|
5 |
-
* @since 4.2
|
6 |
-
*/
|
7 |
-
function wprss_help_page_display() {
|
8 |
-
?>
|
9 |
-
|
10 |
-
<div class="wrap">
|
11 |
-
<?php screen_icon( 'wprss-aggregator' ); ?>
|
12 |
-
|
13 |
-
<h2><?php _e( 'Help & Support', WPRSS_TEXT_DOMAIN ); ?></h2>
|
14 |
-
<h3><?php _e( 'Documentation', WPRSS_TEXT_DOMAIN ) ?></h3>
|
15 |
-
<?php echo wpautop( __('In the <a href="http://www.wprssaggregator.com/documentation/">documentation area</a> on the WP RSS Aggregator website you will find comprehensive details on how to use the core plugin and all the add-ons.
|
16 |
-
|
17 |
-
There are also some videos to help you make a quick start to setting up and enjoying this plugin.', WPRSS_TEXT_DOMAIN) ) ?>
|
18 |
-
<h3><?php _e( 'Frequently Asked Questions (FAQ)', WPRSS_TEXT_DOMAIN ) ?></h3>
|
19 |
-
<?php echo wpautop( __('If after going through the documentation you still have questions, please take a look at the <a href="http://www.wprssaggregator.com/faq/">FAQ page</a> on the site, we set this up purposely to answer the most commonly asked questions by our users.', WPRSS_TEXT_DOMAIN) ) ?>
|
20 |
-
|
21 |
-
<?php
|
22 |
-
if ( wprss_is_premium_user() ) {
|
23 |
-
wprss_premium_help_display();
|
24 |
-
} else {
|
25 |
-
wprss_free_help_display();
|
26 |
-
}
|
27 |
-
?>
|
28 |
-
</div>
|
29 |
-
<?php
|
30 |
-
}
|
31 |
-
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Print the premium help section with inline support form.
|
35 |
-
*
|
36 |
-
* @since 4.7
|
37 |
-
*/
|
38 |
-
function wprss_premium_help_display() {
|
39 |
-
// Get the first valid license.
|
40 |
-
$addon = '';
|
41 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
42 |
-
foreach ( $statuses as $key => $value ) {
|
43 |
-
// If we're looking at a license status key...
|
44 |
-
if ( strpos($key, '_license_status') !== FALSE ) {
|
45 |
-
// ...and the license is valid...
|
46 |
-
if ($value === 'valid') {
|
47 |
-
$addon = substr( $key, 0, strpos( $key, '_license_status' ) );
|
48 |
-
break;
|
49 |
-
}
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
// If we didn't find an add-on with a valid license, show the free help text.
|
54 |
-
if ( $addon === '' ) {
|
55 |
-
wprss_free_help_display();
|
56 |
-
return;
|
57 |
-
}
|
58 |
-
|
59 |
-
// Get the full license info so we can prefill the name and email
|
60 |
-
$license = wprss_edd_check_license($addon, NULL, 'ALL');
|
61 |
-
$customer_name = is_object($license) ? $license->customer_name : '';
|
62 |
-
$customer_email = is_object($license) ? $license->customer_email : '';
|
63 |
-
|
64 |
-
echo '<h3>' . __( 'Email Support', WPRSS_TEXT_DOMAIN ) . '</h3>';
|
65 |
-
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 ) );
|
66 |
-
|
67 |
-
?>
|
68 |
-
|
69 |
-
<form method="post">
|
70 |
-
<table>
|
71 |
-
<tr>
|
72 |
-
<td><strong><?php _e('From: ', WPRSS_TEXT_DOMAIN); ?></strong></td>
|
73 |
-
<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>
|
74 |
-
<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>
|
75 |
-
</tr>
|
76 |
-
<tr>
|
77 |
-
<td colspan="3" style="text-align:right;"><small><?php _e('Replies will be sent to this email address.'); ?></small></td>
|
78 |
-
</tr>
|
79 |
-
<tr>
|
80 |
-
<td colspan="3"><input type='text' name='support-subject' placeholder='<?php echo esc_attr('Subject', WPRSS_TEXT_DOMAIN); ?>' style='width:100%;'></td>
|
81 |
-
</tr>
|
82 |
-
<tr>
|
83 |
-
<td colspan="3"><textarea name='support-message' rows='10' cols='80' placeholder='<?php echo esc_attr('Message', WPRSS_TEXT_DOMAIN); ?>'></textarea></td>
|
84 |
-
</tr>
|
85 |
-
<tr>
|
86 |
-
<td colspan="3"><strong><?php _e('Attachments', WPRSS_TEXT_DOMAIN);?>: </strong></td>
|
87 |
-
</tr>
|
88 |
-
<tr>
|
89 |
-
<td colspan="3"><input type='checkbox' name='support-include-log' value='checked' checked><?php _e('WP RSS Aggregator log file', WPRSS_TEXT_DOMAIN); ?></td>
|
90 |
-
</tr>
|
91 |
-
<tr>
|
92 |
-
<td colspan="3"><input type='checkbox' name='support-include-sys' value='checked' checked><?php _e('WordPress information', WPRSS_TEXT_DOMAIN); ?></td>
|
93 |
-
</tr>
|
94 |
-
</table>
|
95 |
-
</form>
|
96 |
-
<div style='line-height:2.3em;'>
|
97 |
-
<button id='send-message-btn' class='button button-primary'><?php _e('Send Message', WPRSS_TEXT_DOMAIN); ?></button>
|
98 |
-
<span id='support-error'></span>
|
99 |
-
</div>
|
100 |
-
|
101 |
-
<?php
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* Print the free help section with link to forums.
|
106 |
-
*
|
107 |
-
* @since 4.7
|
108 |
-
*/
|
109 |
-
function wprss_free_help_display() {
|
110 |
-
echo '<h3>' . __( 'Support Forums', WPRSS_TEXT_DOMAIN ) . '</h3>';
|
111 |
-
echo wpautop( __( "Users of the free version of WP RSS Aggregator can ask questions on the " . '<a href="http://wordpress.org/support/plugin/wp-rss-aggregator">support forum</a>.', WPRSS_TEXT_DOMAIN ) );
|
112 |
-
}
|
113 |
-
|
114 |
-
|
115 |
-
add_action( 'wp_ajax_wprss_ajax_send_premium_support', 'wprss_ajax_send_premium_support' );
|
116 |
-
/**
|
117 |
-
* Handles the AJAX request to send the support form. Returns a JSON status.
|
118 |
-
*
|
119 |
-
* @since 4.7
|
120 |
-
*/
|
121 |
-
function wprss_ajax_send_premium_support() {
|
122 |
-
$ret = array();
|
123 |
-
|
124 |
-
// Validate the form fields that were submitted and send any errors.
|
125 |
-
$error = wprss_validate_support_request();
|
126 |
-
if ($error !== FALSE) {
|
127 |
-
$ret['error'] = $error;
|
128 |
-
echo json_encode($ret);
|
129 |
-
die();
|
130 |
-
}
|
131 |
-
|
132 |
-
// Create the email content.
|
133 |
-
$subject = sanitize_text_field($_GET['support-subject']);
|
134 |
-
$message = wprss_create_support_message();
|
135 |
-
$headers = wprss_create_support_headers();
|
136 |
-
|
137 |
-
// Send the email.
|
138 |
-
$sent = wp_mail( "support@wprssaggregator.com", $subject, $message, $headers );
|
139 |
-
|
140 |
-
// NB, the retval is a best-guess about email sending. According to the WP Codex it
|
141 |
-
// doesn't mean the user received the email, it "only means that the method used
|
142 |
-
// was able to process the request without any errors."
|
143 |
-
if ($sent === FALSE) {
|
144 |
-
$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('http://www.wprssaggregator.com/contact/'));
|
145 |
-
$ret['message'] = $message;
|
146 |
-
} else {
|
147 |
-
$ret['status'] = 'OK';
|
148 |
-
}
|
149 |
-
|
150 |
-
echo json_encode($ret);
|
151 |
-
die();
|
152 |
-
}
|
153 |
-
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Ensures that all support form fields have been filled out. Returns TRUE
|
157 |
-
*
|
158 |
-
* @since 4.7
|
159 |
-
* @return FALSE when all fields are valid, or a string containing an error they aren't.
|
160 |
-
*/
|
161 |
-
function wprss_validate_support_request() {
|
162 |
-
$fields = array(
|
163 |
-
'support-name',
|
164 |
-
'support-email',
|
165 |
-
'support-subject',
|
166 |
-
'support-message'
|
167 |
-
);
|
168 |
-
|
169 |
-
// Ensure that each required field is present and filled out.
|
170 |
-
foreach ($fields as $field) {
|
171 |
-
if (!isset($_GET[$field]) || $_GET[$field] === "") {
|
172 |
-
|
173 |
-
return sprintf(
|
174 |
-
__('Please fill out all the fields in the form, including the <strong>%s</strong> field.', WPRSS_TEXT_DOMAIN),
|
175 |
-
ucfirst(substr($field, strpos($field, '-') + 1))
|
176 |
-
);
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
// Ensure the email is of a valid format.
|
181 |
-
if (is_email($_GET['support-email']) === FALSE) {
|
182 |
-
return __('Please enter a valid email address.', WPRSS_TEXT_DOMAIN);
|
183 |
-
}
|
184 |
-
|
185 |
-
return FALSE;
|
186 |
-
}
|
187 |
-
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Creates and returns the support request email's message body.
|
191 |
-
*
|
192 |
-
* @since 4.7
|
193 |
-
*/
|
194 |
-
function wprss_create_support_message() {
|
195 |
-
// Get the WP RSS Aggregator log.
|
196 |
-
$log = 'Customer did not send log';
|
197 |
-
if ($_GET['support-include-log'] === 'true') {
|
198 |
-
$log = wprss_get_log();
|
199 |
-
}
|
200 |
-
|
201 |
-
// Get the system information.
|
202 |
-
$sys_info = 'Customer did not send system information';
|
203 |
-
if ($_GET['support-include-sys'] === 'true') {
|
204 |
-
ob_start();
|
205 |
-
wprss_print_system_info();
|
206 |
-
$sys_info = ob_get_contents();
|
207 |
-
ob_end_clean();
|
208 |
-
}
|
209 |
-
|
210 |
-
// Get the license keys.
|
211 |
-
$keys = json_encode( get_option( 'wprss_settings_license_keys', array() ), JSON_PRETTY_PRINT );
|
212 |
-
|
213 |
-
// Get the message they entered.
|
214 |
-
$message = sanitize_text_field($_GET['support-message']);
|
215 |
-
|
216 |
-
// Remove any generated system data that may be present from previous form submission attempts.
|
217 |
-
$idx = strpos($message, "----------------------------------------------");
|
218 |
-
if ($idx !== FALSE) {
|
219 |
-
$message = substr($message, 0, $idx);
|
220 |
-
}
|
221 |
-
|
222 |
-
// Append the generated system data.
|
223 |
-
$message .= "\n\n----------------------------------------------\n";
|
224 |
-
$message .= "\nLicense Information:\n" . $keys;
|
225 |
-
$message .= "\n\n\nError Log:\n" . $log;
|
226 |
-
$message .= "\n\n\nSystem Information:\n" . $sys_info . "\n";
|
227 |
-
|
228 |
-
$message = apply_filters( 'wprss_support_message', $message );
|
229 |
-
|
230 |
-
return $message;
|
231 |
-
}
|
232 |
-
|
233 |
-
|
234 |
-
/**
|
235 |
-
* Creates and returns the support request email's headers.
|
236 |
-
*
|
237 |
-
* @since 4.7
|
238 |
-
*/
|
239 |
-
function wprss_create_support_headers() {
|
240 |
-
$headers = "From: no-reply@wprssaggregator.com\r\n";
|
241 |
-
$headers .= "Reply-to: " . sanitize_text_field($_GET['support-name']) . " <" . sanitize_email($_GET['support-email']) . ">\r\n";
|
242 |
-
|
243 |
-
$headers = apply_filters( 'wprss_support_headers', $headers );
|
244 |
-
|
245 |
-
return $headers;
|
246 |
-
}
|
247 |
-
|
248 |
-
|
249 |
-
/**
|
250 |
-
* Encapsulates features for providing inline help in the admin interface.
|
251 |
-
*
|
252 |
-
* The following filters are introduced:
|
253 |
-
*
|
254 |
-
* - `wprss_help_default_options` - The default options to be extended.
|
255 |
-
*
|
256 |
-
* 1. The array of options
|
257 |
-
*
|
258 |
-
* - `wprss_help_template_path` - The path of template retrieved by WPRSS_Help::get_template().
|
259 |
-
*
|
260 |
-
* 1. The path to the template.
|
261 |
-
* 2. The array of variables passed.
|
262 |
-
*
|
263 |
-
* - `wprss_help_template_vars` - The variables for the template, received by WPRSS_Help::get_template().
|
264 |
-
*
|
265 |
-
* 1. The variables array.
|
266 |
-
* 2. The path to the template, filtered by `wprss_help_template_path`.
|
267 |
-
*
|
268 |
-
* - `wprss_help_tooltip_options` - Options that are in effect when adding tooltips with WPRSS_Help::add_tooltip().
|
269 |
-
* - `wprss_help_tooltip_handle_html_options` - Options that are in effect when retrieving tooltip handle HTML with WPRSS_Help::wprss_help_tooltip_handle_html_options.
|
270 |
-
*
|
271 |
-
*
|
272 |
-
* Also, the following options are available:
|
273 |
-
*
|
274 |
-
* - `tooltip_id_prefix` - The HTML element ID prefix that will be used for tooltips.
|
275 |
-
* - `tooltip_handle_text` - The text that will appear inside the handle HTML elements.
|
276 |
-
* - `tooltip_handle_class` - The CSS class that will be assigned to tooltip handles.
|
277 |
-
* - `tooltip_content_class` - The CSS class that will be assigned to tooltip content HTML elements.
|
278 |
-
* - `enqueue_tooltip_content` - Whether or not content is to be enqueued, instead of being output directly.
|
279 |
-
*
|
280 |
-
* 1. The absolute path to the core plugin directory
|
281 |
-
*/
|
282 |
-
class WPRSS_Help {
|
283 |
-
|
284 |
-
static $_instance;
|
285 |
-
|
286 |
-
protected $_options;
|
287 |
-
protected $_enqueued_tooltip_content = array();
|
288 |
-
protected $_tooltips = array();
|
289 |
-
|
290 |
-
const OPTION_NAME = 'wprss_settings_help';
|
291 |
-
const CODE_PREFIX = 'wprss_help_';
|
292 |
-
const OVERRIDE_DEFAULT_PREFIX = '!';
|
293 |
-
const TEXT_DOMAIN = WPRSS_TEXT_DOMAIN;
|
294 |
-
const HASHING_CONCATENATOR = '|';
|
295 |
-
const OPTIONS_FILTER_SUFFIX = '_options';
|
296 |
-
|
297 |
-
const TOOLTIP_DATA_KEY_ID = 'id';
|
298 |
-
const TOOLTIP_DATA_KEY_TEXT = 'text';
|
299 |
-
const TOOLTIP_DATA_KEY_OPTIONS = 'options';
|
300 |
-
|
301 |
-
/**
|
302 |
-
* Retrieve the singleton instance
|
303 |
-
*
|
304 |
-
* @return WPRSS_Help
|
305 |
-
*/
|
306 |
-
public static function get_instance() {
|
307 |
-
if ( is_null( self::$_instance ) ) {
|
308 |
-
$class_name = __CLASS__; // Late static bindings not allowed
|
309 |
-
self::$_instance = new $class_name();
|
310 |
-
}
|
311 |
-
|
312 |
-
return self::$_instance;
|
313 |
-
}
|
314 |
-
|
315 |
-
|
316 |
-
public static function init() {
|
317 |
-
// Actions
|
318 |
-
add_action( 'admin_enqueue_scripts', array( self::get_instance(), '_admin_enqueue_scripts' ) );
|
319 |
-
add_action( 'admin_footer', array( self::get_instance(), '_admin_footer' ) );
|
320 |
-
}
|
321 |
-
|
322 |
-
|
323 |
-
/**
|
324 |
-
* Filters used:
|
325 |
-
*
|
326 |
-
* - `wprss_help_default_options`
|
327 |
-
*
|
328 |
-
* @param array $options Options that will overwrite defaults.
|
329 |
-
*/
|
330 |
-
public function __construct( $options = array() ) {
|
331 |
-
$defaults = apply_filters( 'wprss_help_default_options', array(
|
332 |
-
'tooltip_id_prefix' => 'wprss-tooltip-',
|
333 |
-
'tooltip_handle_text' => '',
|
334 |
-
'tooltip_handle_class' => 'wprss-tooltip-handle', // Used in logic to identify handle elements
|
335 |
-
'tooltip_handle_class_extra' => 'fa fa-question-circle', // Not used in logic
|
336 |
-
'tooltip_content_class' => 'wprss-tooltip-content',
|
337 |
-
'tooltip_class' => 'wprss-ui-tooltip', // Overrides default jQuery UI class
|
338 |
-
'is_enqueue_tooltip_content' => '0',
|
339 |
-
'tooltip_handle_template' => '%1$s/help-tooltip-handle.php',
|
340 |
-
'tooltip_content_template' => '%1$s/help-tooltip-content.php',
|
341 |
-
'admin_footer_js_template' => '%1$s/help-footer-js.php',
|
342 |
-
'tooltip_not_found_handle_html' => '',
|
343 |
-
'text_domain' => self::TEXT_DOMAIN
|
344 |
-
));
|
345 |
-
$db_options = $this->get_options_db();
|
346 |
-
$this->_set_options( $this->array_merge_recursive_distinct( $db_options, $defaults ) );
|
347 |
-
|
348 |
-
$this->_construct();
|
349 |
-
}
|
350 |
-
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Used for parameter-less extension of constructor logic
|
354 |
-
*/
|
355 |
-
protected function _construct() {
|
356 |
-
|
357 |
-
}
|
358 |
-
|
359 |
-
|
360 |
-
/**
|
361 |
-
* Return an option value, or the whole array of internal options.
|
362 |
-
* These options are a product of the defaults, the database, and anything
|
363 |
-
* set later on, applied on top of eachother and overwriting in that order.
|
364 |
-
*
|
365 |
-
* @param null|string $key The key of the option to return.
|
366 |
-
* @param null|mixed $default What to return if options with the specified key not found.
|
367 |
-
* @return array|mixed|null The option value, or an array of options.
|
368 |
-
*/
|
369 |
-
public function get_options( $key = null, $default = null ) {
|
370 |
-
$options = $this->_options;
|
371 |
-
|
372 |
-
if ( is_null( $key ) ) {
|
373 |
-
return $options;
|
374 |
-
}
|
375 |
-
|
376 |
-
if( is_array( $key ) ) {
|
377 |
-
return $this->array_merge_recursive_distinct( $options, $key );
|
378 |
-
}
|
379 |
-
|
380 |
-
return isset( $options[ $key ] ) ? $options[ $key ] : $default;
|
381 |
-
}
|
382 |
-
|
383 |
-
|
384 |
-
/**
|
385 |
-
* Set the value of an internal option or options.
|
386 |
-
* Existing options will be overwritten. New options will be added.
|
387 |
-
* Database options will not be modified.
|
388 |
-
*
|
389 |
-
* @param string|array $key The key of the option to set, or an array of options.
|
390 |
-
* @param null|mixed $value The value of the option to set.
|
391 |
-
* @return WPRSS_Help This instance.
|
392 |
-
*/
|
393 |
-
public function set_options( $key, $value = null ) {
|
394 |
-
if ( is_array( $key ) ) {
|
395 |
-
foreach ( $key as $_key => $_value ) {
|
396 |
-
$this->_set_options( $_key, $_value );
|
397 |
-
}
|
398 |
-
|
399 |
-
return $this;
|
400 |
-
}
|
401 |
-
|
402 |
-
$this->_set_options( $key, $value );
|
403 |
-
}
|
404 |
-
|
405 |
-
|
406 |
-
/**
|
407 |
-
* Set an option value, or all options.
|
408 |
-
* In latter case completely overrides the whole options array.
|
409 |
-
*
|
410 |
-
* @param string|array $key The key of the option to set, or the whole options array.
|
411 |
-
* @param null|mixed $value Value of the option to set.
|
412 |
-
* @return WPRSS_Help This instance.
|
413 |
-
*/
|
414 |
-
protected function _set_options( $key, $value = null ) {
|
415 |
-
if ( is_array( $key ) ) {
|
416 |
-
$this->_options = $key;
|
417 |
-
return $this;
|
418 |
-
}
|
419 |
-
|
420 |
-
$this->_options[ $key ] = $value;
|
421 |
-
return $this;
|
422 |
-
}
|
423 |
-
|
424 |
-
|
425 |
-
/**
|
426 |
-
* Returns a WPRSS_Help option or options from the database.
|
427 |
-
*
|
428 |
-
* @param string $key The key of the option to return.
|
429 |
-
* @param null|mixed $default What to return if option identified by $key is not found.
|
430 |
-
* @return null|array|mixed The options or option value.
|
431 |
-
*/
|
432 |
-
public function get_options_db( $key = null, $default = null ) {
|
433 |
-
$options = (array) get_option( self::OPTION_NAME, array() );
|
434 |
-
|
435 |
-
if ( is_null( $key ) ) {
|
436 |
-
return $options;
|
437 |
-
}
|
438 |
-
|
439 |
-
return isset( $options[ $key ] ) ? $options[ $key ] : $default;
|
440 |
-
}
|
441 |
-
|
442 |
-
|
443 |
-
/**
|
444 |
-
* Get content of a template.
|
445 |
-
*
|
446 |
-
* Filters used
|
447 |
-
*
|
448 |
-
* - `wprss_help_template_path`
|
449 |
-
* - `wprss_help_template_vars`
|
450 |
-
*
|
451 |
-
* @param string $path Full path to the template
|
452 |
-
* @param array $vars This will be passed to the template
|
453 |
-
*/
|
454 |
-
public function get_template( $path, $vars = array() ) {
|
455 |
-
$vars = (array) $vars;
|
456 |
-
|
457 |
-
// Entry points
|
458 |
-
$path = apply_filters( 'wprss_help_template_path', $path, $vars );
|
459 |
-
$vars = apply_filters( 'wprss_help_template_vars', $vars, $path );
|
460 |
-
|
461 |
-
ob_start();
|
462 |
-
include($path);
|
463 |
-
$content = ob_get_contents();
|
464 |
-
ob_end_clean();
|
465 |
-
|
466 |
-
return $content;
|
467 |
-
}
|
468 |
-
|
469 |
-
|
470 |
-
/**
|
471 |
-
* This is called during the `admin_enqueue_scripts` action, and will
|
472 |
-
* enqueue scripts needed for the backend.
|
473 |
-
*
|
474 |
-
* Filters used:
|
475 |
-
*
|
476 |
-
* - `wprss_help_admin_scripts`
|
477 |
-
*
|
478 |
-
* @return WPRSS_Help This instance.
|
479 |
-
*/
|
480 |
-
public function _admin_enqueue_scripts() {
|
481 |
-
$scripts = $this->apply_filters( 'admin_scripts', array(
|
482 |
-
'jquery-ui-tooltip' => array()
|
483 |
-
));
|
484 |
-
|
485 |
-
foreach ( $scripts as $_handle => $_args ) {
|
486 |
-
// Allows numeric array with handles as values
|
487 |
-
if ( is_numeric( $_handle ) ) {
|
488 |
-
$_handle = $_args;
|
489 |
-
}
|
490 |
-
|
491 |
-
// Allows specifying null as value to simply enqueue handle
|
492 |
-
if ( empty( $_args ) ){
|
493 |
-
$_args = array();
|
494 |
-
}
|
495 |
-
|
496 |
-
array_unshift( $_args, $_handle );
|
497 |
-
call_user_func_array( 'wp_enqueue_script', $_args );
|
498 |
-
}
|
499 |
-
|
500 |
-
return $this;
|
501 |
-
}
|
502 |
-
|
503 |
-
|
504 |
-
public function _admin_footer() {
|
505 |
-
$html = '';
|
506 |
-
$html .= $this->get_enqueued_tooltip_content_html() . "\n";
|
507 |
-
$html .= $this->get_admin_footer_js_html();
|
508 |
-
$html = $this->apply_filters( 'admin_footer', $html );
|
509 |
-
|
510 |
-
echo $html;
|
511 |
-
}
|
512 |
-
|
513 |
-
|
514 |
-
public function is_overrides_default_prefix( $string ) {
|
515 |
-
return strpos( $string, self::OVERRIDE_DEFAULT_PREFIX ) === 0;
|
516 |
-
}
|
517 |
-
|
518 |
-
|
519 |
-
/**
|
520 |
-
* @return string This class's text domain
|
521 |
-
*/
|
522 |
-
public function get_text_domain() {
|
523 |
-
return self::TEXT_DOMAIN;
|
524 |
-
}
|
525 |
-
|
526 |
-
/**
|
527 |
-
* Format this string, replacing placeholders with values, and translate it
|
528 |
-
* in the class's text domain.
|
529 |
-
*
|
530 |
-
* @see sprintf()
|
531 |
-
* @param string $string The string to translate.
|
532 |
-
* @param mixed $argN,.. Additional arguments.
|
533 |
-
*/
|
534 |
-
public function __( $string, $argN = null ) {
|
535 |
-
$args = func_get_args();
|
536 |
-
$args[0] = $string = __( $string, $this->get_text_domain() );
|
537 |
-
|
538 |
-
$string = call_user_func_array( 'sprintf', $args );
|
539 |
-
|
540 |
-
return $string;
|
541 |
-
}
|
542 |
-
|
543 |
-
/**
|
544 |
-
* Hashes all the given values into a single hash.
|
545 |
-
* Accepts an infinite number of parameters, all of which will be first
|
546 |
-
* glued together by a separator, then hashed.
|
547 |
-
* Non-scalar values will be serialized.
|
548 |
-
*
|
549 |
-
* @param mixed $value The value to hash.
|
550 |
-
* @param mixed $argN Other values to hash.
|
551 |
-
* @return string The hash.
|
552 |
-
*/
|
553 |
-
public function get_hash( $value ) {
|
554 |
-
$args = func_get_args();
|
555 |
-
$glue = self::HASHING_CONCATENATOR;
|
556 |
-
|
557 |
-
$blob = '';
|
558 |
-
foreach ( $args as $_idx => $_arg ) {
|
559 |
-
$blob .= is_scalar( $_arg ) ? $_arg : serialize( $_arg );
|
560 |
-
$blob .= $glue;
|
561 |
-
}
|
562 |
-
|
563 |
-
$blob = substr( $blob, 0, -1 );
|
564 |
-
|
565 |
-
return sha1( $blob );
|
566 |
-
}
|
567 |
-
|
568 |
-
/**
|
569 |
-
* Get the class code prefix, or the specified prefixed with it.
|
570 |
-
*
|
571 |
-
* @param string $string A string to prefix.
|
572 |
-
* @return string The code prefix or the prefixed string.
|
573 |
-
*/
|
574 |
-
public function get_code_prefix( $string = '' ) {
|
575 |
-
return self::CODE_PREFIX . (string)$string;
|
576 |
-
}
|
577 |
-
|
578 |
-
/**
|
579 |
-
* Optionally prefix a string with the class code prefix, unless it
|
580 |
-
* contains the "!" character in the very beginning, in which case it will
|
581 |
-
* simply be removed.
|
582 |
-
*
|
583 |
-
* @param string $string The string to consider for prefixing.
|
584 |
-
* @return string The prefixed or clean string.
|
585 |
-
*/
|
586 |
-
public function prefix( $string ) {
|
587 |
-
return $this->is_overrides_default_prefix( $string )
|
588 |
-
? substr( $string, 1 )
|
589 |
-
: $this->get_code_prefix( $string );
|
590 |
-
}
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Applies filters, but prefixes the filter name with 'wprss_help_',
|
594 |
-
* unless '!' is specified as the first character of the filter.
|
595 |
-
*
|
596 |
-
* @param string $filter_name Name or "tag" of the filter.
|
597 |
-
* @param mixed $subject The value to apply filters to.
|
598 |
-
* @param mixed $argN,.. Additional filter arguments
|
599 |
-
* @return mixed Result of filtering
|
600 |
-
*/
|
601 |
-
public function apply_filters( $filter_name, $subject, $argN = null ) {
|
602 |
-
$args = func_get_args();
|
603 |
-
|
604 |
-
$args[0] = $filter_name = $this->prefix( $filter_name );
|
605 |
-
|
606 |
-
return call_user_func_array( 'apply_filters', $args );
|
607 |
-
}
|
608 |
-
|
609 |
-
|
610 |
-
/**
|
611 |
-
* Applies a filters with the specified name to the options that were
|
612 |
-
* applied on top of defaults.
|
613 |
-
* The name will be prefixed with the class prefix 'wprss_help_', and
|
614 |
-
* suffixed with '_options'.
|
615 |
-
*
|
616 |
-
* @param string $filter_name Name of the filter to apply to the options
|
617 |
-
* @param array $options The options to filter
|
618 |
-
* @param mixed $filter_argN,.. Other filter arguments to be passed to filter
|
619 |
-
*/
|
620 |
-
public function apply_options_filters( $filter_name, $options = array(), $filter_argN = null ) {
|
621 |
-
$args = func_get_args();
|
622 |
-
|
623 |
-
// Adding sufix
|
624 |
-
$args[0] = $filter_name .= self::OPTIONS_FILTER_SUFFIX;
|
625 |
-
|
626 |
-
// Applying defaults
|
627 |
-
$args[1] = $options = $this->get_options( $options );
|
628 |
-
|
629 |
-
// Entry point. Order of args is already correct.
|
630 |
-
$options = call_user_func_array( array( $this, 'apply_filters' ), $args );
|
631 |
-
|
632 |
-
return $options;
|
633 |
-
}
|
634 |
-
|
635 |
-
|
636 |
-
/**
|
637 |
-
* Parses the tooltip handle template path for placeholders.
|
638 |
-
*
|
639 |
-
* Filters used:
|
640 |
-
*
|
641 |
-
* - `wprss_help_admin_footer_js_html_template`
|
642 |
-
*
|
643 |
-
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'admin_footer_js_template' option.
|
644 |
-
* @return string Path to the template.
|
645 |
-
*/
|
646 |
-
public function get_admin_footer_js_html_template( $path = null ) {
|
647 |
-
// Default is from options
|
648 |
-
if ( is_null( $path ) ) {
|
649 |
-
$path = $this->get_options( 'admin_footer_js_template' );
|
650 |
-
}
|
651 |
-
|
652 |
-
// Entry point
|
653 |
-
$path = $this->apply_filters( 'admin_footer_js_html_template', $path );
|
654 |
-
|
655 |
-
return $this->parse_path( $path );
|
656 |
-
}
|
657 |
-
|
658 |
-
|
659 |
-
/**
|
660 |
-
* Get the HTML of the JavaScript for the footer in Admin Panel.
|
661 |
-
*
|
662 |
-
* Filters used:
|
663 |
-
*
|
664 |
-
* - `wprss_help_admin_footer_js_html`
|
665 |
-
*
|
666 |
-
* @param array $options Any additional options to be used with defaults.
|
667 |
-
* @return string The HTML.
|
668 |
-
*/
|
669 |
-
public function get_admin_footer_js_html( $options = array() ) {
|
670 |
-
$options = $this->apply_options_filters( 'admin_footer_js_html', $options);
|
671 |
-
|
672 |
-
$templatePath = $this->get_admin_footer_js_html_template( $options['admin_footer_js_template'] );
|
673 |
-
|
674 |
-
return $this->get_template($templatePath, $options);
|
675 |
-
}
|
676 |
-
|
677 |
-
|
678 |
-
/**
|
679 |
-
* Parses the tooltip handle template path for placeholders.
|
680 |
-
*
|
681 |
-
* Filters used:
|
682 |
-
*
|
683 |
-
* - `wprss_help_tooltip_handle_html_template`
|
684 |
-
*
|
685 |
-
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
|
686 |
-
* @return string Path to the template.
|
687 |
-
*/
|
688 |
-
public function get_tooltip_handle_html_template( $path = null ) {
|
689 |
-
// Default is from options
|
690 |
-
if ( is_null( $path ) ) {
|
691 |
-
$path = $this->get_options( 'tooltip_handle_template' );
|
692 |
-
}
|
693 |
-
|
694 |
-
// Entry point
|
695 |
-
$path = $this->apply_filters( 'tooltip_handle_html_template', $path );
|
696 |
-
|
697 |
-
return $this->parse_path( $path );
|
698 |
-
}
|
699 |
-
|
700 |
-
|
701 |
-
/**
|
702 |
-
* Get the HTML of the tooltip handle.
|
703 |
-
*
|
704 |
-
* Filters used:
|
705 |
-
*
|
706 |
-
* - `wprss_help_tooltip_handle_html_options`
|
707 |
-
*
|
708 |
-
* @param string $text Content of the tooltip text.
|
709 |
-
* @param string $id ID of the tooltip.
|
710 |
-
* @param array $options Any additional options to be used with defaults.
|
711 |
-
* @return string The HTML.
|
712 |
-
*/
|
713 |
-
public function get_tooltip_handle_html( $text, $id, $options = array() ) {
|
714 |
-
$options = $this->apply_options_filters( 'tooltip_handle_html', $options, $text, $id);
|
715 |
-
|
716 |
-
// Add template varialbes
|
717 |
-
$options['tooltip_id'] = $id;
|
718 |
-
$options['tooltip_text'] = $text;
|
719 |
-
|
720 |
-
$templatePath = $this->get_tooltip_handle_html_template( $options['tooltip_handle_template'] );
|
721 |
-
|
722 |
-
return $this->get_template($templatePath, $options);
|
723 |
-
}
|
724 |
-
|
725 |
-
|
726 |
-
/**
|
727 |
-
* Parses the tooltip content template path for placeholders.
|
728 |
-
*
|
729 |
-
* Filters used:
|
730 |
-
*
|
731 |
-
* - `wprss_help_tooltip_content_html_template`
|
732 |
-
*
|
733 |
-
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
|
734 |
-
* @return string Path to the template.
|
735 |
-
*/
|
736 |
-
public function get_tooltip_content_html_template( $path = null ) {
|
737 |
-
// Default is from options
|
738 |
-
if ( is_null( $path ) ) {
|
739 |
-
$path = $this->get_options( 'tooltip_content_template' );
|
740 |
-
}
|
741 |
-
|
742 |
-
// Entry point
|
743 |
-
$path = $this->apply_filters( 'tooltip_content_html_template', $path );
|
744 |
-
|
745 |
-
return $this->parse_path( $path );
|
746 |
-
}
|
747 |
-
|
748 |
-
|
749 |
-
/**
|
750 |
-
* Get the HTML of the tooltip content.
|
751 |
-
*
|
752 |
-
* Filters used:
|
753 |
-
*
|
754 |
-
* - `wprss_help_tooltip_content_html_options`
|
755 |
-
*
|
756 |
-
* @param string $text Content of the tooltip text.
|
757 |
-
* @param string $id ID of the tooltip.
|
758 |
-
* @param array $options Any additional options to be used with defaults.
|
759 |
-
* @return string The HTML.
|
760 |
-
*/
|
761 |
-
public function get_tooltip_content_html( $text, $id, $options = array() ) {
|
762 |
-
$options = $this->apply_options_filters( 'tooltip_content_html', $options, $text, $id );
|
763 |
-
|
764 |
-
// Add template varialbes
|
765 |
-
$options['tooltip_id'] = $id;
|
766 |
-
$options['tooltip_text'] = $text;
|
767 |
-
|
768 |
-
$templatePath = $this->get_tooltip_content_html_template( $options['tooltip_content_template'] );
|
769 |
-
|
770 |
-
return $this->get_template( $templatePath, $options );
|
771 |
-
}
|
772 |
-
|
773 |
-
|
774 |
-
/**
|
775 |
-
* Add tooltip and get tooltip HTML.
|
776 |
-
* If $text is null, just get the HTML of tooltip with specified ID.
|
777 |
-
* The `is_enqueue_tooltip_content` option determines whether to enqueue
|
778 |
-
* the content, instead of outputting it after the handle.
|
779 |
-
*
|
780 |
-
* @param string $id ID for this tooltip
|
781 |
-
* @param string|null $text Text of this tooltip. If null, tooltip will not be added, but only retrieved.
|
782 |
-
* @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
|
783 |
-
* @return string The tooltip handle and, optionally, content.
|
784 |
-
*/
|
785 |
-
public function tooltip( $id, $text = null, $options = array() ) {
|
786 |
-
$this->add_tooltip( $id, $text, $options );
|
787 |
-
return $this->do_tooltip( $id );
|
788 |
-
}
|
789 |
-
|
790 |
-
|
791 |
-
/**
|
792 |
-
* Add tooltips in a batch, with optionally prefixed ID.
|
793 |
-
*
|
794 |
-
* @param array $tooltips An array where key is tooltip ID and value is tooltip text.
|
795 |
-
* @param string $prefix A prefix to add to all tooltip IDs.
|
796 |
-
* @param array $options Arra of options for all the tooltips to add.
|
797 |
-
* @return \WPRSS_Help
|
798 |
-
*/
|
799 |
-
public function add_tooltips( $tooltips, $prefix = null, $options = array() ) {
|
800 |
-
$prefix = (string) $prefix;
|
801 |
-
if ( !is_array($options) ) $options = array();
|
802 |
-
|
803 |
-
foreach ( $tooltips as $_id => $_text ) {
|
804 |
-
$this->add_tooltip( $prefix . $_id, $_text, $options );
|
805 |
-
}
|
806 |
-
|
807 |
-
return $this;
|
808 |
-
}
|
809 |
-
|
810 |
-
|
811 |
-
/**
|
812 |
-
* Add a tooltip for later display.
|
813 |
-
* Text and options will be replaced by existing text and options, if they
|
814 |
-
* are empty, and a tooltip with the same ID is already registered.
|
815 |
-
*
|
816 |
-
* @param string $id The ID of this tooltip
|
817 |
-
* @param string $text Text for this tooltip
|
818 |
-
* @param array $options Options for this tooltip.
|
819 |
-
* @return WPRSS_Help This instance.
|
820 |
-
*/
|
821 |
-
public function add_tooltip( $id, $text = null, $options = array() ) {
|
822 |
-
if ( $tooltip = $this->get_tooltip( $id ) ) {
|
823 |
-
if ( is_null( $text ) ) $text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : $text;
|
824 |
-
if ( empty( $options ) ) $options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : $options;
|
825 |
-
}
|
826 |
-
|
827 |
-
$this->set_tooltip( $id, $text, $options );
|
828 |
-
|
829 |
-
return $this;
|
830 |
-
}
|
831 |
-
|
832 |
-
|
833 |
-
/**
|
834 |
-
* Set a tooltip, existing or not.
|
835 |
-
*
|
836 |
-
* @param string $id The ID of this tooltip
|
837 |
-
* @param string $text Text for this tooltip
|
838 |
-
* @param array $options Options for this tooltip.
|
839 |
-
* @return WPRSS_Help This instance.
|
840 |
-
*/
|
841 |
-
public function set_tooltip( $id, $text = null, $options = array() ) {
|
842 |
-
$this->_tooltips[ $id ] = array(
|
843 |
-
self::TOOLTIP_DATA_KEY_ID => $id,
|
844 |
-
self::TOOLTIP_DATA_KEY_TEXT => $text,
|
845 |
-
self::TOOLTIP_DATA_KEY_OPTIONS => $options
|
846 |
-
);
|
847 |
-
|
848 |
-
return $this;
|
849 |
-
}
|
850 |
-
|
851 |
-
|
852 |
-
/**
|
853 |
-
* Retrieve one tooltip, or an array containing all tooltips.
|
854 |
-
*
|
855 |
-
* @param string|null $id The ID of the tooltip to retrieve.
|
856 |
-
* @param mixed|null $default What to return if tooltip with specified ID not found.
|
857 |
-
* @return array An array that contains the following indexes: 'id', 'text', 'options'. See {@link add_tooltip()} for details.
|
858 |
-
*/
|
859 |
-
public function get_tooltip( $id = null, $default = null ) {
|
860 |
-
if ( is_null( $id ) ) {
|
861 |
-
return $this->_tooltips;
|
862 |
-
}
|
863 |
-
|
864 |
-
return $this->has_tooltip( $id ) ? $this->_tooltips[ $id ] : $default;
|
865 |
-
}
|
866 |
-
|
867 |
-
|
868 |
-
/**
|
869 |
-
* Check whether a tooltip with the specified ID exists.
|
870 |
-
*
|
871 |
-
* @param string $id ID of the tooltip to check for.
|
872 |
-
* @return boolean True if a tooltip with the specified ID exists; false otherwise.
|
873 |
-
*/
|
874 |
-
public function has_tooltip( $id ) {
|
875 |
-
return isset( $this->_tooltips[ $id ] );
|
876 |
-
}
|
877 |
-
|
878 |
-
/**
|
879 |
-
* Get registered tooltip HTML.
|
880 |
-
*
|
881 |
-
* Filters used:
|
882 |
-
*
|
883 |
-
* - `wprss_help_tooltip_options` - Filters options used for tooltip
|
884 |
-
*
|
885 |
-
* @param string $id ID for this tooltip
|
886 |
-
* @param string $text Text of this tooltip
|
887 |
-
* @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
|
888 |
-
* @return string The tooltip handle and, optionally, content.
|
889 |
-
*/
|
890 |
-
public function do_tooltip( $id ) {
|
891 |
-
$options = $this->get_options();
|
892 |
-
|
893 |
-
if ( !($tooltip = $this->get_tooltip( $id )) || !isset($tooltip[ self::TOOLTIP_DATA_KEY_TEXT ]) || !$tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) {
|
894 |
-
return isset( $options['tooltip_not_found_handle_html'] )
|
895 |
-
? $options['tooltip_not_found_handle_html']
|
896 |
-
: null;
|
897 |
-
}
|
898 |
-
|
899 |
-
$options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : null;
|
900 |
-
$text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : null;
|
901 |
-
|
902 |
-
if ( !is_array( $options ) ) {
|
903 |
-
$options = array( 'is_enqueue_tooltip_content' => $options );
|
904 |
-
}
|
905 |
-
|
906 |
-
// Entry point
|
907 |
-
$options = $this->apply_options_filters( 'tooltip', $options, $id, $text );
|
908 |
-
|
909 |
-
// Get handle HTML
|
910 |
-
$output = $this->get_tooltip_handle_html( $text, $id, $options );
|
911 |
-
|
912 |
-
if ( $this->evaluate_boolean( $options['is_enqueue_tooltip_content'] ) ) {
|
913 |
-
$this->enqueue_tooltip_content($text, $id, $options);
|
914 |
-
}
|
915 |
-
else {
|
916 |
-
$output .= $this->get_tooltip_content_html( $text, $id, $options );
|
917 |
-
}
|
918 |
-
|
919 |
-
return $output;
|
920 |
-
}
|
921 |
-
|
922 |
-
|
923 |
-
/**
|
924 |
-
* Enqueue tooltip content to be displayed in another part of the page.
|
925 |
-
*
|
926 |
-
* @param string $text The text of the tooltip content to enqueue.
|
927 |
-
* @param string $id ID of the tooltip, the content of which to enqueue.
|
928 |
-
* @param array $options This tooltip's options.
|
929 |
-
* @return \WP_Error|\WPRSS_Help This instance, or error if enqueue method is invalid.
|
930 |
-
*/
|
931 |
-
public function enqueue_tooltip_content( $text, $id, $options = array() ) {
|
932 |
-
$queue_method = $this->apply_filters( 'enqueue_tooltip_content_method', array( $this, '_enqueue_tooltip_content' ), $options, $id, $text );
|
933 |
-
|
934 |
-
// "Error handling" WP style
|
935 |
-
if ( !is_callable( $queue_method ) ) {
|
936 |
-
return new WP_Error( $this->prefix( 'invalid_queue_method' ), $this->__( 'Could not enqueue tooltip content: the queue method is not a valid callable.' ), array(
|
937 |
-
'queue_method' => $queue_method,
|
938 |
-
'text' => $text,
|
939 |
-
'id' => $id,
|
940 |
-
'options' => $options
|
941 |
-
));
|
942 |
-
}
|
943 |
-
|
944 |
-
call_user_func_array( $queue_method, array( $text, $id, $options ) );
|
945 |
-
|
946 |
-
return $this;
|
947 |
-
}
|
948 |
-
|
949 |
-
|
950 |
-
public function _enqueue_tooltip_content( $text, $id, $options = array() ) {
|
951 |
-
$hash = $this->get_hash( $text, $id, $options );
|
952 |
-
$this->_enqueued_tooltip_content[ $hash ] = array(
|
953 |
-
self::TOOLTIP_DATA_KEY_TEXT => $text,
|
954 |
-
self::TOOLTIP_DATA_KEY_ID => $id,
|
955 |
-
self::TOOLTIP_DATA_KEY_OPTIONS => $options
|
956 |
-
);
|
957 |
-
|
958 |
-
return $this;
|
959 |
-
}
|
960 |
-
|
961 |
-
|
962 |
-
public function get_enqueued_tooltip_content() {
|
963 |
-
return $this->_enqueued_tooltip_content;
|
964 |
-
}
|
965 |
-
|
966 |
-
|
967 |
-
public function get_enqueued_tooltip_content_html() {
|
968 |
-
$output = '';
|
969 |
-
foreach ( $this->get_enqueued_tooltip_content() as $_hash => $_vars ) {
|
970 |
-
$options = is_array( $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] : array();
|
971 |
-
$output = $this->get_tooltip_content_html( $_vars[ self::TOOLTIP_DATA_KEY_ID ], $_vars[ self::TOOLTIP_DATA_KEY_ID ], $options );
|
972 |
-
}
|
973 |
-
|
974 |
-
echo $output;
|
975 |
-
}
|
976 |
-
|
977 |
-
|
978 |
-
/**
|
979 |
-
* Check whether or not the given value is false.
|
980 |
-
* False values are all {@link empty()} values, and also strings 'false' and 'no'.
|
981 |
-
*
|
982 |
-
* @param mixed $value The value to check.
|
983 |
-
* @return boolean Whether or not the value is considered to be false.
|
984 |
-
*/
|
985 |
-
public function evaluate_boolean( $value ) {
|
986 |
-
return (empty( $value ) || strtolower( $value ) === 'false' || strtolower( $value ) === 'no')
|
987 |
-
? false
|
988 |
-
: true;
|
989 |
-
}
|
990 |
-
|
991 |
-
|
992 |
-
/**
|
993 |
-
* Merge two arrays in an intuitive way.
|
994 |
-
* Input arrays remain unchanged.
|
995 |
-
*
|
996 |
-
* @see http://php.net/manual/en/function.array-merge-recursive.php#92195
|
997 |
-
* @param array $array1 The array to merge.
|
998 |
-
* @param array $array2 The array to merge into.
|
999 |
-
* @return array The merged array.
|
1000 |
-
*/
|
1001 |
-
public function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
|
1002 |
-
$merged = $array1;
|
1003 |
-
|
1004 |
-
foreach ( $array2 as $key => &$value ) {
|
1005 |
-
if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
|
1006 |
-
$merged[ $key ] = array_merge_recursive_distinct( $merged[ $key ], $value );
|
1007 |
-
} else {
|
1008 |
-
$merged[ $key ] = $value;
|
1009 |
-
}
|
1010 |
-
}
|
1011 |
-
|
1012 |
-
return $merged;
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
|
1016 |
-
/**
|
1017 |
-
* Converts an array to a numeric array.
|
1018 |
-
* If $map is empty, assumes that the array keys are already in order.
|
1019 |
-
* If $map is a number, assumes it's the amount of elements to return.
|
1020 |
-
* If $map is an array, assumes it is the map of intended numeric indexes to their value in the input array.
|
1021 |
-
*
|
1022 |
-
* @param array $array The array to convert to a numeric array
|
1023 |
-
* @param false|null|array $map The map of the array indexes, or number of array elements to slice, or nothing.
|
1024 |
-
* @return array The resulting numeric array.
|
1025 |
-
*/
|
1026 |
-
public function array_to_numeric( $array, $map = null ) {
|
1027 |
-
$result = array();
|
1028 |
-
|
1029 |
-
// If map is not an array, assume it's an indicator
|
1030 |
-
if ( !is_array( $map ) ) {
|
1031 |
-
$array = array_values( $array );
|
1032 |
-
}
|
1033 |
-
|
1034 |
-
// If map is empty, assume keys are in order
|
1035 |
-
if ( empty( $map ) ) {
|
1036 |
-
return $array;
|
1037 |
-
}
|
1038 |
-
|
1039 |
-
// If map is a number, assume it's the amount of elements to return
|
1040 |
-
if ( is_numeric( $map ) ) {
|
1041 |
-
$map = intval( $map );
|
1042 |
-
return array_slice( $array, 0, $map );
|
1043 |
-
}
|
1044 |
-
|
1045 |
-
foreach( $map as $_idx => $_key ) {
|
1046 |
-
$result[ $_idx ] = $array[ $_key ];
|
1047 |
-
}
|
1048 |
-
|
1049 |
-
return $result;
|
1050 |
-
}
|
1051 |
-
|
1052 |
-
|
1053 |
-
/**
|
1054 |
-
* Parses the template and replaces placeholders with their values.
|
1055 |
-
* This function uses {@see sprintf()} to format the template string using
|
1056 |
-
* the values provided in $data.
|
1057 |
-
* It is also possible for $data to be an associative array of key-value pairs.
|
1058 |
-
* To achieve the same result, a map can be provided, mapping data keys to
|
1059 |
-
* their placeholder positions.
|
1060 |
-
* If no map is provided,
|
1061 |
-
*
|
1062 |
-
* @param string $string The template string.
|
1063 |
-
* @param array $data The key-value pairs of template data.
|
1064 |
-
* @param false|null|array $map {@see array_to_numeric()} The template value map.
|
1065 |
-
* @return string The parsed and modified template.
|
1066 |
-
*/
|
1067 |
-
public function parse_template( $string, $data, $map = null ) {
|
1068 |
-
$data = $this->array_to_numeric( $data, $map );
|
1069 |
-
array_unshift( $data, $string );
|
1070 |
-
return call_user_func_array( 'sprintf', $data );
|
1071 |
-
}
|
1072 |
-
|
1073 |
-
|
1074 |
-
/**
|
1075 |
-
* Parses a path template specifically with WPRSS_Help path placeholders.
|
1076 |
-
*
|
1077 |
-
* Filters used (in order):
|
1078 |
-
*
|
1079 |
-
* 1. `parse_path_data_default`;
|
1080 |
-
* 2. `parse_path_data`;
|
1081 |
-
* 3. `parse_path_map`;
|
1082 |
-
* 4. `parse_path_path`.
|
1083 |
-
*
|
1084 |
-
* @see WPRSS_Help::parse_template()
|
1085 |
-
* @param string $path The path to parse.
|
1086 |
-
* @param null|array $data Any additional data. Will be merged with defaults.
|
1087 |
-
* @param null|array $map The map for parsing.
|
1088 |
-
* @return string The path with placeholders replaced
|
1089 |
-
*/
|
1090 |
-
public function parse_path( $path, $data = null, $map = null ) {
|
1091 |
-
if( is_null( $data ) ) {
|
1092 |
-
$data = array();
|
1093 |
-
}
|
1094 |
-
|
1095 |
-
$defaults = $this->apply_filters( 'parse_path_data_default', array(
|
1096 |
-
'wprss_templates_dir' => wprss_get_templates_dir()
|
1097 |
-
));
|
1098 |
-
$data = $this->array_merge_recursive_distinct( $data, $defaults );
|
1099 |
-
$data = $this->apply_filters( 'parse_path_data', $data, $path, $map );
|
1100 |
-
$map = $this->apply_filters( 'parse_path_map', $map, $data, $path );
|
1101 |
-
$path = $this->apply_filters( 'parse_path_path', $path, $data, $map );
|
1102 |
-
|
1103 |
-
return $this->parse_template( $path, $data, $map );
|
1104 |
-
}
|
1105 |
-
}
|
1106 |
-
|
1107 |
-
WPRSS_Help::init();
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Build the Help page
|
4 |
+
*
|
5 |
+
* @since 4.2
|
6 |
+
*/
|
7 |
+
function wprss_help_page_display() {
|
8 |
+
?>
|
9 |
+
|
10 |
+
<div class="wrap">
|
11 |
+
<?php screen_icon( 'wprss-aggregator' ); ?>
|
12 |
+
|
13 |
+
<h2><?php _e( 'Help & Support', WPRSS_TEXT_DOMAIN ); ?></h2>
|
14 |
+
<h3><?php _e( 'Documentation', WPRSS_TEXT_DOMAIN ) ?></h3>
|
15 |
+
<?php echo wpautop( __('In the <a href="http://www.wprssaggregator.com/documentation/">documentation area</a> on the WP RSS Aggregator website you will find comprehensive details on how to use the core plugin and all the add-ons.
|
16 |
+
|
17 |
+
There are also some videos to help you make a quick start to setting up and enjoying this plugin.', WPRSS_TEXT_DOMAIN) ) ?>
|
18 |
+
<h3><?php _e( 'Frequently Asked Questions (FAQ)', WPRSS_TEXT_DOMAIN ) ?></h3>
|
19 |
+
<?php echo wpautop( __('If after going through the documentation you still have questions, please take a look at the <a href="http://www.wprssaggregator.com/faq/">FAQ page</a> on the site, we set this up purposely to answer the most commonly asked questions by our users.', WPRSS_TEXT_DOMAIN) ) ?>
|
20 |
+
|
21 |
+
<?php
|
22 |
+
if ( wprss_is_premium_user() ) {
|
23 |
+
wprss_premium_help_display();
|
24 |
+
} else {
|
25 |
+
wprss_free_help_display();
|
26 |
+
}
|
27 |
+
?>
|
28 |
+
</div>
|
29 |
+
<?php
|
30 |
+
}
|
31 |
+
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Print the premium help section with inline support form.
|
35 |
+
*
|
36 |
+
* @since 4.7
|
37 |
+
*/
|
38 |
+
function wprss_premium_help_display() {
|
39 |
+
// Get the first valid license.
|
40 |
+
$addon = '';
|
41 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
42 |
+
foreach ( $statuses as $key => $value ) {
|
43 |
+
// If we're looking at a license status key...
|
44 |
+
if ( strpos($key, '_license_status') !== FALSE ) {
|
45 |
+
// ...and the license is valid...
|
46 |
+
if ($value === 'valid') {
|
47 |
+
$addon = substr( $key, 0, strpos( $key, '_license_status' ) );
|
48 |
+
break;
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
// If we didn't find an add-on with a valid license, show the free help text.
|
54 |
+
if ( $addon === '' ) {
|
55 |
+
wprss_free_help_display();
|
56 |
+
return;
|
57 |
+
}
|
58 |
+
|
59 |
+
// Get the full license info so we can prefill the name and email
|
60 |
+
$license = wprss_edd_check_license($addon, NULL, 'ALL');
|
61 |
+
$customer_name = is_object($license) ? $license->customer_name : '';
|
62 |
+
$customer_email = is_object($license) ? $license->customer_email : '';
|
63 |
+
|
64 |
+
echo '<h3>' . __( 'Email Support', WPRSS_TEXT_DOMAIN ) . '</h3>';
|
65 |
+
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 ) );
|
66 |
+
|
67 |
+
?>
|
68 |
+
|
69 |
+
<form method="post">
|
70 |
+
<table>
|
71 |
+
<tr>
|
72 |
+
<td><strong><?php _e('From: ', WPRSS_TEXT_DOMAIN); ?></strong></td>
|
73 |
+
<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>
|
74 |
+
<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>
|
75 |
+
</tr>
|
76 |
+
<tr>
|
77 |
+
<td colspan="3" style="text-align:right;"><small><?php _e('Replies will be sent to this email address.'); ?></small></td>
|
78 |
+
</tr>
|
79 |
+
<tr>
|
80 |
+
<td colspan="3"><input type='text' name='support-subject' placeholder='<?php echo esc_attr('Subject', WPRSS_TEXT_DOMAIN); ?>' style='width:100%;'></td>
|
81 |
+
</tr>
|
82 |
+
<tr>
|
83 |
+
<td colspan="3"><textarea name='support-message' rows='10' cols='80' placeholder='<?php echo esc_attr('Message', WPRSS_TEXT_DOMAIN); ?>'></textarea></td>
|
84 |
+
</tr>
|
85 |
+
<tr>
|
86 |
+
<td colspan="3"><strong><?php _e('Attachments', WPRSS_TEXT_DOMAIN);?>: </strong></td>
|
87 |
+
</tr>
|
88 |
+
<tr>
|
89 |
+
<td colspan="3"><input type='checkbox' name='support-include-log' value='checked' checked><?php _e('WP RSS Aggregator log file', WPRSS_TEXT_DOMAIN); ?></td>
|
90 |
+
</tr>
|
91 |
+
<tr>
|
92 |
+
<td colspan="3"><input type='checkbox' name='support-include-sys' value='checked' checked><?php _e('WordPress information', WPRSS_TEXT_DOMAIN); ?></td>
|
93 |
+
</tr>
|
94 |
+
</table>
|
95 |
+
</form>
|
96 |
+
<div style='line-height:2.3em;'>
|
97 |
+
<button id='send-message-btn' class='button button-primary'><?php _e('Send Message', WPRSS_TEXT_DOMAIN); ?></button>
|
98 |
+
<span id='support-error'></span>
|
99 |
+
</div>
|
100 |
+
|
101 |
+
<?php
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Print the free help section with link to forums.
|
106 |
+
*
|
107 |
+
* @since 4.7
|
108 |
+
*/
|
109 |
+
function wprss_free_help_display() {
|
110 |
+
echo '<h3>' . __( 'Support Forums', WPRSS_TEXT_DOMAIN ) . '</h3>';
|
111 |
+
echo wpautop( __( "Users of the free version of WP RSS Aggregator can ask questions on the " . '<a href="http://wordpress.org/support/plugin/wp-rss-aggregator">support forum</a>.', WPRSS_TEXT_DOMAIN ) );
|
112 |
+
}
|
113 |
+
|
114 |
+
|
115 |
+
add_action( 'wp_ajax_wprss_ajax_send_premium_support', 'wprss_ajax_send_premium_support' );
|
116 |
+
/**
|
117 |
+
* Handles the AJAX request to send the support form. Returns a JSON status.
|
118 |
+
*
|
119 |
+
* @since 4.7
|
120 |
+
*/
|
121 |
+
function wprss_ajax_send_premium_support() {
|
122 |
+
$ret = array();
|
123 |
+
|
124 |
+
// Validate the form fields that were submitted and send any errors.
|
125 |
+
$error = wprss_validate_support_request();
|
126 |
+
if ($error !== FALSE) {
|
127 |
+
$ret['error'] = $error;
|
128 |
+
echo json_encode($ret);
|
129 |
+
die();
|
130 |
+
}
|
131 |
+
|
132 |
+
// Create the email content.
|
133 |
+
$subject = sanitize_text_field($_GET['support-subject']);
|
134 |
+
$message = wprss_create_support_message();
|
135 |
+
$headers = wprss_create_support_headers();
|
136 |
+
|
137 |
+
// Send the email.
|
138 |
+
$sent = wp_mail( "support@wprssaggregator.com", $subject, $message, $headers );
|
139 |
+
|
140 |
+
// NB, the retval is a best-guess about email sending. According to the WP Codex it
|
141 |
+
// doesn't mean the user received the email, it "only means that the method used
|
142 |
+
// was able to process the request without any errors."
|
143 |
+
if ($sent === FALSE) {
|
144 |
+
$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('http://www.wprssaggregator.com/contact/'));
|
145 |
+
$ret['message'] = $message;
|
146 |
+
} else {
|
147 |
+
$ret['status'] = 'OK';
|
148 |
+
}
|
149 |
+
|
150 |
+
echo json_encode($ret);
|
151 |
+
die();
|
152 |
+
}
|
153 |
+
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Ensures that all support form fields have been filled out. Returns TRUE
|
157 |
+
*
|
158 |
+
* @since 4.7
|
159 |
+
* @return FALSE when all fields are valid, or a string containing an error they aren't.
|
160 |
+
*/
|
161 |
+
function wprss_validate_support_request() {
|
162 |
+
$fields = array(
|
163 |
+
'support-name',
|
164 |
+
'support-email',
|
165 |
+
'support-subject',
|
166 |
+
'support-message'
|
167 |
+
);
|
168 |
+
|
169 |
+
// Ensure that each required field is present and filled out.
|
170 |
+
foreach ($fields as $field) {
|
171 |
+
if (!isset($_GET[$field]) || $_GET[$field] === "") {
|
172 |
+
|
173 |
+
return sprintf(
|
174 |
+
__('Please fill out all the fields in the form, including the <strong>%s</strong> field.', WPRSS_TEXT_DOMAIN),
|
175 |
+
ucfirst(substr($field, strpos($field, '-') + 1))
|
176 |
+
);
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
// Ensure the email is of a valid format.
|
181 |
+
if (is_email($_GET['support-email']) === FALSE) {
|
182 |
+
return __('Please enter a valid email address.', WPRSS_TEXT_DOMAIN);
|
183 |
+
}
|
184 |
+
|
185 |
+
return FALSE;
|
186 |
+
}
|
187 |
+
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Creates and returns the support request email's message body.
|
191 |
+
*
|
192 |
+
* @since 4.7
|
193 |
+
*/
|
194 |
+
function wprss_create_support_message() {
|
195 |
+
// Get the WP RSS Aggregator log.
|
196 |
+
$log = 'Customer did not send log';
|
197 |
+
if ($_GET['support-include-log'] === 'true') {
|
198 |
+
$log = wprss_get_log();
|
199 |
+
}
|
200 |
+
|
201 |
+
// Get the system information.
|
202 |
+
$sys_info = 'Customer did not send system information';
|
203 |
+
if ($_GET['support-include-sys'] === 'true') {
|
204 |
+
ob_start();
|
205 |
+
wprss_print_system_info();
|
206 |
+
$sys_info = ob_get_contents();
|
207 |
+
ob_end_clean();
|
208 |
+
}
|
209 |
+
|
210 |
+
// Get the license keys.
|
211 |
+
$keys = json_encode( get_option( 'wprss_settings_license_keys', array() ), JSON_PRETTY_PRINT );
|
212 |
+
|
213 |
+
// Get the message they entered.
|
214 |
+
$message = sanitize_text_field($_GET['support-message']);
|
215 |
+
|
216 |
+
// Remove any generated system data that may be present from previous form submission attempts.
|
217 |
+
$idx = strpos($message, "----------------------------------------------");
|
218 |
+
if ($idx !== FALSE) {
|
219 |
+
$message = substr($message, 0, $idx);
|
220 |
+
}
|
221 |
+
|
222 |
+
// Append the generated system data.
|
223 |
+
$message .= "\n\n----------------------------------------------\n";
|
224 |
+
$message .= "\nLicense Information:\n" . $keys;
|
225 |
+
$message .= "\n\n\nError Log:\n" . $log;
|
226 |
+
$message .= "\n\n\nSystem Information:\n" . $sys_info . "\n";
|
227 |
+
|
228 |
+
$message = apply_filters( 'wprss_support_message', $message );
|
229 |
+
|
230 |
+
return $message;
|
231 |
+
}
|
232 |
+
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Creates and returns the support request email's headers.
|
236 |
+
*
|
237 |
+
* @since 4.7
|
238 |
+
*/
|
239 |
+
function wprss_create_support_headers() {
|
240 |
+
$headers = "From: no-reply@wprssaggregator.com\r\n";
|
241 |
+
$headers .= "Reply-to: " . sanitize_text_field($_GET['support-name']) . " <" . sanitize_email($_GET['support-email']) . ">\r\n";
|
242 |
+
|
243 |
+
$headers = apply_filters( 'wprss_support_headers', $headers );
|
244 |
+
|
245 |
+
return $headers;
|
246 |
+
}
|
247 |
+
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Encapsulates features for providing inline help in the admin interface.
|
251 |
+
*
|
252 |
+
* The following filters are introduced:
|
253 |
+
*
|
254 |
+
* - `wprss_help_default_options` - The default options to be extended.
|
255 |
+
*
|
256 |
+
* 1. The array of options
|
257 |
+
*
|
258 |
+
* - `wprss_help_template_path` - The path of template retrieved by WPRSS_Help::get_template().
|
259 |
+
*
|
260 |
+
* 1. The path to the template.
|
261 |
+
* 2. The array of variables passed.
|
262 |
+
*
|
263 |
+
* - `wprss_help_template_vars` - The variables for the template, received by WPRSS_Help::get_template().
|
264 |
+
*
|
265 |
+
* 1. The variables array.
|
266 |
+
* 2. The path to the template, filtered by `wprss_help_template_path`.
|
267 |
+
*
|
268 |
+
* - `wprss_help_tooltip_options` - Options that are in effect when adding tooltips with WPRSS_Help::add_tooltip().
|
269 |
+
* - `wprss_help_tooltip_handle_html_options` - Options that are in effect when retrieving tooltip handle HTML with WPRSS_Help::wprss_help_tooltip_handle_html_options.
|
270 |
+
*
|
271 |
+
*
|
272 |
+
* Also, the following options are available:
|
273 |
+
*
|
274 |
+
* - `tooltip_id_prefix` - The HTML element ID prefix that will be used for tooltips.
|
275 |
+
* - `tooltip_handle_text` - The text that will appear inside the handle HTML elements.
|
276 |
+
* - `tooltip_handle_class` - The CSS class that will be assigned to tooltip handles.
|
277 |
+
* - `tooltip_content_class` - The CSS class that will be assigned to tooltip content HTML elements.
|
278 |
+
* - `enqueue_tooltip_content` - Whether or not content is to be enqueued, instead of being output directly.
|
279 |
+
*
|
280 |
+
* 1. The absolute path to the core plugin directory
|
281 |
+
*/
|
282 |
+
class WPRSS_Help {
|
283 |
+
|
284 |
+
static $_instance;
|
285 |
+
|
286 |
+
protected $_options;
|
287 |
+
protected $_enqueued_tooltip_content = array();
|
288 |
+
protected $_tooltips = array();
|
289 |
+
|
290 |
+
const OPTION_NAME = 'wprss_settings_help';
|
291 |
+
const CODE_PREFIX = 'wprss_help_';
|
292 |
+
const OVERRIDE_DEFAULT_PREFIX = '!';
|
293 |
+
const TEXT_DOMAIN = WPRSS_TEXT_DOMAIN;
|
294 |
+
const HASHING_CONCATENATOR = '|';
|
295 |
+
const OPTIONS_FILTER_SUFFIX = '_options';
|
296 |
+
|
297 |
+
const TOOLTIP_DATA_KEY_ID = 'id';
|
298 |
+
const TOOLTIP_DATA_KEY_TEXT = 'text';
|
299 |
+
const TOOLTIP_DATA_KEY_OPTIONS = 'options';
|
300 |
+
|
301 |
+
/**
|
302 |
+
* Retrieve the singleton instance
|
303 |
+
*
|
304 |
+
* @return WPRSS_Help
|
305 |
+
*/
|
306 |
+
public static function get_instance() {
|
307 |
+
if ( is_null( self::$_instance ) ) {
|
308 |
+
$class_name = __CLASS__; // Late static bindings not allowed
|
309 |
+
self::$_instance = new $class_name();
|
310 |
+
}
|
311 |
+
|
312 |
+
return self::$_instance;
|
313 |
+
}
|
314 |
+
|
315 |
+
|
316 |
+
public static function init() {
|
317 |
+
// Actions
|
318 |
+
add_action( 'admin_enqueue_scripts', array( self::get_instance(), '_admin_enqueue_scripts' ) );
|
319 |
+
add_action( 'admin_footer', array( self::get_instance(), '_admin_footer' ) );
|
320 |
+
}
|
321 |
+
|
322 |
+
|
323 |
+
/**
|
324 |
+
* Filters used:
|
325 |
+
*
|
326 |
+
* - `wprss_help_default_options`
|
327 |
+
*
|
328 |
+
* @param array $options Options that will overwrite defaults.
|
329 |
+
*/
|
330 |
+
public function __construct( $options = array() ) {
|
331 |
+
$defaults = apply_filters( 'wprss_help_default_options', array(
|
332 |
+
'tooltip_id_prefix' => 'wprss-tooltip-',
|
333 |
+
'tooltip_handle_text' => '',
|
334 |
+
'tooltip_handle_class' => 'wprss-tooltip-handle', // Used in logic to identify handle elements
|
335 |
+
'tooltip_handle_class_extra' => 'fa fa-question-circle', // Not used in logic
|
336 |
+
'tooltip_content_class' => 'wprss-tooltip-content',
|
337 |
+
'tooltip_class' => 'wprss-ui-tooltip', // Overrides default jQuery UI class
|
338 |
+
'is_enqueue_tooltip_content' => '0',
|
339 |
+
'tooltip_handle_template' => '%1$s/help-tooltip-handle.php',
|
340 |
+
'tooltip_content_template' => '%1$s/help-tooltip-content.php',
|
341 |
+
'admin_footer_js_template' => '%1$s/help-footer-js.php',
|
342 |
+
'tooltip_not_found_handle_html' => '',
|
343 |
+
'text_domain' => self::TEXT_DOMAIN
|
344 |
+
));
|
345 |
+
$db_options = $this->get_options_db();
|
346 |
+
$this->_set_options( $this->array_merge_recursive_distinct( $db_options, $defaults ) );
|
347 |
+
|
348 |
+
$this->_construct();
|
349 |
+
}
|
350 |
+
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Used for parameter-less extension of constructor logic
|
354 |
+
*/
|
355 |
+
protected function _construct() {
|
356 |
+
|
357 |
+
}
|
358 |
+
|
359 |
+
|
360 |
+
/**
|
361 |
+
* Return an option value, or the whole array of internal options.
|
362 |
+
* These options are a product of the defaults, the database, and anything
|
363 |
+
* set later on, applied on top of eachother and overwriting in that order.
|
364 |
+
*
|
365 |
+
* @param null|string $key The key of the option to return.
|
366 |
+
* @param null|mixed $default What to return if options with the specified key not found.
|
367 |
+
* @return array|mixed|null The option value, or an array of options.
|
368 |
+
*/
|
369 |
+
public function get_options( $key = null, $default = null ) {
|
370 |
+
$options = $this->_options;
|
371 |
+
|
372 |
+
if ( is_null( $key ) ) {
|
373 |
+
return $options;
|
374 |
+
}
|
375 |
+
|
376 |
+
if( is_array( $key ) ) {
|
377 |
+
return $this->array_merge_recursive_distinct( $options, $key );
|
378 |
+
}
|
379 |
+
|
380 |
+
return isset( $options[ $key ] ) ? $options[ $key ] : $default;
|
381 |
+
}
|
382 |
+
|
383 |
+
|
384 |
+
/**
|
385 |
+
* Set the value of an internal option or options.
|
386 |
+
* Existing options will be overwritten. New options will be added.
|
387 |
+
* Database options will not be modified.
|
388 |
+
*
|
389 |
+
* @param string|array $key The key of the option to set, or an array of options.
|
390 |
+
* @param null|mixed $value The value of the option to set.
|
391 |
+
* @return WPRSS_Help This instance.
|
392 |
+
*/
|
393 |
+
public function set_options( $key, $value = null ) {
|
394 |
+
if ( is_array( $key ) ) {
|
395 |
+
foreach ( $key as $_key => $_value ) {
|
396 |
+
$this->_set_options( $_key, $_value );
|
397 |
+
}
|
398 |
+
|
399 |
+
return $this;
|
400 |
+
}
|
401 |
+
|
402 |
+
$this->_set_options( $key, $value );
|
403 |
+
}
|
404 |
+
|
405 |
+
|
406 |
+
/**
|
407 |
+
* Set an option value, or all options.
|
408 |
+
* In latter case completely overrides the whole options array.
|
409 |
+
*
|
410 |
+
* @param string|array $key The key of the option to set, or the whole options array.
|
411 |
+
* @param null|mixed $value Value of the option to set.
|
412 |
+
* @return WPRSS_Help This instance.
|
413 |
+
*/
|
414 |
+
protected function _set_options( $key, $value = null ) {
|
415 |
+
if ( is_array( $key ) ) {
|
416 |
+
$this->_options = $key;
|
417 |
+
return $this;
|
418 |
+
}
|
419 |
+
|
420 |
+
$this->_options[ $key ] = $value;
|
421 |
+
return $this;
|
422 |
+
}
|
423 |
+
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Returns a WPRSS_Help option or options from the database.
|
427 |
+
*
|
428 |
+
* @param string $key The key of the option to return.
|
429 |
+
* @param null|mixed $default What to return if option identified by $key is not found.
|
430 |
+
* @return null|array|mixed The options or option value.
|
431 |
+
*/
|
432 |
+
public function get_options_db( $key = null, $default = null ) {
|
433 |
+
$options = (array) get_option( self::OPTION_NAME, array() );
|
434 |
+
|
435 |
+
if ( is_null( $key ) ) {
|
436 |
+
return $options;
|
437 |
+
}
|
438 |
+
|
439 |
+
return isset( $options[ $key ] ) ? $options[ $key ] : $default;
|
440 |
+
}
|
441 |
+
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Get content of a template.
|
445 |
+
*
|
446 |
+
* Filters used
|
447 |
+
*
|
448 |
+
* - `wprss_help_template_path`
|
449 |
+
* - `wprss_help_template_vars`
|
450 |
+
*
|
451 |
+
* @param string $path Full path to the template
|
452 |
+
* @param array $vars This will be passed to the template
|
453 |
+
*/
|
454 |
+
public function get_template( $path, $vars = array() ) {
|
455 |
+
$vars = (array) $vars;
|
456 |
+
|
457 |
+
// Entry points
|
458 |
+
$path = apply_filters( 'wprss_help_template_path', $path, $vars );
|
459 |
+
$vars = apply_filters( 'wprss_help_template_vars', $vars, $path );
|
460 |
+
|
461 |
+
ob_start();
|
462 |
+
include($path);
|
463 |
+
$content = ob_get_contents();
|
464 |
+
ob_end_clean();
|
465 |
+
|
466 |
+
return $content;
|
467 |
+
}
|
468 |
+
|
469 |
+
|
470 |
+
/**
|
471 |
+
* This is called during the `admin_enqueue_scripts` action, and will
|
472 |
+
* enqueue scripts needed for the backend.
|
473 |
+
*
|
474 |
+
* Filters used:
|
475 |
+
*
|
476 |
+
* - `wprss_help_admin_scripts`
|
477 |
+
*
|
478 |
+
* @return WPRSS_Help This instance.
|
479 |
+
*/
|
480 |
+
public function _admin_enqueue_scripts() {
|
481 |
+
$scripts = $this->apply_filters( 'admin_scripts', array(
|
482 |
+
'jquery-ui-tooltip' => array()
|
483 |
+
));
|
484 |
+
|
485 |
+
foreach ( $scripts as $_handle => $_args ) {
|
486 |
+
// Allows numeric array with handles as values
|
487 |
+
if ( is_numeric( $_handle ) ) {
|
488 |
+
$_handle = $_args;
|
489 |
+
}
|
490 |
+
|
491 |
+
// Allows specifying null as value to simply enqueue handle
|
492 |
+
if ( empty( $_args ) ){
|
493 |
+
$_args = array();
|
494 |
+
}
|
495 |
+
|
496 |
+
array_unshift( $_args, $_handle );
|
497 |
+
call_user_func_array( 'wp_enqueue_script', $_args );
|
498 |
+
}
|
499 |
+
|
500 |
+
return $this;
|
501 |
+
}
|
502 |
+
|
503 |
+
|
504 |
+
public function _admin_footer() {
|
505 |
+
$html = '';
|
506 |
+
$html .= $this->get_enqueued_tooltip_content_html() . "\n";
|
507 |
+
$html .= $this->get_admin_footer_js_html();
|
508 |
+
$html = $this->apply_filters( 'admin_footer', $html );
|
509 |
+
|
510 |
+
echo $html;
|
511 |
+
}
|
512 |
+
|
513 |
+
|
514 |
+
public function is_overrides_default_prefix( $string ) {
|
515 |
+
return strpos( $string, self::OVERRIDE_DEFAULT_PREFIX ) === 0;
|
516 |
+
}
|
517 |
+
|
518 |
+
|
519 |
+
/**
|
520 |
+
* @return string This class's text domain
|
521 |
+
*/
|
522 |
+
public function get_text_domain() {
|
523 |
+
return self::TEXT_DOMAIN;
|
524 |
+
}
|
525 |
+
|
526 |
+
/**
|
527 |
+
* Format this string, replacing placeholders with values, and translate it
|
528 |
+
* in the class's text domain.
|
529 |
+
*
|
530 |
+
* @see sprintf()
|
531 |
+
* @param string $string The string to translate.
|
532 |
+
* @param mixed $argN,.. Additional arguments.
|
533 |
+
*/
|
534 |
+
public function __( $string, $argN = null ) {
|
535 |
+
$args = func_get_args();
|
536 |
+
$args[0] = $string = __( $string, $this->get_text_domain() );
|
537 |
+
|
538 |
+
$string = call_user_func_array( 'sprintf', $args );
|
539 |
+
|
540 |
+
return $string;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Hashes all the given values into a single hash.
|
545 |
+
* Accepts an infinite number of parameters, all of which will be first
|
546 |
+
* glued together by a separator, then hashed.
|
547 |
+
* Non-scalar values will be serialized.
|
548 |
+
*
|
549 |
+
* @param mixed $value The value to hash.
|
550 |
+
* @param mixed $argN Other values to hash.
|
551 |
+
* @return string The hash.
|
552 |
+
*/
|
553 |
+
public function get_hash( $value ) {
|
554 |
+
$args = func_get_args();
|
555 |
+
$glue = self::HASHING_CONCATENATOR;
|
556 |
+
|
557 |
+
$blob = '';
|
558 |
+
foreach ( $args as $_idx => $_arg ) {
|
559 |
+
$blob .= is_scalar( $_arg ) ? $_arg : serialize( $_arg );
|
560 |
+
$blob .= $glue;
|
561 |
+
}
|
562 |
+
|
563 |
+
$blob = substr( $blob, 0, -1 );
|
564 |
+
|
565 |
+
return sha1( $blob );
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* Get the class code prefix, or the specified prefixed with it.
|
570 |
+
*
|
571 |
+
* @param string $string A string to prefix.
|
572 |
+
* @return string The code prefix or the prefixed string.
|
573 |
+
*/
|
574 |
+
public function get_code_prefix( $string = '' ) {
|
575 |
+
return self::CODE_PREFIX . (string)$string;
|
576 |
+
}
|
577 |
+
|
578 |
+
/**
|
579 |
+
* Optionally prefix a string with the class code prefix, unless it
|
580 |
+
* contains the "!" character in the very beginning, in which case it will
|
581 |
+
* simply be removed.
|
582 |
+
*
|
583 |
+
* @param string $string The string to consider for prefixing.
|
584 |
+
* @return string The prefixed or clean string.
|
585 |
+
*/
|
586 |
+
public function prefix( $string ) {
|
587 |
+
return $this->is_overrides_default_prefix( $string )
|
588 |
+
? substr( $string, 1 )
|
589 |
+
: $this->get_code_prefix( $string );
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Applies filters, but prefixes the filter name with 'wprss_help_',
|
594 |
+
* unless '!' is specified as the first character of the filter.
|
595 |
+
*
|
596 |
+
* @param string $filter_name Name or "tag" of the filter.
|
597 |
+
* @param mixed $subject The value to apply filters to.
|
598 |
+
* @param mixed $argN,.. Additional filter arguments
|
599 |
+
* @return mixed Result of filtering
|
600 |
+
*/
|
601 |
+
public function apply_filters( $filter_name, $subject, $argN = null ) {
|
602 |
+
$args = func_get_args();
|
603 |
+
|
604 |
+
$args[0] = $filter_name = $this->prefix( $filter_name );
|
605 |
+
|
606 |
+
return call_user_func_array( 'apply_filters', $args );
|
607 |
+
}
|
608 |
+
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Applies a filters with the specified name to the options that were
|
612 |
+
* applied on top of defaults.
|
613 |
+
* The name will be prefixed with the class prefix 'wprss_help_', and
|
614 |
+
* suffixed with '_options'.
|
615 |
+
*
|
616 |
+
* @param string $filter_name Name of the filter to apply to the options
|
617 |
+
* @param array $options The options to filter
|
618 |
+
* @param mixed $filter_argN,.. Other filter arguments to be passed to filter
|
619 |
+
*/
|
620 |
+
public function apply_options_filters( $filter_name, $options = array(), $filter_argN = null ) {
|
621 |
+
$args = func_get_args();
|
622 |
+
|
623 |
+
// Adding sufix
|
624 |
+
$args[0] = $filter_name .= self::OPTIONS_FILTER_SUFFIX;
|
625 |
+
|
626 |
+
// Applying defaults
|
627 |
+
$args[1] = $options = $this->get_options( $options );
|
628 |
+
|
629 |
+
// Entry point. Order of args is already correct.
|
630 |
+
$options = call_user_func_array( array( $this, 'apply_filters' ), $args );
|
631 |
+
|
632 |
+
return $options;
|
633 |
+
}
|
634 |
+
|
635 |
+
|
636 |
+
/**
|
637 |
+
* Parses the tooltip handle template path for placeholders.
|
638 |
+
*
|
639 |
+
* Filters used:
|
640 |
+
*
|
641 |
+
* - `wprss_help_admin_footer_js_html_template`
|
642 |
+
*
|
643 |
+
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'admin_footer_js_template' option.
|
644 |
+
* @return string Path to the template.
|
645 |
+
*/
|
646 |
+
public function get_admin_footer_js_html_template( $path = null ) {
|
647 |
+
// Default is from options
|
648 |
+
if ( is_null( $path ) ) {
|
649 |
+
$path = $this->get_options( 'admin_footer_js_template' );
|
650 |
+
}
|
651 |
+
|
652 |
+
// Entry point
|
653 |
+
$path = $this->apply_filters( 'admin_footer_js_html_template', $path );
|
654 |
+
|
655 |
+
return $this->parse_path( $path );
|
656 |
+
}
|
657 |
+
|
658 |
+
|
659 |
+
/**
|
660 |
+
* Get the HTML of the JavaScript for the footer in Admin Panel.
|
661 |
+
*
|
662 |
+
* Filters used:
|
663 |
+
*
|
664 |
+
* - `wprss_help_admin_footer_js_html`
|
665 |
+
*
|
666 |
+
* @param array $options Any additional options to be used with defaults.
|
667 |
+
* @return string The HTML.
|
668 |
+
*/
|
669 |
+
public function get_admin_footer_js_html( $options = array() ) {
|
670 |
+
$options = $this->apply_options_filters( 'admin_footer_js_html', $options);
|
671 |
+
|
672 |
+
$templatePath = $this->get_admin_footer_js_html_template( $options['admin_footer_js_template'] );
|
673 |
+
|
674 |
+
return $this->get_template($templatePath, $options);
|
675 |
+
}
|
676 |
+
|
677 |
+
|
678 |
+
/**
|
679 |
+
* Parses the tooltip handle template path for placeholders.
|
680 |
+
*
|
681 |
+
* Filters used:
|
682 |
+
*
|
683 |
+
* - `wprss_help_tooltip_handle_html_template`
|
684 |
+
*
|
685 |
+
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
|
686 |
+
* @return string Path to the template.
|
687 |
+
*/
|
688 |
+
public function get_tooltip_handle_html_template( $path = null ) {
|
689 |
+
// Default is from options
|
690 |
+
if ( is_null( $path ) ) {
|
691 |
+
$path = $this->get_options( 'tooltip_handle_template' );
|
692 |
+
}
|
693 |
+
|
694 |
+
// Entry point
|
695 |
+
$path = $this->apply_filters( 'tooltip_handle_html_template', $path );
|
696 |
+
|
697 |
+
return $this->parse_path( $path );
|
698 |
+
}
|
699 |
+
|
700 |
+
|
701 |
+
/**
|
702 |
+
* Get the HTML of the tooltip handle.
|
703 |
+
*
|
704 |
+
* Filters used:
|
705 |
+
*
|
706 |
+
* - `wprss_help_tooltip_handle_html_options`
|
707 |
+
*
|
708 |
+
* @param string $text Content of the tooltip text.
|
709 |
+
* @param string $id ID of the tooltip.
|
710 |
+
* @param array $options Any additional options to be used with defaults.
|
711 |
+
* @return string The HTML.
|
712 |
+
*/
|
713 |
+
public function get_tooltip_handle_html( $text, $id, $options = array() ) {
|
714 |
+
$options = $this->apply_options_filters( 'tooltip_handle_html', $options, $text, $id);
|
715 |
+
|
716 |
+
// Add template varialbes
|
717 |
+
$options['tooltip_id'] = $id;
|
718 |
+
$options['tooltip_text'] = $text;
|
719 |
+
|
720 |
+
$templatePath = $this->get_tooltip_handle_html_template( $options['tooltip_handle_template'] );
|
721 |
+
|
722 |
+
return $this->get_template($templatePath, $options);
|
723 |
+
}
|
724 |
+
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Parses the tooltip content template path for placeholders.
|
728 |
+
*
|
729 |
+
* Filters used:
|
730 |
+
*
|
731 |
+
* - `wprss_help_tooltip_content_html_template`
|
732 |
+
*
|
733 |
+
* @param null|string $path Optional path to parse and retrieve. Default: value of the 'tooltip_handle_template' option.
|
734 |
+
* @return string Path to the template.
|
735 |
+
*/
|
736 |
+
public function get_tooltip_content_html_template( $path = null ) {
|
737 |
+
// Default is from options
|
738 |
+
if ( is_null( $path ) ) {
|
739 |
+
$path = $this->get_options( 'tooltip_content_template' );
|
740 |
+
}
|
741 |
+
|
742 |
+
// Entry point
|
743 |
+
$path = $this->apply_filters( 'tooltip_content_html_template', $path );
|
744 |
+
|
745 |
+
return $this->parse_path( $path );
|
746 |
+
}
|
747 |
+
|
748 |
+
|
749 |
+
/**
|
750 |
+
* Get the HTML of the tooltip content.
|
751 |
+
*
|
752 |
+
* Filters used:
|
753 |
+
*
|
754 |
+
* - `wprss_help_tooltip_content_html_options`
|
755 |
+
*
|
756 |
+
* @param string $text Content of the tooltip text.
|
757 |
+
* @param string $id ID of the tooltip.
|
758 |
+
* @param array $options Any additional options to be used with defaults.
|
759 |
+
* @return string The HTML.
|
760 |
+
*/
|
761 |
+
public function get_tooltip_content_html( $text, $id, $options = array() ) {
|
762 |
+
$options = $this->apply_options_filters( 'tooltip_content_html', $options, $text, $id );
|
763 |
+
|
764 |
+
// Add template varialbes
|
765 |
+
$options['tooltip_id'] = $id;
|
766 |
+
$options['tooltip_text'] = $text;
|
767 |
+
|
768 |
+
$templatePath = $this->get_tooltip_content_html_template( $options['tooltip_content_template'] );
|
769 |
+
|
770 |
+
return $this->get_template( $templatePath, $options );
|
771 |
+
}
|
772 |
+
|
773 |
+
|
774 |
+
/**
|
775 |
+
* Add tooltip and get tooltip HTML.
|
776 |
+
* If $text is null, just get the HTML of tooltip with specified ID.
|
777 |
+
* The `is_enqueue_tooltip_content` option determines whether to enqueue
|
778 |
+
* the content, instead of outputting it after the handle.
|
779 |
+
*
|
780 |
+
* @param string $id ID for this tooltip
|
781 |
+
* @param string|null $text Text of this tooltip. If null, tooltip will not be added, but only retrieved.
|
782 |
+
* @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
|
783 |
+
* @return string The tooltip handle and, optionally, content.
|
784 |
+
*/
|
785 |
+
public function tooltip( $id, $text = null, $options = array() ) {
|
786 |
+
$this->add_tooltip( $id, $text, $options );
|
787 |
+
return $this->do_tooltip( $id );
|
788 |
+
}
|
789 |
+
|
790 |
+
|
791 |
+
/**
|
792 |
+
* Add tooltips in a batch, with optionally prefixed ID.
|
793 |
+
*
|
794 |
+
* @param array $tooltips An array where key is tooltip ID and value is tooltip text.
|
795 |
+
* @param string $prefix A prefix to add to all tooltip IDs.
|
796 |
+
* @param array $options Arra of options for all the tooltips to add.
|
797 |
+
* @return \WPRSS_Help
|
798 |
+
*/
|
799 |
+
public function add_tooltips( $tooltips, $prefix = null, $options = array() ) {
|
800 |
+
$prefix = (string) $prefix;
|
801 |
+
if ( !is_array($options) ) $options = array();
|
802 |
+
|
803 |
+
foreach ( $tooltips as $_id => $_text ) {
|
804 |
+
$this->add_tooltip( $prefix . $_id, $_text, $options );
|
805 |
+
}
|
806 |
+
|
807 |
+
return $this;
|
808 |
+
}
|
809 |
+
|
810 |
+
|
811 |
+
/**
|
812 |
+
* Add a tooltip for later display.
|
813 |
+
* Text and options will be replaced by existing text and options, if they
|
814 |
+
* are empty, and a tooltip with the same ID is already registered.
|
815 |
+
*
|
816 |
+
* @param string $id The ID of this tooltip
|
817 |
+
* @param string $text Text for this tooltip
|
818 |
+
* @param array $options Options for this tooltip.
|
819 |
+
* @return WPRSS_Help This instance.
|
820 |
+
*/
|
821 |
+
public function add_tooltip( $id, $text = null, $options = array() ) {
|
822 |
+
if ( $tooltip = $this->get_tooltip( $id ) ) {
|
823 |
+
if ( is_null( $text ) ) $text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : $text;
|
824 |
+
if ( empty( $options ) ) $options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : $options;
|
825 |
+
}
|
826 |
+
|
827 |
+
$this->set_tooltip( $id, $text, $options );
|
828 |
+
|
829 |
+
return $this;
|
830 |
+
}
|
831 |
+
|
832 |
+
|
833 |
+
/**
|
834 |
+
* Set a tooltip, existing or not.
|
835 |
+
*
|
836 |
+
* @param string $id The ID of this tooltip
|
837 |
+
* @param string $text Text for this tooltip
|
838 |
+
* @param array $options Options for this tooltip.
|
839 |
+
* @return WPRSS_Help This instance.
|
840 |
+
*/
|
841 |
+
public function set_tooltip( $id, $text = null, $options = array() ) {
|
842 |
+
$this->_tooltips[ $id ] = array(
|
843 |
+
self::TOOLTIP_DATA_KEY_ID => $id,
|
844 |
+
self::TOOLTIP_DATA_KEY_TEXT => $text,
|
845 |
+
self::TOOLTIP_DATA_KEY_OPTIONS => $options
|
846 |
+
);
|
847 |
+
|
848 |
+
return $this;
|
849 |
+
}
|
850 |
+
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Retrieve one tooltip, or an array containing all tooltips.
|
854 |
+
*
|
855 |
+
* @param string|null $id The ID of the tooltip to retrieve.
|
856 |
+
* @param mixed|null $default What to return if tooltip with specified ID not found.
|
857 |
+
* @return array An array that contains the following indexes: 'id', 'text', 'options'. See {@link add_tooltip()} for details.
|
858 |
+
*/
|
859 |
+
public function get_tooltip( $id = null, $default = null ) {
|
860 |
+
if ( is_null( $id ) ) {
|
861 |
+
return $this->_tooltips;
|
862 |
+
}
|
863 |
+
|
864 |
+
return $this->has_tooltip( $id ) ? $this->_tooltips[ $id ] : $default;
|
865 |
+
}
|
866 |
+
|
867 |
+
|
868 |
+
/**
|
869 |
+
* Check whether a tooltip with the specified ID exists.
|
870 |
+
*
|
871 |
+
* @param string $id ID of the tooltip to check for.
|
872 |
+
* @return boolean True if a tooltip with the specified ID exists; false otherwise.
|
873 |
+
*/
|
874 |
+
public function has_tooltip( $id ) {
|
875 |
+
return isset( $this->_tooltips[ $id ] );
|
876 |
+
}
|
877 |
+
|
878 |
+
/**
|
879 |
+
* Get registered tooltip HTML.
|
880 |
+
*
|
881 |
+
* Filters used:
|
882 |
+
*
|
883 |
+
* - `wprss_help_tooltip_options` - Filters options used for tooltip
|
884 |
+
*
|
885 |
+
* @param string $id ID for this tooltip
|
886 |
+
* @param string $text Text of this tooltip
|
887 |
+
* @param array|bool $options The options for this operation, or a boolean indicating whether or not content is to be enqueued
|
888 |
+
* @return string The tooltip handle and, optionally, content.
|
889 |
+
*/
|
890 |
+
public function do_tooltip( $id ) {
|
891 |
+
$options = $this->get_options();
|
892 |
+
|
893 |
+
if ( !($tooltip = $this->get_tooltip( $id )) || !isset($tooltip[ self::TOOLTIP_DATA_KEY_TEXT ]) || !$tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) {
|
894 |
+
return isset( $options['tooltip_not_found_handle_html'] )
|
895 |
+
? $options['tooltip_not_found_handle_html']
|
896 |
+
: null;
|
897 |
+
}
|
898 |
+
|
899 |
+
$options = isset( $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_OPTIONS ] : null;
|
900 |
+
$text = isset( $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] ) ? $tooltip[ self::TOOLTIP_DATA_KEY_TEXT ] : null;
|
901 |
+
|
902 |
+
if ( !is_array( $options ) ) {
|
903 |
+
$options = array( 'is_enqueue_tooltip_content' => $options );
|
904 |
+
}
|
905 |
+
|
906 |
+
// Entry point
|
907 |
+
$options = $this->apply_options_filters( 'tooltip', $options, $id, $text );
|
908 |
+
|
909 |
+
// Get handle HTML
|
910 |
+
$output = $this->get_tooltip_handle_html( $text, $id, $options );
|
911 |
+
|
912 |
+
if ( $this->evaluate_boolean( $options['is_enqueue_tooltip_content'] ) ) {
|
913 |
+
$this->enqueue_tooltip_content($text, $id, $options);
|
914 |
+
}
|
915 |
+
else {
|
916 |
+
$output .= $this->get_tooltip_content_html( $text, $id, $options );
|
917 |
+
}
|
918 |
+
|
919 |
+
return $output;
|
920 |
+
}
|
921 |
+
|
922 |
+
|
923 |
+
/**
|
924 |
+
* Enqueue tooltip content to be displayed in another part of the page.
|
925 |
+
*
|
926 |
+
* @param string $text The text of the tooltip content to enqueue.
|
927 |
+
* @param string $id ID of the tooltip, the content of which to enqueue.
|
928 |
+
* @param array $options This tooltip's options.
|
929 |
+
* @return \WP_Error|\WPRSS_Help This instance, or error if enqueue method is invalid.
|
930 |
+
*/
|
931 |
+
public function enqueue_tooltip_content( $text, $id, $options = array() ) {
|
932 |
+
$queue_method = $this->apply_filters( 'enqueue_tooltip_content_method', array( $this, '_enqueue_tooltip_content' ), $options, $id, $text );
|
933 |
+
|
934 |
+
// "Error handling" WP style
|
935 |
+
if ( !is_callable( $queue_method ) ) {
|
936 |
+
return new WP_Error( $this->prefix( 'invalid_queue_method' ), $this->__( 'Could not enqueue tooltip content: the queue method is not a valid callable.' ), array(
|
937 |
+
'queue_method' => $queue_method,
|
938 |
+
'text' => $text,
|
939 |
+
'id' => $id,
|
940 |
+
'options' => $options
|
941 |
+
));
|
942 |
+
}
|
943 |
+
|
944 |
+
call_user_func_array( $queue_method, array( $text, $id, $options ) );
|
945 |
+
|
946 |
+
return $this;
|
947 |
+
}
|
948 |
+
|
949 |
+
|
950 |
+
public function _enqueue_tooltip_content( $text, $id, $options = array() ) {
|
951 |
+
$hash = $this->get_hash( $text, $id, $options );
|
952 |
+
$this->_enqueued_tooltip_content[ $hash ] = array(
|
953 |
+
self::TOOLTIP_DATA_KEY_TEXT => $text,
|
954 |
+
self::TOOLTIP_DATA_KEY_ID => $id,
|
955 |
+
self::TOOLTIP_DATA_KEY_OPTIONS => $options
|
956 |
+
);
|
957 |
+
|
958 |
+
return $this;
|
959 |
+
}
|
960 |
+
|
961 |
+
|
962 |
+
public function get_enqueued_tooltip_content() {
|
963 |
+
return $this->_enqueued_tooltip_content;
|
964 |
+
}
|
965 |
+
|
966 |
+
|
967 |
+
public function get_enqueued_tooltip_content_html() {
|
968 |
+
$output = '';
|
969 |
+
foreach ( $this->get_enqueued_tooltip_content() as $_hash => $_vars ) {
|
970 |
+
$options = is_array( $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] ) ? $_vars[ self::TOOLTIP_DATA_KEY_OPTIONS ] : array();
|
971 |
+
$output = $this->get_tooltip_content_html( $_vars[ self::TOOLTIP_DATA_KEY_ID ], $_vars[ self::TOOLTIP_DATA_KEY_ID ], $options );
|
972 |
+
}
|
973 |
+
|
974 |
+
echo $output;
|
975 |
+
}
|
976 |
+
|
977 |
+
|
978 |
+
/**
|
979 |
+
* Check whether or not the given value is false.
|
980 |
+
* False values are all {@link empty()} values, and also strings 'false' and 'no'.
|
981 |
+
*
|
982 |
+
* @param mixed $value The value to check.
|
983 |
+
* @return boolean Whether or not the value is considered to be false.
|
984 |
+
*/
|
985 |
+
public function evaluate_boolean( $value ) {
|
986 |
+
return (empty( $value ) || strtolower( $value ) === 'false' || strtolower( $value ) === 'no')
|
987 |
+
? false
|
988 |
+
: true;
|
989 |
+
}
|
990 |
+
|
991 |
+
|
992 |
+
/**
|
993 |
+
* Merge two arrays in an intuitive way.
|
994 |
+
* Input arrays remain unchanged.
|
995 |
+
*
|
996 |
+
* @see http://php.net/manual/en/function.array-merge-recursive.php#92195
|
997 |
+
* @param array $array1 The array to merge.
|
998 |
+
* @param array $array2 The array to merge into.
|
999 |
+
* @return array The merged array.
|
1000 |
+
*/
|
1001 |
+
public function array_merge_recursive_distinct( array &$array1, array &$array2 ) {
|
1002 |
+
$merged = $array1;
|
1003 |
+
|
1004 |
+
foreach ( $array2 as $key => &$value ) {
|
1005 |
+
if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
|
1006 |
+
$merged[ $key ] = array_merge_recursive_distinct( $merged[ $key ], $value );
|
1007 |
+
} else {
|
1008 |
+
$merged[ $key ] = $value;
|
1009 |
+
}
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
return $merged;
|
1013 |
+
}
|
1014 |
+
|
1015 |
+
|
1016 |
+
/**
|
1017 |
+
* Converts an array to a numeric array.
|
1018 |
+
* If $map is empty, assumes that the array keys are already in order.
|
1019 |
+
* If $map is a number, assumes it's the amount of elements to return.
|
1020 |
+
* If $map is an array, assumes it is the map of intended numeric indexes to their value in the input array.
|
1021 |
+
*
|
1022 |
+
* @param array $array The array to convert to a numeric array
|
1023 |
+
* @param false|null|array $map The map of the array indexes, or number of array elements to slice, or nothing.
|
1024 |
+
* @return array The resulting numeric array.
|
1025 |
+
*/
|
1026 |
+
public function array_to_numeric( $array, $map = null ) {
|
1027 |
+
$result = array();
|
1028 |
+
|
1029 |
+
// If map is not an array, assume it's an indicator
|
1030 |
+
if ( !is_array( $map ) ) {
|
1031 |
+
$array = array_values( $array );
|
1032 |
+
}
|
1033 |
+
|
1034 |
+
// If map is empty, assume keys are in order
|
1035 |
+
if ( empty( $map ) ) {
|
1036 |
+
return $array;
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
// If map is a number, assume it's the amount of elements to return
|
1040 |
+
if ( is_numeric( $map ) ) {
|
1041 |
+
$map = intval( $map );
|
1042 |
+
return array_slice( $array, 0, $map );
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
foreach( $map as $_idx => $_key ) {
|
1046 |
+
$result[ $_idx ] = $array[ $_key ];
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
return $result;
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
|
1053 |
+
/**
|
1054 |
+
* Parses the template and replaces placeholders with their values.
|
1055 |
+
* This function uses {@see sprintf()} to format the template string using
|
1056 |
+
* the values provided in $data.
|
1057 |
+
* It is also possible for $data to be an associative array of key-value pairs.
|
1058 |
+
* To achieve the same result, a map can be provided, mapping data keys to
|
1059 |
+
* their placeholder positions.
|
1060 |
+
* If no map is provided,
|
1061 |
+
*
|
1062 |
+
* @param string $string The template string.
|
1063 |
+
* @param array $data The key-value pairs of template data.
|
1064 |
+
* @param false|null|array $map {@see array_to_numeric()} The template value map.
|
1065 |
+
* @return string The parsed and modified template.
|
1066 |
+
*/
|
1067 |
+
public function parse_template( $string, $data, $map = null ) {
|
1068 |
+
$data = $this->array_to_numeric( $data, $map );
|
1069 |
+
array_unshift( $data, $string );
|
1070 |
+
return call_user_func_array( 'sprintf', $data );
|
1071 |
+
}
|
1072 |
+
|
1073 |
+
|
1074 |
+
/**
|
1075 |
+
* Parses a path template specifically with WPRSS_Help path placeholders.
|
1076 |
+
*
|
1077 |
+
* Filters used (in order):
|
1078 |
+
*
|
1079 |
+
* 1. `parse_path_data_default`;
|
1080 |
+
* 2. `parse_path_data`;
|
1081 |
+
* 3. `parse_path_map`;
|
1082 |
+
* 4. `parse_path_path`.
|
1083 |
+
*
|
1084 |
+
* @see WPRSS_Help::parse_template()
|
1085 |
+
* @param string $path The path to parse.
|
1086 |
+
* @param null|array $data Any additional data. Will be merged with defaults.
|
1087 |
+
* @param null|array $map The map for parsing.
|
1088 |
+
* @return string The path with placeholders replaced
|
1089 |
+
*/
|
1090 |
+
public function parse_path( $path, $data = null, $map = null ) {
|
1091 |
+
if( is_null( $data ) ) {
|
1092 |
+
$data = array();
|
1093 |
+
}
|
1094 |
+
|
1095 |
+
$defaults = $this->apply_filters( 'parse_path_data_default', array(
|
1096 |
+
'wprss_templates_dir' => wprss_get_templates_dir()
|
1097 |
+
));
|
1098 |
+
$data = $this->array_merge_recursive_distinct( $data, $defaults );
|
1099 |
+
$data = $this->apply_filters( 'parse_path_data', $data, $path, $map );
|
1100 |
+
$map = $this->apply_filters( 'parse_path_map', $map, $data, $path );
|
1101 |
+
$path = $this->apply_filters( 'parse_path_path', $path, $data, $map );
|
1102 |
+
|
1103 |
+
return $this->parse_template( $path, $data, $map );
|
1104 |
+
}
|
1105 |
+
}
|
1106 |
+
|
1107 |
+
WPRSS_Help::init();
|
includes/admin-import-export.php
CHANGED
@@ -1,239 +1,239 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Build the import/export settings page, used to import and export the plugin's settings
|
4 |
-
* Based on http://wp.tutsplus.com/tutorials/creative-coding/creating-a-simple-backuprestore-settings-feature/
|
5 |
-
*
|
6 |
-
* @since 3.1
|
7 |
-
*/
|
8 |
-
|
9 |
-
add_action( 'admin_init', 'wp_rss_aggregator_bulk_import' );
|
10 |
-
/**
|
11 |
-
* Checks for the submission of a bulk import.
|
12 |
-
* If a bulk submission is made, creates the feed sources.
|
13 |
-
*
|
14 |
-
* @since 4.5
|
15 |
-
*/
|
16 |
-
function wp_rss_aggregator_bulk_import() {
|
17 |
-
// Check if recieving
|
18 |
-
if ( !empty( $_POST['bulk-feeds'] ) ) {
|
19 |
-
// Check nonce
|
20 |
-
check_admin_referer('wprss-bulk-import', 'wprss-bulk-import');
|
21 |
-
// Get the text
|
22 |
-
$bulk_feeds = $_POST['bulk-feeds'];
|
23 |
-
// Split by lines
|
24 |
-
$lines = explode("\n", $bulk_feeds);
|
25 |
-
// Keep a counter
|
26 |
-
global $wprss_bulk_count;
|
27 |
-
$wprss_bulk_count = 0;
|
28 |
-
// Iterate each line
|
29 |
-
foreach( $lines as $line ) {
|
30 |
-
// Split by comma
|
31 |
-
$parts = array_map('trim', explode(",", $line) );
|
32 |
-
// Check if split was successful
|
33 |
-
if ( count($parts) < 2 ) continue;
|
34 |
-
// Prepare the feed data
|
35 |
-
$name = $parts[0];
|
36 |
-
$url = $parts[1];
|
37 |
-
// Check if both name and url are set
|
38 |
-
if ( empty($name) || empty($url) ) continue;
|
39 |
-
$feed = array(
|
40 |
-
'post_title' => $name,
|
41 |
-
'post_status' => 'publish',
|
42 |
-
'post_type' => 'wprss_feed'
|
43 |
-
);
|
44 |
-
// Insert the feed into the DB
|
45 |
-
$inserted_id = wp_insert_post( $feed );
|
46 |
-
// Check if an error occurred
|
47 |
-
if ( is_wp_error($inserted_id) ) continue;
|
48 |
-
// Set the URL
|
49 |
-
update_post_meta($inserted_id, 'wprss_url', $url);
|
50 |
-
// Increment the counter
|
51 |
-
$wprss_bulk_count++;
|
52 |
-
}
|
53 |
-
add_action('admin_notices', 'wprss_notify_bulk_add');
|
54 |
-
}
|
55 |
-
}
|
56 |
-
|
57 |
-
function wprss_notify_bulk_add() {
|
58 |
-
global $wprss_bulk_count; ?>
|
59 |
-
<div class="updated">
|
60 |
-
<p><?php echo sprintf( __( 'Successfully imported <code>%1$s</code> feed sources.', WPRSS_TEXT_DOMAIN ), $wprss_bulk_count )?></p>
|
61 |
-
</div>
|
62 |
-
<?php
|
63 |
-
}
|
64 |
-
|
65 |
-
|
66 |
-
add_action( 'admin_init', 'wp_rss_aggregator_export', 1 );
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Handles exporting of aggregator settings
|
70 |
-
*
|
71 |
-
* @since 3.1
|
72 |
-
*/
|
73 |
-
function wp_rss_aggregator_export() {
|
74 |
-
if ( isset( $_POST['export'] ) && check_admin_referer( 'wprss-settings-export' ) ) {
|
75 |
-
$blogname = str_replace( " ", "", get_option( 'blogname' ) );
|
76 |
-
$date = date( "m-d-Y" );
|
77 |
-
$json_name = $blogname . "-" . $date; // Naming the filename that will be generated.
|
78 |
-
|
79 |
-
header( 'Content-Description: File Transfer' );
|
80 |
-
header( "Content-Type: text/json; charset=" . get_option( 'blog_charset' ) );
|
81 |
-
header( "Content-Disposition: attachment; filename=$json_name.json" );
|
82 |
-
wp_rss_set_export_data();
|
83 |
-
die();
|
84 |
-
}
|
85 |
-
}
|
86 |
-
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Gathers relevant options, encodes them in Json and echoes the file
|
90 |
-
*
|
91 |
-
* @since 3.1
|
92 |
-
*/
|
93 |
-
function wp_rss_set_export_data() {
|
94 |
-
$options = apply_filters(
|
95 |
-
'wprss_fields_export',
|
96 |
-
array( 'wprss_settings_general' => get_option( 'wprss_settings_general' ) )
|
97 |
-
);
|
98 |
-
$json_file = json_encode( $options );
|
99 |
-
|
100 |
-
foreach ( $options as $key => $value ) {
|
101 |
-
$value = maybe_unserialize( $value );
|
102 |
-
$need_options[ $key ] = $value;
|
103 |
-
}
|
104 |
-
$json_file = json_encode( $need_options ); // Encode data into json data
|
105 |
-
echo $json_file;
|
106 |
-
die();
|
107 |
-
}
|
108 |
-
|
109 |
-
|
110 |
-
/**
|
111 |
-
* Notice for a successful export
|
112 |
-
*
|
113 |
-
* @since 3.1
|
114 |
-
*/
|
115 |
-
function wp_rss_aggregator_export_notice() {
|
116 |
-
?><div class="updated"><?php echo wpautop( __( 'All options are exported successfully.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
117 |
-
|
118 |
-
}
|
119 |
-
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Notice for a successful import
|
123 |
-
*
|
124 |
-
* @since 3.1
|
125 |
-
*/
|
126 |
-
function wp_rss_aggregator_import_notice1() {
|
127 |
-
?><div class="updated"><?php echo wpautop( __( 'All options are restored successfully.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
128 |
-
|
129 |
-
}
|
130 |
-
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Notice for an unsuccessful import
|
134 |
-
*
|
135 |
-
* @since 3.1
|
136 |
-
*/
|
137 |
-
function wp_rss_aggregator_import_notice2() {
|
138 |
-
?><div class="error"><?php echo wpautop( __( 'Invalid file or file size too big.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
139 |
-
|
140 |
-
}
|
141 |
-
|
142 |
-
|
143 |
-
add_action( 'admin_init', 'wp_rss_aggregator_import' );
|
144 |
-
/**
|
145 |
-
* Handles the importing of settings
|
146 |
-
*
|
147 |
-
* @since 3.1
|
148 |
-
*/
|
149 |
-
function wp_rss_aggregator_import(){
|
150 |
-
global $pagenow;
|
151 |
-
if( $pagenow == 'admin.php' ) {
|
152 |
-
//Hope this plugin don't use admin.php for anything
|
153 |
-
return;
|
154 |
-
}
|
155 |
-
elseif ( $pagenow == 'edit.php' ) {
|
156 |
-
if ( isset( $_FILES['import'] ) && check_admin_referer( 'wprss-settings-import' ) ) {
|
157 |
-
if ( $_FILES['import']['error'] > 0) {
|
158 |
-
wp_die( "Error during import" );
|
159 |
-
} else {
|
160 |
-
$file_name = $_FILES['import']['name'];
|
161 |
-
$file_ext = strtolower( end( explode( ".", $file_name ) ) );
|
162 |
-
$file_size = $_FILES['import']['size'];
|
163 |
-
if ( ( $file_ext == "json" ) && ( $file_size < 500000 ) ) {
|
164 |
-
$encode_options = file_get_contents( $_FILES['import']['tmp_name'] );
|
165 |
-
$options = json_decode( $encode_options, true );
|
166 |
-
foreach ( $options as $key => $value ) {
|
167 |
-
update_option( $key, $value );
|
168 |
-
}
|
169 |
-
add_action( 'admin_notices', 'wp_rss_aggregator_import_notice1' );
|
170 |
-
do_action( 'wprss_settings_imported' );
|
171 |
-
}
|
172 |
-
else {
|
173 |
-
add_action( 'admin_notices', 'wp_rss_aggregator_import_notice2' );
|
174 |
-
}
|
175 |
-
}
|
176 |
-
}
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Handles the import/export page display
|
183 |
-
*
|
184 |
-
* @since 3.1
|
185 |
-
*/
|
186 |
-
function wprss_import_export_settings_page_display() {
|
187 |
-
if ( !isset( $_POST['export'] ) ) { ?>
|
188 |
-
<div class="wrap">
|
189 |
-
<?php screen_icon( 'wprss-aggregator' ); ?>
|
190 |
-
|
191 |
-
<!-- Bulk Add -->
|
192 |
-
<h2><?php _e( 'Bulk Feed Import', WPRSS_TEXT_DOMAIN ); ?></h2>
|
193 |
-
<p><?php _e( 'Import multiple feed sources at once, by entering the name and URLs of your feeds below.', WPRSS_TEXT_DOMAIN ); ?></p>
|
194 |
-
<p><?php _e( 'Separate the name and the URL using a comma on each line:', WPRSS_TEXT_DOMAIN ); ?>
|
195 |
-
<code><?php _e( 'Feed Name, http://www.myfeed.com', WPRSS_TEXT_DOMAIN ); ?></code>
|
196 |
-
</p>
|
197 |
-
<form id="bulk-add-form" method="POST">
|
198 |
-
<textarea rows="6" cols="80" form="bulk-add-form" name="bulk-feeds" autofocus></textarea>
|
199 |
-
<br/>
|
200 |
-
<?php wp_nonce_field('wprss-bulk-import', 'wprss-bulk-import'); ?>
|
201 |
-
<input type="submit" class="button-secondary" name="bulk-add" value="<?php _e( 'Bulk Import', WPRSS_TEXT_DOMAIN ) ?>" />
|
202 |
-
</form>
|
203 |
-
<hr/>
|
204 |
-
|
205 |
-
<!-- Settings Import/Export -->
|
206 |
-
<h2><?php _e( 'Import & Export Settings', WPRSS_TEXT_DOMAIN ); ?></h2>
|
207 |
-
|
208 |
-
<h3><?php _e( 'Export Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
209 |
-
<?php echo wpautop( __( 'Click the <strong>Export Settings</strong> button to generate a file containing all the settings used by WP RSS Aggregator', WPRSS_TEXT_DOMAIN ) ) ?>
|
210 |
-
<?php echo wpautop( __( 'After exporting, you can either use the backup file to restore your settings to this site or to another WordPress site.', WPRSS_TEXT_DOMAIN ) ) ?>
|
211 |
-
<?php do_action( 'wprss_export_section' ); ?>
|
212 |
-
<form method="post">
|
213 |
-
<p class="submit">
|
214 |
-
<?php wp_nonce_field( 'wprss-settings-export' ); ?>
|
215 |
-
<input type="submit" name="export" value="<?php _e( 'Export Settings', WPRSS_TEXT_DOMAIN ); ?>" class="button" />
|
216 |
-
</p>
|
217 |
-
</form>
|
218 |
-
|
219 |
-
<h3><?php _e( 'Import Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
220 |
-
<?php echo wpautop( __( 'Click the <strong>Choose file</strong> button and choose a backup file.', WPRSS_TEXT_DOMAIN ) ) ?>
|
221 |
-
<?php echo wpautop( __( 'Press the <strong>Import Settings</strong> button, and WordPress will do the rest for you.', WPRSS_TEXT_DOMAIN ) ) ?>
|
222 |
-
<?php do_action( 'wprss_import_section' ); ?>
|
223 |
-
<form method='post' enctype='multipart/form-data'>
|
224 |
-
<p class="submit">
|
225 |
-
<?php wp_nonce_field( 'wprss-settings-import' ); ?>
|
226 |
-
<input type='file' name='import' />
|
227 |
-
<input type='submit' name='import' value="<?php _e( 'Import Settings', WPRSS_TEXT_DOMAIN ); ?>" class="button" />
|
228 |
-
</p>
|
229 |
-
</form>
|
230 |
-
|
231 |
-
<h3><?php _e( 'Importing/Exporting Feed Sources', WPRSS_TEXT_DOMAIN ); ?></h3>
|
232 |
-
<?php echo wpautop( sprintf( __( 'To import/export your feed sources, please use the standard WordPress <a href="%1$simport.php">Import</a> and <a href="%1$sexport.php">Export</a> functionality.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
233 |
-
<?php echo wpautop( sprintf( __( 'On the <a href="%1$sexport.php">Export</a> page, check the <strong>Feed Sources</strong> radio button and click the <strong>Download Export File</strong> button. WordPress will then create an XML file containing all the feed sources.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
234 |
-
<?php echo wpautop( sprintf( __( 'On the <a href="%1$simport.php">Import</a> page, choose the previously created file and click the <strong>Upload file and import</strong> button.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
235 |
-
|
236 |
-
</div>
|
237 |
-
<?php
|
238 |
-
}
|
239 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Build the import/export settings page, used to import and export the plugin's settings
|
4 |
+
* Based on http://wp.tutsplus.com/tutorials/creative-coding/creating-a-simple-backuprestore-settings-feature/
|
5 |
+
*
|
6 |
+
* @since 3.1
|
7 |
+
*/
|
8 |
+
|
9 |
+
add_action( 'admin_init', 'wp_rss_aggregator_bulk_import' );
|
10 |
+
/**
|
11 |
+
* Checks for the submission of a bulk import.
|
12 |
+
* If a bulk submission is made, creates the feed sources.
|
13 |
+
*
|
14 |
+
* @since 4.5
|
15 |
+
*/
|
16 |
+
function wp_rss_aggregator_bulk_import() {
|
17 |
+
// Check if recieving
|
18 |
+
if ( !empty( $_POST['bulk-feeds'] ) ) {
|
19 |
+
// Check nonce
|
20 |
+
check_admin_referer('wprss-bulk-import', 'wprss-bulk-import');
|
21 |
+
// Get the text
|
22 |
+
$bulk_feeds = $_POST['bulk-feeds'];
|
23 |
+
// Split by lines
|
24 |
+
$lines = explode("\n", $bulk_feeds);
|
25 |
+
// Keep a counter
|
26 |
+
global $wprss_bulk_count;
|
27 |
+
$wprss_bulk_count = 0;
|
28 |
+
// Iterate each line
|
29 |
+
foreach( $lines as $line ) {
|
30 |
+
// Split by comma
|
31 |
+
$parts = array_map('trim', explode(",", $line) );
|
32 |
+
// Check if split was successful
|
33 |
+
if ( count($parts) < 2 ) continue;
|
34 |
+
// Prepare the feed data
|
35 |
+
$name = $parts[0];
|
36 |
+
$url = $parts[1];
|
37 |
+
// Check if both name and url are set
|
38 |
+
if ( empty($name) || empty($url) ) continue;
|
39 |
+
$feed = array(
|
40 |
+
'post_title' => $name,
|
41 |
+
'post_status' => 'publish',
|
42 |
+
'post_type' => 'wprss_feed'
|
43 |
+
);
|
44 |
+
// Insert the feed into the DB
|
45 |
+
$inserted_id = wp_insert_post( $feed );
|
46 |
+
// Check if an error occurred
|
47 |
+
if ( is_wp_error($inserted_id) ) continue;
|
48 |
+
// Set the URL
|
49 |
+
update_post_meta($inserted_id, 'wprss_url', $url);
|
50 |
+
// Increment the counter
|
51 |
+
$wprss_bulk_count++;
|
52 |
+
}
|
53 |
+
add_action('admin_notices', 'wprss_notify_bulk_add');
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
function wprss_notify_bulk_add() {
|
58 |
+
global $wprss_bulk_count; ?>
|
59 |
+
<div class="updated">
|
60 |
+
<p><?php echo sprintf( __( 'Successfully imported <code>%1$s</code> feed sources.', WPRSS_TEXT_DOMAIN ), $wprss_bulk_count )?></p>
|
61 |
+
</div>
|
62 |
+
<?php
|
63 |
+
}
|
64 |
+
|
65 |
+
|
66 |
+
add_action( 'admin_init', 'wp_rss_aggregator_export', 1 );
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Handles exporting of aggregator settings
|
70 |
+
*
|
71 |
+
* @since 3.1
|
72 |
+
*/
|
73 |
+
function wp_rss_aggregator_export() {
|
74 |
+
if ( isset( $_POST['export'] ) && check_admin_referer( 'wprss-settings-export' ) ) {
|
75 |
+
$blogname = str_replace( " ", "", get_option( 'blogname' ) );
|
76 |
+
$date = date( "m-d-Y" );
|
77 |
+
$json_name = $blogname . "-" . $date; // Naming the filename that will be generated.
|
78 |
+
|
79 |
+
header( 'Content-Description: File Transfer' );
|
80 |
+
header( "Content-Type: text/json; charset=" . get_option( 'blog_charset' ) );
|
81 |
+
header( "Content-Disposition: attachment; filename=$json_name.json" );
|
82 |
+
wp_rss_set_export_data();
|
83 |
+
die();
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Gathers relevant options, encodes them in Json and echoes the file
|
90 |
+
*
|
91 |
+
* @since 3.1
|
92 |
+
*/
|
93 |
+
function wp_rss_set_export_data() {
|
94 |
+
$options = apply_filters(
|
95 |
+
'wprss_fields_export',
|
96 |
+
array( 'wprss_settings_general' => get_option( 'wprss_settings_general' ) )
|
97 |
+
);
|
98 |
+
$json_file = json_encode( $options );
|
99 |
+
|
100 |
+
foreach ( $options as $key => $value ) {
|
101 |
+
$value = maybe_unserialize( $value );
|
102 |
+
$need_options[ $key ] = $value;
|
103 |
+
}
|
104 |
+
$json_file = json_encode( $need_options ); // Encode data into json data
|
105 |
+
echo $json_file;
|
106 |
+
die();
|
107 |
+
}
|
108 |
+
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Notice for a successful export
|
112 |
+
*
|
113 |
+
* @since 3.1
|
114 |
+
*/
|
115 |
+
function wp_rss_aggregator_export_notice() {
|
116 |
+
?><div class="updated"><?php echo wpautop( __( 'All options are exported successfully.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
117 |
+
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Notice for a successful import
|
123 |
+
*
|
124 |
+
* @since 3.1
|
125 |
+
*/
|
126 |
+
function wp_rss_aggregator_import_notice1() {
|
127 |
+
?><div class="updated"><?php echo wpautop( __( 'All options are restored successfully.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
128 |
+
|
129 |
+
}
|
130 |
+
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Notice for an unsuccessful import
|
134 |
+
*
|
135 |
+
* @since 3.1
|
136 |
+
*/
|
137 |
+
function wp_rss_aggregator_import_notice2() {
|
138 |
+
?><div class="error"><?php echo wpautop( __( 'Invalid file or file size too big.', WPRSS_TEXT_DOMAIN ) ) ?></div><?php
|
139 |
+
|
140 |
+
}
|
141 |
+
|
142 |
+
|
143 |
+
add_action( 'admin_init', 'wp_rss_aggregator_import' );
|
144 |
+
/**
|
145 |
+
* Handles the importing of settings
|
146 |
+
*
|
147 |
+
* @since 3.1
|
148 |
+
*/
|
149 |
+
function wp_rss_aggregator_import(){
|
150 |
+
global $pagenow;
|
151 |
+
if( $pagenow == 'admin.php' ) {
|
152 |
+
//Hope this plugin don't use admin.php for anything
|
153 |
+
return;
|
154 |
+
}
|
155 |
+
elseif ( $pagenow == 'edit.php' ) {
|
156 |
+
if ( isset( $_FILES['import'] ) && check_admin_referer( 'wprss-settings-import' ) ) {
|
157 |
+
if ( $_FILES['import']['error'] > 0) {
|
158 |
+
wp_die( "Error during import" );
|
159 |
+
} else {
|
160 |
+
$file_name = $_FILES['import']['name'];
|
161 |
+
$file_ext = strtolower( end( explode( ".", $file_name ) ) );
|
162 |
+
$file_size = $_FILES['import']['size'];
|
163 |
+
if ( ( $file_ext == "json" ) && ( $file_size < 500000 ) ) {
|
164 |
+
$encode_options = file_get_contents( $_FILES['import']['tmp_name'] );
|
165 |
+
$options = json_decode( $encode_options, true );
|
166 |
+
foreach ( $options as $key => $value ) {
|
167 |
+
update_option( $key, $value );
|
168 |
+
}
|
169 |
+
add_action( 'admin_notices', 'wp_rss_aggregator_import_notice1' );
|
170 |
+
do_action( 'wprss_settings_imported' );
|
171 |
+
}
|
172 |
+
else {
|
173 |
+
add_action( 'admin_notices', 'wp_rss_aggregator_import_notice2' );
|
174 |
+
}
|
175 |
+
}
|
176 |
+
}
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Handles the import/export page display
|
183 |
+
*
|
184 |
+
* @since 3.1
|
185 |
+
*/
|
186 |
+
function wprss_import_export_settings_page_display() {
|
187 |
+
if ( !isset( $_POST['export'] ) ) { ?>
|
188 |
+
<div class="wrap">
|
189 |
+
<?php screen_icon( 'wprss-aggregator' ); ?>
|
190 |
+
|
191 |
+
<!-- Bulk Add -->
|
192 |
+
<h2><?php _e( 'Bulk Feed Import', WPRSS_TEXT_DOMAIN ); ?></h2>
|
193 |
+
<p><?php _e( 'Import multiple feed sources at once, by entering the name and URLs of your feeds below.', WPRSS_TEXT_DOMAIN ); ?></p>
|
194 |
+
<p><?php _e( 'Separate the name and the URL using a comma on each line:', WPRSS_TEXT_DOMAIN ); ?>
|
195 |
+
<code><?php _e( 'Feed Name, http://www.myfeed.com', WPRSS_TEXT_DOMAIN ); ?></code>
|
196 |
+
</p>
|
197 |
+
<form id="bulk-add-form" method="POST">
|
198 |
+
<textarea rows="6" cols="80" form="bulk-add-form" name="bulk-feeds" autofocus></textarea>
|
199 |
+
<br/>
|
200 |
+
<?php wp_nonce_field('wprss-bulk-import', 'wprss-bulk-import'); ?>
|
201 |
+
<input type="submit" class="button-secondary" name="bulk-add" value="<?php _e( 'Bulk Import', WPRSS_TEXT_DOMAIN ) ?>" />
|
202 |
+
</form>
|
203 |
+
<hr/>
|
204 |
+
|
205 |
+
<!-- Settings Import/Export -->
|
206 |
+
<h2><?php _e( 'Import & Export Settings', WPRSS_TEXT_DOMAIN ); ?></h2>
|
207 |
+
|
208 |
+
<h3><?php _e( 'Export Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
209 |
+
<?php echo wpautop( __( 'Click the <strong>Export Settings</strong> button to generate a file containing all the settings used by WP RSS Aggregator', WPRSS_TEXT_DOMAIN ) ) ?>
|
210 |
+
<?php echo wpautop( __( 'After exporting, you can either use the backup file to restore your settings to this site or to another WordPress site.', WPRSS_TEXT_DOMAIN ) ) ?>
|
211 |
+
<?php do_action( 'wprss_export_section' ); ?>
|
212 |
+
<form method="post">
|
213 |
+
<p class="submit">
|
214 |
+
<?php wp_nonce_field( 'wprss-settings-export' ); ?>
|
215 |
+
<input type="submit" name="export" value="<?php _e( 'Export Settings', WPRSS_TEXT_DOMAIN ); ?>" class="button" />
|
216 |
+
</p>
|
217 |
+
</form>
|
218 |
+
|
219 |
+
<h3><?php _e( 'Import Settings', WPRSS_TEXT_DOMAIN ); ?></h3>
|
220 |
+
<?php echo wpautop( __( 'Click the <strong>Choose file</strong> button and choose a backup file.', WPRSS_TEXT_DOMAIN ) ) ?>
|
221 |
+
<?php echo wpautop( __( 'Press the <strong>Import Settings</strong> button, and WordPress will do the rest for you.', WPRSS_TEXT_DOMAIN ) ) ?>
|
222 |
+
<?php do_action( 'wprss_import_section' ); ?>
|
223 |
+
<form method='post' enctype='multipart/form-data'>
|
224 |
+
<p class="submit">
|
225 |
+
<?php wp_nonce_field( 'wprss-settings-import' ); ?>
|
226 |
+
<input type='file' name='import' />
|
227 |
+
<input type='submit' name='import' value="<?php _e( 'Import Settings', WPRSS_TEXT_DOMAIN ); ?>" class="button" />
|
228 |
+
</p>
|
229 |
+
</form>
|
230 |
+
|
231 |
+
<h3><?php _e( 'Importing/Exporting Feed Sources', WPRSS_TEXT_DOMAIN ); ?></h3>
|
232 |
+
<?php echo wpautop( sprintf( __( 'To import/export your feed sources, please use the standard WordPress <a href="%1$simport.php">Import</a> and <a href="%1$sexport.php">Export</a> functionality.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
233 |
+
<?php echo wpautop( sprintf( __( 'On the <a href="%1$sexport.php">Export</a> page, check the <strong>Feed Sources</strong> radio button and click the <strong>Download Export File</strong> button. WordPress will then create an XML file containing all the feed sources.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
234 |
+
<?php echo wpautop( sprintf( __( 'On the <a href="%1$simport.php">Import</a> page, choose the previously created file and click the <strong>Upload file and import</strong> button.', WPRSS_TEXT_DOMAIN ), get_admin_url() ) ) ?>
|
235 |
+
|
236 |
+
</div>
|
237 |
+
<?php
|
238 |
+
}
|
239 |
}
|
includes/admin-log.php
CHANGED
@@ -1,268 +1,268 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
define( 'WPRSS_LOG_DISPLAY_LIMIT', 100000 ); // Number of chars to display in log
|
4 |
-
define( 'WPRSS_OPTION_CODE_LOG_LEVEL', 'log_level' );
|
5 |
-
define( 'WPRSS_LOG_LEVEL_NONE', 0 );
|
6 |
-
define( 'WPRSS_LOG_LEVEL_SYSTEM', 1 );
|
7 |
-
define( 'WPRSS_LOG_LEVEL_INFO', 2 );
|
8 |
-
define( 'WPRSS_LOG_LEVEL_NOTICE', 4 );
|
9 |
-
define( 'WPRSS_LOG_LEVEL_WARNING', 8 );
|
10 |
-
define( 'WPRSS_LOG_LEVEL_ERROR', 16 );
|
11 |
-
define( 'WPRSS_LOG_LEVEL_DEFAULT', 'default' );
|
12 |
-
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Returns the log file path.
|
16 |
-
*
|
17 |
-
* @since 4.0.4
|
18 |
-
*/
|
19 |
-
function wprss_log_file() {
|
20 |
-
return WPRSS_LOG_FILE . '-' . get_current_blog_id() . WPRSS_LOG_FILE_EXT;
|
21 |
-
}
|
22 |
-
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Clears the log file.
|
26 |
-
*
|
27 |
-
* @since 3.9.6
|
28 |
-
*/
|
29 |
-
function wprss_clear_log() {
|
30 |
-
file_put_contents( wprss_log_file(), '' );
|
31 |
-
}
|
32 |
-
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Alias for wprss_clear_log(). Used for code readability.
|
36 |
-
*
|
37 |
-
* @since 3.9.6
|
38 |
-
*/
|
39 |
-
function wprss_reset_log() {
|
40 |
-
wprss_clear_log();
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Gets log level from the database.
|
45 |
-
* @return string The string representing the log level threshold or type.
|
46 |
-
*/
|
47 |
-
function wprss_log_get_level_db() {
|
48 |
-
return wprss_get_general_setting( WPRSS_OPTION_CODE_LOG_LEVEL );
|
49 |
-
}
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Gets log level used.
|
53 |
-
* @return string The string representing the log level threshold.
|
54 |
-
*/
|
55 |
-
function wprss_log_get_level() {
|
56 |
-
$log_level = wprss_log_get_level_db();
|
57 |
-
if ( $log_level === WPRSS_LOG_LEVEL_DEFAULT )
|
58 |
-
$log_level = WPRSS_LOG_LEVEL;
|
59 |
-
|
60 |
-
return apply_filters( 'wprss_log_level', $log_level );
|
61 |
-
}
|
62 |
-
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Check whether or not the specified logging level is the same as, or one of (only for positive),
|
66 |
-
* the currently used logging level.
|
67 |
-
*
|
68 |
-
* @param int $log_level The log level to check. Must be an unsiged whole number.
|
69 |
-
*/
|
70 |
-
function wprss_log_is_level( $log_level, $used_log_level = null ) {
|
71 |
-
$used_log_level = is_null( $used_log_level ) ? wprss_log_get_level() : $used_log_level;
|
72 |
-
|
73 |
-
if( is_numeric( $log_level ) ) {
|
74 |
-
$log_level = intval( $log_level );
|
75 |
-
$used_log_level = intval( $used_log_level );
|
76 |
-
|
77 |
-
return ($log_level > 0 && $used_log_level > 0)
|
78 |
-
// Mostly for the case of 0
|
79 |
-
? intval( $log_level ) & intval( $used_log_level )
|
80 |
-
: $log_level === $used_log_level;
|
81 |
-
}
|
82 |
-
|
83 |
-
return trim( $log_level ) === trim( $used_log_level );
|
84 |
-
}
|
85 |
-
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Check whether or not messages with the specified logging level should be logged.
|
89 |
-
*
|
90 |
-
* @param int $log_level The log level to check. Must be an unsigned whole number
|
91 |
-
* @return bool True if messages with the specified logging level should be logged; false otherwise.
|
92 |
-
*/
|
93 |
-
function wprss_log_is_logging_level( $log_level ) {
|
94 |
-
$original_used_level = $used_log_level = wprss_log_get_level();
|
95 |
-
|
96 |
-
// Whether to use the indicated level and below
|
97 |
-
$is_below = ( substr( $used_log_level, 0, 1 ) === '-' );
|
98 |
-
if ( $is_below )
|
99 |
-
$used_log_level = substr( $used_log_level, 1 );
|
100 |
-
|
101 |
-
if( (int)$used_log_level === WPRSS_LOG_LEVEL_NONE ) {
|
102 |
-
$is_log_level = WPRSS_LOG_LEVEL_NONE;
|
103 |
-
}
|
104 |
-
else {
|
105 |
-
$is_log_level = $is_below
|
106 |
-
? ((int)$log_level <= (int)$used_log_level && (int)$log_level !== WPRSS_LOG_LEVEL_NONE)
|
107 |
-
: wprss_log_is_level( (int)$log_level, $used_log_level );
|
108 |
-
}
|
109 |
-
|
110 |
-
return apply_filters( 'wprss_is_logging_level', $is_log_level, $log_level, $used_log_level, $is_below );
|
111 |
-
}
|
112 |
-
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Get the available log levels.
|
116 |
-
*
|
117 |
-
* @param bool $levels_only Whether or not only numeric actual levels are to be returned.
|
118 |
-
* If false, returns other types as well.
|
119 |
-
* @return array An array, where key is level, and value is level's human-readable name
|
120 |
-
*/
|
121 |
-
function wprss_log_get_levels( $levels_only = true ) {
|
122 |
-
$log_levels = array(
|
123 |
-
WPRSS_LOG_LEVEL_NONE => 'None',
|
124 |
-
WPRSS_LOG_LEVEL_SYSTEM => 'System',
|
125 |
-
WPRSS_LOG_LEVEL_INFO => 'Info',
|
126 |
-
WPRSS_LOG_LEVEL_NOTICE => 'Notice',
|
127 |
-
WPRSS_LOG_LEVEL_WARNING => 'Warning',
|
128 |
-
WPRSS_LOG_LEVEL_ERROR => 'Error'
|
129 |
-
);
|
130 |
-
|
131 |
-
if( !$levels_only )
|
132 |
-
$log_levels[ WPRSS_LOG_LEVEL_DEFAULT ] = 'Default';
|
133 |
-
|
134 |
-
return apply_filters( 'wprss_log_levels', $log_levels, $levels_only );
|
135 |
-
}
|
136 |
-
|
137 |
-
|
138 |
-
/**
|
139 |
-
*
|
140 |
-
* @param string|int $level Any valid level value.
|
141 |
-
* @return string The untranslated label of the specified level, or $default if no such level exists.
|
142 |
-
*/
|
143 |
-
function wprss_log_get_level_label( $level, $default = 'N/A' ) {
|
144 |
-
$levels = wprss_log_get_levels( false );
|
145 |
-
return isset( $levels[$level] ) ? $levels[ $level ] : $default;
|
146 |
-
}
|
147 |
-
|
148 |
-
|
149 |
-
/**
|
150 |
-
* Adds a log entry to the log file.
|
151 |
-
*
|
152 |
-
* @since 3.9.6
|
153 |
-
*/
|
154 |
-
function wprss_log( $message, $src = NULL, $log_level = WPRSS_LOG_LEVEL_ERROR ) {
|
155 |
-
if( !wprss_log_is_logging_level( $log_level ) ) return;
|
156 |
-
|
157 |
-
if ( $src === NULL ) {
|
158 |
-
$callers = debug_backtrace();
|
159 |
-
$src = $callers[1]['function'];
|
160 |
-
if ( $src === 'wprss_log_obj' ) {
|
161 |
-
$src = $callers[2]['function'];
|
162 |
-
}
|
163 |
-
}
|
164 |
-
$log_level_label = wprss_log_get_level_label( $log_level );
|
165 |
-
$date = date( 'd-m-Y H:i:s' );
|
166 |
-
$source = 'WPRSS' . ( ( strlen( $src ) > 0 )? " > $src" : '' ) ;
|
167 |
-
$str = "[$date] [$log_level_label] $source:\n";
|
168 |
-
$str .= "$message\n\n";
|
169 |
-
file_put_contents( wprss_log_file() , $str, FILE_APPEND );
|
170 |
-
|
171 |
-
add_action( 'shutdown', 'wprss_log_separator' );
|
172 |
-
}
|
173 |
-
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Dumps an object to the log file.
|
177 |
-
*
|
178 |
-
* @since 3.9.6
|
179 |
-
*/
|
180 |
-
function wprss_log_obj( $message, $obj, $src = '', $log_level = WPRSS_LOG_LEVEL_ERROR ) {
|
181 |
-
wprss_log( "$message: " . print_r( $obj, TRUE ), $src, $log_level );
|
182 |
-
}
|
183 |
-
|
184 |
-
|
185 |
-
/**
|
186 |
-
* Returns the contents of the log file.
|
187 |
-
*
|
188 |
-
* @since 3.9.6
|
189 |
-
*/
|
190 |
-
function wprss_get_log() {
|
191 |
-
if ( !file_exists( wprss_log_file() ) ) {
|
192 |
-
wprss_clear_log();
|
193 |
-
}
|
194 |
-
$contents = file_get_contents( wprss_log_file() , '' );
|
195 |
-
// Trim the log file to a fixed number of chars
|
196 |
-
$limit = WPRSS_LOG_DISPLAY_LIMIT;
|
197 |
-
if ( strlen( $contents ) > $limit ) {
|
198 |
-
file_put_contents( wprss_log_file(), substr( $contents, 0, $limit ) );
|
199 |
-
return wprss_get_log();
|
200 |
-
} else {
|
201 |
-
return $contents;
|
202 |
-
}
|
203 |
-
}
|
204 |
-
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Adds an empty line at the end of the log file.
|
208 |
-
*
|
209 |
-
* This function is called on wordpress shutdown, if at least one new line
|
210 |
-
* is logged in the log file, to separate logs from different page loads.
|
211 |
-
*
|
212 |
-
* @since 3.9.6
|
213 |
-
*/
|
214 |
-
function wprss_log_separator() {
|
215 |
-
file_put_contents( wprss_log_file(), "\n", FILE_APPEND );
|
216 |
-
}
|
217 |
-
|
218 |
-
|
219 |
-
/**
|
220 |
-
* Adding the default setting value.
|
221 |
-
*/
|
222 |
-
add_filter( 'wprss_default_settings_general', 'wprss_log_default_settings_general' );
|
223 |
-
function wprss_log_default_settings_general( $settings ) {
|
224 |
-
/* @todo Add version info */
|
225 |
-
$settings[ WPRSS_OPTION_CODE_LOG_LEVEL ] = WPRSS_LOG_LEVEL_DEFAULT;
|
226 |
-
return $settings;
|
227 |
-
}
|
228 |
-
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Adding the setting field
|
232 |
-
*/
|
233 |
-
add_filter( 'wprss_settings_array', 'wprss_log_settings_array' );
|
234 |
-
function wprss_log_settings_array( $sections ) {
|
235 |
-
$sections['general'][ WPRSS_OPTION_CODE_LOG_LEVEL ] = array(
|
236 |
-
'label' => __( 'Log level threshold', WPRSS_TEXT_DOMAIN ),
|
237 |
-
'callback' => 'wprss_setting_' . WPRSS_OPTION_CODE_LOG_LEVEL . '_callback'
|
238 |
-
);
|
239 |
-
return $sections;
|
240 |
-
}
|
241 |
-
|
242 |
-
|
243 |
-
/**
|
244 |
-
* Renders the 'log_level' setting field.
|
245 |
-
*
|
246 |
-
* @param array $field Info about the field
|
247 |
-
*/
|
248 |
-
function wprss_setting_log_level_callback( $field ) {
|
249 |
-
$log_level = wprss_get_general_setting( $field['field_id'] );
|
250 |
-
|
251 |
-
foreach( wprss_log_get_levels( false ) as $_level => $_label ) {
|
252 |
-
$options[ $_level ] = $_label;
|
253 |
-
if( is_numeric( $_level ) && ($_level/2 >= 1) ) $options[ (int)$_level * -1 ] = $_label . ' and below';
|
254 |
-
}
|
255 |
-
|
256 |
-
krsort( $options, defined( 'SORT_NATURAL' ) ? SORT_NATURAL : SORT_STRING );
|
257 |
-
?>
|
258 |
-
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[<?php echo $field['field_id'] ?>]">
|
259 |
-
<?php
|
260 |
-
foreach( $options as $value => $text ) {
|
261 |
-
$selected = ( (string)$value === (string)$log_level )? 'selected="selected"' : '';
|
262 |
-
?><option value="<?php echo $value ?>" <?php echo $selected ?>><?php echo __( $text, WPRSS_TEXT_DOMAIN ) ?></option><?php
|
263 |
-
}
|
264 |
-
?>
|
265 |
-
</select>
|
266 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
267 |
-
}
|
268 |
|
1 |
+
<?php
|
2 |
+
|
3 |
+
define( 'WPRSS_LOG_DISPLAY_LIMIT', 100000 ); // Number of chars to display in log
|
4 |
+
define( 'WPRSS_OPTION_CODE_LOG_LEVEL', 'log_level' );
|
5 |
+
define( 'WPRSS_LOG_LEVEL_NONE', 0 );
|
6 |
+
define( 'WPRSS_LOG_LEVEL_SYSTEM', 1 );
|
7 |
+
define( 'WPRSS_LOG_LEVEL_INFO', 2 );
|
8 |
+
define( 'WPRSS_LOG_LEVEL_NOTICE', 4 );
|
9 |
+
define( 'WPRSS_LOG_LEVEL_WARNING', 8 );
|
10 |
+
define( 'WPRSS_LOG_LEVEL_ERROR', 16 );
|
11 |
+
define( 'WPRSS_LOG_LEVEL_DEFAULT', 'default' );
|
12 |
+
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Returns the log file path.
|
16 |
+
*
|
17 |
+
* @since 4.0.4
|
18 |
+
*/
|
19 |
+
function wprss_log_file() {
|
20 |
+
return WPRSS_LOG_FILE . '-' . get_current_blog_id() . WPRSS_LOG_FILE_EXT;
|
21 |
+
}
|
22 |
+
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Clears the log file.
|
26 |
+
*
|
27 |
+
* @since 3.9.6
|
28 |
+
*/
|
29 |
+
function wprss_clear_log() {
|
30 |
+
file_put_contents( wprss_log_file(), '' );
|
31 |
+
}
|
32 |
+
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Alias for wprss_clear_log(). Used for code readability.
|
36 |
+
*
|
37 |
+
* @since 3.9.6
|
38 |
+
*/
|
39 |
+
function wprss_reset_log() {
|
40 |
+
wprss_clear_log();
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Gets log level from the database.
|
45 |
+
* @return string The string representing the log level threshold or type.
|
46 |
+
*/
|
47 |
+
function wprss_log_get_level_db() {
|
48 |
+
return wprss_get_general_setting( WPRSS_OPTION_CODE_LOG_LEVEL );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Gets log level used.
|
53 |
+
* @return string The string representing the log level threshold.
|
54 |
+
*/
|
55 |
+
function wprss_log_get_level() {
|
56 |
+
$log_level = wprss_log_get_level_db();
|
57 |
+
if ( $log_level === WPRSS_LOG_LEVEL_DEFAULT )
|
58 |
+
$log_level = WPRSS_LOG_LEVEL;
|
59 |
+
|
60 |
+
return apply_filters( 'wprss_log_level', $log_level );
|
61 |
+
}
|
62 |
+
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Check whether or not the specified logging level is the same as, or one of (only for positive),
|
66 |
+
* the currently used logging level.
|
67 |
+
*
|
68 |
+
* @param int $log_level The log level to check. Must be an unsiged whole number.
|
69 |
+
*/
|
70 |
+
function wprss_log_is_level( $log_level, $used_log_level = null ) {
|
71 |
+
$used_log_level = is_null( $used_log_level ) ? wprss_log_get_level() : $used_log_level;
|
72 |
+
|
73 |
+
if( is_numeric( $log_level ) ) {
|
74 |
+
$log_level = intval( $log_level );
|
75 |
+
$used_log_level = intval( $used_log_level );
|
76 |
+
|
77 |
+
return ($log_level > 0 && $used_log_level > 0)
|
78 |
+
// Mostly for the case of 0
|
79 |
+
? intval( $log_level ) & intval( $used_log_level )
|
80 |
+
: $log_level === $used_log_level;
|
81 |
+
}
|
82 |
+
|
83 |
+
return trim( $log_level ) === trim( $used_log_level );
|
84 |
+
}
|
85 |
+
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Check whether or not messages with the specified logging level should be logged.
|
89 |
+
*
|
90 |
+
* @param int $log_level The log level to check. Must be an unsigned whole number
|
91 |
+
* @return bool True if messages with the specified logging level should be logged; false otherwise.
|
92 |
+
*/
|
93 |
+
function wprss_log_is_logging_level( $log_level ) {
|
94 |
+
$original_used_level = $used_log_level = wprss_log_get_level();
|
95 |
+
|
96 |
+
// Whether to use the indicated level and below
|
97 |
+
$is_below = ( substr( $used_log_level, 0, 1 ) === '-' );
|
98 |
+
if ( $is_below )
|
99 |
+
$used_log_level = substr( $used_log_level, 1 );
|
100 |
+
|
101 |
+
if( (int)$used_log_level === WPRSS_LOG_LEVEL_NONE ) {
|
102 |
+
$is_log_level = WPRSS_LOG_LEVEL_NONE;
|
103 |
+
}
|
104 |
+
else {
|
105 |
+
$is_log_level = $is_below
|
106 |
+
? ((int)$log_level <= (int)$used_log_level && (int)$log_level !== WPRSS_LOG_LEVEL_NONE)
|
107 |
+
: wprss_log_is_level( (int)$log_level, $used_log_level );
|
108 |
+
}
|
109 |
+
|
110 |
+
return apply_filters( 'wprss_is_logging_level', $is_log_level, $log_level, $used_log_level, $is_below );
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Get the available log levels.
|
116 |
+
*
|
117 |
+
* @param bool $levels_only Whether or not only numeric actual levels are to be returned.
|
118 |
+
* If false, returns other types as well.
|
119 |
+
* @return array An array, where key is level, and value is level's human-readable name
|
120 |
+
*/
|
121 |
+
function wprss_log_get_levels( $levels_only = true ) {
|
122 |
+
$log_levels = array(
|
123 |
+
WPRSS_LOG_LEVEL_NONE => 'None',
|
124 |
+
WPRSS_LOG_LEVEL_SYSTEM => 'System',
|
125 |
+
WPRSS_LOG_LEVEL_INFO => 'Info',
|
126 |
+
WPRSS_LOG_LEVEL_NOTICE => 'Notice',
|
127 |
+
WPRSS_LOG_LEVEL_WARNING => 'Warning',
|
128 |
+
WPRSS_LOG_LEVEL_ERROR => 'Error'
|
129 |
+
);
|
130 |
+
|
131 |
+
if( !$levels_only )
|
132 |
+
$log_levels[ WPRSS_LOG_LEVEL_DEFAULT ] = 'Default';
|
133 |
+
|
134 |
+
return apply_filters( 'wprss_log_levels', $log_levels, $levels_only );
|
135 |
+
}
|
136 |
+
|
137 |
+
|
138 |
+
/**
|
139 |
+
*
|
140 |
+
* @param string|int $level Any valid level value.
|
141 |
+
* @return string The untranslated label of the specified level, or $default if no such level exists.
|
142 |
+
*/
|
143 |
+
function wprss_log_get_level_label( $level, $default = 'N/A' ) {
|
144 |
+
$levels = wprss_log_get_levels( false );
|
145 |
+
return isset( $levels[$level] ) ? $levels[ $level ] : $default;
|
146 |
+
}
|
147 |
+
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Adds a log entry to the log file.
|
151 |
+
*
|
152 |
+
* @since 3.9.6
|
153 |
+
*/
|
154 |
+
function wprss_log( $message, $src = NULL, $log_level = WPRSS_LOG_LEVEL_ERROR ) {
|
155 |
+
if( !wprss_log_is_logging_level( $log_level ) ) return;
|
156 |
+
|
157 |
+
if ( $src === NULL ) {
|
158 |
+
$callers = debug_backtrace();
|
159 |
+
$src = $callers[1]['function'];
|
160 |
+
if ( $src === 'wprss_log_obj' ) {
|
161 |
+
$src = $callers[2]['function'];
|
162 |
+
}
|
163 |
+
}
|
164 |
+
$log_level_label = wprss_log_get_level_label( $log_level );
|
165 |
+
$date = date( 'd-m-Y H:i:s' );
|
166 |
+
$source = 'WPRSS' . ( ( strlen( $src ) > 0 )? " > $src" : '' ) ;
|
167 |
+
$str = "[$date] [$log_level_label] $source:\n";
|
168 |
+
$str .= "$message\n\n";
|
169 |
+
file_put_contents( wprss_log_file() , $str, FILE_APPEND );
|
170 |
+
|
171 |
+
add_action( 'shutdown', 'wprss_log_separator' );
|
172 |
+
}
|
173 |
+
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Dumps an object to the log file.
|
177 |
+
*
|
178 |
+
* @since 3.9.6
|
179 |
+
*/
|
180 |
+
function wprss_log_obj( $message, $obj, $src = '', $log_level = WPRSS_LOG_LEVEL_ERROR ) {
|
181 |
+
wprss_log( "$message: " . print_r( $obj, TRUE ), $src, $log_level );
|
182 |
+
}
|
183 |
+
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Returns the contents of the log file.
|
187 |
+
*
|
188 |
+
* @since 3.9.6
|
189 |
+
*/
|
190 |
+
function wprss_get_log() {
|
191 |
+
if ( !file_exists( wprss_log_file() ) ) {
|
192 |
+
wprss_clear_log();
|
193 |
+
}
|
194 |
+
$contents = file_get_contents( wprss_log_file() , '' );
|
195 |
+
// Trim the log file to a fixed number of chars
|
196 |
+
$limit = WPRSS_LOG_DISPLAY_LIMIT;
|
197 |
+
if ( strlen( $contents ) > $limit ) {
|
198 |
+
file_put_contents( wprss_log_file(), substr( $contents, 0, $limit ) );
|
199 |
+
return wprss_get_log();
|
200 |
+
} else {
|
201 |
+
return $contents;
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Adds an empty line at the end of the log file.
|
208 |
+
*
|
209 |
+
* This function is called on wordpress shutdown, if at least one new line
|
210 |
+
* is logged in the log file, to separate logs from different page loads.
|
211 |
+
*
|
212 |
+
* @since 3.9.6
|
213 |
+
*/
|
214 |
+
function wprss_log_separator() {
|
215 |
+
file_put_contents( wprss_log_file(), "\n", FILE_APPEND );
|
216 |
+
}
|
217 |
+
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Adding the default setting value.
|
221 |
+
*/
|
222 |
+
add_filter( 'wprss_default_settings_general', 'wprss_log_default_settings_general' );
|
223 |
+
function wprss_log_default_settings_general( $settings ) {
|
224 |
+
/* @todo Add version info */
|
225 |
+
$settings[ WPRSS_OPTION_CODE_LOG_LEVEL ] = WPRSS_LOG_LEVEL_DEFAULT;
|
226 |
+
return $settings;
|
227 |
+
}
|
228 |
+
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Adding the setting field
|
232 |
+
*/
|
233 |
+
add_filter( 'wprss_settings_array', 'wprss_log_settings_array' );
|
234 |
+
function wprss_log_settings_array( $sections ) {
|
235 |
+
$sections['general'][ WPRSS_OPTION_CODE_LOG_LEVEL ] = array(
|
236 |
+
'label' => __( 'Log level threshold', WPRSS_TEXT_DOMAIN ),
|
237 |
+
'callback' => 'wprss_setting_' . WPRSS_OPTION_CODE_LOG_LEVEL . '_callback'
|
238 |
+
);
|
239 |
+
return $sections;
|
240 |
+
}
|
241 |
+
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Renders the 'log_level' setting field.
|
245 |
+
*
|
246 |
+
* @param array $field Info about the field
|
247 |
+
*/
|
248 |
+
function wprss_setting_log_level_callback( $field ) {
|
249 |
+
$log_level = wprss_get_general_setting( $field['field_id'] );
|
250 |
+
|
251 |
+
foreach( wprss_log_get_levels( false ) as $_level => $_label ) {
|
252 |
+
$options[ $_level ] = $_label;
|
253 |
+
if( is_numeric( $_level ) && ($_level/2 >= 1) ) $options[ (int)$_level * -1 ] = $_label . ' and below';
|
254 |
+
}
|
255 |
+
|
256 |
+
krsort( $options, defined( 'SORT_NATURAL' ) ? SORT_NATURAL : SORT_STRING );
|
257 |
+
?>
|
258 |
+
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[<?php echo $field['field_id'] ?>]">
|
259 |
+
<?php
|
260 |
+
foreach( $options as $value => $text ) {
|
261 |
+
$selected = ( (string)$value === (string)$log_level )? 'selected="selected"' : '';
|
262 |
+
?><option value="<?php echo $value ?>" <?php echo $selected ?>><?php echo __( $text, WPRSS_TEXT_DOMAIN ) ?></option><?php
|
263 |
+
}
|
264 |
+
?>
|
265 |
+
</select>
|
266 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
267 |
+
}
|
268 |
|
includes/admin-metaboxes.php
CHANGED
@@ -1,665 +1,680 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
add_action( 'add_meta_boxes', 'wprss_add_meta_boxes', 99);
|
4 |
-
/**
|
5 |
-
* Set up the input boxes for the wprss_feed post type
|
6 |
-
*
|
7 |
-
* @since 2.0
|
8 |
-
*/
|
9 |
-
function wprss_add_meta_boxes() {
|
10 |
-
global $wprss_meta_fields;
|
11 |
-
|
12 |
-
// Remove the default WordPress Publish box, because we will be using custom ones
|
13 |
-
remove_meta_box( 'submitdiv', 'wprss_feed', 'side' );
|
14 |
-
|
15 |
-
// Remove some plugin's metaboxes because they're not relevant to the wprss_feed post type.
|
16 |
-
wprss_remove_unrelated_meta_boxes();
|
17 |
-
|
18 |
-
add_meta_box(
|
19 |
-
'submitdiv', // $id
|
20 |
-
__( 'Save Feed Source', WPRSS_TEXT_DOMAIN ), // $title
|
21 |
-
'post_submit_meta_box', // $callback
|
22 |
-
'wprss_feed', // $page
|
23 |
-
'side', // $context
|
24 |
-
'high' // $priority
|
25 |
-
);
|
26 |
-
|
27 |
-
add_meta_box(
|
28 |
-
'preview_meta_box',
|
29 |
-
__( 'Feed Preview', WPRSS_TEXT_DOMAIN ),
|
30 |
-
'wprss_preview_meta_box_callback',
|
31 |
-
'wprss_feed',
|
32 |
-
'side',
|
33 |
-
'high'
|
34 |
-
);
|
35 |
-
|
36 |
-
add_meta_box(
|
37 |
-
'wprss-feed-processing-meta',
|
38 |
-
__( 'Feed Processing', WPRSS_TEXT_DOMAIN ),
|
39 |
-
'wprss_feed_processing_meta_box_callback',
|
40 |
-
'wprss_feed',
|
41 |
-
'side',
|
42 |
-
'high'
|
43 |
-
);
|
44 |
-
|
45 |
-
if ( !defined('WPRSS_FTP_VERSION') && !defined('WPRSS_ET_VERSION') && !defined('WPRSS_C_VERSION') ) {
|
46 |
-
add_meta_box(
|
47 |
-
'wprss-like-meta',
|
48 |
-
__( 'Like This Plugin?', WPRSS_TEXT_DOMAIN ),
|
49 |
-
'wprss_like_meta_box_callback',
|
50 |
-
'wprss_feed',
|
51 |
-
'side',
|
52 |
-
'low'
|
53 |
-
);
|
54 |
-
}
|
55 |
-
|
56 |
-
add_meta_box(
|
57 |
-
'custom_meta_box',
|
58 |
-
__( 'Feed Source Details', WPRSS_TEXT_DOMAIN ),
|
59 |
-
'wprss_show_meta_box_callback',
|
60 |
-
'wprss_feed',
|
61 |
-
'normal',
|
62 |
-
'high'
|
63 |
-
);
|
64 |
-
|
65 |
-
}
|
66 |
-
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Removes some other plugin's metaboxes because they're not relevant to the wprss_feed post type.
|
70 |
-
*
|
71 |
-
* @since 4.7
|
72 |
-
*/
|
73 |
-
function wprss_remove_unrelated_meta_boxes() {
|
74 |
-
$post_type = 'wprss_feed';
|
75 |
-
remove_meta_box( 'wpseo_meta', $post_type, 'normal'); // WP SEO Yoast
|
76 |
-
remove_meta_box( 'ta-reviews-post-meta-box', $post_type, 'normal'); // Author hReview
|
77 |
-
remove_meta_box( 'wpdf_editor_section', $post_type, 'advanced'); // ImageInject
|
78 |
-
}
|
79 |
-
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Set up fields for the meta box for the wprss_feed post type
|
83 |
-
*
|
84 |
-
* @since 2.0
|
85 |
-
*/
|
86 |
-
function wprss_get_custom_fields() {
|
87 |
-
$prefix = 'wprss_';
|
88 |
-
|
89 |
-
// Field Array
|
90 |
-
$wprss_meta_fields[ 'url' ] = array(
|
91 |
-
'label' => __( 'URL', WPRSS_TEXT_DOMAIN ),
|
92 |
-
'id' => $prefix .'url',
|
93 |
-
'type' => 'url',
|
94 |
-
'after' => 'wprss_validate_feed_link',
|
95 |
-
'placeholder' => 'http://'
|
96 |
-
);
|
97 |
-
|
98 |
-
$wprss_meta_fields[ 'limit' ] = array(
|
99 |
-
'label' => __( 'Limit', WPRSS_TEXT_DOMAIN ),
|
100 |
-
'id' => $prefix . 'limit',
|
101 |
-
'type' => 'number'
|
102 |
-
);
|
103 |
-
|
104 |
-
$wprss_meta_fields[ 'enclosure' ] = array(
|
105 |
-
'label' => __( 'Link to enclosure', WPRSS_TEXT_DOMAIN ),
|
106 |
-
'id' => $prefix . 'enclosure',
|
107 |
-
'type' => 'checkbox'
|
108 |
-
);
|
109 |
-
|
110 |
-
// for extensibility, allows more meta fields to be added
|
111 |
-
return apply_filters( 'wprss_fields', $wprss_meta_fields );
|
112 |
-
}
|
113 |
-
|
114 |
-
|
115 |
-
/**
|
116 |
-
* Set up the meta box for the wprss_feed post type
|
117 |
-
*
|
118 |
-
* @since 2.0
|
119 |
-
*/
|
120 |
-
function wprss_show_meta_box_callback() {
|
121 |
-
global $post;
|
122 |
-
$meta_fields = wprss_get_custom_fields();
|
123 |
-
$field_tooltip_id_prefix = 'field_';
|
124 |
-
$help = WPRSS_Help::get_instance();
|
125 |
-
|
126 |
-
// Use nonce for verification
|
127 |
-
wp_nonce_field( basename( __FILE__ ), 'wprss_meta_box_nonce' );
|
128 |
-
|
129 |
-
// Fix for WordpRess SEO JS issue
|
130 |
-
?><input type="hidden" id="content" value="" /><?php
|
131 |
-
|
132 |
-
// Begin the field table and loop
|
133 |
-
?><table class="form-table wprss-form-table"><?php
|
134 |
-
|
135 |
-
foreach ( $meta_fields as $field ) {
|
136 |
-
// get value of this field if it exists for this post
|
137 |
-
$meta = get_post_meta( $post->ID, $field['id'], true );
|
138 |
-
// begin a table row with
|
139 |
-
?><tr>
|
140 |
-
<th><label for="<?php echo $field['id'] ?>"><?php echo $field['label'] /* Should be already translated */ ?></label></th>
|
141 |
-
<td><?php
|
142 |
-
|
143 |
-
if ( isset( $field['before'] ) && !empty( $field['before'] ) ) {
|
144 |
-
call_user_func( $field['before'] );
|
145 |
-
}
|
146 |
-
|
147 |
-
// Add default placeholder value
|
148 |
-
$field = wp_parse_args( $field, array(
|
149 |
-
'desc' => '',
|
150 |
-
'placeholder' => '',
|
151 |
-
'type' => 'text'
|
152 |
-
) );
|
153 |
-
|
154 |
-
$tooltip = isset( $field['tooltip'] ) ? trim( $field['tooltip'] ) : null;
|
155 |
-
$tooltip_id = isset( $field['id'] ) ? $field_tooltip_id_prefix . $field['id'] : uniqid( $field_tooltip_id_prefix );
|
156 |
-
|
157 |
-
$field_description = __( $field['desc'], WPRSS_TEXT_DOMAIN );
|
158 |
-
|
159 |
-
/*
|
160 |
-
* So, here's how tooltips work here.
|
161 |
-
* Tooltip output will be attempted in any case.
|
162 |
-
* If 'tooltip' index is not defined, or is null, then
|
163 |
-
* a registered tooltip will be attempted. If that is
|
164 |
-
* not found, default value will be output. This value
|
165 |
-
* is by default an empty string, but can be altered
|
166 |
-
* by the `tooltip_not_found_handle_html` option of `WPRSS_Help`.
|
167 |
-
*/
|
168 |
-
|
169 |
-
switch( $field['type'] ) {
|
170 |
-
|
171 |
-
// text/url
|
172 |
-
case 'url':
|
173 |
-
case 'text':
|
174 |
-
?><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
|
175 |
-
echo $help->tooltip( $tooltip_id, $tooltip );
|
176 |
-
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
177 |
-
?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php _e( $field['desc'], WPRSS_TEXT_DOMAIN ) ?></span></label><?php
|
178 |
-
}
|
179 |
-
break;
|
180 |
-
|
181 |
-
// textarea
|
182 |
-
case 'textarea':
|
183 |
-
?><textarea name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" cols="60" rows="4"><?php echo esc_attr( $meta ) ?></textarea><?php
|
184 |
-
echo $help->tooltip( $tooltip_id, $tooltip );
|
185 |
-
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
186 |
-
?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
187 |
-
}
|
188 |
-
break;
|
189 |
-
|
190 |
-
// checkbox
|
191 |
-
case 'checkbox':
|
192 |
-
?>
|
193 |
-
<input type="hidden" name="<?php echo $field['id'] ?>" value="false" />
|
194 |
-
<input type="checkbox" name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" value="true" <?php checked( $meta, 'true' ) ?> /><?php
|
195 |
-
echo $help->tooltip( $tooltip_id, $tooltip );
|
196 |
-
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
197 |
-
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
198 |
-
}
|
199 |
-
break;
|
200 |
-
|
201 |
-
// select
|
202 |
-
case 'select':
|
203 |
-
?><select name="<?php echo $field['id'] ?>" id="<?php $field['id'] ?>"><?php
|
204 |
-
foreach ($field['options'] as $option) {
|
205 |
-
?><option<?php if ( $meta == $option['value'] ): ?> selected="selected"<?php endif ?> value="<?php echo $option['value'] ?>"><?php echo $option['label'] ?></option><?php
|
206 |
-
}
|
207 |
-
|
208 |
-
?></select><?php
|
209 |
-
echo $help->tooltip( $tooltip_id, $tooltip );
|
210 |
-
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
211 |
-
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
212 |
-
}
|
213 |
-
break;
|
214 |
-
|
215 |
-
// number
|
216 |
-
case 'number':
|
217 |
-
?><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
|
218 |
-
echo $help->tooltip( $tooltip_id, $tooltip );
|
219 |
-
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
220 |
-
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
221 |
-
}
|
222 |
-
break;
|
223 |
-
|
224 |
-
} //end switch
|
225 |
-
|
226 |
-
if ( isset( $field['after'] ) && !empty( $field['after'] ) ) {
|
227 |
-
call_user_func( $field['after'] );
|
228 |
-
}
|
229 |
-
|
230 |
-
?></td></tr><?php
|
231 |
-
} // end foreach
|
232 |
-
?></table><?php
|
233 |
-
}
|
234 |
-
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Adds the link that validates the feed
|
238 |
-
* @since 3.9.5
|
239 |
-
*/
|
240 |
-
function wprss_validate_feed_link() {
|
241 |
-
?>
|
242 |
-
<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>
|
243 |
-
<div id="wprss-url-error" style="color:red"></div>
|
244 |
-
<a href="#" id="validate-feed-link">Validate feed</a>
|
245 |
-
<script type="text/javascript">
|
246 |
-
(function($){
|
247 |
-
// When the DOM is ready
|
248 |
-
$(document).ready( function(){
|
249 |
-
// Move the link immediately after the url text field, and add the click event handler
|
250 |
-
$('#validate-feed-link').click(function(e){
|
251 |
-
// Get the url and proceed only if the url is not empty
|
252 |
-
var url = $('#wprss_url').val();
|
253 |
-
if ( url.trim().length > 0 ) {
|
254 |
-
// Encode the url and generate the full url to the w3 feed validator
|
255 |
-
var encodedUrl = encodeURIComponent( url );
|
256 |
-
var fullURL = 'http://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
|
257 |
-
// Open the window / tab
|
258 |
-
window.open( fullURL, 'wprss-feed-validator' );
|
259 |
-
}
|
260 |
-
// Suppress the default link click behaviour
|
261 |
-
e.preventDefault();
|
262 |
-
e.stopPropagation();
|
263 |
-
return false;
|
264 |
-
});
|
265 |
-
});
|
266 |
-
})(jQuery);
|
267 |
-
</script>
|
268 |
-
<?php
|
269 |
-
}
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
add_action( 'save_post', 'wprss_save_custom_fields', 10, 2 );
|
274 |
-
/**
|
275 |
-
* Save the custom fields
|
276 |
-
*
|
277 |
-
* @since 2.0
|
278 |
-
*/
|
279 |
-
function wprss_save_custom_fields( $post_id, $post ) {
|
280 |
-
$meta_fields = wprss_get_custom_fields();
|
281 |
-
|
282 |
-
/* Verify the nonce before proceeding. */
|
283 |
-
if ( !isset( $_POST['wprss_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['wprss_meta_box_nonce'], basename( __FILE__ ) ) )
|
284 |
-
return $post_id;
|
285 |
-
|
286 |
-
/* Get the post type object. */
|
287 |
-
$post_type = get_post_type_object( $post->post_type );
|
288 |
-
|
289 |
-
/* Check if the current user has permission to edit the post. */
|
290 |
-
if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
|
291 |
-
return $post_id;
|
292 |
-
|
293 |
-
/* // Stop WP from clearing custom fields on autosave - maybe not needed
|
294 |
-
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
|
295 |
-
return;
|
296 |
-
|
297 |
-
// Prevent quick edit from clearing custom fields - maybe not needed
|
298 |
-
if (defined('DOING_AJAX') && DOING_AJAX)
|
299 |
-
return; */
|
300 |
-
|
301 |
-
/** Bail out if running an autosave, ajax or a cron */
|
302 |
-
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
|
303 |
-
return;
|
304 |
-
if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
|
305 |
-
return;
|
306 |
-
if ( defined( 'DOING_CRON' ) && DOING_CRON )
|
307 |
-
return;
|
308 |
-
|
309 |
-
// Change the limit, if it is zero, to an empty string
|
310 |
-
if ( isset( $_POST['wprss_limit'] ) && strval( $_POST['wprss_limit'] ) == '0' ) {
|
311 |
-
$_POST['wprss_limit'] = '';
|
312 |
-
}
|
313 |
-
|
314 |
-
// loop through fields and save the data
|
315 |
-
foreach ( $meta_fields as $field ) {
|
316 |
-
$old = get_post_meta( $post_id, $field[ 'id' ], true );
|
317 |
-
$new = trim( $_POST[ $field[ 'id' ] ] );
|
318 |
-
if ( $new && $new != $old ) {
|
319 |
-
update_post_meta( $post_id, $field[ 'id' ], $new );
|
320 |
-
} elseif ( '' == $new && $old ) {
|
321 |
-
delete_post_meta( $post_id, $field[ 'id' ], $old );
|
322 |
-
}
|
323 |
-
} // end foreach
|
324 |
-
|
325 |
-
$force_feed = ( isset( $_POST['wprss_force_feed'] ) )? $_POST['wprss_force_feed'] : 'false';
|
326 |
-
$state = ( isset( $_POST['wprss_state'] ) )? $_POST['wprss_state'] : 'active';
|
327 |
-
$activate = ( isset( $_POST['wprss_activate_feed'] ) )? stripslashes( $_POST['wprss_activate_feed'] ) : '';
|
328 |
-
$pause = ( isset( $_POST['wprss_pause_feed'] ) )? stripslashes( $_POST['wprss_pause_feed'] ) : '';
|
329 |
-
$age_limit = ( isset( $_POST['wprss_age_limit'] ) )? stripslashes( $_POST['wprss_age_limit'] ) : '';
|
330 |
-
$age_unit = ( isset( $_POST['wprss_age_unit'] ) )? stripslashes( $_POST['wprss_age_unit'] ) : '';
|
331 |
-
$update_interval = ( isset( $_POST['wprss_update_interval'] ) )? stripslashes( $_POST['wprss_update_interval'] ) : wprss_get_default_feed_source_update_interval();
|
332 |
-
$old_update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
|
333 |
-
|
334 |
-
// Update the feed source meta
|
335 |
-
update_post_meta( $post_id, 'wprss_force_feed', $force_feed );
|
336 |
-
update_post_meta( $post_id, 'wprss_activate_feed', $activate );
|
337 |
-
update_post_meta( $post_id, 'wprss_pause_feed', $pause );
|
338 |
-
update_post_meta( $post_id, 'wprss_age_limit', $age_limit );
|
339 |
-
update_post_meta( $post_id, 'wprss_age_unit', $age_unit );
|
340 |
-
update_post_meta( $post_id, 'wprss_update_interval', $update_interval );
|
341 |
-
|
342 |
-
// Check if the state or the update interval has changed
|
343 |
-
if ( get_post_meta( $post_id, 'wprss_state', TRUE ) !== $state || $old_update_interval !== $update_interval ) {
|
344 |
-
// Pause the feed source, and if it is active, re-activate it.
|
345 |
-
// This should update the feed's scheduling
|
346 |
-
wprss_pause_feed_source( $post_id );
|
347 |
-
if ( $state === 'active' )
|
348 |
-
wprss_activate_feed_source( $post_id );
|
349 |
-
}
|
350 |
-
|
351 |
-
// Update the schedules
|
352 |
-
wprss_update_feed_processing_schedules( $post_id );
|
353 |
-
|
354 |
-
// If the feed source uses the global updating system, update the feed on publish
|
355 |
-
if ( $update_interval === wprss_get_default_feed_source_update_interval() ) {
|
356 |
-
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
|
357 |
-
}
|
358 |
-
}
|
359 |
-
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Generate a preview of the latest 5 posts from the feed source being added/edited
|
363 |
-
*
|
364 |
-
* @since 2.0
|
365 |
-
*/
|
366 |
-
function wprss_preview_meta_box_callback() {
|
367 |
-
global $post;
|
368 |
-
$feed_url = get_post_meta( $post->ID, 'wprss_url', true );
|
369 |
-
|
370 |
-
$help = WPRSS_Help::get_instance();
|
371 |
-
/* @var $help WPRSS_Help */
|
372 |
-
|
373 |
-
if ( ! empty( $feed_url ) ) {
|
374 |
-
$feed = wprss_fetch_feed( $feed_url, $post->ID );
|
375 |
-
if ( ! is_wp_error( $feed ) ) {
|
376 |
-
$items = $feed->get_items();
|
377 |
-
// Figure out how many total items there are
|
378 |
-
$total = $feed->get_item_quantity();
|
379 |
-
// Get the number of items again, but limit it to 5.
|
380 |
-
$maxitems = $feed->get_item_quantity(5);
|
381 |
-
|
382 |
-
// Build an array of all the items, starting with element 0 (first element).
|
383 |
-
$items = $feed->get_items( 0, $maxitems );
|
384 |
-
?>
|
385 |
-
<h4><?php echo sprintf( __( 'Latest %1$s feed items out of %2$s available from %3$s' ), $maxitems, $total, get_the_title() ) ?></h4>
|
386 |
-
<ul>
|
387 |
-
<?php
|
388 |
-
foreach ( $items as $item ) {
|
389 |
-
// Get human date (comment if you want to use non human date)
|
390 |
-
$has_date = $item->get_date( 'U' ) ? TRUE : FALSE;
|
391 |
-
if ( $has_date ) {
|
392 |
-
$item_date = human_time_diff( $item->get_date('U'), current_time('timestamp')).' '.__( 'ago', 'rc_mdm' );
|
393 |
-
} else {
|
394 |
-
$item_date = '<em>[' . __( 'No Date', WPRSS_TEXT_DOMAIN ) . ']</em>';
|
395 |
-
}
|
396 |
-
// Start displaying item content within a <li> tag
|
397 |
-
echo '<li>';
|
398 |
-
// create item link
|
399 |
-
//echo '<a href="'.esc_url( $item->get_permalink() ).'" title="'.$item_date.'">';
|
400 |
-
// Get item title
|
401 |
-
echo esc_html( $item->get_title() );
|
402 |
-
//echo '</a>';
|
403 |
-
// Display date
|
404 |
-
echo ' <div class="rss-date"><small>'.$item_date.'</small></div>';
|
405 |
-
// End <li> tag
|
406 |
-
echo '</li>';
|
407 |
-
}
|
408 |
-
?>
|
409 |
-
</ul>
|
410 |
-
<?php
|
411 |
-
}
|
412 |
-
else {
|
413 |
-
?>
|
414 |
-
<span class="invalid-feed-url">
|
415 |
-
<?php _e( '<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', WPRSS_TEXT_DOMAIN ) ?>
|
416 |
-
<?php wprss_log_obj( 'Failed to preview feed.', $feed->get_error_message(), NULL, WPRSS_LOG_LEVEL_INFO ); ?>
|
417 |
-
</span>
|
418 |
-
<?php
|
419 |
-
echo wpautop( sprintf( __( '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_TEXT_DOMAIN ), 'http://webtrends.about.com/od/webfeedsyndicationrss/ss/rss_howto.htm' ) );
|
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 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
$
|
463 |
-
|
464 |
-
|
465 |
-
$
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
$
|
473 |
-
$
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
<
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
</div>
|
514 |
-
|
515 |
-
<div class="wprss-meta-side-setting">
|
516 |
-
<p>
|
517 |
-
<label for="">
|
518 |
-
<strong id="wprss-
|
519 |
-
<a href="#">Edit</a>
|
520 |
-
<?php echo $help->tooltip( '
|
521 |
-
</p>
|
522 |
-
<div class="wprss-meta-slider" data-collapse-viewer="wprss-
|
523 |
-
<input id="
|
524 |
-
<span class="description">
|
525 |
-
Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
|
526 |
-
</span>
|
527 |
-
</div>
|
528 |
-
</div>
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
<
|
534 |
-
<
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
<
|
548 |
-
<
|
549 |
-
|
550 |
-
<?php
|
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 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
*
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
<li
|
636 |
-
|
637 |
-
|
638 |
-
<?php }
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
*
|
644 |
-
*
|
645 |
-
*
|
646 |
-
*/
|
647 |
-
function
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
add_action( 'add_meta_boxes', 'wprss_add_meta_boxes', 99);
|
4 |
+
/**
|
5 |
+
* Set up the input boxes for the wprss_feed post type
|
6 |
+
*
|
7 |
+
* @since 2.0
|
8 |
+
*/
|
9 |
+
function wprss_add_meta_boxes() {
|
10 |
+
global $wprss_meta_fields;
|
11 |
+
|
12 |
+
// Remove the default WordPress Publish box, because we will be using custom ones
|
13 |
+
remove_meta_box( 'submitdiv', 'wprss_feed', 'side' );
|
14 |
+
|
15 |
+
// Remove some plugin's metaboxes because they're not relevant to the wprss_feed post type.
|
16 |
+
wprss_remove_unrelated_meta_boxes();
|
17 |
+
|
18 |
+
add_meta_box(
|
19 |
+
'submitdiv', // $id
|
20 |
+
__( 'Save Feed Source', WPRSS_TEXT_DOMAIN ), // $title
|
21 |
+
'post_submit_meta_box', // $callback
|
22 |
+
'wprss_feed', // $page
|
23 |
+
'side', // $context
|
24 |
+
'high' // $priority
|
25 |
+
);
|
26 |
+
|
27 |
+
add_meta_box(
|
28 |
+
'preview_meta_box',
|
29 |
+
__( 'Feed Preview', WPRSS_TEXT_DOMAIN ),
|
30 |
+
'wprss_preview_meta_box_callback',
|
31 |
+
'wprss_feed',
|
32 |
+
'side',
|
33 |
+
'high'
|
34 |
+
);
|
35 |
+
|
36 |
+
add_meta_box(
|
37 |
+
'wprss-feed-processing-meta',
|
38 |
+
__( 'Feed Processing', WPRSS_TEXT_DOMAIN ),
|
39 |
+
'wprss_feed_processing_meta_box_callback',
|
40 |
+
'wprss_feed',
|
41 |
+
'side',
|
42 |
+
'high'
|
43 |
+
);
|
44 |
+
|
45 |
+
if ( !defined('WPRSS_FTP_VERSION') && !defined('WPRSS_ET_VERSION') && !defined('WPRSS_C_VERSION') ) {
|
46 |
+
add_meta_box(
|
47 |
+
'wprss-like-meta',
|
48 |
+
__( 'Like This Plugin?', WPRSS_TEXT_DOMAIN ),
|
49 |
+
'wprss_like_meta_box_callback',
|
50 |
+
'wprss_feed',
|
51 |
+
'side',
|
52 |
+
'low'
|
53 |
+
);
|
54 |
+
}
|
55 |
+
|
56 |
+
add_meta_box(
|
57 |
+
'custom_meta_box',
|
58 |
+
__( 'Feed Source Details', WPRSS_TEXT_DOMAIN ),
|
59 |
+
'wprss_show_meta_box_callback',
|
60 |
+
'wprss_feed',
|
61 |
+
'normal',
|
62 |
+
'high'
|
63 |
+
);
|
64 |
+
|
65 |
+
}
|
66 |
+
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Removes some other plugin's metaboxes because they're not relevant to the wprss_feed post type.
|
70 |
+
*
|
71 |
+
* @since 4.7
|
72 |
+
*/
|
73 |
+
function wprss_remove_unrelated_meta_boxes() {
|
74 |
+
$post_type = 'wprss_feed';
|
75 |
+
remove_meta_box( 'wpseo_meta', $post_type, 'normal'); // WP SEO Yoast
|
76 |
+
remove_meta_box( 'ta-reviews-post-meta-box', $post_type, 'normal'); // Author hReview
|
77 |
+
remove_meta_box( 'wpdf_editor_section', $post_type, 'advanced'); // ImageInject
|
78 |
+
}
|
79 |
+
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Set up fields for the meta box for the wprss_feed post type
|
83 |
+
*
|
84 |
+
* @since 2.0
|
85 |
+
*/
|
86 |
+
function wprss_get_custom_fields() {
|
87 |
+
$prefix = 'wprss_';
|
88 |
+
|
89 |
+
// Field Array
|
90 |
+
$wprss_meta_fields[ 'url' ] = array(
|
91 |
+
'label' => __( 'URL', WPRSS_TEXT_DOMAIN ),
|
92 |
+
'id' => $prefix .'url',
|
93 |
+
'type' => 'url',
|
94 |
+
'after' => 'wprss_validate_feed_link',
|
95 |
+
'placeholder' => 'http://'
|
96 |
+
);
|
97 |
+
|
98 |
+
$wprss_meta_fields[ 'limit' ] = array(
|
99 |
+
'label' => __( 'Limit', WPRSS_TEXT_DOMAIN ),
|
100 |
+
'id' => $prefix . 'limit',
|
101 |
+
'type' => 'number'
|
102 |
+
);
|
103 |
+
|
104 |
+
$wprss_meta_fields[ 'enclosure' ] = array(
|
105 |
+
'label' => __( 'Link to enclosure', WPRSS_TEXT_DOMAIN ),
|
106 |
+
'id' => $prefix . 'enclosure',
|
107 |
+
'type' => 'checkbox'
|
108 |
+
);
|
109 |
+
|
110 |
+
// for extensibility, allows more meta fields to be added
|
111 |
+
return apply_filters( 'wprss_fields', $wprss_meta_fields );
|
112 |
+
}
|
113 |
+
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Set up the meta box for the wprss_feed post type
|
117 |
+
*
|
118 |
+
* @since 2.0
|
119 |
+
*/
|
120 |
+
function wprss_show_meta_box_callback() {
|
121 |
+
global $post;
|
122 |
+
$meta_fields = wprss_get_custom_fields();
|
123 |
+
$field_tooltip_id_prefix = 'field_';
|
124 |
+
$help = WPRSS_Help::get_instance();
|
125 |
+
|
126 |
+
// Use nonce for verification
|
127 |
+
wp_nonce_field( basename( __FILE__ ), 'wprss_meta_box_nonce' );
|
128 |
+
|
129 |
+
// Fix for WordpRess SEO JS issue
|
130 |
+
?><input type="hidden" id="content" value="" /><?php
|
131 |
+
|
132 |
+
// Begin the field table and loop
|
133 |
+
?><table class="form-table wprss-form-table"><?php
|
134 |
+
|
135 |
+
foreach ( $meta_fields as $field ) {
|
136 |
+
// get value of this field if it exists for this post
|
137 |
+
$meta = get_post_meta( $post->ID, $field['id'], true );
|
138 |
+
// begin a table row with
|
139 |
+
?><tr>
|
140 |
+
<th><label for="<?php echo $field['id'] ?>"><?php echo $field['label'] /* Should be already translated */ ?></label></th>
|
141 |
+
<td><?php
|
142 |
+
|
143 |
+
if ( isset( $field['before'] ) && !empty( $field['before'] ) ) {
|
144 |
+
call_user_func( $field['before'] );
|
145 |
+
}
|
146 |
+
|
147 |
+
// Add default placeholder value
|
148 |
+
$field = wp_parse_args( $field, array(
|
149 |
+
'desc' => '',
|
150 |
+
'placeholder' => '',
|
151 |
+
'type' => 'text'
|
152 |
+
) );
|
153 |
+
|
154 |
+
$tooltip = isset( $field['tooltip'] ) ? trim( $field['tooltip'] ) : null;
|
155 |
+
$tooltip_id = isset( $field['id'] ) ? $field_tooltip_id_prefix . $field['id'] : uniqid( $field_tooltip_id_prefix );
|
156 |
+
|
157 |
+
$field_description = __( $field['desc'], WPRSS_TEXT_DOMAIN );
|
158 |
+
|
159 |
+
/*
|
160 |
+
* So, here's how tooltips work here.
|
161 |
+
* Tooltip output will be attempted in any case.
|
162 |
+
* If 'tooltip' index is not defined, or is null, then
|
163 |
+
* a registered tooltip will be attempted. If that is
|
164 |
+
* not found, default value will be output. This value
|
165 |
+
* is by default an empty string, but can be altered
|
166 |
+
* by the `tooltip_not_found_handle_html` option of `WPRSS_Help`.
|
167 |
+
*/
|
168 |
+
|
169 |
+
switch( $field['type'] ) {
|
170 |
+
|
171 |
+
// text/url
|
172 |
+
case 'url':
|
173 |
+
case 'text':
|
174 |
+
?><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
|
175 |
+
echo $help->tooltip( $tooltip_id, $tooltip );
|
176 |
+
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
177 |
+
?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php _e( $field['desc'], WPRSS_TEXT_DOMAIN ) ?></span></label><?php
|
178 |
+
}
|
179 |
+
break;
|
180 |
+
|
181 |
+
// textarea
|
182 |
+
case 'textarea':
|
183 |
+
?><textarea name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" cols="60" rows="4"><?php echo esc_attr( $meta ) ?></textarea><?php
|
184 |
+
echo $help->tooltip( $tooltip_id, $tooltip );
|
185 |
+
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
186 |
+
?><br /><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
187 |
+
}
|
188 |
+
break;
|
189 |
+
|
190 |
+
// checkbox
|
191 |
+
case 'checkbox':
|
192 |
+
?>
|
193 |
+
<input type="hidden" name="<?php echo $field['id'] ?>" value="false" />
|
194 |
+
<input type="checkbox" name="<?php echo $field['id'] ?>" id="<?php echo $field['id'] ?>" value="true" <?php checked( $meta, 'true' ) ?> /><?php
|
195 |
+
echo $help->tooltip( $tooltip_id, $tooltip );
|
196 |
+
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
197 |
+
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
198 |
+
}
|
199 |
+
break;
|
200 |
+
|
201 |
+
// select
|
202 |
+
case 'select':
|
203 |
+
?><select name="<?php echo $field['id'] ?>" id="<?php $field['id'] ?>"><?php
|
204 |
+
foreach ($field['options'] as $option) {
|
205 |
+
?><option<?php if ( $meta == $option['value'] ): ?> selected="selected"<?php endif ?> value="<?php echo $option['value'] ?>"><?php echo $option['label'] ?></option><?php
|
206 |
+
}
|
207 |
+
|
208 |
+
?></select><?php
|
209 |
+
echo $help->tooltip( $tooltip_id, $tooltip );
|
210 |
+
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
211 |
+
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
212 |
+
}
|
213 |
+
break;
|
214 |
+
|
215 |
+
// number
|
216 |
+
case 'number':
|
217 |
+
?><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
|
218 |
+
echo $help->tooltip( $tooltip_id, $tooltip );
|
219 |
+
if ( strlen( trim( $field['desc'] ) ) > 0 ) {
|
220 |
+
?><label for="<?php echo $field['id'] ?>"><span class="description"><?php echo $field_description ?></span></label><?php
|
221 |
+
}
|
222 |
+
break;
|
223 |
+
|
224 |
+
} //end switch
|
225 |
+
|
226 |
+
if ( isset( $field['after'] ) && !empty( $field['after'] ) ) {
|
227 |
+
call_user_func( $field['after'] );
|
228 |
+
}
|
229 |
+
|
230 |
+
?></td></tr><?php
|
231 |
+
} // end foreach
|
232 |
+
?></table><?php
|
233 |
+
}
|
234 |
+
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Adds the link that validates the feed
|
238 |
+
* @since 3.9.5
|
239 |
+
*/
|
240 |
+
function wprss_validate_feed_link() {
|
241 |
+
?>
|
242 |
+
<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>
|
243 |
+
<div id="wprss-url-error" style="color:red"></div>
|
244 |
+
<a href="#" id="validate-feed-link">Validate feed</a>
|
245 |
+
<script type="text/javascript">
|
246 |
+
(function($){
|
247 |
+
// When the DOM is ready
|
248 |
+
$(document).ready( function(){
|
249 |
+
// Move the link immediately after the url text field, and add the click event handler
|
250 |
+
$('#validate-feed-link').click(function(e){
|
251 |
+
// Get the url and proceed only if the url is not empty
|
252 |
+
var url = $('#wprss_url').val();
|
253 |
+
if ( url.trim().length > 0 ) {
|
254 |
+
// Encode the url and generate the full url to the w3 feed validator
|
255 |
+
var encodedUrl = encodeURIComponent( url );
|
256 |
+
var fullURL = 'http://validator.w3.org/feed/check.cgi?url=' + encodedUrl;
|
257 |
+
// Open the window / tab
|
258 |
+
window.open( fullURL, 'wprss-feed-validator' );
|
259 |
+
}
|
260 |
+
// Suppress the default link click behaviour
|
261 |
+
e.preventDefault();
|
262 |
+
e.stopPropagation();
|
263 |
+
return false;
|
264 |
+
});
|
265 |
+
});
|
266 |
+
})(jQuery);
|
267 |
+
</script>
|
268 |
+
<?php
|
269 |
+
}
|
270 |
+
|
271 |
+
|
272 |
+
|
273 |
+
add_action( 'save_post', 'wprss_save_custom_fields', 10, 2 );
|
274 |
+
/**
|
275 |
+
* Save the custom fields
|
276 |
+
*
|
277 |
+
* @since 2.0
|
278 |
+
*/
|
279 |
+
function wprss_save_custom_fields( $post_id, $post ) {
|
280 |
+
$meta_fields = wprss_get_custom_fields();
|
281 |
+
|
282 |
+
/* Verify the nonce before proceeding. */
|
283 |
+
if ( !isset( $_POST['wprss_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['wprss_meta_box_nonce'], basename( __FILE__ ) ) )
|
284 |
+
return $post_id;
|
285 |
+
|
286 |
+
/* Get the post type object. */
|
287 |
+
$post_type = get_post_type_object( $post->post_type );
|
288 |
+
|
289 |
+
/* Check if the current user has permission to edit the post. */
|
290 |
+
if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
|
291 |
+
return $post_id;
|
292 |
+
|
293 |
+
/* // Stop WP from clearing custom fields on autosave - maybe not needed
|
294 |
+
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
|
295 |
+
return;
|
296 |
+
|
297 |
+
// Prevent quick edit from clearing custom fields - maybe not needed
|
298 |
+
if (defined('DOING_AJAX') && DOING_AJAX)
|
299 |
+
return; */
|
300 |
+
|
301 |
+
/** Bail out if running an autosave, ajax or a cron */
|
302 |
+
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
|
303 |
+
return;
|
304 |
+
if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
|
305 |
+
return;
|
306 |
+
if ( defined( 'DOING_CRON' ) && DOING_CRON )
|
307 |
+
return;
|
308 |
+
|
309 |
+
// Change the limit, if it is zero, to an empty string
|
310 |
+
if ( isset( $_POST['wprss_limit'] ) && strval( $_POST['wprss_limit'] ) == '0' ) {
|
311 |
+
$_POST['wprss_limit'] = '';
|
312 |
+
}
|
313 |
+
|
314 |
+
// loop through fields and save the data
|
315 |
+
foreach ( $meta_fields as $field ) {
|
316 |
+
$old = get_post_meta( $post_id, $field[ 'id' ], true );
|
317 |
+
$new = trim( $_POST[ $field[ 'id' ] ] );
|
318 |
+
if ( $new && $new != $old ) {
|
319 |
+
update_post_meta( $post_id, $field[ 'id' ], $new );
|
320 |
+
} elseif ( '' == $new && $old ) {
|
321 |
+
delete_post_meta( $post_id, $field[ 'id' ], $old );
|
322 |
+
}
|
323 |
+
} // end foreach
|
324 |
+
|
325 |
+
$force_feed = ( isset( $_POST['wprss_force_feed'] ) )? $_POST['wprss_force_feed'] : 'false';
|
326 |
+
$state = ( isset( $_POST['wprss_state'] ) )? $_POST['wprss_state'] : 'active';
|
327 |
+
$activate = ( isset( $_POST['wprss_activate_feed'] ) )? stripslashes( $_POST['wprss_activate_feed'] ) : '';
|
328 |
+
$pause = ( isset( $_POST['wprss_pause_feed'] ) )? stripslashes( $_POST['wprss_pause_feed'] ) : '';
|
329 |
+
$age_limit = ( isset( $_POST['wprss_age_limit'] ) )? stripslashes( $_POST['wprss_age_limit'] ) : '';
|
330 |
+
$age_unit = ( isset( $_POST['wprss_age_unit'] ) )? stripslashes( $_POST['wprss_age_unit'] ) : '';
|
331 |
+
$update_interval = ( isset( $_POST['wprss_update_interval'] ) )? stripslashes( $_POST['wprss_update_interval'] ) : wprss_get_default_feed_source_update_interval();
|
332 |
+
$old_update_interval = get_post_meta( $post_id, 'wprss_update_interval', TRUE );
|
333 |
+
|
334 |
+
// Update the feed source meta
|
335 |
+
update_post_meta( $post_id, 'wprss_force_feed', $force_feed );
|
336 |
+
update_post_meta( $post_id, 'wprss_activate_feed', $activate );
|
337 |
+
update_post_meta( $post_id, 'wprss_pause_feed', $pause );
|
338 |
+
update_post_meta( $post_id, 'wprss_age_limit', $age_limit );
|
339 |
+
update_post_meta( $post_id, 'wprss_age_unit', $age_unit );
|
340 |
+
update_post_meta( $post_id, 'wprss_update_interval', $update_interval );
|
341 |
+
|
342 |
+
// Check if the state or the update interval has changed
|
343 |
+
if ( get_post_meta( $post_id, 'wprss_state', TRUE ) !== $state || $old_update_interval !== $update_interval ) {
|
344 |
+
// Pause the feed source, and if it is active, re-activate it.
|
345 |
+
// This should update the feed's scheduling
|
346 |
+
wprss_pause_feed_source( $post_id );
|
347 |
+
if ( $state === 'active' )
|
348 |
+
wprss_activate_feed_source( $post_id );
|
349 |
+
}
|
350 |
+
|
351 |
+
// Update the schedules
|
352 |
+
wprss_update_feed_processing_schedules( $post_id );
|
353 |
+
|
354 |
+
// If the feed source uses the global updating system, update the feed on publish
|
355 |
+
if ( $update_interval === wprss_get_default_feed_source_update_interval() ) {
|
356 |
+
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
|
357 |
+
}
|
358 |
+
}
|
359 |
+
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Generate a preview of the latest 5 posts from the feed source being added/edited
|
363 |
+
*
|
364 |
+
* @since 2.0
|
365 |
+
*/
|
366 |
+
function wprss_preview_meta_box_callback() {
|
367 |
+
global $post;
|
368 |
+
$feed_url = get_post_meta( $post->ID, 'wprss_url', true );
|
369 |
+
|
370 |
+
$help = WPRSS_Help::get_instance();
|
371 |
+
/* @var $help WPRSS_Help */
|
372 |
+
|
373 |
+
if ( ! empty( $feed_url ) ) {
|
374 |
+
$feed = wprss_fetch_feed( $feed_url, $post->ID );
|
375 |
+
if ( ! is_wp_error( $feed ) ) {
|
376 |
+
$items = $feed->get_items();
|
377 |
+
// Figure out how many total items there are
|
378 |
+
$total = $feed->get_item_quantity();
|
379 |
+
// Get the number of items again, but limit it to 5.
|
380 |
+
$maxitems = $feed->get_item_quantity(5);
|
381 |
+
|
382 |
+
// Build an array of all the items, starting with element 0 (first element).
|
383 |
+
$items = $feed->get_items( 0, $maxitems );
|
384 |
+
?>
|
385 |
+
<h4><?php echo sprintf( __( 'Latest %1$s feed items out of %2$s available from %3$s' ), $maxitems, $total, get_the_title() ) ?></h4>
|
386 |
+
<ul>
|
387 |
+
<?php
|
388 |
+
foreach ( $items as $item ) {
|
389 |
+
// Get human date (comment if you want to use non human date)
|
390 |
+
$has_date = $item->get_date( 'U' ) ? TRUE : FALSE;
|
391 |
+
if ( $has_date ) {
|
392 |
+
$item_date = human_time_diff( $item->get_date('U'), current_time('timestamp')).' '.__( 'ago', 'rc_mdm' );
|
393 |
+
} else {
|
394 |
+
$item_date = '<em>[' . __( 'No Date', WPRSS_TEXT_DOMAIN ) . ']</em>';
|
395 |
+
}
|
396 |
+
// Start displaying item content within a <li> tag
|
397 |
+
echo '<li>';
|
398 |
+
// create item link
|
399 |
+
//echo '<a href="'.esc_url( $item->get_permalink() ).'" title="'.$item_date.'">';
|
400 |
+
// Get item title
|
401 |
+
echo esc_html( $item->get_title() );
|
402 |
+
//echo '</a>';
|
403 |
+
// Display date
|
404 |
+
echo ' <div class="rss-date"><small>'.$item_date.'</small></div>';
|
405 |
+
// End <li> tag
|
406 |
+
echo '</li>';
|
407 |
+
}
|
408 |
+
?>
|
409 |
+
</ul>
|
410 |
+
<?php
|
411 |
+
}
|
412 |
+
else {
|
413 |
+
?>
|
414 |
+
<span class="invalid-feed-url">
|
415 |
+
<?php _e( '<strong>Invalid feed URL</strong> - Double check the feed source URL setting above.', WPRSS_TEXT_DOMAIN ) ?>
|
416 |
+
<?php wprss_log_obj( 'Failed to preview feed.', $feed->get_error_message(), NULL, WPRSS_LOG_LEVEL_INFO ); ?>
|
417 |
+
</span>
|
418 |
+
<?php
|
419 |
+
echo wpautop( sprintf( __( '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_TEXT_DOMAIN ), 'http://webtrends.about.com/od/webfeedsyndicationrss/ss/rss_howto.htm' ) );
|
420 |
+
}
|
421 |
+
|
422 |
+
wprss_render_force_feed_option( $post->ID, TRUE );
|
423 |
+
}
|
424 |
+
|
425 |
+
else _e( 'No feed URL defined yet', WPRSS_TEXT_DOMAIN );
|
426 |
+
}
|
427 |
+
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Renders the Force Feed option for the Feed Preview.
|
431 |
+
*
|
432 |
+
* @param int|string $feed_source_id (Optional) The ID of the feed source for the option will be rendered. If not given or
|
433 |
+
* its value is null, the option will not be checked.
|
434 |
+
* @param bool $echo (Optional) If set to true, the function will immediately echo the option,
|
435 |
+
* rather than return a string of the option's markup. Default: False.
|
436 |
+
* @return string|null A string containing the HTML for the rendered option if $echo is set to false,
|
437 |
+
* or null if $echo is set to true.
|
438 |
+
* @since 4.6.12
|
439 |
+
*/
|
440 |
+
function wprss_render_force_feed_option( $feed_source_id = NULL, $echo = FALSE ) {
|
441 |
+
if ( ! $echo ) ob_start();
|
442 |
+
$force_feed = $feed_source_id === NULL ? '' : get_post_meta( $feed_source_id, 'wprss_force_feed', TRUE ); ?>
|
443 |
+
<hr/>
|
444 |
+
<p>
|
445 |
+
<label for="wprss-force-feed"><?php _e('Force the feed') ?></label>
|
446 |
+
<input type="hidden" name="wprss_force_feed" value="false" />
|
447 |
+
<input type="checkbox" name="wprss_force_feed" id="wprss-force-feed" value="true" <?php echo checked( $force_feed, 'true' ); ?> />
|
448 |
+
<?php echo WPRSS_Help::get_instance()->tooltip( 'field_wprss_force_feed' ) ?>
|
449 |
+
</p>
|
450 |
+
<?php
|
451 |
+
if ( ! $echo ) return ob_get_clean();
|
452 |
+
return NULL;
|
453 |
+
}
|
454 |
+
|
455 |
+
|
456 |
+
/**
|
457 |
+
* Renders the Feed Processing metabox
|
458 |
+
*
|
459 |
+
* @since 3.7
|
460 |
+
*/
|
461 |
+
function wprss_feed_processing_meta_box_callback() {
|
462 |
+
global $post;
|
463 |
+
// Get the post meta
|
464 |
+
$state = get_post_meta( $post->ID, 'wprss_state', TRUE );
|
465 |
+
$activate = get_post_meta( $post->ID, 'wprss_activate_feed', TRUE );
|
466 |
+
$pause = get_post_meta( $post->ID, 'wprss_pause_feed', TRUE );
|
467 |
+
$update_interval = get_post_meta( $post->ID, 'wprss_update_interval', TRUE );
|
468 |
+
|
469 |
+
$age_limit = get_post_meta( $post->ID, 'wprss_age_limit', FALSE );
|
470 |
+
$age_unit = get_post_meta( $post->ID, 'wprss_age_unit', FALSE );
|
471 |
+
|
472 |
+
$age_limit = ( count( $age_limit ) === 0 )? wprss_get_general_setting( 'limit_feed_items_age' ) : $age_limit[0];
|
473 |
+
$age_unit = ( count( $age_unit ) === 0 )? wprss_get_general_setting( 'limit_feed_items_age_unit' ) : $age_unit[0];
|
474 |
+
|
475 |
+
// Set default strings for activate and pause times
|
476 |
+
$default_activate = 'immediately';
|
477 |
+
$default_pause = 'never';
|
478 |
+
|
479 |
+
// Prepare the states
|
480 |
+
$states = array(
|
481 |
+
'active' => __( 'Active', WPRSS_TEXT_DOMAIN ),
|
482 |
+
'paused' => __( 'Paused', WPRSS_TEXT_DOMAIN ),
|
483 |
+
);
|
484 |
+
|
485 |
+
// Prepare the schedules
|
486 |
+
$default_interval = __( 'Default', WPRSS_TEXT_DOMAIN );
|
487 |
+
$wprss_schedules = apply_filters( 'wprss_schedules', wprss_get_schedules() );
|
488 |
+
$default_interval_key = wprss_get_default_feed_source_update_interval();
|
489 |
+
$schedules = array_merge(
|
490 |
+
array(
|
491 |
+
$default_interval_key => array(
|
492 |
+
'display' => $default_interval,
|
493 |
+
'interval' => $default_interval,
|
494 |
+
),
|
495 |
+
),
|
496 |
+
$wprss_schedules
|
497 |
+
);
|
498 |
+
|
499 |
+
// Inline help
|
500 |
+
$help = WPRSS_Help::get_instance();
|
501 |
+
$help_options = array('tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-side');
|
502 |
+
|
503 |
+
?>
|
504 |
+
|
505 |
+
<div class="wprss-meta-side-setting">
|
506 |
+
<label for="wprss_state">Feed state:</label>
|
507 |
+
<select id="wprss_state" name="wprss_state">
|
508 |
+
<?php foreach( $states as $value => $label ) : ?>
|
509 |
+
<option value="<?php echo $value; ?>" <?php selected( $state, $value ) ?> ><?php echo $label; ?></option>
|
510 |
+
<?php endforeach; ?>
|
511 |
+
</select>
|
512 |
+
<?php echo $help->tooltip( 'field_wprss_state', null, $help_options ) ?>
|
513 |
+
</div>
|
514 |
+
|
515 |
+
<div class="wprss-meta-side-setting">
|
516 |
+
<p>
|
517 |
+
<label for="">Activate feed: </label>
|
518 |
+
<strong id="wprss-activate-feed-viewer"><?php echo ( ( $activate !== '' )? $activate : $default_activate ); ?></strong>
|
519 |
+
<a href="#">Edit</a>
|
520 |
+
<?php echo $help->tooltip( 'field_wprss_activate_feed', null, $help_options ) ?>
|
521 |
+
</p>
|
522 |
+
<div class="wprss-meta-slider" data-collapse-viewer="wprss-activate-feed-viewer" data-default-value="<?php echo $default_activate; ?>">
|
523 |
+
<input id="wprss_activate_feed" class="wprss-datetimepicker-from-today" name="wprss_activate_feed" value="<?php echo $activate; ?>" />
|
524 |
+
<span class="description">
|
525 |
+
Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
|
526 |
+
</span>
|
527 |
+
</div>
|
528 |
+
</div>
|
529 |
+
|
530 |
+
<div class="wprss-meta-side-setting">
|
531 |
+
<p>
|
532 |
+
<label for="">Pause feed: </label>
|
533 |
+
<strong id="wprss-pause-feed-viewer"><?php echo ( ( $pause !== '' )? $pause : $default_pause ); ?></strong>
|
534 |
+
<a href="#">Edit</a>
|
535 |
+
<?php echo $help->tooltip( 'field_wprss_pause_feed', null, $help_options ) ?>
|
536 |
+
</p>
|
537 |
+
<div class="wprss-meta-slider" data-collapse-viewer="wprss-pause-feed-viewer" data-default-value="<?php echo $default_pause; ?>">
|
538 |
+
<input id="wprss_pause_feed" class="wprss-datetimepicker-from-today" name="wprss_pause_feed" value="<?php echo $pause; ?>" />
|
539 |
+
<span class="description">
|
540 |
+
Current UTC time is:<br/><code><?php echo date( 'd/m/Y H:i:s', current_time('timestamp',1) ); ?></code>
|
541 |
+
</span>
|
542 |
+
</div>
|
543 |
+
</div>
|
544 |
+
|
545 |
+
|
546 |
+
<div class="wprss-meta-side-setting">
|
547 |
+
<p>
|
548 |
+
<label for="">Update interval: </label>
|
549 |
+
<strong id="wprss-feed-update-interval-viewer">
|
550 |
+
<?php
|
551 |
+
if ( $update_interval === '' || $update_interval === wprss_get_default_feed_source_update_interval() ) {
|
552 |
+
echo $default_interval;
|
553 |
+
}
|
554 |
+
else {
|
555 |
+
echo wprss_interval( $schedules[$update_interval]['interval'] );
|
556 |
+
}
|
557 |
+
?>
|
558 |
+
</strong>
|
559 |
+
<a href="#">Edit</a>
|
560 |
+
<?php echo $help->tooltip( 'field_wprss_update_interval', null, $help_options ) ?>
|
561 |
+
</p>
|
562 |
+
<div class="wprss-meta-slider" data-collapse-viewer="wprss-feed-update-interval-viewer" data-default-value="<?php echo $default_interval; ?>">
|
563 |
+
<select id="feed-update-interval" name="wprss_update_interval">
|
564 |
+
<?php foreach ( $schedules as $value => $schedule ) : ?>
|
565 |
+
<?php $text = ( $value === wprss_get_default_feed_source_update_interval() )? $default_interval : wprss_interval( $schedule['interval'] ); ?>
|
566 |
+
<option value="<?php echo $value; ?>" <?php selected( $update_interval, $value ); ?> ><?php echo $text; ?></option>
|
567 |
+
<?php endforeach; ?>
|
568 |
+
</select>
|
569 |
+
</div>
|
570 |
+
</div>
|
571 |
+
|
572 |
+
|
573 |
+
<div class="wprss-meta-side-setting">
|
574 |
+
<p>
|
575 |
+
<label id="wprss-age-limit-feed-label" for="" data-when-empty="Delete old feed items:">Delete feed items older than: </label>
|
576 |
+
<strong id="wprss-age-limit-feed-viewer"><?php echo $age_limit . ' ' . $age_unit; ?></strong>
|
577 |
+
<a href="#">Edit</a>
|
578 |
+
<?php echo $help->tooltip( 'field_wprss_age_limit', null, $help_options ) ?>
|
579 |
+
</p>
|
580 |
+
<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">
|
581 |
+
<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; ?>" />
|
582 |
+
|
583 |
+
<select id="limit-feed-items-age-unit" name="wprss_age_unit">
|
584 |
+
<?php foreach ( wprss_age_limit_units() as $unit ) : ?>
|
585 |
+
<option value="<?php echo $unit; ?>" <?php selected( $age_unit, $unit ); ?> ><?php echo $unit; ?></option>
|
586 |
+
<?php endforeach; ?>
|
587 |
+
</select>
|
588 |
+
</div>
|
589 |
+
</div>
|
590 |
+
|
591 |
+
|
592 |
+
<?php
|
593 |
+
}
|
594 |
+
|
595 |
+
|
596 |
+
|
597 |
+
/**
|
598 |
+
* Generate Help meta box
|
599 |
+
*
|
600 |
+
* @since 2.0
|
601 |
+
*
|
602 |
+
*/
|
603 |
+
function wprss_help_meta_box_callback() {
|
604 |
+
echo '<p><a href="http://www.wprssaggregator.com/documentation/">View the documentation</p>';
|
605 |
+
echo '<p><strong>';
|
606 |
+
_e( 'Need help?', WPRSS_TEXT_DOMAIN );
|
607 |
+
echo '</strong> <a target="_blank" href="http://wordpress.org/support/plugin/wp-rss-aggregator">';
|
608 |
+
_e( 'Check out the support forum', WPRSS_TEXT_DOMAIN );
|
609 |
+
echo '</a></p>';
|
610 |
+
echo '</strong> <a target="_blank" href="http://www.wprssaggregator.com/feature-requests/">';
|
611 |
+
_e( 'Suggest a new feature', WPRSS_TEXT_DOMAIN );
|
612 |
+
echo '</a></p>';
|
613 |
+
}
|
614 |
+
|
615 |
+
/**
|
616 |
+
* Generate Like this plugin meta box
|
617 |
+
*
|
618 |
+
* @since 2.0
|
619 |
+
*
|
620 |
+
*/
|
621 |
+
function wprss_like_meta_box_callback() { ?>
|
622 |
+
|
623 |
+
<ul>
|
624 |
+
<li><a href="http://wordpress.org/extend/plugins/wp-rss-aggregator/"><?php _e( 'Give it a 5 star rating on WordPress.org', WPRSS_TEXT_DOMAIN ) ?></a></li>
|
625 |
+
<li class="donate_link"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=X9GP6BL4BLXBJ"><?php _e( 'Donate a token of your appreciation', WPRSS_TEXT_DOMAIN ); ?></a></li>
|
626 |
+
</ul>
|
627 |
+
<?php
|
628 |
+
echo '<p><strong>';
|
629 |
+
_e( 'Check out the Premium Extensions:', WPRSS_TEXT_DOMAIN );
|
630 |
+
echo '</strong>'; ?>
|
631 |
+
<ul>
|
632 |
+
<li><a href="http://www.wprssaggregator.com/extension/feed-to-post/"><?php echo 'Feed to Post'; ?></a></li>
|
633 |
+
<li><a href="http://www.wprssaggregator.com/extension/excerpts-thumbnails/"><?php echo 'Excerpts & Thumbnails'; ?></a></li>
|
634 |
+
<li><a href="http://www.wprssaggregator.com/extension/categories/"><?php echo 'Categories'; ?></a></li>
|
635 |
+
<li><a href="http://www.wprssaggregator.com/extension/keyword-filtering/"><?php echo 'Keyword Filtering'; ?></a></li>
|
636 |
+
</ul>
|
637 |
+
</p>
|
638 |
+
<?php }
|
639 |
+
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Generate Follow us plugin meta box
|
643 |
+
*
|
644 |
+
* @since 2.0
|
645 |
+
*
|
646 |
+
*/
|
647 |
+
function wprss_follow_meta_box_callback() {
|
648 |
+
?>
|
649 |
+
<ul>
|
650 |
+
<li class="twitter"><a href="http://twitter.com/wpmayor"><?php _e( 'Follow WP Mayor on Twitter.', WPRSS_TEXT_DOMAIN ) ?></a></li>
|
651 |
+
<li class="facebook"><a href="https://www.facebook.com/wpmayor"><?php _e( 'Like WP Mayor on Facebook.', WPRSS_TEXT_DOMAIN ) ?></a></li>
|
652 |
+
</ul>
|
653 |
+
<?php }
|
654 |
+
|
655 |
+
|
656 |
+
add_action( 'add_meta_boxes', 'wprss_remove_meta_boxes', 100 );
|
657 |
+
/**
|
658 |
+
* Remove unneeded meta boxes from add feed source screen
|
659 |
+
*
|
660 |
+
* @since 2.0
|
661 |
+
*/
|
662 |
+
function wprss_remove_meta_boxes() {
|
663 |
+
if ( 'wprss_feed' !== get_current_screen()->id ) return;
|
664 |
+
// Remove meta boxes of other plugins that tend to appear on all posts
|
665 |
+
//remove_meta_box( 'wpseo_meta', 'wprss_feed' ,'normal' );
|
666 |
+
remove_meta_box( 'postpsp', 'wprss_feed' ,'normal' );
|
667 |
+
remove_meta_box( 'su_postmeta', 'wprss_feed' ,'normal' );
|
668 |
+
remove_meta_box( 'woothemes-settings', 'wprss_feed' ,'normal' );
|
669 |
+
remove_meta_box( 'wpcf-post-relationship', 'wprss_feed' ,'normal' );
|
670 |
+
remove_meta_box( 'wpar_plugin_meta_box ', 'wprss_feed' ,'normal' );
|
671 |
+
remove_meta_box( 'sharing_meta', 'wprss_feed' ,'advanced' );
|
672 |
+
remove_meta_box( 'content-permissions-meta-box', 'wprss_feed' ,'advanced' );
|
673 |
+
remove_meta_box( 'theme-layouts-post-meta-box', 'wprss_feed' ,'side' );
|
674 |
+
remove_meta_box( 'post-stylesheets', 'wprss_feed' ,'side' );
|
675 |
+
remove_meta_box( 'hybrid-core-post-template', 'wprss_feed' ,'side' );
|
676 |
+
remove_meta_box( 'wpcf-marketing', 'wprss_feed' ,'side' );
|
677 |
+
remove_meta_box( 'trackbacksdiv22', 'wprss_feed' ,'advanced' );
|
678 |
+
remove_meta_box( 'aiosp', 'wprss_feed' ,'advanced' );
|
679 |
+
remove_action( 'post_submitbox_start', 'fpp_post_submitbox_start_action' );
|
680 |
+
}
|
includes/admin-options.php
CHANGED
@@ -1,1133 +1,1133 @@
|
|
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 option_name The name of the option to get
|
18 |
-
* @return mixed
|
19 |
-
* @since 3.7.1
|
20 |
-
*/
|
21 |
-
function wprss_get_general_setting( $option_name ) {
|
22 |
-
$options = get_option( 'wprss_settings_general', array() );
|
23 |
-
$defaults = wprss_get_default_settings_general();
|
24 |
-
return ( ( isset( $options[ $option_name ] ) )? $options[$option_name] : $defaults[$option_name] );
|
25 |
-
}
|
26 |
-
|
27 |
-
|
28 |
-
add_action( 'admin_init', 'wprss_admin_init' );
|
29 |
-
/**
|
30 |
-
* Register and define options and settings
|
31 |
-
* @since 2.0
|
32 |
-
* @todo add option for cron frequency
|
33 |
-
*
|
34 |
-
* Note: In the future might change to
|
35 |
-
* the way EDD builds the settings pages, cleaner method.
|
36 |
-
*/
|
37 |
-
function wprss_admin_init() {
|
38 |
-
|
39 |
-
register_setting(
|
40 |
-
'wprss_settings_general', // A settings group name.
|
41 |
-
'wprss_settings_general', // The name of an option to sanitize and save.
|
42 |
-
'wprss_settings_general_validate' // A callback function that sanitizes the option's value.
|
43 |
-
);
|
44 |
-
|
45 |
-
// Licensing of add-ons
|
46 |
-
register_setting(
|
47 |
-
'wprss_settings_license_keys',
|
48 |
-
'wprss_settings_license_keys',
|
49 |
-
'wprss_settings_license_keys_validate'
|
50 |
-
);
|
51 |
-
|
52 |
-
|
53 |
-
$sections = apply_filters(
|
54 |
-
'wprss_settings_sections_array',
|
55 |
-
array(
|
56 |
-
'general' => __( 'General plugin settings', WPRSS_TEXT_DOMAIN ),
|
57 |
-
'display' => __( 'General display settings', WPRSS_TEXT_DOMAIN ),
|
58 |
-
'source' => __( 'Source display settings', WPRSS_TEXT_DOMAIN ),
|
59 |
-
'date' => __( 'Date display settings', WPRSS_TEXT_DOMAIN ),
|
60 |
-
'styles' => __( 'Styles', WPRSS_TEXT_DOMAIN ),
|
61 |
-
)
|
62 |
-
);
|
63 |
-
|
64 |
-
// Define the settings per section
|
65 |
-
$settings = apply_filters(
|
66 |
-
'wprss_settings_array',
|
67 |
-
array(
|
68 |
-
'general' => array(
|
69 |
-
'limit-feed-items-by-age' => array(
|
70 |
-
'label' => __( 'Limit feed items by age', WPRSS_TEXT_DOMAIN ),
|
71 |
-
'callback' => 'wprss_setting_limit_feed_items_age_callback'
|
72 |
-
),
|
73 |
-
'limit-feed-items-db' => array(
|
74 |
-
'label' => __( 'Limit feed items stored', WPRSS_TEXT_DOMAIN ),
|
75 |
-
'callback' => 'wprss_setting_limit_feed_items_callback'
|
76 |
-
),
|
77 |
-
'limit-feed-items-imported' => array(
|
78 |
-
'label' => __( 'Limit feed items per feed', WPRSS_TEXT_DOMAIN ),
|
79 |
-
'callback' => 'wprss_setting_limit_feed_items_imported_callback'
|
80 |
-
),
|
81 |
-
'cron-interval' => array(
|
82 |
-
'label' => __( 'Feed processing interval', WPRSS_TEXT_DOMAIN ),
|
83 |
-
'callback' => 'wprss_setting_cron_interval_callback'
|
84 |
-
),
|
85 |
-
'custom-feed-url' => array(
|
86 |
-
'label' => __( 'Custom feed URL', WPRSS_TEXT_DOMAIN ),
|
87 |
-
'callback' => 'wprss_settings_custom_feed_url_callback'
|
88 |
-
),
|
89 |
-
'custom-feed-title' => array(
|
90 |
-
'label' => __( 'Custom feed Title', WPRSS_TEXT_DOMAIN ),
|
91 |
-
'callback' => 'wprss_settings_custom_feed_title_callback'
|
92 |
-
),
|
93 |
-
'custom-feed-limit' => array(
|
94 |
-
'label' => __( 'Custom feed limit', WPRSS_TEXT_DOMAIN ),
|
95 |
-
'callback' => 'wprss_setings_custom_feed_limit_callback'
|
96 |
-
),
|
97 |
-
'tracking' => array(
|
98 |
-
'label' => __( 'Anonymous tracking', WPRSS_TEXT_DOMAIN ),
|
99 |
-
'callback' => 'wprss_tracking_callback',
|
100 |
-
)
|
101 |
-
),
|
102 |
-
|
103 |
-
'display' => array(
|
104 |
-
// Title options
|
105 |
-
'link-enable' => array(
|
106 |
-
'label' => __( 'Link title', WPRSS_TEXT_DOMAIN ),
|
107 |
-
'callback' => 'wprss_setting_title_link_callback'
|
108 |
-
),
|
109 |
-
'title-limit' => array(
|
110 |
-
'label' => __( 'Title maximum length', WPRSS_TEXT_DOMAIN ),
|
111 |
-
'callback' => 'wprss_setting_title_length_callback'
|
112 |
-
),
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
// Misc Options
|
117 |
-
'authors-enable' => array(
|
118 |
-
'label' => __( 'Show authors', WPRSS_TEXT_DOMAIN ),
|
119 |
-
'callback' => 'wprss_setting_authors_enable_callback',
|
120 |
-
),
|
121 |
-
'video-links' => array(
|
122 |
-
'label' => __( 'For video feed items use', WPRSS_TEXT_DOMAIN ),
|
123 |
-
'callback' => 'wprss_setting_video_links_callback'
|
124 |
-
),
|
125 |
-
'pagination' => array(
|
126 |
-
'label' => __( 'Pagination type', WPRSS_TEXT_DOMAIN ),
|
127 |
-
'callback' => 'wprss_setting_pagination_type_callback',
|
128 |
-
),
|
129 |
-
'feed-limit' => array(
|
130 |
-
'label' => __( 'Feed display limit', WPRSS_TEXT_DOMAIN ),
|
131 |
-
'callback' => 'wprss_setting_feed_limit_callback'
|
132 |
-
),
|
133 |
-
'open-dd' => array(
|
134 |
-
'label' => __( 'Open links behaviour', WPRSS_TEXT_DOMAIN ),
|
135 |
-
'callback' => 'wprss_setting_open_dd_callback'
|
136 |
-
),
|
137 |
-
'follow-dd' => array(
|
138 |
-
'label' => __( 'Set links as nofollow', WPRSS_TEXT_DOMAIN ),
|
139 |
-
'callback' => 'wprss_setting_follow_dd_callback'
|
140 |
-
),
|
141 |
-
),
|
142 |
-
|
143 |
-
// Source Options
|
144 |
-
'source' => array(
|
145 |
-
'source-enable' => array(
|
146 |
-
'label' => __( 'Show source', WPRSS_TEXT_DOMAIN ),
|
147 |
-
'callback' => 'wprss_setting_source_enable_callback'
|
148 |
-
),
|
149 |
-
'text-preceding-source' => array(
|
150 |
-
'label' => __( 'Text preceding source', WPRSS_TEXT_DOMAIN ),
|
151 |
-
'callback' => 'wprss_setting_text_preceding_source_callback'
|
152 |
-
),
|
153 |
-
'source-link' => array(
|
154 |
-
'label' => __( 'Link source', WPRSS_TEXT_DOMAIN ),
|
155 |
-
'callback' => 'wprss_setting_source_link_callback'
|
156 |
-
),
|
157 |
-
),
|
158 |
-
|
159 |
-
// Date options
|
160 |
-
'date' => array(
|
161 |
-
'date-enable' => array(
|
162 |
-
'label' => __( 'Show date', WPRSS_TEXT_DOMAIN ),
|
163 |
-
'callback' => 'wprss_setting_date_enable_callback'
|
164 |
-
),
|
165 |
-
'text-preceding-date' => array(
|
166 |
-
'label' => __( 'Text preceding date', WPRSS_TEXT_DOMAIN ),
|
167 |
-
'callback' => 'wprss_setting_text_preceding_date_callback'
|
168 |
-
),
|
169 |
-
'date-format' => array(
|
170 |
-
'label' => __( 'Date format', WPRSS_TEXT_DOMAIN ),
|
171 |
-
'callback' => 'wprss_setting_date_format_callback'
|
172 |
-
),
|
173 |
-
'time-ago-format-enable' => array(
|
174 |
-
'label' => __( 'Time ago format', WPRSS_TEXT_DOMAIN ),
|
175 |
-
'callback' => 'wprss_setting_time_ago_format_enable_callback'
|
176 |
-
),
|
177 |
-
),
|
178 |
-
|
179 |
-
'styles' => array(
|
180 |
-
'styles-disable' => array(
|
181 |
-
'label' => __( 'Disable Styles', WPRSS_TEXT_DOMAIN ),
|
182 |
-
'callback' => 'wprss_setting_styles_disable_callback'
|
183 |
-
)
|
184 |
-
)
|
185 |
-
)
|
186 |
-
);
|
187 |
-
|
188 |
-
if ( apply_filters( 'wprss_use_fixed_feed_limit', FALSE ) === FALSE ) {
|
189 |
-
unset( $settings['general']['limit-feed-items-db'] );
|
190 |
-
}
|
191 |
-
|
192 |
-
$setting_field_id_prefix = 'wprss-settings-';
|
193 |
-
|
194 |
-
|
195 |
-
// Loop through each setting field and register it
|
196 |
-
foreach( $settings as $section => $fields ) {
|
197 |
-
if ( count( $fields ) > 0 ) {
|
198 |
-
$section_desc = $sections[ $section ];
|
199 |
-
add_settings_section(
|
200 |
-
"wprss_settings_${section}_section",
|
201 |
-
$section_desc,
|
202 |
-
"wprss_settings_${section}_callback",
|
203 |
-
'wprss_settings_general'
|
204 |
-
);
|
205 |
-
|
206 |
-
foreach ( $fields as $id => $data ) {
|
207 |
-
|
208 |
-
/**
|
209 |
-
* @var This will be passed to the field callback as the only argument
|
210 |
-
* @see http://codex.wordpress.org/Function_Reference/add_settings_field#Parameters
|
211 |
-
*/
|
212 |
-
$callback_args = array(
|
213 |
-
'field_id' => $id,
|
214 |
-
'field_id_prefix' => $setting_field_id_prefix,
|
215 |
-
'section_id' => $section,
|
216 |
-
'field_label' => isset( $data['label'] ) ? $data['label'] : null,
|
217 |
-
'tooltip' => isset( $data['tooltip'] ) ? $data['tooltip'] : null
|
218 |
-
);
|
219 |
-
|
220 |
-
|
221 |
-
add_settings_field(
|
222 |
-
$setting_field_id_prefix . $id,
|
223 |
-
$data['label'],
|
224 |
-
$data['callback'],
|
225 |
-
'wprss_settings_general',
|
226 |
-
"wprss_settings_${section}_section",
|
227 |
-
$callback_args
|
228 |
-
);
|
229 |
-
|
230 |
-
}
|
231 |
-
}
|
232 |
-
}
|
233 |
-
|
234 |
-
|
235 |
-
/*
|
236 |
-
// SECURE RESET OPTION
|
237 |
-
register_setting(
|
238 |
-
'wprss_secure_reset', // A settings group name.
|
239 |
-
'wprss_secure_reset_code', // The name of an option to sanitize and save.
|
240 |
-
'' // A callback function that sanitizes the option's value.
|
241 |
-
);
|
242 |
-
add_settings_section(
|
243 |
-
'wprss_secure_reset_section', // ID of section
|
244 |
-
__( 'Secure Reset', WPRSS_TEXT_DOMAIN ), // Title of section
|
245 |
-
'wprss_secure_reset_section_callback', // Callback that renders the section header
|
246 |
-
'wprss_settings_general' // The page on which to display the section
|
247 |
-
);
|
248 |
-
add_settings_field(
|
249 |
-
'wprss-settings-secure-reset', // ID of setting
|
250 |
-
__( 'Secure Reset', WPRSS_TEXT_DOMAIN ), // The title of the setting
|
251 |
-
'wprss_settings_secure_reset_code_callback', // The callback that renders the setting
|
252 |
-
'wprss_settings_general', // The page on which to display the setting
|
253 |
-
"wprss_secure_reset_section" // The section in which to display the setting
|
254 |
-
);
|
255 |
-
*/
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
do_action( 'wprss_admin_init' );
|
260 |
-
}
|
261 |
-
|
262 |
-
|
263 |
-
/**
|
264 |
-
* Returns the HTML of a tooltip handle.
|
265 |
-
*
|
266 |
-
* Filters used:
|
267 |
-
* - `wprss_settings_inline_help_default_options` - The default options for "Settings" page's tooltips
|
268 |
-
* - `wprss_settings_inline_help_id_prefix` - The prefix for all tooltip IDs for the "Settings" page.
|
269 |
-
*
|
270 |
-
* @param string $id The ID of the tooltip
|
271 |
-
* @param string|null $text Text for this tooltip, if any.
|
272 |
-
* @param array $options Any options for this setting.
|
273 |
-
* @return string Tooltip handle HTML. See {@link WPRSS_Help::tooltip()}.
|
274 |
-
*/
|
275 |
-
function wprss_settings_inline_help( $id, $text = null, $options = array() ) {
|
276 |
-
$help = WPRSS_Help::get_instance();
|
277 |
-
|
278 |
-
// Default options, entry point
|
279 |
-
$defaults = apply_filters( 'wprss_settings_inline_help_default_options', array(
|
280 |
-
'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-setting'
|
281 |
-
));
|
282 |
-
|
283 |
-
$options = $help->array_merge_recursive_distinct( $defaults, $options );
|
284 |
-
|
285 |
-
// ID Prefix
|
286 |
-
$id = apply_filters( 'wprss_settings_inline_help_id_prefix', 'setting-' ) . $id;
|
287 |
-
|
288 |
-
return $help->tooltip( $id, $text, $options );
|
289 |
-
}
|
290 |
-
|
291 |
-
|
292 |
-
/**
|
293 |
-
*
|
294 |
-
* @param type $string
|
295 |
-
* @return type
|
296 |
-
*/
|
297 |
-
function wprss_settings_field_name_prefix( $string = '' ) {
|
298 |
-
$string = (string) $string;
|
299 |
-
$prefix = apply_filters( 'wprss_settings_field_name_prefix', 'wprss_settings_', $string );
|
300 |
-
return $prefix . $string;
|
301 |
-
}
|
302 |
-
|
303 |
-
|
304 |
-
/**
|
305 |
-
* Generates a uniform setting field name for use in HTML.
|
306 |
-
* The parts used are the ID of the field, the section it is in, and an optional prefix.
|
307 |
-
* All parts are optional, but, if they appear, they shall appear in this order: $prefix, $section, $id.
|
308 |
-
*
|
309 |
-
* If only the section is not specified, the $id will be simply prefixed by $prefix.
|
310 |
-
* If either the $id or the $section are empty (but not both), $prefix will be stripped of known separators.
|
311 |
-
* Empty parts will be excluded.
|
312 |
-
*
|
313 |
-
* @param string $id ID of the field.
|
314 |
-
* @param string|null $section Name of the section, to which this field belongs.
|
315 |
-
* @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()}.
|
316 |
-
* @return string Name of the settings field, namespaced and optionally prefixed.
|
317 |
-
*/
|
318 |
-
function wprss_settings_field_name( $id = null, $section = null, $prefix = null ) {
|
319 |
-
if( $prefix !== false ) $prefix = is_null( $prefix ) ? wprss_settings_field_name_prefix() : $prefix;
|
320 |
-
else $prefix = '';
|
321 |
-
|
322 |
-
$section = (string) $section;
|
323 |
-
|
324 |
-
$format = '';
|
325 |
-
if( !strlen( $section ) xor !strlen($id) ) $prefix = trim ( $prefix, "\t\n\r _-:" );
|
326 |
-
if( strlen( $prefix ) ) $format .= '%3$s';
|
327 |
-
if( strlen( $section ) ) $format .= '%2$s';
|
328 |
-
if( strlen( $id ) ) $format .= ( !strlen( $section ) ? '%1$s' : '[%1$s]' );
|
329 |
-
|
330 |
-
return apply_filters( 'wprss_settings_field_name', sprintf( $format, $id, $section, $prefix ), $id, $section, $prefix );
|
331 |
-
}
|
332 |
-
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Build the plugin settings page, used to save general settings like whether a link should be follow or no follow
|
336 |
-
* @since 1.1
|
337 |
-
*/
|
338 |
-
function wprss_settings_page_display() {
|
339 |
-
?>
|
340 |
-
<div class="wrap">
|
341 |
-
<?php screen_icon( 'wprss-aggregator' ); ?>
|
342 |
-
|
343 |
-
<h2><?php _e( 'WP RSS Aggregator Settings', WPRSS_TEXT_DOMAIN ); ?></h2>
|
344 |
-
|
345 |
-
<?php settings_errors(); ?>
|
346 |
-
|
347 |
-
<?php $active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general_settings'; ?>
|
348 |
-
|
349 |
-
<?php
|
350 |
-
|
351 |
-
$default_tabs = array(
|
352 |
-
'general' => array(
|
353 |
-
'label' => __( 'General', WPRSS_TEXT_DOMAIN ),
|
354 |
-
'slug' => 'general_settings',
|
355 |
-
),
|
356 |
-
'licenses' => array(
|
357 |
-
'label' => __( 'Licenses', WPRSS_TEXT_DOMAIN ),
|
358 |
-
'slug' => 'licenses_settings'
|
359 |
-
)
|
360 |
-
);
|
361 |
-
|
362 |
-
$addon_tabs = apply_filters( 'wprss_options_tabs', array() );
|
363 |
-
|
364 |
-
$tabs = array_merge( array( $default_tabs['general'] ), $addon_tabs , array( $default_tabs['licenses'] ) );
|
365 |
-
|
366 |
-
$show_tabs = ( count( $addon_tabs ) > 0 ) || apply_filters( 'wprss_show_settings_tabs_condition', FALSE );
|
367 |
-
|
368 |
-
if ( $show_tabs ) { ?>
|
369 |
-
<h2 class="nav-tab-wrapper">
|
370 |
-
<?php
|
371 |
-
foreach ( $tabs as $tab => $tab_property ) { ?>
|
372 |
-
<a href="?post_type=wprss_feed&page=wprss-aggregator-settings&tab=<?php echo esc_attr( $tab_property['slug'] ); ?>"
|
373 |
-
class="nav-tab <?php echo $active_tab == $tab_property['slug'] ? 'nav-tab-active' : ''; ?>"><?php echo esc_html( $tab_property['label'] ); ?></a>
|
374 |
-
<?php } ?>
|
375 |
-
<?php } ?>
|
376 |
-
</h2>
|
377 |
-
|
378 |
-
<form action="options.php" method="post">
|
379 |
-
|
380 |
-
<?php
|
381 |
-
|
382 |
-
if ( $active_tab === 'general_settings' ) {
|
383 |
-
settings_fields( 'wprss_settings_general' );
|
384 |
-
//settings_fields( 'wprss_secure_reset' );
|
385 |
-
do_settings_sections( 'wprss_settings_general' );
|
386 |
-
}
|
387 |
-
elseif ( $show_tabs ) {
|
388 |
-
|
389 |
-
if ( $active_tab === 'licenses_settings' ) {
|
390 |
-
settings_fields( 'wprss_settings_license_keys' );
|
391 |
-
do_settings_sections( 'wprss_settings_license_keys' );
|
392 |
-
}
|
393 |
-
|
394 |
-
do_action( 'wprss_add_settings_fields_sections', $active_tab );
|
395 |
-
}
|
396 |
-
|
397 |
-
submit_button( __( 'Save Settings', WPRSS_TEXT_DOMAIN ) );
|
398 |
-
|
399 |
-
?>
|
400 |
-
</form>
|
401 |
-
</div>
|
402 |
-
<?php
|
403 |
-
}
|
404 |
-
|
405 |
-
|
406 |
-
/**
|
407 |
-
* General settings section header
|
408 |
-
* @since 3.0
|
409 |
-
*/
|
410 |
-
function wprss_settings_general_callback() {
|
411 |
-
echo wpautop( __( 'These are the general settings for WP RSS Aggregator.', WPRSS_TEXT_DOMAIN ) );
|
412 |
-
}
|
413 |
-
|
414 |
-
|
415 |
-
/**
|
416 |
-
* General settings display section header
|
417 |
-
* @since 3.5
|
418 |
-
*/
|
419 |
-
function wprss_settings_display_callback() {
|
420 |
-
echo wpautop( __( 'In this section you can find some general options that control how the feed items are displayed.', WPRSS_TEXT_DOMAIN ) );
|
421 |
-
}
|
422 |
-
|
423 |
-
|
424 |
-
/**
|
425 |
-
* Display settings for source section header
|
426 |
-
*
|
427 |
-
* @since 4.2.4
|
428 |
-
*/
|
429 |
-
function wprss_settings_source_callback() {
|
430 |
-
echo wpautop( __( "Options that control how the feed item's source is displayed.", WPRSS_TEXT_DOMAIN ) );
|
431 |
-
}
|
432 |
-
|
433 |
-
/**
|
434 |
-
* Display settings for date section header
|
435 |
-
*
|
436 |
-
* @since 4.2.4
|
437 |
-
*/
|
438 |
-
function wprss_settings_date_callback() {
|
439 |
-
echo wpautop( __( "Options that control how the feed item's date is displayed.", WPRSS_TEXT_DOMAIN ) );
|
440 |
-
}
|
441 |
-
|
442 |
-
|
443 |
-
/**
|
444 |
-
* General settings styles section header
|
445 |
-
* @since 3.0
|
446 |
-
*/
|
447 |
-
function wprss_settings_styles_callback() {
|
448 |
-
echo wpautop( __( 'If you would like to disable all styles used in this plugin, tick the checkbox.', WPRSS_TEXT_DOMAIN ) );
|
449 |
-
}
|
450 |
-
|
451 |
-
|
452 |
-
/**
|
453 |
-
* General settings scure reset section header
|
454 |
-
* @since 3.0
|
455 |
-
*/
|
456 |
-
function wprss_secure_reset_section_callback() {
|
457 |
-
echo wpautop( __( 'Set your security reset code, in case of any errors.', WPRSS_TEXT_DOMAIN ) );
|
458 |
-
}
|
459 |
-
|
460 |
-
|
461 |
-
/**
|
462 |
-
* Tracking settings section header
|
463 |
-
* @since 3.0
|
464 |
-
*/
|
465 |
-
function wprss_tracking_section_callback() {
|
466 |
-
echo wpautop( __( 'Participate in helping us make the plugin better.', WPRSS_TEXT_DOMAIN ) );
|
467 |
-
}
|
468 |
-
|
469 |
-
|
470 |
-
/**
|
471 |
-
* Follow or No Follow dropdown
|
472 |
-
* @since 1.1
|
473 |
-
*/
|
474 |
-
function wprss_setting_follow_dd_callback( $field ) {
|
475 |
-
$follow_dd = wprss_get_general_setting( 'follow_dd' );
|
476 |
-
|
477 |
-
$checked = ( $follow_dd === 'no_follow' );
|
478 |
-
$checked_attr = ( $checked )? 'checked="checked"' : '';
|
479 |
-
?>
|
480 |
-
<input type="hidden" name="wprss_settings_general[follow_dd]" value="follow" />
|
481 |
-
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[follow_dd]" value="no_follow" <?php echo $checked_attr ?> />
|
482 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
483 |
-
}
|
484 |
-
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Use original video link, or embedded video links dropwdown
|
488 |
-
* @since 3.4
|
489 |
-
*/
|
490 |
-
function wprss_setting_video_links_callback( $field ) {
|
491 |
-
$video_link = wprss_get_general_setting('video_link');
|
492 |
-
$items = array(
|
493 |
-
'false' => __( 'Original page link', WPRSS_TEXT_DOMAIN ),
|
494 |
-
'true' => __( 'Embedded video player link', WPRSS_TEXT_DOMAIN )
|
495 |
-
);
|
496 |
-
?>
|
497 |
-
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[video_link]">
|
498 |
-
<?php
|
499 |
-
foreach ( $items as $boolean => $text ) {
|
500 |
-
$selected = ( $video_link === $boolean )? 'selected="selected"' : '';
|
501 |
-
?><option value="<?php echo $boolean ?>" <?php echo $selected ?>><?php echo $text ?></option><?php
|
502 |
-
}
|
503 |
-
?>
|
504 |
-
</select>
|
505 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
506 |
-
<p>
|
507 |
-
<span class="description">
|
508 |
-
<?php _e( 'This will not affect already imported feed items.', WPRSS_TEXT_DOMAIN ) ?>
|
509 |
-
</span>
|
510 |
-
</p>
|
511 |
-
<?php
|
512 |
-
}
|
513 |
-
|
514 |
-
|
515 |
-
/**
|
516 |
-
* Link open setting dropdown
|
517 |
-
* @since 1.1
|
518 |
-
*/
|
519 |
-
function wprss_setting_open_dd_callback( $field ) {
|
520 |
-
$open_dd = wprss_get_general_setting('open_dd');
|
521 |
-
|
522 |
-
$items = array(
|
523 |
-
__( 'Lightbox', WPRSS_TEXT_DOMAIN ),
|
524 |
-
__( 'New window', WPRSS_TEXT_DOMAIN ),
|
525 |
-
__( 'Self', WPRSS_TEXT_DOMAIN )
|
526 |
-
);
|
527 |
-
?>
|
528 |
-
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[open_dd]">
|
529 |
-
<?php
|
530 |
-
foreach( $items as $item ) {
|
531 |
-
$selected = ( $open_dd == $item ) ? 'selected="selected"' : '';
|
532 |
-
?><option value="<?php echo $item ?>" <?php echo $selected ?>><?php echo $item ?></option><?php
|
533 |
-
}
|
534 |
-
?>
|
535 |
-
</select>
|
536 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
537 |
-
}
|
538 |
-
|
539 |
-
|
540 |
-
/**
|
541 |
-
* Set limit for feeds on frontend
|
542 |
-
* @since 2.0
|
543 |
-
*/
|
544 |
-
function wprss_setting_feed_limit_callback( $field ) {
|
545 |
-
$feed_limit = wprss_get_general_setting( 'feed_limit' );
|
546 |
-
?>
|
547 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[feed_limit]" type="text" value="<?php echo $feed_limit ?>" />
|
548 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
549 |
-
}
|
550 |
-
|
551 |
-
|
552 |
-
/**
|
553 |
-
* Set date format
|
554 |
-
* @since 3.0
|
555 |
-
*/
|
556 |
-
function wprss_setting_date_format_callback( $field ) {
|
557 |
-
$date_format = wprss_get_general_setting( 'date_format' );
|
558 |
-
?>
|
559 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[date_format]" type="text" value="<?php echo $date_format ?>" />
|
560 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
561 |
-
<p>
|
562 |
-
<a href="http://codex.wordpress.org/Formatting_Date_and_Time">
|
563 |
-
<?php _e( 'PHP Date Format Reference', WPRSS_TEXT_DOMAIN ); ?>
|
564 |
-
</a>
|
565 |
-
</p>
|
566 |
-
<?php
|
567 |
-
}
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
/**
|
572 |
-
* Enable linked title
|
573 |
-
* @since 3.0
|
574 |
-
*/
|
575 |
-
function wprss_setting_title_link_callback( $field ) {
|
576 |
-
$title_link = wprss_get_general_setting( 'title_link' );
|
577 |
-
?>
|
578 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[title_link]" type="checkbox" value="1" <?php echo checked( 1, $title_link, false ) ?> />
|
579 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
580 |
-
}
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
/**
|
585 |
-
* Set the title length limit
|
586 |
-
* @since 3.0
|
587 |
-
*/
|
588 |
-
function wprss_setting_title_length_callback( $field ) {
|
589 |
-
$title_limit = wprss_get_general_setting( 'title_limit' );
|
590 |
-
?>
|
591 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[title_limit]" type="number" class="wprss-number-roller" min="0" value="<?php echo $title_limit ?>" placeholder="<?php _e( 'No limit', WPRSS_TEXT_DOMAIN ) ?>" />
|
592 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
593 |
-
}
|
594 |
-
|
595 |
-
|
596 |
-
/**
|
597 |
-
* Enable source
|
598 |
-
* @since 3.0
|
599 |
-
*/
|
600 |
-
function wprss_setting_source_enable_callback( $field ) {
|
601 |
-
$source_enable = wprss_get_general_setting( 'source_enable' );
|
602 |
-
?>
|
603 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[source_enable]" type="checkbox" value="1" <?php echo checked( 1, $source_enable, false ) ?> />
|
604 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
605 |
-
}
|
606 |
-
|
607 |
-
/**
|
608 |
-
* Enable linked title
|
609 |
-
* @since 3.0
|
610 |
-
*/
|
611 |
-
function wprss_setting_source_link_callback( $field ) {
|
612 |
-
$source_link = wprss_get_general_setting( 'source_link' );
|
613 |
-
?>
|
614 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[source_link]" type="checkbox" value="1" <?php echo checked( 1, $source_link, false ) ?> />
|
615 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
616 |
-
}
|
617 |
-
|
618 |
-
|
619 |
-
/**
|
620 |
-
* Set text preceding source
|
621 |
-
* @since 3.0
|
622 |
-
*/
|
623 |
-
function wprss_setting_text_preceding_source_callback( $field ) {
|
624 |
-
$text_preceding_source = wprss_get_general_setting( 'text_preceding_source' );
|
625 |
-
?>
|
626 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[text_preceding_source]" type="text" value="<?php echo $text_preceding_source ?>" />
|
627 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
628 |
-
}
|
629 |
-
/**
|
630 |
-
* Enable date
|
631 |
-
* @since 3.0
|
632 |
-
*/
|
633 |
-
function wprss_setting_date_enable_callback( $field ) {
|
634 |
-
$date_enable = wprss_get_general_setting( 'date_enable' );
|
635 |
-
?>
|
636 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[date_enable]" type="checkbox" value="1" <?php echo checked( 1, $date_enable, false ) ?> />
|
637 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
638 |
-
}
|
639 |
-
|
640 |
-
/**
|
641 |
-
* Set text preceding date
|
642 |
-
* @since 3.0
|
643 |
-
*/
|
644 |
-
function wprss_setting_text_preceding_date_callback( $field ) {
|
645 |
-
$text_preceding_date = wprss_get_general_setting( 'text_preceding_date' );
|
646 |
-
?>
|
647 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[text_preceding_date]" type="text" value="<?php echo $text_preceding_date ?>" />
|
648 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
649 |
-
}
|
650 |
-
|
651 |
-
|
652 |
-
/**
|
653 |
-
* Shows the feed item authors option
|
654 |
-
*
|
655 |
-
* @since 4.2.4
|
656 |
-
*/
|
657 |
-
function wprss_setting_authors_enable_callback( $field ) {
|
658 |
-
$authors_enable = wprss_get_general_setting( 'authors_enable' );
|
659 |
-
?>
|
660 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[authors_enable]" type="checkbox" value="1" <?php echo checked( 1, $authors_enable, false ) ?> />
|
661 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
662 |
-
}
|
663 |
-
|
664 |
-
|
665 |
-
/**
|
666 |
-
* Pagination Type
|
667 |
-
*
|
668 |
-
* @since 4.2.3
|
669 |
-
*/
|
670 |
-
function wprss_setting_pagination_type_callback( $field ) {
|
671 |
-
$pagination = wprss_get_general_setting( 'pagination' );
|
672 |
-
$options = array(
|
673 |
-
'default' => __( '"Older posts" and "Newer posts" links', WPRSS_TEXT_DOMAIN ),
|
674 |
-
'numbered' => __( 'Page numbers with "Next" and "Previous" page links', WPRSS_TEXT_DOMAIN ),
|
675 |
-
);
|
676 |
-
?>
|
677 |
-
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[pagination]">
|
678 |
-
<?php
|
679 |
-
foreach( $options as $value => $text ) {
|
680 |
-
$selected = ( $value === $pagination )? 'selected="selected"' : '';
|
681 |
-
?><option value="<?php echo $value ?>" <?php echo $selected ?>><?php echo $text ?></option><?php
|
682 |
-
}
|
683 |
-
?>
|
684 |
-
</select>
|
685 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
686 |
-
}
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
/**
|
691 |
-
* Limit number of feed items stored by their age
|
692 |
-
* @since 3.0
|
693 |
-
*/
|
694 |
-
function wprss_setting_limit_feed_items_age_callback( $field ) {
|
695 |
-
$limit_feed_items_age = wprss_get_general_setting( 'limit_feed_items_age' );
|
696 |
-
$limit_feed_items_age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
|
697 |
-
$units = wprss_age_limit_units();
|
698 |
-
// echo wprss_settings_field_name( $field_info['field_id'], $field_info['section_id'], $field_info['field_name_prefix'] )
|
699 |
-
?>
|
700 |
-
|
701 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_age]" type="number" min="0"
|
702 |
-
class="wprss-number-roller" placeholder="<?php _e( 'No limit', WPRSS_TEXT_DOMAIN ) ?>" value="<?php echo $limit_feed_items_age; ?>" />
|
703 |
-
|
704 |
-
<select id="limit-feed-items-age-unit" name="wprss_settings_general[limit_feed_items_age_unit]">
|
705 |
-
<?php foreach ( $units as $unit ) : ?>
|
706 |
-
<option value="<?php echo $unit ?>" <?php selected( $limit_feed_items_age_unit, $unit ) ?> ><?php _e( $unit, WPRSS_TEXT_DOMAIN ) ?></option>
|
707 |
-
<?php endforeach ?>
|
708 |
-
</select>
|
709 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
710 |
-
|
711 |
-
<br/>
|
712 |
-
<?php
|
713 |
-
}
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
/**
|
718 |
-
* Limit number of feed items stored
|
719 |
-
* @since 3.0
|
720 |
-
*/
|
721 |
-
function wprss_setting_limit_feed_items_callback( $field ) {
|
722 |
-
$limit_feed_items_db = wprss_get_general_setting( 'limit_feed_items_db' );
|
723 |
-
?>
|
724 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_db]" type="text" value="<?php echo $limit_feed_items_db ?>" />
|
725 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
726 |
-
}
|
727 |
-
|
728 |
-
|
729 |
-
/**
|
730 |
-
* Limit number of feed items imported per feed
|
731 |
-
* @since 3.1
|
732 |
-
*/
|
733 |
-
function wprss_setting_limit_feed_items_imported_callback( $field ) {
|
734 |
-
$limit_feed_items_imported = wprss_get_general_setting( 'limit_feed_items_imported' );
|
735 |
-
?>
|
736 |
-
<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 ) ?>" />
|
737 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
738 |
-
}
|
739 |
-
|
740 |
-
|
741 |
-
/**
|
742 |
-
* Gets a sorted (according to interval) list of the cron schedules
|
743 |
-
* @since 3.0
|
744 |
-
*/
|
745 |
-
function wprss_get_schedules() {
|
746 |
-
$schedules = wp_get_schedules();
|
747 |
-
uasort( $schedules, create_function( '$a,$b', 'return $a["interval"]-$b["interval"];' ) );
|
748 |
-
return $schedules;
|
749 |
-
}
|
750 |
-
|
751 |
-
|
752 |
-
/**
|
753 |
-
* Cron interval dropdown callback
|
754 |
-
* @since 3.0
|
755 |
-
*/
|
756 |
-
function wprss_setting_cron_interval_callback( $field ) {
|
757 |
-
$options = get_option( 'wprss_settings_general' );
|
758 |
-
$current = $options['cron_interval'];
|
759 |
-
|
760 |
-
$schedules = wprss_get_schedules();
|
761 |
-
// Set the allowed Cron schedules, we don't want any intervals that can lead to issues with server load
|
762 |
-
$wprss_schedules = apply_filters(
|
763 |
-
'wprss_schedules',
|
764 |
-
array( 'fifteen_min', 'thirty_min', 'hourly', 'two_hours', 'twicedaily', 'daily' )
|
765 |
-
);
|
766 |
-
?>
|
767 |
-
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[cron_interval]">
|
768 |
-
<?php
|
769 |
-
foreach( $schedules as $schedule_name => $schedule_data ):
|
770 |
-
if ( in_array( $schedule_name, $wprss_schedules ) ): ?>
|
771 |
-
<option value="<?php echo $schedule_name ?>" <?php selected( $current, $schedule_name ) ?> >
|
772 |
-
<?php echo $schedule_data['display'] ?> (<?php echo wprss_interval( $schedule_data['interval'] ) ?>)
|
773 |
-
</option>
|
774 |
-
<?php endif ?>
|
775 |
-
<?php endforeach ?>
|
776 |
-
</select>
|
777 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?><?php
|
778 |
-
}
|
779 |
-
|
780 |
-
/**
|
781 |
-
* Sets the custom feed URL
|
782 |
-
* @since 3.3
|
783 |
-
*/
|
784 |
-
function wprss_settings_custom_feed_url_callback( $field ) {
|
785 |
-
$custom_feed_url = wprss_get_general_setting( 'custom_feed_url' );
|
786 |
-
?>
|
787 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_url]" type="text" value="<?php echo $custom_feed_url ?>" />
|
788 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
789 |
-
}
|
790 |
-
|
791 |
-
/**
|
792 |
-
* Sets the custom feed title
|
793 |
-
* @since 4.1.2
|
794 |
-
*/
|
795 |
-
function wprss_settings_custom_feed_title_callback( $field ) {
|
796 |
-
$custom_feed_title = wprss_get_general_setting( 'custom_feed_title' );
|
797 |
-
?>
|
798 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_title]" type="text" value="<?php echo $custom_feed_title ?>" />
|
799 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
800 |
-
}
|
801 |
-
|
802 |
-
/**
|
803 |
-
* Sets the custom feed limit
|
804 |
-
* @since 3.3
|
805 |
-
*/
|
806 |
-
function wprss_setings_custom_feed_limit_callback( $field ) {
|
807 |
-
$custom_feed_limit = wprss_get_general_setting( 'custom_feed_limit' );
|
808 |
-
?>
|
809 |
-
<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 ?>" />
|
810 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
811 |
-
}
|
812 |
-
|
813 |
-
/**
|
814 |
-
* Disable styles
|
815 |
-
* @since 3.0
|
816 |
-
*/
|
817 |
-
function wprss_setting_styles_disable_callback( $field ) {
|
818 |
-
$styles_disable = wprss_get_general_setting( 'styles_disable' );
|
819 |
-
?>
|
820 |
-
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[styles_disable]" type="checkbox" value="1" <?php echo checked( 1, $styles_disable, false ) ?> />
|
821 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
822 |
-
}
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
/**
|
827 |
-
* Secure Reset section
|
828 |
-
*
|
829 |
-
* @since 3.7.1
|
830 |
-
*/
|
831 |
-
function wprss_settings_secure_reset_code_callback( $args ) {
|
832 |
-
$reset_code = get_option( 'wprss_secure_reset_code', '' );
|
833 |
-
?>
|
834 |
-
<input id="wprss-secure-reset-code" name="wprss_secure_reset_code" type="input" value="<?php echo $reset_code; ?>" />
|
835 |
-
<button type="button" role="button" id="wprss-secure-reset-generate"><?php _e( 'Generate Random Code', WPRSS_TEXT_DOMAIN ) ?></button>
|
836 |
-
|
837 |
-
<br/>
|
838 |
-
|
839 |
-
<label class="description" for="wprss-secure-reset-code">
|
840 |
-
<?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/>
|
841 |
-
</label>
|
842 |
-
|
843 |
-
<br/>
|
844 |
-
|
845 |
-
<p>
|
846 |
-
<?php _e( 'Leave this empty to disable the secure reset function.<br/>
|
847 |
-
You use this code by adding any of the following to any URL on your site.', WPRSS_TEXT_DOMAIN ) ?>
|
848 |
-
<ol>
|
849 |
-
<li>"?wprss_action=reset&wprss_security_code=<your_code>" - <b><?php _e( 'Resets your WP RSS Aggregator settings', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
850 |
-
<li>"?wprss_action=deactivate&wprss_security_code=<your_code>" - <b><?php _e( 'Deactivates WP RSS Aggregator', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
851 |
-
<li>"?wprss_action=reset_and_deactivate&wprss_security_code=<your_code>" - <b><?php _e( 'Does both of the above', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
852 |
-
</ol>
|
853 |
-
</p>
|
854 |
-
<p class="description">
|
855 |
-
<?php _e( 'Use the above actions only when absolutely necessary, or when instructed to by support staff.', WPRSS_TEXT_DOMAIN ) ?>
|
856 |
-
</p>
|
857 |
-
<?php
|
858 |
-
}
|
859 |
-
|
860 |
-
|
861 |
-
/**
|
862 |
-
* Tracking checkbox
|
863 |
-
* @since 3.6
|
864 |
-
*/
|
865 |
-
function wprss_tracking_callback( $field ) {
|
866 |
-
$tracking = wprss_get_general_setting( 'tracking' );
|
867 |
-
?>
|
868 |
-
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[tracking]" value="1" <?php echo checked( 1, $tracking, false ) ?> />
|
869 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
870 |
-
<label class="description" for="<?php echo $field['field_id'] ?>">
|
871 |
-
<?php _e( 'Please help us improve WP RSS Aggregator by allowing us to gather anonymous usage statistics. No sensitive data is collected.', WPRSS_TEXT_DOMAIN ) ?>
|
872 |
-
</label>
|
873 |
-
<?php
|
874 |
-
}
|
875 |
-
|
876 |
-
/**
|
877 |
-
* Time ago format checkbox
|
878 |
-
* @since 4.2
|
879 |
-
*/
|
880 |
-
function wprss_setting_time_ago_format_enable_callback( $field ) {
|
881 |
-
$time_ago_format = wprss_get_general_setting( 'time_ago_format_enable' );
|
882 |
-
?>
|
883 |
-
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[time_ago_format_enable]" value="1" <?php echo checked( 1, $time_ago_format, false ) ?> />
|
884 |
-
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
885 |
-
}
|
886 |
-
|
887 |
-
|
888 |
-
/**
|
889 |
-
* Pretty-prints the difference in two times.
|
890 |
-
*
|
891 |
-
* @since 3.0
|
892 |
-
* @param time $older_date
|
893 |
-
* @param time $newer_date
|
894 |
-
* @return string The pretty time_since value
|
895 |
-
* @link http://wordpress.org/extend/plugins/wp-crontrol/
|
896 |
-
*/
|
897 |
-
function wprss_time_since( $older_date, $newer_date ) {
|
898 |
-
return wprss_interval( $newer_date - $older_date );
|
899 |
-
}
|
900 |
-
|
901 |
-
/**
|
902 |
-
* Calculates difference between times
|
903 |
-
*
|
904 |
-
* Taken from the WP-Crontrol plugin
|
905 |
-
* @link http://wordpress.org/extend/plugins/wp-crontrol/
|
906 |
-
* @since 3.0
|
907 |
-
*
|
908 |
-
*/
|
909 |
-
function wprss_interval( $since ) {
|
910 |
-
if ( $since === wprss_get_default_feed_source_update_interval() ) {
|
911 |
-
return __( 'Default', WPRSS_TEXT_DOMAIN );
|
912 |
-
}
|
913 |
-
// array of time period chunks
|
914 |
-
$chunks = array(
|
915 |
-
array(60 * 60 * 24 * 365 , _n_noop('%s year', '%s years', 'crontrol')),
|
916 |
-
array(60 * 60 * 24 * 30 , _n_noop('%s month', '%s months', 'crontrol')),
|
917 |
-
array(60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'crontrol')),
|
918 |
-
array(60 * 60 * 24 , _n_noop('%s day', '%s days', 'crontrol')),
|
919 |
-
array(60 * 60 , _n_noop('%s hour', '%s hours', 'crontrol')),
|
920 |
-
array(60 , _n_noop('%s minute', '%s minutes', 'crontrol')),
|
921 |
-
array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
|
922 |
-
);
|
923 |
-
|
924 |
-
|
925 |
-
if( $since <= 0 ) {
|
926 |
-
return __( 'now', WPRSS_TEXT_DOMAIN );
|
927 |
-
}
|
928 |
-
|
929 |
-
// we only want to output two chunks of time here, eg:
|
930 |
-
// x years, xx months
|
931 |
-
// x days, xx hours
|
932 |
-
// so there's only two bits of calculation below:
|
933 |
-
|
934 |
-
// step one: the first chunk
|
935 |
-
for ($i = 0, $j = count($chunks); $i < $j; $i++)
|
936 |
-
{
|
937 |
-
$seconds = $chunks[$i][0];
|
938 |
-
$name = $chunks[$i][1];
|
939 |
-
|
940 |
-
// finding the biggest chunk (if the chunk fits, break)
|
941 |
-
if (($count = floor($since / $seconds)) != 0)
|
942 |
-
{
|
943 |
-
break;
|
944 |
-
}
|
945 |
-
}
|
946 |
-
|
947 |
-
// set output var
|
948 |
-
$output = sprintf(_n($name[0], $name[1], $count, WPRSS_TEXT_DOMAIN), $count);
|
949 |
-
|
950 |
-
// step two: the second chunk
|
951 |
-
if ($i + 1 < $j)
|
952 |
-
{
|
953 |
-
$seconds2 = $chunks[$i + 1][0];
|
954 |
-
$name2 = $chunks[$i + 1][1];
|
955 |
-
|
956 |
-
if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
|
957 |
-
{
|
958 |
-
// add to output var
|
959 |
-
$output .= ' '.sprintf(_n($name2[0], $name2[1], $count2, WPRSS_TEXT_DOMAIN), $count2);
|
960 |
-
}
|
961 |
-
}
|
962 |
-
|
963 |
-
return $output;
|
964 |
-
}
|
965 |
-
|
966 |
-
|
967 |
-
/**
|
968 |
-
* Validate inputs from the general settings page
|
969 |
-
* @since 3.0
|
970 |
-
*/
|
971 |
-
function wprss_settings_general_validate( $input ) {
|
972 |
-
$options = get_option( 'wprss_settings_general' );
|
973 |
-
$current_cron_interval = $options['cron_interval'];
|
974 |
-
|
975 |
-
// Create our array for storing the validated options
|
976 |
-
$output = array();
|
977 |
-
|
978 |
-
// Loop through each of the incoming options
|
979 |
-
foreach( $input as $key => $value ) {
|
980 |
-
|
981 |
-
// Check to see if the current option has a value. If so, process it.
|
982 |
-
if( isset( $input[ $key ] ) ) {
|
983 |
-
|
984 |
-
// Strip all HTML and PHP tags and properly handle quoted strings
|
985 |
-
$output[ $key ] = strip_tags( stripslashes( $input[ $key ] ) );
|
986 |
-
|
987 |
-
} // end if
|
988 |
-
|
989 |
-
} // end foreach
|
990 |
-
|
991 |
-
// If limit_feed_items_age_unit is not set or it set to zero, set it to empty
|
992 |
-
if ( ! isset( $input['limit_feed_items_age'] ) || strval( $input['limit_feed_items_age'] ) == '0' ) {
|
993 |
-
$output['limit_feed_items_age'] = '';
|
994 |
-
}
|
995 |
-
|
996 |
-
if ( ! isset( $input['title_link'] ) || $input['title_link'] != '1' )
|
997 |
-
$output['title_link'] = 0;
|
998 |
-
else
|
999 |
-
$output['title_link'] = 1;
|
1000 |
-
|
1001 |
-
if ( ! isset( $input['source_enable'] ) || $input['source_enable'] != '1' )
|
1002 |
-
$output['source_enable'] = 0;
|
1003 |
-
else
|
1004 |
-
$output['source_enable'] = 1;
|
1005 |
-
|
1006 |
-
if ( ! isset( $input['date_enable'] ) || $input['date_enable'] != '1' )
|
1007 |
-
$output['date_enable'] = 0;
|
1008 |
-
else
|
1009 |
-
$output['date_enable'] = 1;
|
1010 |
-
|
1011 |
-
if ( ! isset( $input['styles_disable'] ) || $input['styles_disable'] != '1' )
|
1012 |
-
$output['styles_disable'] = 0;
|
1013 |
-
else
|
1014 |
-
$output['styles_disable'] = 1;
|
1015 |
-
|
1016 |
-
if ( ! isset( $input['video_link'] ) || strtolower( $input['video_link'] ) !== 'true' )
|
1017 |
-
$output['video_link'] = 'false';
|
1018 |
-
else
|
1019 |
-
$output['video_link'] = 'true';
|
1020 |
-
|
1021 |
-
if ( $input['cron_interval'] != $current_cron_interval ) {
|
1022 |
-
wp_clear_scheduled_hook( 'wprss_fetch_all_feeds_hook' );
|
1023 |
-
wp_schedule_event( time(), $input['cron_interval'], 'wprss_fetch_all_feeds_hook' );
|
1024 |
-
}
|
1025 |
-
|
1026 |
-
// Return the array processing any additional functions filtered by this action
|
1027 |
-
return apply_filters( 'wprss_settings_general_validate', $output, $input );
|
1028 |
-
}
|
1029 |
-
|
1030 |
-
|
1031 |
-
/**
|
1032 |
-
* Validates the licenses settings
|
1033 |
-
*
|
1034 |
-
* @since 3.8
|
1035 |
-
*/
|
1036 |
-
function wprss_settings_license_keys_validate( $input ) {
|
1037 |
-
// Get the current licenses option
|
1038 |
-
$licenses = get_option( 'wprss_settings_license_keys' );
|
1039 |
-
// If no licenses have been defined yet, create an empty array
|
1040 |
-
if ( !is_array( $licenses ) ) {
|
1041 |
-
$licenses = array();
|
1042 |
-
}
|
1043 |
-
// For each entry in the received input
|
1044 |
-
foreach ( $input as $addon => $license_code ) {
|
1045 |
-
$addon_code = explode( '_', $addon );
|
1046 |
-
$addon_code = isset( $addon_code[0] ) ? $addon_code[0] : null;
|
1047 |
-
// Only save if the entry does not exist OR the code is different
|
1048 |
-
if ( array_key_exists( $addon, $licenses ) && $license_code === $licenses[ $addon ] )
|
1049 |
-
continue;
|
1050 |
-
|
1051 |
-
$is_valid = apply_filters( 'wprss_settings_license_key_is_valid', true, $license_code );
|
1052 |
-
if( $addon_code )
|
1053 |
-
$is_valid = apply_filters( "wprss_settings_license_key_{$addon_code}_is_valid", $is_valid, $license_code );
|
1054 |
-
if( !$is_valid ) continue;
|
1055 |
-
|
1056 |
-
// Save it to the licenses option
|
1057 |
-
$licenses[ $addon ] = $license_code;
|
1058 |
-
}
|
1059 |
-
wprss_check_license_statuses();
|
1060 |
-
// Return the new licenses
|
1061 |
-
return $licenses;
|
1062 |
-
}
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
add_action( 'wprss_check_license_statuses', 'wprss_check_license_statuses' );
|
1067 |
-
/**
|
1068 |
-
* Checks the license statuses
|
1069 |
-
*
|
1070 |
-
* @since 3.8.1
|
1071 |
-
*/
|
1072 |
-
function wprss_check_license_statuses() {
|
1073 |
-
$license_statuses = get_option( 'wprss_settings_license_statuses', array() );
|
1074 |
-
|
1075 |
-
if ( count( $license_statuses ) === 0 ) return;
|
1076 |
-
|
1077 |
-
$found_inactive = FALSE;
|
1078 |
-
foreach ( $license_statuses as $addon => $status ) {
|
1079 |
-
if ( $status !== 'active' ) {
|
1080 |
-
$found_inactive = TRUE;
|
1081 |
-
break;
|
1082 |
-
}
|
1083 |
-
}
|
1084 |
-
|
1085 |
-
if ( $found_inactive ) {
|
1086 |
-
set_transient( 'wprss_notify_inactive_licenses', 1, 0 );
|
1087 |
-
}
|
1088 |
-
}
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
/**
|
1093 |
-
* Validates the wprss_secure_reset_code option
|
1094 |
-
*
|
1095 |
-
* @since 3.7.1
|
1096 |
-
*/
|
1097 |
-
function wprss_secure_reset_code_validate( $input ) {
|
1098 |
-
return $input;
|
1099 |
-
}
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
/**
|
1104 |
-
* Validates the presstrends setting
|
1105 |
-
*
|
1106 |
-
* @since 3.6
|
1107 |
-
*/
|
1108 |
-
function wprss_tracking_validate ( $input ) {
|
1109 |
-
$output = $input;
|
1110 |
-
if ( ! isset( $input['wprss_tracking'] ) ) {
|
1111 |
-
$output['wprss_tracking'] = 0;
|
1112 |
-
}
|
1113 |
-
return $output;
|
1114 |
-
}
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
/**
|
1119 |
-
* Returns the units used for the limit by age option.
|
1120 |
-
*
|
1121 |
-
* @since 3.8
|
1122 |
-
*/
|
1123 |
-
function wprss_age_limit_units() {
|
1124 |
-
return apply_filters(
|
1125 |
-
'wprss_age_limit_units',
|
1126 |
-
array(
|
1127 |
-
'days',
|
1128 |
-
'weeks',
|
1129 |
-
'months',
|
1130 |
-
'years'
|
1131 |
-
)
|
1132 |
-
);
|
1133 |
}
|
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 option_name The name of the option to get
|
18 |
+
* @return mixed
|
19 |
+
* @since 3.7.1
|
20 |
+
*/
|
21 |
+
function wprss_get_general_setting( $option_name ) {
|
22 |
+
$options = get_option( 'wprss_settings_general', array() );
|
23 |
+
$defaults = wprss_get_default_settings_general();
|
24 |
+
return ( ( isset( $options[ $option_name ] ) )? $options[$option_name] : $defaults[$option_name] );
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
add_action( 'admin_init', 'wprss_admin_init' );
|
29 |
+
/**
|
30 |
+
* Register and define options and settings
|
31 |
+
* @since 2.0
|
32 |
+
* @todo add option for cron frequency
|
33 |
+
*
|
34 |
+
* Note: In the future might change to
|
35 |
+
* the way EDD builds the settings pages, cleaner method.
|
36 |
+
*/
|
37 |
+
function wprss_admin_init() {
|
38 |
+
|
39 |
+
register_setting(
|
40 |
+
'wprss_settings_general', // A settings group name.
|
41 |
+
'wprss_settings_general', // The name of an option to sanitize and save.
|
42 |
+
'wprss_settings_general_validate' // A callback function that sanitizes the option's value.
|
43 |
+
);
|
44 |
+
|
45 |
+
// Licensing of add-ons
|
46 |
+
register_setting(
|
47 |
+
'wprss_settings_license_keys',
|
48 |
+
'wprss_settings_license_keys',
|
49 |
+
'wprss_settings_license_keys_validate'
|
50 |
+
);
|
51 |
+
|
52 |
+
|
53 |
+
$sections = apply_filters(
|
54 |
+
'wprss_settings_sections_array',
|
55 |
+
array(
|
56 |
+
'general' => __( 'General plugin settings', WPRSS_TEXT_DOMAIN ),
|
57 |
+
'display' => __( 'General display settings', WPRSS_TEXT_DOMAIN ),
|
58 |
+
'source' => __( 'Source display settings', WPRSS_TEXT_DOMAIN ),
|
59 |
+
'date' => __( 'Date display settings', WPRSS_TEXT_DOMAIN ),
|
60 |
+
'styles' => __( 'Styles', WPRSS_TEXT_DOMAIN ),
|
61 |
+
)
|
62 |
+
);
|
63 |
+
|
64 |
+
// Define the settings per section
|
65 |
+
$settings = apply_filters(
|
66 |
+
'wprss_settings_array',
|
67 |
+
array(
|
68 |
+
'general' => array(
|
69 |
+
'limit-feed-items-by-age' => array(
|
70 |
+
'label' => __( 'Limit feed items by age', WPRSS_TEXT_DOMAIN ),
|
71 |
+
'callback' => 'wprss_setting_limit_feed_items_age_callback'
|
72 |
+
),
|
73 |
+
'limit-feed-items-db' => array(
|
74 |
+
'label' => __( 'Limit feed items stored', WPRSS_TEXT_DOMAIN ),
|
75 |
+
'callback' => 'wprss_setting_limit_feed_items_callback'
|
76 |
+
),
|
77 |
+
'limit-feed-items-imported' => array(
|
78 |
+
'label' => __( 'Limit feed items per feed', WPRSS_TEXT_DOMAIN ),
|
79 |
+
'callback' => 'wprss_setting_limit_feed_items_imported_callback'
|
80 |
+
),
|
81 |
+
'cron-interval' => array(
|
82 |
+
'label' => __( 'Feed processing interval', WPRSS_TEXT_DOMAIN ),
|
83 |
+
'callback' => 'wprss_setting_cron_interval_callback'
|
84 |
+
),
|
85 |
+
'custom-feed-url' => array(
|
86 |
+
'label' => __( 'Custom feed URL', WPRSS_TEXT_DOMAIN ),
|
87 |
+
'callback' => 'wprss_settings_custom_feed_url_callback'
|
88 |
+
),
|
89 |
+
'custom-feed-title' => array(
|
90 |
+
'label' => __( 'Custom feed Title', WPRSS_TEXT_DOMAIN ),
|
91 |
+
'callback' => 'wprss_settings_custom_feed_title_callback'
|
92 |
+
),
|
93 |
+
'custom-feed-limit' => array(
|
94 |
+
'label' => __( 'Custom feed limit', WPRSS_TEXT_DOMAIN ),
|
95 |
+
'callback' => 'wprss_setings_custom_feed_limit_callback'
|
96 |
+
),
|
97 |
+
'tracking' => array(
|
98 |
+
'label' => __( 'Anonymous tracking', WPRSS_TEXT_DOMAIN ),
|
99 |
+
'callback' => 'wprss_tracking_callback',
|
100 |
+
)
|
101 |
+
),
|
102 |
+
|
103 |
+
'display' => array(
|
104 |
+
// Title options
|
105 |
+
'link-enable' => array(
|
106 |
+
'label' => __( 'Link title', WPRSS_TEXT_DOMAIN ),
|
107 |
+
'callback' => 'wprss_setting_title_link_callback'
|
108 |
+
),
|
109 |
+
'title-limit' => array(
|
110 |
+
'label' => __( 'Title maximum length', WPRSS_TEXT_DOMAIN ),
|
111 |
+
'callback' => 'wprss_setting_title_length_callback'
|
112 |
+
),
|
113 |
+
|
114 |
+
|
115 |
+
|
116 |
+
// Misc Options
|
117 |
+
'authors-enable' => array(
|
118 |
+
'label' => __( 'Show authors', WPRSS_TEXT_DOMAIN ),
|
119 |
+
'callback' => 'wprss_setting_authors_enable_callback',
|
120 |
+
),
|
121 |
+
'video-links' => array(
|
122 |
+
'label' => __( 'For video feed items use', WPRSS_TEXT_DOMAIN ),
|
123 |
+
'callback' => 'wprss_setting_video_links_callback'
|
124 |
+
),
|
125 |
+
'pagination' => array(
|
126 |
+
'label' => __( 'Pagination type', WPRSS_TEXT_DOMAIN ),
|
127 |
+
'callback' => 'wprss_setting_pagination_type_callback',
|
128 |
+
),
|
129 |
+
'feed-limit' => array(
|
130 |
+
'label' => __( 'Feed display limit', WPRSS_TEXT_DOMAIN ),
|
131 |
+
'callback' => 'wprss_setting_feed_limit_callback'
|
132 |
+
),
|
133 |
+
'open-dd' => array(
|
134 |
+
'label' => __( 'Open links behaviour', WPRSS_TEXT_DOMAIN ),
|
135 |
+
'callback' => 'wprss_setting_open_dd_callback'
|
136 |
+
),
|
137 |
+
'follow-dd' => array(
|
138 |
+
'label' => __( 'Set links as nofollow', WPRSS_TEXT_DOMAIN ),
|
139 |
+
'callback' => 'wprss_setting_follow_dd_callback'
|
140 |
+
),
|
141 |
+
),
|
142 |
+
|
143 |
+
// Source Options
|
144 |
+
'source' => array(
|
145 |
+
'source-enable' => array(
|
146 |
+
'label' => __( 'Show source', WPRSS_TEXT_DOMAIN ),
|
147 |
+
'callback' => 'wprss_setting_source_enable_callback'
|
148 |
+
),
|
149 |
+
'text-preceding-source' => array(
|
150 |
+
'label' => __( 'Text preceding source', WPRSS_TEXT_DOMAIN ),
|
151 |
+
'callback' => 'wprss_setting_text_preceding_source_callback'
|
152 |
+
),
|
153 |
+
'source-link' => array(
|
154 |
+
'label' => __( 'Link source', WPRSS_TEXT_DOMAIN ),
|
155 |
+
'callback' => 'wprss_setting_source_link_callback'
|
156 |
+
),
|
157 |
+
),
|
158 |
+
|
159 |
+
// Date options
|
160 |
+
'date' => array(
|
161 |
+
'date-enable' => array(
|
162 |
+
'label' => __( 'Show date', WPRSS_TEXT_DOMAIN ),
|
163 |
+
'callback' => 'wprss_setting_date_enable_callback'
|
164 |
+
),
|
165 |
+
'text-preceding-date' => array(
|
166 |
+
'label' => __( 'Text preceding date', WPRSS_TEXT_DOMAIN ),
|
167 |
+
'callback' => 'wprss_setting_text_preceding_date_callback'
|
168 |
+
),
|
169 |
+
'date-format' => array(
|
170 |
+
'label' => __( 'Date format', WPRSS_TEXT_DOMAIN ),
|
171 |
+
'callback' => 'wprss_setting_date_format_callback'
|
172 |
+
),
|
173 |
+
'time-ago-format-enable' => array(
|
174 |
+
'label' => __( 'Time ago format', WPRSS_TEXT_DOMAIN ),
|
175 |
+
'callback' => 'wprss_setting_time_ago_format_enable_callback'
|
176 |
+
),
|
177 |
+
),
|
178 |
+
|
179 |
+
'styles' => array(
|
180 |
+
'styles-disable' => array(
|
181 |
+
'label' => __( 'Disable Styles', WPRSS_TEXT_DOMAIN ),
|
182 |
+
'callback' => 'wprss_setting_styles_disable_callback'
|
183 |
+
)
|
184 |
+
)
|
185 |
+
)
|
186 |
+
);
|
187 |
+
|
188 |
+
if ( apply_filters( 'wprss_use_fixed_feed_limit', FALSE ) === FALSE ) {
|
189 |
+
unset( $settings['general']['limit-feed-items-db'] );
|
190 |
+
}
|
191 |
+
|
192 |
+
$setting_field_id_prefix = 'wprss-settings-';
|
193 |
+
|
194 |
+
|
195 |
+
// Loop through each setting field and register it
|
196 |
+
foreach( $settings as $section => $fields ) {
|
197 |
+
if ( count( $fields ) > 0 ) {
|
198 |
+
$section_desc = $sections[ $section ];
|
199 |
+
add_settings_section(
|
200 |
+
"wprss_settings_${section}_section",
|
201 |
+
$section_desc,
|
202 |
+
"wprss_settings_${section}_callback",
|
203 |
+
'wprss_settings_general'
|
204 |
+
);
|
205 |
+
|
206 |
+
foreach ( $fields as $id => $data ) {
|
207 |
+
|
208 |
+
/**
|
209 |
+
* @var This will be passed to the field callback as the only argument
|
210 |
+
* @see http://codex.wordpress.org/Function_Reference/add_settings_field#Parameters
|
211 |
+
*/
|
212 |
+
$callback_args = array(
|
213 |
+
'field_id' => $id,
|
214 |
+
'field_id_prefix' => $setting_field_id_prefix,
|
215 |
+
'section_id' => $section,
|
216 |
+
'field_label' => isset( $data['label'] ) ? $data['label'] : null,
|
217 |
+
'tooltip' => isset( $data['tooltip'] ) ? $data['tooltip'] : null
|
218 |
+
);
|
219 |
+
|
220 |
+
|
221 |
+
add_settings_field(
|
222 |
+
$setting_field_id_prefix . $id,
|
223 |
+
$data['label'],
|
224 |
+
$data['callback'],
|
225 |
+
'wprss_settings_general',
|
226 |
+
"wprss_settings_${section}_section",
|
227 |
+
$callback_args
|
228 |
+
);
|
229 |
+
|
230 |
+
}
|
231 |
+
}
|
232 |
+
}
|
233 |
+
|
234 |
+
|
235 |
+
/*
|
236 |
+
// SECURE RESET OPTION
|
237 |
+
register_setting(
|
238 |
+
'wprss_secure_reset', // A settings group name.
|
239 |
+
'wprss_secure_reset_code', // The name of an option to sanitize and save.
|
240 |
+
'' // A callback function that sanitizes the option's value.
|
241 |
+
);
|
242 |
+
add_settings_section(
|
243 |
+
'wprss_secure_reset_section', // ID of section
|
244 |
+
__( 'Secure Reset', WPRSS_TEXT_DOMAIN ), // Title of section
|
245 |
+
'wprss_secure_reset_section_callback', // Callback that renders the section header
|
246 |
+
'wprss_settings_general' // The page on which to display the section
|
247 |
+
);
|
248 |
+
add_settings_field(
|
249 |
+
'wprss-settings-secure-reset', // ID of setting
|
250 |
+
__( 'Secure Reset', WPRSS_TEXT_DOMAIN ), // The title of the setting
|
251 |
+
'wprss_settings_secure_reset_code_callback', // The callback that renders the setting
|
252 |
+
'wprss_settings_general', // The page on which to display the setting
|
253 |
+
"wprss_secure_reset_section" // The section in which to display the setting
|
254 |
+
);
|
255 |
+
*/
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
do_action( 'wprss_admin_init' );
|
260 |
+
}
|
261 |
+
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Returns the HTML of a tooltip handle.
|
265 |
+
*
|
266 |
+
* Filters used:
|
267 |
+
* - `wprss_settings_inline_help_default_options` - The default options for "Settings" page's tooltips
|
268 |
+
* - `wprss_settings_inline_help_id_prefix` - The prefix for all tooltip IDs for the "Settings" page.
|
269 |
+
*
|
270 |
+
* @param string $id The ID of the tooltip
|
271 |
+
* @param string|null $text Text for this tooltip, if any.
|
272 |
+
* @param array $options Any options for this setting.
|
273 |
+
* @return string Tooltip handle HTML. See {@link WPRSS_Help::tooltip()}.
|
274 |
+
*/
|
275 |
+
function wprss_settings_inline_help( $id, $text = null, $options = array() ) {
|
276 |
+
$help = WPRSS_Help::get_instance();
|
277 |
+
|
278 |
+
// Default options, entry point
|
279 |
+
$defaults = apply_filters( 'wprss_settings_inline_help_default_options', array(
|
280 |
+
'tooltip_handle_class_extra' => $help->get_options('tooltip_handle_class_extra') . ' ' . $help->get_options('tooltip_handle_class') . '-setting'
|
281 |
+
));
|
282 |
+
|
283 |
+
$options = $help->array_merge_recursive_distinct( $defaults, $options );
|
284 |
+
|
285 |
+
// ID Prefix
|
286 |
+
$id = apply_filters( 'wprss_settings_inline_help_id_prefix', 'setting-' ) . $id;
|
287 |
+
|
288 |
+
return $help->tooltip( $id, $text, $options );
|
289 |
+
}
|
290 |
+
|
291 |
+
|
292 |
+
/**
|
293 |
+
*
|
294 |
+
* @param type $string
|
295 |
+
* @return type
|
296 |
+
*/
|
297 |
+
function wprss_settings_field_name_prefix( $string = '' ) {
|
298 |
+
$string = (string) $string;
|
299 |
+
$prefix = apply_filters( 'wprss_settings_field_name_prefix', 'wprss_settings_', $string );
|
300 |
+
return $prefix . $string;
|
301 |
+
}
|
302 |
+
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Generates a uniform setting field name for use in HTML.
|
306 |
+
* The parts used are the ID of the field, the section it is in, and an optional prefix.
|
307 |
+
* All parts are optional, but, if they appear, they shall appear in this order: $prefix, $section, $id.
|
308 |
+
*
|
309 |
+
* If only the section is not specified, the $id will be simply prefixed by $prefix.
|
310 |
+
* If either the $id or the $section are empty (but not both), $prefix will be stripped of known separators.
|
311 |
+
* Empty parts will be excluded.
|
312 |
+
*
|
313 |
+
* @param string $id ID of the field.
|
314 |
+
* @param string|null $section Name of the section, to which this field belongs.
|
315 |
+
* @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()}.
|
316 |
+
* @return string Name of the settings field, namespaced and optionally prefixed.
|
317 |
+
*/
|
318 |
+
function wprss_settings_field_name( $id = null, $section = null, $prefix = null ) {
|
319 |
+
if( $prefix !== false ) $prefix = is_null( $prefix ) ? wprss_settings_field_name_prefix() : $prefix;
|
320 |
+
else $prefix = '';
|
321 |
+
|
322 |
+
$section = (string) $section;
|
323 |
+
|
324 |
+
$format = '';
|
325 |
+
if( !strlen( $section ) xor !strlen($id) ) $prefix = trim ( $prefix, "\t\n\r _-:" );
|
326 |
+
if( strlen( $prefix ) ) $format .= '%3$s';
|
327 |
+
if( strlen( $section ) ) $format .= '%2$s';
|
328 |
+
if( strlen( $id ) ) $format .= ( !strlen( $section ) ? '%1$s' : '[%1$s]' );
|
329 |
+
|
330 |
+
return apply_filters( 'wprss_settings_field_name', sprintf( $format, $id, $section, $prefix ), $id, $section, $prefix );
|
331 |
+
}
|
332 |
+
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Build the plugin settings page, used to save general settings like whether a link should be follow or no follow
|
336 |
+
* @since 1.1
|
337 |
+
*/
|
338 |
+
function wprss_settings_page_display() {
|
339 |
+
?>
|
340 |
+
<div class="wrap">
|
341 |
+
<?php screen_icon( 'wprss-aggregator' ); ?>
|
342 |
+
|
343 |
+
<h2><?php _e( 'WP RSS Aggregator Settings', WPRSS_TEXT_DOMAIN ); ?></h2>
|
344 |
+
|
345 |
+
<?php settings_errors(); ?>
|
346 |
+
|
347 |
+
<?php $active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general_settings'; ?>
|
348 |
+
|
349 |
+
<?php
|
350 |
+
|
351 |
+
$default_tabs = array(
|
352 |
+
'general' => array(
|
353 |
+
'label' => __( 'General', WPRSS_TEXT_DOMAIN ),
|
354 |
+
'slug' => 'general_settings',
|
355 |
+
),
|
356 |
+
'licenses' => array(
|
357 |
+
'label' => __( 'Licenses', WPRSS_TEXT_DOMAIN ),
|
358 |
+
'slug' => 'licenses_settings'
|
359 |
+
)
|
360 |
+
);
|
361 |
+
|
362 |
+
$addon_tabs = apply_filters( 'wprss_options_tabs', array() );
|
363 |
+
|
364 |
+
$tabs = array_merge( array( $default_tabs['general'] ), $addon_tabs , array( $default_tabs['licenses'] ) );
|
365 |
+
|
366 |
+
$show_tabs = ( count( $addon_tabs ) > 0 ) || apply_filters( 'wprss_show_settings_tabs_condition', FALSE );
|
367 |
+
|
368 |
+
if ( $show_tabs ) { ?>
|
369 |
+
<h2 class="nav-tab-wrapper">
|
370 |
+
<?php
|
371 |
+
foreach ( $tabs as $tab => $tab_property ) { ?>
|
372 |
+
<a href="?post_type=wprss_feed&page=wprss-aggregator-settings&tab=<?php echo esc_attr( $tab_property['slug'] ); ?>"
|
373 |
+
class="nav-tab <?php echo $active_tab == $tab_property['slug'] ? 'nav-tab-active' : ''; ?>"><?php echo esc_html( $tab_property['label'] ); ?></a>
|
374 |
+
<?php } ?>
|
375 |
+
<?php } ?>
|
376 |
+
</h2>
|
377 |
+
|
378 |
+
<form action="options.php" method="post">
|
379 |
+
|
380 |
+
<?php
|
381 |
+
|
382 |
+
if ( $active_tab === 'general_settings' ) {
|
383 |
+
settings_fields( 'wprss_settings_general' );
|
384 |
+
//settings_fields( 'wprss_secure_reset' );
|
385 |
+
do_settings_sections( 'wprss_settings_general' );
|
386 |
+
}
|
387 |
+
elseif ( $show_tabs ) {
|
388 |
+
|
389 |
+
if ( $active_tab === 'licenses_settings' ) {
|
390 |
+
settings_fields( 'wprss_settings_license_keys' );
|
391 |
+
do_settings_sections( 'wprss_settings_license_keys' );
|
392 |
+
}
|
393 |
+
|
394 |
+
do_action( 'wprss_add_settings_fields_sections', $active_tab );
|
395 |
+
}
|
396 |
+
|
397 |
+
submit_button( __( 'Save Settings', WPRSS_TEXT_DOMAIN ) );
|
398 |
+
|
399 |
+
?>
|
400 |
+
</form>
|
401 |
+
</div>
|
402 |
+
<?php
|
403 |
+
}
|
404 |
+
|
405 |
+
|
406 |
+
/**
|
407 |
+
* General settings section header
|
408 |
+
* @since 3.0
|
409 |
+
*/
|
410 |
+
function wprss_settings_general_callback() {
|
411 |
+
echo wpautop( __( 'These are the general settings for WP RSS Aggregator.', WPRSS_TEXT_DOMAIN ) );
|
412 |
+
}
|
413 |
+
|
414 |
+
|
415 |
+
/**
|
416 |
+
* General settings display section header
|
417 |
+
* @since 3.5
|
418 |
+
*/
|
419 |
+
function wprss_settings_display_callback() {
|
420 |
+
echo wpautop( __( 'In this section you can find some general options that control how the feed items are displayed.', WPRSS_TEXT_DOMAIN ) );
|
421 |
+
}
|
422 |
+
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Display settings for source section header
|
426 |
+
*
|
427 |
+
* @since 4.2.4
|
428 |
+
*/
|
429 |
+
function wprss_settings_source_callback() {
|
430 |
+
echo wpautop( __( "Options that control how the feed item's source is displayed.", WPRSS_TEXT_DOMAIN ) );
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Display settings for date section header
|
435 |
+
*
|
436 |
+
* @since 4.2.4
|
437 |
+
*/
|
438 |
+
function wprss_settings_date_callback() {
|
439 |
+
echo wpautop( __( "Options that control how the feed item's date is displayed.", WPRSS_TEXT_DOMAIN ) );
|
440 |
+
}
|
441 |
+
|
442 |
+
|
443 |
+
/**
|
444 |
+
* General settings styles section header
|
445 |
+
* @since 3.0
|
446 |
+
*/
|
447 |
+
function wprss_settings_styles_callback() {
|
448 |
+
echo wpautop( __( 'If you would like to disable all styles used in this plugin, tick the checkbox.', WPRSS_TEXT_DOMAIN ) );
|
449 |
+
}
|
450 |
+
|
451 |
+
|
452 |
+
/**
|
453 |
+
* General settings scure reset section header
|
454 |
+
* @since 3.0
|
455 |
+
*/
|
456 |
+
function wprss_secure_reset_section_callback() {
|
457 |
+
echo wpautop( __( 'Set your security reset code, in case of any errors.', WPRSS_TEXT_DOMAIN ) );
|
458 |
+
}
|
459 |
+
|
460 |
+
|
461 |
+
/**
|
462 |
+
* Tracking settings section header
|
463 |
+
* @since 3.0
|
464 |
+
*/
|
465 |
+
function wprss_tracking_section_callback() {
|
466 |
+
echo wpautop( __( 'Participate in helping us make the plugin better.', WPRSS_TEXT_DOMAIN ) );
|
467 |
+
}
|
468 |
+
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Follow or No Follow dropdown
|
472 |
+
* @since 1.1
|
473 |
+
*/
|
474 |
+
function wprss_setting_follow_dd_callback( $field ) {
|
475 |
+
$follow_dd = wprss_get_general_setting( 'follow_dd' );
|
476 |
+
|
477 |
+
$checked = ( $follow_dd === 'no_follow' );
|
478 |
+
$checked_attr = ( $checked )? 'checked="checked"' : '';
|
479 |
+
?>
|
480 |
+
<input type="hidden" name="wprss_settings_general[follow_dd]" value="follow" />
|
481 |
+
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[follow_dd]" value="no_follow" <?php echo $checked_attr ?> />
|
482 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
483 |
+
}
|
484 |
+
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Use original video link, or embedded video links dropwdown
|
488 |
+
* @since 3.4
|
489 |
+
*/
|
490 |
+
function wprss_setting_video_links_callback( $field ) {
|
491 |
+
$video_link = wprss_get_general_setting('video_link');
|
492 |
+
$items = array(
|
493 |
+
'false' => __( 'Original page link', WPRSS_TEXT_DOMAIN ),
|
494 |
+
'true' => __( 'Embedded video player link', WPRSS_TEXT_DOMAIN )
|
495 |
+
);
|
496 |
+
?>
|
497 |
+
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[video_link]">
|
498 |
+
<?php
|
499 |
+
foreach ( $items as $boolean => $text ) {
|
500 |
+
$selected = ( $video_link === $boolean )? 'selected="selected"' : '';
|
501 |
+
?><option value="<?php echo $boolean ?>" <?php echo $selected ?>><?php echo $text ?></option><?php
|
502 |
+
}
|
503 |
+
?>
|
504 |
+
</select>
|
505 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
506 |
+
<p>
|
507 |
+
<span class="description">
|
508 |
+
<?php _e( 'This will not affect already imported feed items.', WPRSS_TEXT_DOMAIN ) ?>
|
509 |
+
</span>
|
510 |
+
</p>
|
511 |
+
<?php
|
512 |
+
}
|
513 |
+
|
514 |
+
|
515 |
+
/**
|
516 |
+
* Link open setting dropdown
|
517 |
+
* @since 1.1
|
518 |
+
*/
|
519 |
+
function wprss_setting_open_dd_callback( $field ) {
|
520 |
+
$open_dd = wprss_get_general_setting('open_dd');
|
521 |
+
|
522 |
+
$items = array(
|
523 |
+
__( 'Lightbox', WPRSS_TEXT_DOMAIN ),
|
524 |
+
__( 'New window', WPRSS_TEXT_DOMAIN ),
|
525 |
+
__( 'Self', WPRSS_TEXT_DOMAIN )
|
526 |
+
);
|
527 |
+
?>
|
528 |
+
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[open_dd]">
|
529 |
+
<?php
|
530 |
+
foreach( $items as $item ) {
|
531 |
+
$selected = ( $open_dd == $item ) ? 'selected="selected"' : '';
|
532 |
+
?><option value="<?php echo $item ?>" <?php echo $selected ?>><?php echo $item ?></option><?php
|
533 |
+
}
|
534 |
+
?>
|
535 |
+
</select>
|
536 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
537 |
+
}
|
538 |
+
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Set limit for feeds on frontend
|
542 |
+
* @since 2.0
|
543 |
+
*/
|
544 |
+
function wprss_setting_feed_limit_callback( $field ) {
|
545 |
+
$feed_limit = wprss_get_general_setting( 'feed_limit' );
|
546 |
+
?>
|
547 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[feed_limit]" type="text" value="<?php echo $feed_limit ?>" />
|
548 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
549 |
+
}
|
550 |
+
|
551 |
+
|
552 |
+
/**
|
553 |
+
* Set date format
|
554 |
+
* @since 3.0
|
555 |
+
*/
|
556 |
+
function wprss_setting_date_format_callback( $field ) {
|
557 |
+
$date_format = wprss_get_general_setting( 'date_format' );
|
558 |
+
?>
|
559 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[date_format]" type="text" value="<?php echo $date_format ?>" />
|
560 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
561 |
+
<p>
|
562 |
+
<a href="http://codex.wordpress.org/Formatting_Date_and_Time">
|
563 |
+
<?php _e( 'PHP Date Format Reference', WPRSS_TEXT_DOMAIN ); ?>
|
564 |
+
</a>
|
565 |
+
</p>
|
566 |
+
<?php
|
567 |
+
}
|
568 |
+
|
569 |
+
|
570 |
+
|
571 |
+
/**
|
572 |
+
* Enable linked title
|
573 |
+
* @since 3.0
|
574 |
+
*/
|
575 |
+
function wprss_setting_title_link_callback( $field ) {
|
576 |
+
$title_link = wprss_get_general_setting( 'title_link' );
|
577 |
+
?>
|
578 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[title_link]" type="checkbox" value="1" <?php echo checked( 1, $title_link, false ) ?> />
|
579 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
580 |
+
}
|
581 |
+
|
582 |
+
|
583 |
+
|
584 |
+
/**
|
585 |
+
* Set the title length limit
|
586 |
+
* @since 3.0
|
587 |
+
*/
|
588 |
+
function wprss_setting_title_length_callback( $field ) {
|
589 |
+
$title_limit = wprss_get_general_setting( 'title_limit' );
|
590 |
+
?>
|
591 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[title_limit]" type="number" class="wprss-number-roller" min="0" value="<?php echo $title_limit ?>" placeholder="<?php _e( 'No limit', WPRSS_TEXT_DOMAIN ) ?>" />
|
592 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
593 |
+
}
|
594 |
+
|
595 |
+
|
596 |
+
/**
|
597 |
+
* Enable source
|
598 |
+
* @since 3.0
|
599 |
+
*/
|
600 |
+
function wprss_setting_source_enable_callback( $field ) {
|
601 |
+
$source_enable = wprss_get_general_setting( 'source_enable' );
|
602 |
+
?>
|
603 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[source_enable]" type="checkbox" value="1" <?php echo checked( 1, $source_enable, false ) ?> />
|
604 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
605 |
+
}
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Enable linked title
|
609 |
+
* @since 3.0
|
610 |
+
*/
|
611 |
+
function wprss_setting_source_link_callback( $field ) {
|
612 |
+
$source_link = wprss_get_general_setting( 'source_link' );
|
613 |
+
?>
|
614 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[source_link]" type="checkbox" value="1" <?php echo checked( 1, $source_link, false ) ?> />
|
615 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
616 |
+
}
|
617 |
+
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Set text preceding source
|
621 |
+
* @since 3.0
|
622 |
+
*/
|
623 |
+
function wprss_setting_text_preceding_source_callback( $field ) {
|
624 |
+
$text_preceding_source = wprss_get_general_setting( 'text_preceding_source' );
|
625 |
+
?>
|
626 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[text_preceding_source]" type="text" value="<?php echo $text_preceding_source ?>" />
|
627 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
628 |
+
}
|
629 |
+
/**
|
630 |
+
* Enable date
|
631 |
+
* @since 3.0
|
632 |
+
*/
|
633 |
+
function wprss_setting_date_enable_callback( $field ) {
|
634 |
+
$date_enable = wprss_get_general_setting( 'date_enable' );
|
635 |
+
?>
|
636 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[date_enable]" type="checkbox" value="1" <?php echo checked( 1, $date_enable, false ) ?> />
|
637 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
638 |
+
}
|
639 |
+
|
640 |
+
/**
|
641 |
+
* Set text preceding date
|
642 |
+
* @since 3.0
|
643 |
+
*/
|
644 |
+
function wprss_setting_text_preceding_date_callback( $field ) {
|
645 |
+
$text_preceding_date = wprss_get_general_setting( 'text_preceding_date' );
|
646 |
+
?>
|
647 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[text_preceding_date]" type="text" value="<?php echo $text_preceding_date ?>" />
|
648 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
649 |
+
}
|
650 |
+
|
651 |
+
|
652 |
+
/**
|
653 |
+
* Shows the feed item authors option
|
654 |
+
*
|
655 |
+
* @since 4.2.4
|
656 |
+
*/
|
657 |
+
function wprss_setting_authors_enable_callback( $field ) {
|
658 |
+
$authors_enable = wprss_get_general_setting( 'authors_enable' );
|
659 |
+
?>
|
660 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[authors_enable]" type="checkbox" value="1" <?php echo checked( 1, $authors_enable, false ) ?> />
|
661 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
662 |
+
}
|
663 |
+
|
664 |
+
|
665 |
+
/**
|
666 |
+
* Pagination Type
|
667 |
+
*
|
668 |
+
* @since 4.2.3
|
669 |
+
*/
|
670 |
+
function wprss_setting_pagination_type_callback( $field ) {
|
671 |
+
$pagination = wprss_get_general_setting( 'pagination' );
|
672 |
+
$options = array(
|
673 |
+
'default' => __( '"Older posts" and "Newer posts" links', WPRSS_TEXT_DOMAIN ),
|
674 |
+
'numbered' => __( 'Page numbers with "Next" and "Previous" page links', WPRSS_TEXT_DOMAIN ),
|
675 |
+
);
|
676 |
+
?>
|
677 |
+
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[pagination]">
|
678 |
+
<?php
|
679 |
+
foreach( $options as $value => $text ) {
|
680 |
+
$selected = ( $value === $pagination )? 'selected="selected"' : '';
|
681 |
+
?><option value="<?php echo $value ?>" <?php echo $selected ?>><?php echo $text ?></option><?php
|
682 |
+
}
|
683 |
+
?>
|
684 |
+
</select>
|
685 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
686 |
+
}
|
687 |
+
|
688 |
+
|
689 |
+
|
690 |
+
/**
|
691 |
+
* Limit number of feed items stored by their age
|
692 |
+
* @since 3.0
|
693 |
+
*/
|
694 |
+
function wprss_setting_limit_feed_items_age_callback( $field ) {
|
695 |
+
$limit_feed_items_age = wprss_get_general_setting( 'limit_feed_items_age' );
|
696 |
+
$limit_feed_items_age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
|
697 |
+
$units = wprss_age_limit_units();
|
698 |
+
// echo wprss_settings_field_name( $field_info['field_id'], $field_info['section_id'], $field_info['field_name_prefix'] )
|
699 |
+
?>
|
700 |
+
|
701 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_age]" type="number" min="0"
|
702 |
+
class="wprss-number-roller" placeholder="<?php _e( 'No limit', WPRSS_TEXT_DOMAIN ) ?>" value="<?php echo $limit_feed_items_age; ?>" />
|
703 |
+
|
704 |
+
<select id="limit-feed-items-age-unit" name="wprss_settings_general[limit_feed_items_age_unit]">
|
705 |
+
<?php foreach ( $units as $unit ) : ?>
|
706 |
+
<option value="<?php echo $unit ?>" <?php selected( $limit_feed_items_age_unit, $unit ) ?> ><?php _e( $unit, WPRSS_TEXT_DOMAIN ) ?></option>
|
707 |
+
<?php endforeach ?>
|
708 |
+
</select>
|
709 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
710 |
+
|
711 |
+
<br/>
|
712 |
+
<?php
|
713 |
+
}
|
714 |
+
|
715 |
+
|
716 |
+
|
717 |
+
/**
|
718 |
+
* Limit number of feed items stored
|
719 |
+
* @since 3.0
|
720 |
+
*/
|
721 |
+
function wprss_setting_limit_feed_items_callback( $field ) {
|
722 |
+
$limit_feed_items_db = wprss_get_general_setting( 'limit_feed_items_db' );
|
723 |
+
?>
|
724 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[limit_feed_items_db]" type="text" value="<?php echo $limit_feed_items_db ?>" />
|
725 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
726 |
+
}
|
727 |
+
|
728 |
+
|
729 |
+
/**
|
730 |
+
* Limit number of feed items imported per feed
|
731 |
+
* @since 3.1
|
732 |
+
*/
|
733 |
+
function wprss_setting_limit_feed_items_imported_callback( $field ) {
|
734 |
+
$limit_feed_items_imported = wprss_get_general_setting( 'limit_feed_items_imported' );
|
735 |
+
?>
|
736 |
+
<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 ) ?>" />
|
737 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
738 |
+
}
|
739 |
+
|
740 |
+
|
741 |
+
/**
|
742 |
+
* Gets a sorted (according to interval) list of the cron schedules
|
743 |
+
* @since 3.0
|
744 |
+
*/
|
745 |
+
function wprss_get_schedules() {
|
746 |
+
$schedules = wp_get_schedules();
|
747 |
+
uasort( $schedules, create_function( '$a,$b', 'return $a["interval"]-$b["interval"];' ) );
|
748 |
+
return $schedules;
|
749 |
+
}
|
750 |
+
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Cron interval dropdown callback
|
754 |
+
* @since 3.0
|
755 |
+
*/
|
756 |
+
function wprss_setting_cron_interval_callback( $field ) {
|
757 |
+
$options = get_option( 'wprss_settings_general' );
|
758 |
+
$current = $options['cron_interval'];
|
759 |
+
|
760 |
+
$schedules = wprss_get_schedules();
|
761 |
+
// Set the allowed Cron schedules, we don't want any intervals that can lead to issues with server load
|
762 |
+
$wprss_schedules = apply_filters(
|
763 |
+
'wprss_schedules',
|
764 |
+
array( 'fifteen_min', 'thirty_min', 'hourly', 'two_hours', 'twicedaily', 'daily' )
|
765 |
+
);
|
766 |
+
?>
|
767 |
+
<select id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[cron_interval]">
|
768 |
+
<?php
|
769 |
+
foreach( $schedules as $schedule_name => $schedule_data ):
|
770 |
+
if ( in_array( $schedule_name, $wprss_schedules ) ): ?>
|
771 |
+
<option value="<?php echo $schedule_name ?>" <?php selected( $current, $schedule_name ) ?> >
|
772 |
+
<?php echo $schedule_data['display'] ?> (<?php echo wprss_interval( $schedule_data['interval'] ) ?>)
|
773 |
+
</option>
|
774 |
+
<?php endif ?>
|
775 |
+
<?php endforeach ?>
|
776 |
+
</select>
|
777 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?><?php
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Sets the custom feed URL
|
782 |
+
* @since 3.3
|
783 |
+
*/
|
784 |
+
function wprss_settings_custom_feed_url_callback( $field ) {
|
785 |
+
$custom_feed_url = wprss_get_general_setting( 'custom_feed_url' );
|
786 |
+
?>
|
787 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_url]" type="text" value="<?php echo $custom_feed_url ?>" />
|
788 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
789 |
+
}
|
790 |
+
|
791 |
+
/**
|
792 |
+
* Sets the custom feed title
|
793 |
+
* @since 4.1.2
|
794 |
+
*/
|
795 |
+
function wprss_settings_custom_feed_title_callback( $field ) {
|
796 |
+
$custom_feed_title = wprss_get_general_setting( 'custom_feed_title' );
|
797 |
+
?>
|
798 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[custom_feed_title]" type="text" value="<?php echo $custom_feed_title ?>" />
|
799 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
800 |
+
}
|
801 |
+
|
802 |
+
/**
|
803 |
+
* Sets the custom feed limit
|
804 |
+
* @since 3.3
|
805 |
+
*/
|
806 |
+
function wprss_setings_custom_feed_limit_callback( $field ) {
|
807 |
+
$custom_feed_limit = wprss_get_general_setting( 'custom_feed_limit' );
|
808 |
+
?>
|
809 |
+
<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 ?>" />
|
810 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
811 |
+
}
|
812 |
+
|
813 |
+
/**
|
814 |
+
* Disable styles
|
815 |
+
* @since 3.0
|
816 |
+
*/
|
817 |
+
function wprss_setting_styles_disable_callback( $field ) {
|
818 |
+
$styles_disable = wprss_get_general_setting( 'styles_disable' );
|
819 |
+
?>
|
820 |
+
<input id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[styles_disable]" type="checkbox" value="1" <?php echo checked( 1, $styles_disable, false ) ?> />
|
821 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
822 |
+
}
|
823 |
+
|
824 |
+
|
825 |
+
|
826 |
+
/**
|
827 |
+
* Secure Reset section
|
828 |
+
*
|
829 |
+
* @since 3.7.1
|
830 |
+
*/
|
831 |
+
function wprss_settings_secure_reset_code_callback( $args ) {
|
832 |
+
$reset_code = get_option( 'wprss_secure_reset_code', '' );
|
833 |
+
?>
|
834 |
+
<input id="wprss-secure-reset-code" name="wprss_secure_reset_code" type="input" value="<?php echo $reset_code; ?>" />
|
835 |
+
<button type="button" role="button" id="wprss-secure-reset-generate"><?php _e( 'Generate Random Code', WPRSS_TEXT_DOMAIN ) ?></button>
|
836 |
+
|
837 |
+
<br/>
|
838 |
+
|
839 |
+
<label class="description" for="wprss-secure-reset-code">
|
840 |
+
<?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/>
|
841 |
+
</label>
|
842 |
+
|
843 |
+
<br/>
|
844 |
+
|
845 |
+
<p>
|
846 |
+
<?php _e( 'Leave this empty to disable the secure reset function.<br/>
|
847 |
+
You use this code by adding any of the following to any URL on your site.', WPRSS_TEXT_DOMAIN ) ?>
|
848 |
+
<ol>
|
849 |
+
<li>"?wprss_action=reset&wprss_security_code=<your_code>" - <b><?php _e( 'Resets your WP RSS Aggregator settings', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
850 |
+
<li>"?wprss_action=deactivate&wprss_security_code=<your_code>" - <b><?php _e( 'Deactivates WP RSS Aggregator', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
851 |
+
<li>"?wprss_action=reset_and_deactivate&wprss_security_code=<your_code>" - <b><?php _e( 'Does both of the above', WPRSS_TEXT_DOMAIN ) ?></b></li>
|
852 |
+
</ol>
|
853 |
+
</p>
|
854 |
+
<p class="description">
|
855 |
+
<?php _e( 'Use the above actions only when absolutely necessary, or when instructed to by support staff.', WPRSS_TEXT_DOMAIN ) ?>
|
856 |
+
</p>
|
857 |
+
<?php
|
858 |
+
}
|
859 |
+
|
860 |
+
|
861 |
+
/**
|
862 |
+
* Tracking checkbox
|
863 |
+
* @since 3.6
|
864 |
+
*/
|
865 |
+
function wprss_tracking_callback( $field ) {
|
866 |
+
$tracking = wprss_get_general_setting( 'tracking' );
|
867 |
+
?>
|
868 |
+
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[tracking]" value="1" <?php echo checked( 1, $tracking, false ) ?> />
|
869 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] ) ?>
|
870 |
+
<label class="description" for="<?php echo $field['field_id'] ?>">
|
871 |
+
<?php _e( 'Please help us improve WP RSS Aggregator by allowing us to gather anonymous usage statistics. No sensitive data is collected.', WPRSS_TEXT_DOMAIN ) ?>
|
872 |
+
</label>
|
873 |
+
<?php
|
874 |
+
}
|
875 |
+
|
876 |
+
/**
|
877 |
+
* Time ago format checkbox
|
878 |
+
* @since 4.2
|
879 |
+
*/
|
880 |
+
function wprss_setting_time_ago_format_enable_callback( $field ) {
|
881 |
+
$time_ago_format = wprss_get_general_setting( 'time_ago_format_enable' );
|
882 |
+
?>
|
883 |
+
<input type="checkbox" id="<?php echo $field['field_id'] ?>" name="wprss_settings_general[time_ago_format_enable]" value="1" <?php echo checked( 1, $time_ago_format, false ) ?> />
|
884 |
+
<?php echo wprss_settings_inline_help( $field['field_id'], $field['tooltip'] );
|
885 |
+
}
|
886 |
+
|
887 |
+
|
888 |
+
/**
|
889 |
+
* Pretty-prints the difference in two times.
|
890 |
+
*
|
891 |
+
* @since 3.0
|
892 |
+
* @param time $older_date
|
893 |
+
* @param time $newer_date
|
894 |
+
* @return string The pretty time_since value
|
895 |
+
* @link http://wordpress.org/extend/plugins/wp-crontrol/
|
896 |
+
*/
|
897 |
+
function wprss_time_since( $older_date, $newer_date ) {
|
898 |
+
return wprss_interval( $newer_date - $older_date );
|
899 |
+
}
|
900 |
+
|
901 |
+
/**
|
902 |
+
* Calculates difference between times
|
903 |
+
*
|
904 |
+
* Taken from the WP-Crontrol plugin
|
905 |
+
* @link http://wordpress.org/extend/plugins/wp-crontrol/
|
906 |
+
* @since 3.0
|
907 |
+
*
|
908 |
+
*/
|
909 |
+
function wprss_interval( $since ) {
|
910 |
+
if ( $since === wprss_get_default_feed_source_update_interval() ) {
|
911 |
+
return __( 'Default', WPRSS_TEXT_DOMAIN );
|
912 |
+
}
|
913 |
+
// array of time period chunks
|
914 |
+
$chunks = array(
|
915 |
+
array(60 * 60 * 24 * 365 , _n_noop('%s year', '%s years', 'crontrol')),
|
916 |
+
array(60 * 60 * 24 * 30 , _n_noop('%s month', '%s months', 'crontrol')),
|
917 |
+
array(60 * 60 * 24 * 7, _n_noop('%s week', '%s weeks', 'crontrol')),
|
918 |
+
array(60 * 60 * 24 , _n_noop('%s day', '%s days', 'crontrol')),
|
919 |
+
array(60 * 60 , _n_noop('%s hour', '%s hours', 'crontrol')),
|
920 |
+
array(60 , _n_noop('%s minute', '%s minutes', 'crontrol')),
|
921 |
+
array( 1 , _n_noop('%s second', '%s seconds', 'crontrol')),
|
922 |
+
);
|
923 |
+
|
924 |
+
|
925 |
+
if( $since <= 0 ) {
|
926 |
+
return __( 'now', WPRSS_TEXT_DOMAIN );
|
927 |
+
}
|
928 |
+
|
929 |
+
// we only want to output two chunks of time here, eg:
|
930 |
+
// x years, xx months
|
931 |
+
// x days, xx hours
|
932 |
+
// so there's only two bits of calculation below:
|
933 |
+
|
934 |
+
// step one: the first chunk
|
935 |
+
for ($i = 0, $j = count($chunks); $i < $j; $i++)
|
936 |
+
{
|
937 |
+
$seconds = $chunks[$i][0];
|
938 |
+
$name = $chunks[$i][1];
|
939 |
+
|
940 |
+
// finding the biggest chunk (if the chunk fits, break)
|
941 |
+
if (($count = floor($since / $seconds)) != 0)
|
942 |
+
{
|
943 |
+
break;
|
944 |
+
}
|
945 |
+
}
|
946 |
+
|
947 |
+
// set output var
|
948 |
+
$output = sprintf(_n($name[0], $name[1], $count, WPRSS_TEXT_DOMAIN), $count);
|
949 |
+
|
950 |
+
// step two: the second chunk
|
951 |
+
if ($i + 1 < $j)
|
952 |
+
{
|
953 |
+
$seconds2 = $chunks[$i + 1][0];
|
954 |
+
$name2 = $chunks[$i + 1][1];
|
955 |
+
|
956 |
+
if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
|
957 |
+
{
|
958 |
+
// add to output var
|
959 |
+
$output .= ' '.sprintf(_n($name2[0], $name2[1], $count2, WPRSS_TEXT_DOMAIN), $count2);
|
960 |
+
}
|
961 |
+
}
|
962 |
+
|
963 |
+
return $output;
|
964 |
+
}
|
965 |
+
|
966 |
+
|
967 |
+
/**
|
968 |
+
* Validate inputs from the general settings page
|
969 |
+
* @since 3.0
|
970 |
+
*/
|
971 |
+
function wprss_settings_general_validate( $input ) {
|
972 |
+
$options = get_option( 'wprss_settings_general' );
|
973 |
+
$current_cron_interval = $options['cron_interval'];
|
974 |
+
|
975 |
+
// Create our array for storing the validated options
|
976 |
+
$output = array();
|
977 |
+
|
978 |
+
// Loop through each of the incoming options
|
979 |
+
foreach( $input as $key => $value ) {
|
980 |
+
|
981 |
+
// Check to see if the current option has a value. If so, process it.
|
982 |
+
if( isset( $input[ $key ] ) ) {
|
983 |
+
|
984 |
+
// Strip all HTML and PHP tags and properly handle quoted strings
|
985 |
+
$output[ $key ] = strip_tags( stripslashes( $input[ $key ] ) );
|
986 |
+
|
987 |
+
} // end if
|
988 |
+
|
989 |
+
} // end foreach
|
990 |
+
|
991 |
+
// If limit_feed_items_age_unit is not set or it set to zero, set it to empty
|
992 |
+
if ( ! isset( $input['limit_feed_items_age'] ) || strval( $input['limit_feed_items_age'] ) == '0' ) {
|
993 |
+
$output['limit_feed_items_age'] = '';
|
994 |
+
}
|
995 |
+
|
996 |
+
if ( ! isset( $input['title_link'] ) || $input['title_link'] != '1' )
|
997 |
+
$output['title_link'] = 0;
|
998 |
+
else
|
999 |
+
$output['title_link'] = 1;
|
1000 |
+
|
1001 |
+
if ( ! isset( $input['source_enable'] ) || $input['source_enable'] != '1' )
|
1002 |
+
$output['source_enable'] = 0;
|
1003 |
+
else
|
1004 |
+
$output['source_enable'] = 1;
|
1005 |
+
|
1006 |
+
if ( ! isset( $input['date_enable'] ) || $input['date_enable'] != '1' )
|
1007 |
+
$output['date_enable'] = 0;
|
1008 |
+
else
|
1009 |
+
$output['date_enable'] = 1;
|
1010 |
+
|
1011 |
+
if ( ! isset( $input['styles_disable'] ) || $input['styles_disable'] != '1' )
|
1012 |
+
$output['styles_disable'] = 0;
|
1013 |
+
else
|
1014 |
+
$output['styles_disable'] = 1;
|
1015 |
+
|
1016 |
+
if ( ! isset( $input['video_link'] ) || strtolower( $input['video_link'] ) !== 'true' )
|
1017 |
+
$output['video_link'] = 'false';
|
1018 |
+
else
|
1019 |
+
$output['video_link'] = 'true';
|
1020 |
+
|
1021 |
+
if ( $input['cron_interval'] != $current_cron_interval ) {
|
1022 |
+
wp_clear_scheduled_hook( 'wprss_fetch_all_feeds_hook' );
|
1023 |
+
wp_schedule_event( time(), $input['cron_interval'], 'wprss_fetch_all_feeds_hook' );
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
// Return the array processing any additional functions filtered by this action
|
1027 |
+
return apply_filters( 'wprss_settings_general_validate', $output, $input );
|
1028 |
+
}
|
1029 |
+
|
1030 |
+
|
1031 |
+
/**
|
1032 |
+
* Validates the licenses settings
|
1033 |
+
*
|
1034 |
+
* @since 3.8
|
1035 |
+
*/
|
1036 |
+
function wprss_settings_license_keys_validate( $input ) {
|
1037 |
+
// Get the current licenses option
|
1038 |
+
$licenses = get_option( 'wprss_settings_license_keys' );
|
1039 |
+
// If no licenses have been defined yet, create an empty array
|
1040 |
+
if ( !is_array( $licenses ) ) {
|
1041 |
+
$licenses = array();
|
1042 |
+
}
|
1043 |
+
// For each entry in the received input
|
1044 |
+
foreach ( $input as $addon => $license_code ) {
|
1045 |
+
$addon_code = explode( '_', $addon );
|
1046 |
+
$addon_code = isset( $addon_code[0] ) ? $addon_code[0] : null;
|
1047 |
+
// Only save if the entry does not exist OR the code is different
|
1048 |
+
if ( array_key_exists( $addon, $licenses ) && $license_code === $licenses[ $addon ] )
|
1049 |
+
continue;
|
1050 |
+
|
1051 |
+
$is_valid = apply_filters( 'wprss_settings_license_key_is_valid', true, $license_code );
|
1052 |
+
if( $addon_code )
|
1053 |
+
$is_valid = apply_filters( "wprss_settings_license_key_{$addon_code}_is_valid", $is_valid, $license_code );
|
1054 |
+
if( !$is_valid ) continue;
|
1055 |
+
|
1056 |
+
// Save it to the licenses option
|
1057 |
+
$licenses[ $addon ] = $license_code;
|
1058 |
+
}
|
1059 |
+
wprss_check_license_statuses();
|
1060 |
+
// Return the new licenses
|
1061 |
+
return $licenses;
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
|
1065 |
+
|
1066 |
+
add_action( 'wprss_check_license_statuses', 'wprss_check_license_statuses' );
|
1067 |
+
/**
|
1068 |
+
* Checks the license statuses
|
1069 |
+
*
|
1070 |
+
* @since 3.8.1
|
1071 |
+
*/
|
1072 |
+
function wprss_check_license_statuses() {
|
1073 |
+
$license_statuses = get_option( 'wprss_settings_license_statuses', array() );
|
1074 |
+
|
1075 |
+
if ( count( $license_statuses ) === 0 ) return;
|
1076 |
+
|
1077 |
+
$found_inactive = FALSE;
|
1078 |
+
foreach ( $license_statuses as $addon => $status ) {
|
1079 |
+
if ( $status !== 'active' ) {
|
1080 |
+
$found_inactive = TRUE;
|
1081 |
+
break;
|
1082 |
+
}
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
if ( $found_inactive ) {
|
1086 |
+
set_transient( 'wprss_notify_inactive_licenses', 1, 0 );
|
1087 |
+
}
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
|
1091 |
+
|
1092 |
+
/**
|
1093 |
+
* Validates the wprss_secure_reset_code option
|
1094 |
+
*
|
1095 |
+
* @since 3.7.1
|
1096 |
+
*/
|
1097 |
+
function wprss_secure_reset_code_validate( $input ) {
|
1098 |
+
return $input;
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
|
1102 |
+
|
1103 |
+
/**
|
1104 |
+
* Validates the presstrends setting
|
1105 |
+
*
|
1106 |
+
* @since 3.6
|
1107 |
+
*/
|
1108 |
+
function wprss_tracking_validate ( $input ) {
|
1109 |
+
$output = $input;
|
1110 |
+
if ( ! isset( $input['wprss_tracking'] ) ) {
|
1111 |
+
$output['wprss_tracking'] = 0;
|
1112 |
+
}
|
1113 |
+
return $output;
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
|
1117 |
+
|
1118 |
+
/**
|
1119 |
+
* Returns the units used for the limit by age option.
|
1120 |
+
*
|
1121 |
+
* @since 3.8
|
1122 |
+
*/
|
1123 |
+
function wprss_age_limit_units() {
|
1124 |
+
return apply_filters(
|
1125 |
+
'wprss_age_limit_units',
|
1126 |
+
array(
|
1127 |
+
'days',
|
1128 |
+
'weeks',
|
1129 |
+
'months',
|
1130 |
+
'years'
|
1131 |
+
)
|
1132 |
+
);
|
1133 |
}
|
includes/admin-statistics.php
CHANGED
@@ -1,152 +1,152 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( !defined( 'WPRSS_TRACKING_SERVER_URL' ) )
|
4 |
-
define( 'WPRSS_TRACKING_SERVER_URL', 'http://www.wprssaggregator.com/', TRUE );
|
5 |
-
|
6 |
-
if ( !defined( 'WPRSS_TRACKING_INTEVAL' ) )
|
7 |
-
define( 'WPRSS_TRACKING_INTEVAL', 'daily', TRUE );
|
8 |
-
|
9 |
-
|
10 |
-
add_action( 'admin_init', 'wprss_send_tracking_data' );
|
11 |
-
function wprss_send_tracking_data() {
|
12 |
-
|
13 |
-
// Check the tracking option - if turned off, exit out of function
|
14 |
-
$tracking_option = wprss_get_general_setting('tracking');
|
15 |
-
if ( $tracking_option == 0 || $tracking_option == FALSE ) return;
|
16 |
-
|
17 |
-
// Get the tracking transient.
|
18 |
-
$transient = get_transient( 'wprss_tracking_transient' );
|
19 |
-
// If the transient did not expire, exit out of function
|
20 |
-
if ( $transient !== FALSE && !isset( $_GET['wprss_send_report'] ) ) return;
|
21 |
-
// If the GET parameter is set, show an admin notice
|
22 |
-
if ( isset( $_GET['wprss_send_report'] ) ) {
|
23 |
-
add_action( 'admin_notices', 'wprss_tracking_notice' );
|
24 |
-
}
|
25 |
-
|
26 |
-
// Check if running on localhost
|
27 |
-
$site_url = site_url();
|
28 |
-
$running_on_local = preg_match_all( "/(localhost|127\.0\.0\.1)/", $site_url, $matches ) > 0;
|
29 |
-
if( $running_on_local ) {
|
30 |
-
return;
|
31 |
-
}
|
32 |
-
|
33 |
-
// Get data about the plugin
|
34 |
-
$plugin_data = get_plugin_data( WPRSS_FILE_CONSTANT );
|
35 |
-
|
36 |
-
// Get the theme name
|
37 |
-
if ( function_exists( 'wp_get_theme' ) ) {
|
38 |
-
$theme_data = wp_get_theme();
|
39 |
-
$theme_name = $theme_data->Name;
|
40 |
-
} else {
|
41 |
-
$theme_data = get_theme_data( get_stylesheet_directory() . '/style.css' );
|
42 |
-
$theme_name = $theme_data['Name'];
|
43 |
-
}
|
44 |
-
|
45 |
-
// Get plugins
|
46 |
-
$plugins = get_plugins();
|
47 |
-
$active_plugins_option = get_option( 'active_plugins', array() );
|
48 |
-
// Prepare plugin arrays
|
49 |
-
$active_plugins = array();
|
50 |
-
$inactive_plugins = array();
|
51 |
-
// Loop through plugins
|
52 |
-
foreach ( $plugins as $plugins_path => $plugin_info ) {
|
53 |
-
// If plugin found in active plugins list, then add to the active_plugins array
|
54 |
-
if ( in_array( $plugins_path, $active_plugins_option ) ) {
|
55 |
-
$add_to = &$active_plugins;
|
56 |
-
}
|
57 |
-
// Otherwise add to inactive_plugins array
|
58 |
-
else {
|
59 |
-
$add_to = &$inactive_plugins;
|
60 |
-
}
|
61 |
-
// Add the plugin info to the chosen array
|
62 |
-
$add_to[] = $plugin_info['Name'] . ' v' . $plugin_info['Version'];
|
63 |
-
}
|
64 |
-
|
65 |
-
// If multisite
|
66 |
-
if ( is_multisite() ) {
|
67 |
-
// Get network plugins
|
68 |
-
$network_plugins = wp_get_active_network_plugins();
|
69 |
-
$network_active_plugins_option = get_site_option( 'active_sitewide_plugins', array() );
|
70 |
-
// Prepare plugin array
|
71 |
-
$network_active_plugins = array();
|
72 |
-
// Loop through plugins
|
73 |
-
foreach ( $network_plugins as $plugin_path ) {
|
74 |
-
// Get plugin basename
|
75 |
-
$plugin_base = plugin_basename( $plugin_path );
|
76 |
-
// If the plugin basename is found in the active network plugin list
|
77 |
-
if ( array_key_exists( $plugin_base, $network_active_plugins_option ) ) {
|
78 |
-
// Get the plugin info and add it to the plugin list
|
79 |
-
$plugin_info = get_plugin_data( $plugin_path );
|
80 |
-
$network_active_plugins[] = $plugin_info['Name'] . ' v' . $plugin_info['Version'];
|
81 |
-
}
|
82 |
-
}
|
83 |
-
} else {
|
84 |
-
// Otherwise, indicate that the site is not a multisite installation
|
85 |
-
$network_active_plugins = 'Not multisite';
|
86 |
-
}
|
87 |
-
|
88 |
-
|
89 |
-
// Detect add-ons
|
90 |
-
$addons = array();
|
91 |
-
if ( defined( 'WPRSS_C_VERSION' ) ) {
|
92 |
-
$addons[] = 'Categories';
|
93 |
-
}
|
94 |
-
if ( defined( 'WPRSS_ET_VERSION' ) ) {
|
95 |
-
$addons[] = 'Excerpts & Thumbnails';
|
96 |
-
}
|
97 |
-
if ( defined( 'WPRSS_KF_VERSION' ) ) {
|
98 |
-
$addons[] = 'Keyword Filtering';
|
99 |
-
}
|
100 |
-
if ( defined( 'WPRSS_FTP_VERSION' ) ) {
|
101 |
-
$addons[] = 'Feed to Post';
|
102 |
-
}
|
103 |
-
|
104 |
-
// Compile the data
|
105 |
-
$data = array(
|
106 |
-
'Site URL' => base64_encode( $site_url ),
|
107 |
-
'Plugin Version' => $plugin_data['Version'],
|
108 |
-
'Active Add-ons' => $addons,
|
109 |
-
'Theme Name' => $theme_name,
|
110 |
-
'Site Name' => str_replace( ' ', '', get_bloginfo( 'name' ) ),
|
111 |
-
'Plugin Count' => count( get_option( 'active_plugins' ) ),
|
112 |
-
'Active Plugins' => $active_plugins,
|
113 |
-
'Network Active Plugins' => $network_active_plugins,
|
114 |
-
'Inactive Plugins' => $inactive_plugins,
|
115 |
-
'WordPress Version' => get_bloginfo( 'version' ),
|
116 |
-
);
|
117 |
-
|
118 |
-
// Send the data
|
119 |
-
wp_remote_post(
|
120 |
-
WPRSS_TRACKING_SERVER_URL,
|
121 |
-
array(
|
122 |
-
'method' => 'POST',
|
123 |
-
'timeout' => 45,
|
124 |
-
'redirection' => 5,
|
125 |
-
'httpversion' => '1.0',
|
126 |
-
'blocking' => true,
|
127 |
-
'headers' => array(),
|
128 |
-
'body' => array(
|
129 |
-
'wprss_tracking_data' => $data,
|
130 |
-
),
|
131 |
-
'cookies' => array()
|
132 |
-
)
|
133 |
-
);
|
134 |
-
|
135 |
-
// Set a transient that expires in 1 week. When it expires, this function will run again
|
136 |
-
// Expiration: 60secs * 60mins * 24hrs * 7days = 1 week
|
137 |
-
set_transient( 'wprss_tracking_transient', '-', 60 * 60 * 24 * 7 );
|
138 |
-
}
|
139 |
-
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Shows a notice that notifies the user that the data report has been sent.
|
143 |
-
*
|
144 |
-
* @since 1.0
|
145 |
-
*/
|
146 |
-
function wprss_tracking_notice() {
|
147 |
-
?>
|
148 |
-
<div class="updated">
|
149 |
-
<?php echo wpautop( __( '<b>WP RSS Aggregator:</b> Data report sent!', WPRSS_TEXT_DOMAIN ) ) ?>
|
150 |
-
</div>
|
151 |
-
<?php
|
152 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if ( !defined( 'WPRSS_TRACKING_SERVER_URL' ) )
|
4 |
+
define( 'WPRSS_TRACKING_SERVER_URL', 'http://www.wprssaggregator.com/', TRUE );
|
5 |
+
|
6 |
+
if ( !defined( 'WPRSS_TRACKING_INTEVAL' ) )
|
7 |
+
define( 'WPRSS_TRACKING_INTEVAL', 'daily', TRUE );
|
8 |
+
|
9 |
+
|
10 |
+
add_action( 'admin_init', 'wprss_send_tracking_data' );
|
11 |
+
function wprss_send_tracking_data() {
|
12 |
+
|
13 |
+
// Check the tracking option - if turned off, exit out of function
|
14 |
+
$tracking_option = wprss_get_general_setting('tracking');
|
15 |
+
if ( $tracking_option == 0 || $tracking_option == FALSE ) return;
|
16 |
+
|
17 |
+
// Get the tracking transient.
|
18 |
+
$transient = get_transient( 'wprss_tracking_transient' );
|
19 |
+
// If the transient did not expire, exit out of function
|
20 |
+
if ( $transient !== FALSE && !isset( $_GET['wprss_send_report'] ) ) return;
|
21 |
+
// If the GET parameter is set, show an admin notice
|
22 |
+
if ( isset( $_GET['wprss_send_report'] ) ) {
|
23 |
+
add_action( 'admin_notices', 'wprss_tracking_notice' );
|
24 |
+
}
|
25 |
+
|
26 |
+
// Check if running on localhost
|
27 |
+
$site_url = site_url();
|
28 |
+
$running_on_local = preg_match_all( "/(localhost|127\.0\.0\.1)/", $site_url, $matches ) > 0;
|
29 |
+
if( $running_on_local ) {
|
30 |
+
return;
|
31 |
+
}
|
32 |
+
|
33 |
+
// Get data about the plugin
|
34 |
+
$plugin_data = get_plugin_data( WPRSS_FILE_CONSTANT );
|
35 |
+
|
36 |
+
// Get the theme name
|
37 |
+
if ( function_exists( 'wp_get_theme' ) ) {
|
38 |
+
$theme_data = wp_get_theme();
|
39 |
+
$theme_name = $theme_data->Name;
|
40 |
+
} else {
|
41 |
+
$theme_data = get_theme_data( get_stylesheet_directory() . '/style.css' );
|
42 |
+
$theme_name = $theme_data['Name'];
|
43 |
+
}
|
44 |
+
|
45 |
+
// Get plugins
|
46 |
+
$plugins = get_plugins();
|
47 |
+
$active_plugins_option = get_option( 'active_plugins', array() );
|
48 |
+
// Prepare plugin arrays
|
49 |
+
$active_plugins = array();
|
50 |
+
$inactive_plugins = array();
|
51 |
+
// Loop through plugins
|
52 |
+
foreach ( $plugins as $plugins_path => $plugin_info ) {
|
53 |
+
// If plugin found in active plugins list, then add to the active_plugins array
|
54 |
+
if ( in_array( $plugins_path, $active_plugins_option ) ) {
|
55 |
+
$add_to = &$active_plugins;
|
56 |
+
}
|
57 |
+
// Otherwise add to inactive_plugins array
|
58 |
+
else {
|
59 |
+
$add_to = &$inactive_plugins;
|
60 |
+
}
|
61 |
+
// Add the plugin info to the chosen array
|
62 |
+
$add_to[] = $plugin_info['Name'] . ' v' . $plugin_info['Version'];
|
63 |
+
}
|
64 |
+
|
65 |
+
// If multisite
|
66 |
+
if ( is_multisite() ) {
|
67 |
+
// Get network plugins
|
68 |
+
$network_plugins = wp_get_active_network_plugins();
|
69 |
+
$network_active_plugins_option = get_site_option( 'active_sitewide_plugins', array() );
|
70 |
+
// Prepare plugin array
|
71 |
+
$network_active_plugins = array();
|
72 |
+
// Loop through plugins
|
73 |
+
foreach ( $network_plugins as $plugin_path ) {
|
74 |
+
// Get plugin basename
|
75 |
+
$plugin_base = plugin_basename( $plugin_path );
|
76 |
+
// If the plugin basename is found in the active network plugin list
|
77 |
+
if ( array_key_exists( $plugin_base, $network_active_plugins_option ) ) {
|
78 |
+
// Get the plugin info and add it to the plugin list
|
79 |
+
$plugin_info = get_plugin_data( $plugin_path );
|
80 |
+
$network_active_plugins[] = $plugin_info['Name'] . ' v' . $plugin_info['Version'];
|
81 |
+
}
|
82 |
+
}
|
83 |
+
} else {
|
84 |
+
// Otherwise, indicate that the site is not a multisite installation
|
85 |
+
$network_active_plugins = 'Not multisite';
|
86 |
+
}
|
87 |
+
|
88 |
+
|
89 |
+
// Detect add-ons
|
90 |
+
$addons = array();
|
91 |
+
if ( defined( 'WPRSS_C_VERSION' ) ) {
|
92 |
+
$addons[] = 'Categories';
|
93 |
+
}
|
94 |
+
if ( defined( 'WPRSS_ET_VERSION' ) ) {
|
95 |
+
$addons[] = 'Excerpts & Thumbnails';
|
96 |
+
}
|
97 |
+
if ( defined( 'WPRSS_KF_VERSION' ) ) {
|
98 |
+
$addons[] = 'Keyword Filtering';
|
99 |
+
}
|
100 |
+
if ( defined( 'WPRSS_FTP_VERSION' ) ) {
|
101 |
+
$addons[] = 'Feed to Post';
|
102 |
+
}
|
103 |
+
|
104 |
+
// Compile the data
|
105 |
+
$data = array(
|
106 |
+
'Site URL' => base64_encode( $site_url ),
|
107 |
+
'Plugin Version' => $plugin_data['Version'],
|
108 |
+
'Active Add-ons' => $addons,
|
109 |
+
'Theme Name' => $theme_name,
|
110 |
+
'Site Name' => str_replace( ' ', '', get_bloginfo( 'name' ) ),
|
111 |
+
'Plugin Count' => count( get_option( 'active_plugins' ) ),
|
112 |
+
'Active Plugins' => $active_plugins,
|
113 |
+
'Network Active Plugins' => $network_active_plugins,
|
114 |
+
'Inactive Plugins' => $inactive_plugins,
|
115 |
+
'WordPress Version' => get_bloginfo( 'version' ),
|
116 |
+
);
|
117 |
+
|
118 |
+
// Send the data
|
119 |
+
wp_remote_post(
|
120 |
+
WPRSS_TRACKING_SERVER_URL,
|
121 |
+
array(
|
122 |
+
'method' => 'POST',
|
123 |
+
'timeout' => 45,
|
124 |
+
'redirection' => 5,
|
125 |
+
'httpversion' => '1.0',
|
126 |
+
'blocking' => true,
|
127 |
+
'headers' => array(),
|
128 |
+
'body' => array(
|
129 |
+
'wprss_tracking_data' => $data,
|
130 |
+
),
|
131 |
+
'cookies' => array()
|
132 |
+
)
|
133 |
+
);
|
134 |
+
|
135 |
+
// Set a transient that expires in 1 week. When it expires, this function will run again
|
136 |
+
// Expiration: 60secs * 60mins * 24hrs * 7days = 1 week
|
137 |
+
set_transient( 'wprss_tracking_transient', '-', 60 * 60 * 24 * 7 );
|
138 |
+
}
|
139 |
+
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Shows a notice that notifies the user that the data report has been sent.
|
143 |
+
*
|
144 |
+
* @since 1.0
|
145 |
+
*/
|
146 |
+
function wprss_tracking_notice() {
|
147 |
+
?>
|
148 |
+
<div class="updated">
|
149 |
+
<?php echo wpautop( __( '<b>WP RSS Aggregator:</b> Data report sent!', WPRSS_TEXT_DOMAIN ) ) ?>
|
150 |
+
</div>
|
151 |
+
<?php
|
152 |
}
|
includes/admin-welcome.php
CHANGED
@@ -1,168 +1,168 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @todo Localize
|
5 |
-
*/
|
6 |
-
|
7 |
-
// Exit if the page is accessed directly
|
8 |
-
if ( ! defined( 'ABSPATH' ) ) exit;
|
9 |
-
|
10 |
-
// The readme lib
|
11 |
-
require_once( WPRSS_INC . '/readme.php' );
|
12 |
-
|
13 |
-
|
14 |
-
// The tabs to be shown
|
15 |
-
$tabs = array(
|
16 |
-
/* 'cat' => 'Categories',
|
17 |
-
'et' => 'Excerpts & Thumbnails',
|
18 |
-
'kf' => 'Keyword Filtering'*/
|
19 |
-
);
|
20 |
-
|
21 |
-
// Determine the tab currently being shown
|
22 |
-
$tab = null;
|
23 |
-
if ( isset( $_GET['tab'] ) && !empty( $_GET['tab'] ) ) {
|
24 |
-
$tab = $_GET['tab'];
|
25 |
-
}
|
26 |
-
|
27 |
-
$settings_url = admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings');
|
28 |
-
|
29 |
-
?>
|
30 |
-
|
31 |
-
<div class="wrap about-wrap">
|
32 |
-
<h1><?php printf( __( 'Welcome to WP RSS Aggregator %1$s!', WPRSS_TEXT_DOMAIN ), WPRSS_VERSION ); ?></h1>
|
33 |
-
<div class="wprss-about-text">
|
34 |
-
<?php _e( 'Thank you for upgrading to the latest version!', WPRSS_TEXT_DOMAIN ) ?>
|
35 |
-
</div>
|
36 |
-
<!-- <div class="wprss-badge">Version</div>-->
|
37 |
-
|
38 |
-
<!-- TAB WRAPPER -->
|
39 |
-
<h2 class="nav-tab-wrapper">
|
40 |
-
<!--<a class="nav-tab <?php if ( $tab === null ) echo 'nav-tab-active'; ?>"
|
41 |
-
href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome' ), 'index.php' ) ) ); ?>">
|
42 |
-
<?php _e( "What's New?", WPRSS_TEXT_DOMAIN ) ?>
|
43 |
-
</a>-->
|
44 |
-
|
45 |
-
<!-- SHOW ALL TABS -->
|
46 |
-
<?php foreach ($tabs as $slug => $title) : ?>
|
47 |
-
|
48 |
-
<a class="nav-tab <?php if ( $tab === $slug ) echo 'nav-tab-active'; ?>"
|
49 |
-
href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome', 'tab' => $slug ), 'index.php' ) ) ); ?>">
|
50 |
-
<?php _e( $title, WPRSS_TEXT_DOMAIN ) ?>
|
51 |
-
</a>
|
52 |
-
|
53 |
-
<?php endforeach; ?>
|
54 |
-
|
55 |
-
</h2>
|
56 |
-
|
57 |
-
<!-- TAB CONTENT -->
|
58 |
-
<?php
|
59 |
-
/* Show content depending on the current tab */
|
60 |
-
switch( $tab ) {
|
61 |
-
|
62 |
-
// Default tab. ( when tab = null )
|
63 |
-
default: ?>
|
64 |
-
<div class="changelog">
|
65 |
-
|
66 |
-
<!--<h2 class="about-headline-callout"><?php _e( 'Bulk Adding Feed Sources', WPRSS_TEXT_DOMAIN ) ?></h2>
|
67 |
-
<div class="about-overview">
|
68 |
-
<img src="<?php echo WPRSS_IMG; ?>welcome-page/bulk-add.png" />
|
69 |
-
<?php echo wpautop( sprintf( __('The new bulk adding option saves you time by allowing you to enter your feed names and URLs all at once.
|
70 |
-
Simply type in or paste your feed sources, and with the press of a button, your feed sources will instantly be created!
|
71 |
-
Try it now from the <a href="%1$s">Import & Export</a> page.', WPRSS_TEXT_DOMAIN), 'edit.php?post_type=wprss_feed&page=wprss-import-export-settings' ) ) ?>
|
72 |
-
</div>
|
73 |
-
|
74 |
-
<h2 class="about-headline-callout"><?php _e( 'Feed Item Blacklist', WPRSS_TEXT_DOMAIN ) ?></h2>
|
75 |
-
<div class="feature-section col three-col">
|
76 |
-
<div class="col-1">
|
77 |
-
<img src="<?php echo WPRSS_IMG;?>welcome-page/trash-feed-item.png" />
|
78 |
-
<h4><?php _e( 'Trash undesired items', WPRSS_TEXT_DOMAIN ) ?></h4>
|
79 |
-
<?php echo wpautop( sprintf( __('Did a feed import an item that you do not wish to keep? Up till now, <strong>WP RSS Aggregator</strong>'
|
80 |
-
. 'only allowed you to trash the item and keep it in your trash.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
81 |
-
</div>
|
82 |
-
<div class="col-2">
|
83 |
-
<img src="<?php echo WPRSS_IMG;?>welcome-page/blacklist-feed-item.png" />
|
84 |
-
<h4><?php _e( 'Blacklist Trashed Items', WPRSS_TEXT_DOMAIN ) ?></h4>
|
85 |
-
<?php echo wpautop( sprintf( __('Permanently deleting the item will cause it to be re-imported. '
|
86 |
-
. 'Using the new <strong>Delete Permanently & Blacklist</strong> option, the feed item is deleted '
|
87 |
-
. 'and added to the <strong>Blacklist</strong>.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
88 |
-
</div>
|
89 |
-
<div class="col-3 last-feature">
|
90 |
-
<img src="<?php echo WPRSS_IMG;?>welcome-page/blacklist.png" />
|
91 |
-
<h4><?php _e( 'The Blacklist', WPRSS_TEXT_DOMAIN ) ?></h4>
|
92 |
-
<?php echo wpautop( sprintf( __('This is your list of unwanted feed item links. Any item in this list will be ignored by '
|
93 |
-
. "<strong>WP RSS Aggregator</strong> in the future, meaning it won't be imported from any of your feed sources."
|
94 |
-
. 'and added to the <strong>Blacklist</strong>.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
95 |
-
</div>
|
96 |
-
</div>-->
|
97 |
-
|
98 |
-
<hr/>
|
99 |
-
|
100 |
-
<h3><?php _e( 'Check out our add-ons:', WPRSS_TEXT_DOMAIN ) ?></h3>
|
101 |
-
|
102 |
-
<ul>
|
103 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/feed-post/" target="wprss_ftp"><?php _e( 'Feed to Post', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
104 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/excerpts-thumbnails/" target="wprss_et"><?php _e( 'Excerpts & Thumbnails', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
105 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/categories/" target="wprss_cat"><?php _e( 'Categories', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
106 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/keyword-filtering/" target="wprss_kf"><?php _e( 'Keyword Filtering', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
107 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/full-text-rss-feeds/" target="wprss_kf"><?php _e( 'Full Text RSS Feeds', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
108 |
-
<li><strong><a href="http://www.wprssaggregator.com/extension/wordai/" target="wprss_ai"><?php _e( 'WordAi', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
109 |
-
</ul>
|
110 |
-
</p>
|
111 |
-
<?php echo wpautop( sprintf( __( 'More information about add-ons can be found on our website <a href="%1$s">%2$s</a>', WPRSS_TEXT_DOMAIN ), 'http://www.wprssaggregator.com', 'www.wprssaggregator.com' ) ) ?>
|
112 |
-
|
113 |
-
<hr/>
|
114 |
-
|
115 |
-
<?php $changelog = wprss_parse_changelog() ?>
|
116 |
-
<?php if ( count( $changelog ) ): foreach( $changelog as $_version => $_changes_html ): ?>
|
117 |
-
<h3><?php printf( __( 'Changelog for v%1$s', WPRSS_TEXT_DOMAIN ), $_version ) ?></h3>
|
118 |
-
<div class="changelog-changeset" >
|
119 |
-
<?php echo $_changes_html ?>
|
120 |
-
</div>
|
121 |
-
<?php break; endforeach; endif; ?>
|
122 |
-
|
123 |
-
<?php echo wpautop( sprintf( __( 'Need functionality not already available in core or the add-ons? You can <a href="%1$s">suggest new features</a>!', WPRSS_TEXT_DOMAIN ), 'https://trello.com/b/UJJwpvZu/wp-rss-aggregator-public-roadmap' ) ) ?>
|
124 |
-
|
125 |
-
</div>
|
126 |
-
|
127 |
-
<?php
|
128 |
-
break;
|
129 |
-
|
130 |
-
// Excerpts and Thumbnails tab
|
131 |
-
case 'et': ?>
|
132 |
-
|
133 |
-
<p class="about-description">
|
134 |
-
<?php _e( 'Fetch RSS feed excerpts to your blog and add thumbnails! Perfect for adding some life and color to your feeds.', WPRSS_TEXT_DOMAIN ) ?>
|
135 |
-
</p>
|
136 |
-
|
137 |
-
<?php
|
138 |
-
break;
|
139 |
-
|
140 |
-
// Categories Tab
|
141 |
-
case 'cat': ?>
|
142 |
-
|
143 |
-
<p class="about-description">
|
144 |
-
<?php _e( 'Organize your feeds into custom categories. Filter feed items by category and make custom WordPress feeds for specific categories.', WPRSS_TEXT_DOMAIN ) ?>
|
145 |
-
</p>
|
146 |
-
|
147 |
-
<?php
|
148 |
-
break;
|
149 |
-
|
150 |
-
// Keyword Filtering tab
|
151 |
-
case 'kf': ?>
|
152 |
-
|
153 |
-
<p class="about-description">
|
154 |
-
<?php _e( 'Import and store feeds that contain specific keywords in either the title or their content. Control what gets imported to your blog.', WPRSS_TEXT_DOMAIN ) ?>
|
155 |
-
</p>
|
156 |
-
|
157 |
-
<?php
|
158 |
-
break;
|
159 |
-
}
|
160 |
-
?>
|
161 |
-
|
162 |
-
<hr/>
|
163 |
-
|
164 |
-
<p><a href="<?php echo $settings_url; ?>"><?php _e( 'Go to WP RSS Aggregator settings', WPRSS_TEXT_DOMAIN ) ?></a></p>
|
165 |
-
|
166 |
-
</div>
|
167 |
-
|
168 |
-
<?php update_option( 'wprss_pwsv', WPRSS_VERSION ); // Update the previous welcome screen version ?>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @todo Localize
|
5 |
+
*/
|
6 |
+
|
7 |
+
// Exit if the page is accessed directly
|
8 |
+
if ( ! defined( 'ABSPATH' ) ) exit;
|
9 |
+
|
10 |
+
// The readme lib
|
11 |
+
require_once( WPRSS_INC . '/readme.php' );
|
12 |
+
|
13 |
+
|
14 |
+
// The tabs to be shown
|
15 |
+
$tabs = array(
|
16 |
+
/* 'cat' => 'Categories',
|
17 |
+
'et' => 'Excerpts & Thumbnails',
|
18 |
+
'kf' => 'Keyword Filtering'*/
|
19 |
+
);
|
20 |
+
|
21 |
+
// Determine the tab currently being shown
|
22 |
+
$tab = null;
|
23 |
+
if ( isset( $_GET['tab'] ) && !empty( $_GET['tab'] ) ) {
|
24 |
+
$tab = $_GET['tab'];
|
25 |
+
}
|
26 |
+
|
27 |
+
$settings_url = admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings');
|
28 |
+
|
29 |
+
?>
|
30 |
+
|
31 |
+
<div class="wrap about-wrap">
|
32 |
+
<h1><?php printf( __( 'Welcome to WP RSS Aggregator %1$s!', WPRSS_TEXT_DOMAIN ), WPRSS_VERSION ); ?></h1>
|
33 |
+
<div class="wprss-about-text">
|
34 |
+
<?php _e( 'Thank you for upgrading to the latest version!', WPRSS_TEXT_DOMAIN ) ?>
|
35 |
+
</div>
|
36 |
+
<!-- <div class="wprss-badge">Version</div>-->
|
37 |
+
|
38 |
+
<!-- TAB WRAPPER -->
|
39 |
+
<h2 class="nav-tab-wrapper">
|
40 |
+
<!--<a class="nav-tab <?php if ( $tab === null ) echo 'nav-tab-active'; ?>"
|
41 |
+
href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome' ), 'index.php' ) ) ); ?>">
|
42 |
+
<?php _e( "What's New?", WPRSS_TEXT_DOMAIN ) ?>
|
43 |
+
</a>-->
|
44 |
+
|
45 |
+
<!-- SHOW ALL TABS -->
|
46 |
+
<?php foreach ($tabs as $slug => $title) : ?>
|
47 |
+
|
48 |
+
<a class="nav-tab <?php if ( $tab === $slug ) echo 'nav-tab-active'; ?>"
|
49 |
+
href="<?php echo esc_url( admin_url( add_query_arg( array( 'page' => 'wprss-welcome', 'tab' => $slug ), 'index.php' ) ) ); ?>">
|
50 |
+
<?php _e( $title, WPRSS_TEXT_DOMAIN ) ?>
|
51 |
+
</a>
|
52 |
+
|
53 |
+
<?php endforeach; ?>
|
54 |
+
|
55 |
+
</h2>
|
56 |
+
|
57 |
+
<!-- TAB CONTENT -->
|
58 |
+
<?php
|
59 |
+
/* Show content depending on the current tab */
|
60 |
+
switch( $tab ) {
|
61 |
+
|
62 |
+
// Default tab. ( when tab = null )
|
63 |
+
default: ?>
|
64 |
+
<div class="changelog">
|
65 |
+
|
66 |
+
<!--<h2 class="about-headline-callout"><?php _e( 'Bulk Adding Feed Sources', WPRSS_TEXT_DOMAIN ) ?></h2>
|
67 |
+
<div class="about-overview">
|
68 |
+
<img src="<?php echo WPRSS_IMG; ?>welcome-page/bulk-add.png" />
|
69 |
+
<?php echo wpautop( sprintf( __('The new bulk adding option saves you time by allowing you to enter your feed names and URLs all at once.
|
70 |
+
Simply type in or paste your feed sources, and with the press of a button, your feed sources will instantly be created!
|
71 |
+
Try it now from the <a href="%1$s">Import & Export</a> page.', WPRSS_TEXT_DOMAIN), 'edit.php?post_type=wprss_feed&page=wprss-import-export-settings' ) ) ?>
|
72 |
+
</div>
|
73 |
+
|
74 |
+
<h2 class="about-headline-callout"><?php _e( 'Feed Item Blacklist', WPRSS_TEXT_DOMAIN ) ?></h2>
|
75 |
+
<div class="feature-section col three-col">
|
76 |
+
<div class="col-1">
|
77 |
+
<img src="<?php echo WPRSS_IMG;?>welcome-page/trash-feed-item.png" />
|
78 |
+
<h4><?php _e( 'Trash undesired items', WPRSS_TEXT_DOMAIN ) ?></h4>
|
79 |
+
<?php echo wpautop( sprintf( __('Did a feed import an item that you do not wish to keep? Up till now, <strong>WP RSS Aggregator</strong>'
|
80 |
+
. 'only allowed you to trash the item and keep it in your trash.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
81 |
+
</div>
|
82 |
+
<div class="col-2">
|
83 |
+
<img src="<?php echo WPRSS_IMG;?>welcome-page/blacklist-feed-item.png" />
|
84 |
+
<h4><?php _e( 'Blacklist Trashed Items', WPRSS_TEXT_DOMAIN ) ?></h4>
|
85 |
+
<?php echo wpautop( sprintf( __('Permanently deleting the item will cause it to be re-imported. '
|
86 |
+
. 'Using the new <strong>Delete Permanently & Blacklist</strong> option, the feed item is deleted '
|
87 |
+
. 'and added to the <strong>Blacklist</strong>.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
88 |
+
</div>
|
89 |
+
<div class="col-3 last-feature">
|
90 |
+
<img src="<?php echo WPRSS_IMG;?>welcome-page/blacklist.png" />
|
91 |
+
<h4><?php _e( 'The Blacklist', WPRSS_TEXT_DOMAIN ) ?></h4>
|
92 |
+
<?php echo wpautop( sprintf( __('This is your list of unwanted feed item links. Any item in this list will be ignored by '
|
93 |
+
. "<strong>WP RSS Aggregator</strong> in the future, meaning it won't be imported from any of your feed sources."
|
94 |
+
. 'and added to the <strong>Blacklist</strong>.', WPRSS_TEXT_DOMAIN) ) ) ?>
|
95 |
+
</div>
|
96 |
+
</div>-->
|
97 |
+
|
98 |
+
<hr/>
|
99 |
+
|
100 |
+
<h3><?php _e( 'Check out our add-ons:', WPRSS_TEXT_DOMAIN ) ?></h3>
|
101 |
+
|
102 |
+
<ul>
|
103 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/feed-post/" target="wprss_ftp"><?php _e( 'Feed to Post', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
104 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/excerpts-thumbnails/" target="wprss_et"><?php _e( 'Excerpts & Thumbnails', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
105 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/categories/" target="wprss_cat"><?php _e( 'Categories', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
106 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/keyword-filtering/" target="wprss_kf"><?php _e( 'Keyword Filtering', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
107 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/full-text-rss-feeds/" target="wprss_kf"><?php _e( 'Full Text RSS Feeds', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
108 |
+
<li><strong><a href="http://www.wprssaggregator.com/extension/wordai/" target="wprss_ai"><?php _e( 'WordAi', WPRSS_TEXT_DOMAIN ); ?></a></strong></li>
|
109 |
+
</ul>
|
110 |
+
</p>
|
111 |
+
<?php echo wpautop( sprintf( __( 'More information about add-ons can be found on our website <a href="%1$s">%2$s</a>', WPRSS_TEXT_DOMAIN ), 'http://www.wprssaggregator.com', 'www.wprssaggregator.com' ) ) ?>
|
112 |
+
|
113 |
+
<hr/>
|
114 |
+
|
115 |
+
<?php $changelog = wprss_parse_changelog() ?>
|
116 |
+
<?php if ( count( $changelog ) ): foreach( $changelog as $_version => $_changes_html ): ?>
|
117 |
+
<h3><?php printf( __( 'Changelog for v%1$s', WPRSS_TEXT_DOMAIN ), $_version ) ?></h3>
|
118 |
+
<div class="changelog-changeset" >
|
119 |
+
<?php echo $_changes_html ?>
|
120 |
+
</div>
|
121 |
+
<?php break; endforeach; endif; ?>
|
122 |
+
|
123 |
+
<?php echo wpautop( sprintf( __( 'Need functionality not already available in core or the add-ons? You can <a href="%1$s">suggest new features</a>!', WPRSS_TEXT_DOMAIN ), 'https://trello.com/b/UJJwpvZu/wp-rss-aggregator-public-roadmap' ) ) ?>
|
124 |
+
|
125 |
+
</div>
|
126 |
+
|
127 |
+
<?php
|
128 |
+
break;
|
129 |
+
|
130 |
+
// Excerpts and Thumbnails tab
|
131 |
+
case 'et': ?>
|
132 |
+
|
133 |
+
<p class="about-description">
|
134 |
+
<?php _e( 'Fetch RSS feed excerpts to your blog and add thumbnails! Perfect for adding some life and color to your feeds.', WPRSS_TEXT_DOMAIN ) ?>
|
135 |
+
</p>
|
136 |
+
|
137 |
+
<?php
|
138 |
+
break;
|
139 |
+
|
140 |
+
// Categories Tab
|
141 |
+
case 'cat': ?>
|
142 |
+
|
143 |
+
<p class="about-description">
|
144 |
+
<?php _e( 'Organize your feeds into custom categories. Filter feed items by category and make custom WordPress feeds for specific categories.', WPRSS_TEXT_DOMAIN ) ?>
|
145 |
+
</p>
|
146 |
+
|
147 |
+
<?php
|
148 |
+
break;
|
149 |
+
|
150 |
+
// Keyword Filtering tab
|
151 |
+
case 'kf': ?>
|
152 |
+
|
153 |
+
<p class="about-description">
|
154 |
+
<?php _e( 'Import and store feeds that contain specific keywords in either the title or their content. Control what gets imported to your blog.', WPRSS_TEXT_DOMAIN ) ?>
|
155 |
+
</p>
|
156 |
+
|
157 |
+
<?php
|
158 |
+
break;
|
159 |
+
}
|
160 |
+
?>
|
161 |
+
|
162 |
+
<hr/>
|
163 |
+
|
164 |
+
<p><a href="<?php echo $settings_url; ?>"><?php _e( 'Go to WP RSS Aggregator settings', WPRSS_TEXT_DOMAIN ) ?></a></p>
|
165 |
+
|
166 |
+
</div>
|
167 |
+
|
168 |
+
<?php update_option( 'wprss_pwsv', WPRSS_VERSION ); // Update the previous welcome screen version ?>
|
includes/admin.php
CHANGED
@@ -1,144 +1,144 @@
|
|
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 |
-
|
28 |
-
add_action( 'admin_menu', 'wprss_register_menu_pages' );
|
29 |
-
/**
|
30 |
-
* Register menu and submenus
|
31 |
-
* @since 2.0
|
32 |
-
*/
|
33 |
-
|
34 |
-
// Add the admin options pages as submenus to the Feed CPT
|
35 |
-
function wprss_register_menu_pages() {
|
36 |
-
global $submenu;
|
37 |
-
// Uncomment line below to hide "Add New" link from menu
|
38 |
-
// unset( $submenu['edit.php?post_type=wprss_feed'][10] );
|
39 |
-
// create submenu items
|
40 |
-
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Export & Import Settings', WPRSS_TEXT_DOMAIN ), __( 'Import & Export', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings' ), 'wprss-import-export-settings', 'wprss_import_export_settings_page_display' );
|
41 |
-
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' );
|
42 |
-
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Debugging', WPRSS_TEXT_DOMAIN ), __( 'Debugging', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings'), 'wprss-debugging', 'wprss_debugging_page_display' );
|
43 |
-
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Add-Ons', WPRSS_TEXT_DOMAIN ), __( 'Add-Ons', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings'), 'wprss-addons', 'wprss_addons_page_display' );
|
44 |
-
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' );
|
45 |
-
}
|
46 |
-
|
47 |
-
add_filter('admin_body_class', 'wprss_base_admin_body_class');
|
48 |
-
/**
|
49 |
-
* Set body class for admin screens
|
50 |
-
* http://www.kevinleary.net/customizing-wordpress-admin-css-javascript/
|
51 |
-
* @since 2.0
|
52 |
-
*/
|
53 |
-
function wprss_base_admin_body_class( $classes )
|
54 |
-
{
|
55 |
-
// Current action
|
56 |
-
if ( is_admin() && isset($_GET['action']) ) {
|
57 |
-
$classes .= 'action-'.$_GET['action'];
|
58 |
-
}
|
59 |
-
// Current post ID
|
60 |
-
if ( is_admin() && isset($_GET['post']) ) {
|
61 |
-
$classes .= ' ';
|
62 |
-
$classes .= 'post-'.$_GET['post'];
|
63 |
-
}
|
64 |
-
// New post type & listing page
|
65 |
-
if ( isset($_GET['post_type']) ) $post_type = $_GET['post_type'];
|
66 |
-
if ( isset($post_type) ) {
|
67 |
-
$classes .= ' ';
|
68 |
-
$classes .= 'post-type-'.$post_type;
|
69 |
-
}
|
70 |
-
// Editting a post type
|
71 |
-
if ( isset( $_GET['post'] ) ) {
|
72 |
-
$post_query = $_GET['post'];
|
73 |
-
}
|
74 |
-
if ( isset($post_query) ) {
|
75 |
-
$current_post_edit = get_post($post_query);
|
76 |
-
$current_post_type = $current_post_edit->post_type;
|
77 |
-
if ( !empty($current_post_type) ) {
|
78 |
-
$classes .= ' ';
|
79 |
-
$classes .= 'post-type-'.$current_post_type;
|
80 |
-
}
|
81 |
-
}
|
82 |
-
// Return the $classes array
|
83 |
-
return $classes;
|
84 |
-
}
|
85 |
-
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Change title on wprss_feed post type screen
|
89 |
-
*
|
90 |
-
* @since 2.0
|
91 |
-
* @return void
|
92 |
-
*/
|
93 |
-
function wprss_change_title_text() {
|
94 |
-
return __( 'Name this feed (e.g. WP Mayor)', WPRSS_TEXT_DOMAIN );
|
95 |
-
}
|
96 |
-
|
97 |
-
|
98 |
-
add_filter( 'plugin_action_links', 'wprss_plugin_action_links', 10, 2 );
|
99 |
-
/**
|
100 |
-
* Add Settings action link in plugin listing
|
101 |
-
*
|
102 |
-
* @since 3.0
|
103 |
-
* @param array $action_links
|
104 |
-
* @param string $plugin_file
|
105 |
-
* @return array
|
106 |
-
*/
|
107 |
-
function wprss_plugin_action_links( $action_links, $plugin_file ) {
|
108 |
-
// check to make sure we are on the correct plugin
|
109 |
-
if ( $plugin_file == 'wp-rss-aggregator/wp-rss-aggregator.php' ) {
|
110 |
-
// the anchor tag and href to the URLs we want.
|
111 |
-
$settings_link = '<a href="' . admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings">' . __( 'Settings', WPRSS_TEXT_DOMAIN ) . '</a>';
|
112 |
-
$docs_link = '<a href="http://www.wprssaggregator.com/documentation/">' . __( 'Documentation', WPRSS_TEXT_DOMAIN ) . '</a>';
|
113 |
-
// add the links to the beginning of the list
|
114 |
-
array_unshift( $action_links, $settings_link, $docs_link );
|
115 |
-
}
|
116 |
-
return $action_links;
|
117 |
-
}
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
if ( is_main_site() ) {
|
122 |
-
add_action( 'admin_notices', 'wprss_notify_inactive_licenses' );
|
123 |
-
}
|
124 |
-
/**
|
125 |
-
* Shows a notification that tells the user that there are saved licenses that have not been activated.
|
126 |
-
*
|
127 |
-
* @since 3.8.1
|
128 |
-
*/
|
129 |
-
function wprss_notify_inactive_licenses() {
|
130 |
-
// Check if a transient to show the notice is set
|
131 |
-
$transient = get_transient( 'wprss_notify_inactive_licenses' );
|
132 |
-
// If it is not set, then do nothing and return
|
133 |
-
if ( $transient === FALSE ) return;
|
134 |
-
// If it is set, delete it
|
135 |
-
delete_transient( 'wprss_notify_inactive_licenses' );
|
136 |
-
|
137 |
-
// Show the notice ?>
|
138 |
-
<div class="wprss-license-notice updated">
|
139 |
-
<?php echo wpautop( sprintf( __('<b>WP RSS Aggregator</b>:'
|
140 |
-
. ' There are saved licenses that have not yet been activated. Go to the'
|
141 |
-
. ' <a href="%1$s">License page</a> to activate them.', WPRSS_TEXT_DOMAIN ), admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ) ?>
|
142 |
-
</div>
|
143 |
-
<?php
|
144 |
}
|
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 |
+
|
28 |
+
add_action( 'admin_menu', 'wprss_register_menu_pages' );
|
29 |
+
/**
|
30 |
+
* Register menu and submenus
|
31 |
+
* @since 2.0
|
32 |
+
*/
|
33 |
+
|
34 |
+
// Add the admin options pages as submenus to the Feed CPT
|
35 |
+
function wprss_register_menu_pages() {
|
36 |
+
global $submenu;
|
37 |
+
// Uncomment line below to hide "Add New" link from menu
|
38 |
+
// unset( $submenu['edit.php?post_type=wprss_feed'][10] );
|
39 |
+
// create submenu items
|
40 |
+
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Export & Import Settings', WPRSS_TEXT_DOMAIN ), __( 'Import & Export', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings' ), 'wprss-import-export-settings', 'wprss_import_export_settings_page_display' );
|
41 |
+
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' );
|
42 |
+
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Debugging', WPRSS_TEXT_DOMAIN ), __( 'Debugging', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings'), 'wprss-debugging', 'wprss_debugging_page_display' );
|
43 |
+
add_submenu_page( 'edit.php?post_type=wprss_feed', __( 'Add-Ons', WPRSS_TEXT_DOMAIN ), __( 'Add-Ons', WPRSS_TEXT_DOMAIN ), apply_filters( 'wprss_capability', 'manage_feed_settings'), 'wprss-addons', 'wprss_addons_page_display' );
|
44 |
+
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' );
|
45 |
+
}
|
46 |
+
|
47 |
+
add_filter('admin_body_class', 'wprss_base_admin_body_class');
|
48 |
+
/**
|
49 |
+
* Set body class for admin screens
|
50 |
+
* http://www.kevinleary.net/customizing-wordpress-admin-css-javascript/
|
51 |
+
* @since 2.0
|
52 |
+
*/
|
53 |
+
function wprss_base_admin_body_class( $classes )
|
54 |
+
{
|
55 |
+
// Current action
|
56 |
+
if ( is_admin() && isset($_GET['action']) ) {
|
57 |
+
$classes .= 'action-'.$_GET['action'];
|
58 |
+
}
|
59 |
+
// Current post ID
|
60 |
+
if ( is_admin() && isset($_GET['post']) ) {
|
61 |
+
$classes .= ' ';
|
62 |
+
$classes .= 'post-'.$_GET['post'];
|
63 |
+
}
|
64 |
+
// New post type & listing page
|
65 |
+
if ( isset($_GET['post_type']) ) $post_type = $_GET['post_type'];
|
66 |
+
if ( isset($post_type) ) {
|
67 |
+
$classes .= ' ';
|
68 |
+
$classes .= 'post-type-'.$post_type;
|
69 |
+
}
|
70 |
+
// Editting a post type
|
71 |
+
if ( isset( $_GET['post'] ) ) {
|
72 |
+
$post_query = $_GET['post'];
|
73 |
+
}
|
74 |
+
if ( isset($post_query) ) {
|
75 |
+
$current_post_edit = get_post($post_query);
|
76 |
+
$current_post_type = $current_post_edit->post_type;
|
77 |
+
if ( !empty($current_post_type) ) {
|
78 |
+
$classes .= ' ';
|
79 |
+
$classes .= 'post-type-'.$current_post_type;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
// Return the $classes array
|
83 |
+
return $classes;
|
84 |
+
}
|
85 |
+
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Change title on wprss_feed post type screen
|
89 |
+
*
|
90 |
+
* @since 2.0
|
91 |
+
* @return void
|
92 |
+
*/
|
93 |
+
function wprss_change_title_text() {
|
94 |
+
return __( 'Name this feed (e.g. WP Mayor)', WPRSS_TEXT_DOMAIN );
|
95 |
+
}
|
96 |
+
|
97 |
+
|
98 |
+
add_filter( 'plugin_action_links', 'wprss_plugin_action_links', 10, 2 );
|
99 |
+
/**
|
100 |
+
* Add Settings action link in plugin listing
|
101 |
+
*
|
102 |
+
* @since 3.0
|
103 |
+
* @param array $action_links
|
104 |
+
* @param string $plugin_file
|
105 |
+
* @return array
|
106 |
+
*/
|
107 |
+
function wprss_plugin_action_links( $action_links, $plugin_file ) {
|
108 |
+
// check to make sure we are on the correct plugin
|
109 |
+
if ( $plugin_file == 'wp-rss-aggregator/wp-rss-aggregator.php' ) {
|
110 |
+
// the anchor tag and href to the URLs we want.
|
111 |
+
$settings_link = '<a href="' . admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings">' . __( 'Settings', WPRSS_TEXT_DOMAIN ) . '</a>';
|
112 |
+
$docs_link = '<a href="http://www.wprssaggregator.com/documentation/">' . __( 'Documentation', WPRSS_TEXT_DOMAIN ) . '</a>';
|
113 |
+
// add the links to the beginning of the list
|
114 |
+
array_unshift( $action_links, $settings_link, $docs_link );
|
115 |
+
}
|
116 |
+
return $action_links;
|
117 |
+
}
|
118 |
+
|
119 |
+
|
120 |
+
|
121 |
+
if ( is_main_site() ) {
|
122 |
+
add_action( 'admin_notices', 'wprss_notify_inactive_licenses' );
|
123 |
+
}
|
124 |
+
/**
|
125 |
+
* Shows a notification that tells the user that there are saved licenses that have not been activated.
|
126 |
+
*
|
127 |
+
* @since 3.8.1
|
128 |
+
*/
|
129 |
+
function wprss_notify_inactive_licenses() {
|
130 |
+
// Check if a transient to show the notice is set
|
131 |
+
$transient = get_transient( 'wprss_notify_inactive_licenses' );
|
132 |
+
// If it is not set, then do nothing and return
|
133 |
+
if ( $transient === FALSE ) return;
|
134 |
+
// If it is set, delete it
|
135 |
+
delete_transient( 'wprss_notify_inactive_licenses' );
|
136 |
+
|
137 |
+
// Show the notice ?>
|
138 |
+
<div class="wprss-license-notice updated">
|
139 |
+
<?php echo wpautop( sprintf( __('<b>WP RSS Aggregator</b>:'
|
140 |
+
. ' There are saved licenses that have not yet been activated. Go to the'
|
141 |
+
. ' <a href="%1$s">License page</a> to activate them.', WPRSS_TEXT_DOMAIN ), admin_url() . 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' ) ) ?>
|
142 |
+
</div>
|
143 |
+
<?php
|
144 |
}
|
includes/cpt-feeds.php
CHANGED
@@ -1,101 +1,101 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
add_action( 'wp_head', 'wprss_cpt_feeds' );
|
4 |
-
/**
|
5 |
-
* Adds Link tags to the head of the page, for CPTs' feeds.
|
6 |
-
*/
|
7 |
-
function wprss_cpt_feeds() {
|
8 |
-
// 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 = 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 » %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('unparse_url') ) {
|
89 |
-
function 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 |
+
// 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 = 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 » %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('unparse_url') ) {
|
89 |
+
function unparse_url( $parsed_url ) {
|
90 |
+
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
|
91 |
+
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
|
92 |
+
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
|
93 |
+
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
|
94 |
+
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
|
95 |
+
$pass = ($user || $pass) ? "$pass@" : '';
|
96 |
+
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
|
97 |
+
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
|
98 |
+
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
99 |
+
return "$scheme$user$pass$host$port$path$query$fragment";
|
100 |
+
}
|
101 |
}
|
includes/custom-feed.php
CHANGED
@@ -1,168 +1,168 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Function to create a custom feed with the latest imported feed items
|
4 |
-
*
|
5 |
-
* @package WP RSS Aggregator
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
add_action( 'init', 'wprss_addfeed_add_feed' );
|
10 |
-
/**
|
11 |
-
* Adds the custom feed, as specified by the user in the general settings.
|
12 |
-
*
|
13 |
-
* @since 3.3
|
14 |
-
*/
|
15 |
-
function wprss_addfeed_add_feed() {
|
16 |
-
$general_settings = get_option( 'wprss_settings_general', 'wprss' );
|
17 |
-
if ( !empty( $general_settings ) && isset( $general_settings['custom_feed_url'] ) && !empty( $general_settings['custom_feed_url'] ) ) {
|
18 |
-
$url = $general_settings['custom_feed_url'];
|
19 |
-
}
|
20 |
-
else {
|
21 |
-
$url = $general_settings['custom_feed_url'] = 'wprss';
|
22 |
-
update_option( 'wprss_settings_general', $general_settings );
|
23 |
-
}
|
24 |
-
|
25 |
-
// Add the feed
|
26 |
-
add_feed( $url, 'wprss_addfeed_do_feed' );
|
27 |
-
|
28 |
-
// Whether or not the feed is already registered or not
|
29 |
-
$registered = FALSE;
|
30 |
-
|
31 |
-
// Get all registered rewrite rules
|
32 |
-
$rules = get_option( 'rewrite_rules' );
|
33 |
-
|
34 |
-
// If no rules exist, then it is not registered
|
35 |
-
if ( !is_array( $rules ) ) {
|
36 |
-
$registered = FALSE;
|
37 |
-
}
|
38 |
-
// If there are exisiting rules
|
39 |
-
else {
|
40 |
-
// Get all the array keys that match the given pattern
|
41 |
-
// The resulting array will only contain the second part of each matching key ( $matches[1] )
|
42 |
-
$feeds = array_keys( $rules, 'index.php?&feed=$matches[1]' );
|
43 |
-
// Check if the rewrite rule for the custom feed is already registered
|
44 |
-
foreach( $feeds as $feed ) {
|
45 |
-
if ( strpos( $feed, $url ) !== FALSE ) {
|
46 |
-
$registered = TRUE;
|
47 |
-
}
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
// If not registered, flush the rewrite rules
|
52 |
-
if ( ! $registered ) {
|
53 |
-
flush_rewrite_rules();
|
54 |
-
}
|
55 |
-
|
56 |
-
}
|
57 |
-
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Generate the feed
|
61 |
-
*
|
62 |
-
* @since 3.3
|
63 |
-
*/
|
64 |
-
function wprss_addfeed_do_feed( $in ) {
|
65 |
-
|
66 |
-
// Prepare the post query
|
67 |
-
/*
|
68 |
-
$wprss_custom_feed_query = apply_filters(
|
69 |
-
'wprss_custom_feed_query',
|
70 |
-
array(
|
71 |
-
'post_type' => 'wprss_feed_item',
|
72 |
-
'post_status' => 'publish',
|
73 |
-
'cache_results' => false, // disable caching
|
74 |
-
)
|
75 |
-
|
76 |
-
);*/
|
77 |
-
$wprss_custom_feed_query = wprss_get_feed_items_query(
|
78 |
-
apply_filters(
|
79 |
-
'wprss_custom_feed_query',
|
80 |
-
array(
|
81 |
-
'get-args' => TRUE, // Get the query args instead of the query object
|
82 |
-
'no-paged' => TRUE, // ignore pagination
|
83 |
-
'feed_limit' => 0, // ignore limit
|
84 |
-
)
|
85 |
-
)
|
86 |
-
);
|
87 |
-
|
88 |
-
// Suppress caching
|
89 |
-
$wprss_custom_feed_query['cache_results'] = FALSE;
|
90 |
-
|
91 |
-
// Get options
|
92 |
-
$options = get_option( 'wprss_settings_general' );
|
93 |
-
if ( $options !== FALSE ) {
|
94 |
-
// If options exist, get the limit
|
95 |
-
$limit = $options['custom_feed_limit'];
|
96 |
-
if ( $limit !== FALSE ) {
|
97 |
-
// if limit exists, set the query limit
|
98 |
-
$wprss_custom_feed_query['posts_per_page'] = $limit;
|
99 |
-
}
|
100 |
-
}
|
101 |
-
|
102 |
-
// Submit the query to get latest feed items
|
103 |
-
query_posts( $wprss_custom_feed_query );
|
104 |
-
|
105 |
-
$custom_feed_title = wprss_get_general_setting( 'custom_feed_title' );
|
106 |
-
|
107 |
-
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
|
108 |
-
header( "$protocol 200 OK" );
|
109 |
-
// Send content header and start ATOM output
|
110 |
-
header('Content-Type: application/rss+xml');
|
111 |
-
// Disabling caching
|
112 |
-
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
|
113 |
-
header('Pragma: no-cache'); // HTTP 1.0.
|
114 |
-
header('Expires: 0'); // Proxies.
|
115 |
-
echo '<?xml version="1.0" encoding="' . get_option('blog_charset') . '"?>';
|
116 |
-
?>
|
117 |
-
|
118 |
-
<rss version="2.0"
|
119 |
-
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
120 |
-
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
121 |
-
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
122 |
-
xmlns:atom="http://www.w3.org/2005/Atom"
|
123 |
-
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
|
124 |
-
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
|
125 |
-
xmlns:media="http://search.yahoo.com/mrss/" >
|
126 |
-
<channel>
|
127 |
-
<title><?php echo $custom_feed_title; ?></title>
|
128 |
-
<description></description>
|
129 |
-
<link><?php echo get_site_url(); ?></link>
|
130 |
-
<atom:link href="<?php echo $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] ?>" rel="self" type="application/rss+xml" />
|
131 |
-
<?php // Start the Loop
|
132 |
-
while ( have_posts() ) : the_post();
|
133 |
-
$source = get_post_meta( get_the_ID(), 'wprss_feed_id', TRUE );
|
134 |
-
$permalink = get_post_meta( get_the_ID(), 'wprss_item_permalink', true );
|
135 |
-
$content = apply_filters( 'wprss_custom_feed_item_content', get_the_content() );
|
136 |
-
?>
|
137 |
-
<item>
|
138 |
-
<title><![CDATA[<?php the_title_rss(); ?>]]></title>
|
139 |
-
<link><?php echo $permalink; ?></link>
|
140 |
-
<guid isPermaLink="true"><?php echo $permalink; ?></guid>
|
141 |
-
<pubDate><?php echo get_post_time( DATE_RSS ); ?></pubDate>
|
142 |
-
<description><![CDATA[<?php echo $content; ?>]]></description>
|
143 |
-
<content:encoded><![CDATA[<?php echo $content; ?>]]></content:encoded>
|
144 |
-
<source url="<?php echo esc_attr(get_post_meta( $source, 'wprss_url', TRUE )); ?>"><?php echo get_the_title( $source ); ?></source>
|
145 |
-
<?php do_action( 'wprss_custom_feed_entry', get_the_ID() ); ?>
|
146 |
-
</item>
|
147 |
-
<?php
|
148 |
-
endwhile; // END OF LOOP
|
149 |
-
?>
|
150 |
-
</channel>
|
151 |
-
</rss>
|
152 |
-
<?php
|
153 |
-
}
|
154 |
-
|
155 |
-
|
156 |
-
add_filter( 'post_limits', 'wprss_custom_feed_limits' );
|
157 |
-
/**
|
158 |
-
* Set a different limit to our custom feeds
|
159 |
-
*
|
160 |
-
* @since 3.3
|
161 |
-
*/
|
162 |
-
function wprss_custom_feed_limits( $limit ) {
|
163 |
-
if ( is_feed( ) ) {
|
164 |
-
// return 'LIMIT 0, 3';
|
165 |
-
return $limit;
|
166 |
-
}
|
167 |
-
return $limit;
|
168 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Function to create a custom feed with the latest imported feed items
|
4 |
+
*
|
5 |
+
* @package WP RSS Aggregator
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
add_action( 'init', 'wprss_addfeed_add_feed' );
|
10 |
+
/**
|
11 |
+
* Adds the custom feed, as specified by the user in the general settings.
|
12 |
+
*
|
13 |
+
* @since 3.3
|
14 |
+
*/
|
15 |
+
function wprss_addfeed_add_feed() {
|
16 |
+
$general_settings = get_option( 'wprss_settings_general', 'wprss' );
|
17 |
+
if ( !empty( $general_settings ) && isset( $general_settings['custom_feed_url'] ) && !empty( $general_settings['custom_feed_url'] ) ) {
|
18 |
+
$url = $general_settings['custom_feed_url'];
|
19 |
+
}
|
20 |
+
else {
|
21 |
+
$url = $general_settings['custom_feed_url'] = 'wprss';
|
22 |
+
update_option( 'wprss_settings_general', $general_settings );
|
23 |
+
}
|
24 |
+
|
25 |
+
// Add the feed
|
26 |
+
add_feed( $url, 'wprss_addfeed_do_feed' );
|
27 |
+
|
28 |
+
// Whether or not the feed is already registered or not
|
29 |
+
$registered = FALSE;
|
30 |
+
|
31 |
+
// Get all registered rewrite rules
|
32 |
+
$rules = get_option( 'rewrite_rules' );
|
33 |
+
|
34 |
+
// If no rules exist, then it is not registered
|
35 |
+
if ( !is_array( $rules ) ) {
|
36 |
+
$registered = FALSE;
|
37 |
+
}
|
38 |
+
// If there are exisiting rules
|
39 |
+
else {
|
40 |
+
// Get all the array keys that match the given pattern
|
41 |
+
// The resulting array will only contain the second part of each matching key ( $matches[1] )
|
42 |
+
$feeds = array_keys( $rules, 'index.php?&feed=$matches[1]' );
|
43 |
+
// Check if the rewrite rule for the custom feed is already registered
|
44 |
+
foreach( $feeds as $feed ) {
|
45 |
+
if ( strpos( $feed, $url ) !== FALSE ) {
|
46 |
+
$registered = TRUE;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
// If not registered, flush the rewrite rules
|
52 |
+
if ( ! $registered ) {
|
53 |
+
flush_rewrite_rules();
|
54 |
+
}
|
55 |
+
|
56 |
+
}
|
57 |
+
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Generate the feed
|
61 |
+
*
|
62 |
+
* @since 3.3
|
63 |
+
*/
|
64 |
+
function wprss_addfeed_do_feed( $in ) {
|
65 |
+
|
66 |
+
// Prepare the post query
|
67 |
+
/*
|
68 |
+
$wprss_custom_feed_query = apply_filters(
|
69 |
+
'wprss_custom_feed_query',
|
70 |
+
array(
|
71 |
+
'post_type' => 'wprss_feed_item',
|
72 |
+
'post_status' => 'publish',
|
73 |
+
'cache_results' => false, // disable caching
|
74 |
+
)
|
75 |
+
|
76 |
+
);*/
|
77 |
+
$wprss_custom_feed_query = wprss_get_feed_items_query(
|
78 |
+
apply_filters(
|
79 |
+
'wprss_custom_feed_query',
|
80 |
+
array(
|
81 |
+
'get-args' => TRUE, // Get the query args instead of the query object
|
82 |
+
'no-paged' => TRUE, // ignore pagination
|
83 |
+
'feed_limit' => 0, // ignore limit
|
84 |
+
)
|
85 |
+
)
|
86 |
+
);
|
87 |
+
|
88 |
+
// Suppress caching
|
89 |
+
$wprss_custom_feed_query['cache_results'] = FALSE;
|
90 |
+
|
91 |
+
// Get options
|
92 |
+
$options = get_option( 'wprss_settings_general' );
|
93 |
+
if ( $options !== FALSE ) {
|
94 |
+
// If options exist, get the limit
|
95 |
+
$limit = $options['custom_feed_limit'];
|
96 |
+
if ( $limit !== FALSE ) {
|
97 |
+
// if limit exists, set the query limit
|
98 |
+
$wprss_custom_feed_query['posts_per_page'] = $limit;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
// Submit the query to get latest feed items
|
103 |
+
query_posts( $wprss_custom_feed_query );
|
104 |
+
|
105 |
+
$custom_feed_title = wprss_get_general_setting( 'custom_feed_title' );
|
106 |
+
|
107 |
+
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
|
108 |
+
header( "$protocol 200 OK" );
|
109 |
+
// Send content header and start ATOM output
|
110 |
+
header('Content-Type: application/rss+xml');
|
111 |
+
// Disabling caching
|
112 |
+
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
|
113 |
+
header('Pragma: no-cache'); // HTTP 1.0.
|
114 |
+
header('Expires: 0'); // Proxies.
|
115 |
+
echo '<?xml version="1.0" encoding="' . get_option('blog_charset') . '"?>';
|
116 |
+
?>
|
117 |
+
|
118 |
+
<rss version="2.0"
|
119 |
+
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
120 |
+
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
121 |
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
122 |
+
xmlns:atom="http://www.w3.org/2005/Atom"
|
123 |
+
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
|
124 |
+
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
|
125 |
+
xmlns:media="http://search.yahoo.com/mrss/" >
|
126 |
+
<channel>
|
127 |
+
<title><?php echo $custom_feed_title; ?></title>
|
128 |
+
<description></description>
|
129 |
+
<link><?php echo get_site_url(); ?></link>
|
130 |
+
<atom:link href="<?php echo $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] ?>" rel="self" type="application/rss+xml" />
|
131 |
+
<?php // Start the Loop
|
132 |
+
while ( have_posts() ) : the_post();
|
133 |
+
$source = get_post_meta( get_the_ID(), 'wprss_feed_id', TRUE );
|
134 |
+
$permalink = get_post_meta( get_the_ID(), 'wprss_item_permalink', true );
|
135 |
+
$content = apply_filters( 'wprss_custom_feed_item_content', get_the_content() );
|
136 |
+
?>
|
137 |
+
<item>
|
138 |
+
<title><![CDATA[<?php the_title_rss(); ?>]]></title>
|
139 |
+
<link><?php echo $permalink; ?></link>
|
140 |
+
<guid isPermaLink="true"><?php echo $permalink; ?></guid>
|
141 |
+
<pubDate><?php echo get_post_time( DATE_RSS ); ?></pubDate>
|
142 |
+
<description><![CDATA[<?php echo $content; ?>]]></description>
|
143 |
+
<content:encoded><![CDATA[<?php echo $content; ?>]]></content:encoded>
|
144 |
+
<source url="<?php echo esc_attr(get_post_meta( $source, 'wprss_url', TRUE )); ?>"><?php echo get_the_title( $source ); ?></source>
|
145 |
+
<?php do_action( 'wprss_custom_feed_entry', get_the_ID() ); ?>
|
146 |
+
</item>
|
147 |
+
<?php
|
148 |
+
endwhile; // END OF LOOP
|
149 |
+
?>
|
150 |
+
</channel>
|
151 |
+
</rss>
|
152 |
+
<?php
|
153 |
+
}
|
154 |
+
|
155 |
+
|
156 |
+
add_filter( 'post_limits', 'wprss_custom_feed_limits' );
|
157 |
+
/**
|
158 |
+
* Set a different limit to our custom feeds
|
159 |
+
*
|
160 |
+
* @since 3.3
|
161 |
+
*/
|
162 |
+
function wprss_custom_feed_limits( $limit ) {
|
163 |
+
if ( is_feed( ) ) {
|
164 |
+
// return 'LIMIT 0, 3';
|
165 |
+
return $limit;
|
166 |
+
}
|
167 |
+
return $limit;
|
168 |
}
|
includes/deprecated-functions.php
CHANGED
@@ -1,83 +1,83 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Fetches feed items from sources provided
|
5 |
-
* DEPRECATED - JUST FOR REFERENCE
|
6 |
-
*
|
7 |
-
* @since 2.0
|
8 |
-
* @deprecated 3.0
|
9 |
-
*/
|
10 |
-
/*function wprss_fetch_all_feed_items( ) {
|
11 |
-
|
12 |
-
// Get all feed sources
|
13 |
-
$feed_sources = new WP_Query( array(
|
14 |
-
'post_type' => 'wprss_feed',
|
15 |
-
'post_status' => 'publish',
|
16 |
-
'posts_per_page' => -1,
|
17 |
-
) );
|
18 |
-
|
19 |
-
if( $feed_sources->have_posts() ) {
|
20 |
-
/* Start by getting one feed source, we will cycle through them one by one,
|
21 |
-
fetching feed items and adding them to the database in each pass */
|
22 |
-
/* while ( $feed_sources->have_posts() ) {
|
23 |
-
$feed_sources->the_post();
|
24 |
-
|
25 |
-
$feed_ID = get_the_ID();
|
26 |
-
$feed_url = get_post_meta( get_the_ID(), 'wprss_url', true );
|
27 |
-
|
28 |
-
// Use the URL custom field to fetch the feed items for this source
|
29 |
-
if( !empty( $feed_url ) ) {
|
30 |
-
|
31 |
-
add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_return_7200' );
|
32 |
-
//$feed = fetch_feed( $feed_url );
|
33 |
-
$feed = wprss_fetch_feed( $feed_url, $feed_ID );
|
34 |
-
remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_return_7200' );
|
35 |
-
|
36 |
-
// $feed->strip_htmltags( array_merge( $feed->strip_htmltags, array('h1', 'a', 'img') ) );
|
37 |
-
|
38 |
-
if ( !is_wp_error( $feed ) ) {
|
39 |
-
// Figure out how many total items there are, but limit it to 10.
|
40 |
-
$maxitems = $feed->get_item_quantity(10);
|
41 |
-
|
42 |
-
// Build an array of all the items, starting with element 0 (first element).
|
43 |
-
$items = $feed->get_items( 0, $maxitems );
|
44 |
-
}
|
45 |
-
else { return; }
|
46 |
-
}
|
47 |
-
|
48 |
-
if ( ! empty( $items ) ) {
|
49 |
-
// Gather the permalinks of existing feed item's related to this feed source
|
50 |
-
global $wpdb;
|
51 |
-
$existing_permalinks = $wpdb->get_col(
|
52 |
-
"SELECT meta_value
|
53 |
-
FROM $wpdb->postmeta
|
54 |
-
WHERE meta_key = 'wprss_item_permalink'
|
55 |
-
AND post_id IN ( SELECT post_id FROM $wpdb->postmeta WHERE meta_value = $feed_ID)
|
56 |
-
");
|
57 |
-
|
58 |
-
foreach ( $items as $item ) {
|
59 |
-
// Check if newly fetched item already present in existing feed item item,
|
60 |
-
// if not insert it into wp_posts and insert post meta.
|
61 |
-
if ( ! ( in_array( $item->get_permalink(), $existing_permalinks ) ) ) {
|
62 |
-
// Create post object
|
63 |
-
$feed_item = array(
|
64 |
-
'post_title' => $item->get_title(),
|
65 |
-
'post_content' => '',
|
66 |
-
'post_status' => 'publish',
|
67 |
-
'post_type' => 'wprss_feed_item'
|
68 |
-
);
|
69 |
-
$inserted_ID = wp_insert_post( $feed_item );
|
70 |
-
wprss_items_create_post_meta( $inserted_ID, $item, $feed_ID );
|
71 |
-
} //end if
|
72 |
-
} //end foreach
|
73 |
-
} // end if
|
74 |
-
} // end $feed_sources while loop
|
75 |
-
wp_reset_postdata(); // Restore the $post global to the current post in the main query
|
76 |
-
// } // end if
|
77 |
-
} // end if
|
78 |
-
}
|
79 |
-
|
80 |
-
// For testing query speed
|
81 |
-
// $time_start = microtime( true );
|
82 |
-
// wp_die(number_format( microtime( true ) - $time_start, 10 ));
|
83 |
-
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fetches feed items from sources provided
|
5 |
+
* DEPRECATED - JUST FOR REFERENCE
|
6 |
+
*
|
7 |
+
* @since 2.0
|
8 |
+
* @deprecated 3.0
|
9 |
+
*/
|
10 |
+
/*function wprss_fetch_all_feed_items( ) {
|
11 |
+
|
12 |
+
// Get all feed sources
|
13 |
+
$feed_sources = new WP_Query( array(
|
14 |
+
'post_type' => 'wprss_feed',
|
15 |
+
'post_status' => 'publish',
|
16 |
+
'posts_per_page' => -1,
|
17 |
+
) );
|
18 |
+
|
19 |
+
if( $feed_sources->have_posts() ) {
|
20 |
+
/* Start by getting one feed source, we will cycle through them one by one,
|
21 |
+
fetching feed items and adding them to the database in each pass */
|
22 |
+
/* while ( $feed_sources->have_posts() ) {
|
23 |
+
$feed_sources->the_post();
|
24 |
+
|
25 |
+
$feed_ID = get_the_ID();
|
26 |
+
$feed_url = get_post_meta( get_the_ID(), 'wprss_url', true );
|
27 |
+
|
28 |
+
// Use the URL custom field to fetch the feed items for this source
|
29 |
+
if( !empty( $feed_url ) ) {
|
30 |
+
|
31 |
+
add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_return_7200' );
|
32 |
+
//$feed = fetch_feed( $feed_url );
|
33 |
+
$feed = wprss_fetch_feed( $feed_url, $feed_ID );
|
34 |
+
remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_return_7200' );
|
35 |
+
|
36 |
+
// $feed->strip_htmltags( array_merge( $feed->strip_htmltags, array('h1', 'a', 'img') ) );
|
37 |
+
|
38 |
+
if ( !is_wp_error( $feed ) ) {
|
39 |
+
// Figure out how many total items there are, but limit it to 10.
|
40 |
+
$maxitems = $feed->get_item_quantity(10);
|
41 |
+
|
42 |
+
// Build an array of all the items, starting with element 0 (first element).
|
43 |
+
$items = $feed->get_items( 0, $maxitems );
|
44 |
+
}
|
45 |
+
else { return; }
|
46 |
+
}
|
47 |
+
|
48 |
+
if ( ! empty( $items ) ) {
|
49 |
+
// Gather the permalinks of existing feed item's related to this feed source
|
50 |
+
global $wpdb;
|
51 |
+
$existing_permalinks = $wpdb->get_col(
|
52 |
+
"SELECT meta_value
|
53 |
+
FROM $wpdb->postmeta
|
54 |
+
WHERE meta_key = 'wprss_item_permalink'
|
55 |
+
AND post_id IN ( SELECT post_id FROM $wpdb->postmeta WHERE meta_value = $feed_ID)
|
56 |
+
");
|
57 |
+
|
58 |
+
foreach ( $items as $item ) {
|
59 |
+
// Check if newly fetched item already present in existing feed item item,
|
60 |
+
// if not insert it into wp_posts and insert post meta.
|
61 |
+
if ( ! ( in_array( $item->get_permalink(), $existing_permalinks ) ) ) {
|
62 |
+
// Create post object
|
63 |
+
$feed_item = array(
|
64 |
+
'post_title' => $item->get_title(),
|
65 |
+
'post_content' => '',
|
66 |
+
'post_status' => 'publish',
|
67 |
+
'post_type' => 'wprss_feed_item'
|
68 |
+
);
|
69 |
+
$inserted_ID = wp_insert_post( $feed_item );
|
70 |
+
wprss_items_create_post_meta( $inserted_ID, $item, $feed_ID );
|
71 |
+
} //end if
|
72 |
+
} //end foreach
|
73 |
+
} // end if
|
74 |
+
} // end $feed_sources while loop
|
75 |
+
wp_reset_postdata(); // Restore the $post global to the current post in the main query
|
76 |
+
// } // end if
|
77 |
+
} // end if
|
78 |
+
}
|
79 |
+
|
80 |
+
// For testing query speed
|
81 |
+
// $time_start = microtime( true );
|
82 |
+
// wp_die(number_format( microtime( true ) - $time_start, 10 ));
|
83 |
+
|
includes/feed-blacklist.php
CHANGED
@@ -1,353 +1,353 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* This file contains all functions relating to the blacklisting of
|
5 |
-
* imported feeds items.
|
6 |
-
*
|
7 |
-
* Blacklisting a feed item is in essence nothing more than a saved list
|
8 |
-
* of feed items. When a feed item is imported, its normalized permalink
|
9 |
-
* is tested against this list, and if found, the feed item is not
|
10 |
-
* imported. Admins can add items to the blacklist, to prevent them
|
11 |
-
* from being imported again.
|
12 |
-
*
|
13 |
-
* @package WP RSS Aggregator
|
14 |
-
* @since 4.4
|
15 |
-
*/
|
16 |
-
|
17 |
-
|
18 |
-
// Check if the 'blacklist' GET param is set
|
19 |
-
add_action( 'admin_init', 'wprss_check_if_blacklist_item' );
|
20 |
-
// Checks if the transient is set to show the notice
|
21 |
-
add_action( 'admin_init', 'wprss_check_notice_transient' );
|
22 |
-
// Register custom post type
|
23 |
-
add_action( 'init', 'wprss_blacklist_cpt' );
|
24 |
-
// Add the row actions to the targetted post type
|
25 |
-
add_filter( 'post_row_actions', 'wprss_blacklist_row_actions', 10, 1 );
|
26 |
-
// Check if deleting a blacklist item, from the GET parameter
|
27 |
-
add_action( 'admin_init', 'wprss_check_if_blacklist_delete' );
|
28 |
-
// Changes the wprss_blacklist table columns
|
29 |
-
add_filter( 'manage_wprss_blacklist_posts_columns', 'wprss_blacklist_columns');
|
30 |
-
// Prints the table data for each blacklist entry
|
31 |
-
add_action( 'manage_wprss_blacklist_posts_custom_column' , 'wprss_blacklist_table_contents', 10, 2 );
|
32 |
-
// Changes the wprss_blacklist bulk actions
|
33 |
-
add_filter('bulk_actions-edit-wprss_blacklist','wprss_blacklist_bulk_actions', 5, 1 );
|
34 |
-
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Retrieves the blacklisted items.
|
38 |
-
*
|
39 |
-
* @since 4.4
|
40 |
-
* @return array An associative array of blacklisted item, each entry
|
41 |
-
* having the key as the permalink, and the value as the title.
|
42 |
-
*/
|
43 |
-
function wprss_get_blacklist() {
|
44 |
-
// Get the option
|
45 |
-
$blacklist_option = get_option('wprss_blacklist');
|
46 |
-
// If the option does not exist
|
47 |
-
if ( $blacklist_option === FALSE || !is_array( $blacklist_option ) ) {
|
48 |
-
// create it
|
49 |
-
update_option( 'wprss_blacklist', array() );
|
50 |
-
$blacklist_option = array();
|
51 |
-
}
|
52 |
-
return $blacklist_option;
|
53 |
-
}
|
54 |
-
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Creates a blacklist entry for the given feed item.
|
58 |
-
*
|
59 |
-
* @since 4.4
|
60 |
-
* @param int|string The ID of the feed item to add to the blacklist
|
61 |
-
*/
|
62 |
-
function wprss_blacklist_item( $ID ) {
|
63 |
-
// Return if feed item is null
|
64 |
-
if ( is_null( $ID ) ) return;
|
65 |
-
|
66 |
-
// Get the feed item data
|
67 |
-
$item_title = get_the_title( $ID );
|
68 |
-
$item_permalink = get_post_meta( $ID, 'wprss_item_permalink', TRUE );
|
69 |
-
// If not an imported item, stop
|
70 |
-
if ( $item_permalink === '' ) {
|
71 |
-
wprss_log_obj( 'An item being blacklisted was ignored for not being an imported item', $ID, null, WPRSS_LOG_LEVEL_INFO );
|
72 |
-
return;
|
73 |
-
}
|
74 |
-
// Prepare the data for blacklisting
|
75 |
-
$title = apply_filters( 'wprss_blacklist_title', trim( $item_title ) );
|
76 |
-
$permalink = apply_filters( 'wprss_blacklist_permalink', trim( $item_permalink ) );
|
77 |
-
|
78 |
-
// Get the blacklisted items
|
79 |
-
$blacklist = wprss_get_blacklist();
|
80 |
-
// Add the item to the blacklist
|
81 |
-
$blacklist[ $permalink ] = $title;
|
82 |
-
|
83 |
-
// Delete the item
|
84 |
-
wp_delete_post( $ID, TRUE );
|
85 |
-
|
86 |
-
// Add the blacklisted item
|
87 |
-
$id = wp_insert_post(array(
|
88 |
-
'post_title' => $title,
|
89 |
-
'post_type' => 'wprss_blacklist',
|
90 |
-
'post_status' => 'publish'
|
91 |
-
));
|
92 |
-
update_post_meta( $id, 'wprss_permalink', $permalink );
|
93 |
-
}
|
94 |
-
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Determines whether the given item is blacklist.
|
98 |
-
*
|
99 |
-
* @since 4.4
|
100 |
-
* @param string $permalink The permalink to look for in the saved option
|
101 |
-
* @return bool TRUE if the permalink is found, FALSE otherwise.
|
102 |
-
*/
|
103 |
-
function wprss_is_blacklisted( $permalink ) {
|
104 |
-
// Query the blacklist entries, for an item with the given permalink
|
105 |
-
$query = new WP_Query(array(
|
106 |
-
'post_type' => 'wprss_blacklist',
|
107 |
-
'meta_key' => 'wprss_permalink',
|
108 |
-
'meta_value' => $permalink
|
109 |
-
));
|
110 |
-
// Return TRUE if the query returned a result, FALSE otherwise
|
111 |
-
return $query->have_posts();
|
112 |
-
}
|
113 |
-
|
114 |
-
|
115 |
-
/**
|
116 |
-
* Check if the 'blacklist' GET param is set, and prepare to blacklist
|
117 |
-
* the item.
|
118 |
-
*
|
119 |
-
* @since 4.4
|
120 |
-
*/
|
121 |
-
function wprss_check_if_blacklist_item() {
|
122 |
-
// If the GET param is not set, do nothing. Return.
|
123 |
-
if ( empty( $_GET['wprss_blacklist'] ) ) return;
|
124 |
-
|
125 |
-
// Get the ID from the GET param
|
126 |
-
$ID = $_GET['wprss_blacklist'];
|
127 |
-
// If the post does not exist, stop. Show a message
|
128 |
-
if ( get_post($ID) === NULL ) {
|
129 |
-
wp_die( __( 'The item you are trying to blacklist does not exist', WPRSS_TEXT_DOMAIN ) );
|
130 |
-
}
|
131 |
-
|
132 |
-
// If the post type is not correct,
|
133 |
-
if ( get_post_meta( $ID, 'wprss_item_permalink', TRUE ) === '' || get_post_status( $ID ) !== 'trash' ) {
|
134 |
-
wp_die( __( 'The item you are trying to blacklist is not valid!', WPRSS_TEXT_DOMAIN ) );
|
135 |
-
}
|
136 |
-
|
137 |
-
check_admin_referer( 'blacklist-item-' . $ID, 'wprss_blacklist_item' );
|
138 |
-
wprss_blacklist_item( $ID );
|
139 |
-
|
140 |
-
// Get the current post type for the current page
|
141 |
-
$post_type = isset( $_GET['post_type'] )? $_GET['post_type'] : 'post';
|
142 |
-
// Check the current page, and generate the URL query string for the page
|
143 |
-
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
144 |
-
// Set the notice transient
|
145 |
-
set_transient( 'wprss_item_blacklist_notice', 'true' );
|
146 |
-
// Refresh the page without the GET parameter
|
147 |
-
wp_redirect( admin_url( "edit.php?post_type=$post_type&post_status=trash" . $paged ) );
|
148 |
-
exit();
|
149 |
-
}
|
150 |
-
|
151 |
-
|
152 |
-
/**
|
153 |
-
* Checks if the transient for the blacklist notice is set, and shows the notice
|
154 |
-
* if it is set.
|
155 |
-
*/
|
156 |
-
function wprss_check_notice_transient() {
|
157 |
-
// Check if the transient exists
|
158 |
-
$transient = get_transient( 'wprss_item_blacklist_notice' );
|
159 |
-
if ( $transient !== FALSE ) {
|
160 |
-
// Remove the transient
|
161 |
-
delete_transient( 'wprss_item_blacklist_notice' );
|
162 |
-
// Show the notice
|
163 |
-
add_action( 'admin_notices', 'wprss_blacklist_item_notice' );
|
164 |
-
}
|
165 |
-
}
|
166 |
-
|
167 |
-
/**
|
168 |
-
* The admin notice shown when an item is blacklisted.
|
169 |
-
*/
|
170 |
-
function wprss_blacklist_item_notice() {
|
171 |
-
?>
|
172 |
-
<div class="updated">
|
173 |
-
<p>
|
174 |
-
The item was deleted successfully and added to the blacklist.
|
175 |
-
</p>
|
176 |
-
</div>
|
177 |
-
<?php
|
178 |
-
}
|
179 |
-
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Registers the Blacklist Custom Post Type.
|
183 |
-
*
|
184 |
-
* @since 4.4
|
185 |
-
*/
|
186 |
-
function wprss_blacklist_cpt() {
|
187 |
-
register_post_type( 'wprss_blacklist', array(
|
188 |
-
'label' => 'Blacklist',
|
189 |
-
'public' => false,
|
190 |
-
'exclude_from_search' => true,
|
191 |
-
'show_ui' => true,
|
192 |
-
'show_in_menu' => 'edit.php?post_type=wprss_feed',
|
193 |
-
'capability_type' => 'feed_source',
|
194 |
-
'supports' => array( 'title' ),
|
195 |
-
'labels' => array(
|
196 |
-
'name' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
197 |
-
'singular_name' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
198 |
-
'all_items' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
199 |
-
'search_items' => __( 'Search Blacklist', WPRSS_TEXT_DOMAIN ),
|
200 |
-
'not_found' => __( 'You do not have any items blacklisted yet!', WPRSS_TEXT_DOMAIN ),
|
201 |
-
)
|
202 |
-
));
|
203 |
-
}
|
204 |
-
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Adds the row actions to the targetted post type.
|
208 |
-
* Default post type = wprss_feed_item
|
209 |
-
*
|
210 |
-
* @since 4.4
|
211 |
-
* @param array $actions The row actions to be filtered
|
212 |
-
* @return array The new filtered row actions
|
213 |
-
*/
|
214 |
-
function wprss_blacklist_row_actions( $actions ) {
|
215 |
-
// Check the current page, and generate the URL query string for the page
|
216 |
-
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
217 |
-
|
218 |
-
|
219 |
-
// Check the post type
|
220 |
-
if ( get_post_status() == 'trash' ) {
|
221 |
-
// Get the Post ID
|
222 |
-
$ID = get_the_ID();
|
223 |
-
|
224 |
-
// Get the permalink. If does not exist, then it is not an imported item.
|
225 |
-
$permalink = get_post_meta( $ID, 'wprss_item_permalink', TRUE );
|
226 |
-
if ( $permalink === '' ) {
|
227 |
-
$actions;
|
228 |
-
}
|
229 |
-
|
230 |
-
// The post type on the current screen
|
231 |
-
$post_type = get_post_type();
|
232 |
-
// Prepare the blacklist URL
|
233 |
-
$plain_url = apply_filters(
|
234 |
-
'wprss_blacklist_row_action_url',
|
235 |
-
admin_url( "edit.php?post_type=$post_type&wprss_blacklist=$ID" ),
|
236 |
-
$ID
|
237 |
-
) . $paged;
|
238 |
-
// Add a nonce to the URL
|
239 |
-
$nonced_url = wp_nonce_url( $plain_url, 'blacklist-item-' . $ID, 'wprss_blacklist_item' );
|
240 |
-
|
241 |
-
// Prepare the text
|
242 |
-
$text = apply_filters( 'wprss_blacklist_row_action_text', htmlentities( __( 'Delete Permanently & Blacklist', WPRSS_TEXT_DOMAIN ) ) );
|
243 |
-
$text = __( $text, WPRSS_TEXT_DOMAIN );
|
244 |
-
|
245 |
-
// Prepare the hint
|
246 |
-
$hint = apply_filters(
|
247 |
-
'wprss_blacklist_row_action_hint',
|
248 |
-
__( 'The item will be deleted permanently, and its permalink will be recorded in the blacklist', WPRSS_TEXT_DOMAIN )
|
249 |
-
);
|
250 |
-
$hint = esc_attr( __( $hint, WPRSS_TEXT_DOMAIN ) );
|
251 |
-
|
252 |
-
// Add the blacklist action
|
253 |
-
$actions['blacklist-item'] = "<span class='delete'><a title='$hint' href='$nonced_url'>$text</a></span>";
|
254 |
-
}
|
255 |
-
|
256 |
-
// For the blacklisted item
|
257 |
-
elseif ( get_post_type() === 'wprss_blacklist' ) {
|
258 |
-
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
259 |
-
$remove_url = wp_nonce_url( 'post.php?wprss-blacklist-remove='.get_the_ID(), 'blacklist-remove-' . get_the_ID(), 'wprss_blacklist_trash' );
|
260 |
-
$actions = array(
|
261 |
-
'trash' => '<a href="'.$remove_url.'">' . __( 'Remove from blacklist', WPRSS_TEXT_DOMAIN ) . '</a>'
|
262 |
-
);
|
263 |
-
}
|
264 |
-
|
265 |
-
// Return the actions
|
266 |
-
return $actions;
|
267 |
-
}
|
268 |
-
|
269 |
-
|
270 |
-
/**
|
271 |
-
* Checks for the GET parameter wprss-blacklist-remove, and if present,
|
272 |
-
* deletes the appropriate blacklist entry. Uses nonce 'wprss_blacklist_trash'
|
273 |
-
* with action 'blacklist-remove-$ID'
|
274 |
-
*
|
275 |
-
* @since 4.4
|
276 |
-
*/
|
277 |
-
function wprss_check_if_blacklist_delete() {
|
278 |
-
// If the GET param is not set, do nothing. Return.
|
279 |
-
if ( empty( $_GET['wprss-blacklist-remove'] ) ) return;
|
280 |
-
|
281 |
-
// The array of blacklist entries to delete
|
282 |
-
$to_delete = array();
|
283 |
-
// The ID of the blacklist entry - if only deleting a single entry
|
284 |
-
$ID = $_GET['wprss-blacklist-remove'];
|
285 |
-
|
286 |
-
// check if deleting in bulk
|
287 |
-
if ( isset( $_GET['wprss-bulk'] ) && $_GET['wprss-bulk'] == '1' ) {
|
288 |
-
$to_delete = explode( ',', $ID );
|
289 |
-
check_admin_referer( 'blacklist-remove-selected', 'wprss_blacklist_trash' );
|
290 |
-
} else {
|
291 |
-
$to_delete = array( $ID );
|
292 |
-
// Get the ID from the GET param
|
293 |
-
// Verify the nonce
|
294 |
-
check_admin_referer( 'blacklist-remove-' . $ID, 'wprss_blacklist_trash' );
|
295 |
-
}
|
296 |
-
|
297 |
-
// Delete the posts marked for delete
|
298 |
-
foreach( $to_delete as $delete_id ) {
|
299 |
-
$post = get_post( $delete_id );
|
300 |
-
if ( $post === NULL || get_post_type( $post ) !== 'wprss_blacklist' ) continue;
|
301 |
-
wp_delete_post( $delete_id, TRUE );
|
302 |
-
}
|
303 |
-
|
304 |
-
// Redirect back to blacklists page
|
305 |
-
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
306 |
-
header('Location: ' . admin_url('edit.php?post_type=wprss_blacklist' . $paged ) );
|
307 |
-
exit;
|
308 |
-
}
|
309 |
-
|
310 |
-
|
311 |
-
/**
|
312 |
-
* Returns the custom columns for the blacklist post type
|
313 |
-
*
|
314 |
-
* @since 4.4
|
315 |
-
* @params array $cols The columns to filter
|
316 |
-
* @return array The new columns
|
317 |
-
*/
|
318 |
-
function wprss_blacklist_columns( $cols ) {
|
319 |
-
return array(
|
320 |
-
'cb' => $cols['cb'],
|
321 |
-
'title' => __( 'Title' ),
|
322 |
-
'permalink' => __( 'Permalink' )
|
323 |
-
);
|
324 |
-
}
|
325 |
-
|
326 |
-
|
327 |
-
/**
|
328 |
-
* Prints the cell data in the table for each blacklist entry
|
329 |
-
*
|
330 |
-
* @since 4.4
|
331 |
-
* @param string $column The column slug
|
332 |
-
* @param string|int $ID The ID of the post currently being printed
|
333 |
-
*/
|
334 |
-
function wprss_blacklist_table_contents( $column, $ID ) {
|
335 |
-
switch ( $column ) {
|
336 |
-
case 'permalink':
|
337 |
-
$permalink = get_post_meta( $ID, 'wprss_permalink', TRUE );
|
338 |
-
echo '<a href="'.$permalink.'" target="_blank">'.$permalink.'</a>';
|
339 |
-
break;
|
340 |
-
}
|
341 |
-
}
|
342 |
-
|
343 |
-
|
344 |
-
/**
|
345 |
-
* Removes the bulk actions for the Blacklist post type
|
346 |
-
*
|
347 |
-
* @since 4.4
|
348 |
-
* @param array $actions The array of actions to be filtered
|
349 |
-
* @return array An empty array
|
350 |
-
*/
|
351 |
-
function wprss_blacklist_bulk_actions( $actions ) {
|
352 |
-
return array();
|
353 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This file contains all functions relating to the blacklisting of
|
5 |
+
* imported feeds items.
|
6 |
+
*
|
7 |
+
* Blacklisting a feed item is in essence nothing more than a saved list
|
8 |
+
* of feed items. When a feed item is imported, its normalized permalink
|
9 |
+
* is tested against this list, and if found, the feed item is not
|
10 |
+
* imported. Admins can add items to the blacklist, to prevent them
|
11 |
+
* from being imported again.
|
12 |
+
*
|
13 |
+
* @package WP RSS Aggregator
|
14 |
+
* @since 4.4
|
15 |
+
*/
|
16 |
+
|
17 |
+
|
18 |
+
// Check if the 'blacklist' GET param is set
|
19 |
+
add_action( 'admin_init', 'wprss_check_if_blacklist_item' );
|
20 |
+
// Checks if the transient is set to show the notice
|
21 |
+
add_action( 'admin_init', 'wprss_check_notice_transient' );
|
22 |
+
// Register custom post type
|
23 |
+
add_action( 'init', 'wprss_blacklist_cpt' );
|
24 |
+
// Add the row actions to the targetted post type
|
25 |
+
add_filter( 'post_row_actions', 'wprss_blacklist_row_actions', 10, 1 );
|
26 |
+
// Check if deleting a blacklist item, from the GET parameter
|
27 |
+
add_action( 'admin_init', 'wprss_check_if_blacklist_delete' );
|
28 |
+
// Changes the wprss_blacklist table columns
|
29 |
+
add_filter( 'manage_wprss_blacklist_posts_columns', 'wprss_blacklist_columns');
|
30 |
+
// Prints the table data for each blacklist entry
|
31 |
+
add_action( 'manage_wprss_blacklist_posts_custom_column' , 'wprss_blacklist_table_contents', 10, 2 );
|
32 |
+
// Changes the wprss_blacklist bulk actions
|
33 |
+
add_filter('bulk_actions-edit-wprss_blacklist','wprss_blacklist_bulk_actions', 5, 1 );
|
34 |
+
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Retrieves the blacklisted items.
|
38 |
+
*
|
39 |
+
* @since 4.4
|
40 |
+
* @return array An associative array of blacklisted item, each entry
|
41 |
+
* having the key as the permalink, and the value as the title.
|
42 |
+
*/
|
43 |
+
function wprss_get_blacklist() {
|
44 |
+
// Get the option
|
45 |
+
$blacklist_option = get_option('wprss_blacklist');
|
46 |
+
// If the option does not exist
|
47 |
+
if ( $blacklist_option === FALSE || !is_array( $blacklist_option ) ) {
|
48 |
+
// create it
|
49 |
+
update_option( 'wprss_blacklist', array() );
|
50 |
+
$blacklist_option = array();
|
51 |
+
}
|
52 |
+
return $blacklist_option;
|
53 |
+
}
|
54 |
+
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Creates a blacklist entry for the given feed item.
|
58 |
+
*
|
59 |
+
* @since 4.4
|
60 |
+
* @param int|string The ID of the feed item to add to the blacklist
|
61 |
+
*/
|
62 |
+
function wprss_blacklist_item( $ID ) {
|
63 |
+
// Return if feed item is null
|
64 |
+
if ( is_null( $ID ) ) return;
|
65 |
+
|
66 |
+
// Get the feed item data
|
67 |
+
$item_title = get_the_title( $ID );
|
68 |
+
$item_permalink = get_post_meta( $ID, 'wprss_item_permalink', TRUE );
|
69 |
+
// If not an imported item, stop
|
70 |
+
if ( $item_permalink === '' ) {
|
71 |
+
wprss_log_obj( 'An item being blacklisted was ignored for not being an imported item', $ID, null, WPRSS_LOG_LEVEL_INFO );
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
// Prepare the data for blacklisting
|
75 |
+
$title = apply_filters( 'wprss_blacklist_title', trim( $item_title ) );
|
76 |
+
$permalink = apply_filters( 'wprss_blacklist_permalink', trim( $item_permalink ) );
|
77 |
+
|
78 |
+
// Get the blacklisted items
|
79 |
+
$blacklist = wprss_get_blacklist();
|
80 |
+
// Add the item to the blacklist
|
81 |
+
$blacklist[ $permalink ] = $title;
|
82 |
+
|
83 |
+
// Delete the item
|
84 |
+
wp_delete_post( $ID, TRUE );
|
85 |
+
|
86 |
+
// Add the blacklisted item
|
87 |
+
$id = wp_insert_post(array(
|
88 |
+
'post_title' => $title,
|
89 |
+
'post_type' => 'wprss_blacklist',
|
90 |
+
'post_status' => 'publish'
|
91 |
+
));
|
92 |
+
update_post_meta( $id, 'wprss_permalink', $permalink );
|
93 |
+
}
|
94 |
+
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Determines whether the given item is blacklist.
|
98 |
+
*
|
99 |
+
* @since 4.4
|
100 |
+
* @param string $permalink The permalink to look for in the saved option
|
101 |
+
* @return bool TRUE if the permalink is found, FALSE otherwise.
|
102 |
+
*/
|
103 |
+
function wprss_is_blacklisted( $permalink ) {
|
104 |
+
// Query the blacklist entries, for an item with the given permalink
|
105 |
+
$query = new WP_Query(array(
|
106 |
+
'post_type' => 'wprss_blacklist',
|
107 |
+
'meta_key' => 'wprss_permalink',
|
108 |
+
'meta_value' => $permalink
|
109 |
+
));
|
110 |
+
// Return TRUE if the query returned a result, FALSE otherwise
|
111 |
+
return $query->have_posts();
|
112 |
+
}
|
113 |
+
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Check if the 'blacklist' GET param is set, and prepare to blacklist
|
117 |
+
* the item.
|
118 |
+
*
|
119 |
+
* @since 4.4
|
120 |
+
*/
|
121 |
+
function wprss_check_if_blacklist_item() {
|
122 |
+
// If the GET param is not set, do nothing. Return.
|
123 |
+
if ( empty( $_GET['wprss_blacklist'] ) ) return;
|
124 |
+
|
125 |
+
// Get the ID from the GET param
|
126 |
+
$ID = $_GET['wprss_blacklist'];
|
127 |
+
// If the post does not exist, stop. Show a message
|
128 |
+
if ( get_post($ID) === NULL ) {
|
129 |
+
wp_die( __( 'The item you are trying to blacklist does not exist', WPRSS_TEXT_DOMAIN ) );
|
130 |
+
}
|
131 |
+
|
132 |
+
// If the post type is not correct,
|
133 |
+
if ( get_post_meta( $ID, 'wprss_item_permalink', TRUE ) === '' || get_post_status( $ID ) !== 'trash' ) {
|
134 |
+
wp_die( __( 'The item you are trying to blacklist is not valid!', WPRSS_TEXT_DOMAIN ) );
|
135 |
+
}
|
136 |
+
|
137 |
+
check_admin_referer( 'blacklist-item-' . $ID, 'wprss_blacklist_item' );
|
138 |
+
wprss_blacklist_item( $ID );
|
139 |
+
|
140 |
+
// Get the current post type for the current page
|
141 |
+
$post_type = isset( $_GET['post_type'] )? $_GET['post_type'] : 'post';
|
142 |
+
// Check the current page, and generate the URL query string for the page
|
143 |
+
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
144 |
+
// Set the notice transient
|
145 |
+
set_transient( 'wprss_item_blacklist_notice', 'true' );
|
146 |
+
// Refresh the page without the GET parameter
|
147 |
+
wp_redirect( admin_url( "edit.php?post_type=$post_type&post_status=trash" . $paged ) );
|
148 |
+
exit();
|
149 |
+
}
|
150 |
+
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Checks if the transient for the blacklist notice is set, and shows the notice
|
154 |
+
* if it is set.
|
155 |
+
*/
|
156 |
+
function wprss_check_notice_transient() {
|
157 |
+
// Check if the transient exists
|
158 |
+
$transient = get_transient( 'wprss_item_blacklist_notice' );
|
159 |
+
if ( $transient !== FALSE ) {
|
160 |
+
// Remove the transient
|
161 |
+
delete_transient( 'wprss_item_blacklist_notice' );
|
162 |
+
// Show the notice
|
163 |
+
add_action( 'admin_notices', 'wprss_blacklist_item_notice' );
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* The admin notice shown when an item is blacklisted.
|
169 |
+
*/
|
170 |
+
function wprss_blacklist_item_notice() {
|
171 |
+
?>
|
172 |
+
<div class="updated">
|
173 |
+
<p>
|
174 |
+
The item was deleted successfully and added to the blacklist.
|
175 |
+
</p>
|
176 |
+
</div>
|
177 |
+
<?php
|
178 |
+
}
|
179 |
+
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Registers the Blacklist Custom Post Type.
|
183 |
+
*
|
184 |
+
* @since 4.4
|
185 |
+
*/
|
186 |
+
function wprss_blacklist_cpt() {
|
187 |
+
register_post_type( 'wprss_blacklist', array(
|
188 |
+
'label' => 'Blacklist',
|
189 |
+
'public' => false,
|
190 |
+
'exclude_from_search' => true,
|
191 |
+
'show_ui' => true,
|
192 |
+
'show_in_menu' => 'edit.php?post_type=wprss_feed',
|
193 |
+
'capability_type' => 'feed_source',
|
194 |
+
'supports' => array( 'title' ),
|
195 |
+
'labels' => array(
|
196 |
+
'name' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
197 |
+
'singular_name' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
198 |
+
'all_items' => __( 'Blacklist', WPRSS_TEXT_DOMAIN ),
|
199 |
+
'search_items' => __( 'Search Blacklist', WPRSS_TEXT_DOMAIN ),
|
200 |
+
'not_found' => __( 'You do not have any items blacklisted yet!', WPRSS_TEXT_DOMAIN ),
|
201 |
+
)
|
202 |
+
));
|
203 |
+
}
|
204 |
+
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Adds the row actions to the targetted post type.
|
208 |
+
* Default post type = wprss_feed_item
|
209 |
+
*
|
210 |
+
* @since 4.4
|
211 |
+
* @param array $actions The row actions to be filtered
|
212 |
+
* @return array The new filtered row actions
|
213 |
+
*/
|
214 |
+
function wprss_blacklist_row_actions( $actions ) {
|
215 |
+
// Check the current page, and generate the URL query string for the page
|
216 |
+
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
217 |
+
|
218 |
+
|
219 |
+
// Check the post type
|
220 |
+
if ( get_post_status() == 'trash' ) {
|
221 |
+
// Get the Post ID
|
222 |
+
$ID = get_the_ID();
|
223 |
+
|
224 |
+
// Get the permalink. If does not exist, then it is not an imported item.
|
225 |
+
$permalink = get_post_meta( $ID, 'wprss_item_permalink', TRUE );
|
226 |
+
if ( $permalink === '' ) {
|
227 |
+
$actions;
|
228 |
+
}
|
229 |
+
|
230 |
+
// The post type on the current screen
|
231 |
+
$post_type = get_post_type();
|
232 |
+
// Prepare the blacklist URL
|
233 |
+
$plain_url = apply_filters(
|
234 |
+
'wprss_blacklist_row_action_url',
|
235 |
+
admin_url( "edit.php?post_type=$post_type&wprss_blacklist=$ID" ),
|
236 |
+
$ID
|
237 |
+
) . $paged;
|
238 |
+
// Add a nonce to the URL
|
239 |
+
$nonced_url = wp_nonce_url( $plain_url, 'blacklist-item-' . $ID, 'wprss_blacklist_item' );
|
240 |
+
|
241 |
+
// Prepare the text
|
242 |
+
$text = apply_filters( 'wprss_blacklist_row_action_text', htmlentities( __( 'Delete Permanently & Blacklist', WPRSS_TEXT_DOMAIN ) ) );
|
243 |
+
$text = __( $text, WPRSS_TEXT_DOMAIN );
|
244 |
+
|
245 |
+
// Prepare the hint
|
246 |
+
$hint = apply_filters(
|
247 |
+
'wprss_blacklist_row_action_hint',
|
248 |
+
__( 'The item will be deleted permanently, and its permalink will be recorded in the blacklist', WPRSS_TEXT_DOMAIN )
|
249 |
+
);
|
250 |
+
$hint = esc_attr( __( $hint, WPRSS_TEXT_DOMAIN ) );
|
251 |
+
|
252 |
+
// Add the blacklist action
|
253 |
+
$actions['blacklist-item'] = "<span class='delete'><a title='$hint' href='$nonced_url'>$text</a></span>";
|
254 |
+
}
|
255 |
+
|
256 |
+
// For the blacklisted item
|
257 |
+
elseif ( get_post_type() === 'wprss_blacklist' ) {
|
258 |
+
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
259 |
+
$remove_url = wp_nonce_url( 'post.php?wprss-blacklist-remove='.get_the_ID(), 'blacklist-remove-' . get_the_ID(), 'wprss_blacklist_trash' );
|
260 |
+
$actions = array(
|
261 |
+
'trash' => '<a href="'.$remove_url.'">' . __( 'Remove from blacklist', WPRSS_TEXT_DOMAIN ) . '</a>'
|
262 |
+
);
|
263 |
+
}
|
264 |
+
|
265 |
+
// Return the actions
|
266 |
+
return $actions;
|
267 |
+
}
|
268 |
+
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Checks for the GET parameter wprss-blacklist-remove, and if present,
|
272 |
+
* deletes the appropriate blacklist entry. Uses nonce 'wprss_blacklist_trash'
|
273 |
+
* with action 'blacklist-remove-$ID'
|
274 |
+
*
|
275 |
+
* @since 4.4
|
276 |
+
*/
|
277 |
+
function wprss_check_if_blacklist_delete() {
|
278 |
+
// If the GET param is not set, do nothing. Return.
|
279 |
+
if ( empty( $_GET['wprss-blacklist-remove'] ) ) return;
|
280 |
+
|
281 |
+
// The array of blacklist entries to delete
|
282 |
+
$to_delete = array();
|
283 |
+
// The ID of the blacklist entry - if only deleting a single entry
|
284 |
+
$ID = $_GET['wprss-blacklist-remove'];
|
285 |
+
|
286 |
+
// check if deleting in bulk
|
287 |
+
if ( isset( $_GET['wprss-bulk'] ) && $_GET['wprss-bulk'] == '1' ) {
|
288 |
+
$to_delete = explode( ',', $ID );
|
289 |
+
check_admin_referer( 'blacklist-remove-selected', 'wprss_blacklist_trash' );
|
290 |
+
} else {
|
291 |
+
$to_delete = array( $ID );
|
292 |
+
// Get the ID from the GET param
|
293 |
+
// Verify the nonce
|
294 |
+
check_admin_referer( 'blacklist-remove-' . $ID, 'wprss_blacklist_trash' );
|
295 |
+
}
|
296 |
+
|
297 |
+
// Delete the posts marked for delete
|
298 |
+
foreach( $to_delete as $delete_id ) {
|
299 |
+
$post = get_post( $delete_id );
|
300 |
+
if ( $post === NULL || get_post_type( $post ) !== 'wprss_blacklist' ) continue;
|
301 |
+
wp_delete_post( $delete_id, TRUE );
|
302 |
+
}
|
303 |
+
|
304 |
+
// Redirect back to blacklists page
|
305 |
+
$paged = isset( $_GET['paged'] )? '&paged=' . $_GET['paged'] : '';
|
306 |
+
header('Location: ' . admin_url('edit.php?post_type=wprss_blacklist' . $paged ) );
|
307 |
+
exit;
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Returns the custom columns for the blacklist post type
|
313 |
+
*
|
314 |
+
* @since 4.4
|
315 |
+
* @params array $cols The columns to filter
|
316 |
+
* @return array The new columns
|
317 |
+
*/
|
318 |
+
function wprss_blacklist_columns( $cols ) {
|
319 |
+
return array(
|
320 |
+
'cb' => $cols['cb'],
|
321 |
+
'title' => __( 'Title' ),
|
322 |
+
'permalink' => __( 'Permalink' )
|
323 |
+
);
|
324 |
+
}
|
325 |
+
|
326 |
+
|
327 |
+
/**
|
328 |
+
* Prints the cell data in the table for each blacklist entry
|
329 |
+
*
|
330 |
+
* @since 4.4
|
331 |
+
* @param string $column The column slug
|
332 |
+
* @param string|int $ID The ID of the post currently being printed
|
333 |
+
*/
|
334 |
+
function wprss_blacklist_table_contents( $column, $ID ) {
|
335 |
+
switch ( $column ) {
|
336 |
+
case 'permalink':
|
337 |
+
$permalink = get_post_meta( $ID, 'wprss_permalink', TRUE );
|
338 |
+
echo '<a href="'.$permalink.'" target="_blank">'.$permalink.'</a>';
|
339 |
+
break;
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Removes the bulk actions for the Blacklist post type
|
346 |
+
*
|
347 |
+
* @since 4.4
|
348 |
+
* @param array $actions The array of actions to be filtered
|
349 |
+
* @return array An empty array
|
350 |
+
*/
|
351 |
+
function wprss_blacklist_bulk_actions( $actions ) {
|
352 |
+
return array();
|
353 |
}
|
includes/feed-display.php
CHANGED
@@ -1,509 +1,509 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Feed display related functions
|
4 |
-
*
|
5 |
-
* @package WPRSSAggregator
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
add_filter( 'the_content', 'wprss_render_feed_view' );
|
10 |
-
/**
|
11 |
-
* Display template for a feed source. Simulates a shortcode call.
|
12 |
-
*
|
13 |
-
* @since 4.6.6
|
14 |
-
*/
|
15 |
-
function wprss_render_feed_view( $content ) {
|
16 |
-
if ( get_post_type() === 'wprss_feed' && ! is_feed() ) {
|
17 |
-
$content = wprss_shortcode( array(
|
18 |
-
'source' => get_the_ID()
|
19 |
-
) );
|
20 |
-
}
|
21 |
-
return $content;
|
22 |
-
}
|
23 |
-
|
24 |
-
|
25 |
-
add_filter( 'the_content', 'wprss_render_feed_item_view' );
|
26 |
-
/**
|
27 |
-
* Display template for a feed source. Simulates a shortcode call.
|
28 |
-
*
|
29 |
-
* @since 4.6.6
|
30 |
-
*/
|
31 |
-
function wprss_render_feed_item_view( $content ) {
|
32 |
-
if ( get_post_type() === 'wprss_feed_item' && ! is_feed() ) {
|
33 |
-
$content = wprss_shortcode_single( array(
|
34 |
-
'id' => get_the_ID()
|
35 |
-
) );
|
36 |
-
}
|
37 |
-
return $content;
|
38 |
-
}
|
39 |
-
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Renders a single feed item.
|
43 |
-
*
|
44 |
-
* @param int $ID The ID of the feed item to render
|
45 |
-
* @param string $default The default text to return if something fails.
|
46 |
-
* @return string The output
|
47 |
-
* @since 4.6.6
|
48 |
-
*/
|
49 |
-
function wprss_render_feed_item( $ID = NULL, $default = '', $args = array() ) {
|
50 |
-
$ID = ( $ID === NULL )? get_the_ID() : $ID;
|
51 |
-
if ( get_post_type( $ID ) !== 'wprss_feed_item' || is_feed() ) return $default;
|
52 |
-
|
53 |
-
// Prepare the options
|
54 |
-
$general_settings = get_option( 'wprss_settings_general' );
|
55 |
-
$display_settings = wprss_get_display_settings( $general_settings );
|
56 |
-
$excerpts_settings = get_option( 'wprss_settings_excerpts' );
|
57 |
-
$thumbnails_settings = get_option( 'wprss_settings_thumbnails' );
|
58 |
-
|
59 |
-
$extra_options = apply_filters( 'wprss_template_extra_options', array(), $args);
|
60 |
-
|
61 |
-
// Normalize the source_link option
|
62 |
-
$source_link = isset( $general_settings['source_link'] )? $general_settings['source_link'] : 0;
|
63 |
-
|
64 |
-
// Declare each item in $args as its own variable
|
65 |
-
extract( $args, EXTR_SKIP );
|
66 |
-
|
67 |
-
// Get the item meta
|
68 |
-
$permalink = get_post_meta( $ID, 'wprss_item_permalink', true );
|
69 |
-
$enclosure = get_post_meta( $ID, 'wprss_item_enclosure', true );
|
70 |
-
$feed_source_id = get_post_meta( $ID, 'wprss_feed_id', true );
|
71 |
-
$link_enclosure = get_post_meta( $feed_source_id, 'wprss_enclosure', true );
|
72 |
-
$source_name = get_the_title( $feed_source_id );
|
73 |
-
$source_url = get_post_meta( $feed_source_id, 'wprss_site_url', true );
|
74 |
-
$timestamp = get_the_time( 'U', $ID );
|
75 |
-
|
76 |
-
// Fallback for feeds created with older versions of the plugin
|
77 |
-
if ( $source_url === '' ) $source_url = get_post_meta( $feed_source_id, 'wprss_url', true );
|
78 |
-
// convert from Unix timestamp
|
79 |
-
$date = wprss_date_i18n( $timestamp );
|
80 |
-
|
81 |
-
// Prepare the title
|
82 |
-
$feed_item_title = get_the_title();
|
83 |
-
$feed_item_title_link = ( $link_enclosure === 'true' && $enclosure !== '' )? $enclosure : $permalink;
|
84 |
-
|
85 |
-
// Prepare the text that precedes the source
|
86 |
-
$text_preceding_source = wprss_get_general_setting('text_preceding_source');
|
87 |
-
$text_preceding_source = ltrim( __( $text_preceding_source, WPRSS_TEXT_DOMAIN ) . ' ' );
|
88 |
-
|
89 |
-
$text_preceding_date = wprss_get_general_setting('text_preceding_date');
|
90 |
-
$text_preceding_date = ltrim( __( $text_preceding_date, WPRSS_TEXT_DOMAIN ) . ' ' );
|
91 |
-
|
92 |
-
do_action( 'wprss_get_post_data' );
|
93 |
-
|
94 |
-
$meta = $extra_options;
|
95 |
-
$extra_meta = apply_filters( 'wprss_template_extra_meta', $meta, $args, $ID );
|
96 |
-
|
97 |
-
///////////////////////////////////////////////////////////////
|
98 |
-
// BEGIN TEMPLATE
|
99 |
-
|
100 |
-
// Prepare the output
|
101 |
-
$output = '';
|
102 |
-
// Begin output buffering
|
103 |
-
ob_start();
|
104 |
-
// Print the links before
|
105 |
-
echo $link_before;
|
106 |
-
|
107 |
-
// The Title
|
108 |
-
$item_title = wprss_link_display( $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link') );
|
109 |
-
$item_title = apply_filters('wprss_item_title', $item_title, $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link'));
|
110 |
-
echo $item_title;
|
111 |
-
|
112 |
-
do_action( 'wprss_after_feed_item_title', $extra_meta, $display_settings, $ID );
|
113 |
-
|
114 |
-
// FEED ITEM META
|
115 |
-
echo '<div class="wprss-feed-meta">';
|
116 |
-
|
117 |
-
// SOURCE
|
118 |
-
if ( wprss_get_general_setting('source_enable') == 1 ) {
|
119 |
-
echo '<span class="feed-source">';
|
120 |
-
$source_link_text = apply_filters('wprss_item_source_link', wprss_link_display( $source_url, $source_name, $source_link ) );
|
121 |
-
$source_link_text = $text_preceding_source . $source_link_text;
|
122 |
-
echo $source_link_text;
|
123 |
-
echo '</span>';
|
124 |
-
}
|
125 |
-
|
126 |
-
// DATE
|
127 |
-
if ( wprss_get_general_setting('date_enable') == 1 ) {
|
128 |
-
echo '<span class="feed-date">';
|
129 |
-
$date_text = apply_filters( 'wprss_item_date', $date );
|
130 |
-
$date_text = $text_preceding_date . $date_text;
|
131 |
-
echo $date_text;
|
132 |
-
echo '</span>';
|
133 |
-
}
|
134 |
-
|
135 |
-
// AUTHOR
|
136 |
-
$author = get_post_meta( $ID, 'wprss_item_author', TRUE );
|
137 |
-
if ( wprss_get_general_setting('authors_enable') == 1 && $author !== NULL && is_string( $author ) && $author !== '' ) {
|
138 |
-
echo '<span class="feed-author">';
|
139 |
-
$author_text = apply_filters( 'wprss_item_author', $author );
|
140 |
-
$author_prefix_text = apply_filters( 'wprss_author_prefix_text', 'By' );
|
141 |
-
_e( $author_prefix_text, WPRSS_TEXT_DOMAIN );
|
142 |
-
echo ' ' . $author_text;
|
143 |
-
echo '</span>';
|
144 |
-
}
|
145 |
-
|
146 |
-
echo '</div>';
|
147 |
-
|
148 |
-
// TIME AGO
|
149 |
-
if ( wprss_get_general_setting('date_enable') == 1 && wprss_get_general_setting('time_ago_format_enable') == 1 ) {
|
150 |
-
$time_ago = human_time_diff( $timestamp, time() );
|
151 |
-
echo '<div class="wprss-time-ago">';
|
152 |
-
$time_ago_text = apply_filters( 'wprss_item_time_ago', $time_ago );
|
153 |
-
printf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), $time_ago_text );
|
154 |
-
echo '</div>';
|
155 |
-
}
|
156 |
-
|
157 |
-
// END TEMPLATE - Retrieve buffered output
|
158 |
-
$output .= ob_get_clean();
|
159 |
-
$output = apply_filters( 'wprss_single_feed_output', $output, $permalink );
|
160 |
-
$output .= "$link_after";
|
161 |
-
|
162 |
-
// Print the output
|
163 |
-
return $output;
|
164 |
-
}
|
165 |
-
|
166 |
-
|
167 |
-
/**
|
168 |
-
* Retrieve settings and prepare them for use in the display function
|
169 |
-
*
|
170 |
-
* @since 3.0
|
171 |
-
*/
|
172 |
-
function wprss_get_display_settings( $settings = NULL ) {
|
173 |
-
if ( $settings === NULL ) {
|
174 |
-
$settings = get_option( 'wprss_settings_general' );
|
175 |
-
}
|
176 |
-
// Parse the arguments together with their default values
|
177 |
-
$args = wp_parse_args(
|
178 |
-
$settings,
|
179 |
-
array(
|
180 |
-
'open_dd' => 'New Window',
|
181 |
-
'follow_dd' => '',
|
182 |
-
)
|
183 |
-
);
|
184 |
-
|
185 |
-
// Prepare the 'open' setting - how to open links for feed items
|
186 |
-
$open = '';
|
187 |
-
switch ( $args['open_dd'] ) {
|
188 |
-
case 'Lightbox' :
|
189 |
-
$open = 'class="colorbox"';
|
190 |
-
break;
|
191 |
-
case 'New window' :
|
192 |
-
$open = 'target="_blank"';
|
193 |
-
break;
|
194 |
-
}
|
195 |
-
|
196 |
-
// Prepare the 'follow' setting - whether links marked as nofollow or not
|
197 |
-
$follow = ( $args['follow_dd'] == 'no_follow' )? 'rel="nofollow"' : '';
|
198 |
-
|
199 |
-
// Prepare the final settings array
|
200 |
-
$display_settings = array(
|
201 |
-
'open' => $open,
|
202 |
-
'follow' => $follow
|
203 |
-
);
|
204 |
-
|
205 |
-
do_action( 'wprss_get_settings' );
|
206 |
-
|
207 |
-
return $display_settings;
|
208 |
-
}
|
209 |
-
|
210 |
-
|
211 |
-
/**
|
212 |
-
* Merges the default arguments with the user set arguments
|
213 |
-
*
|
214 |
-
* @since 3.0
|
215 |
-
*/
|
216 |
-
function wprss_get_shortcode_default_args( $args ) {
|
217 |
-
// Default shortcode/function arguments for displaying feed items
|
218 |
-
$shortcode_args = apply_filters(
|
219 |
-
'wprss_shortcode_args',
|
220 |
-
array(
|
221 |
-
'links_before' => '<ul class="rss-aggregator">',
|
222 |
-
'links_after' => '</ul>',
|
223 |
-
'link_before' => '<li class="feed-item">',
|
224 |
-
'link_after' => '</li>'
|
225 |
-
)
|
226 |
-
);
|
227 |
-
|
228 |
-
// Parse incoming $args into an array and merge it with $shortcode_args
|
229 |
-
$args = wp_parse_args( $args, $shortcode_args );
|
230 |
-
|
231 |
-
return $args;
|
232 |
-
}
|
233 |
-
|
234 |
-
|
235 |
-
/**
|
236 |
-
* Prepares and builds the query for fetching the feed items
|
237 |
-
*
|
238 |
-
* @since 3.0
|
239 |
-
*/
|
240 |
-
function wprss_get_feed_items_query( $settings ) {
|
241 |
-
if( isset( $settings['feed_limit'] ) ) {
|
242 |
-
$posts_per_page = $settings['feed_limit'];
|
243 |
-
} else {
|
244 |
-
$posts_per_page = wprss_get_general_setting('feed_limit');
|
245 |
-
}
|
246 |
-
global $paged;
|
247 |
-
if ( get_query_var('paged') ) {
|
248 |
-
$paged = get_query_var('paged');
|
249 |
-
} elseif ( get_query_var('page') ) {
|
250 |
-
$paged = get_query_var('page');
|
251 |
-
} else {
|
252 |
-
$paged = 1;
|
253 |
-
}
|
254 |
-
|
255 |
-
$feed_items_args = array(
|
256 |
-
'post_type' => 'wprss_feed_item',
|
257 |
-
'posts_per_page' => $posts_per_page,
|
258 |
-
'orderby' => 'date',
|
259 |
-
'order' => 'DESC',
|
260 |
-
'paged' => $paged,
|
261 |
-
'suppress_filters' => true
|
262 |
-
);
|
263 |
-
|
264 |
-
if ( isset($settings['pagination']) ) {
|
265 |
-
$pagination = strtolower( $settings['pagination'] );
|
266 |
-
if ( in_array( $pagination, array('false','off','0') ) ) {
|
267 |
-
unset( $feed_items_args['paged'] );
|
268 |
-
}
|
269 |
-
}
|
270 |
-
|
271 |
-
if ( isset( $settings['no-paged'] ) && $settings['no-paged'] === TRUE ) {
|
272 |
-
unset( $feed_items_args['no-paged'] );
|
273 |
-
}
|
274 |
-
|
275 |
-
// If either the source or exclude arguments are set (but not both), prepare a meta query
|
276 |
-
if ( isset( $settings['source'] ) xor isset( $settings['exclude'] ) ) {
|
277 |
-
// Set the appropriate setting and operator
|
278 |
-
$setting = 'source';
|
279 |
-
$operator = 'IN';
|
280 |
-
if ( isset( $settings['exclude'] ) ) {
|
281 |
-
$setting = 'exclude';
|
282 |
-
$operator = 'NOT IN';
|
283 |
-
}
|
284 |
-
$feeds = array_filter( array_map( 'intval', explode( ',', $settings[$setting] ) ) );
|
285 |
-
foreach ( $feeds as $feed )
|
286 |
-
trim( $feed );
|
287 |
-
if ( !empty( $feeds ) ) {
|
288 |
-
$feed_items_args['meta_query'] = array(
|
289 |
-
array(
|
290 |
-
'key' => 'wprss_feed_id',
|
291 |
-
'value' => $feeds,
|
292 |
-
'type' => 'numeric',
|
293 |
-
'compare' => $operator,
|
294 |
-
),
|
295 |
-
);
|
296 |
-
}
|
297 |
-
}
|
298 |
-
|
299 |
-
// Arguments for the next query to fetch all feed items
|
300 |
-
$feed_items_args = apply_filters( 'wprss_display_feed_items_query', $feed_items_args, $settings );
|
301 |
-
|
302 |
-
// Query to get all feed items for display
|
303 |
-
$feed_items = new WP_Query( $feed_items_args );
|
304 |
-
|
305 |
-
if ( isset( $settings['get-args'] ) && $settings['get-args'] === TRUE ) {
|
306 |
-
return $feed_items_args;
|
307 |
-
} else return $feed_items;
|
308 |
-
}
|
309 |
-
|
310 |
-
|
311 |
-
add_action( 'wprss_display_template', 'wprss_default_display_template', 10, 3 );
|
312 |
-
/**
|
313 |
-
* Default template for feed items display
|
314 |
-
*
|
315 |
-
* @since 3.0
|
316 |
-
* @param $args array The shortcode arguments
|
317 |
-
* @param $feed_items WP_Query The feed items to display
|
318 |
-
*/
|
319 |
-
function wprss_default_display_template( $args, $feed_items ) {
|
320 |
-
global $wp_query;
|
321 |
-
global $paged;
|
322 |
-
|
323 |
-
// Swap the current WordPress Query with our own
|
324 |
-
$old_wp_query = $wp_query;
|
325 |
-
$wp_query = $feed_items;
|
326 |
-
|
327 |
-
// Prepare the output
|
328 |
-
$output = '';
|
329 |
-
|
330 |
-
// Check if our current query returned any feed items
|
331 |
-
if ( $feed_items->have_posts() ) {
|
332 |
-
// PRINT LINKS BEFORE LIST OF FEED ITEMS
|
333 |
-
$output .= $args['links_before'];
|
334 |
-
|
335 |
-
// FOR EACH ITEM
|
336 |
-
while ( $feed_items->have_posts() ) {
|
337 |
-
// Get the item
|
338 |
-
$feed_items->the_post();
|
339 |
-
// Add the output
|
340 |
-
$output .= wprss_render_feed_item( NULL, '', $args );
|
341 |
-
}
|
342 |
-
|
343 |
-
// OUTPUT LINKS AFTER LIST OF FEED ITEMS
|
344 |
-
$output .= $args['links_after'];
|
345 |
-
|
346 |
-
// Add pagination if needed
|
347 |
-
if ( !isset( $args['pagination'] ) || !in_array( $args['pagination'], array('off','false','0',0) ) ) {
|
348 |
-
$output = apply_filters( 'wprss_pagination', $output );
|
349 |
-
}
|
350 |
-
|
351 |
-
// Filter the final output, and print it
|
352 |
-
echo apply_filters( 'feed_output', $output );
|
353 |
-
} else {
|
354 |
-
// No items found message
|
355 |
-
echo apply_filters( 'no_feed_items_found', __( 'No feed items found.', WPRSS_TEXT_DOMAIN ) );
|
356 |
-
}
|
357 |
-
|
358 |
-
// Reset the WordPress query
|
359 |
-
$wp_query = $old_wp_query;
|
360 |
-
wp_reset_postdata();
|
361 |
-
}
|
362 |
-
|
363 |
-
|
364 |
-
/**
|
365 |
-
* Generates an HTML link, using the saved display settings.
|
366 |
-
*
|
367 |
-
* @param string $link The link URL
|
368 |
-
* @param string $text The link text to display
|
369 |
-
* @param string $bool Optional boolean. If FALSE, the text is returned unlinked. Default: TRUE.
|
370 |
-
* @return string The generated link
|
371 |
-
* @since 4.2.4
|
372 |
-
*/
|
373 |
-
function wprss_link_display( $link, $text, $bool = TRUE ) {
|
374 |
-
$display_settings = wprss_get_display_settings( get_option( 'wprss_settings_general' ) );
|
375 |
-
$a = $bool ? "<a {$display_settings['open']} {$display_settings['follow']} href='$link'>$text</a>" : $text;
|
376 |
-
return $a;
|
377 |
-
}
|
378 |
-
|
379 |
-
|
380 |
-
add_filter( 'wprss_pagination', 'wprss_pagination_links' );
|
381 |
-
/**
|
382 |
-
* Display pagination links
|
383 |
-
*
|
384 |
-
* @since 3.5
|
385 |
-
*/
|
386 |
-
function wprss_pagination_links( $output ) {
|
387 |
-
// Get the general setting
|
388 |
-
$pagination = wprss_get_general_setting( 'pagination' );;
|
389 |
-
|
390 |
-
// Check the pagination setting, if using page numbers
|
391 |
-
if ( $pagination === 'numbered' ) {
|
392 |
-
global $wp_query;
|
393 |
-
$big = 999999999; // need an unlikely integer
|
394 |
-
$output .= paginate_links( array(
|
395 |
-
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
|
396 |
-
'format' => '?paged=%#%',
|
397 |
-
'current' => max( 1, get_query_var('paged') ),
|
398 |
-
'total' => $wp_query->max_num_pages
|
399 |
-
) );
|
400 |
-
return $output;
|
401 |
-
}
|
402 |
-
// Otherwise, using default paginations
|
403 |
-
else {
|
404 |
-
$output .= '<div class="nav-links">';
|
405 |
-
$output .= ' <div class="nav-previous alignleft">' . get_next_posts_link( __( 'Older posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
|
406 |
-
$output .= ' <div class="nav-next alignright">' . get_previous_posts_link( __( 'Newer posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
|
407 |
-
$output .= '</div>';
|
408 |
-
return $output;
|
409 |
-
}
|
410 |
-
}
|
411 |
-
|
412 |
-
|
413 |
-
add_filter( 'the_title', 'wprss_shorten_title', 10, 2 );
|
414 |
-
/**
|
415 |
-
* Checks the title limit option and shortens the title when necassary.
|
416 |
-
*
|
417 |
-
* @since 1.0
|
418 |
-
*/
|
419 |
-
function wprss_shorten_title( $title, $id = null ) {
|
420 |
-
if ( $id === null ) return $title;
|
421 |
-
// Get the option. If does not exist, use 0, which is ignored.
|
422 |
-
$general_settings = get_option( 'wprss_settings_general' );
|
423 |
-
$title_limit = isset( $general_settings['title_limit'] )? intval( $general_settings['title_limit'] ) : 0;
|
424 |
-
// Check if the title is for a wprss_feed_item, and check if trimming is needed
|
425 |
-
if ( isset( $id ) && get_post_type( $id ) === 'wprss_feed_item' && $title_limit > 0 && strlen( $title ) > $title_limit ) {
|
426 |
-
// Return the trimmed version of the title
|
427 |
-
return substr( $title, 0, $title_limit ) . apply_filters( 'wprss_shortened_title_ending', '...' );
|
428 |
-
}
|
429 |
-
// Otherwise, return the same title
|
430 |
-
return $title;
|
431 |
-
}
|
432 |
-
|
433 |
-
|
434 |
-
/**
|
435 |
-
* Display feed items on the front end (via shortcode or function)
|
436 |
-
*
|
437 |
-
* @since 2.0
|
438 |
-
*/
|
439 |
-
function wprss_display_feed_items( $args = array() ) {
|
440 |
-
$settings = get_option( 'wprss_settings_general' );
|
441 |
-
$args = wprss_get_shortcode_default_args( $args );
|
442 |
-
|
443 |
-
$args = apply_filters( 'wprss_shortcode_args', $args );
|
444 |
-
|
445 |
-
$query_args = $settings;
|
446 |
-
if ( isset( $args['limit'] ) ) {
|
447 |
-
$query_args['feed_limit'] = filter_var( $args['limit'], FILTER_VALIDATE_INT, array(
|
448 |
-
'options' => array(
|
449 |
-
'min_range' => 1,
|
450 |
-
'default' => $query_args['feed_limit'],
|
451 |
-
),
|
452 |
-
) );
|
453 |
-
}
|
454 |
-
|
455 |
-
if ( isset( $args['pagination'] ) ) {
|
456 |
-
$query_args['pagination'] = $args['pagination'];
|
457 |
-
}
|
458 |
-
|
459 |
-
if ( isset( $args['source'] ) ) {
|
460 |
-
$query_args['source'] = $args['source'];
|
461 |
-
}
|
462 |
-
elseif ( isset( $args['exclude'] ) ) {
|
463 |
-
$query_args['exclude'] = $args['exclude'];
|
464 |
-
}
|
465 |
-
|
466 |
-
$query_args = apply_filters( 'wprss_process_shortcode_args', $query_args, $args );
|
467 |
-
|
468 |
-
$feed_items = wprss_get_feed_items_query( $query_args );
|
469 |
-
|
470 |
-
do_action( 'wprss_display_template', $args, $feed_items );
|
471 |
-
}
|
472 |
-
|
473 |
-
|
474 |
-
/**
|
475 |
-
* Redirects to wprss_display_feed_items
|
476 |
-
* It is used for backwards compatibility to versions < 2.0
|
477 |
-
*
|
478 |
-
* @since 2.1
|
479 |
-
*/
|
480 |
-
function wp_rss_aggregator( $args = array() ) {
|
481 |
-
wprss_display_feed_items( $args );
|
482 |
-
}
|
483 |
-
|
484 |
-
|
485 |
-
/**
|
486 |
-
* Limits a phrase/content to a defined number of words
|
487 |
-
*
|
488 |
-
* NOT BEING USED as we're using the native WP function, although the native one strips tags, so I'll
|
489 |
-
* probably revisit this one again soon.
|
490 |
-
*
|
491 |
-
* @since 3.0
|
492 |
-
* @param string $words
|
493 |
-
* @param integer $limit
|
494 |
-
* @param string $append
|
495 |
-
* @return string
|
496 |
-
*/
|
497 |
-
function wprss_limit_words( $words, $limit, $append = '' ) {
|
498 |
-
/* Add 1 to the specified limit becuase arrays start at 0 */
|
499 |
-
$limit = $limit + 1;
|
500 |
-
/* Store each individual word as an array element
|
501 |
-
up to the limit */
|
502 |
-
$words = explode( ' ', $words, $limit );
|
503 |
-
/* Shorten the array by 1 because that final element will be the sum of all the words after the limit */
|
504 |
-
array_pop( $words );
|
505 |
-
/* Implode the array for output, and append an ellipse */
|
506 |
-
$words = implode( ' ', $words ) . $append;
|
507 |
-
/* Return the result */
|
508 |
-
return rtrim( $words );
|
509 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Feed display related functions
|
4 |
+
*
|
5 |
+
* @package WPRSSAggregator
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
add_filter( 'the_content', 'wprss_render_feed_view' );
|
10 |
+
/**
|
11 |
+
* Display template for a feed source. Simulates a shortcode call.
|
12 |
+
*
|
13 |
+
* @since 4.6.6
|
14 |
+
*/
|
15 |
+
function wprss_render_feed_view( $content ) {
|
16 |
+
if ( get_post_type() === 'wprss_feed' && ! is_feed() ) {
|
17 |
+
$content = wprss_shortcode( array(
|
18 |
+
'source' => get_the_ID()
|
19 |
+
) );
|
20 |
+
}
|
21 |
+
return $content;
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
add_filter( 'the_content', 'wprss_render_feed_item_view' );
|
26 |
+
/**
|
27 |
+
* Display template for a feed source. Simulates a shortcode call.
|
28 |
+
*
|
29 |
+
* @since 4.6.6
|
30 |
+
*/
|
31 |
+
function wprss_render_feed_item_view( $content ) {
|
32 |
+
if ( get_post_type() === 'wprss_feed_item' && ! is_feed() ) {
|
33 |
+
$content = wprss_shortcode_single( array(
|
34 |
+
'id' => get_the_ID()
|
35 |
+
) );
|
36 |
+
}
|
37 |
+
return $content;
|
38 |
+
}
|
39 |
+
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Renders a single feed item.
|
43 |
+
*
|
44 |
+
* @param int $ID The ID of the feed item to render
|
45 |
+
* @param string $default The default text to return if something fails.
|
46 |
+
* @return string The output
|
47 |
+
* @since 4.6.6
|
48 |
+
*/
|
49 |
+
function wprss_render_feed_item( $ID = NULL, $default = '', $args = array() ) {
|
50 |
+
$ID = ( $ID === NULL )? get_the_ID() : $ID;
|
51 |
+
if ( get_post_type( $ID ) !== 'wprss_feed_item' || is_feed() ) return $default;
|
52 |
+
|
53 |
+
// Prepare the options
|
54 |
+
$general_settings = get_option( 'wprss_settings_general' );
|
55 |
+
$display_settings = wprss_get_display_settings( $general_settings );
|
56 |
+
$excerpts_settings = get_option( 'wprss_settings_excerpts' );
|
57 |
+
$thumbnails_settings = get_option( 'wprss_settings_thumbnails' );
|
58 |
+
|
59 |
+
$extra_options = apply_filters( 'wprss_template_extra_options', array(), $args);
|
60 |
+
|
61 |
+
// Normalize the source_link option
|
62 |
+
$source_link = isset( $general_settings['source_link'] )? $general_settings['source_link'] : 0;
|
63 |
+
|
64 |
+
// Declare each item in $args as its own variable
|
65 |
+
extract( $args, EXTR_SKIP );
|
66 |
+
|
67 |
+
// Get the item meta
|
68 |
+
$permalink = get_post_meta( $ID, 'wprss_item_permalink', true );
|
69 |
+
$enclosure = get_post_meta( $ID, 'wprss_item_enclosure', true );
|
70 |
+
$feed_source_id = get_post_meta( $ID, 'wprss_feed_id', true );
|
71 |
+
$link_enclosure = get_post_meta( $feed_source_id, 'wprss_enclosure', true );
|
72 |
+
$source_name = get_the_title( $feed_source_id );
|
73 |
+
$source_url = get_post_meta( $feed_source_id, 'wprss_site_url', true );
|
74 |
+
$timestamp = get_the_time( 'U', $ID );
|
75 |
+
|
76 |
+
// Fallback for feeds created with older versions of the plugin
|
77 |
+
if ( $source_url === '' ) $source_url = get_post_meta( $feed_source_id, 'wprss_url', true );
|
78 |
+
// convert from Unix timestamp
|
79 |
+
$date = wprss_date_i18n( $timestamp );
|
80 |
+
|
81 |
+
// Prepare the title
|
82 |
+
$feed_item_title = get_the_title();
|
83 |
+
$feed_item_title_link = ( $link_enclosure === 'true' && $enclosure !== '' )? $enclosure : $permalink;
|
84 |
+
|
85 |
+
// Prepare the text that precedes the source
|
86 |
+
$text_preceding_source = wprss_get_general_setting('text_preceding_source');
|
87 |
+
$text_preceding_source = ltrim( __( $text_preceding_source, WPRSS_TEXT_DOMAIN ) . ' ' );
|
88 |
+
|
89 |
+
$text_preceding_date = wprss_get_general_setting('text_preceding_date');
|
90 |
+
$text_preceding_date = ltrim( __( $text_preceding_date, WPRSS_TEXT_DOMAIN ) . ' ' );
|
91 |
+
|
92 |
+
do_action( 'wprss_get_post_data' );
|
93 |
+
|
94 |
+
$meta = $extra_options;
|
95 |
+
$extra_meta = apply_filters( 'wprss_template_extra_meta', $meta, $args, $ID );
|
96 |
+
|
97 |
+
///////////////////////////////////////////////////////////////
|
98 |
+
// BEGIN TEMPLATE
|
99 |
+
|
100 |
+
// Prepare the output
|
101 |
+
$output = '';
|
102 |
+
// Begin output buffering
|
103 |
+
ob_start();
|
104 |
+
// Print the links before
|
105 |
+
echo $link_before;
|
106 |
+
|
107 |
+
// The Title
|
108 |
+
$item_title = wprss_link_display( $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link') );
|
109 |
+
$item_title = apply_filters('wprss_item_title', $item_title, $feed_item_title_link, $feed_item_title, wprss_get_general_setting('title_link'));
|
110 |
+
echo $item_title;
|
111 |
+
|
112 |
+
do_action( 'wprss_after_feed_item_title', $extra_meta, $display_settings, $ID );
|
113 |
+
|
114 |
+
// FEED ITEM META
|
115 |
+
echo '<div class="wprss-feed-meta">';
|
116 |
+
|
117 |
+
// SOURCE
|
118 |
+
if ( wprss_get_general_setting('source_enable') == 1 ) {
|
119 |
+
echo '<span class="feed-source">';
|
120 |
+
$source_link_text = apply_filters('wprss_item_source_link', wprss_link_display( $source_url, $source_name, $source_link ) );
|
121 |
+
$source_link_text = $text_preceding_source . $source_link_text;
|
122 |
+
echo $source_link_text;
|
123 |
+
echo '</span>';
|
124 |
+
}
|
125 |
+
|
126 |
+
// DATE
|
127 |
+
if ( wprss_get_general_setting('date_enable') == 1 ) {
|
128 |
+
echo '<span class="feed-date">';
|
129 |
+
$date_text = apply_filters( 'wprss_item_date', $date );
|
130 |
+
$date_text = $text_preceding_date . $date_text;
|
131 |
+
echo $date_text;
|
132 |
+
echo '</span>';
|
133 |
+
}
|
134 |
+
|
135 |
+
// AUTHOR
|
136 |
+
$author = get_post_meta( $ID, 'wprss_item_author', TRUE );
|
137 |
+
if ( wprss_get_general_setting('authors_enable') == 1 && $author !== NULL && is_string( $author ) && $author !== '' ) {
|
138 |
+
echo '<span class="feed-author">';
|
139 |
+
$author_text = apply_filters( 'wprss_item_author', $author );
|
140 |
+
$author_prefix_text = apply_filters( 'wprss_author_prefix_text', 'By' );
|
141 |
+
_e( $author_prefix_text, WPRSS_TEXT_DOMAIN );
|
142 |
+
echo ' ' . $author_text;
|
143 |
+
echo '</span>';
|
144 |
+
}
|
145 |
+
|
146 |
+
echo '</div>';
|
147 |
+
|
148 |
+
// TIME AGO
|
149 |
+
if ( wprss_get_general_setting('date_enable') == 1 && wprss_get_general_setting('time_ago_format_enable') == 1 ) {
|
150 |
+
$time_ago = human_time_diff( $timestamp, time() );
|
151 |
+
echo '<div class="wprss-time-ago">';
|
152 |
+
$time_ago_text = apply_filters( 'wprss_item_time_ago', $time_ago );
|
153 |
+
printf( __( '%1$s ago', WPRSS_TEXT_DOMAIN ), $time_ago_text );
|
154 |
+
echo '</div>';
|
155 |
+
}
|
156 |
+
|
157 |
+
// END TEMPLATE - Retrieve buffered output
|
158 |
+
$output .= ob_get_clean();
|
159 |
+
$output = apply_filters( 'wprss_single_feed_output', $output, $permalink );
|
160 |
+
$output .= "$link_after";
|
161 |
+
|
162 |
+
// Print the output
|
163 |
+
return $output;
|
164 |
+
}
|
165 |
+
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Retrieve settings and prepare them for use in the display function
|
169 |
+
*
|
170 |
+
* @since 3.0
|
171 |
+
*/
|
172 |
+
function wprss_get_display_settings( $settings = NULL ) {
|
173 |
+
if ( $settings === NULL ) {
|
174 |
+
$settings = get_option( 'wprss_settings_general' );
|
175 |
+
}
|
176 |
+
// Parse the arguments together with their default values
|
177 |
+
$args = wp_parse_args(
|
178 |
+
$settings,
|
179 |
+
array(
|
180 |
+
'open_dd' => 'New Window',
|
181 |
+
'follow_dd' => '',
|
182 |
+
)
|
183 |
+
);
|
184 |
+
|
185 |
+
// Prepare the 'open' setting - how to open links for feed items
|
186 |
+
$open = '';
|
187 |
+
switch ( $args['open_dd'] ) {
|
188 |
+
case 'Lightbox' :
|
189 |
+
$open = 'class="colorbox"';
|
190 |
+
break;
|
191 |
+
case 'New window' :
|
192 |
+
$open = 'target="_blank"';
|
193 |
+
break;
|
194 |
+
}
|
195 |
+
|
196 |
+
// Prepare the 'follow' setting - whether links marked as nofollow or not
|
197 |
+
$follow = ( $args['follow_dd'] == 'no_follow' )? 'rel="nofollow"' : '';
|
198 |
+
|
199 |
+
// Prepare the final settings array
|
200 |
+
$display_settings = array(
|
201 |
+
'open' => $open,
|
202 |
+
'follow' => $follow
|
203 |
+
);
|
204 |
+
|
205 |
+
do_action( 'wprss_get_settings' );
|
206 |
+
|
207 |
+
return $display_settings;
|
208 |
+
}
|
209 |
+
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Merges the default arguments with the user set arguments
|
213 |
+
*
|
214 |
+
* @since 3.0
|
215 |
+
*/
|
216 |
+
function wprss_get_shortcode_default_args( $args ) {
|
217 |
+
// Default shortcode/function arguments for displaying feed items
|
218 |
+
$shortcode_args = apply_filters(
|
219 |
+
'wprss_shortcode_args',
|
220 |
+
array(
|
221 |
+
'links_before' => '<ul class="rss-aggregator">',
|
222 |
+
'links_after' => '</ul>',
|
223 |
+
'link_before' => '<li class="feed-item">',
|
224 |
+
'link_after' => '</li>'
|
225 |
+
)
|
226 |
+
);
|
227 |
+
|
228 |
+
// Parse incoming $args into an array and merge it with $shortcode_args
|
229 |
+
$args = wp_parse_args( $args, $shortcode_args );
|
230 |
+
|
231 |
+
return $args;
|
232 |
+
}
|
233 |
+
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Prepares and builds the query for fetching the feed items
|
237 |
+
*
|
238 |
+
* @since 3.0
|
239 |
+
*/
|
240 |
+
function wprss_get_feed_items_query( $settings ) {
|
241 |
+
if( isset( $settings['feed_limit'] ) ) {
|
242 |
+
$posts_per_page = $settings['feed_limit'];
|
243 |
+
} else {
|
244 |
+
$posts_per_page = wprss_get_general_setting('feed_limit');
|
245 |
+
}
|
246 |
+
global $paged;
|
247 |
+
if ( get_query_var('paged') ) {
|
248 |
+
$paged = get_query_var('paged');
|
249 |
+
} elseif ( get_query_var('page') ) {
|
250 |
+
$paged = get_query_var('page');
|
251 |
+
} else {
|
252 |
+
$paged = 1;
|
253 |
+
}
|
254 |
+
|
255 |
+
$feed_items_args = array(
|
256 |
+
'post_type' => 'wprss_feed_item',
|
257 |
+
'posts_per_page' => $posts_per_page,
|
258 |
+
'orderby' => 'date',
|
259 |
+
'order' => 'DESC',
|
260 |
+
'paged' => $paged,
|
261 |
+
'suppress_filters' => true
|
262 |
+
);
|
263 |
+
|
264 |
+
if ( isset($settings['pagination']) ) {
|
265 |
+
$pagination = strtolower( $settings['pagination'] );
|
266 |
+
if ( in_array( $pagination, array('false','off','0') ) ) {
|
267 |
+
unset( $feed_items_args['paged'] );
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
if ( isset( $settings['no-paged'] ) && $settings['no-paged'] === TRUE ) {
|
272 |
+
unset( $feed_items_args['no-paged'] );
|
273 |
+
}
|
274 |
+
|
275 |
+
// If either the source or exclude arguments are set (but not both), prepare a meta query
|
276 |
+
if ( isset( $settings['source'] ) xor isset( $settings['exclude'] ) ) {
|
277 |
+
// Set the appropriate setting and operator
|
278 |
+
$setting = 'source';
|
279 |
+
$operator = 'IN';
|
280 |
+
if ( isset( $settings['exclude'] ) ) {
|
281 |
+
$setting = 'exclude';
|
282 |
+
$operator = 'NOT IN';
|
283 |
+
}
|
284 |
+
$feeds = array_filter( array_map( 'intval', explode( ',', $settings[$setting] ) ) );
|
285 |
+
foreach ( $feeds as $feed )
|
286 |
+
trim( $feed );
|
287 |
+
if ( !empty( $feeds ) ) {
|
288 |
+
$feed_items_args['meta_query'] = array(
|
289 |
+
array(
|
290 |
+
'key' => 'wprss_feed_id',
|
291 |
+
'value' => $feeds,
|
292 |
+
'type' => 'numeric',
|
293 |
+
'compare' => $operator,
|
294 |
+
),
|
295 |
+
);
|
296 |
+
}
|
297 |
+
}
|
298 |
+
|
299 |
+
// Arguments for the next query to fetch all feed items
|
300 |
+
$feed_items_args = apply_filters( 'wprss_display_feed_items_query', $feed_items_args, $settings );
|
301 |
+
|
302 |
+
// Query to get all feed items for display
|
303 |
+
$feed_items = new WP_Query( $feed_items_args );
|
304 |
+
|
305 |
+
if ( isset( $settings['get-args'] ) && $settings['get-args'] === TRUE ) {
|
306 |
+
return $feed_items_args;
|
307 |
+
} else return $feed_items;
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
add_action( 'wprss_display_template', 'wprss_default_display_template', 10, 3 );
|
312 |
+
/**
|
313 |
+
* Default template for feed items display
|
314 |
+
*
|
315 |
+
* @since 3.0
|
316 |
+
* @param $args array The shortcode arguments
|
317 |
+
* @param $feed_items WP_Query The feed items to display
|
318 |
+
*/
|
319 |
+
function wprss_default_display_template( $args, $feed_items ) {
|
320 |
+
global $wp_query;
|
321 |
+
global $paged;
|
322 |
+
|
323 |
+
// Swap the current WordPress Query with our own
|
324 |
+
$old_wp_query = $wp_query;
|
325 |
+
$wp_query = $feed_items;
|
326 |
+
|
327 |
+
// Prepare the output
|
328 |
+
$output = '';
|
329 |
+
|
330 |
+
// Check if our current query returned any feed items
|
331 |
+
if ( $feed_items->have_posts() ) {
|
332 |
+
// PRINT LINKS BEFORE LIST OF FEED ITEMS
|
333 |
+
$output .= $args['links_before'];
|
334 |
+
|
335 |
+
// FOR EACH ITEM
|
336 |
+
while ( $feed_items->have_posts() ) {
|
337 |
+
// Get the item
|
338 |
+
$feed_items->the_post();
|
339 |
+
// Add the output
|
340 |
+
$output .= wprss_render_feed_item( NULL, '', $args );
|
341 |
+
}
|
342 |
+
|
343 |
+
// OUTPUT LINKS AFTER LIST OF FEED ITEMS
|
344 |
+
$output .= $args['links_after'];
|
345 |
+
|
346 |
+
// Add pagination if needed
|
347 |
+
if ( !isset( $args['pagination'] ) || !in_array( $args['pagination'], array('off','false','0',0) ) ) {
|
348 |
+
$output = apply_filters( 'wprss_pagination', $output );
|
349 |
+
}
|
350 |
+
|
351 |
+
// Filter the final output, and print it
|
352 |
+
echo apply_filters( 'feed_output', $output );
|
353 |
+
} else {
|
354 |
+
// No items found message
|
355 |
+
echo apply_filters( 'no_feed_items_found', __( 'No feed items found.', WPRSS_TEXT_DOMAIN ) );
|
356 |
+
}
|
357 |
+
|
358 |
+
// Reset the WordPress query
|
359 |
+
$wp_query = $old_wp_query;
|
360 |
+
wp_reset_postdata();
|
361 |
+
}
|
362 |
+
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Generates an HTML link, using the saved display settings.
|
366 |
+
*
|
367 |
+
* @param string $link The link URL
|
368 |
+
* @param string $text The link text to display
|
369 |
+
* @param string $bool Optional boolean. If FALSE, the text is returned unlinked. Default: TRUE.
|
370 |
+
* @return string The generated link
|
371 |
+
* @since 4.2.4
|
372 |
+
*/
|
373 |
+
function wprss_link_display( $link, $text, $bool = TRUE ) {
|
374 |
+
$display_settings = wprss_get_display_settings( get_option( 'wprss_settings_general' ) );
|
375 |
+
$a = $bool ? "<a {$display_settings['open']} {$display_settings['follow']} href='$link'>$text</a>" : $text;
|
376 |
+
return $a;
|
377 |
+
}
|
378 |
+
|
379 |
+
|
380 |
+
add_filter( 'wprss_pagination', 'wprss_pagination_links' );
|
381 |
+
/**
|
382 |
+
* Display pagination links
|
383 |
+
*
|
384 |
+
* @since 3.5
|
385 |
+
*/
|
386 |
+
function wprss_pagination_links( $output ) {
|
387 |
+
// Get the general setting
|
388 |
+
$pagination = wprss_get_general_setting( 'pagination' );;
|
389 |
+
|
390 |
+
// Check the pagination setting, if using page numbers
|
391 |
+
if ( $pagination === 'numbered' ) {
|
392 |
+
global $wp_query;
|
393 |
+
$big = 999999999; // need an unlikely integer
|
394 |
+
$output .= paginate_links( array(
|
395 |
+
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
|
396 |
+
'format' => '?paged=%#%',
|
397 |
+
'current' => max( 1, get_query_var('paged') ),
|
398 |
+
'total' => $wp_query->max_num_pages
|
399 |
+
) );
|
400 |
+
return $output;
|
401 |
+
}
|
402 |
+
// Otherwise, using default paginations
|
403 |
+
else {
|
404 |
+
$output .= '<div class="nav-links">';
|
405 |
+
$output .= ' <div class="nav-previous alignleft">' . get_next_posts_link( __( 'Older posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
|
406 |
+
$output .= ' <div class="nav-next alignright">' . get_previous_posts_link( __( 'Newer posts', WPRSS_TEXT_DOMAIN ) ) . '</div>';
|
407 |
+
$output .= '</div>';
|
408 |
+
return $output;
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
+
|
413 |
+
add_filter( 'the_title', 'wprss_shorten_title', 10, 2 );
|
414 |
+
/**
|
415 |
+
* Checks the title limit option and shortens the title when necassary.
|
416 |
+
*
|
417 |
+
* @since 1.0
|
418 |
+
*/
|
419 |
+
function wprss_shorten_title( $title, $id = null ) {
|
420 |
+
if ( $id === null ) return $title;
|
421 |
+
// Get the option. If does not exist, use 0, which is ignored.
|
422 |
+
$general_settings = get_option( 'wprss_settings_general' );
|
423 |
+
$title_limit = isset( $general_settings['title_limit'] )? intval( $general_settings['title_limit'] ) : 0;
|
424 |
+
// Check if the title is for a wprss_feed_item, and check if trimming is needed
|
425 |
+
if ( isset( $id ) && get_post_type( $id ) === 'wprss_feed_item' && $title_limit > 0 && strlen( $title ) > $title_limit ) {
|
426 |
+
// Return the trimmed version of the title
|
427 |
+
return substr( $title, 0, $title_limit ) . apply_filters( 'wprss_shortened_title_ending', '...' );
|
428 |
+
}
|
429 |
+
// Otherwise, return the same title
|
430 |
+
return $title;
|
431 |
+
}
|
432 |
+
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Display feed items on the front end (via shortcode or function)
|
436 |
+
*
|
437 |
+
* @since 2.0
|
438 |
+
*/
|
439 |
+
function wprss_display_feed_items( $args = array() ) {
|
440 |
+
$settings = get_option( 'wprss_settings_general' );
|
441 |
+
$args = wprss_get_shortcode_default_args( $args );
|
442 |
+
|
443 |
+
$args = apply_filters( 'wprss_shortcode_args', $args );
|
444 |
+
|
445 |
+
$query_args = $settings;
|
446 |
+
if ( isset( $args['limit'] ) ) {
|
447 |
+
$query_args['feed_limit'] = filter_var( $args['limit'], FILTER_VALIDATE_INT, array(
|
448 |
+
'options' => array(
|
449 |
+
'min_range' => 1,
|
450 |
+
'default' => $query_args['feed_limit'],
|
451 |
+
),
|
452 |
+
) );
|
453 |
+
}
|
454 |
+
|
455 |
+
if ( isset( $args['pagination'] ) ) {
|
456 |
+
$query_args['pagination'] = $args['pagination'];
|
457 |
+
}
|
458 |
+
|
459 |
+
if ( isset( $args['source'] ) ) {
|
460 |
+
$query_args['source'] = $args['source'];
|
461 |
+
}
|
462 |
+
elseif ( isset( $args['exclude'] ) ) {
|
463 |
+
$query_args['exclude'] = $args['exclude'];
|
464 |
+
}
|
465 |
+
|
466 |
+
$query_args = apply_filters( 'wprss_process_shortcode_args', $query_args, $args );
|
467 |
+
|
468 |
+
$feed_items = wprss_get_feed_items_query( $query_args );
|
469 |
+
|
470 |
+
do_action( 'wprss_display_template', $args, $feed_items );
|
471 |
+
}
|
472 |
+
|
473 |
+
|
474 |
+
/**
|
475 |
+
* Redirects to wprss_display_feed_items
|
476 |
+
* It is used for backwards compatibility to versions < 2.0
|
477 |
+
*
|
478 |
+
* @since 2.1
|
479 |
+
*/
|
480 |
+
function wp_rss_aggregator( $args = array() ) {
|
481 |
+
wprss_display_feed_items( $args );
|
482 |
+
}
|
483 |
+
|
484 |
+
|
485 |
+
/**
|
486 |
+
* Limits a phrase/content to a defined number of words
|
487 |
+
*
|
488 |
+
* NOT BEING USED as we're using the native WP function, although the native one strips tags, so I'll
|
489 |
+
* probably revisit this one again soon.
|
490 |
+
*
|
491 |
+
* @since 3.0
|
492 |
+
* @param string $words
|
493 |
+
* @param integer $limit
|
494 |
+
* @param string $append
|
495 |
+
* @return string
|
496 |
+
*/
|
497 |
+
function wprss_limit_words( $words, $limit, $append = '' ) {
|
498 |
+
/* Add 1 to the specified limit becuase arrays start at 0 */
|
499 |
+
$limit = $limit + 1;
|
500 |
+
/* Store each individual word as an array element
|
501 |
+
up to the limit */
|
502 |
+
$words = explode( ' ', $words, $limit );
|
503 |
+
/* Shorten the array by 1 because that final element will be the sum of all the words after the limit */
|
504 |
+
array_pop( $words );
|
505 |
+
/* Implode the array for output, and append an ellipse */
|
506 |
+
$words = implode( ' ', $words ) . $append;
|
507 |
+
/* Return the result */
|
508 |
+
return rtrim( $words );
|
509 |
+
}
|
includes/feed-importing.php
CHANGED
@@ -1,661 +1,661 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Functions relating to feed importing
|
4 |
-
*
|
5 |
-
* @package WPRSSAggregator
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
// Warning: Order may be important
|
10 |
-
add_filter('wprss_normalize_permalink', 'wprss_google_news_url_fix', 8);
|
11 |
-
add_filter('wprss_normalize_permalink', 'wprss_bing_news_url_fix', 9);
|
12 |
-
add_filter('wprss_normalize_permalink', 'wprss_convert_video_permalink', 100);
|
13 |
-
|
14 |
-
|
15 |
-
add_action( 'wprss_fetch_single_feed_hook', 'wprss_fetch_insert_single_feed_items' );
|
16 |
-
/**
|
17 |
-
* The main feed fetching function.
|
18 |
-
* Fetches the feed items from the source provided and inserts them into the DB.
|
19 |
-
*
|
20 |
-
* Called on hook 'wprss_fetch_single_feed_hook'.
|
21 |
-
*
|
22 |
-
* @since 3.2
|
23 |
-
*/
|
24 |
-
function wprss_fetch_insert_single_feed_items( $feed_ID ) {
|
25 |
-
wprss_log_obj( 'Starting import of feed', $feed_ID, null, WPRSS_LOG_LEVEL_INFO );
|
26 |
-
|
27 |
-
global $wprss_importing_feed;
|
28 |
-
$wprss_importing_feed = $feed_ID;
|
29 |
-
register_shutdown_function( 'wprss_detect_exec_timeout' );
|
30 |
-
|
31 |
-
// Check if the feed source is active.
|
32 |
-
if ( wprss_is_feed_source_active( $feed_ID ) === FALSE && wprss_feed_source_force_next_fetch( $feed_ID ) === FALSE ) {
|
33 |
-
// If it is not active ( paused ), return without fetching the feed items.
|
34 |
-
wprss_log( 'Feed is not active and not forced. Import cancelled.', null, WPRSS_LOG_LEVEL_INFO );
|
35 |
-
return;
|
36 |
-
}
|
37 |
-
// If the feed source is forced for next fetch, remove the force next fetch data
|
38 |
-
if ( wprss_feed_source_force_next_fetch( $feed_ID ) ) {
|
39 |
-
delete_post_meta( $feed_ID, 'wprss_force_next_fetch' );
|
40 |
-
wprss_log( 'Force feed flag removed', null, WPRSS_LOG_LEVEL_SYSTEM );
|
41 |
-
}
|
42 |
-
|
43 |
-
$start_of_update = wprss_flag_feed_as_updating( $feed_ID );
|
44 |
-
wprss_log_obj( 'Start of import time updated', date( 'Y-m-d H:i:s', $start_of_update), null, WPRSS_LOG_LEVEL_SYSTEM );
|
45 |
-
|
46 |
-
// Get the feed source URL from post meta, and filter it
|
47 |
-
$feed_url = get_post_meta( $feed_ID, 'wprss_url', true );
|
48 |
-
wprss_log_obj( 'Original feed source URL', $feed_url, null, WPRSS_LOG_LEVEL_SYSTEM );
|
49 |
-
$feed_url = apply_filters( 'wprss_feed_source_url', $feed_url, $feed_ID );
|
50 |
-
wprss_log_obj( 'Actual feed source URL', $feed_url, null, WPRSS_LOG_LEVEL_INFO );
|
51 |
-
|
52 |
-
// Get the feed limit from post meta
|
53 |
-
$feed_limit = get_post_meta( $feed_ID, 'wprss_limit', true );
|
54 |
-
wprss_log_obj( 'Feed limit value is', $feed_limit, null, WPRSS_LOG_LEVEL_SYSTEM );
|
55 |
-
|
56 |
-
// If the feed has no individual limit
|
57 |
-
if ( $feed_limit === '' || intval( $feed_limit ) <= 0 ) {
|
58 |
-
wprss_log_obj( 'Using global limit', $feed_limit, null, WPRSS_LOG_LEVEL_NOTICE );
|
59 |
-
// Get the global limit
|
60 |
-
$global_limit = wprss_get_general_setting('limit_feed_items_imported');
|
61 |
-
// If no global limit is set, mark as NULL
|
62 |
-
if ( $global_limit === '' || intval($global_limit) <= 0 ) {
|
63 |
-
$feed_limit = NULL;
|
64 |
-
}
|
65 |
-
else $feed_limit = $global_limit;
|
66 |
-
}
|
67 |
-
wprss_log_obj( 'Feed import limit', $feed_limit, null, WPRSS_LOG_LEVEL_INFO );
|
68 |
-
|
69 |
-
// Filter the URL for validaty
|
70 |
-
if ( wprss_validate_url( $feed_url ) ) {
|
71 |
-
wprss_log_obj( 'Feed URL is valid', $feed_url, null, WPRSS_LOG_LEVEL_INFO );
|
72 |
-
// Get the feed items from the source
|
73 |
-
$items = wprss_get_feed_items( $feed_url, $feed_ID );
|
74 |
-
// If got NULL, convert to an empty array
|
75 |
-
if ( $items === NULL ) {
|
76 |
-
$items = array();
|
77 |
-
wprss_log( 'Items were NULL. Using empty array', null, WPRSS_LOG_LEVEL_WARNING );
|
78 |
-
}
|
79 |
-
|
80 |
-
// If using a limit ...
|
81 |
-
if ( $feed_limit === NULL ) {
|
82 |
-
$items_to_insert = $items;
|
83 |
-
} else {
|
84 |
-
$items_to_insert = array_slice( $items, 0, $feed_limit );
|
85 |
-
wprss_log_obj( 'Sliced a segment of items', count($items_to_insert), null, WPRSS_LOG_LEVEL_SYSTEM );
|
86 |
-
}
|
87 |
-
|
88 |
-
// Gather the permalinks of existing feed item's related to this feed source
|
89 |
-
$existing_permalinks = get_existing_permalinks( $feed_ID );
|
90 |
-
wprss_log_obj( 'Retrieved existing permalinks', count( $existing_permalinks ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
91 |
-
|
92 |
-
// Generate a list of items fetched, that are not already in the DB
|
93 |
-
$new_items = array();
|
94 |
-
foreach ( $items_to_insert as $item ) {
|
95 |
-
$permalink = wprss_normalize_permalink( $item->get_permalink() );
|
96 |
-
wprss_log_obj( 'Normalizing permalink', sprintf('%1$s -> %2$s', $item->get_permalink(), $permalink), null, WPRSS_LOG_LEVEL_SYSTEM );
|
97 |
-
// Check if not blacklisted and not already imported
|
98 |
-
$is_blacklisted = wprss_is_blacklisted( $permalink );
|
99 |
-
$already_exists = in_array( $permalink, $existing_permalinks );
|
100 |
-
if ( $is_blacklisted === FALSE && $already_exists === FALSE ) {
|
101 |
-
$new_items[] = $item;
|
102 |
-
wprss_log_obj( 'Permalink OK', $permalink, null, WPRSS_LOG_LEVEL_SYSTEM );
|
103 |
-
}
|
104 |
-
else {
|
105 |
-
if ( $is_blacklisted ) {
|
106 |
-
wprss_log( 'Permalink blacklisted', null, WPRSS_LOG_LEVEL_SYSTEM );
|
107 |
-
}
|
108 |
-
if ( $already_exists ) {
|
109 |
-
wprss_log( 'Permalink already exists', null, WPRSS_LOG_LEVEL_SYSTEM );
|
110 |
-
}
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
$original_count = count( $items_to_insert );
|
115 |
-
$new_count = count( $new_items );
|
116 |
-
if ( $new_count !== $original_count ) {
|
117 |
-
wprss_log_obj( 'Items filtered out', $original_count - $new_count, null, WPRSS_LOG_LEVEL_SYSTEM );
|
118 |
-
} else {
|
119 |
-
wprss_log( 'Items to import remained untouched. Not items already exist or are blacklisted.', null, WPRSS_LOG_LEVEL_SYSTEM );
|
120 |
-
}
|
121 |
-
|
122 |
-
$items_to_insert = $new_items;
|
123 |
-
|
124 |
-
// If using a limit - delete any excess items to make room for the new items
|
125 |
-
if ( $feed_limit !== NULL ) {
|
126 |
-
wprss_log_obj( 'Some items may be deleted due to limit', $feed_limit, null, WPRSS_LOG_LEVEL_SYSTEM );
|
127 |
-
|
128 |
-
// Get the number of feed items in DB, and their count
|
129 |
-
$db_feed_items = wprss_get_feed_items_for_source( $feed_ID );
|
130 |
-
$num_db_feed_items = $db_feed_items->post_count;
|
131 |
-
|
132 |
-
// Get the number of feed items we can store until we reach the limit
|
133 |
-
$num_can_insert = $feed_limit - $num_db_feed_items;
|
134 |
-
// Calculate how many feed items we must delete before importing, to keep to the limit
|
135 |
-
$num_new_items = count( $new_items );
|
136 |
-
$num_feed_items_to_delete = $num_can_insert > $num_new_items
|
137 |
-
? 0
|
138 |
-
: $num_new_items - $num_can_insert;
|
139 |
-
|
140 |
-
// Get an array with the DB feed items in reverse order (oldest first)
|
141 |
-
$db_feed_items_reversed = array_reverse( $db_feed_items->posts );
|
142 |
-
// Cut the array to get only the first few that are to be deleted ( equal to $num_feed_items_to_delete )
|
143 |
-
$feed_items_to_delete = array_slice( $db_feed_items_reversed, 0, $num_feed_items_to_delete );
|
144 |
-
wprss_log( sprintf( 'There already are %1$d items in the database. %2$d items can be inserted. %3$d items will be deleted', $num_db_feed_items, $num_can_insert, $num_feed_items_to_delete ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
145 |
-
|
146 |
-
// Iterate the feed items and delete them
|
147 |
-
foreach ( $feed_items_to_delete as $key => $post ) {
|
148 |
-
wp_delete_post( $post->ID, TRUE );
|
149 |
-
}
|
150 |
-
|
151 |
-
if ( $deleted_items_count = count( $feed_items_to_delete ) )
|
152 |
-
wprss_log_obj( 'Items deleted due to limit', $deleted_items_count, null, WPRSS_LOG_LEVEL_NOTICE );
|
153 |
-
}
|
154 |
-
|
155 |
-
update_post_meta( $feed_ID, 'wprss_last_update', $last_update_time = time() );
|
156 |
-
update_post_meta( $feed_ID, 'wprss_last_update_items', 0 );
|
157 |
-
wprss_log_obj( 'Last import time updated', $last_update_time, null, WPRSS_LOG_LEVEL_SYSTEM );
|
158 |
-
|
159 |
-
// Insert the items into the db
|
160 |
-
if ( !empty( $items_to_insert ) ) {
|
161 |
-
wprss_log_obj( 'There are items to insert', count($items_to_insert), null, WPRSS_LOG_LEVEL_INFO );
|
162 |
-
wprss_items_insert_post( $items_to_insert, $feed_ID );
|
163 |
-
}
|
164 |
-
} else {
|
165 |
-
wprss_log_obj('The feed URL is not valid! Please recheck', $feed_url);
|
166 |
-
}
|
167 |
-
|
168 |
-
$next_scheduled = get_post_meta( $feed_ID, 'wprss_reschedule_event', TRUE );
|
169 |
-
|
170 |
-
if ( $next_scheduled !== '' ) {
|
171 |
-
wprss_feed_source_update_start_schedule( $feed_ID );
|
172 |
-
delete_post_meta( $feed_ID, 'wprss_reschedule_event' );
|
173 |
-
wprss_log( 'Next update rescheduled', null, WPRSS_LOG_LEVEL_SYSTEM );
|
174 |
-
}
|
175 |
-
|
176 |
-
wprss_flag_feed_as_idle( $feed_ID );
|
177 |
-
wprss_log_obj( 'Import complete', $feed_ID, __FUNCTION__, WPRSS_LOG_LEVEL_INFO );
|
178 |
-
}
|
179 |
-
|
180 |
-
|
181 |
-
/**
|
182 |
-
* Fetches the feed items from a feed at the given URL.
|
183 |
-
*
|
184 |
-
* Called from 'wprss_fetch_insert_single_feed_items'
|
185 |
-
*
|
186 |
-
* @since 3.0
|
187 |
-
*/
|
188 |
-
function wprss_get_feed_items( $feed_url, $source ) {
|
189 |
-
// Add filters and actions prior to fetching the feed items
|
190 |
-
add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
|
191 |
-
add_action( 'wp_feed_options', 'wprss_do_not_cache_feeds' );
|
192 |
-
|
193 |
-
/* Fetch the feed from the soure URL specified */
|
194 |
-
$feed = wprss_fetch_feed( $feed_url, $source );
|
195 |
-
|
196 |
-
// Remove previously added filters and actions
|
197 |
-
remove_action( 'wp_feed_options', 'wprss_do_not_cache_feeds' );
|
198 |
-
remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
|
199 |
-
|
200 |
-
if ( !is_wp_error( $feed ) ) {
|
201 |
-
// Return the items in the feed.
|
202 |
-
return $feed->get_items();
|
203 |
-
}
|
204 |
-
else {
|
205 |
-
wprss_log( 'Failed to fetch feed "' . $feed_url . '". ' . $feed->get_error_message() );
|
206 |
-
return NULL;
|
207 |
-
}
|
208 |
-
}
|
209 |
-
|
210 |
-
|
211 |
-
/**
|
212 |
-
* A clone of the function 'fetch_feed' in wp-includes/feed.php [line #529]
|
213 |
-
*
|
214 |
-
* Called from 'wprss_get_feed_items'
|
215 |
-
*
|
216 |
-
* @since 3.5
|
217 |
-
*/
|
218 |
-
function wprss_fetch_feed( $url, $source = NULL ) {
|
219 |
-
// Import SimplePie
|
220 |
-
require_once ( ABSPATH . WPINC . '/class-feed.php' );
|
221 |
-
|
222 |
-
// Trim the URL
|
223 |
-
$url = trim( $url );
|
224 |
-
|
225 |
-
// Initialize the Feed
|
226 |
-
$feed = new SimplePie();
|
227 |
-
// Obselete method calls ?
|
228 |
-
//$feed->set_cache_class( 'WP_Feed_Cache' );
|
229 |
-
//$feed->set_file_class( 'WP_SimplePie_File' );
|
230 |
-
$feed->set_feed_url( $url );
|
231 |
-
$feed->set_autodiscovery_level( SIMPLEPIE_LOCATOR_ALL );
|
232 |
-
|
233 |
-
// If a feed source was passed
|
234 |
-
if ( $source !== NULL ) {
|
235 |
-
// Get the force feed option for the feed source
|
236 |
-
$force_feed = get_post_meta( $source, 'wprss_force_feed', TRUE );
|
237 |
-
// If turned on, force the feed
|
238 |
-
if ( $force_feed == 'true' ) {
|
239 |
-
$feed->force_feed( TRUE );
|
240 |
-
}
|
241 |
-
}
|
242 |
-
|
243 |
-
// Set timeout limit
|
244 |
-
$fetch_time_limit = wprss_get_feed_fetch_time_limit();
|
245 |
-
$feed->set_timeout( $fetch_time_limit );
|
246 |
-
|
247 |
-
//$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );
|
248 |
-
$feed->enable_cache( FALSE );
|
249 |
-
|
250 |
-
// Reference array action hook, for the feed object and the URL
|
251 |
-
do_action_ref_array( 'wp_feed_options', array( &$feed, $url ) );
|
252 |
-
|
253 |
-
// Prepare the tags to strip from the feed
|
254 |
-
$tags_to_strip = apply_filters( 'wprss_feed_tags_to_strip', $feed->strip_htmltags, $source );
|
255 |
-
// Strip them
|
256 |
-
$feed->strip_htmltags( $tags_to_strip );
|
257 |
-
|
258 |
-
// Fetch the feed
|
259 |
-
$feed->init();
|
260 |
-
$feed->handle_content_type();
|
261 |
-
|
262 |
-
// Convert the feed error into a WP_Error, if applicable
|
263 |
-
if ( $feed->error() ) {
|
264 |
-
if ( $source !== NULL ) {
|
265 |
-
$msg = sprintf( __( 'Failed to fetch the RSS feed. Error: %s', WPRSS_TEXT_DOMAIN ), $feed->error() );
|
266 |
-
update_post_meta( $source, 'wprss_error_last_import', $msg );
|
267 |
-
}
|
268 |
-
return new WP_Error( 'simplepie-error', $feed->error() );
|
269 |
-
}
|
270 |
-
// If no error, return the feed and remove any error meta
|
271 |
-
delete_post_meta( $source, "wprss_error_last_import" );
|
272 |
-
return $feed;
|
273 |
-
}
|
274 |
-
|
275 |
-
|
276 |
-
/**
|
277 |
-
* Normalizes the given permalink.
|
278 |
-
*
|
279 |
-
* @param $permalink The permalink to normalize
|
280 |
-
* @return string The normalized permalink
|
281 |
-
* @since 4.2.3
|
282 |
-
*/
|
283 |
-
function wprss_normalize_permalink( $permalink ) {
|
284 |
-
// Apply normalization functions on the permalink
|
285 |
-
$permalink = trim( $permalink );
|
286 |
-
$permalink = apply_filters( 'wprss_normalize_permalink', $permalink );
|
287 |
-
// Return the normalized permalink
|
288 |
-
return $permalink;
|
289 |
-
}
|
290 |
-
|
291 |
-
|
292 |
-
/**
|
293 |
-
* Extracts the actual URL from a Google News permalink
|
294 |
-
*
|
295 |
-
* @param string $permalink The permalink to normalize.
|
296 |
-
* @since 4.2.3
|
297 |
-
*/
|
298 |
-
function wprss_google_news_url_fix($permalink) {
|
299 |
-
return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?' . preg_quote('news.google.com', '!') . '.*!');
|
300 |
-
}
|
301 |
-
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Extracts the actual URL from a Bing permalink
|
305 |
-
*
|
306 |
-
* @param string $permalink The permalink to normalize.
|
307 |
-
* @since 4.2.3
|
308 |
-
*/
|
309 |
-
function wprss_bing_news_url_fix($permalink) {
|
310 |
-
return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('bing.com/news', '!') . '.*!');
|
311 |
-
}
|
312 |
-
|
313 |
-
|
314 |
-
/**
|
315 |
-
* Checks if the permalink is a tracking permalink based on host, and if
|
316 |
-
* it is, returns the normalized URL of the proper feed item article,
|
317 |
-
* determined by the named query argument.
|
318 |
-
*
|
319 |
-
* Fixes the issue with equivalent Google News etc. items having
|
320 |
-
* different URLs, that contain randomly generated GET parameters.
|
321 |
-
* Example:
|
322 |
-
*
|
323 |
-
* http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=V3e9U6izMMnm1QaB1YHoDA&url=http://abcd...
|
324 |
-
* http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=One9U-HQLsTp1Aal-oDQBQ&url=http://abcd...
|
325 |
-
*
|
326 |
-
* @param string $permalink The permalink URL to check and/or normalize.
|
327 |
-
* @param string|array $patterns One or an array of host names, for which the URL should be fixed.
|
328 |
-
* @param string Name of the query argument that specifies the actual URL.
|
329 |
-
* @return string The normalized URL of the original article, as indicated by the `url`
|
330 |
-
* parameter in the URL query string.
|
331 |
-
* @since 4.2.3
|
332 |
-
*/
|
333 |
-
function wprss_tracking_url_fix( $permalink, $patterns, $argName = 'url' ) {
|
334 |
-
// Parse the url
|
335 |
-
$parsed = parse_url( urldecode( html_entity_decode( $permalink ) ) );
|
336 |
-
$patterns = is_array($patterns) ? $patterns :array($patterns);
|
337 |
-
|
338 |
-
// If parsing failed, return the permalink
|
339 |
-
if ( $parsed === FALSE || $parsed === NULL ) return $permalink;
|
340 |
-
|
341 |
-
// Determine if it's a tracking item
|
342 |
-
$isMatch = false;
|
343 |
-
foreach( $patterns as $_idx => $_pattern ) {
|
344 |
-
if( preg_match($_pattern, $permalink) ) {
|
345 |
-
$isMatch = true;
|
346 |
-
break;
|
347 |
-
}
|
348 |
-
}
|
349 |
-
|
350 |
-
if( !$isMatch ) return $permalink;
|
351 |
-
|
352 |
-
// Check if the url GET query string is present
|
353 |
-
if ( !isset( $parsed['query'] ) ) return $permalink;
|
354 |
-
|
355 |
-
// Parse the query string
|
356 |
-
$query = array();
|
357 |
-
parse_str( $parsed['query'], $query );
|
358 |
-
|
359 |
-
// Check if the url GET parameter is present in the query string
|
360 |
-
if ( !is_array($query) || !isset( $query[$argName] ) ) return $permalink;
|
361 |
-
|
362 |
-
return urldecode( $query[$argName] );
|
363 |
-
}
|
364 |
-
|
365 |
-
|
366 |
-
/**
|
367 |
-
* Converts YouTube, Vimeo and DailyMotion video urls
|
368 |
-
* into embedded video player urls.
|
369 |
-
* If the permalink is not a video url, the permalink is returned as is.
|
370 |
-
*
|
371 |
-
* @param $permalink The string permalink url to convert.
|
372 |
-
* @return A string, with the convert permalink, or the same permalink passed as parameter if
|
373 |
-
* not a video url.
|
374 |
-
* @since 4.0
|
375 |
-
*/
|
376 |
-
function wprss_convert_video_permalink( $permalink ) {
|
377 |
-
// CHECK PERMALINK FOR VIDEO HOSTS : YOUTUBE, VIMEO AND DAILYMOTION
|
378 |
-
$found_video_host = preg_match( '/http[s]?:\/\/(www\.)?(youtube|dailymotion|vimeo)\.com\/(.*)/i', $permalink, $matches );
|
379 |
-
|
380 |
-
// If video host was found
|
381 |
-
if ( $found_video_host !== 0 && $found_video_host !== FALSE ) {
|
382 |
-
|
383 |
-
// Get general options
|
384 |
-
$options = get_option( 'wprss_settings_general' );
|
385 |
-
// Get the video link option entry, or false if it does not exist
|
386 |
-
$video_link = ( isset($options['video_link']) )? $options['video_link'] : 'false';
|
387 |
-
|
388 |
-
// If the video link option is true, change the video URL to its repective host's embedded
|
389 |
-
// video player URL. Otherwise, leave the permalink as is.
|
390 |
-
if ( strtolower( $video_link ) === 'true' ) {
|
391 |
-
$host = $matches[2];
|
392 |
-
switch( $host ) {
|
393 |
-
case 'youtube':
|
394 |
-
preg_match( '/(&|\?)v=([^&]+)/', $permalink, $yt_matches );
|
395 |
-
$permalink = 'http://www.youtube.com/embed/' . $yt_matches[2];
|
396 |
-
break;
|
397 |
-
case 'vimeo':
|
398 |
-
preg_match( '/(\d*)$/i', $permalink, $vim_matches );
|
399 |
-
$permalink = 'http://player.vimeo.com/video/' . $vim_matches[0];
|
400 |
-
break;
|
401 |
-
case 'dailymotion':
|
402 |
-
preg_match( '/(\.com\/)(video\/)(.*)/i', $permalink, $dm_matches );
|
403 |
-
$permalink = 'http://www.dailymotion.com/embed/video/' . $dm_matches[3];
|
404 |
-
break;
|
405 |
-
}
|
406 |
-
}
|
407 |
-
}
|
408 |
-
|
409 |
-
return $permalink;
|
410 |
-
}
|
411 |
-
|
412 |
-
|
413 |
-
/**
|
414 |
-
* Insert wprss_feed_item posts into the DB
|
415 |
-
*
|
416 |
-
* @since 3.0
|
417 |
-
*/
|
418 |
-
function wprss_items_insert_post( $items, $feed_ID ) {
|
419 |
-
update_post_meta( $feed_ID, 'wprss_feed_is_updating', $update_started_at = time() );
|
420 |
-
wprss_log_obj( 'Starting import of items for feed ' . $feed_ID, $update_started_at, null, WPRSS_LOG_LEVEL_INFO );
|
421 |
-
|
422 |
-
// Gather the permalinks of existing feed item's related to this feed source
|
423 |
-
$existing_permalinks = get_existing_permalinks( $feed_ID );
|
424 |
-
|
425 |
-
// Count of items inserted
|
426 |
-
$items_inserted = 0;
|
427 |
-
|
428 |
-
foreach ( $items as $item ) {
|
429 |
-
|
430 |
-
// Normalize the URL
|
431 |
-
$permalink = wprss_normalize_permalink( $item->get_permalink() );
|
432 |
-
wprss_log_obj( 'Importing item', $permalink, null, WPRSS_LOG_LEVEL_INFO );
|
433 |
-
wprss_log_obj( 'Original permalink', $item->get_permalink(), null, WPRSS_LOG_LEVEL_SYSTEM );
|
434 |
-
|
435 |
-
// Save the enclosure URL
|
436 |
-
$enclosure_url = '';
|
437 |
-
if ( $enclosure = $item->get_enclosure(0) ) {
|
438 |
-
wprss_log( 'Item has an enclosure', null, WPRSS_LOG_LEVEL_SYSTEM );
|
439 |
-
if ( $enclosure->get_link() ) {
|
440 |
-
$enclosure_url = $enclosure->get_link();
|
441 |
-
wprss_log_obj( 'Enclosure has link', $enclosure_url, null, WPRSS_LOG_LEVEL_SYSTEM );
|
442 |
-
}
|
443 |
-
}
|
444 |
-
|
445 |
-
/* OLD NORMALIZATION CODE - TO NORMALIZE URLS FROM PROXY URLS
|
446 |
-
$response = wp_remote_head( $permalink );
|
447 |
-
if ( !is_wp_error( $response ) && isset( $response['headers']['location'] ) ) {
|
448 |
-
$permalink = current( explode( '?', $response['headers']['location'] ) );
|
449 |
-
}*/
|
450 |
-
|
451 |
-
// Check if newly fetched item already present in existing feed items,
|
452 |
-
// if not insert it into wp_posts and insert post meta.
|
453 |
-
if ( ! ( in_array( $permalink, $existing_permalinks ) ) ) {
|
454 |
-
wprss_log( "Importing (unique) feed item (Source: $feed_ID)", null, WPRSS_LOG_LEVEL_INFO );
|
455 |
-
|
456 |
-
// Extend the importing time and refresh the feed's updating flag to reflect that it is active
|
457 |
-
$extend_time = wprss_flag_feed_as_updating( $feed_ID );
|
458 |
-
$extend_time_f = date( 'Y-m-d H:i:s', $extend_time );
|
459 |
-
$time_limit = wprss_get_item_import_time_limit();
|
460 |
-
wprss_log( "Extended execution time limit by {$time_limit}. (Current Time: {$extend_time_f})", null, WPRSS_LOG_LEVEL_INFO );
|
461 |
-
set_time_limit( $time_limit );
|
462 |
-
|
463 |
-
// Apply filters that determine if the feed item should be inserted into the DB or not.
|
464 |
-
$item = apply_filters( 'wprss_insert_post_item_conditionals', $item, $feed_ID, $permalink );
|
465 |
-
|
466 |
-
// Check if the imported count should still be updated, even if the item is NULL
|
467 |
-
$still_update_count = apply_filters( 'wprss_still_update_import_count', FALSE );
|
468 |
-
|
469 |
-
// If the item is not NULL, continue to inserting the feed item post into the DB
|
470 |
-
if ( $item !== NULL && !is_bool($item) ) {
|
471 |
-
wprss_log( 'Using core logic', null, WPRSS_LOG_LEVEL_SYSTEM );
|
472 |
-
|
473 |
-
// Get the date and GTM date and normalize if not valid dor not present
|
474 |
-
$format = 'Y-m-d H:i:s';
|
475 |
-
$has_date = $item->get_date( 'U' ) ? TRUE : FALSE;
|
476 |
-
$timestamp = $has_date ? $item->get_date( 'U' ) : date( 'U' );
|
477 |
-
$date = date( $format, $timestamp );
|
478 |
-
$date_gmt = gmdate( $format, $timestamp );
|
479 |
-
// Prepare the item data
|
480 |
-
$feed_item = apply_filters(
|
481 |
-
'wprss_populate_post_data',
|
482 |
-
array(
|
483 |
-
'post_title' => html_entity_decode( $item->get_title() ),
|
484 |
-
'post_content' => '',
|
485 |
-
'post_status' => 'publish',
|
486 |
-
'post_type' => 'wprss_feed_item',
|
487 |
-
'post_date' => $date,
|
488 |
-
'post_date_gmt' => $date_gmt
|
489 |
-
),
|
490 |
-
$item
|
491 |
-
);
|
492 |
-
wprss_log( 'Post data filters applied', null, WPRSS_LOG_LEVEL_SYSTEM );
|
493 |
-
|
494 |
-
if ( defined('ICL_SITEPRESS_VERSION') )
|
495 |
-
@include_once( WP_PLUGIN_DIR . '/sitepress-multilingual-cms/inc/wpml-api.php' );
|
496 |
-
if ( defined('ICL_LANGUAGE_CODE') ) {
|
497 |
-
$_POST['icl_post_language'] = $language_code = ICL_LANGUAGE_CODE;
|
498 |
-
wprss_log_obj( 'WPML detected. Language code determined', $language_code, null, WPRSS_LOG_LEVEL_SYSTEM );
|
499 |
-
}
|
500 |
-
|
501 |
-
// Create and insert post object into the DB
|
502 |
-
$inserted_ID = wp_insert_post( $feed_item );
|
503 |
-
|
504 |
-
if ( !is_wp_error( $inserted_ID ) ) {
|
505 |
-
|
506 |
-
if ( is_object( $inserted_ID ) ) {
|
507 |
-
if ( isset( $inserted_ID['ID'] ) ) {
|
508 |
-
$inserted_ID = $inserted_ID['ID'];
|
509 |
-
}
|
510 |
-
elseif ( isset( $inserted_ID->ID ) ) {
|
511 |
-
$inserted_ID = $inserted_ID->ID;
|
512 |
-
}
|
513 |
-
}
|
514 |
-
|
515 |
-
// Increment the inserted items counter
|
516 |
-
$items_inserted++;
|
517 |
-
|
518 |
-
// Create and insert post meta into the DB
|
519 |
-
wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url );
|
520 |
-
|
521 |
-
// Remember newly added permalink
|
522 |
-
$existing_permalinks[] = $permalink;
|
523 |
-
wprss_log_obj( 'Item imported', $inserted_ID, null, WPRSS_LOG_LEVEL_INFO );
|
524 |
-
}
|
525 |
-
else {
|
526 |
-
update_post_meta( $source, 'wprss_error_last_import', 'An error occurred while inserting a feed item into the database.' );
|
527 |
-
wprss_log_obj( 'Failed to insert post', $feed_item, 'wprss_items_insert_post > wp_insert_post' );
|
528 |
-
}
|
529 |
-
}
|
530 |
-
// If the item is TRUE, then a hook function in the filter inserted the item.
|
531 |
-
// increment the inserted counter
|
532 |
-
elseif ( ( is_bool($item) && $item === TRUE ) || ( $still_update_count === TRUE && $item !== FALSE ) ) {
|
533 |
-
$items_inserted++;
|
534 |
-
}
|
535 |
-
}
|
536 |
-
else {
|
537 |
-
wprss_log( 'Item already exists and will be skipped', null, WPRSS_LOG_LEVEL_NOTICE );
|
538 |
-
}
|
539 |
-
|
540 |
-
wprss_log_obj( 'Finished importing item', $permalink, null, WPRSS_LOG_LEVEL_INFO );
|
541 |
-
}
|
542 |
-
|
543 |
-
update_post_meta( $feed_ID, 'wprss_last_update_items', $items_inserted );
|
544 |
-
wprss_log_obj( sprintf( 'Finished importing %1$d items for feed source', $items_inserted ), $feed_ID, null, WPRSS_LOG_LEVEL_INFO );
|
545 |
-
}
|
546 |
-
|
547 |
-
|
548 |
-
/**
|
549 |
-
* Inserts the appropriate post meta for feed items.
|
550 |
-
*
|
551 |
-
* Called from 'wprss_items_insert_post'
|
552 |
-
*
|
553 |
-
* @since 2.3
|
554 |
-
*/
|
555 |
-
function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url ) {
|
556 |
-
update_post_meta( $inserted_ID, 'wprss_item_permalink', $permalink );
|
557 |
-
update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosure_url );
|
558 |
-
|
559 |
-
$author = $item->get_author();
|
560 |
-
if ( $author ) {
|
561 |
-
update_post_meta( $inserted_ID, 'wprss_item_author', $author->get_name() );
|
562 |
-
}
|
563 |
-
|
564 |
-
update_post_meta( $inserted_ID, 'wprss_feed_id', $feed_ID);
|
565 |
-
do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
|
566 |
-
}
|
567 |
-
|
568 |
-
|
569 |
-
/**
|
570 |
-
* Returns the time limit for the importing of a single feed item.
|
571 |
-
* The value if filtered through 'wprss_item_import_time_limit'. The default value is WPRSS_ITEM_IMPORT_TIME_LIMIT.
|
572 |
-
*
|
573 |
-
* @since 4.6.6
|
574 |
-
* @return int The maximum amount of seconds allowed for a single feed item to import.
|
575 |
-
*/
|
576 |
-
function wprss_get_item_import_time_limit() {
|
577 |
-
return apply_filters( 'wprss_item_import_time_limit', WPRSS_ITEM_IMPORT_TIME_LIMIT );
|
578 |
-
}
|
579 |
-
|
580 |
-
/**
|
581 |
-
* Returns the time limit for a feed fetch operation.
|
582 |
-
* The value if filtered through 'wprss_feed_fetch_time_limit'. The default value is WPRSS_FEED_FETCH_TIME_LIMIT.
|
583 |
-
*
|
584 |
-
* @since 4.6.6
|
585 |
-
* @return int The maximum amount of seconds allowed for an RSS feed XML document to be fetched.
|
586 |
-
*/
|
587 |
-
function wprss_get_feed_fetch_time_limit() {
|
588 |
-
return apply_filters( 'wprss_feed_fetch_time_limit', WPRSS_FEED_FETCH_TIME_LIMIT );
|
589 |
-
}
|
590 |
-
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Fetches all feed items from all feed sources.
|
594 |
-
* Iteratively calls 'wprss_fetch_insert_single_feed_items' for all feed sources.
|
595 |
-
*
|
596 |
-
* This function is used by the cron job or the debugging functions to get all feeds from all feed sources
|
597 |
-
*
|
598 |
-
* @param $all If set to TRUE, the function will pull from all feed sources, regardless of their individual
|
599 |
-
* update interval. If set to FALSE, only feed sources using the global update system will be updated.
|
600 |
-
* (Optional) Default: TRUE.
|
601 |
-
* @since 3.0
|
602 |
-
*/
|
603 |
-
function wprss_fetch_insert_all_feed_items( $all = TRUE ) {
|
604 |
-
wprss_log( 'Importing from all sources...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM );
|
605 |
-
// Get all feed sources
|
606 |
-
$feed_sources = wprss_get_all_feed_sources();
|
607 |
-
|
608 |
-
if( $feed_sources->have_posts() ) {
|
609 |
-
// Start by getting one feed source, we will cycle through them one by one,
|
610 |
-
// fetching feed items and adding them to the database in each pass
|
611 |
-
while ( $feed_sources->have_posts() ) {
|
612 |
-
$feed_sources->the_post();
|
613 |
-
|
614 |
-
$interval = get_post_meta( get_the_ID(), 'wprss_update_interval', TRUE );
|
615 |
-
$using_global_interval = ( $interval === wprss_get_default_feed_source_update_interval() || $interval === '' );
|
616 |
-
|
617 |
-
// Check if fetching from all, or if feed source uses the global interval
|
618 |
-
if ( $all === TRUE || $using_global_interval ) {
|
619 |
-
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( get_the_ID() ) );
|
620 |
-
}
|
621 |
-
}
|
622 |
-
wp_reset_postdata(); // Restore the $post global to the current post in the main query
|
623 |
-
}
|
624 |
-
}
|
625 |
-
|
626 |
-
|
627 |
-
/**
|
628 |
-
* Runs the above function with parameter FALSE
|
629 |
-
*
|
630 |
-
* @since 3.9
|
631 |
-
*/
|
632 |
-
function wprss_fetch_insert_all_feed_items_from_cron() {
|
633 |
-
wprss_fetch_insert_all_feed_items( FALSE );
|
634 |
-
}
|
635 |
-
|
636 |
-
|
637 |
-
/**
|
638 |
-
* Shutdown function for detecting if the PHP script reaches the maximum execution time limit
|
639 |
-
* while importing a feed.
|
640 |
-
*
|
641 |
-
* @since 4.6.6
|
642 |
-
*/
|
643 |
-
function wprss_detect_exec_timeout() {
|
644 |
-
// Get last error
|
645 |
-
if ( $error = error_get_last() ){
|
646 |
-
// Check if it is an E_ERROR and if it is a max exec time limit error
|
647 |
-
if ( $error['type'] === E_ERROR && stripos( $error['message'], 'maximum execution' ) === 0 ) {
|
648 |
-
// If the importing process was running
|
649 |
-
if ( array_key_exists( 'wprss_importing_feed', $GLOBALS ) && $GLOBALS['wprss_importing_feed'] !== NULL ) {
|
650 |
-
// Get the ID of the feed that was importing
|
651 |
-
$feed_ID = $GLOBALS['wprss_importing_feed'];
|
652 |
-
// Perform clean up
|
653 |
-
wprss_flag_feed_as_idle( $feed_ID );
|
654 |
-
$msg = sprintf( __( 'The PHP script timed out while importing an item from this feed, after %d seconds.', WPRSS_TEXT_DOMAIN ), wprss_get_item_import_time_limit() );
|
655 |
-
update_post_meta( $feed_ID, 'wprss_error_last_import', $msg );
|
656 |
-
// Log the error
|
657 |
-
wprss_log( 'The PHP script timed out while importing feed #' . $feed_ID, NULL, WPRSS_LOG_LEVEL_ERROR );
|
658 |
-
}
|
659 |
-
}
|
660 |
-
}
|
661 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Functions relating to feed importing
|
4 |
+
*
|
5 |
+
* @package WPRSSAggregator
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
// Warning: Order may be important
|
10 |
+
add_filter('wprss_normalize_permalink', 'wprss_google_news_url_fix', 8);
|
11 |
+
add_filter('wprss_normalize_permalink', 'wprss_bing_news_url_fix', 9);
|
12 |
+
add_filter('wprss_normalize_permalink', 'wprss_convert_video_permalink', 100);
|
13 |
+
|
14 |
+
|
15 |
+
add_action( 'wprss_fetch_single_feed_hook', 'wprss_fetch_insert_single_feed_items' );
|
16 |
+
/**
|
17 |
+
* The main feed fetching function.
|
18 |
+
* Fetches the feed items from the source provided and inserts them into the DB.
|
19 |
+
*
|
20 |
+
* Called on hook 'wprss_fetch_single_feed_hook'.
|
21 |
+
*
|
22 |
+
* @since 3.2
|
23 |
+
*/
|
24 |
+
function wprss_fetch_insert_single_feed_items( $feed_ID ) {
|
25 |
+
wprss_log_obj( 'Starting import of feed', $feed_ID, null, WPRSS_LOG_LEVEL_INFO );
|
26 |
+
|
27 |
+
global $wprss_importing_feed;
|
28 |
+
$wprss_importing_feed = $feed_ID;
|
29 |
+
register_shutdown_function( 'wprss_detect_exec_timeout' );
|
30 |
+
|
31 |
+
// Check if the feed source is active.
|
32 |
+
if ( wprss_is_feed_source_active( $feed_ID ) === FALSE && wprss_feed_source_force_next_fetch( $feed_ID ) === FALSE ) {
|
33 |
+
// If it is not active ( paused ), return without fetching the feed items.
|
34 |
+
wprss_log( 'Feed is not active and not forced. Import cancelled.', null, WPRSS_LOG_LEVEL_INFO );
|
35 |
+
return;
|
36 |
+
}
|
37 |
+
// If the feed source is forced for next fetch, remove the force next fetch data
|
38 |
+
if ( wprss_feed_source_force_next_fetch( $feed_ID ) ) {
|
39 |
+
delete_post_meta( $feed_ID, 'wprss_force_next_fetch' );
|
40 |
+
wprss_log( 'Force feed flag removed', null, WPRSS_LOG_LEVEL_SYSTEM );
|
41 |
+
}
|
42 |
+
|
43 |
+
$start_of_update = wprss_flag_feed_as_updating( $feed_ID );
|
44 |
+
wprss_log_obj( 'Start of import time updated', date( 'Y-m-d H:i:s', $start_of_update), null, WPRSS_LOG_LEVEL_SYSTEM );
|
45 |
+
|
46 |
+
// Get the feed source URL from post meta, and filter it
|
47 |
+
$feed_url = get_post_meta( $feed_ID, 'wprss_url', true );
|
48 |
+
wprss_log_obj( 'Original feed source URL', $feed_url, null, WPRSS_LOG_LEVEL_SYSTEM );
|
49 |
+
$feed_url = apply_filters( 'wprss_feed_source_url', $feed_url, $feed_ID );
|
50 |
+
wprss_log_obj( 'Actual feed source URL', $feed_url, null, WPRSS_LOG_LEVEL_INFO );
|
51 |
+
|
52 |
+
// Get the feed limit from post meta
|
53 |
+
$feed_limit = get_post_meta( $feed_ID, 'wprss_limit', true );
|
54 |
+
wprss_log_obj( 'Feed limit value is', $feed_limit, null, WPRSS_LOG_LEVEL_SYSTEM );
|
55 |
+
|
56 |
+
// If the feed has no individual limit
|
57 |
+
if ( $feed_limit === '' || intval( $feed_limit ) <= 0 ) {
|
58 |
+
wprss_log_obj( 'Using global limit', $feed_limit, null, WPRSS_LOG_LEVEL_NOTICE );
|
59 |
+
// Get the global limit
|
60 |
+
$global_limit = wprss_get_general_setting('limit_feed_items_imported');
|
61 |
+
// If no global limit is set, mark as NULL
|
62 |
+
if ( $global_limit === '' || intval($global_limit) <= 0 ) {
|
63 |
+
$feed_limit = NULL;
|
64 |
+
}
|
65 |
+
else $feed_limit = $global_limit;
|
66 |
+
}
|
67 |
+
wprss_log_obj( 'Feed import limit', $feed_limit, null, WPRSS_LOG_LEVEL_INFO );
|
68 |
+
|
69 |
+
// Filter the URL for validaty
|
70 |
+
if ( wprss_validate_url( $feed_url ) ) {
|
71 |
+
wprss_log_obj( 'Feed URL is valid', $feed_url, null, WPRSS_LOG_LEVEL_INFO );
|
72 |
+
// Get the feed items from the source
|
73 |
+
$items = wprss_get_feed_items( $feed_url, $feed_ID );
|
74 |
+
// If got NULL, convert to an empty array
|
75 |
+
if ( $items === NULL ) {
|
76 |
+
$items = array();
|
77 |
+
wprss_log( 'Items were NULL. Using empty array', null, WPRSS_LOG_LEVEL_WARNING );
|
78 |
+
}
|
79 |
+
|
80 |
+
// If using a limit ...
|
81 |
+
if ( $feed_limit === NULL ) {
|
82 |
+
$items_to_insert = $items;
|
83 |
+
} else {
|
84 |
+
$items_to_insert = array_slice( $items, 0, $feed_limit );
|
85 |
+
wprss_log_obj( 'Sliced a segment of items', count($items_to_insert), null, WPRSS_LOG_LEVEL_SYSTEM );
|
86 |
+
}
|
87 |
+
|
88 |
+
// Gather the permalinks of existing feed item's related to this feed source
|
89 |
+
$existing_permalinks = get_existing_permalinks( $feed_ID );
|
90 |
+
wprss_log_obj( 'Retrieved existing permalinks', count( $existing_permalinks ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
91 |
+
|
92 |
+
// Generate a list of items fetched, that are not already in the DB
|
93 |
+
$new_items = array();
|
94 |
+
foreach ( $items_to_insert as $item ) {
|
95 |
+
$permalink = wprss_normalize_permalink( $item->get_permalink() );
|
96 |
+
wprss_log_obj( 'Normalizing permalink', sprintf('%1$s -> %2$s', $item->get_permalink(), $permalink), null, WPRSS_LOG_LEVEL_SYSTEM );
|
97 |
+
// Check if not blacklisted and not already imported
|
98 |
+
$is_blacklisted = wprss_is_blacklisted( $permalink );
|
99 |
+
$already_exists = in_array( $permalink, $existing_permalinks );
|
100 |
+
if ( $is_blacklisted === FALSE && $already_exists === FALSE ) {
|
101 |
+
$new_items[] = $item;
|
102 |
+
wprss_log_obj( 'Permalink OK', $permalink, null, WPRSS_LOG_LEVEL_SYSTEM );
|
103 |
+
}
|
104 |
+
else {
|
105 |
+
if ( $is_blacklisted ) {
|
106 |
+
wprss_log( 'Permalink blacklisted', null, WPRSS_LOG_LEVEL_SYSTEM );
|
107 |
+
}
|
108 |
+
if ( $already_exists ) {
|
109 |
+
wprss_log( 'Permalink already exists', null, WPRSS_LOG_LEVEL_SYSTEM );
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
$original_count = count( $items_to_insert );
|
115 |
+
$new_count = count( $new_items );
|
116 |
+
if ( $new_count !== $original_count ) {
|
117 |
+
wprss_log_obj( 'Items filtered out', $original_count - $new_count, null, WPRSS_LOG_LEVEL_SYSTEM );
|
118 |
+
} else {
|
119 |
+
wprss_log( 'Items to import remained untouched. Not items already exist or are blacklisted.', null, WPRSS_LOG_LEVEL_SYSTEM );
|
120 |
+
}
|
121 |
+
|
122 |
+
$items_to_insert = $new_items;
|
123 |
+
|
124 |
+
// If using a limit - delete any excess items to make room for the new items
|
125 |
+
if ( $feed_limit !== NULL ) {
|
126 |
+
wprss_log_obj( 'Some items may be deleted due to limit', $feed_limit, null, WPRSS_LOG_LEVEL_SYSTEM );
|
127 |
+
|
128 |
+
// Get the number of feed items in DB, and their count
|
129 |
+
$db_feed_items = wprss_get_feed_items_for_source( $feed_ID );
|
130 |
+
$num_db_feed_items = $db_feed_items->post_count;
|
131 |
+
|
132 |
+
// Get the number of feed items we can store until we reach the limit
|
133 |
+
$num_can_insert = $feed_limit - $num_db_feed_items;
|
134 |
+
// Calculate how many feed items we must delete before importing, to keep to the limit
|
135 |
+
$num_new_items = count( $new_items );
|
136 |
+
$num_feed_items_to_delete = $num_can_insert > $num_new_items
|
137 |
+
? 0
|
138 |
+
: $num_new_items - $num_can_insert;
|
139 |
+
|
140 |
+
// Get an array with the DB feed items in reverse order (oldest first)
|
141 |
+
$db_feed_items_reversed = array_reverse( $db_feed_items->posts );
|
142 |
+
// Cut the array to get only the first few that are to be deleted ( equal to $num_feed_items_to_delete )
|
143 |
+
$feed_items_to_delete = array_slice( $db_feed_items_reversed, 0, $num_feed_items_to_delete );
|
144 |
+
wprss_log( sprintf( 'There already are %1$d items in the database. %2$d items can be inserted. %3$d items will be deleted', $num_db_feed_items, $num_can_insert, $num_feed_items_to_delete ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
145 |
+
|
146 |
+
// Iterate the feed items and delete them
|
147 |
+
foreach ( $feed_items_to_delete as $key => $post ) {
|
148 |
+
wp_delete_post( $post->ID, TRUE );
|
149 |
+
}
|
150 |
+
|
151 |
+
if ( $deleted_items_count = count( $feed_items_to_delete ) )
|
152 |
+
wprss_log_obj( 'Items deleted due to limit', $deleted_items_count, null, WPRSS_LOG_LEVEL_NOTICE );
|
153 |
+
}
|
154 |
+
|
155 |
+
update_post_meta( $feed_ID, 'wprss_last_update', $last_update_time = time() );
|
156 |
+
update_post_meta( $feed_ID, 'wprss_last_update_items', 0 );
|
157 |
+
wprss_log_obj( 'Last import time updated', $last_update_time, null, WPRSS_LOG_LEVEL_SYSTEM );
|
158 |
+
|
159 |
+
// Insert the items into the db
|
160 |
+
if ( !empty( $items_to_insert ) ) {
|
161 |
+
wprss_log_obj( 'There are items to insert', count($items_to_insert), null, WPRSS_LOG_LEVEL_INFO );
|
162 |
+
wprss_items_insert_post( $items_to_insert, $feed_ID );
|
163 |
+
}
|
164 |
+
} else {
|
165 |
+
wprss_log_obj('The feed URL is not valid! Please recheck', $feed_url);
|
166 |
+
}
|
167 |
+
|
168 |
+
$next_scheduled = get_post_meta( $feed_ID, 'wprss_reschedule_event', TRUE );
|
169 |
+
|
170 |
+
if ( $next_scheduled !== '' ) {
|
171 |
+
wprss_feed_source_update_start_schedule( $feed_ID );
|
172 |
+
delete_post_meta( $feed_ID, 'wprss_reschedule_event' );
|
173 |
+
wprss_log( 'Next update rescheduled', null, WPRSS_LOG_LEVEL_SYSTEM );
|
174 |
+
}
|
175 |
+
|
176 |
+
wprss_flag_feed_as_idle( $feed_ID );
|
177 |
+
wprss_log_obj( 'Import complete', $feed_ID, __FUNCTION__, WPRSS_LOG_LEVEL_INFO );
|
178 |
+
}
|
179 |
+
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Fetches the feed items from a feed at the given URL.
|
183 |
+
*
|
184 |
+
* Called from 'wprss_fetch_insert_single_feed_items'
|
185 |
+
*
|
186 |
+
* @since 3.0
|
187 |
+
*/
|
188 |
+
function wprss_get_feed_items( $feed_url, $source ) {
|
189 |
+
// Add filters and actions prior to fetching the feed items
|
190 |
+
add_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
|
191 |
+
add_action( 'wp_feed_options', 'wprss_do_not_cache_feeds' );
|
192 |
+
|
193 |
+
/* Fetch the feed from the soure URL specified */
|
194 |
+
$feed = wprss_fetch_feed( $feed_url, $source );
|
195 |
+
|
196 |
+
// Remove previously added filters and actions
|
197 |
+
remove_action( 'wp_feed_options', 'wprss_do_not_cache_feeds' );
|
198 |
+
remove_filter( 'wp_feed_cache_transient_lifetime' , 'wprss_feed_cache_lifetime' );
|
199 |
+
|
200 |
+
if ( !is_wp_error( $feed ) ) {
|
201 |
+
// Return the items in the feed.
|
202 |
+
return $feed->get_items();
|
203 |
+
}
|
204 |
+
else {
|
205 |
+
wprss_log( 'Failed to fetch feed "' . $feed_url . '". ' . $feed->get_error_message() );
|
206 |
+
return NULL;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
|
211 |
+
/**
|
212 |
+
* A clone of the function 'fetch_feed' in wp-includes/feed.php [line #529]
|
213 |
+
*
|
214 |
+
* Called from 'wprss_get_feed_items'
|
215 |
+
*
|
216 |
+
* @since 3.5
|
217 |
+
*/
|
218 |
+
function wprss_fetch_feed( $url, $source = NULL ) {
|
219 |
+
// Import SimplePie
|
220 |
+
require_once ( ABSPATH . WPINC . '/class-feed.php' );
|
221 |
+
|
222 |
+
// Trim the URL
|
223 |
+
$url = trim( $url );
|
224 |
+
|
225 |
+
// Initialize the Feed
|
226 |
+
$feed = new SimplePie();
|
227 |
+
// Obselete method calls ?
|
228 |
+
//$feed->set_cache_class( 'WP_Feed_Cache' );
|
229 |
+
//$feed->set_file_class( 'WP_SimplePie_File' );
|
230 |
+
$feed->set_feed_url( $url );
|
231 |
+
$feed->set_autodiscovery_level( SIMPLEPIE_LOCATOR_ALL );
|
232 |
+
|
233 |
+
// If a feed source was passed
|
234 |
+
if ( $source !== NULL ) {
|
235 |
+
// Get the force feed option for the feed source
|
236 |
+
$force_feed = get_post_meta( $source, 'wprss_force_feed', TRUE );
|
237 |
+
// If turned on, force the feed
|
238 |
+
if ( $force_feed == 'true' ) {
|
239 |
+
$feed->force_feed( TRUE );
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
// Set timeout limit
|
244 |
+
$fetch_time_limit = wprss_get_feed_fetch_time_limit();
|
245 |
+
$feed->set_timeout( $fetch_time_limit );
|
246 |
+
|
247 |
+
//$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );
|
248 |
+
$feed->enable_cache( FALSE );
|
249 |
+
|
250 |
+
// Reference array action hook, for the feed object and the URL
|
251 |
+
do_action_ref_array( 'wp_feed_options', array( &$feed, $url ) );
|
252 |
+
|
253 |
+
// Prepare the tags to strip from the feed
|
254 |
+
$tags_to_strip = apply_filters( 'wprss_feed_tags_to_strip', $feed->strip_htmltags, $source );
|
255 |
+
// Strip them
|
256 |
+
$feed->strip_htmltags( $tags_to_strip );
|
257 |
+
|
258 |
+
// Fetch the feed
|
259 |
+
$feed->init();
|
260 |
+
$feed->handle_content_type();
|
261 |
+
|
262 |
+
// Convert the feed error into a WP_Error, if applicable
|
263 |
+
if ( $feed->error() ) {
|
264 |
+
if ( $source !== NULL ) {
|
265 |
+
$msg = sprintf( __( 'Failed to fetch the RSS feed. Error: %s', WPRSS_TEXT_DOMAIN ), $feed->error() );
|
266 |
+
update_post_meta( $source, 'wprss_error_last_import', $msg );
|
267 |
+
}
|
268 |
+
return new WP_Error( 'simplepie-error', $feed->error() );
|
269 |
+
}
|
270 |
+
// If no error, return the feed and remove any error meta
|
271 |
+
delete_post_meta( $source, "wprss_error_last_import" );
|
272 |
+
return $feed;
|
273 |
+
}
|
274 |
+
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Normalizes the given permalink.
|
278 |
+
*
|
279 |
+
* @param $permalink The permalink to normalize
|
280 |
+
* @return string The normalized permalink
|
281 |
+
* @since 4.2.3
|
282 |
+
*/
|
283 |
+
function wprss_normalize_permalink( $permalink ) {
|
284 |
+
// Apply normalization functions on the permalink
|
285 |
+
$permalink = trim( $permalink );
|
286 |
+
$permalink = apply_filters( 'wprss_normalize_permalink', $permalink );
|
287 |
+
// Return the normalized permalink
|
288 |
+
return $permalink;
|
289 |
+
}
|
290 |
+
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Extracts the actual URL from a Google News permalink
|
294 |
+
*
|
295 |
+
* @param string $permalink The permalink to normalize.
|
296 |
+
* @since 4.2.3
|
297 |
+
*/
|
298 |
+
function wprss_google_news_url_fix($permalink) {
|
299 |
+
return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?' . preg_quote('news.google.com', '!') . '.*!');
|
300 |
+
}
|
301 |
+
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Extracts the actual URL from a Bing permalink
|
305 |
+
*
|
306 |
+
* @param string $permalink The permalink to normalize.
|
307 |
+
* @since 4.2.3
|
308 |
+
*/
|
309 |
+
function wprss_bing_news_url_fix($permalink) {
|
310 |
+
return wprss_tracking_url_fix($permalink, '!^(https?:\/\/)?(www\.)?' . preg_quote('bing.com/news', '!') . '.*!');
|
311 |
+
}
|
312 |
+
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Checks if the permalink is a tracking permalink based on host, and if
|
316 |
+
* it is, returns the normalized URL of the proper feed item article,
|
317 |
+
* determined by the named query argument.
|
318 |
+
*
|
319 |
+
* Fixes the issue with equivalent Google News etc. items having
|
320 |
+
* different URLs, that contain randomly generated GET parameters.
|
321 |
+
* Example:
|
322 |
+
*
|
323 |
+
* http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=V3e9U6izMMnm1QaB1YHoDA&url=http://abcd...
|
324 |
+
* http://news.google.com/news/url?sa=t&fd=R&ct2=us&ei=One9U-HQLsTp1Aal-oDQBQ&url=http://abcd...
|
325 |
+
*
|
326 |
+
* @param string $permalink The permalink URL to check and/or normalize.
|
327 |
+
* @param string|array $patterns One or an array of host names, for which the URL should be fixed.
|
328 |
+
* @param string Name of the query argument that specifies the actual URL.
|
329 |
+
* @return string The normalized URL of the original article, as indicated by the `url`
|
330 |
+
* parameter in the URL query string.
|
331 |
+
* @since 4.2.3
|
332 |
+
*/
|
333 |
+
function wprss_tracking_url_fix( $permalink, $patterns, $argName = 'url' ) {
|
334 |
+
// Parse the url
|
335 |
+
$parsed = parse_url( urldecode( html_entity_decode( $permalink ) ) );
|
336 |
+
$patterns = is_array($patterns) ? $patterns :array($patterns);
|
337 |
+
|
338 |
+
// If parsing failed, return the permalink
|
339 |
+
if ( $parsed === FALSE || $parsed === NULL ) return $permalink;
|
340 |
+
|
341 |
+
// Determine if it's a tracking item
|
342 |
+
$isMatch = false;
|
343 |
+
foreach( $patterns as $_idx => $_pattern ) {
|
344 |
+
if( preg_match($_pattern, $permalink) ) {
|
345 |
+
$isMatch = true;
|
346 |
+
break;
|
347 |
+
}
|
348 |
+
}
|
349 |
+
|
350 |
+
if( !$isMatch ) return $permalink;
|
351 |
+
|
352 |
+
// Check if the url GET query string is present
|
353 |
+
if ( !isset( $parsed['query'] ) ) return $permalink;
|
354 |
+
|
355 |
+
// Parse the query string
|
356 |
+
$query = array();
|
357 |
+
parse_str( $parsed['query'], $query );
|
358 |
+
|
359 |
+
// Check if the url GET parameter is present in the query string
|
360 |
+
if ( !is_array($query) || !isset( $query[$argName] ) ) return $permalink;
|
361 |
+
|
362 |
+
return urldecode( $query[$argName] );
|
363 |
+
}
|
364 |
+
|
365 |
+
|
366 |
+
/**
|
367 |
+
* Converts YouTube, Vimeo and DailyMotion video urls
|
368 |
+
* into embedded video player urls.
|
369 |
+
* If the permalink is not a video url, the permalink is returned as is.
|
370 |
+
*
|
371 |
+
* @param $permalink The string permalink url to convert.
|
372 |
+
* @return A string, with the convert permalink, or the same permalink passed as parameter if
|
373 |
+
* not a video url.
|
374 |
+
* @since 4.0
|
375 |
+
*/
|
376 |
+
function wprss_convert_video_permalink( $permalink ) {
|
377 |
+
// CHECK PERMALINK FOR VIDEO HOSTS : YOUTUBE, VIMEO AND DAILYMOTION
|
378 |
+
$found_video_host = preg_match( '/http[s]?:\/\/(www\.)?(youtube|dailymotion|vimeo)\.com\/(.*)/i', $permalink, $matches );
|
379 |
+
|
380 |
+
// If video host was found
|
381 |
+
if ( $found_video_host !== 0 && $found_video_host !== FALSE ) {
|
382 |
+
|
383 |
+
// Get general options
|
384 |
+
$options = get_option( 'wprss_settings_general' );
|
385 |
+
// Get the video link option entry, or false if it does not exist
|
386 |
+
$video_link = ( isset($options['video_link']) )? $options['video_link'] : 'false';
|
387 |
+
|
388 |
+
// If the video link option is true, change the video URL to its repective host's embedded
|
389 |
+
// video player URL. Otherwise, leave the permalink as is.
|
390 |
+
if ( strtolower( $video_link ) === 'true' ) {
|
391 |
+
$host = $matches[2];
|
392 |
+
switch( $host ) {
|
393 |
+
case 'youtube':
|
394 |
+
preg_match( '/(&|\?)v=([^&]+)/', $permalink, $yt_matches );
|
395 |
+
$permalink = 'http://www.youtube.com/embed/' . $yt_matches[2];
|
396 |
+
break;
|
397 |
+
case 'vimeo':
|
398 |
+
preg_match( '/(\d*)$/i', $permalink, $vim_matches );
|
399 |
+
$permalink = 'http://player.vimeo.com/video/' . $vim_matches[0];
|
400 |
+
break;
|
401 |
+
case 'dailymotion':
|
402 |
+
preg_match( '/(\.com\/)(video\/)(.*)/i', $permalink, $dm_matches );
|
403 |
+
$permalink = 'http://www.dailymotion.com/embed/video/' . $dm_matches[3];
|
404 |
+
break;
|
405 |
+
}
|
406 |
+
}
|
407 |
+
}
|
408 |
+
|
409 |
+
return $permalink;
|
410 |
+
}
|
411 |
+
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Insert wprss_feed_item posts into the DB
|
415 |
+
*
|
416 |
+
* @since 3.0
|
417 |
+
*/
|
418 |
+
function wprss_items_insert_post( $items, $feed_ID ) {
|
419 |
+
update_post_meta( $feed_ID, 'wprss_feed_is_updating', $update_started_at = time() );
|
420 |
+
wprss_log_obj( 'Starting import of items for feed ' . $feed_ID, $update_started_at, null, WPRSS_LOG_LEVEL_INFO );
|
421 |
+
|
422 |
+
// Gather the permalinks of existing feed item's related to this feed source
|
423 |
+
$existing_permalinks = get_existing_permalinks( $feed_ID );
|
424 |
+
|
425 |
+
// Count of items inserted
|
426 |
+
$items_inserted = 0;
|
427 |
+
|
428 |
+
foreach ( $items as $item ) {
|
429 |
+
|
430 |
+
// Normalize the URL
|
431 |
+
$permalink = wprss_normalize_permalink( $item->get_permalink() );
|
432 |
+
wprss_log_obj( 'Importing item', $permalink, null, WPRSS_LOG_LEVEL_INFO );
|
433 |
+
wprss_log_obj( 'Original permalink', $item->get_permalink(), null, WPRSS_LOG_LEVEL_SYSTEM );
|
434 |
+
|
435 |
+
// Save the enclosure URL
|
436 |
+
$enclosure_url = '';
|
437 |
+
if ( $enclosure = $item->get_enclosure(0) ) {
|
438 |
+
wprss_log( 'Item has an enclosure', null, WPRSS_LOG_LEVEL_SYSTEM );
|
439 |
+
if ( $enclosure->get_link() ) {
|
440 |
+
$enclosure_url = $enclosure->get_link();
|
441 |
+
wprss_log_obj( 'Enclosure has link', $enclosure_url, null, WPRSS_LOG_LEVEL_SYSTEM );
|
442 |
+
}
|
443 |
+
}
|
444 |
+
|
445 |
+
/* OLD NORMALIZATION CODE - TO NORMALIZE URLS FROM PROXY URLS
|
446 |
+
$response = wp_remote_head( $permalink );
|
447 |
+
if ( !is_wp_error( $response ) && isset( $response['headers']['location'] ) ) {
|
448 |
+
$permalink = current( explode( '?', $response['headers']['location'] ) );
|
449 |
+
}*/
|
450 |
+
|
451 |
+
// Check if newly fetched item already present in existing feed items,
|
452 |
+
// if not insert it into wp_posts and insert post meta.
|
453 |
+
if ( ! ( in_array( $permalink, $existing_permalinks ) ) ) {
|
454 |
+
wprss_log( "Importing (unique) feed item (Source: $feed_ID)", null, WPRSS_LOG_LEVEL_INFO );
|
455 |
+
|
456 |
+
// Extend the importing time and refresh the feed's updating flag to reflect that it is active
|
457 |
+
$extend_time = wprss_flag_feed_as_updating( $feed_ID );
|
458 |
+
$extend_time_f = date( 'Y-m-d H:i:s', $extend_time );
|
459 |
+
$time_limit = wprss_get_item_import_time_limit();
|
460 |
+
wprss_log( "Extended execution time limit by {$time_limit}. (Current Time: {$extend_time_f})", null, WPRSS_LOG_LEVEL_INFO );
|
461 |
+
set_time_limit( $time_limit );
|
462 |
+
|
463 |
+
// Apply filters that determine if the feed item should be inserted into the DB or not.
|
464 |
+
$item = apply_filters( 'wprss_insert_post_item_conditionals', $item, $feed_ID, $permalink );
|
465 |
+
|
466 |
+
// Check if the imported count should still be updated, even if the item is NULL
|
467 |
+
$still_update_count = apply_filters( 'wprss_still_update_import_count', FALSE );
|
468 |
+
|
469 |
+
// If the item is not NULL, continue to inserting the feed item post into the DB
|
470 |
+
if ( $item !== NULL && !is_bool($item) ) {
|
471 |
+
wprss_log( 'Using core logic', null, WPRSS_LOG_LEVEL_SYSTEM );
|
472 |
+
|
473 |
+
// Get the date and GTM date and normalize if not valid dor not present
|
474 |
+
$format = 'Y-m-d H:i:s';
|
475 |
+
$has_date = $item->get_date( 'U' ) ? TRUE : FALSE;
|
476 |
+
$timestamp = $has_date ? $item->get_date( 'U' ) : date( 'U' );
|
477 |
+
$date = date( $format, $timestamp );
|
478 |
+
$date_gmt = gmdate( $format, $timestamp );
|
479 |
+
// Prepare the item data
|
480 |
+
$feed_item = apply_filters(
|
481 |
+
'wprss_populate_post_data',
|
482 |
+
array(
|
483 |
+
'post_title' => html_entity_decode( $item->get_title() ),
|
484 |
+
'post_content' => '',
|
485 |
+
'post_status' => 'publish',
|
486 |
+
'post_type' => 'wprss_feed_item',
|
487 |
+
'post_date' => $date,
|
488 |
+
'post_date_gmt' => $date_gmt
|
489 |
+
),
|
490 |
+
$item
|
491 |
+
);
|
492 |
+
wprss_log( 'Post data filters applied', null, WPRSS_LOG_LEVEL_SYSTEM );
|
493 |
+
|
494 |
+
if ( defined('ICL_SITEPRESS_VERSION') )
|
495 |
+
@include_once( WP_PLUGIN_DIR . '/sitepress-multilingual-cms/inc/wpml-api.php' );
|
496 |
+
if ( defined('ICL_LANGUAGE_CODE') ) {
|
497 |
+
$_POST['icl_post_language'] = $language_code = ICL_LANGUAGE_CODE;
|
498 |
+
wprss_log_obj( 'WPML detected. Language code determined', $language_code, null, WPRSS_LOG_LEVEL_SYSTEM );
|
499 |
+
}
|
500 |
+
|
501 |
+
// Create and insert post object into the DB
|
502 |
+
$inserted_ID = wp_insert_post( $feed_item );
|
503 |
+
|
504 |
+
if ( !is_wp_error( $inserted_ID ) ) {
|
505 |
+
|
506 |
+
if ( is_object( $inserted_ID ) ) {
|
507 |
+
if ( isset( $inserted_ID['ID'] ) ) {
|
508 |
+
$inserted_ID = $inserted_ID['ID'];
|
509 |
+
}
|
510 |
+
elseif ( isset( $inserted_ID->ID ) ) {
|
511 |
+
$inserted_ID = $inserted_ID->ID;
|
512 |
+
}
|
513 |
+
}
|
514 |
+
|
515 |
+
// Increment the inserted items counter
|
516 |
+
$items_inserted++;
|
517 |
+
|
518 |
+
// Create and insert post meta into the DB
|
519 |
+
wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url );
|
520 |
+
|
521 |
+
// Remember newly added permalink
|
522 |
+
$existing_permalinks[] = $permalink;
|
523 |
+
wprss_log_obj( 'Item imported', $inserted_ID, null, WPRSS_LOG_LEVEL_INFO );
|
524 |
+
}
|
525 |
+
else {
|
526 |
+
update_post_meta( $source, 'wprss_error_last_import', 'An error occurred while inserting a feed item into the database.' );
|
527 |
+
wprss_log_obj( 'Failed to insert post', $feed_item, 'wprss_items_insert_post > wp_insert_post' );
|
528 |
+
}
|
529 |
+
}
|
530 |
+
// If the item is TRUE, then a hook function in the filter inserted the item.
|
531 |
+
// increment the inserted counter
|
532 |
+
elseif ( ( is_bool($item) && $item === TRUE ) || ( $still_update_count === TRUE && $item !== FALSE ) ) {
|
533 |
+
$items_inserted++;
|
534 |
+
}
|
535 |
+
}
|
536 |
+
else {
|
537 |
+
wprss_log( 'Item already exists and will be skipped', null, WPRSS_LOG_LEVEL_NOTICE );
|
538 |
+
}
|
539 |
+
|
540 |
+
wprss_log_obj( 'Finished importing item', $permalink, null, WPRSS_LOG_LEVEL_INFO );
|
541 |
+
}
|
542 |
+
|
543 |
+
update_post_meta( $feed_ID, 'wprss_last_update_items', $items_inserted );
|
544 |
+
wprss_log_obj( sprintf( 'Finished importing %1$d items for feed source', $items_inserted ), $feed_ID, null, WPRSS_LOG_LEVEL_INFO );
|
545 |
+
}
|
546 |
+
|
547 |
+
|
548 |
+
/**
|
549 |
+
* Inserts the appropriate post meta for feed items.
|
550 |
+
*
|
551 |
+
* Called from 'wprss_items_insert_post'
|
552 |
+
*
|
553 |
+
* @since 2.3
|
554 |
+
*/
|
555 |
+
function wprss_items_insert_post_meta( $inserted_ID, $item, $feed_ID, $permalink, $enclosure_url ) {
|
556 |
+
update_post_meta( $inserted_ID, 'wprss_item_permalink', $permalink );
|
557 |
+
update_post_meta( $inserted_ID, 'wprss_item_enclosure', $enclosure_url );
|
558 |
+
|
559 |
+
$author = $item->get_author();
|
560 |
+
if ( $author ) {
|
561 |
+
update_post_meta( $inserted_ID, 'wprss_item_author', $author->get_name() );
|
562 |
+
}
|
563 |
+
|
564 |
+
update_post_meta( $inserted_ID, 'wprss_feed_id', $feed_ID);
|
565 |
+
do_action( 'wprss_items_create_post_meta', $inserted_ID, $item, $feed_ID );
|
566 |
+
}
|
567 |
+
|
568 |
+
|
569 |
+
/**
|
570 |
+
* Returns the time limit for the importing of a single feed item.
|
571 |
+
* The value if filtered through 'wprss_item_import_time_limit'. The default value is WPRSS_ITEM_IMPORT_TIME_LIMIT.
|
572 |
+
*
|
573 |
+
* @since 4.6.6
|
574 |
+
* @return int The maximum amount of seconds allowed for a single feed item to import.
|
575 |
+
*/
|
576 |
+
function wprss_get_item_import_time_limit() {
|
577 |
+
return apply_filters( 'wprss_item_import_time_limit', WPRSS_ITEM_IMPORT_TIME_LIMIT );
|
578 |
+
}
|
579 |
+
|
580 |
+
/**
|
581 |
+
* Returns the time limit for a feed fetch operation.
|
582 |
+
* The value if filtered through 'wprss_feed_fetch_time_limit'. The default value is WPRSS_FEED_FETCH_TIME_LIMIT.
|
583 |
+
*
|
584 |
+
* @since 4.6.6
|
585 |
+
* @return int The maximum amount of seconds allowed for an RSS feed XML document to be fetched.
|
586 |
+
*/
|
587 |
+
function wprss_get_feed_fetch_time_limit() {
|
588 |
+
return apply_filters( 'wprss_feed_fetch_time_limit', WPRSS_FEED_FETCH_TIME_LIMIT );
|
589 |
+
}
|
590 |
+
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Fetches all feed items from all feed sources.
|
594 |
+
* Iteratively calls 'wprss_fetch_insert_single_feed_items' for all feed sources.
|
595 |
+
*
|
596 |
+
* This function is used by the cron job or the debugging functions to get all feeds from all feed sources
|
597 |
+
*
|
598 |
+
* @param $all If set to TRUE, the function will pull from all feed sources, regardless of their individual
|
599 |
+
* update interval. If set to FALSE, only feed sources using the global update system will be updated.
|
600 |
+
* (Optional) Default: TRUE.
|
601 |
+
* @since 3.0
|
602 |
+
*/
|
603 |
+
function wprss_fetch_insert_all_feed_items( $all = TRUE ) {
|
604 |
+
wprss_log( 'Importing from all sources...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM );
|
605 |
+
// Get all feed sources
|
606 |
+
$feed_sources = wprss_get_all_feed_sources();
|
607 |
+
|
608 |
+
if( $feed_sources->have_posts() ) {
|
609 |
+
// Start by getting one feed source, we will cycle through them one by one,
|
610 |
+
// fetching feed items and adding them to the database in each pass
|
611 |
+
while ( $feed_sources->have_posts() ) {
|
612 |
+
$feed_sources->the_post();
|
613 |
+
|
614 |
+
$interval = get_post_meta( get_the_ID(), 'wprss_update_interval', TRUE );
|
615 |
+
$using_global_interval = ( $interval === wprss_get_default_feed_source_update_interval() || $interval === '' );
|
616 |
+
|
617 |
+
// Check if fetching from all, or if feed source uses the global interval
|
618 |
+
if ( $all === TRUE || $using_global_interval ) {
|
619 |
+
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( get_the_ID() ) );
|
620 |
+
}
|
621 |
+
}
|
622 |
+
wp_reset_postdata(); // Restore the $post global to the current post in the main query
|
623 |
+
}
|
624 |
+
}
|
625 |
+
|
626 |
+
|
627 |
+
/**
|
628 |
+
* Runs the above function with parameter FALSE
|
629 |
+
*
|
630 |
+
* @since 3.9
|
631 |
+
*/
|
632 |
+
function wprss_fetch_insert_all_feed_items_from_cron() {
|
633 |
+
wprss_fetch_insert_all_feed_items( FALSE );
|
634 |
+
}
|
635 |
+
|
636 |
+
|
637 |
+
/**
|
638 |
+
* Shutdown function for detecting if the PHP script reaches the maximum execution time limit
|
639 |
+
* while importing a feed.
|
640 |
+
*
|
641 |
+
* @since 4.6.6
|
642 |
+
*/
|
643 |
+
function wprss_detect_exec_timeout() {
|
644 |
+
// Get last error
|
645 |
+
if ( $error = error_get_last() ){
|
646 |
+
// Check if it is an E_ERROR and if it is a max exec time limit error
|
647 |
+
if ( $error['type'] === E_ERROR && stripos( $error['message'], 'maximum execution' ) === 0 ) {
|
648 |
+
// If the importing process was running
|
649 |
+
if ( array_key_exists( 'wprss_importing_feed', $GLOBALS ) && $GLOBALS['wprss_importing_feed'] !== NULL ) {
|
650 |
+
// Get the ID of the feed that was importing
|
651 |
+
$feed_ID = $GLOBALS['wprss_importing_feed'];
|
652 |
+
// Perform clean up
|
653 |
+
wprss_flag_feed_as_idle( $feed_ID );
|
654 |
+
$msg = sprintf( __( 'The PHP script timed out while importing an item from this feed, after %d seconds.', WPRSS_TEXT_DOMAIN ), wprss_get_item_import_time_limit() );
|
655 |
+
update_post_meta( $feed_ID, 'wprss_error_last_import', $msg );
|
656 |
+
// Log the error
|
657 |
+
wprss_log( 'The PHP script timed out while importing feed #' . $feed_ID, NULL, WPRSS_LOG_LEVEL_ERROR );
|
658 |
+
}
|
659 |
+
}
|
660 |
+
}
|
661 |
}
|
includes/feed-processing.php
CHANGED
@@ -1,704 +1,704 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
define( 'WPRSS_TRANSIENT_NAME_IS_REIMPORTING', 'is_reimporting' );
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Feed processing related functions
|
7 |
-
*
|
8 |
-
* @package WPRSSAggregator
|
9 |
-
*/
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Returns whether or not the feed source will forcefully fetch the next fetch,
|
13 |
-
* ignoring whether or not it is paused or not.
|
14 |
-
*
|
15 |
-
* @param $source_id The ID of the feed soruce
|
16 |
-
* @return boolean
|
17 |
-
* @since 3.7
|
18 |
-
*/
|
19 |
-
function wprss_feed_source_force_next_fetch( $source_id ) {
|
20 |
-
$force = get_post_meta( $source_id, 'wprss_force_next_fetch', TRUE );
|
21 |
-
return ( $force !== '' || $force == '1' );
|
22 |
-
}
|
23 |
-
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Change the default feed cache recreation period to 2 hours
|
27 |
-
*
|
28 |
-
* Probably not needed since we are now disabling caching altogether
|
29 |
-
*
|
30 |
-
* @since 2.1
|
31 |
-
*/
|
32 |
-
function wprss_feed_cache_lifetime( $seconds ) {
|
33 |
-
return 1; // one second
|
34 |
-
}
|
35 |
-
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Disable caching of feeds in transients, we don't need it as we are storing them in the wp_posts table
|
39 |
-
*
|
40 |
-
* @since 3.0
|
41 |
-
*/
|
42 |
-
function wprss_do_not_cache_feeds( &$feed ) {
|
43 |
-
$feed->enable_cache( false );
|
44 |
-
}
|
45 |
-
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Parameters for query to get all feed sources
|
49 |
-
*
|
50 |
-
* @since 3.0
|
51 |
-
*/
|
52 |
-
function wprss_get_all_feed_sources() {
|
53 |
-
// Get all feed sources
|
54 |
-
$feed_sources = new WP_Query( apply_filters(
|
55 |
-
'wprss_get_all_feed_sources',
|
56 |
-
array(
|
57 |
-
'post_type' => 'wprss_feed',
|
58 |
-
'post_status' => 'publish',
|
59 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
60 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
61 |
-
'posts_per_page' => -1
|
62 |
-
)
|
63 |
-
) );
|
64 |
-
return $feed_sources;
|
65 |
-
}
|
66 |
-
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Returns all the feed items of a source.
|
70 |
-
*
|
71 |
-
* @since 3.8
|
72 |
-
*/
|
73 |
-
function wprss_get_feed_items_for_source( $source_id ) {
|
74 |
-
$args = apply_filters(
|
75 |
-
'wprss_get_feed_items_for_source_args',
|
76 |
-
array(
|
77 |
-
'post_type' => 'wprss_feed_item',
|
78 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
79 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
80 |
-
'posts_per_page'=> -1,
|
81 |
-
'orderby' => 'date',
|
82 |
-
'order' => 'DESC',
|
83 |
-
'meta_query' => array(
|
84 |
-
array(
|
85 |
-
'key' => 'wprss_feed_id',
|
86 |
-
'value' => $source_id,
|
87 |
-
'compare' => '=',
|
88 |
-
),
|
89 |
-
),
|
90 |
-
'suppress_filters' => 1
|
91 |
-
), $source_id
|
92 |
-
);
|
93 |
-
return new WP_Query( $args );
|
94 |
-
}
|
95 |
-
|
96 |
-
|
97 |
-
/**
|
98 |
-
* Parameters for query to get feed sources
|
99 |
-
*
|
100 |
-
* @since 3.0
|
101 |
-
*/
|
102 |
-
function wprss_get_feed_source() {
|
103 |
-
// Get all feed sources
|
104 |
-
$feed_sources = new WP_Query( apply_filters(
|
105 |
-
'wprss_get_all_feed_sources',
|
106 |
-
array(
|
107 |
-
'post_type' => 'wprss_feed',
|
108 |
-
'post_status' => 'publish',
|
109 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
110 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
111 |
-
'posts_per_page' => -1
|
112 |
-
)
|
113 |
-
) );
|
114 |
-
return $feed_sources;
|
115 |
-
}
|
116 |
-
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Database query to get existing permalinks
|
120 |
-
*
|
121 |
-
* @since 3.0
|
122 |
-
*/
|
123 |
-
function get_existing_permalinks( $feed_ID ) {
|
124 |
-
global $wpdb;
|
125 |
-
|
126 |
-
return $wpdb->get_col(
|
127 |
-
"SELECT q.`meta_value`
|
128 |
-
FROM {$wpdb->postmeta} AS p
|
129 |
-
JOIN {$wpdb->postmeta} AS q ON (q.`meta_key` = 'wprss_item_permalink' AND p.`post_id` = q.`post_id`)
|
130 |
-
WHERE p.`meta_key` = 'wprss_feed_id' AND p.`meta_value` = '{$feed_ID}'"
|
131 |
-
);
|
132 |
-
}
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Checks if a permalink exists.
|
136 |
-
*
|
137 |
-
* Untested!
|
138 |
-
*
|
139 |
-
* @param string $permalink The permalink, expected to be normalized.
|
140 |
-
* @return bool
|
141 |
-
*/
|
142 |
-
function wprss_permalink_exists( $permalink ) {
|
143 |
-
global $wpdb;
|
144 |
-
|
145 |
-
$wpdb->query(
|
146 |
-
$wpdb->prepare(
|
147 |
-
"SELECT *
|
148 |
-
FROM {$wpdb->postmeta}
|
149 |
-
WHERE `meta_value` = '{$permalink}'"
|
150 |
-
)
|
151 |
-
);
|
152 |
-
|
153 |
-
return $wpdb->num_rows > 0;
|
154 |
-
}
|
155 |
-
|
156 |
-
|
157 |
-
add_action( 'publish_wprss_feed', 'wprss_fetch_insert_feed_items', 10 );
|
158 |
-
/**
|
159 |
-
* Fetches feed items from source provided and inserts into db
|
160 |
-
*
|
161 |
-
* This function is used when inserting or untrashing a new feed source, it only gets feeds from that particular source
|
162 |
-
*
|
163 |
-
* @since 3.0
|
164 |
-
*/
|
165 |
-
function wprss_fetch_insert_feed_items( $post_id ) {
|
166 |
-
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
|
167 |
-
}
|
168 |
-
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Returns the image of the feed.
|
172 |
-
* The reason this function exists is for add-ons to be able to detect if the plugin core
|
173 |
-
* supports feed image functionality through a simple function_exists() call.
|
174 |
-
*
|
175 |
-
* @param $source_id The ID of the feed source
|
176 |
-
* @return string The link to the feed image
|
177 |
-
* @since 1.0
|
178 |
-
*/
|
179 |
-
function wprss_get_feed_image( $source_id ) {
|
180 |
-
return get_post_meta( $source_id, 'wprss_feed_image', true );
|
181 |
-
}
|
182 |
-
|
183 |
-
|
184 |
-
add_action( 'post_updated', 'wprss_updated_feed_source', 10, 3 );
|
185 |
-
/**
|
186 |
-
* This function is triggered just after a post is updated.
|
187 |
-
* It checks if the updated post is a feed source, and carries out any
|
188 |
-
* updating necassary.
|
189 |
-
*
|
190 |
-
* @since 3.3
|
191 |
-
*/
|
192 |
-
function wprss_updated_feed_source( $post_ID, $post_after, $post_before ) {
|
193 |
-
// Check if the post is a feed source and is published
|
194 |
-
|
195 |
-
if ( ( $post_after->post_type == 'wprss_feed' ) && ( $post_after->post_status == 'publish' ) ) {
|
196 |
-
|
197 |
-
if ( isset( $_POST['wprss_url'] ) && !empty( $_POST['wprss_url'] ) ) {
|
198 |
-
$url = $_POST['wprss_url'];
|
199 |
-
$feed = wprss_fetch_feed( $url );
|
200 |
-
if ( $feed !== NULL && !is_wp_error( $feed ) ) {
|
201 |
-
update_post_meta( $post_ID, 'wprss_site_url', $feed->get_permalink() );
|
202 |
-
update_post_meta( $post_ID, 'wprss_feed_image', $feed->get_image_url() );
|
203 |
-
}
|
204 |
-
}
|
205 |
-
|
206 |
-
|
207 |
-
if ( isset( $_POST['wprss_limit'] ) && !empty( $_POST['wprss_limit'] ) ) {
|
208 |
-
// Checking feed limit change
|
209 |
-
// Get the limit currently saved in db, and limit in POST request
|
210 |
-
//$limit = get_post_meta( $post_ID, 'wprss_limit', true );
|
211 |
-
$limit = $_POST['wprss_limit'];
|
212 |
-
// Get all feed items for this source
|
213 |
-
$feed_sources = new WP_Query(
|
214 |
-
array(
|
215 |
-
'post_type' => 'wprss_feed_item',
|
216 |
-
'post_status' => 'publish',
|
217 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
218 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
219 |
-
'posts_per_page' => -1,
|
220 |
-
'orderby' => 'date',
|
221 |
-
'order' => 'ASC',
|
222 |
-
'meta_query' => array(
|
223 |
-
array(
|
224 |
-
'key' => 'wprss_feed_id',
|
225 |
-
'value' => $post_ID,
|
226 |
-
'compare' => 'LIKE'
|
227 |
-
)
|
228 |
-
)
|
229 |
-
)
|
230 |
-
);
|
231 |
-
// If the limit is smaller than the number of found posts, delete the feed items
|
232 |
-
// and re-import, to ensure that most recent feed items are present.
|
233 |
-
$difference = intval( $feed_sources->post_count ) - intval( $limit );
|
234 |
-
if ( $difference > 0 ) {
|
235 |
-
// Loop and delete the excess feed items
|
236 |
-
while ( $feed_sources->have_posts() && $difference > 0 ) {
|
237 |
-
$feed_sources->the_post();
|
238 |
-
wp_delete_post( get_the_ID(), true );
|
239 |
-
$difference--;
|
240 |
-
}
|
241 |
-
}
|
242 |
-
}
|
243 |
-
}
|
244 |
-
}
|
245 |
-
|
246 |
-
|
247 |
-
add_action( 'added_post_meta', 'wprss_update_feed_meta', 10, 4 );
|
248 |
-
add_action( 'updated_post_meta', 'wprss_update_feed_meta', 10, 4 );
|
249 |
-
/**
|
250 |
-
* This function is run whenever a post is saved or updated.
|
251 |
-
*
|
252 |
-
* @since 3.4
|
253 |
-
*/
|
254 |
-
function wprss_update_feed_meta( $meta_id, $post_id, $meta_key, $meta_value ) {
|
255 |
-
$post = get_post( $post_id );
|
256 |
-
if ( $post !== NULL && $post->post_status === 'publish' && $post->post_type === 'wprss_feed' ) {
|
257 |
-
if ( $meta_key === 'wprss_url' )
|
258 |
-
wprss_change_fb_url( $post_id, $meta_value );
|
259 |
-
}
|
260 |
-
}
|
261 |
-
|
262 |
-
|
263 |
-
function wprss_change_fb_url( $post_id, $url ) {
|
264 |
-
# Check if url begins with a known facebook hostname.
|
265 |
-
if ( stripos( $url, 'http://facebook.com' ) === 0
|
266 |
-
|| stripos( $url, 'http://www.facebook.com' ) === 0
|
267 |
-
|| stripos( $url, 'https://facebook.com' ) === 0
|
268 |
-
|| stripos( $url, 'https://www.facebook.com' ) === 0
|
269 |
-
) {
|
270 |
-
# Generate the new URL to FB Graph
|
271 |
-
$com_index = stripos( $url, '.com' );
|
272 |
-
$fb_page = substr( $url, $com_index + 4 ); # 4 = length of ".com"
|
273 |
-
$fb_graph_url = 'http://graph.facebook.com' . $fb_page;
|
274 |
-
# Contact FB Graph and get data
|
275 |
-
$response = wp_remote_get( $fb_graph_url );
|
276 |
-
# If the repsonse successful and has a body
|
277 |
-
if ( !is_wp_error( $response ) && isset( $response['body'] ) ) {
|
278 |
-
# Parse the body as a JSON string
|
279 |
-
$json = json_decode( $response['body'], true );
|
280 |
-
# If an id is present ...
|
281 |
-
if ( isset( $json['id'] ) ) {
|
282 |
-
# Generate the final URL for this feed and update the post meta
|
283 |
-
$final_url = "http://www.facebook.com/feeds/page.php?format=rss20&id=" . $json['id'];
|
284 |
-
update_post_meta( $post_id, 'wprss_url', $final_url, $url );
|
285 |
-
}
|
286 |
-
}
|
287 |
-
}
|
288 |
-
}
|
289 |
-
|
290 |
-
|
291 |
-
add_action( 'trash_wprss_feed', 'wprss_delete_feed_items' ); // maybe use wp_trash_post action? wp_trash_wprss_feed
|
292 |
-
/**
|
293 |
-
* Delete feed items on trashing of corresponding feed source
|
294 |
-
*
|
295 |
-
* @since 2.0
|
296 |
-
*/
|
297 |
-
function wprss_delete_feed_items( $postid ) {
|
298 |
-
|
299 |
-
$args = array(
|
300 |
-
'post_type' => 'wprss_feed_item',
|
301 |
-
// Next 3 parameters for performance, see http://thomasgriffinmedia.com/blog/2012/10/optimize-wordpress-queries
|
302 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
303 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
304 |
-
'fields' => 'ids', // Returns post IDs only
|
305 |
-
'posts_per_page'=> -1,
|
306 |
-
'meta_query' => array(
|
307 |
-
array(
|
308 |
-
'key' => 'wprss_feed_id',
|
309 |
-
'value' => $postid,
|
310 |
-
'compare' => 'LIKE'
|
311 |
-
)
|
312 |
-
)
|
313 |
-
);
|
314 |
-
|
315 |
-
$feed_item_ids = get_posts( $args );
|
316 |
-
foreach( $feed_item_ids as $feed_item_id ) {
|
317 |
-
$purge = wp_delete_post( $feed_item_id, true ); // delete the feed item, skipping trash
|
318 |
-
}
|
319 |
-
wp_reset_postdata();
|
320 |
-
}
|
321 |
-
|
322 |
-
|
323 |
-
add_action( 'wprss_delete_all_feed_items_hook', 'wprss_delete_all_feed_items' );
|
324 |
-
/**
|
325 |
-
* Delete all feed items
|
326 |
-
*
|
327 |
-
* @since 3.0
|
328 |
-
*/
|
329 |
-
function wprss_delete_all_feed_items() {
|
330 |
-
wprss_log( sprintf( 'Deleting all feed items...'), __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM );
|
331 |
-
$args = array(
|
332 |
-
'post_type' => 'wprss_feed_item',
|
333 |
-
'cache_results' => false, // Disable caching, used for one-off queries
|
334 |
-
'no_found_rows' => true, // We don't need pagination, so disable it
|
335 |
-
'fields' => 'ids', // Returns post IDs only
|
336 |
-
'posts_per_page' => -1,
|
337 |
-
);
|
338 |
-
|
339 |
-
$feed_item_ids = get_posts( $args );
|
340 |
-
foreach( $feed_item_ids as $feed_item_id ) {
|
341 |
-
$purge = wp_delete_post( $feed_item_id, true ); // delete the feed item, skipping trash
|
342 |
-
}
|
343 |
-
wp_reset_postdata();
|
344 |
-
wprss_log( sprintf( 'All feed items deleted: %1$d', count($feed_item_ids) ), __FUNCTION__, WPRSS_LOG_LEVEL_INFO );
|
345 |
-
do_action('wprss_delete_all_feed_items_after', $feed_item_ids);
|
346 |
-
}
|
347 |
-
|
348 |
-
|
349 |
-
/**
|
350 |
-
* Marks the feed source as 'updating' (importing).
|
351 |
-
*
|
352 |
-
* @since 4.6.6
|
353 |
-
* @return int The time value set in the 'updating' meta field
|
354 |
-
*/
|
355 |
-
function wprss_flag_feed_as_updating( $feed_ID ) {
|
356 |
-
update_post_meta( $feed_ID, 'wprss_feed_is_updating', $start_time = time() );
|
357 |
-
return $start_time;
|
358 |
-
}
|
359 |
-
|
360 |
-
/**
|
361 |
-
* Marks the feed source as 'idle' (not importing).
|
362 |
-
*
|
363 |
-
* @since 4.6.6
|
364 |
-
*/
|
365 |
-
function wprss_flag_feed_as_idle( $feed_ID ) {
|
366 |
-
delete_post_meta( $feed_ID, 'wprss_feed_is_updating' );
|
367 |
-
}
|
368 |
-
|
369 |
-
|
370 |
-
/**
|
371 |
-
* Returns whether or not the feed source is updating.
|
372 |
-
*
|
373 |
-
* @param (string|int) The id of the feed source
|
374 |
-
* @return (bool) TRUE if the feed source is currently updating, FALSE otherwise.
|
375 |
-
*
|
376 |
-
*/
|
377 |
-
function wprss_is_feed_source_updating( $id ) {
|
378 |
-
// Get the 'updating' meta field
|
379 |
-
$is_updating_meta = get_post_meta( $id, 'wprss_feed_is_updating', TRUE );
|
380 |
-
|
381 |
-
// Check if the feed has the 'updating' meta field set
|
382 |
-
if ( $is_updating_meta === '' ) {
|
383 |
-
// If not, then the feed is not updating
|
384 |
-
return FALSE;
|
385 |
-
}
|
386 |
-
|
387 |
-
// Get the limit used for the feed
|
388 |
-
$limit = get_post_meta( $id, 'wprss_limit', true );
|
389 |
-
if ( $limit === '' || intval( $limit ) <= 0 ) {
|
390 |
-
$global_limit = wprss_get_general_setting('limit_feed_items_imported');
|
391 |
-
$limit = ( $global_limit === '' || intval( $global_limit ) <= 0 ) ? NULL : $global_limit;
|
392 |
-
}
|
393 |
-
|
394 |
-
// Calculate the allowed maximum time, based on the maximum number of items allowed to be
|
395 |
-
// imported from this source.
|
396 |
-
// If no limit is used, 60s (1min) is used.
|
397 |
-
$single_item_time_limit = wprss_get_item_import_time_limit();
|
398 |
-
$allowed_time = $limit === NULL ? 60 : $single_item_time_limit * intval( $limit );
|
399 |
-
|
400 |
-
// Calculate how many seconds have passed since the feed last signalled that it is updating
|
401 |
-
$diff = time() - $is_updating_meta;
|
402 |
-
|
403 |
-
// If the difference is greater than the allowed maximum amount of time, mark the feed as idle.
|
404 |
-
if ( $diff > $allowed_time ) {
|
405 |
-
wprss_flag_feed_as_idle( $id );
|
406 |
-
// Feed is not updating
|
407 |
-
return FALSE;
|
408 |
-
}
|
409 |
-
|
410 |
-
// Feed is updating
|
411 |
-
return TRUE;
|
412 |
-
}
|
413 |
-
|
414 |
-
|
415 |
-
/**
|
416 |
-
* Returns whether or not the feed source is deleting its feeed items.
|
417 |
-
*
|
418 |
-
* @param (string|int) The id of the feed source
|
419 |
-
* @return (bool) TRUE if the feed source is currently deleting its items, FALSE otherwise.
|
420 |
-
*
|
421 |
-
*/
|
422 |
-
function wprss_is_feed_source_deleting( $id ) {
|
423 |
-
$is_deleting_meta = get_post_meta( $id, 'wprss_feed_is_deleting_items', TRUE );
|
424 |
-
|
425 |
-
if ( $is_deleting_meta === '' ) {
|
426 |
-
return FALSE;
|
427 |
-
}
|
428 |
-
|
429 |
-
$diff = time() - $is_deleting_meta;
|
430 |
-
|
431 |
-
$items = wprss_get_feed_items_for_source( $id );
|
432 |
-
if ( $items->post_count == 0 || $diff > 300 ) {
|
433 |
-
delete_post_meta( $id, 'wprss_feed_is_deleting_items' );
|
434 |
-
return FALSE;
|
435 |
-
}
|
436 |
-
|
437 |
-
return TRUE;
|
438 |
-
}
|
439 |
-
|
440 |
-
|
441 |
-
/**
|
442 |
-
* Returns the given parameter as a string. Used in wprss_truncate_posts()
|
443 |
-
*
|
444 |
-
* @return string The given parameter as a string
|
445 |
-
* @since 3.5.1
|
446 |
-
*/
|
447 |
-
function wprss_return_as_string( $item ) {
|
448 |
-
return "'$item'";
|
449 |
-
}
|
450 |
-
|
451 |
-
|
452 |
-
/**
|
453 |
-
* Returns true if the feed item is older than the given timestamp,
|
454 |
-
* false otherwise;
|
455 |
-
*
|
456 |
-
* @since 3.8
|
457 |
-
*/
|
458 |
-
function wprss_is_feed_item_older_than( $id, $timestamp ) {
|
459 |
-
// GET THE DATE
|
460 |
-
$age = get_the_time( 'U', $id );
|
461 |
-
if ( $age === '' ) return FALSE;
|
462 |
-
// Calculate the age difference
|
463 |
-
$difference = $age - $timestamp;
|
464 |
-
// Return whether the difference is negative ( the age is smaller than the timestamp )
|
465 |
-
return ( $difference <= 0 );
|
466 |
-
}
|
467 |
-
|
468 |
-
|
469 |
-
/**
|
470 |
-
* Returns the maximum age setting for a feed source.
|
471 |
-
*
|
472 |
-
* @since 3.8
|
473 |
-
*/
|
474 |
-
function wprss_get_max_age_for_feed_source( $source_id ) {
|
475 |
-
$general_settings = get_option( 'wprss_settings_general' );
|
476 |
-
// Get the meta data for age for this feed source
|
477 |
-
$age_limit = trim( get_post_meta( $source_id, 'wprss_age_limit', TRUE ) );
|
478 |
-
$age_unit = get_post_meta( $source_id, 'wprss_age_unit', TRUE );
|
479 |
-
|
480 |
-
// If the meta does not exist, use the global settings
|
481 |
-
if( $age_limit === '' ) {
|
482 |
-
$age_limit = trim( wprss_get_general_setting( 'limit_feed_items_age' ) );
|
483 |
-
$age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
|
484 |
-
}
|
485 |
-
|
486 |
-
// If the age limit is an empty string, use no limit
|
487 |
-
if ( $age_limit === '' ) {
|
488 |
-
return FALSE;
|
489 |
-
}
|
490 |
-
|
491 |
-
// Return the timestamp of the max age date
|
492 |
-
return strtotime( "-$age_limit $age_unit" );
|
493 |
-
}
|
494 |
-
|
495 |
-
|
496 |
-
/**
|
497 |
-
* Delete old feed items from the database to avoid bloat.
|
498 |
-
* As of 3.8, it uses the new feed age system.
|
499 |
-
*
|
500 |
-
* @since 3.8
|
501 |
-
*/
|
502 |
-
function wprss_truncate_posts() {
|
503 |
-
$general_settings = get_option( 'wprss_settings_general' );
|
504 |
-
|
505 |
-
// Get all feed sources
|
506 |
-
$feed_sources = wprss_get_all_feed_sources();
|
507 |
-
|
508 |
-
|
509 |
-
if( $feed_sources->have_posts() ) {
|
510 |
-
|
511 |
-
// FOR EACH FEED SOURCE
|
512 |
-
while ( $feed_sources->have_posts() ) {
|
513 |
-
$feed_sources->the_post();
|
514 |
-
|
515 |
-
// Get the max age setting for this feed source
|
516 |
-
$max_age = wprss_get_max_age_for_feed_source( get_the_ID() );
|
517 |
-
|
518 |
-
// If the data is empty, do not delete
|
519 |
-
if ( $max_age !== FALSE ) {
|
520 |
-
|
521 |
-
// Get all feed items for this source
|
522 |
-
$feed_items = wprss_get_feed_items_for_source( get_the_ID() );
|
523 |
-
|
524 |
-
// FOR EACH FEED ITEM
|
525 |
-
if ( $feed_items-> have_posts() ) {
|
526 |
-
while ( $feed_items->have_posts() ) {
|
527 |
-
$feed_items->the_post();
|
528 |
-
// If the post is older than the maximum age
|
529 |
-
if ( wprss_is_feed_item_older_than( get_the_ID(), $max_age ) === TRUE ){
|
530 |
-
// Delete the post
|
531 |
-
wp_delete_post( get_the_ID(), true );
|
532 |
-
}
|
533 |
-
}
|
534 |
-
// Reset feed items query data
|
535 |
-
wp_reset_postdata();
|
536 |
-
}
|
537 |
-
|
538 |
-
}
|
539 |
-
}
|
540 |
-
// Reset feed sources query data
|
541 |
-
wp_reset_postdata();
|
542 |
-
}
|
543 |
-
|
544 |
-
// If the filter to use the fixed limit is enabled, call the old truncation function
|
545 |
-
if ( apply_filters( 'wprss_use_fixed_feed_limit', FALSE ) === TRUE && isset( $general_settings['limit_feed_items_db'] ) ) {
|
546 |
-
wprss_old_truncate_posts();
|
547 |
-
}
|
548 |
-
}
|
549 |
-
|
550 |
-
|
551 |
-
/**
|
552 |
-
* The old truncation function.
|
553 |
-
* This truncation method uses the deprecated fixed feed limit.
|
554 |
-
*
|
555 |
-
* @since 2.0
|
556 |
-
*/
|
557 |
-
function wprss_old_truncate_posts() {
|
558 |
-
global $wpdb;
|
559 |
-
$general_settings = get_option( 'wprss_settings_general' );
|
560 |
-
|
561 |
-
if ( $general_settings['limit_feed_items_db'] == 0 ) {
|
562 |
-
return;
|
563 |
-
}
|
564 |
-
|
565 |
-
// Set your threshold of max posts and post_type name
|
566 |
-
$threshold = $general_settings['limit_feed_items_db'];
|
567 |
-
$post_types = apply_filters( 'wprss_truncation_post_types', array( 'wprss_feed_item' ) );
|
568 |
-
$post_types_str = array_map( 'wprss_return_as_string', $post_types );
|
569 |
-
|
570 |
-
$post_type_list = implode( ',' , $post_types_str );
|
571 |
-
|
572 |
-
// Query post type
|
573 |
-
// $wpdb query allows me to select specific columns instead of grabbing the entire post object.
|
574 |
-
$query = "
|
575 |
-
SELECT ID, post_title FROM $wpdb->posts
|
576 |
-
WHERE post_type IN ($post_type_list)
|
577 |
-
AND post_status = 'publish'
|
578 |
-
ORDER BY post_modified DESC
|
579 |
-
";
|
580 |
-
|
581 |
-
$results = $wpdb->get_results( $query );
|
582 |
-
|
583 |
-
// Check if there are any results
|
584 |
-
$i = 0;
|
585 |
-
if ( count( $results ) ){
|
586 |
-
foreach ( $results as $post ) {
|
587 |
-
$i++;
|
588 |
-
|
589 |
-
// Skip any posts within our threshold
|
590 |
-
if ( $i <= $threshold )
|
591 |
-
continue;
|
592 |
-
|
593 |
-
// Let the WordPress API do the heavy lifting for cleaning up entire post trails
|
594 |
-
$purge = wp_delete_post( $post->ID, true );
|
595 |
-
}
|
596 |
-
}
|
597 |
-
}
|
598 |
-
|
599 |
-
|
600 |
-
add_filter( 'wprss_insert_post_item_conditionals', 'wprss_check_feed_item_date_on_import', 2, 3 );
|
601 |
-
/**
|
602 |
-
* When a feed item is imported, it's date is compared against the max age of it's feed source.
|
603 |
-
*
|
604 |
-
*
|
605 |
-
* @since 3.8
|
606 |
-
*/
|
607 |
-
function wprss_check_feed_item_date_on_import( $item, $source, $permalink ){
|
608 |
-
if ( $item === NULL ) return NULL;
|
609 |
-
|
610 |
-
// Get the age of the item and the max age setting for its feed source
|
611 |
-
$age = $item->get_date( 'U' );
|
612 |
-
$max_age = wprss_get_max_age_for_feed_source( $source );
|
613 |
-
|
614 |
-
// If the age is not a valid timestamp, and the max age setting is disabled, return the item
|
615 |
-
if ( $age === '' || $age === NULL || $max_age === FALSE || $max_age === NULL ) {
|
616 |
-
return $item;
|
617 |
-
}
|
618 |
-
|
619 |
-
// Calculate the age difference
|
620 |
-
$difference = $age - $max_age;
|
621 |
-
|
622 |
-
if ( $difference <= 0 ) {
|
623 |
-
return NULL;
|
624 |
-
} else {
|
625 |
-
return $item;
|
626 |
-
}
|
627 |
-
}
|
628 |
-
|
629 |
-
|
630 |
-
/**
|
631 |
-
* Deletes all imported feeds and re-imports everything
|
632 |
-
*
|
633 |
-
* @since 3.0
|
634 |
-
*/
|
635 |
-
function wprss_feed_reset() {
|
636 |
-
wp_schedule_single_event( time(), 'wprss_delete_all_feed_items_hook' );
|
637 |
-
set_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING, true );
|
638 |
-
}
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
function wprss_schedule_reimport_all($deleted_ids) {
|
643 |
-
if( !get_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING ) )
|
644 |
-
return;
|
645 |
-
|
646 |
-
wprss_log( 'Re-import scheduled...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM);
|
647 |
-
delete_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING );
|
648 |
-
wprss_fetch_insert_all_feed_items( TRUE );
|
649 |
-
}
|
650 |
-
add_action('wprss_delete_all_feed_items_after', 'wprss_schedule_reimport_all');
|
651 |
-
|
652 |
-
|
653 |
-
/**
|
654 |
-
* Deletes N oldest feed items for the given source
|
655 |
-
*
|
656 |
-
* @since 4.2
|
657 |
-
* @deprecated
|
658 |
-
*/
|
659 |
-
function wprss_delete_oldest_feed_items( $n, $source ) {
|
660 |
-
// If the source does not exist, do nothing
|
661 |
-
if ( get_post( $source ) == NULL ) return;
|
662 |
-
|
663 |
-
// Make sure $n is an integer
|
664 |
-
$n = intval($n);
|
665 |
-
|
666 |
-
// Do nothing if n is zero or negative
|
667 |
-
if ( $n <= 0 ) return;
|
668 |
-
|
669 |
-
// Get the feed items, as an array, not WP_Query.
|
670 |
-
// We will need to perform some array operations
|
671 |
-
$feed_items = wprss_get_feed_items_for_source( $source );
|
672 |
-
$feed_items = $feed_items->get_posts();
|
673 |
-
// Get number of feed items
|
674 |
-
$count = count( $feed_items );
|
675 |
-
|
676 |
-
// Index of first feed item to delete
|
677 |
-
$start = $count - $n;
|
678 |
-
// Cut the array of feed items to get the items to delete
|
679 |
-
$to_delete = array_slice( $feed_items, $start );
|
680 |
-
// log -- for now
|
681 |
-
foreach( $to_delete as $fi ) {
|
682 |
-
//wprss_log_obj( "To delete" , $fi->ID );
|
683 |
-
}
|
684 |
-
}
|
685 |
-
|
686 |
-
|
687 |
-
/**
|
688 |
-
* Deletes the required number of feed items for the given source,
|
689 |
-
* to keep the number of feed items below its limit.
|
690 |
-
*
|
691 |
-
* @since 4.2
|
692 |
-
* @deprecated
|
693 |
-
*/
|
694 |
-
function wprss_truncate_feed_items_for_source( $source ) {
|
695 |
-
// Get the limit setting
|
696 |
-
$limit = get_post_meta( $source, 'wprss_limit', true );
|
697 |
-
|
698 |
-
// Calculate the number of feed items to delete
|
699 |
-
$feed_items = wprss_get_feed_items_for_source( $source );
|
700 |
-
$n = intval($feed_items->found_posts) - intval($limit);
|
701 |
-
|
702 |
-
// Delete the feed items
|
703 |
-
wprss_delete_oldest_feed_items( $n, $source );
|
704 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
define( 'WPRSS_TRANSIENT_NAME_IS_REIMPORTING', 'is_reimporting' );
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Feed processing related functions
|
7 |
+
*
|
8 |
+
* @package WPRSSAggregator
|
9 |
+
*/
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Returns whether or not the feed source will forcefully fetch the next fetch,
|
13 |
+
* ignoring whether or not it is paused or not.
|
14 |
+
*
|
15 |
+
* @param $source_id The ID of the feed soruce
|
16 |
+
* @return boolean
|
17 |
+
* @since 3.7
|
18 |
+
*/
|
19 |
+
function wprss_feed_source_force_next_fetch( $source_id ) {
|
20 |
+
$force = get_post_meta( $source_id, 'wprss_force_next_fetch', TRUE );
|
21 |
+
return ( $force !== '' || $force == '1' );
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Change the default feed cache recreation period to 2 hours
|
27 |
+
*
|
28 |
+
* Probably not needed since we are now disabling caching altogether
|
29 |
+
*
|
30 |
+
* @since 2.1
|
31 |
+
*/
|
32 |
+
function wprss_feed_cache_lifetime( $seconds ) {
|
33 |
+
return 1; // one second
|
34 |
+
}
|
35 |
+
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Disable caching of feeds in transients, we don't need it as we are storing them in the wp_posts table
|
39 |
+
*
|
40 |
+
* @since 3.0
|
41 |
+
*/
|
42 |
+
function wprss_do_not_cache_feeds( &$feed ) {
|
43 |
+
$feed->enable_cache( false );
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Parameters for query to get all feed sources
|
49 |
+
*
|
50 |
+
* @since 3.0
|
51 |
+
*/
|
52 |
+
function wprss_get_all_feed_sources() {
|
53 |
+
// Get all feed sources
|
54 |
+
$feed_sources = new WP_Query( apply_filters(
|
55 |
+
'wprss_get_all_feed_sources',
|
56 |
+
array(
|
57 |
+
'post_type' => 'wprss_feed',
|
58 |
+
'post_status' => 'publish',
|
59 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
60 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
61 |
+
'posts_per_page' => -1
|
62 |
+
)
|
63 |
+
) );
|
64 |
+
return $feed_sources;
|
65 |
+
}
|
66 |
+
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Returns all the feed items of a source.
|
70 |
+
*
|
71 |
+
* @since 3.8
|
72 |
+
*/
|
73 |
+
function wprss_get_feed_items_for_source( $source_id ) {
|
74 |
+
$args = apply_filters(
|
75 |
+
'wprss_get_feed_items_for_source_args',
|
76 |
+
array(
|
77 |
+
'post_type' => 'wprss_feed_item',
|
78 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
79 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
80 |
+
'posts_per_page'=> -1,
|
81 |
+
'orderby' => 'date',
|
82 |
+
'order' => 'DESC',
|
83 |
+
'meta_query' => array(
|
84 |
+
array(
|
85 |
+
'key' => 'wprss_feed_id',
|
86 |
+
'value' => $source_id,
|
87 |
+
'compare' => '=',
|
88 |
+
),
|
89 |
+
),
|
90 |
+
'suppress_filters' => 1
|
91 |
+
), $source_id
|
92 |
+
);
|
93 |
+
return new WP_Query( $args );
|
94 |
+
}
|
95 |
+
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Parameters for query to get feed sources
|
99 |
+
*
|
100 |
+
* @since 3.0
|
101 |
+
*/
|
102 |
+
function wprss_get_feed_source() {
|
103 |
+
// Get all feed sources
|
104 |
+
$feed_sources = new WP_Query( apply_filters(
|
105 |
+
'wprss_get_all_feed_sources',
|
106 |
+
array(
|
107 |
+
'post_type' => 'wprss_feed',
|
108 |
+
'post_status' => 'publish',
|
109 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
110 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
111 |
+
'posts_per_page' => -1
|
112 |
+
)
|
113 |
+
) );
|
114 |
+
return $feed_sources;
|
115 |
+
}
|
116 |
+
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Database query to get existing permalinks
|
120 |
+
*
|
121 |
+
* @since 3.0
|
122 |
+
*/
|
123 |
+
function get_existing_permalinks( $feed_ID ) {
|
124 |
+
global $wpdb;
|
125 |
+
|
126 |
+
return $wpdb->get_col(
|
127 |
+
"SELECT q.`meta_value`
|
128 |
+
FROM {$wpdb->postmeta} AS p
|
129 |
+
JOIN {$wpdb->postmeta} AS q ON (q.`meta_key` = 'wprss_item_permalink' AND p.`post_id` = q.`post_id`)
|
130 |
+
WHERE p.`meta_key` = 'wprss_feed_id' AND p.`meta_value` = '{$feed_ID}'"
|
131 |
+
);
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Checks if a permalink exists.
|
136 |
+
*
|
137 |
+
* Untested!
|
138 |
+
*
|
139 |
+
* @param string $permalink The permalink, expected to be normalized.
|
140 |
+
* @return bool
|
141 |
+
*/
|
142 |
+
function wprss_permalink_exists( $permalink ) {
|
143 |
+
global $wpdb;
|
144 |
+
|
145 |
+
$wpdb->query(
|
146 |
+
$wpdb->prepare(
|
147 |
+
"SELECT *
|
148 |
+
FROM {$wpdb->postmeta}
|
149 |
+
WHERE `meta_value` = '{$permalink}'"
|
150 |
+
)
|
151 |
+
);
|
152 |
+
|
153 |
+
return $wpdb->num_rows > 0;
|
154 |
+
}
|
155 |
+
|
156 |
+
|
157 |
+
add_action( 'publish_wprss_feed', 'wprss_fetch_insert_feed_items', 10 );
|
158 |
+
/**
|
159 |
+
* Fetches feed items from source provided and inserts into db
|
160 |
+
*
|
161 |
+
* This function is used when inserting or untrashing a new feed source, it only gets feeds from that particular source
|
162 |
+
*
|
163 |
+
* @since 3.0
|
164 |
+
*/
|
165 |
+
function wprss_fetch_insert_feed_items( $post_id ) {
|
166 |
+
wp_schedule_single_event( time(), 'wprss_fetch_single_feed_hook', array( $post_id ) );
|
167 |
+
}
|
168 |
+
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Returns the image of the feed.
|
172 |
+
* The reason this function exists is for add-ons to be able to detect if the plugin core
|
173 |
+
* supports feed image functionality through a simple function_exists() call.
|
174 |
+
*
|
175 |
+
* @param $source_id The ID of the feed source
|
176 |
+
* @return string The link to the feed image
|
177 |
+
* @since 1.0
|
178 |
+
*/
|
179 |
+
function wprss_get_feed_image( $source_id ) {
|
180 |
+
return get_post_meta( $source_id, 'wprss_feed_image', true );
|
181 |
+
}
|
182 |
+
|
183 |
+
|
184 |
+
add_action( 'post_updated', 'wprss_updated_feed_source', 10, 3 );
|
185 |
+
/**
|
186 |
+
* This function is triggered just after a post is updated.
|
187 |
+
* It checks if the updated post is a feed source, and carries out any
|
188 |
+
* updating necassary.
|
189 |
+
*
|
190 |
+
* @since 3.3
|
191 |
+
*/
|
192 |
+
function wprss_updated_feed_source( $post_ID, $post_after, $post_before ) {
|
193 |
+
// Check if the post is a feed source and is published
|
194 |
+
|
195 |
+
if ( ( $post_after->post_type == 'wprss_feed' ) && ( $post_after->post_status == 'publish' ) ) {
|
196 |
+
|
197 |
+
if ( isset( $_POST['wprss_url'] ) && !empty( $_POST['wprss_url'] ) ) {
|
198 |
+
$url = $_POST['wprss_url'];
|
199 |
+
$feed = wprss_fetch_feed( $url );
|
200 |
+
if ( $feed !== NULL && !is_wp_error( $feed ) ) {
|
201 |
+
update_post_meta( $post_ID, 'wprss_site_url', $feed->get_permalink() );
|
202 |
+
update_post_meta( $post_ID, 'wprss_feed_image', $feed->get_image_url() );
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
|
207 |
+
if ( isset( $_POST['wprss_limit'] ) && !empty( $_POST['wprss_limit'] ) ) {
|
208 |
+
// Checking feed limit change
|
209 |
+
// Get the limit currently saved in db, and limit in POST request
|
210 |
+
//$limit = get_post_meta( $post_ID, 'wprss_limit', true );
|
211 |
+
$limit = $_POST['wprss_limit'];
|
212 |
+
// Get all feed items for this source
|
213 |
+
$feed_sources = new WP_Query(
|
214 |
+
array(
|
215 |
+
'post_type' => 'wprss_feed_item',
|
216 |
+
'post_status' => 'publish',
|
217 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
218 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
219 |
+
'posts_per_page' => -1,
|
220 |
+
'orderby' => 'date',
|
221 |
+
'order' => 'ASC',
|
222 |
+
'meta_query' => array(
|
223 |
+
array(
|
224 |
+
'key' => 'wprss_feed_id',
|
225 |
+
'value' => $post_ID,
|
226 |
+
'compare' => 'LIKE'
|
227 |
+
)
|
228 |
+
)
|
229 |
+
)
|
230 |
+
);
|
231 |
+
// If the limit is smaller than the number of found posts, delete the feed items
|
232 |
+
// and re-import, to ensure that most recent feed items are present.
|
233 |
+
$difference = intval( $feed_sources->post_count ) - intval( $limit );
|
234 |
+
if ( $difference > 0 ) {
|
235 |
+
// Loop and delete the excess feed items
|
236 |
+
while ( $feed_sources->have_posts() && $difference > 0 ) {
|
237 |
+
$feed_sources->the_post();
|
238 |
+
wp_delete_post( get_the_ID(), true );
|
239 |
+
$difference--;
|
240 |
+
}
|
241 |
+
}
|
242 |
+
}
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
|
247 |
+
add_action( 'added_post_meta', 'wprss_update_feed_meta', 10, 4 );
|
248 |
+
add_action( 'updated_post_meta', 'wprss_update_feed_meta', 10, 4 );
|
249 |
+
/**
|
250 |
+
* This function is run whenever a post is saved or updated.
|
251 |
+
*
|
252 |
+
* @since 3.4
|
253 |
+
*/
|
254 |
+
function wprss_update_feed_meta( $meta_id, $post_id, $meta_key, $meta_value ) {
|
255 |
+
$post = get_post( $post_id );
|
256 |
+
if ( $post !== NULL && $post->post_status === 'publish' && $post->post_type === 'wprss_feed' ) {
|
257 |
+
if ( $meta_key === 'wprss_url' )
|
258 |
+
wprss_change_fb_url( $post_id, $meta_value );
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
|
263 |
+
function wprss_change_fb_url( $post_id, $url ) {
|
264 |
+
# Check if url begins with a known facebook hostname.
|
265 |
+
if ( stripos( $url, 'http://facebook.com' ) === 0
|
266 |
+
|| stripos( $url, 'http://www.facebook.com' ) === 0
|
267 |
+
|| stripos( $url, 'https://facebook.com' ) === 0
|
268 |
+
|| stripos( $url, 'https://www.facebook.com' ) === 0
|
269 |
+
) {
|
270 |
+
# Generate the new URL to FB Graph
|
271 |
+
$com_index = stripos( $url, '.com' );
|
272 |
+
$fb_page = substr( $url, $com_index + 4 ); # 4 = length of ".com"
|
273 |
+
$fb_graph_url = 'http://graph.facebook.com' . $fb_page;
|
274 |
+
# Contact FB Graph and get data
|
275 |
+
$response = wp_remote_get( $fb_graph_url );
|
276 |
+
# If the repsonse successful and has a body
|
277 |
+
if ( !is_wp_error( $response ) && isset( $response['body'] ) ) {
|
278 |
+
# Parse the body as a JSON string
|
279 |
+
$json = json_decode( $response['body'], true );
|
280 |
+
# If an id is present ...
|
281 |
+
if ( isset( $json['id'] ) ) {
|
282 |
+
# Generate the final URL for this feed and update the post meta
|
283 |
+
$final_url = "http://www.facebook.com/feeds/page.php?format=rss20&id=" . $json['id'];
|
284 |
+
update_post_meta( $post_id, 'wprss_url', $final_url, $url );
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
|
291 |
+
add_action( 'trash_wprss_feed', 'wprss_delete_feed_items' ); // maybe use wp_trash_post action? wp_trash_wprss_feed
|
292 |
+
/**
|
293 |
+
* Delete feed items on trashing of corresponding feed source
|
294 |
+
*
|
295 |
+
* @since 2.0
|
296 |
+
*/
|
297 |
+
function wprss_delete_feed_items( $postid ) {
|
298 |
+
|
299 |
+
$args = array(
|
300 |
+
'post_type' => 'wprss_feed_item',
|
301 |
+
// Next 3 parameters for performance, see http://thomasgriffinmedia.com/blog/2012/10/optimize-wordpress-queries
|
302 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
303 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
304 |
+
'fields' => 'ids', // Returns post IDs only
|
305 |
+
'posts_per_page'=> -1,
|
306 |
+
'meta_query' => array(
|
307 |
+
array(
|
308 |
+
'key' => 'wprss_feed_id',
|
309 |
+
'value' => $postid,
|
310 |
+
'compare' => 'LIKE'
|
311 |
+
)
|
312 |
+
)
|
313 |
+
);
|
314 |
+
|
315 |
+
$feed_item_ids = get_posts( $args );
|
316 |
+
foreach( $feed_item_ids as $feed_item_id ) {
|
317 |
+
$purge = wp_delete_post( $feed_item_id, true ); // delete the feed item, skipping trash
|
318 |
+
}
|
319 |
+
wp_reset_postdata();
|
320 |
+
}
|
321 |
+
|
322 |
+
|
323 |
+
add_action( 'wprss_delete_all_feed_items_hook', 'wprss_delete_all_feed_items' );
|
324 |
+
/**
|
325 |
+
* Delete all feed items
|
326 |
+
*
|
327 |
+
* @since 3.0
|
328 |
+
*/
|
329 |
+
function wprss_delete_all_feed_items() {
|
330 |
+
wprss_log( sprintf( 'Deleting all feed items...'), __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM );
|
331 |
+
$args = array(
|
332 |
+
'post_type' => 'wprss_feed_item',
|
333 |
+
'cache_results' => false, // Disable caching, used for one-off queries
|
334 |
+
'no_found_rows' => true, // We don't need pagination, so disable it
|
335 |
+
'fields' => 'ids', // Returns post IDs only
|
336 |
+
'posts_per_page' => -1,
|
337 |
+
);
|
338 |
+
|
339 |
+
$feed_item_ids = get_posts( $args );
|
340 |
+
foreach( $feed_item_ids as $feed_item_id ) {
|
341 |
+
$purge = wp_delete_post( $feed_item_id, true ); // delete the feed item, skipping trash
|
342 |
+
}
|
343 |
+
wp_reset_postdata();
|
344 |
+
wprss_log( sprintf( 'All feed items deleted: %1$d', count($feed_item_ids) ), __FUNCTION__, WPRSS_LOG_LEVEL_INFO );
|
345 |
+
do_action('wprss_delete_all_feed_items_after', $feed_item_ids);
|
346 |
+
}
|
347 |
+
|
348 |
+
|
349 |
+
/**
|
350 |
+
* Marks the feed source as 'updating' (importing).
|
351 |
+
*
|
352 |
+
* @since 4.6.6
|
353 |
+
* @return int The time value set in the 'updating' meta field
|
354 |
+
*/
|
355 |
+
function wprss_flag_feed_as_updating( $feed_ID ) {
|
356 |
+
update_post_meta( $feed_ID, 'wprss_feed_is_updating', $start_time = time() );
|
357 |
+
return $start_time;
|
358 |
+
}
|
359 |
+
|
360 |
+
/**
|
361 |
+
* Marks the feed source as 'idle' (not importing).
|
362 |
+
*
|
363 |
+
* @since 4.6.6
|
364 |
+
*/
|
365 |
+
function wprss_flag_feed_as_idle( $feed_ID ) {
|
366 |
+
delete_post_meta( $feed_ID, 'wprss_feed_is_updating' );
|
367 |
+
}
|
368 |
+
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Returns whether or not the feed source is updating.
|
372 |
+
*
|
373 |
+
* @param (string|int) The id of the feed source
|
374 |
+
* @return (bool) TRUE if the feed source is currently updating, FALSE otherwise.
|
375 |
+
*
|
376 |
+
*/
|
377 |
+
function wprss_is_feed_source_updating( $id ) {
|
378 |
+
// Get the 'updating' meta field
|
379 |
+
$is_updating_meta = get_post_meta( $id, 'wprss_feed_is_updating', TRUE );
|
380 |
+
|
381 |
+
// Check if the feed has the 'updating' meta field set
|
382 |
+
if ( $is_updating_meta === '' ) {
|
383 |
+
// If not, then the feed is not updating
|
384 |
+
return FALSE;
|
385 |
+
}
|
386 |
+
|
387 |
+
// Get the limit used for the feed
|
388 |
+
$limit = get_post_meta( $id, 'wprss_limit', true );
|
389 |
+
if ( $limit === '' || intval( $limit ) <= 0 ) {
|
390 |
+
$global_limit = wprss_get_general_setting('limit_feed_items_imported');
|
391 |
+
$limit = ( $global_limit === '' || intval( $global_limit ) <= 0 ) ? NULL : $global_limit;
|
392 |
+
}
|
393 |
+
|
394 |
+
// Calculate the allowed maximum time, based on the maximum number of items allowed to be
|
395 |
+
// imported from this source.
|
396 |
+
// If no limit is used, 60s (1min) is used.
|
397 |
+
$single_item_time_limit = wprss_get_item_import_time_limit();
|
398 |
+
$allowed_time = $limit === NULL ? 60 : $single_item_time_limit * intval( $limit );
|
399 |
+
|
400 |
+
// Calculate how many seconds have passed since the feed last signalled that it is updating
|
401 |
+
$diff = time() - $is_updating_meta;
|
402 |
+
|
403 |
+
// If the difference is greater than the allowed maximum amount of time, mark the feed as idle.
|
404 |
+
if ( $diff > $allowed_time ) {
|
405 |
+
wprss_flag_feed_as_idle( $id );
|
406 |
+
// Feed is not updating
|
407 |
+
return FALSE;
|
408 |
+
}
|
409 |
+
|
410 |
+
// Feed is updating
|
411 |
+
return TRUE;
|
412 |
+
}
|
413 |
+
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Returns whether or not the feed source is deleting its feeed items.
|
417 |
+
*
|
418 |
+
* @param (string|int) The id of the feed source
|
419 |
+
* @return (bool) TRUE if the feed source is currently deleting its items, FALSE otherwise.
|
420 |
+
*
|
421 |
+
*/
|
422 |
+
function wprss_is_feed_source_deleting( $id ) {
|
423 |
+
$is_deleting_meta = get_post_meta( $id, 'wprss_feed_is_deleting_items', TRUE );
|
424 |
+
|
425 |
+
if ( $is_deleting_meta === '' ) {
|
426 |
+
return FALSE;
|
427 |
+
}
|
428 |
+
|
429 |
+
$diff = time() - $is_deleting_meta;
|
430 |
+
|
431 |
+
$items = wprss_get_feed_items_for_source( $id );
|
432 |
+
if ( $items->post_count == 0 || $diff > 300 ) {
|
433 |
+
delete_post_meta( $id, 'wprss_feed_is_deleting_items' );
|
434 |
+
return FALSE;
|
435 |
+
}
|
436 |
+
|
437 |
+
return TRUE;
|
438 |
+
}
|
439 |
+
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Returns the given parameter as a string. Used in wprss_truncate_posts()
|
443 |
+
*
|
444 |
+
* @return string The given parameter as a string
|
445 |
+
* @since 3.5.1
|
446 |
+
*/
|
447 |
+
function wprss_return_as_string( $item ) {
|
448 |
+
return "'$item'";
|
449 |
+
}
|
450 |
+
|
451 |
+
|
452 |
+
/**
|
453 |
+
* Returns true if the feed item is older than the given timestamp,
|
454 |
+
* false otherwise;
|
455 |
+
*
|
456 |
+
* @since 3.8
|
457 |
+
*/
|
458 |
+
function wprss_is_feed_item_older_than( $id, $timestamp ) {
|
459 |
+
// GET THE DATE
|
460 |
+
$age = get_the_time( 'U', $id );
|
461 |
+
if ( $age === '' ) return FALSE;
|
462 |
+
// Calculate the age difference
|
463 |
+
$difference = $age - $timestamp;
|
464 |
+
// Return whether the difference is negative ( the age is smaller than the timestamp )
|
465 |
+
return ( $difference <= 0 );
|
466 |
+
}
|
467 |
+
|
468 |
+
|
469 |
+
/**
|
470 |
+
* Returns the maximum age setting for a feed source.
|
471 |
+
*
|
472 |
+
* @since 3.8
|
473 |
+
*/
|
474 |
+
function wprss_get_max_age_for_feed_source( $source_id ) {
|
475 |
+
$general_settings = get_option( 'wprss_settings_general' );
|
476 |
+
// Get the meta data for age for this feed source
|
477 |
+
$age_limit = trim( get_post_meta( $source_id, 'wprss_age_limit', TRUE ) );
|
478 |
+
$age_unit = get_post_meta( $source_id, 'wprss_age_unit', TRUE );
|
479 |
+
|
480 |
+
// If the meta does not exist, use the global settings
|
481 |
+
if( $age_limit === '' ) {
|
482 |
+
$age_limit = trim( wprss_get_general_setting( 'limit_feed_items_age' ) );
|
483 |
+
$age_unit = wprss_get_general_setting( 'limit_feed_items_age_unit' );
|
484 |
+
}
|
485 |
+
|
486 |
+
// If the age limit is an empty string, use no limit
|
487 |
+
if ( $age_limit === '' ) {
|
488 |
+
return FALSE;
|
489 |
+
}
|
490 |
+
|
491 |
+
// Return the timestamp of the max age date
|
492 |
+
return strtotime( "-$age_limit $age_unit" );
|
493 |
+
}
|
494 |
+
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Delete old feed items from the database to avoid bloat.
|
498 |
+
* As of 3.8, it uses the new feed age system.
|
499 |
+
*
|
500 |
+
* @since 3.8
|
501 |
+
*/
|
502 |
+
function wprss_truncate_posts() {
|
503 |
+
$general_settings = get_option( 'wprss_settings_general' );
|
504 |
+
|
505 |
+
// Get all feed sources
|
506 |
+
$feed_sources = wprss_get_all_feed_sources();
|
507 |
+
|
508 |
+
|
509 |
+
if( $feed_sources->have_posts() ) {
|
510 |
+
|
511 |
+
// FOR EACH FEED SOURCE
|
512 |
+
while ( $feed_sources->have_posts() ) {
|
513 |
+
$feed_sources->the_post();
|
514 |
+
|
515 |
+
// Get the max age setting for this feed source
|
516 |
+
$max_age = wprss_get_max_age_for_feed_source( get_the_ID() );
|
517 |
+
|
518 |
+
// If the data is empty, do not delete
|
519 |
+
if ( $max_age !== FALSE ) {
|
520 |
+
|
521 |
+
// Get all feed items for this source
|
522 |
+
$feed_items = wprss_get_feed_items_for_source( get_the_ID() );
|
523 |
+
|
524 |
+
// FOR EACH FEED ITEM
|
525 |
+
if ( $feed_items-> have_posts() ) {
|
526 |
+
while ( $feed_items->have_posts() ) {
|
527 |
+
$feed_items->the_post();
|
528 |
+
// If the post is older than the maximum age
|
529 |
+
if ( wprss_is_feed_item_older_than( get_the_ID(), $max_age ) === TRUE ){
|
530 |
+
// Delete the post
|
531 |
+
wp_delete_post( get_the_ID(), true );
|
532 |
+
}
|
533 |
+
}
|
534 |
+
// Reset feed items query data
|
535 |
+
wp_reset_postdata();
|
536 |
+
}
|
537 |
+
|
538 |
+
}
|
539 |
+
}
|
540 |
+
// Reset feed sources query data
|
541 |
+
wp_reset_postdata();
|
542 |
+
}
|
543 |
+
|
544 |
+
// If the filter to use the fixed limit is enabled, call the old truncation function
|
545 |
+
if ( apply_filters( 'wprss_use_fixed_feed_limit', FALSE ) === TRUE && isset( $general_settings['limit_feed_items_db'] ) ) {
|
546 |
+
wprss_old_truncate_posts();
|
547 |
+
}
|
548 |
+
}
|
549 |
+
|
550 |
+
|
551 |
+
/**
|
552 |
+
* The old truncation function.
|
553 |
+
* This truncation method uses the deprecated fixed feed limit.
|
554 |
+
*
|
555 |
+
* @since 2.0
|
556 |
+
*/
|
557 |
+
function wprss_old_truncate_posts() {
|
558 |
+
global $wpdb;
|
559 |
+
$general_settings = get_option( 'wprss_settings_general' );
|
560 |
+
|
561 |
+
if ( $general_settings['limit_feed_items_db'] == 0 ) {
|
562 |
+
return;
|
563 |
+
}
|
564 |
+
|
565 |
+
// Set your threshold of max posts and post_type name
|
566 |
+
$threshold = $general_settings['limit_feed_items_db'];
|
567 |
+
$post_types = apply_filters( 'wprss_truncation_post_types', array( 'wprss_feed_item' ) );
|
568 |
+
$post_types_str = array_map( 'wprss_return_as_string', $post_types );
|
569 |
+
|
570 |
+
$post_type_list = implode( ',' , $post_types_str );
|
571 |
+
|
572 |
+
// Query post type
|
573 |
+
// $wpdb query allows me to select specific columns instead of grabbing the entire post object.
|
574 |
+
$query = "
|
575 |
+
SELECT ID, post_title FROM $wpdb->posts
|
576 |
+
WHERE post_type IN ($post_type_list)
|
577 |
+
AND post_status = 'publish'
|
578 |
+
ORDER BY post_modified DESC
|
579 |
+
";
|
580 |
+
|
581 |
+
$results = $wpdb->get_results( $query );
|
582 |
+
|
583 |
+
// Check if there are any results
|
584 |
+
$i = 0;
|
585 |
+
if ( count( $results ) ){
|
586 |
+
foreach ( $results as $post ) {
|
587 |
+
$i++;
|
588 |
+
|
589 |
+
// Skip any posts within our threshold
|
590 |
+
if ( $i <= $threshold )
|
591 |
+
continue;
|
592 |
+
|
593 |
+
// Let the WordPress API do the heavy lifting for cleaning up entire post trails
|
594 |
+
$purge = wp_delete_post( $post->ID, true );
|
595 |
+
}
|
596 |
+
}
|
597 |
+
}
|
598 |
+
|
599 |
+
|
600 |
+
add_filter( 'wprss_insert_post_item_conditionals', 'wprss_check_feed_item_date_on_import', 2, 3 );
|
601 |
+
/**
|
602 |
+
* When a feed item is imported, it's date is compared against the max age of it's feed source.
|
603 |
+
*
|
604 |
+
*
|
605 |
+
* @since 3.8
|
606 |
+
*/
|
607 |
+
function wprss_check_feed_item_date_on_import( $item, $source, $permalink ){
|
608 |
+
if ( $item === NULL ) return NULL;
|
609 |
+
|
610 |
+
// Get the age of the item and the max age setting for its feed source
|
611 |
+
$age = $item->get_date( 'U' );
|
612 |
+
$max_age = wprss_get_max_age_for_feed_source( $source );
|
613 |
+
|
614 |
+
// If the age is not a valid timestamp, and the max age setting is disabled, return the item
|
615 |
+
if ( $age === '' || $age === NULL || $max_age === FALSE || $max_age === NULL ) {
|
616 |
+
return $item;
|
617 |
+
}
|
618 |
+
|
619 |
+
// Calculate the age difference
|
620 |
+
$difference = $age - $max_age;
|
621 |
+
|
622 |
+
if ( $difference <= 0 ) {
|
623 |
+
return NULL;
|
624 |
+
} else {
|
625 |
+
return $item;
|
626 |
+
}
|
627 |
+
}
|
628 |
+
|
629 |
+
|
630 |
+
/**
|
631 |
+
* Deletes all imported feeds and re-imports everything
|
632 |
+
*
|
633 |
+
* @since 3.0
|
634 |
+
*/
|
635 |
+
function wprss_feed_reset() {
|
636 |
+
wp_schedule_single_event( time(), 'wprss_delete_all_feed_items_hook' );
|
637 |
+
set_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING, true );
|
638 |
+
}
|
639 |
+
|
640 |
+
|
641 |
+
|
642 |
+
function wprss_schedule_reimport_all($deleted_ids) {
|
643 |
+
if( !get_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING ) )
|
644 |
+
return;
|
645 |
+
|
646 |
+
wprss_log( 'Re-import scheduled...', __FUNCTION__, WPRSS_LOG_LEVEL_SYSTEM);
|
647 |
+
delete_transient( WPRSS_TRANSIENT_NAME_IS_REIMPORTING );
|
648 |
+
wprss_fetch_insert_all_feed_items( TRUE );
|
649 |
+
}
|
650 |
+
add_action('wprss_delete_all_feed_items_after', 'wprss_schedule_reimport_all');
|
651 |
+
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Deletes N oldest feed items for the given source
|
655 |
+
*
|
656 |
+
* @since 4.2
|
657 |
+
* @deprecated
|
658 |
+
*/
|
659 |
+
function wprss_delete_oldest_feed_items( $n, $source ) {
|
660 |
+
// If the source does not exist, do nothing
|
661 |
+
if ( get_post( $source ) == NULL ) return;
|
662 |
+
|
663 |
+
// Make sure $n is an integer
|
664 |
+
$n = intval($n);
|
665 |
+
|
666 |
+
// Do nothing if n is zero or negative
|
667 |
+
if ( $n <= 0 ) return;
|
668 |
+
|
669 |
+
// Get the feed items, as an array, not WP_Query.
|
670 |
+
// We will need to perform some array operations
|
671 |
+
$feed_items = wprss_get_feed_items_for_source( $source );
|
672 |
+
$feed_items = $feed_items->get_posts();
|
673 |
+
// Get number of feed items
|
674 |
+
$count = count( $feed_items );
|
675 |
+
|
676 |
+
// Index of first feed item to delete
|
677 |
+
$start = $count - $n;
|
678 |
+
// Cut the array of feed items to get the items to delete
|
679 |
+
$to_delete = array_slice( $feed_items, $start );
|
680 |
+
// log -- for now
|
681 |
+
foreach( $to_delete as $fi ) {
|
682 |
+
//wprss_log_obj( "To delete" , $fi->ID );
|
683 |
+
}
|
684 |
+
}
|
685 |
+
|
686 |
+
|
687 |
+
/**
|
688 |
+
* Deletes the required number of feed items for the given source,
|
689 |
+
* to keep the number of feed items below its limit.
|
690 |
+
*
|
691 |
+
* @since 4.2
|
692 |
+
* @deprecated
|
693 |
+
*/
|
694 |
+
function wprss_truncate_feed_items_for_source( $source ) {
|
695 |
+
// Get the limit setting
|
696 |
+
$limit = get_post_meta( $source, 'wprss_limit', true );
|
697 |
+
|
698 |
+
// Calculate the number of feed items to delete
|
699 |
+
$feed_items = wprss_get_feed_items_for_source( $source );
|
700 |
+
$n = intval($feed_items->found_posts) - intval($limit);
|
701 |
+
|
702 |
+
// Delete the feed items
|
703 |
+
wprss_delete_oldest_feed_items( $n, $source );
|
704 |
+
}
|
includes/feed-states.php
CHANGED
@@ -1,178 +1,178 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Functions relating to feed source states
|
4 |
-
*
|
5 |
-
* @package WPRSSAggregator
|
6 |
-
*/
|
7 |
-
|
8 |
-
|
9 |
-
add_action( 'admin_init', 'wprss_change_feed_state' );
|
10 |
-
/**
|
11 |
-
* Changes the state of a feed source, using POST data
|
12 |
-
*
|
13 |
-
* @since 3.7
|
14 |
-
*/
|
15 |
-
function wprss_change_feed_state() {
|
16 |
-
// If the id and state are in POST data
|
17 |
-
if ( isset( $_GET['wprss-feed-id'] ) ) {
|
18 |
-
// Get the id and state
|
19 |
-
$feed_ID = $_GET['wprss-feed-id'];
|
20 |
-
// Change the state
|
21 |
-
if ( wprss_is_feed_source_active( $feed_ID ) ) {
|
22 |
-
wprss_pause_feed_source( $feed_ID );
|
23 |
-
} else {
|
24 |
-
wprss_activate_feed_source( $feed_ID );
|
25 |
-
}
|
26 |
-
// Check for a redirect
|
27 |
-
if ( isset( $_GET['wprss-redirect'] ) && $_GET['wprss-redirect'] == '1' ) {
|
28 |
-
wp_redirect( admin_url( 'edit.php?post_type=wprss_feed', 301 ) );
|
29 |
-
exit();
|
30 |
-
}
|
31 |
-
}
|
32 |
-
}
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
add_action( 'admin_init', 'wprss_bulk_change_state', 2 );
|
38 |
-
/**
|
39 |
-
* Changes the state of feed sources selected from the table bulk actions.
|
40 |
-
*
|
41 |
-
* @since 4.1
|
42 |
-
*/
|
43 |
-
function wprss_bulk_change_state() {
|
44 |
-
// If the id and state are in POST data
|
45 |
-
if ( isset( $_GET['post_type'] ) && (isset( $_GET['action'] ) || isset( $_GET['action2'] )) && isset( $_GET['post'] ) ) {
|
46 |
-
// Get the action and post ids from GET request
|
47 |
-
$action = isset($_GET['action']) && $_GET['action'] !== '-1' ? $_GET['action'] : $_GET['action2'];
|
48 |
-
$post_ids = $_GET['post'];
|
49 |
-
|
50 |
-
// check the action
|
51 |
-
switch ( $action ) {
|
52 |
-
// Activate all feed sources in $post_ids
|
53 |
-
case 'activate':
|
54 |
-
foreach( $post_ids as $post_id ) {
|
55 |
-
wprss_activate_feed_source( $post_id );
|
56 |
-
}
|
57 |
-
// Set a transient to show the admin notice, after redirection
|
58 |
-
set_transient( 'wprss_notify_bulk_change_state', 'activated', 0 );
|
59 |
-
break;
|
60 |
-
|
61 |
-
// Pause all feed sources in $post_ids
|
62 |
-
case 'pause':
|
63 |
-
foreach( $post_ids as $post_id ) {
|
64 |
-
wprss_pause_feed_source( $post_id );
|
65 |
-
}
|
66 |
-
// Set a transient to show the admin notice, after redirection
|
67 |
-
set_transient( 'wprss_notify_bulk_change_state', 'paused', 0 );
|
68 |
-
break;
|
69 |
-
}
|
70 |
-
|
71 |
-
/* Note:
|
72 |
-
* Transients are used since bulk actions will, after processing, case a redirect to the same page.
|
73 |
-
* Thus, using add_action( 'all_admin_notices', ... ) will result in the notice appearing on the first request,
|
74 |
-
* and not be shown after redirection.
|
75 |
-
* The transient is set to show the notification AFTER redirection.
|
76 |
-
*/
|
77 |
-
}
|
78 |
-
}
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
add_action( 'admin_init', 'check_for_state_notice_after_redirect', 1 );
|
83 |
-
/**
|
84 |
-
* Checks if the 'wprss_notify_bulk_change_state' transient is set.
|
85 |
-
* If it is, it will show the appropriate admin notice
|
86 |
-
*
|
87 |
-
* @since 4.1
|
88 |
-
*/
|
89 |
-
function check_for_state_notice_after_redirect() {
|
90 |
-
$transient = get_transient( 'wprss_notify_bulk_change_state' );
|
91 |
-
if ( $transient !== FALSE ) {
|
92 |
-
switch ( $transient ) {
|
93 |
-
case 'activated': add_action( 'all_admin_notices', 'wprss_notify_feed_sources_activated' ); break;
|
94 |
-
case 'paused': add_action( 'all_admin_notices', 'wprss_notify_feed_sources_paused' ); break;
|
95 |
-
}
|
96 |
-
delete_transient( 'wprss_notify_bulk_change_state' );
|
97 |
-
}
|
98 |
-
}
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Shows an admin notice to notify that feed sources have been activated.
|
104 |
-
*
|
105 |
-
* @since 4.1
|
106 |
-
*/
|
107 |
-
function wprss_notify_feed_sources_activated() {
|
108 |
-
?>
|
109 |
-
<div class="updated">
|
110 |
-
<?php echo wpautop( __( 'The feed sources have been activated!', WPRSS_TEXT_DOMAIN ) ) ?>
|
111 |
-
</div>
|
112 |
-
<?php
|
113 |
-
}
|
114 |
-
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Shows an admin notice to notify that feed sources have been activated.
|
118 |
-
*
|
119 |
-
* @since 4.1
|
120 |
-
*/
|
121 |
-
function wprss_notify_feed_sources_paused() {
|
122 |
-
?>
|
123 |
-
<div class="updated">
|
124 |
-
<?php echo wpautop( __( 'The feed sources have been paused!!', WPRSS_TEXT_DOMAIN ) ) ?>
|
125 |
-
</div>
|
126 |
-
<?php
|
127 |
-
}
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Activates the feed source. Runs on a schedule.
|
136 |
-
*
|
137 |
-
* @param $feed_id The of of the wprss_feed
|
138 |
-
* @since 3.7
|
139 |
-
*/
|
140 |
-
function wprss_activate_feed_source( $feed_id ) {
|
141 |
-
update_post_meta( $feed_id, 'wprss_state', 'active' );
|
142 |
-
update_post_meta( $feed_id, 'wprss_activate_feed', '' );
|
143 |
-
|
144 |
-
// Add an action hook, so functions can be run when a feed source is activated
|
145 |
-
do_action( 'wprss_on_feed_source_activated', $feed_id );
|
146 |
-
}
|
147 |
-
|
148 |
-
|
149 |
-
/**
|
150 |
-
* Pauses the feed source. Runs on a schedule.
|
151 |
-
*
|
152 |
-
* @param $feed_id The of of the wprss_feed
|
153 |
-
* @since 3.7
|
154 |
-
*/
|
155 |
-
function wprss_pause_feed_source( $feed_id ) {
|
156 |
-
update_post_meta( $feed_id, 'wprss_state', 'paused' );
|
157 |
-
update_post_meta( $feed_id, 'wprss_pause_feed', '' );
|
158 |
-
|
159 |
-
// Add an action hook, so functions can be run when a feed source is paused
|
160 |
-
do_action( 'wprss_on_feed_source_paused', $feed_id );
|
161 |
-
}
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
/**
|
169 |
-
* Returns whether or not a feed source is active.
|
170 |
-
*
|
171 |
-
* @param $source_id The ID of the feed soruce
|
172 |
-
* @return boolean
|
173 |
-
* @since 3.7
|
174 |
-
*/
|
175 |
-
function wprss_is_feed_source_active( $source_id ) {
|
176 |
-
$state = get_post_meta( $source_id, 'wprss_state', TRUE );
|
177 |
-
return ( $state === '' || $state === 'active' );
|
178 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Functions relating to feed source states
|
4 |
+
*
|
5 |
+
* @package WPRSSAggregator
|
6 |
+
*/
|
7 |
+
|
8 |
+
|
9 |
+
add_action( 'admin_init', 'wprss_change_feed_state' );
|
10 |
+
/**
|
11 |
+
* Changes the state of a feed source, using POST data
|
12 |
+
*
|
13 |
+
* @since 3.7
|
14 |
+
*/
|
15 |
+
function wprss_change_feed_state() {
|
16 |
+
// If the id and state are in POST data
|
17 |
+
if ( isset( $_GET['wprss-feed-id'] ) ) {
|
18 |
+
// Get the id and state
|
19 |
+
$feed_ID = $_GET['wprss-feed-id'];
|
20 |
+
// Change the state
|
21 |
+
if ( wprss_is_feed_source_active( $feed_ID ) ) {
|
22 |
+
wprss_pause_feed_source( $feed_ID );
|
23 |
+
} else {
|
24 |
+
wprss_activate_feed_source( $feed_ID );
|
25 |
+
}
|
26 |
+
// Check for a redirect
|
27 |
+
if ( isset( $_GET['wprss-redirect'] ) && $_GET['wprss-redirect'] == '1' ) {
|
28 |
+
wp_redirect( admin_url( 'edit.php?post_type=wprss_feed', 301 ) );
|
29 |
+
exit();
|
30 |
+
}
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
|
36 |
+
|
37 |
+
add_action( 'admin_init', 'wprss_bulk_change_state', 2 );
|
38 |
+
/**
|
39 |
+
* Changes the state of feed sources selected from the table bulk actions.
|
40 |
+
*
|
41 |
+
* @since 4.1
|
42 |
+
*/
|
43 |
+
function wprss_bulk_change_state() {
|
44 |
+
// If the id and state are in POST data
|
45 |
+
if ( isset( $_GET['post_type'] ) && (isset( $_GET['action'] ) || isset( $_GET['action2'] )) && isset( $_GET['post'] ) ) {
|
46 |
+
// Get the action and post ids from GET request
|
47 |
+
$action = isset($_GET['action']) && $_GET['action'] !== '-1' ? $_GET['action'] : $_GET['action2'];
|
48 |
+
$post_ids = $_GET['post'];
|
49 |
+
|
50 |
+
// check the action
|
51 |
+
switch ( $action ) {
|
52 |
+
// Activate all feed sources in $post_ids
|
53 |
+
case 'activate':
|
54 |
+
foreach( $post_ids as $post_id ) {
|
55 |
+
wprss_activate_feed_source( $post_id );
|
56 |
+
}
|
57 |
+
// Set a transient to show the admin notice, after redirection
|
58 |
+
set_transient( 'wprss_notify_bulk_change_state', 'activated', 0 );
|
59 |
+
break;
|
60 |
+
|
61 |
+
// Pause all feed sources in $post_ids
|
62 |
+
case 'pause':
|
63 |
+
foreach( $post_ids as $post_id ) {
|
64 |
+
wprss_pause_feed_source( $post_id );
|
65 |
+
}
|
66 |
+
// Set a transient to show the admin notice, after redirection
|
67 |
+
set_transient( 'wprss_notify_bulk_change_state', 'paused', 0 );
|
68 |
+
break;
|
69 |
+
}
|
70 |
+
|
71 |
+
/* Note:
|
72 |
+
* Transients are used since bulk actions will, after processing, case a redirect to the same page.
|
73 |
+
* Thus, using add_action( 'all_admin_notices', ... ) will result in the notice appearing on the first request,
|
74 |
+
* and not be shown after redirection.
|
75 |
+
* The transient is set to show the notification AFTER redirection.
|
76 |
+
*/
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
|
81 |
+
|
82 |
+
add_action( 'admin_init', 'check_for_state_notice_after_redirect', 1 );
|
83 |
+
/**
|
84 |
+
* Checks if the 'wprss_notify_bulk_change_state' transient is set.
|
85 |
+
* If it is, it will show the appropriate admin notice
|
86 |
+
*
|
87 |
+
* @since 4.1
|
88 |
+
*/
|
89 |
+
function check_for_state_notice_after_redirect() {
|
90 |
+
$transient = get_transient( 'wprss_notify_bulk_change_state' );
|
91 |
+
if ( $transient !== FALSE ) {
|
92 |
+
switch ( $transient ) {
|
93 |
+
case 'activated': add_action( 'all_admin_notices', 'wprss_notify_feed_sources_activated' ); break;
|
94 |
+
case 'paused': add_action( 'all_admin_notices', 'wprss_notify_feed_sources_paused' ); break;
|
95 |
+
}
|
96 |
+
delete_transient( 'wprss_notify_bulk_change_state' );
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Shows an admin notice to notify that feed sources have been activated.
|
104 |
+
*
|
105 |
+
* @since 4.1
|
106 |
+
*/
|
107 |
+
function wprss_notify_feed_sources_activated() {
|
108 |
+
?>
|
109 |
+
<div class="updated">
|
110 |
+
<?php echo wpautop( __( 'The feed sources have been activated!', WPRSS_TEXT_DOMAIN ) ) ?>
|
111 |
+
</div>
|
112 |
+
<?php
|
113 |
+
}
|
114 |
+
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Shows an admin notice to notify that feed sources have been activated.
|
118 |
+
*
|
119 |
+
* @since 4.1
|
120 |
+
*/
|
121 |
+
function wprss_notify_feed_sources_paused() {
|
122 |
+
?>
|
123 |
+
<div class="updated">
|
124 |
+
<?php echo wpautop( __( 'The feed sources have been paused!!', WPRSS_TEXT_DOMAIN ) ) ?>
|
125 |
+
</div>
|
126 |
+
<?php
|
127 |
+
}
|
128 |
+
|
129 |
+
|
130 |
+
|
131 |
+
|
132 |
+
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Activates the feed source. Runs on a schedule.
|
136 |
+
*
|
137 |
+
* @param $feed_id The of of the wprss_feed
|
138 |
+
* @since 3.7
|
139 |
+
*/
|
140 |
+
function wprss_activate_feed_source( $feed_id ) {
|
141 |
+
update_post_meta( $feed_id, 'wprss_state', 'active' );
|
142 |
+
update_post_meta( $feed_id, 'wprss_activate_feed', '' );
|
143 |
+
|
144 |
+
// Add an action hook, so functions can be run when a feed source is activated
|
145 |
+
do_action( 'wprss_on_feed_source_activated', $feed_id );
|
146 |
+
}
|
147 |
+
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Pauses the feed source. Runs on a schedule.
|
151 |
+
*
|
152 |
+
* @param $feed_id The of of the wprss_feed
|
153 |
+
* @since 3.7
|
154 |
+
*/
|
155 |
+
function wprss_pause_feed_source( $feed_id ) {
|
156 |
+
update_post_meta( $feed_id, 'wprss_state', 'paused' );
|
157 |
+
update_post_meta( $feed_id, 'wprss_pause_feed', '' );
|
158 |
+
|
159 |
+
// Add an action hook, so functions can be run when a feed source is paused
|
160 |
+
do_action( 'wprss_on_feed_source_paused', $feed_id );
|
161 |
+
}
|
162 |
+
|
163 |
+
|
164 |
+
|
165 |
+
|
166 |
+
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Returns whether or not a feed source is active.
|
170 |
+
*
|
171 |
+
* @param $source_id The ID of the feed soruce
|
172 |
+
* @return boolean
|
173 |
+
* @since 3.7
|
174 |
+
*/
|
175 |
+
function wprss_is_feed_source_active( $source_id ) {
|
176 |
+
$state = get_post_meta( $source_id, 'wprss_state', TRUE );
|
177 |
+
return ( $state === '' || $state === 'active' );
|
178 |
}
|
includes/image-caching.php
CHANGED
@@ -1,290 +1,290 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class WPRSS_Image_Cache {
|
4 |
-
|
5 |
-
protected $_download_request_timeout = 300;
|
6 |
-
|
7 |
-
protected $_image_class_name = 'WPRSS_Image_Cache_Image';
|
8 |
-
protected $_images = array();
|
9 |
-
|
10 |
-
public function __construct() {
|
11 |
-
}
|
12 |
-
|
13 |
-
public function set_image_class_name( $class_name ) {
|
14 |
-
$this->_image_class_name = $class_name;
|
15 |
-
return $this;
|
16 |
-
}
|
17 |
-
|
18 |
-
public function get_image_class_name() {
|
19 |
-
return trim($this->_image_class_name);
|
20 |
-
}
|
21 |
-
|
22 |
-
public function set_download_request_timeout( $timeout ) {
|
23 |
-
$this->_download_request_timeout = intval( $timeout );
|
24 |
-
return $this;
|
25 |
-
}
|
26 |
-
|
27 |
-
public function get_download_request_timeout() {
|
28 |
-
return $this->_download_request_timeout;
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* @param string $url
|
33 |
-
* @return \WPRSS_Image_Cache_Image
|
34 |
-
* @throws Exception If class invalid, or not found
|
35 |
-
*/
|
36 |
-
public function get_new_image( $url = null ) {
|
37 |
-
$error_caption = 'Could not create new cache image';
|
38 |
-
$class_name = $this->get_image_class_name();
|
39 |
-
if ( empty( $class_name ) ) throw new Exception( sprintf( '%1$s: class name must not be empty' ) );
|
40 |
-
if ( !class_exists( $class_name ) ) throw new Exception( sprintf( '%1$s: class "%2$s" does not exist', $class_name ) );
|
41 |
-
|
42 |
-
$image = new $class_name();
|
43 |
-
$this->_prepare_image( $image );
|
44 |
-
/* @var $image WPRSS_Image_Cache_Image */
|
45 |
-
if ( !is_null( $url ) ) $image->set_url( $url );
|
46 |
-
|
47 |
-
return $image;
|
48 |
-
}
|
49 |
-
|
50 |
-
/**
|
51 |
-
*
|
52 |
-
* @param WPRSS_Image_Cache_Image $image
|
53 |
-
*/
|
54 |
-
protected function _prepare_image( $image ) {
|
55 |
-
$image->set_download_request_timeout( $this->get_download_request_timeout() );
|
56 |
-
}
|
57 |
-
|
58 |
-
public function get_images( $url = null ) {
|
59 |
-
if ( is_null( $url ) ) return $this->_images;
|
60 |
-
|
61 |
-
// Gotta cache one
|
62 |
-
if ( !isset( $this->_images[ $url ] ) ) {
|
63 |
-
try {
|
64 |
-
$image = $this->_download_image($url);
|
65 |
-
} catch ( Exception $e ) {
|
66 |
-
return new WP_Error( 'image_cache_cannot_download', $e->getMessage() );
|
67 |
-
}
|
68 |
-
|
69 |
-
$this->_images[ $url ] = $image;
|
70 |
-
}
|
71 |
-
|
72 |
-
return $this->_images[ $url ];
|
73 |
-
}
|
74 |
-
|
75 |
-
public function purge() {
|
76 |
-
$image_class_name = $this->get_image_class_name();
|
77 |
-
foreach( $this->get_images() as $_url => $_image ) {
|
78 |
-
/* @var $_image WPRSS_Image_Cache_Image */
|
79 |
-
if ( is_a( $_image, $image_class_name ) )
|
80 |
-
$_image->delete();
|
81 |
-
}
|
82 |
-
|
83 |
-
$this->_images = array();
|
84 |
-
return $this;
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* @param string $url
|
89 |
-
* @return WPRSS_Image_Cache_Image
|
90 |
-
*/
|
91 |
-
protected function _download_image( $url ) {
|
92 |
-
$image = $this->get_new_image( $url );
|
93 |
-
$image->download();
|
94 |
-
|
95 |
-
return $image;
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
class WPRSS_Image_Cache_Image {
|
100 |
-
|
101 |
-
protected $_url;
|
102 |
-
protected $_local_path;
|
103 |
-
protected $_unique_name;
|
104 |
-
protected $_size;
|
105 |
-
protected $_download_request_timeout;
|
106 |
-
protected $_is_attempted;
|
107 |
-
protected $_is_fall_back_to_unsecure;
|
108 |
-
|
109 |
-
public function __construct( $data = null ) {
|
110 |
-
$this->reset();
|
111 |
-
|
112 |
-
if ( is_string( $data ) && !empty( $data ) )
|
113 |
-
$this->_set_url( $data );
|
114 |
-
}
|
115 |
-
|
116 |
-
public function reset() {
|
117 |
-
$this->_url = null;
|
118 |
-
$this->_local_path = null;
|
119 |
-
$this->_unique_name = null;
|
120 |
-
$this->_size = null;
|
121 |
-
$this->_download_request_timeout = 300;
|
122 |
-
$this->_is_attempted = false;
|
123 |
-
$this->_is_fall_back_to_unsecure = true;
|
124 |
-
|
125 |
-
return $this;
|
126 |
-
}
|
127 |
-
|
128 |
-
protected function _set_url( $url ) {
|
129 |
-
$this->_url = $url;
|
130 |
-
return $this;
|
131 |
-
}
|
132 |
-
|
133 |
-
public function set_url( $url ) {
|
134 |
-
$this->reset();
|
135 |
-
$this->_set_url($url);
|
136 |
-
|
137 |
-
return $this;
|
138 |
-
}
|
139 |
-
|
140 |
-
public function get_url() {
|
141 |
-
return $this->_url;
|
142 |
-
}
|
143 |
-
|
144 |
-
public function has_url() {
|
145 |
-
return isset( $this->_url );
|
146 |
-
}
|
147 |
-
|
148 |
-
protected function _set_local_path( $path ) {
|
149 |
-
$this->_local_path = $path;
|
150 |
-
return $this;
|
151 |
-
}
|
152 |
-
|
153 |
-
public function get_local_path() {
|
154 |
-
return $this->_local_path;
|
155 |
-
}
|
156 |
-
|
157 |
-
public function has_local_path() {
|
158 |
-
return isset( $this->_local_path );
|
159 |
-
}
|
160 |
-
|
161 |
-
public function set_download_request_timeout( $timeout ) {
|
162 |
-
$this->_download_request_timeout = intval( $timeout );
|
163 |
-
return $this;
|
164 |
-
}
|
165 |
-
|
166 |
-
public function get_download_request_timeout() {
|
167 |
-
return $this->_download_request_timeout;
|
168 |
-
}
|
169 |
-
|
170 |
-
protected function _is_attempted( $is_attempted = null ) {
|
171 |
-
if ( is_null( $is_attempted ) )
|
172 |
-
return (bool)$this->_is_attempted;
|
173 |
-
|
174 |
-
$this->_is_attempted = (bool) $is_attempted;
|
175 |
-
return $this;
|
176 |
-
}
|
177 |
-
|
178 |
-
public function is_attempted() {
|
179 |
-
return $this->_is_attempted();
|
180 |
-
}
|
181 |
-
|
182 |
-
public function is_fall_back_to_unsecure( $is_fall_back = null ) {
|
183 |
-
if ( is_null( $is_fall_back ) )
|
184 |
-
return (bool) $this->_is_fall_back_to_unsecure;
|
185 |
-
|
186 |
-
$this->_is_fall_back_to_unsecure = (bool) $is_fall_back;
|
187 |
-
return $this;
|
188 |
-
}
|
189 |
-
|
190 |
-
public function download() {
|
191 |
-
$error_caption = 'Could not download image';
|
192 |
-
if ( !$this->has_url() ) throw new Exception ( sprintf( '%1$s: a URL must be supplied' ) );
|
193 |
-
|
194 |
-
// Getting file download lib
|
195 |
-
$file_lib_path = ABSPATH . 'wp-admin/includes/file.php';
|
196 |
-
if ( !is_readable( $file_lib_path ) ) throw new Exception( sprintf( '%1$s: the file library cannot be read from %2$s', $error_caption, $file_lib_path ) );
|
197 |
-
require_once( $file_lib_path );
|
198 |
-
|
199 |
-
// Downloading the image
|
200 |
-
$url = $this->get_url();
|
201 |
-
$timeout = $this->get_download_request_timeout();
|
202 |
-
$tmp_path = $this->_download( $url, $timeout );
|
203 |
-
if ( is_wp_error( $tmp_path ) ) throw new Exception ( sprintf( '%1$s: %2$s', $error_caption, $tmp_path->get_error_message() ) );
|
204 |
-
// wprss_log( sprintf( 'Image saved to "%1$s"', $tmp_path ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
205 |
-
$this->_set_local_path( $tmp_path );
|
206 |
-
|
207 |
-
return $this->get_local_path();
|
208 |
-
}
|
209 |
-
|
210 |
-
protected function _download( $url, $timeout ) {
|
211 |
-
// wprss_log( sprintf( 'Downloading from "%1$s"', $url ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
212 |
-
$tmp_path = download_url( $url, $timeout );
|
213 |
-
if ( is_wp_error( $tmp_path ) ) {
|
214 |
-
$https = 'https';
|
215 |
-
if ( $this->is_fall_back_to_unsecure() && (stripos( $url, $https ) === 0) ) {
|
216 |
-
$url = 'http' . substr( $url, strlen( $https ) );
|
217 |
-
// wprss_log( sprintf( 'Downloading from "%1$s"', $url ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
218 |
-
$tmp_path = $this->_download( $url, $timeout );
|
219 |
-
}
|
220 |
-
}
|
221 |
-
|
222 |
-
return $tmp_path;
|
223 |
-
}
|
224 |
-
|
225 |
-
public function delete() {
|
226 |
-
if ( $path = $this->get_local_path() )
|
227 |
-
unlink( $path );
|
228 |
-
|
229 |
-
return $this;
|
230 |
-
}
|
231 |
-
|
232 |
-
public function get_unique_name() {
|
233 |
-
if( !isset($this->_unique_name) ) {
|
234 |
-
$url = $this->get_url();
|
235 |
-
// Extract filename from url for title (ignoring query string)
|
236 |
-
// One of more character that is not a '?', followed by an image extension
|
237 |
-
preg_match( '/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $url, $matches );
|
238 |
-
$url_filename = basename( urldecode( $matches[0] ) );
|
239 |
-
// Check for extension. If not found, use last component of the URL
|
240 |
-
if ( !isset( $matches[1] ) ) {
|
241 |
-
$matches = array();
|
242 |
-
// Get the path to the image, without the domain. ex. /news/132456/image
|
243 |
-
preg_match_all( '/[^:]+:\/\/[^\/]+\/(.+)/', $url, $matches );
|
244 |
-
// If found
|
245 |
-
if ( isset( $matches[1][0] ) ) {
|
246 |
-
// Replace all '/' into '.' for the filename
|
247 |
-
$url_filename = str_replace( '/', '-', $matches[1][0] );
|
248 |
-
}
|
249 |
-
// If not found
|
250 |
-
else {
|
251 |
-
// Use a random string as a fallback, with length of 16 characters
|
252 |
-
$url_filename = wprss_ftp_generate_random_string( 16 );
|
253 |
-
}
|
254 |
-
}
|
255 |
-
// determine file type (ext and mime/type)
|
256 |
-
$url_type = wp_check_filetype($url_filename);
|
257 |
-
}
|
258 |
-
|
259 |
-
return $this->_unique_name;
|
260 |
-
}
|
261 |
-
|
262 |
-
public function get_size() {
|
263 |
-
if ( !isset( $this->_size ) ) {
|
264 |
-
$error_caption = 'Could not get image size';
|
265 |
-
if ( !$this->is_readable() ) throw new Exception( sprintf( '%1$s: image file is not readable' ) );
|
266 |
-
$path = $this->get_local_path();
|
267 |
-
|
268 |
-
// Trying simplest way
|
269 |
-
if ( $size = getimagesize( $path ) )
|
270 |
-
$this->_size = array( 0 => $size[0], 1 => $size[1] );
|
271 |
-
|
272 |
-
wprss_log( sprintf( 'Tried `getimagesize()`: %1$s', empty($this->_size) ? 'failure' : 'success' ), __METHOD__, WPRSS_LOG_LEVEL_SYSTEM );
|
273 |
-
|
274 |
-
if( !$this->_size && function_exists( 'gd_info' ) ) {
|
275 |
-
$image = file_get_contents( $path );
|
276 |
-
$image = imagecreatefromstring( $image );
|
277 |
-
$width = imagesx( $image );
|
278 |
-
$height = imagesy( $image );
|
279 |
-
$this->_size = array( 0 => $width, 1 => $height );
|
280 |
-
wprss_log( sprintf( 'Tried GD: %1$s', empty($this->_size) ? 'failure' : 'success' ), __METHOD__, WPRSS_LOG_LEVEL_SYSTEM );
|
281 |
-
}
|
282 |
-
}
|
283 |
-
|
284 |
-
return $this->_size;
|
285 |
-
}
|
286 |
-
|
287 |
-
public function is_readable() {
|
288 |
-
return is_readable( $this->get_local_path() );
|
289 |
-
}
|
290 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class WPRSS_Image_Cache {
|
4 |
+
|
5 |
+
protected $_download_request_timeout = 300;
|
6 |
+
|
7 |
+
protected $_image_class_name = 'WPRSS_Image_Cache_Image';
|
8 |
+
protected $_images = array();
|
9 |
+
|
10 |
+
public function __construct() {
|
11 |
+
}
|
12 |
+
|
13 |
+
public function set_image_class_name( $class_name ) {
|
14 |
+
$this->_image_class_name = $class_name;
|
15 |
+
return $this;
|
16 |
+
}
|
17 |
+
|
18 |
+
public function get_image_class_name() {
|
19 |
+
return trim($this->_image_class_name);
|
20 |
+
}
|
21 |
+
|
22 |
+
public function set_download_request_timeout( $timeout ) {
|
23 |
+
$this->_download_request_timeout = intval( $timeout );
|
24 |
+
return $this;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function get_download_request_timeout() {
|
28 |
+
return $this->_download_request_timeout;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $url
|
33 |
+
* @return \WPRSS_Image_Cache_Image
|
34 |
+
* @throws Exception If class invalid, or not found
|
35 |
+
*/
|
36 |
+
public function get_new_image( $url = null ) {
|
37 |
+
$error_caption = 'Could not create new cache image';
|
38 |
+
$class_name = $this->get_image_class_name();
|
39 |
+
if ( empty( $class_name ) ) throw new Exception( sprintf( '%1$s: class name must not be empty' ) );
|
40 |
+
if ( !class_exists( $class_name ) ) throw new Exception( sprintf( '%1$s: class "%2$s" does not exist', $class_name ) );
|
41 |
+
|
42 |
+
$image = new $class_name();
|
43 |
+
$this->_prepare_image( $image );
|
44 |
+
/* @var $image WPRSS_Image_Cache_Image */
|
45 |
+
if ( !is_null( $url ) ) $image->set_url( $url );
|
46 |
+
|
47 |
+
return $image;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
*
|
52 |
+
* @param WPRSS_Image_Cache_Image $image
|
53 |
+
*/
|
54 |
+
protected function _prepare_image( $image ) {
|
55 |
+
$image->set_download_request_timeout( $this->get_download_request_timeout() );
|
56 |
+
}
|
57 |
+
|
58 |
+
public function get_images( $url = null ) {
|
59 |
+
if ( is_null( $url ) ) return $this->_images;
|
60 |
+
|
61 |
+
// Gotta cache one
|
62 |
+
if ( !isset( $this->_images[ $url ] ) ) {
|
63 |
+
try {
|
64 |
+
$image = $this->_download_image($url);
|
65 |
+
} catch ( Exception $e ) {
|
66 |
+
return new WP_Error( 'image_cache_cannot_download', $e->getMessage() );
|
67 |
+
}
|
68 |
+
|
69 |
+
$this->_images[ $url ] = $image;
|
70 |
+
}
|
71 |
+
|
72 |
+
return $this->_images[ $url ];
|
73 |
+
}
|
74 |
+
|
75 |
+
public function purge() {
|
76 |
+
$image_class_name = $this->get_image_class_name();
|
77 |
+
foreach( $this->get_images() as $_url => $_image ) {
|
78 |
+
/* @var $_image WPRSS_Image_Cache_Image */
|
79 |
+
if ( is_a( $_image, $image_class_name ) )
|
80 |
+
$_image->delete();
|
81 |
+
}
|
82 |
+
|
83 |
+
$this->_images = array();
|
84 |
+
return $this;
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param string $url
|
89 |
+
* @return WPRSS_Image_Cache_Image
|
90 |
+
*/
|
91 |
+
protected function _download_image( $url ) {
|
92 |
+
$image = $this->get_new_image( $url );
|
93 |
+
$image->download();
|
94 |
+
|
95 |
+
return $image;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
class WPRSS_Image_Cache_Image {
|
100 |
+
|
101 |
+
protected $_url;
|
102 |
+
protected $_local_path;
|
103 |
+
protected $_unique_name;
|
104 |
+
protected $_size;
|
105 |
+
protected $_download_request_timeout;
|
106 |
+
protected $_is_attempted;
|
107 |
+
protected $_is_fall_back_to_unsecure;
|
108 |
+
|
109 |
+
public function __construct( $data = null ) {
|
110 |
+
$this->reset();
|
111 |
+
|
112 |
+
if ( is_string( $data ) && !empty( $data ) )
|
113 |
+
$this->_set_url( $data );
|
114 |
+
}
|
115 |
+
|
116 |
+
public function reset() {
|
117 |
+
$this->_url = null;
|
118 |
+
$this->_local_path = null;
|
119 |
+
$this->_unique_name = null;
|
120 |
+
$this->_size = null;
|
121 |
+
$this->_download_request_timeout = 300;
|
122 |
+
$this->_is_attempted = false;
|
123 |
+
$this->_is_fall_back_to_unsecure = true;
|
124 |
+
|
125 |
+
return $this;
|
126 |
+
}
|
127 |
+
|
128 |
+
protected function _set_url( $url ) {
|
129 |
+
$this->_url = $url;
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
public function set_url( $url ) {
|
134 |
+
$this->reset();
|
135 |
+
$this->_set_url($url);
|
136 |
+
|
137 |
+
return $this;
|
138 |
+
}
|
139 |
+
|
140 |
+
public function get_url() {
|
141 |
+
return $this->_url;
|
142 |
+
}
|
143 |
+
|
144 |
+
public function has_url() {
|
145 |
+
return isset( $this->_url );
|
146 |
+
}
|
147 |
+
|
148 |
+
protected function _set_local_path( $path ) {
|
149 |
+
$this->_local_path = $path;
|
150 |
+
return $this;
|
151 |
+
}
|
152 |
+
|
153 |
+
public function get_local_path() {
|
154 |
+
return $this->_local_path;
|
155 |
+
}
|
156 |
+
|
157 |
+
public function has_local_path() {
|
158 |
+
return isset( $this->_local_path );
|
159 |
+
}
|
160 |
+
|
161 |
+
public function set_download_request_timeout( $timeout ) {
|
162 |
+
$this->_download_request_timeout = intval( $timeout );
|
163 |
+
return $this;
|
164 |
+
}
|
165 |
+
|
166 |
+
public function get_download_request_timeout() {
|
167 |
+
return $this->_download_request_timeout;
|
168 |
+
}
|
169 |
+
|
170 |
+
protected function _is_attempted( $is_attempted = null ) {
|
171 |
+
if ( is_null( $is_attempted ) )
|
172 |
+
return (bool)$this->_is_attempted;
|
173 |
+
|
174 |
+
$this->_is_attempted = (bool) $is_attempted;
|
175 |
+
return $this;
|
176 |
+
}
|
177 |
+
|
178 |
+
public function is_attempted() {
|
179 |
+
return $this->_is_attempted();
|
180 |
+
}
|
181 |
+
|
182 |
+
public function is_fall_back_to_unsecure( $is_fall_back = null ) {
|
183 |
+
if ( is_null( $is_fall_back ) )
|
184 |
+
return (bool) $this->_is_fall_back_to_unsecure;
|
185 |
+
|
186 |
+
$this->_is_fall_back_to_unsecure = (bool) $is_fall_back;
|
187 |
+
return $this;
|
188 |
+
}
|
189 |
+
|
190 |
+
public function download() {
|
191 |
+
$error_caption = 'Could not download image';
|
192 |
+
if ( !$this->has_url() ) throw new Exception ( sprintf( '%1$s: a URL must be supplied' ) );
|
193 |
+
|
194 |
+
// Getting file download lib
|
195 |
+
$file_lib_path = ABSPATH . 'wp-admin/includes/file.php';
|
196 |
+
if ( !is_readable( $file_lib_path ) ) throw new Exception( sprintf( '%1$s: the file library cannot be read from %2$s', $error_caption, $file_lib_path ) );
|
197 |
+
require_once( $file_lib_path );
|
198 |
+
|
199 |
+
// Downloading the image
|
200 |
+
$url = $this->get_url();
|
201 |
+
$timeout = $this->get_download_request_timeout();
|
202 |
+
$tmp_path = $this->_download( $url, $timeout );
|
203 |
+
if ( is_wp_error( $tmp_path ) ) throw new Exception ( sprintf( '%1$s: %2$s', $error_caption, $tmp_path->get_error_message() ) );
|
204 |
+
// wprss_log( sprintf( 'Image saved to "%1$s"', $tmp_path ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
205 |
+
$this->_set_local_path( $tmp_path );
|
206 |
+
|
207 |
+
return $this->get_local_path();
|
208 |
+
}
|
209 |
+
|
210 |
+
protected function _download( $url, $timeout ) {
|
211 |
+
// wprss_log( sprintf( 'Downloading from "%1$s"', $url ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
212 |
+
$tmp_path = download_url( $url, $timeout );
|
213 |
+
if ( is_wp_error( $tmp_path ) ) {
|
214 |
+
$https = 'https';
|
215 |
+
if ( $this->is_fall_back_to_unsecure() && (stripos( $url, $https ) === 0) ) {
|
216 |
+
$url = 'http' . substr( $url, strlen( $https ) );
|
217 |
+
// wprss_log( sprintf( 'Downloading from "%1$s"', $url ), null, WPRSS_LOG_LEVEL_SYSTEM );
|
218 |
+
$tmp_path = $this->_download( $url, $timeout );
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
return $tmp_path;
|
223 |
+
}
|
224 |
+
|
225 |
+
public function delete() {
|
226 |
+
if ( $path = $this->get_local_path() )
|
227 |
+
unlink( $path );
|
228 |
+
|
229 |
+
return $this;
|
230 |
+
}
|
231 |
+
|
232 |
+
public function get_unique_name() {
|
233 |
+
if( !isset($this->_unique_name) ) {
|
234 |
+
$url = $this->get_url();
|
235 |
+
// Extract filename from url for title (ignoring query string)
|
236 |
+
// One of more character that is not a '?', followed by an image extension
|
237 |
+
preg_match( '/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $url, $matches );
|
238 |
+
$url_filename = basename( urldecode( $matches[0] ) );
|
239 |
+
// Check for extension. If not found, use last component of the URL
|
240 |
+
if ( !isset( $matches[1] ) ) {
|
241 |
+
$matches = array();
|
242 |
+
// Get the path to the image, without the domain. ex. /news/132456/image
|
243 |
+
preg_match_all( '/[^:]+:\/\/[^\/]+\/(.+)/', $url, $matches );
|
244 |
+
// If found
|
245 |
+
if ( isset( $matches[1][0] ) ) {
|
246 |
+
// Replace all '/' into '.' for the filename
|
247 |
+
$url_filename = str_replace( '/', '-', $matches[1][0] );
|
248 |
+
}
|
249 |
+
// If not found
|
250 |
+
else {
|
251 |
+
// Use a random string as a fallback, with length of 16 characters
|
252 |
+
$url_filename = wprss_ftp_generate_random_string( 16 );
|
253 |
+
}
|
254 |
+
}
|
255 |
+
// determine file type (ext and mime/type)
|
256 |
+
$url_type = wp_check_filetype($url_filename);
|
257 |
+
}
|
258 |
+
|
259 |
+
return $this->_unique_name;
|
260 |
+
}
|
261 |
+
|
262 |
+
public function get_size() {
|
263 |
+
if ( !isset( $this->_size ) ) {
|
264 |
+
$error_caption = 'Could not get image size';
|
265 |
+
if ( !$this->is_readable() ) throw new Exception( sprintf( '%1$s: image file is not readable' ) );
|
266 |
+
$path = $this->get_local_path();
|
267 |
+
|
268 |
+
// Trying simplest way
|
269 |
+
if ( $size = getimagesize( $path ) )
|
270 |
+
$this->_size = array( 0 => $size[0], 1 => $size[1] );
|
271 |
+
|
272 |
+
wprss_log( sprintf( 'Tried `getimagesize()`: %1$s', empty($this->_size) ? 'failure' : 'success' ), __METHOD__, WPRSS_LOG_LEVEL_SYSTEM );
|
273 |
+
|
274 |
+
if( !$this->_size && function_exists( 'gd_info' ) ) {
|
275 |
+
$image = file_get_contents( $path );
|
276 |
+
$image = imagecreatefromstring( $image );
|
277 |
+
$width = imagesx( $image );
|
278 |
+
$height = imagesy( $image );
|
279 |
+
$this->_size = array( 0 => $width, 1 => $height );
|
280 |
+
wprss_log( sprintf( 'Tried GD: %1$s', empty($this->_size) ? 'failure' : 'success' ), __METHOD__, WPRSS_LOG_LEVEL_SYSTEM );
|
281 |
+
}
|
282 |
+
}
|
283 |
+
|
284 |
+
return $this->_size;
|
285 |
+
}
|
286 |
+
|
287 |
+
public function is_readable() {
|
288 |
+
return is_readable( $this->get_local_path() );
|
289 |
+
}
|
290 |
}
|
includes/libraries/EDD_licensing/EDD_SL_Plugin_Updater.php
CHANGED
@@ -1,314 +1,314 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// uncomment this line for testing
|
4 |
-
//set_site_transient( 'update_plugins', null );
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Allows plugins to use their own update API.
|
8 |
-
*
|
9 |
-
* @author Pippin Williamson
|
10 |
-
* @version 1.5
|
11 |
-
*/
|
12 |
-
class EDD_SL_Plugin_Updater {
|
13 |
-
private $api_url = '';
|
14 |
-
private $api_data = array();
|
15 |
-
private $name = '';
|
16 |
-
private $slug = '';
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Class constructor.
|
20 |
-
*
|
21 |
-
* @uses plugin_basename()
|
22 |
-
* @uses hook()
|
23 |
-
*
|
24 |
-
* @param string $_api_url The URL pointing to the custom API endpoint.
|
25 |
-
* @param string $_plugin_file Path to the plugin file.
|
26 |
-
* @param array $_api_data Optional data to send with API calls.
|
27 |
-
* @return void
|
28 |
-
*/
|
29 |
-
function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
|
30 |
-
$this->api_url = trailingslashit( $_api_url );
|
31 |
-
$this->api_data = $_api_data;
|
32 |
-
$this->name = plugin_basename( $_plugin_file );
|
33 |
-
$this->slug = basename( $_plugin_file, '.php' );
|
34 |
-
$this->version = $_api_data['version'];
|
35 |
-
|
36 |
-
// Set up hooks.
|
37 |
-
$this->init();
|
38 |
-
add_action( 'admin_init', array( $this, 'show_changelog' ) );
|
39 |
-
}
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Set up WordPress filters to hook into WP's update process.
|
43 |
-
*
|
44 |
-
* @uses add_filter()
|
45 |
-
*
|
46 |
-
* @return void
|
47 |
-
*/
|
48 |
-
public function init() {
|
49 |
-
|
50 |
-
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
51 |
-
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
|
52 |
-
|
53 |
-
add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Check for Updates at the defined API endpoint and modify the update array.
|
58 |
-
*
|
59 |
-
* This function dives into the update API just when WordPress creates its update array,
|
60 |
-
* then adds a custom API call and injects the custom plugin data retrieved from the API.
|
61 |
-
* It is reassembled from parts of the native WordPress plugin update code.
|
62 |
-
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
|
63 |
-
*
|
64 |
-
* @uses api_request()
|
65 |
-
*
|
66 |
-
* @param array $_transient_data Update array build by WordPress.
|
67 |
-
* @return array Modified update array with custom plugin data.
|
68 |
-
*/
|
69 |
-
function check_update( $_transient_data ) {
|
70 |
-
|
71 |
-
if( ! is_object( $_transient_data ) ) {
|
72 |
-
$_transient_data = new stdClass;
|
73 |
-
}
|
74 |
-
|
75 |
-
if ( empty( $_transient_data->response ) || empty( $_transient_data->response[ $this->name ] ) ) {
|
76 |
-
|
77 |
-
$version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug ) );
|
78 |
-
|
79 |
-
if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
|
80 |
-
|
81 |
-
$this->did_check = true;
|
82 |
-
|
83 |
-
if( version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
84 |
-
|
85 |
-
$_transient_data->response[ $this->name ] = $version_info;
|
86 |
-
|
87 |
-
}
|
88 |
-
|
89 |
-
$_transient_data->last_checked = time();
|
90 |
-
$_transient_data->checked[ $this->name ] = $this->version;
|
91 |
-
|
92 |
-
}
|
93 |
-
|
94 |
-
}
|
95 |
-
|
96 |
-
return $_transient_data;
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
|
101 |
-
*
|
102 |
-
* @param string $file
|
103 |
-
* @param array $plugin
|
104 |
-
*/
|
105 |
-
public function show_update_notification( $file, $plugin ) {
|
106 |
-
|
107 |
-
if( ! current_user_can( 'update_plugins' ) ) {
|
108 |
-
return;
|
109 |
-
}
|
110 |
-
|
111 |
-
if( ! is_multisite() ) {
|
112 |
-
return;
|
113 |
-
}
|
114 |
-
|
115 |
-
if ( $this->name != $file ) {
|
116 |
-
return;
|
117 |
-
}
|
118 |
-
|
119 |
-
// Remove our filter on the site transient
|
120 |
-
remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
|
121 |
-
|
122 |
-
$update_cache = get_site_transient( 'update_plugins' );
|
123 |
-
|
124 |
-
if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
|
125 |
-
|
126 |
-
$version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug ) );
|
127 |
-
|
128 |
-
if( version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
129 |
-
|
130 |
-
$update_cache->response[ $this->name ] = $version_info;
|
131 |
-
|
132 |
-
}
|
133 |
-
|
134 |
-
$update_cache->last_checked = time();
|
135 |
-
$update_cache->checked[ $this->name ] = $this->version;
|
136 |
-
|
137 |
-
set_site_transient( 'update_plugins', $update_cache );
|
138 |
-
|
139 |
-
}
|
140 |
-
|
141 |
-
// Restore our filter
|
142 |
-
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
143 |
-
|
144 |
-
if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
145 |
-
|
146 |
-
// build a plugin list row, with update notification
|
147 |
-
$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
|
148 |
-
echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
|
149 |
-
|
150 |
-
$changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
|
151 |
-
|
152 |
-
if ( empty( $version_info->download_link ) ) {
|
153 |
-
printf(
|
154 |
-
__( 'There is a new version of %1$s available. <a target="_blank" class="thickbox" href="%2$s">View version %3$s details</a>.' ),
|
155 |
-
esc_html( $version_info->name ),
|
156 |
-
esc_url( $changelog_link ),
|
157 |
-
esc_html( $version_info->new_version )
|
158 |
-
);
|
159 |
-
} else {
|
160 |
-
printf(
|
161 |
-
__( 'There is a new version of %1$s available. <a target="_blank" class="thickbox" href="%2$s">View version %3$s details</a> or <a href="%4$s">update now</a>.' ),
|
162 |
-
esc_html( $version_info->name ),
|
163 |
-
esc_url( $changelog_link ),
|
164 |
-
esc_html( $version_info->new_version ),
|
165 |
-
esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) )
|
166 |
-
);
|
167 |
-
}
|
168 |
-
|
169 |
-
echo '</div></td></tr>';
|
170 |
-
}
|
171 |
-
}
|
172 |
-
|
173 |
-
|
174 |
-
/**
|
175 |
-
* Updates information on the "View version x.x details" page with custom data.
|
176 |
-
*
|
177 |
-
* @uses api_request()
|
178 |
-
*
|
179 |
-
* @param mixed $_data
|
180 |
-
* @param string $_action
|
181 |
-
* @param object $_args
|
182 |
-
* @return object $_data
|
183 |
-
*/
|
184 |
-
function plugins_api_filter( $_data, $_action = '', $_args = null ) {
|
185 |
-
|
186 |
-
|
187 |
-
if ( $_action != 'plugin_information' ) {
|
188 |
-
|
189 |
-
return $_data;
|
190 |
-
|
191 |
-
}
|
192 |
-
|
193 |
-
if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
|
194 |
-
|
195 |
-
return $_data;
|
196 |
-
|
197 |
-
}
|
198 |
-
|
199 |
-
$to_send = array(
|
200 |
-
'slug' => $this->slug,
|
201 |
-
'is_ssl' => is_ssl(),
|
202 |
-
'fields' => array(
|
203 |
-
'banners' => false, // These will be supported soon hopefully
|
204 |
-
'reviews' => false
|
205 |
-
)
|
206 |
-
);
|
207 |
-
|
208 |
-
$api_response = $this->api_request( 'plugin_information', $to_send );
|
209 |
-
|
210 |
-
if ( false !== $api_response ) {
|
211 |
-
$_data = $api_response;
|
212 |
-
}
|
213 |
-
|
214 |
-
return $_data;
|
215 |
-
}
|
216 |
-
|
217 |
-
|
218 |
-
/**
|
219 |
-
* Disable SSL verification in order to prevent download update failures
|
220 |
-
*
|
221 |
-
* @param array $args
|
222 |
-
* @param string $url
|
223 |
-
* @return object $array
|
224 |
-
*/
|
225 |
-
function http_request_args( $args, $url ) {
|
226 |
-
// If it is an https request and we are performing a package download, disable ssl verification
|
227 |
-
if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
|
228 |
-
$args['sslverify'] = false;
|
229 |
-
}
|
230 |
-
return $args;
|
231 |
-
}
|
232 |
-
|
233 |
-
/**
|
234 |
-
* Calls the API and, if successfull, returns the object delivered by the API.
|
235 |
-
*
|
236 |
-
* @uses get_bloginfo()
|
237 |
-
* @uses wp_remote_post()
|
238 |
-
* @uses is_wp_error()
|
239 |
-
*
|
240 |
-
* @param string $_action The requested action.
|
241 |
-
* @param array $_data Parameters for the API action.
|
242 |
-
* @return false||object
|
243 |
-
*/
|
244 |
-
private function api_request( $_action, $_data ) {
|
245 |
-
|
246 |
-
global $wp_version;
|
247 |
-
|
248 |
-
$data = array_merge( $this->api_data, $_data );
|
249 |
-
|
250 |
-
if ( $data['slug'] != $this->slug )
|
251 |
-
return;
|
252 |
-
|
253 |
-
if ( empty( $data['license'] ) )
|
254 |
-
return;
|
255 |
-
|
256 |
-
if( $this->api_url == home_url() ) {
|
257 |
-
return false; // Don't allow a plugin to ping itself
|
258 |
-
}
|
259 |
-
|
260 |
-
$api_params = array(
|
261 |
-
'edd_action' => 'get_version',
|
262 |
-
'license' => $data['license'],
|
263 |
-
'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
|
264 |
-
'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
|
265 |
-
'slug' => $this->slug,
|
266 |
-
'author' => $data['author'],
|
267 |
-
'url' => home_url()
|
268 |
-
);
|
269 |
-
|
270 |
-
$request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
|
271 |
-
|
272 |
-
if ( ! is_wp_error( $request ) ) {
|
273 |
-
$request = json_decode( wp_remote_retrieve_body( $request ) );
|
274 |
-
}
|
275 |
-
|
276 |
-
if ( $request && isset( $request->sections ) ) {
|
277 |
-
$request->sections = maybe_unserialize( $request->sections );
|
278 |
-
} else {
|
279 |
-
$request = false;
|
280 |
-
}
|
281 |
-
|
282 |
-
return $request;
|
283 |
-
}
|
284 |
-
|
285 |
-
public function show_changelog() {
|
286 |
-
|
287 |
-
|
288 |
-
if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
|
289 |
-
return;
|
290 |
-
}
|
291 |
-
|
292 |
-
if( empty( $_REQUEST['plugin'] ) ) {
|
293 |
-
return;
|
294 |
-
}
|
295 |
-
|
296 |
-
if( empty( $_REQUEST['slug'] ) ) {
|
297 |
-
return;
|
298 |
-
}
|
299 |
-
|
300 |
-
if( ! current_user_can( 'update_plugins' ) ) {
|
301 |
-
wp_die( __( 'You do not have permission to install plugin updates' ), __( 'Error', 'edd_sl' ), array( 'response' => 401 ) );
|
302 |
-
}
|
303 |
-
|
304 |
-
$response = $this->api_request( 'plugin_latest_version', array( 'slug' => $_REQUEST['slug'] ) );
|
305 |
-
|
306 |
-
if( $response && isset( $response->sections['changelog'] ) ) {
|
307 |
-
echo '<div style="background:#fff;padding:10px;">' . $response->sections['changelog'] . '</div>';
|
308 |
-
}
|
309 |
-
|
310 |
-
|
311 |
-
exit;
|
312 |
-
}
|
313 |
-
|
314 |
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// uncomment this line for testing
|
4 |
+
//set_site_transient( 'update_plugins', null );
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Allows plugins to use their own update API.
|
8 |
+
*
|
9 |
+
* @author Pippin Williamson
|
10 |
+
* @version 1.5
|
11 |
+
*/
|
12 |
+
class EDD_SL_Plugin_Updater {
|
13 |
+
private $api_url = '';
|
14 |
+
private $api_data = array();
|
15 |
+
private $name = '';
|
16 |
+
private $slug = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Class constructor.
|
20 |
+
*
|
21 |
+
* @uses plugin_basename()
|
22 |
+
* @uses hook()
|
23 |
+
*
|
24 |
+
* @param string $_api_url The URL pointing to the custom API endpoint.
|
25 |
+
* @param string $_plugin_file Path to the plugin file.
|
26 |
+
* @param array $_api_data Optional data to send with API calls.
|
27 |
+
* @return void
|
28 |
+
*/
|
29 |
+
function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
|
30 |
+
$this->api_url = trailingslashit( $_api_url );
|
31 |
+
$this->api_data = $_api_data;
|
32 |
+
$this->name = plugin_basename( $_plugin_file );
|
33 |
+
$this->slug = basename( $_plugin_file, '.php' );
|
34 |
+
$this->version = $_api_data['version'];
|
35 |
+
|
36 |
+
// Set up hooks.
|
37 |
+
$this->init();
|
38 |
+
add_action( 'admin_init', array( $this, 'show_changelog' ) );
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Set up WordPress filters to hook into WP's update process.
|
43 |
+
*
|
44 |
+
* @uses add_filter()
|
45 |
+
*
|
46 |
+
* @return void
|
47 |
+
*/
|
48 |
+
public function init() {
|
49 |
+
|
50 |
+
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
51 |
+
add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
|
52 |
+
|
53 |
+
add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Check for Updates at the defined API endpoint and modify the update array.
|
58 |
+
*
|
59 |
+
* This function dives into the update API just when WordPress creates its update array,
|
60 |
+
* then adds a custom API call and injects the custom plugin data retrieved from the API.
|
61 |
+
* It is reassembled from parts of the native WordPress plugin update code.
|
62 |
+
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
|
63 |
+
*
|
64 |
+
* @uses api_request()
|
65 |
+
*
|
66 |
+
* @param array $_transient_data Update array build by WordPress.
|
67 |
+
* @return array Modified update array with custom plugin data.
|
68 |
+
*/
|
69 |
+
function check_update( $_transient_data ) {
|
70 |
+
|
71 |
+
if( ! is_object( $_transient_data ) ) {
|
72 |
+
$_transient_data = new stdClass;
|
73 |
+
}
|
74 |
+
|
75 |
+
if ( empty( $_transient_data->response ) || empty( $_transient_data->response[ $this->name ] ) ) {
|
76 |
+
|
77 |
+
$version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug ) );
|
78 |
+
|
79 |
+
if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
|
80 |
+
|
81 |
+
$this->did_check = true;
|
82 |
+
|
83 |
+
if( version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
84 |
+
|
85 |
+
$_transient_data->response[ $this->name ] = $version_info;
|
86 |
+
|
87 |
+
}
|
88 |
+
|
89 |
+
$_transient_data->last_checked = time();
|
90 |
+
$_transient_data->checked[ $this->name ] = $this->version;
|
91 |
+
|
92 |
+
}
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
return $_transient_data;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
|
101 |
+
*
|
102 |
+
* @param string $file
|
103 |
+
* @param array $plugin
|
104 |
+
*/
|
105 |
+
public function show_update_notification( $file, $plugin ) {
|
106 |
+
|
107 |
+
if( ! current_user_can( 'update_plugins' ) ) {
|
108 |
+
return;
|
109 |
+
}
|
110 |
+
|
111 |
+
if( ! is_multisite() ) {
|
112 |
+
return;
|
113 |
+
}
|
114 |
+
|
115 |
+
if ( $this->name != $file ) {
|
116 |
+
return;
|
117 |
+
}
|
118 |
+
|
119 |
+
// Remove our filter on the site transient
|
120 |
+
remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
|
121 |
+
|
122 |
+
$update_cache = get_site_transient( 'update_plugins' );
|
123 |
+
|
124 |
+
if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
|
125 |
+
|
126 |
+
$version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug ) );
|
127 |
+
|
128 |
+
if( version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
129 |
+
|
130 |
+
$update_cache->response[ $this->name ] = $version_info;
|
131 |
+
|
132 |
+
}
|
133 |
+
|
134 |
+
$update_cache->last_checked = time();
|
135 |
+
$update_cache->checked[ $this->name ] = $this->version;
|
136 |
+
|
137 |
+
set_site_transient( 'update_plugins', $update_cache );
|
138 |
+
|
139 |
+
}
|
140 |
+
|
141 |
+
// Restore our filter
|
142 |
+
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
|
143 |
+
|
144 |
+
if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
|
145 |
+
|
146 |
+
// build a plugin list row, with update notification
|
147 |
+
$wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
|
148 |
+
echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
|
149 |
+
|
150 |
+
$changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' );
|
151 |
+
|
152 |
+
if ( empty( $version_info->download_link ) ) {
|
153 |
+
printf(
|
154 |
+
__( 'There is a new version of %1$s available. <a target="_blank" class="thickbox" href="%2$s">View version %3$s details</a>.' ),
|
155 |
+
esc_html( $version_info->name ),
|
156 |
+
esc_url( $changelog_link ),
|
157 |
+
esc_html( $version_info->new_version )
|
158 |
+
);
|
159 |
+
} else {
|
160 |
+
printf(
|
161 |
+
__( 'There is a new version of %1$s available. <a target="_blank" class="thickbox" href="%2$s">View version %3$s details</a> or <a href="%4$s">update now</a>.' ),
|
162 |
+
esc_html( $version_info->name ),
|
163 |
+
esc_url( $changelog_link ),
|
164 |
+
esc_html( $version_info->new_version ),
|
165 |
+
esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) )
|
166 |
+
);
|
167 |
+
}
|
168 |
+
|
169 |
+
echo '</div></td></tr>';
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Updates information on the "View version x.x details" page with custom data.
|
176 |
+
*
|
177 |
+
* @uses api_request()
|
178 |
+
*
|
179 |
+
* @param mixed $_data
|
180 |
+
* @param string $_action
|
181 |
+
* @param object $_args
|
182 |
+
* @return object $_data
|
183 |
+
*/
|
184 |
+
function plugins_api_filter( $_data, $_action = '', $_args = null ) {
|
185 |
+
|
186 |
+
|
187 |
+
if ( $_action != 'plugin_information' ) {
|
188 |
+
|
189 |
+
return $_data;
|
190 |
+
|
191 |
+
}
|
192 |
+
|
193 |
+
if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
|
194 |
+
|
195 |
+
return $_data;
|
196 |
+
|
197 |
+
}
|
198 |
+
|
199 |
+
$to_send = array(
|
200 |
+
'slug' => $this->slug,
|
201 |
+
'is_ssl' => is_ssl(),
|
202 |
+
'fields' => array(
|
203 |
+
'banners' => false, // These will be supported soon hopefully
|
204 |
+
'reviews' => false
|
205 |
+
)
|
206 |
+
);
|
207 |
+
|
208 |
+
$api_response = $this->api_request( 'plugin_information', $to_send );
|
209 |
+
|
210 |
+
if ( false !== $api_response ) {
|
211 |
+
$_data = $api_response;
|
212 |
+
}
|
213 |
+
|
214 |
+
return $_data;
|
215 |
+
}
|
216 |
+
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Disable SSL verification in order to prevent download update failures
|
220 |
+
*
|
221 |
+
* @param array $args
|
222 |
+
* @param string $url
|
223 |
+
* @return object $array
|
224 |
+
*/
|
225 |
+
function http_request_args( $args, $url ) {
|
226 |
+
// If it is an https request and we are performing a package download, disable ssl verification
|
227 |
+
if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
|
228 |
+
$args['sslverify'] = false;
|
229 |
+
}
|
230 |
+
return $args;
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Calls the API and, if successfull, returns the object delivered by the API.
|
235 |
+
*
|
236 |
+
* @uses get_bloginfo()
|
237 |
+
* @uses wp_remote_post()
|
238 |
+
* @uses is_wp_error()
|
239 |
+
*
|
240 |
+
* @param string $_action The requested action.
|
241 |
+
* @param array $_data Parameters for the API action.
|
242 |
+
* @return false||object
|
243 |
+
*/
|
244 |
+
private function api_request( $_action, $_data ) {
|
245 |
+
|
246 |
+
global $wp_version;
|
247 |
+
|
248 |
+
$data = array_merge( $this->api_data, $_data );
|
249 |
+
|
250 |
+
if ( $data['slug'] != $this->slug )
|
251 |
+
return;
|
252 |
+
|
253 |
+
if ( empty( $data['license'] ) )
|
254 |
+
return;
|
255 |
+
|
256 |
+
if( $this->api_url == home_url() ) {
|
257 |
+
return false; // Don't allow a plugin to ping itself
|
258 |
+
}
|
259 |
+
|
260 |
+
$api_params = array(
|
261 |
+
'edd_action' => 'get_version',
|
262 |
+
'license' => $data['license'],
|
263 |
+
'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
|
264 |
+
'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
|
265 |
+
'slug' => $this->slug,
|
266 |
+
'author' => $data['author'],
|
267 |
+
'url' => home_url()
|
268 |
+
);
|
269 |
+
|
270 |
+
$request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
|
271 |
+
|
272 |
+
if ( ! is_wp_error( $request ) ) {
|
273 |
+
$request = json_decode( wp_remote_retrieve_body( $request ) );
|
274 |
+
}
|
275 |
+
|
276 |
+
if ( $request && isset( $request->sections ) ) {
|
277 |
+
$request->sections = maybe_unserialize( $request->sections );
|
278 |
+
} else {
|
279 |
+
$request = false;
|
280 |
+
}
|
281 |
+
|
282 |
+
return $request;
|
283 |
+
}
|
284 |
+
|
285 |
+
public function show_changelog() {
|
286 |
+
|
287 |
+
|
288 |
+
if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
|
289 |
+
return;
|
290 |
+
}
|
291 |
+
|
292 |
+
if( empty( $_REQUEST['plugin'] ) ) {
|
293 |
+
return;
|
294 |
+
}
|
295 |
+
|
296 |
+
if( empty( $_REQUEST['slug'] ) ) {
|
297 |
+
return;
|
298 |
+
}
|
299 |
+
|
300 |
+
if( ! current_user_can( 'update_plugins' ) ) {
|
301 |
+
wp_die( __( 'You do not have permission to install plugin updates' ), __( 'Error', 'edd_sl' ), array( 'response' => 401 ) );
|
302 |
+
}
|
303 |
+
|
304 |
+
$response = $this->api_request( 'plugin_latest_version', array( 'slug' => $_REQUEST['slug'] ) );
|
305 |
+
|
306 |
+
if( $response && isset( $response->sections['changelog'] ) ) {
|
307 |
+
echo '<div style="background:#fff;padding:10px;">' . $response->sections['changelog'] . '</div>';
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
exit;
|
312 |
+
}
|
313 |
+
|
314 |
}
|
includes/libraries/WordPress-Readme-Parser/ReadmeParser.php
CHANGED
@@ -1,329 +1,329 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Custom readme parser
|
4 |
-
*
|
5 |
-
* Based on Automattic_Readme from http://code.google.com/p/wordpress-plugin-readme-parser/
|
6 |
-
*
|
7 |
-
* Relies on Markdown_Extra
|
8 |
-
*
|
9 |
-
* @todo Handle screenshots section properly
|
10 |
-
* @todo Create validator for this based on http://code.google.com/p/wordpress-plugin-readme-parser/source/browse/trunk/validator.php
|
11 |
-
*/
|
12 |
-
class Baikonur_ReadmeParser {
|
13 |
-
|
14 |
-
public static function parse_readme($file) {
|
15 |
-
$contents = file($file);
|
16 |
-
return self::parse_readme_contents($contents);
|
17 |
-
}
|
18 |
-
|
19 |
-
public static function parse_readme_contents($contents) {
|
20 |
-
if (is_string($contents)) {
|
21 |
-
$contents = explode("\n", $contents);
|
22 |
-
}
|
23 |
-
|
24 |
-
$this_class = __CLASS__;
|
25 |
-
if (function_exists('get_called_class')) {
|
26 |
-
$this_class = get_called_class();
|
27 |
-
}
|
28 |
-
|
29 |
-
$contents = array_map(array($this_class, 'strip_newlines'), $contents);
|
30 |
-
|
31 |
-
// Strip BOM
|
32 |
-
if (strpos($contents[0], "\xEF\xBB\xBF") === 0) {
|
33 |
-
$contents[0] = substr($contents[0], 3);
|
34 |
-
}
|
35 |
-
|
36 |
-
$data = new stdClass;
|
37 |
-
|
38 |
-
// Defaults
|
39 |
-
$data->is_excerpt = false;
|
40 |
-
$data->is_truncated = false;
|
41 |
-
$data->tags = array();
|
42 |
-
$data->requires = '';
|
43 |
-
$data->tested = '';
|
44 |
-
$data->contributors = array();
|
45 |
-
$data->stable_tag = '';
|
46 |
-
$data->version = '';
|
47 |
-
$data->donate_link = '';
|
48 |
-
$data->short_description = '';
|
49 |
-
$data->sections = array();
|
50 |
-
$data->changelog = array();
|
51 |
-
$data->upgrade_notice = array();
|
52 |
-
$data->screenshots = array();
|
53 |
-
$data->remaining_content = array();
|
54 |
-
|
55 |
-
$line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
|
56 |
-
$data->name = $line;
|
57 |
-
$data->name = trim($data->name, "#= ");
|
58 |
-
|
59 |
-
// Parse headers
|
60 |
-
$headers = array();
|
61 |
-
|
62 |
-
$line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
|
63 |
-
do {
|
64 |
-
$key = $value = null;
|
65 |
-
if (strpos($line, ':') === false) {
|
66 |
-
break;
|
67 |
-
}
|
68 |
-
$bits = explode(':', $line, 2);
|
69 |
-
list($key, $value) = $bits;
|
70 |
-
$key = strtolower(str_replace(array(' ', "\t"), '_', trim($key)));
|
71 |
-
if ($key === 'tags' && isset($headers['tags'])) {
|
72 |
-
$headers[$key] .= ',' . trim($value);
|
73 |
-
}
|
74 |
-
else {
|
75 |
-
$headers[$key] = trim($value);
|
76 |
-
}
|
77 |
-
}
|
78 |
-
while (($line = array_shift($contents)) !== null && ($line = trim($line)) && !empty($line));
|
79 |
-
array_unshift($contents, $line);
|
80 |
-
|
81 |
-
if (!empty($headers['tags'])) {
|
82 |
-
$data->tags = explode(',', $headers['tags']);
|
83 |
-
$data->tags = array_map('trim', $data->tags);
|
84 |
-
}
|
85 |
-
if (!empty($headers['requires'])) {
|
86 |
-
$data->requires = $headers['requires'];
|
87 |
-
}
|
88 |
-
if (!empty($headers['requires_at_least'])) {
|
89 |
-
$data->requires = $headers['requires_at_least'];
|
90 |
-
}
|
91 |
-
if (!empty($headers['tested'])) {
|
92 |
-
$data->tested = $headers['tested'];
|
93 |
-
}
|
94 |
-
if (!empty($headers['tested_up_to'])) {
|
95 |
-
$data->tested = $headers['tested_up_to'];
|
96 |
-
}
|
97 |
-
if (!empty($headers['contributors'])) {
|
98 |
-
$data->contributors = explode(',', $headers['contributors']);
|
99 |
-
$data->contributors = array_map('trim', $data->contributors);
|
100 |
-
}
|
101 |
-
if (!empty($headers['stable_tag'])) {
|
102 |
-
$data->stable_tag = $headers['stable_tag'];
|
103 |
-
}
|
104 |
-
if (!empty($headers['donate_link'])) {
|
105 |
-
$data->donate_link = $headers['donate_link'];
|
106 |
-
}
|
107 |
-
if (!empty($headers['version'])) {
|
108 |
-
$data->version = $headers['version'];
|
109 |
-
}
|
110 |
-
else {
|
111 |
-
$data->version = $data->stable_tag;
|
112 |
-
}
|
113 |
-
|
114 |
-
// Parse the short description
|
115 |
-
while (($line = array_shift($contents)) !== null) {
|
116 |
-
$trimmed = trim($line);
|
117 |
-
if (empty($trimmed)) {
|
118 |
-
$data->short_description .= "\n";
|
119 |
-
continue;
|
120 |
-
}
|
121 |
-
if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
|
122 |
-
array_unshift($contents, $line);
|
123 |
-
break;
|
124 |
-
}
|
125 |
-
|
126 |
-
$data->short_description .= $line . "\n";
|
127 |
-
}
|
128 |
-
$data->short_description = trim($data->short_description);
|
129 |
-
|
130 |
-
$data->is_truncated = call_user_func_array(array($this_class, 'trim_short_desc'), array(&$data->short_description));
|
131 |
-
|
132 |
-
// Parse the rest of the body
|
133 |
-
$current = '';
|
134 |
-
$special = array('description', 'installation', 'faq', 'frequently_asked_questions', 'screenshots', 'changelog', 'upgrade_notice');
|
135 |
-
|
136 |
-
while (($line = array_shift($contents)) !== null) {
|
137 |
-
$trimmed = trim($line);
|
138 |
-
if (empty($trimmed)) {
|
139 |
-
$current .= "\n";
|
140 |
-
continue;
|
141 |
-
}
|
142 |
-
|
143 |
-
if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
|
144 |
-
if (!empty($title)) {
|
145 |
-
$data->sections[$title] = trim($current);
|
146 |
-
}
|
147 |
-
|
148 |
-
$current = '';
|
149 |
-
$real_title = trim($line, "#= \t");
|
150 |
-
$title = strtolower(str_replace(' ', '_', $real_title));
|
151 |
-
if ($title === 'faq') {
|
152 |
-
$title = 'frequently_asked_questions';
|
153 |
-
}
|
154 |
-
elseif ($title === 'change_log') {
|
155 |
-
$title = 'changelog';
|
156 |
-
}
|
157 |
-
if (!in_array($title, $special)) {
|
158 |
-
$current .= '<h3>' . $real_title . "</h3>";
|
159 |
-
}
|
160 |
-
continue;
|
161 |
-
}
|
162 |
-
|
163 |
-
$current .= $line . "\n";
|
164 |
-
}
|
165 |
-
|
166 |
-
if (!empty($title)) {
|
167 |
-
$data->sections[$title] = trim($current);
|
168 |
-
}
|
169 |
-
$title = null;
|
170 |
-
$current = null;
|
171 |
-
|
172 |
-
if (empty($data->sections['description'])) {
|
173 |
-
$data->sections['description'] = call_user_func(array($this_class, 'parse_markdown'), $data->short_description);
|
174 |
-
}
|
175 |
-
|
176 |
-
// Parse changelog
|
177 |
-
if (!empty($data->sections['changelog'])) {
|
178 |
-
$lines = explode("\n", $data->sections['changelog']);
|
179 |
-
while (($line = array_shift($lines)) !== null) {
|
180 |
-
$trimmed = trim($line);
|
181 |
-
if (empty($trimmed)) {
|
182 |
-
continue;
|
183 |
-
}
|
184 |
-
|
185 |
-
if ($trimmed[0] === '=') {
|
186 |
-
if (!empty($current)) {
|
187 |
-
$data->changelog[$title] = trim($current);
|
188 |
-
}
|
189 |
-
|
190 |
-
$current = '';
|
191 |
-
$title = trim($line, "#= \t");
|
192 |
-
continue;
|
193 |
-
}
|
194 |
-
|
195 |
-
$current .= $line . "\n";
|
196 |
-
}
|
197 |
-
|
198 |
-
$data->changelog[$title] = trim($current);
|
199 |
-
}
|
200 |
-
$title = null;
|
201 |
-
$current = null;
|
202 |
-
|
203 |
-
if (isset($data->sections['upgrade_notice'])) {
|
204 |
-
$lines = explode("\n", $data->sections['upgrade_notice']);
|
205 |
-
while (($line = array_shift($lines)) !== null) {
|
206 |
-
$trimmed = trim($line);
|
207 |
-
if (empty($trimmed)) {
|
208 |
-
continue;
|
209 |
-
}
|
210 |
-
|
211 |
-
if ($trimmed[0] === '=') {
|
212 |
-
if (!empty($current)) {
|
213 |
-
$data->upgrade_notice[$title] = trim($current);
|
214 |
-
}
|
215 |
-
|
216 |
-
$current = '';
|
217 |
-
$title = trim($line, "#= \t");
|
218 |
-
continue;
|
219 |
-
}
|
220 |
-
|
221 |
-
$current .= $line . "\n";
|
222 |
-
}
|
223 |
-
|
224 |
-
if (!empty($title) && !empty($current)) {
|
225 |
-
$data->upgrade_notice[$title] = trim($current);
|
226 |
-
}
|
227 |
-
unset($data->sections['upgrade_notice']);
|
228 |
-
}
|
229 |
-
|
230 |
-
// Markdownify!
|
231 |
-
|
232 |
-
$data->sections = array_map(array($this_class, 'parse_markdown'), $data->sections);
|
233 |
-
$data->changelog = array_map(array($this_class, 'parse_markdown'), $data->changelog);
|
234 |
-
$data->upgrade_notice = array_map(array($this_class, 'parse_markdown'), $data->upgrade_notice);
|
235 |
-
|
236 |
-
if (isset($data->sections['screenshots'])) {
|
237 |
-
preg_match_all('#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER);
|
238 |
-
if ($screenshots) {
|
239 |
-
foreach ((array) $screenshots as $ss) {
|
240 |
-
$data->screenshots[] = trim($ss[1]);
|
241 |
-
}
|
242 |
-
}
|
243 |
-
}
|
244 |
-
|
245 |
-
// Rearrange stuff
|
246 |
-
|
247 |
-
$data->remaining_content = $data->sections;
|
248 |
-
$data->sections = array();
|
249 |
-
|
250 |
-
foreach ($special as $spec) {
|
251 |
-
if (isset($data->remaining_content[$spec])) {
|
252 |
-
$data->sections[$spec] = $data->remaining_content[$spec];
|
253 |
-
unset($data->remaining_content[$spec]);
|
254 |
-
}
|
255 |
-
}
|
256 |
-
|
257 |
-
return $data;
|
258 |
-
}
|
259 |
-
|
260 |
-
protected static function get_first_nonwhitespace(&$contents) {
|
261 |
-
while (($line = array_shift($contents)) !== null) {
|
262 |
-
$trimmed = trim($line);
|
263 |
-
if (!empty($line)) {
|
264 |
-
break;
|
265 |
-
}
|
266 |
-
}
|
267 |
-
|
268 |
-
return $line;
|
269 |
-
}
|
270 |
-
|
271 |
-
protected static function strip_newlines($line) {
|
272 |
-
return rtrim($line, "\r\n");
|
273 |
-
}
|
274 |
-
|
275 |
-
protected static function trim_short_desc(&$desc) {
|
276 |
-
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
277 |
-
if (mb_strlen($desc) > 150) {
|
278 |
-
$desc = mb_substr($desc, 0, 150);
|
279 |
-
$desc = trim($desc);
|
280 |
-
return true;
|
281 |
-
}
|
282 |
-
}
|
283 |
-
else {
|
284 |
-
if (strlen($desc) > 150) {
|
285 |
-
$desc = substr($desc, 0, 150);
|
286 |
-
$desc = trim($desc);
|
287 |
-
return true;
|
288 |
-
}
|
289 |
-
}
|
290 |
-
|
291 |
-
return false;
|
292 |
-
}
|
293 |
-
|
294 |
-
protected static function parse_markdown($text) {
|
295 |
-
$text = self::code_trick($text);
|
296 |
-
$text = preg_replace('/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text);
|
297 |
-
$text = Markdown(trim($text));
|
298 |
-
return trim($text);
|
299 |
-
}
|
300 |
-
|
301 |
-
protected static function code_trick($text) {
|
302 |
-
// If doing markdown, first take any user formatted code blocks and turn them into backticks so that
|
303 |
-
// markdown will preserve things like underscores in code blocks
|
304 |
-
$text = preg_replace_callback("!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array(__CLASS__, 'decodeit'), $text);
|
305 |
-
|
306 |
-
$text = str_replace(array("\r\n", "\r"), "\n", $text);
|
307 |
-
// Markdown can do inline code, we convert bbPress style block level code to Markdown style
|
308 |
-
$text = preg_replace_callback("!(^|\n)([ \t]*?)`(.*?)`!s", array(__CLASS__, 'indent'), $text);
|
309 |
-
return $text;
|
310 |
-
}
|
311 |
-
|
312 |
-
protected static function indent($matches) {
|
313 |
-
$text = $matches[3];
|
314 |
-
$text = preg_replace('|^|m', $matches[2] . ' ', $text);
|
315 |
-
return $matches[1] . $text;
|
316 |
-
}
|
317 |
-
|
318 |
-
protected static function decodeit($matches) {
|
319 |
-
$text = $matches[2];
|
320 |
-
$trans_table = array_flip(get_html_translation_table(HTML_ENTITIES));
|
321 |
-
$text = strtr($text, $trans_table);
|
322 |
-
$text = str_replace('<br />', '', $text);
|
323 |
-
$text = str_replace('&', '&', $text);
|
324 |
-
$text = str_replace(''', "'", $text);
|
325 |
-
if ( '<pre><code>' == $matches[1] )
|
326 |
-
$text = "\n$text\n";
|
327 |
-
return "`$text`";
|
328 |
-
}
|
329 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Custom readme parser
|
4 |
+
*
|
5 |
+
* Based on Automattic_Readme from http://code.google.com/p/wordpress-plugin-readme-parser/
|
6 |
+
*
|
7 |
+
* Relies on Markdown_Extra
|
8 |
+
*
|
9 |
+
* @todo Handle screenshots section properly
|
10 |
+
* @todo Create validator for this based on http://code.google.com/p/wordpress-plugin-readme-parser/source/browse/trunk/validator.php
|
11 |
+
*/
|
12 |
+
class Baikonur_ReadmeParser {
|
13 |
+
|
14 |
+
public static function parse_readme($file) {
|
15 |
+
$contents = file($file);
|
16 |
+
return self::parse_readme_contents($contents);
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function parse_readme_contents($contents) {
|
20 |
+
if (is_string($contents)) {
|
21 |
+
$contents = explode("\n", $contents);
|
22 |
+
}
|
23 |
+
|
24 |
+
$this_class = __CLASS__;
|
25 |
+
if (function_exists('get_called_class')) {
|
26 |
+
$this_class = get_called_class();
|
27 |
+
}
|
28 |
+
|
29 |
+
$contents = array_map(array($this_class, 'strip_newlines'), $contents);
|
30 |
+
|
31 |
+
// Strip BOM
|
32 |
+
if (strpos($contents[0], "\xEF\xBB\xBF") === 0) {
|
33 |
+
$contents[0] = substr($contents[0], 3);
|
34 |
+
}
|
35 |
+
|
36 |
+
$data = new stdClass;
|
37 |
+
|
38 |
+
// Defaults
|
39 |
+
$data->is_excerpt = false;
|
40 |
+
$data->is_truncated = false;
|
41 |
+
$data->tags = array();
|
42 |
+
$data->requires = '';
|
43 |
+
$data->tested = '';
|
44 |
+
$data->contributors = array();
|
45 |
+
$data->stable_tag = '';
|
46 |
+
$data->version = '';
|
47 |
+
$data->donate_link = '';
|
48 |
+
$data->short_description = '';
|
49 |
+
$data->sections = array();
|
50 |
+
$data->changelog = array();
|
51 |
+
$data->upgrade_notice = array();
|
52 |
+
$data->screenshots = array();
|
53 |
+
$data->remaining_content = array();
|
54 |
+
|
55 |
+
$line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
|
56 |
+
$data->name = $line;
|
57 |
+
$data->name = trim($data->name, "#= ");
|
58 |
+
|
59 |
+
// Parse headers
|
60 |
+
$headers = array();
|
61 |
+
|
62 |
+
$line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
|
63 |
+
do {
|
64 |
+
$key = $value = null;
|
65 |
+
if (strpos($line, ':') === false) {
|
66 |
+
break;
|
67 |
+
}
|
68 |
+
$bits = explode(':', $line, 2);
|
69 |
+
list($key, $value) = $bits;
|
70 |
+
$key = strtolower(str_replace(array(' ', "\t"), '_', trim($key)));
|
71 |
+
if ($key === 'tags' && isset($headers['tags'])) {
|
72 |
+
$headers[$key] .= ',' . trim($value);
|
73 |
+
}
|
74 |
+
else {
|
75 |
+
$headers[$key] = trim($value);
|
76 |
+
}
|
77 |
+
}
|
78 |
+
while (($line = array_shift($contents)) !== null && ($line = trim($line)) && !empty($line));
|
79 |
+
array_unshift($contents, $line);
|
80 |
+
|
81 |
+
if (!empty($headers['tags'])) {
|
82 |
+
$data->tags = explode(',', $headers['tags']);
|
83 |
+
$data->tags = array_map('trim', $data->tags);
|
84 |
+
}
|
85 |
+
if (!empty($headers['requires'])) {
|
86 |
+
$data->requires = $headers['requires'];
|
87 |
+
}
|
88 |
+
if (!empty($headers['requires_at_least'])) {
|
89 |
+
$data->requires = $headers['requires_at_least'];
|
90 |
+
}
|
91 |
+
if (!empty($headers['tested'])) {
|
92 |
+
$data->tested = $headers['tested'];
|
93 |
+
}
|
94 |
+
if (!empty($headers['tested_up_to'])) {
|
95 |
+
$data->tested = $headers['tested_up_to'];
|
96 |
+
}
|
97 |
+
if (!empty($headers['contributors'])) {
|
98 |
+
$data->contributors = explode(',', $headers['contributors']);
|
99 |
+
$data->contributors = array_map('trim', $data->contributors);
|
100 |
+
}
|
101 |
+
if (!empty($headers['stable_tag'])) {
|
102 |
+
$data->stable_tag = $headers['stable_tag'];
|
103 |
+
}
|
104 |
+
if (!empty($headers['donate_link'])) {
|
105 |
+
$data->donate_link = $headers['donate_link'];
|
106 |
+
}
|
107 |
+
if (!empty($headers['version'])) {
|
108 |
+
$data->version = $headers['version'];
|
109 |
+
}
|
110 |
+
else {
|
111 |
+
$data->version = $data->stable_tag;
|
112 |
+
}
|
113 |
+
|
114 |
+
// Parse the short description
|
115 |
+
while (($line = array_shift($contents)) !== null) {
|
116 |
+
$trimmed = trim($line);
|
117 |
+
if (empty($trimmed)) {
|
118 |
+
$data->short_description .= "\n";
|
119 |
+
continue;
|
120 |
+
}
|
121 |
+
if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
|
122 |
+
array_unshift($contents, $line);
|
123 |
+
break;
|
124 |
+
}
|
125 |
+
|
126 |
+
$data->short_description .= $line . "\n";
|
127 |
+
}
|
128 |
+
$data->short_description = trim($data->short_description);
|
129 |
+
|
130 |
+
$data->is_truncated = call_user_func_array(array($this_class, 'trim_short_desc'), array(&$data->short_description));
|
131 |
+
|
132 |
+
// Parse the rest of the body
|
133 |
+
$current = '';
|
134 |
+
$special = array('description', 'installation', 'faq', 'frequently_asked_questions', 'screenshots', 'changelog', 'upgrade_notice');
|
135 |
+
|
136 |
+
while (($line = array_shift($contents)) !== null) {
|
137 |
+
$trimmed = trim($line);
|
138 |
+
if (empty($trimmed)) {
|
139 |
+
$current .= "\n";
|
140 |
+
continue;
|
141 |
+
}
|
142 |
+
|
143 |
+
if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
|
144 |
+
if (!empty($title)) {
|
145 |
+
$data->sections[$title] = trim($current);
|
146 |
+
}
|
147 |
+
|
148 |
+
$current = '';
|
149 |
+
$real_title = trim($line, "#= \t");
|
150 |
+
$title = strtolower(str_replace(' ', '_', $real_title));
|
151 |
+
if ($title === 'faq') {
|
152 |
+
$title = 'frequently_asked_questions';
|
153 |
+
}
|
154 |
+
elseif ($title === 'change_log') {
|
155 |
+
$title = 'changelog';
|
156 |
+
}
|
157 |
+
if (!in_array($title, $special)) {
|
158 |
+
$current .= '<h3>' . $real_title . "</h3>";
|
159 |
+
}
|
160 |
+
continue;
|
161 |
+
}
|
162 |
+
|
163 |
+
$current .= $line . "\n";
|
164 |
+
}
|
165 |
+
|
166 |
+
if (!empty($title)) {
|
167 |
+
$data->sections[$title] = trim($current);
|
168 |
+
}
|
169 |
+
$title = null;
|
170 |
+
$current = null;
|
171 |
+
|
172 |
+
if (empty($data->sections['description'])) {
|
173 |
+
$data->sections['description'] = call_user_func(array($this_class, 'parse_markdown'), $data->short_description);
|
174 |
+
}
|
175 |
+
|
176 |
+
// Parse changelog
|
177 |
+
if (!empty($data->sections['changelog'])) {
|
178 |
+
$lines = explode("\n", $data->sections['changelog']);
|
179 |
+
while (($line = array_shift($lines)) !== null) {
|
180 |
+
$trimmed = trim($line);
|
181 |
+
if (empty($trimmed)) {
|
182 |
+
continue;
|
183 |
+
}
|
184 |
+
|
185 |
+
if ($trimmed[0] === '=') {
|
186 |
+
if (!empty($current)) {
|
187 |
+
$data->changelog[$title] = trim($current);
|
188 |
+
}
|
189 |
+
|
190 |
+
$current = '';
|
191 |
+
$title = trim($line, "#= \t");
|
192 |
+
continue;
|
193 |
+
}
|
194 |
+
|
195 |
+
$current .= $line . "\n";
|
196 |
+
}
|
197 |
+
|
198 |
+
$data->changelog[$title] = trim($current);
|
199 |
+
}
|
200 |
+
$title = null;
|
201 |
+
$current = null;
|
202 |
+
|
203 |
+
if (isset($data->sections['upgrade_notice'])) {
|
204 |
+
$lines = explode("\n", $data->sections['upgrade_notice']);
|
205 |
+
while (($line = array_shift($lines)) !== null) {
|
206 |
+
$trimmed = trim($line);
|
207 |
+
if (empty($trimmed)) {
|
208 |
+
continue;
|
209 |
+
}
|
210 |
+
|
211 |
+
if ($trimmed[0] === '=') {
|
212 |
+
if (!empty($current)) {
|
213 |
+
$data->upgrade_notice[$title] = trim($current);
|
214 |
+
}
|
215 |
+
|
216 |
+
$current = '';
|
217 |
+
$title = trim($line, "#= \t");
|
218 |
+
continue;
|
219 |
+
}
|
220 |
+
|
221 |
+
$current .= $line . "\n";
|
222 |
+
}
|
223 |
+
|
224 |
+
if (!empty($title) && !empty($current)) {
|
225 |
+
$data->upgrade_notice[$title] = trim($current);
|
226 |
+
}
|
227 |
+
unset($data->sections['upgrade_notice']);
|
228 |
+
}
|
229 |
+
|
230 |
+
// Markdownify!
|
231 |
+
|
232 |
+
$data->sections = array_map(array($this_class, 'parse_markdown'), $data->sections);
|
233 |
+
$data->changelog = array_map(array($this_class, 'parse_markdown'), $data->changelog);
|
234 |
+
$data->upgrade_notice = array_map(array($this_class, 'parse_markdown'), $data->upgrade_notice);
|
235 |
+
|
236 |
+
if (isset($data->sections['screenshots'])) {
|
237 |
+
preg_match_all('#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER);
|
238 |
+
if ($screenshots) {
|
239 |
+
foreach ((array) $screenshots as $ss) {
|
240 |
+
$data->screenshots[] = trim($ss[1]);
|
241 |
+
}
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
+
// Rearrange stuff
|
246 |
+
|
247 |
+
$data->remaining_content = $data->sections;
|
248 |
+
$data->sections = array();
|
249 |
+
|
250 |
+
foreach ($special as $spec) {
|
251 |
+
if (isset($data->remaining_content[$spec])) {
|
252 |
+
$data->sections[$spec] = $data->remaining_content[$spec];
|
253 |
+
unset($data->remaining_content[$spec]);
|
254 |
+
}
|
255 |
+
}
|
256 |
+
|
257 |
+
return $data;
|
258 |
+
}
|
259 |
+
|
260 |
+
protected static function get_first_nonwhitespace(&$contents) {
|
261 |
+
while (($line = array_shift($contents)) !== null) {
|
262 |
+
$trimmed = trim($line);
|
263 |
+
if (!empty($line)) {
|
264 |
+
break;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
return $line;
|
269 |
+
}
|
270 |
+
|
271 |
+
protected static function strip_newlines($line) {
|
272 |
+
return rtrim($line, "\r\n");
|
273 |
+
}
|
274 |
+
|
275 |
+
protected static function trim_short_desc(&$desc) {
|
276 |
+
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
277 |
+
if (mb_strlen($desc) > 150) {
|
278 |
+
$desc = mb_substr($desc, 0, 150);
|
279 |
+
$desc = trim($desc);
|
280 |
+
return true;
|
281 |
+
}
|
282 |
+
}
|
283 |
+
else {
|
284 |
+
if (strlen($desc) > 150) {
|
285 |
+
$desc = substr($desc, 0, 150);
|
286 |
+
$desc = trim($desc);
|
287 |
+
return true;
|
288 |
+
}
|
289 |
+
}
|
290 |
+
|
291 |
+
return false;
|
292 |
+
}
|
293 |
+
|
294 |
+
protected static function parse_markdown($text) {
|
295 |
+
$text = self::code_trick($text);
|
296 |
+
$text = preg_replace('/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text);
|
297 |
+
$text = Markdown(trim($text));
|
298 |
+
return trim($text);
|
299 |
+
}
|
300 |
+
|
301 |
+
protected static function code_trick($text) {
|
302 |
+
// If doing markdown, first take any user formatted code blocks and turn them into backticks so that
|
303 |
+
// markdown will preserve things like underscores in code blocks
|
304 |
+
$text = preg_replace_callback("!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array(__CLASS__, 'decodeit'), $text);
|
305 |
+
|
306 |
+
$text = str_replace(array("\r\n", "\r"), "\n", $text);
|
307 |
+
// Markdown can do inline code, we convert bbPress style block level code to Markdown style
|
308 |
+
$text = preg_replace_callback("!(^|\n)([ \t]*?)`(.*?)`!s", array(__CLASS__, 'indent'), $text);
|
309 |
+
return $text;
|
310 |
+
}
|
311 |
+
|
312 |
+
protected static function indent($matches) {
|
313 |
+
$text = $matches[3];
|
314 |
+
$text = preg_replace('|^|m', $matches[2] . ' ', $text);
|
315 |
+
return $matches[1] . $text;
|
316 |
+
}
|
317 |
+
|
318 |
+
protected static function decodeit($matches) {
|
319 |
+
$text = $matches[2];
|
320 |
+
$trans_table = array_flip(get_html_translation_table(HTML_ENTITIES));
|
321 |
+
$text = strtr($text, $trans_table);
|
322 |
+
$text = str_replace('<br />', '', $text);
|
323 |
+
$text = str_replace('&', '&', $text);
|
324 |
+
$text = str_replace(''', "'", $text);
|
325 |
+
if ( '<pre><code>' == $matches[1] )
|
326 |
+
$text = "\n$text\n";
|
327 |
+
return "`$text`";
|
328 |
+
}
|
329 |
}
|
includes/libraries/browser.php
CHANGED
@@ -1,1082 +1,1082 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Modified to remove var
|
4 |
-
* Chris Christoff on 12/26/2012
|
5 |
-
* Changes: Changes vars to publics
|
6 |
-
*
|
7 |
-
* Modified to work for EDD by
|
8 |
-
* Chris Christoff on 12/23/2012
|
9 |
-
* Changes: Removed the browser string return and added spacing. Also removed return HTML formatting.
|
10 |
-
*
|
11 |
-
* Modified to add formatted User Agent string for EDD System Info by
|
12 |
-
* Chris Christoff on 12/23/2012
|
13 |
-
* Changes: Split user string and add formatting so we can print a nicely
|
14 |
-
* formatted user agent string on the EDD System Info
|
15 |
-
*
|
16 |
-
* File: Browser.php
|
17 |
-
* Author: Chris Schuld (http://chrisschuld.com/)
|
18 |
-
* Last Modified: August 20th, 2010
|
19 |
-
* @version 1.9
|
20 |
-
* @package PegasusPHP
|
21 |
-
*
|
22 |
-
* Copyright (C) 2008-2010 Chris Schuld (chris@chrisschuld.com)
|
23 |
-
*
|
24 |
-
* This program is free software; you can redistribute it and/or
|
25 |
-
* modify it under the terms of the GNU General Public License as
|
26 |
-
* published by the Free Software Foundation; either version 2 of
|
27 |
-
* the License, or (at your option) any later version.
|
28 |
-
*
|
29 |
-
* This program is distributed in the hope that it will be useful,
|
30 |
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
31 |
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
32 |
-
* GNU General Public License for more details at:
|
33 |
-
* http://www.gnu.org/copyleft/gpl.html
|
34 |
-
*
|
35 |
-
*
|
36 |
-
* Typical Usage:
|
37 |
-
*
|
38 |
-
* $browser = new Browser();
|
39 |
-
* if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
|
40 |
-
* echo 'You have FireFox version 2 or greater';
|
41 |
-
* }
|
42 |
-
*
|
43 |
-
* User Agents Sampled from: http://www.useragentstring.com/
|
44 |
-
*
|
45 |
-
* This implementation is based on the original work from Gary White
|
46 |
-
* http://apptools.com/phptools/browser/
|
47 |
-
*
|
48 |
-
* UPDATES:
|
49 |
-
*
|
50 |
-
* 2010-08-20 (v1.9):
|
51 |
-
* + Added MSN Explorer Browser (legacy)
|
52 |
-
* + Added Bing/MSN Robot (Thanks Rob MacDonald)
|
53 |
-
* + Added the Android Platform (PLATFORM_ANDROID)
|
54 |
-
* + Fixed issue with Android 1.6/2.2 (Thanks Tom Hirashima)
|
55 |
-
*
|
56 |
-
* 2010-04-27 (v1.8):
|
57 |
-
* + Added iPad Support
|
58 |
-
*
|
59 |
-
* 2010-03-07 (v1.7):
|
60 |
-
* + *MAJOR* Rebuild (preg_match and other "slow" routine removal(s))
|
61 |
-
* + Almost allof Gary's original code has been replaced
|
62 |
-
* + Large PHPUNIT testing environment created to validate new releases and additions
|
63 |
-
* + Added FreeBSD Platform
|
64 |
-
* + Added OpenBSD Platform
|
65 |
-
* + Added NetBSD Platform
|
66 |
-
* + Added SunOS Platform
|
67 |
-
* + Added OpenSolaris Platform
|
68 |
-
* + Added support of the Iceweazel Browser
|
69 |
-
* + Added isChromeFrame() call to check if chromeframe is in use
|
70 |
-
* + Moved the Opera check in front of the Firefox check due to legacy Opera User Agents
|
71 |
-
* + Added the __toString() method (Thanks Deano)
|
72 |
-
*
|
73 |
-
* 2009-11-15:
|
74 |
-
* + Updated the checkes for Firefox
|
75 |
-
* + Added the NOKIA platform
|
76 |
-
* + Added Checks for the NOKIA brower(s)
|
77 |
-
*
|
78 |
-
* 2009-11-08:
|
79 |
-
* + PHP 5.3 Support
|
80 |
-
* + Added support for BlackBerry OS and BlackBerry browser
|
81 |
-
* + Added support for the Opera Mini browser
|
82 |
-
* + Added additional documenation
|
83 |
-
* + Added support for isRobot() and isMobile()
|
84 |
-
* + Added support for Opera version 10
|
85 |
-
* + Added support for deprecated Netscape Navigator version 9
|
86 |
-
* + Added support for IceCat
|
87 |
-
* + Added support for Shiretoko
|
88 |
-
*
|
89 |
-
* 2010-04-27 (v1.8):
|
90 |
-
* + Added iPad Support
|
91 |
-
*
|
92 |
-
* 2009-08-18:
|
93 |
-
* + Updated to support PHP 5.3 - removed all deprecated function calls
|
94 |
-
* + Updated to remove all double quotes (") -- converted to single quotes (')
|
95 |
-
*
|
96 |
-
* 2009-04-27:
|
97 |
-
* + Updated the IE check to remove a typo and bug (thanks John)
|
98 |
-
*
|
99 |
-
* 2009-04-22:
|
100 |
-
* + Added detection for GoogleBot
|
101 |
-
* + Added detection for the W3C Validator.
|
102 |
-
* + Added detection for Yahoo! Slurp
|
103 |
-
*
|
104 |
-
* 2009-03-14:
|
105 |
-
* + Added detection for iPods.
|
106 |
-
* + Added Platform detection for iPhones
|
107 |
-
* + Added Platform detection for iPods
|
108 |
-
*
|
109 |
-
* 2009-02-16: (Rick Hale)
|
110 |
-
* + Added version detection for Android phones.
|
111 |
-
*
|
112 |
-
* 2008-12-09:
|
113 |
-
* + Removed unused constant
|
114 |
-
*
|
115 |
-
* 2008-11-07:
|
116 |
-
* + Added Google's Chrome to the detection list
|
117 |
-
* + Added isBrowser(string) to the list of functions special thanks to
|
118 |
-
* Daniel 'mavrick' Lang for the function concept (http://mavrick.id.au)
|
119 |
-
*
|
120 |
-
*
|
121 |
-
* Gary White noted: "Since browser detection is so unreliable, I am
|
122 |
-
* no longer maintaining this script. You are free to use and or
|
123 |
-
* modify/update it as you want, however the author assumes no
|
124 |
-
* responsibility for the accuracy of the detected values."
|
125 |
-
*
|
126 |
-
* Anyone experienced with Gary's script might be interested in these notes:
|
127 |
-
*
|
128 |
-
* Added class constants
|
129 |
-
* Added detection and version detection for Google's Chrome
|
130 |
-
* Updated the version detection for Amaya
|
131 |
-
* Updated the version detection for Firefox
|
132 |
-
* Updated the version detection for Lynx
|
133 |
-
* Updated the version detection for WebTV
|
134 |
-
* Updated the version detection for NetPositive
|
135 |
-
* Updated the version detection for IE
|
136 |
-
* Updated the version detection for OmniWeb
|
137 |
-
* Updated the version detection for iCab
|
138 |
-
* Updated the version detection for Safari
|
139 |
-
* Updated Safari to remove mobile devices (iPhone)
|
140 |
-
* Added detection for iPhone
|
141 |
-
* Added detection for robots
|
142 |
-
* Added detection for mobile devices
|
143 |
-
* Added detection for BlackBerry
|
144 |
-
* Removed Netscape checks (matches heavily with firefox & mozilla)
|
145 |
-
*
|
146 |
-
*/
|
147 |
-
|
148 |
-
class Browser {
|
149 |
-
public $_agent = '';
|
150 |
-
public $_browser_name = '';
|
151 |
-
public $_version = '';
|
152 |
-
public $_platform = '';
|
153 |
-
public $_os = '';
|
154 |
-
public $_is_aol = false;
|
155 |
-
public $_is_mobile = false;
|
156 |
-
public $_is_robot = false;
|
157 |
-
public $_aol_version = '';
|
158 |
-
|
159 |
-
public $BROWSER_UNKNOWN = 'unknown';
|
160 |
-
public $VERSION_UNKNOWN = 'unknown';
|
161 |
-
|
162 |
-
public $BROWSER_OPERA = 'Opera'; // Http://www.opera.com/
|
163 |
-
public $BROWSER_OPERA_MINI = 'Opera Mini'; // Http://www.opera.com/mini/
|
164 |
-
public $BROWSER_WEBTV = 'WebTV'; // Http://www.webtv.net/pc/
|
165 |
-
public $BROWSER_IE = 'Internet Explorer'; // Http://www.microsoft.com/ie/
|
166 |
-
public $BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // Http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
|
167 |
-
public $BROWSER_KONQUEROR = 'Konqueror'; // Http://www.konqueror.org/
|
168 |
-
public $BROWSER_ICAB = 'iCab'; // Http://www.icab.de/
|
169 |
-
public $BROWSER_OMNIWEB = 'OmniWeb'; // Http://www.omnigroup.com/applications/omniweb/
|
170 |
-
public $BROWSER_FIREBIRD = 'Firebird'; // Http://www.ibphoenix.com/
|
171 |
-
public $BROWSER_FIREFOX = 'Firefox'; // Http://www.mozilla.com/en-US/firefox/firefox.html
|
172 |
-
public $BROWSER_ICEWEASEL = 'Iceweasel'; // Http://www.geticeweasel.org/
|
173 |
-
public $BROWSER_SHIRETOKO = 'Shiretoko'; // Http://wiki.mozilla.org/Projects/shiretoko
|
174 |
-
public $BROWSER_MOZILLA = 'Mozilla'; // Http://www.mozilla.com/en-US/
|
175 |
-
public $BROWSER_AMAYA = 'Amaya'; // Http://www.w3.org/Amaya/
|
176 |
-
public $BROWSER_LYNX = 'Lynx'; // Http://en.wikipedia.org/wiki/Lynx
|
177 |
-
public $BROWSER_SAFARI = 'Safari'; // Http://apple.com
|
178 |
-
public $BROWSER_IPHONE = 'iPhone'; // Http://apple.com
|
179 |
-
public $BROWSER_IPOD = 'iPod'; // Http://apple.com
|
180 |
-
public $BROWSER_IPAD = 'iPad'; // Http://apple.com
|
181 |
-
public $BROWSER_CHROME = 'Chrome'; // Http://www.google.com/chrome
|
182 |
-
public $BROWSER_ANDROID = 'Android'; // Http://www.android.com/
|
183 |
-
public $BROWSER_GOOGLEBOT = 'GoogleBot'; // Http://en.wikipedia.org/wiki/Googlebot
|
184 |
-
public $BROWSER_SLURP = 'Yahoo! Slurp'; // Http://en.wikipedia.org/wiki/Yahoo!_Slurp
|
185 |
-
public $BROWSER_W3CVALIDATOR = 'W3C Validator'; // Http://validator.w3.org/
|
186 |
-
public $BROWSER_BLACKBERRY = 'BlackBerry'; // Http://www.blackberry.com/
|
187 |
-
public $BROWSER_ICECAT = 'IceCat'; // Http://en.wikipedia.org/wiki/GNU_IceCat
|
188 |
-
public $BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // Http://en.wikipedia.org/wiki/Web_Browser_for_S60
|
189 |
-
public $BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
|
190 |
-
public $BROWSER_MSN = 'MSN Browser'; // Http://explorer.msn.com/
|
191 |
-
public $BROWSER_MSNBOT = 'MSN Bot'; // Http://search.msn.com/msnbot.htm
|
192 |
-
// Http://en.wikipedia.org/wiki/Msnbot (used for Bing as well)
|
193 |
-
|
194 |
-
public $BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // Http://browser.netscape.com/ (DEPRECATED)
|
195 |
-
public $BROWSER_GALEON = 'Galeon'; // Http://galeon.sourceforge.net/ (DEPRECATED)
|
196 |
-
public $BROWSER_NETPOSITIVE = 'NetPositive'; // Http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
|
197 |
-
public $BROWSER_PHOENIX = 'Phoenix'; // Http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
|
198 |
-
|
199 |
-
public $PLATFORM_UNKNOWN = 'unknown';
|
200 |
-
public $PLATFORM_WINDOWS = 'Windows';
|
201 |
-
public $PLATFORM_WINDOWS_CE = 'Windows CE';
|
202 |
-
public $PLATFORM_APPLE = 'Apple';
|
203 |
-
public $PLATFORM_LINUX = 'Linux';
|
204 |
-
public $PLATFORM_OS2 = 'OS/2';
|
205 |
-
public $PLATFORM_BEOS = 'BeOS';
|
206 |
-
public $PLATFORM_IPHONE = 'iPhone';
|
207 |
-
public $PLATFORM_IPOD = 'iPod';
|
208 |
-
public $PLATFORM_IPAD = 'iPad';
|
209 |
-
public $PLATFORM_BLACKBERRY = 'BlackBerry';
|
210 |
-
public $PLATFORM_NOKIA = 'Nokia';
|
211 |
-
public $PLATFORM_FREEBSD = 'FreeBSD';
|
212 |
-
public $PLATFORM_OPENBSD = 'OpenBSD';
|
213 |
-
public $PLATFORM_NETBSD = 'NetBSD';
|
214 |
-
public $PLATFORM_SUNOS = 'SunOS';
|
215 |
-
public $PLATFORM_OPENSOLARIS = 'OpenSolaris';
|
216 |
-
public $PLATFORM_ANDROID = 'Android';
|
217 |
-
|
218 |
-
public $OPERATING_SYSTEM_UNKNOWN = 'unknown';
|
219 |
-
|
220 |
-
function Browser($useragent="") {
|
221 |
-
$this->reset();
|
222 |
-
if( $useragent != "" ) {
|
223 |
-
$this->setUserAgent($useragent);
|
224 |
-
}
|
225 |
-
else {
|
226 |
-
$this->determine();
|
227 |
-
}
|
228 |
-
}
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Reset all properties
|
232 |
-
*/
|
233 |
-
function reset() {
|
234 |
-
$this->_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
|
235 |
-
$this->_browser_name = $this->BROWSER_UNKNOWN;
|
236 |
-
$this->_version = $this->VERSION_UNKNOWN;
|
237 |
-
$this->_platform = $this->PLATFORM_UNKNOWN;
|
238 |
-
$this->_os = $this->OPERATING_SYSTEM_UNKNOWN;
|
239 |
-
$this->_is_aol = false;
|
240 |
-
$this->_is_mobile = false;
|
241 |
-
$this->_is_robot = false;
|
242 |
-
$this->_aol_version = $this->VERSION_UNKNOWN;
|
243 |
-
}
|
244 |
-
|
245 |
-
/**
|
246 |
-
* Check to see if the specific browser is valid
|
247 |
-
* @param string $browserName
|
248 |
-
* @return True if the browser is the specified browser
|
249 |
-
*/
|
250 |
-
function isBrowser($browserName) { return( 0 == strcasecmp($this->_browser_name, trim($browserName))); }
|
251 |
-
|
252 |
-
/**
|
253 |
-
* The name of the browser. All return types are from the class contants
|
254 |
-
* @return string Name of the browser
|
255 |
-
*/
|
256 |
-
function getBrowser() { return $this->_browser_name; }
|
257 |
-
/**
|
258 |
-
* Set the name of the browser
|
259 |
-
* @param $browser The name of the Browser
|
260 |
-
*/
|
261 |
-
function setBrowser($browser) { return $this->_browser_name = $browser; }
|
262 |
-
/**
|
263 |
-
* The name of the platform. All return types are from the class contants
|
264 |
-
* @return string Name of the browser
|
265 |
-
*/
|
266 |
-
function getPlatform() { return $this->_platform; }
|
267 |
-
/**
|
268 |
-
* Set the name of the platform
|
269 |
-
* @param $platform The name of the Platform
|
270 |
-
*/
|
271 |
-
function setPlatform($platform) { return $this->_platform = $platform; }
|
272 |
-
/**
|
273 |
-
* The version of the browser.
|
274 |
-
* @return string Version of the browser (will only contain alpha-numeric characters and a period)
|
275 |
-
*/
|
276 |
-
function getVersion() { return $this->_version; }
|
277 |
-
/**
|
278 |
-
* Set the version of the browser
|
279 |
-
* @param $version The version of the Browser
|
280 |
-
*/
|
281 |
-
function setVersion($version) { $this->_version = preg_replace('/[^0-9,.,a-z,A-Z-]/','',$version); }
|
282 |
-
/**
|
283 |
-
* The version of AOL.
|
284 |
-
* @return string Version of AOL (will only contain alpha-numeric characters and a period)
|
285 |
-
*/
|
286 |
-
function getAolVersion() { return $this->_aol_version; }
|
287 |
-
/**
|
288 |
-
* Set the version of AOL
|
289 |
-
* @param $version The version of AOL
|
290 |
-
*/
|
291 |
-
function setAolVersion($version) { $this->_aol_version = preg_replace('/[^0-9,.,a-z,A-Z]/','',$version); }
|
292 |
-
/**
|
293 |
-
* Is the browser from AOL?
|
294 |
-
* @return boolean True if the browser is from AOL otherwise false
|
295 |
-
*/
|
296 |
-
function isAol() { return $this->_is_aol; }
|
297 |
-
/**
|
298 |
-
* Is the browser from a mobile device?
|
299 |
-
* @return boolean True if the browser is from a mobile device otherwise false
|
300 |
-
*/
|
301 |
-
function isMobile() { return $this->_is_mobile; }
|
302 |
-
/**
|
303 |
-
* Is the browser from a robot (ex Slurp,GoogleBot)?
|
304 |
-
* @return boolean True if the browser is from a robot otherwise false
|
305 |
-
*/
|
306 |
-
function isRobot() { return $this->_is_robot; }
|
307 |
-
/**
|
308 |
-
* Set the browser to be from AOL
|
309 |
-
* @param $isAol
|
310 |
-
*/
|
311 |
-
function setAol($isAol) { $this->_is_aol = $isAol; }
|
312 |
-
/**
|
313 |
-
* Set the Browser to be mobile
|
314 |
-
* @param boolean $value is the browser a mobile brower or not
|
315 |
-
*/
|
316 |
-
function setMobile($value=true) { $this->_is_mobile = $value; }
|
317 |
-
/**
|
318 |
-
* Set the Browser to be a robot
|
319 |
-
* @param boolean $value is the browser a robot or not
|
320 |
-
*/
|
321 |
-
function setRobot($value=true) { $this->_is_robot = $value; }
|
322 |
-
/**
|
323 |
-
* Get the user agent value in use to determine the browser
|
324 |
-
* @return string The user agent from the HTTP header
|
325 |
-
*/
|
326 |
-
function getUserAgent() { return $this->_agent; }
|
327 |
-
/**
|
328 |
-
* Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
|
329 |
-
* @param $agent_string The value for the User Agent
|
330 |
-
*/
|
331 |
-
function setUserAgent($agent_string) {
|
332 |
-
$this->reset();
|
333 |
-
$this->_agent = $agent_string;
|
334 |
-
$this->determine();
|
335 |
-
}
|
336 |
-
/**
|
337 |
-
* Used to determine if the browser is actually "chromeframe"
|
338 |
-
* @since 1.7
|
339 |
-
* @return boolean True if the browser is using chromeframe
|
340 |
-
*/
|
341 |
-
function isChromeFrame() {
|
342 |
-
return( strpos($this->_agent,"chromeframe") !== false );
|
343 |
-
}
|
344 |
-
/**
|
345 |
-
* Returns a formatted string with a summary of the details of the browser.
|
346 |
-
* @return string formatted string with a summary of the browser
|
347 |
-
*/
|
348 |
-
function __toString() {
|
349 |
-
$text1 = $this->getUserAgent(); //grabs the UA (user agent) string
|
350 |
-
$UAline1 = substr($text1, 0, 32); //the first line we print should only be the first 32 characters of the UA string
|
351 |
-
$text2 = $this->getUserAgent();//now we grab it again and save it to a string
|
352 |
-
$towrapUA = str_replace($UAline1, '', $text2);//the rest of the printoff (other than first line) is equivolent
|
353 |
-
// To the whole string minus the part we printed off. IE
|
354 |
-
// User Agent: thefirst32charactersfromUAline1
|
355 |
-
// the rest of it is now stored in
|
356 |
-
// $text2 to be printed off
|
357 |
-
// But we need to add spaces before each line that is split other than line 1
|
358 |
-
$space = '';
|
359 |
-
for($i = 0; $i < 25; $i++) {
|
360 |
-
$space .= ' ';
|
361 |
-
}
|
362 |
-
// Now we split the remaining string of UA ($text2) into lines that are prefixed by spaces for formatting
|
363 |
-
$wordwrapped = chunk_split($towrapUA, 32, "\n $space");
|
364 |
-
return "Platform: {$this->getPlatform()} \n".
|
365 |
-
"Browser Name: {$this->getBrowser()} \n" .
|
366 |
-
"Browser Version: {$this->getVersion()} \n" .
|
367 |
-
"User Agent String: $UAline1 \n\t\t\t " .
|
368 |
-
"$wordwrapped";
|
369 |
-
}
|
370 |
-
/**
|
371 |
-
* Protected routine to calculate and determine what the browser is in use (including platform)
|
372 |
-
*/
|
373 |
-
function determine() {
|
374 |
-
$this->checkPlatform();
|
375 |
-
$this->checkBrowsers();
|
376 |
-
$this->checkForAol();
|
377 |
-
}
|
378 |
-
/**
|
379 |
-
* Protected routine to determine the browser type
|
380 |
-
* @return boolean True if the browser was detected otherwise false
|
381 |
-
*/
|
382 |
-
function checkBrowsers() {
|
383 |
-
return (
|
384 |
-
// Well-known, well-used
|
385 |
-
// Special Notes:
|
386 |
-
// (1) Opera must be checked before FireFox due to the odd
|
387 |
-
// user agents used in some older versions of Opera
|
388 |
-
// (2) WebTV is strapped onto Internet Explorer so we must
|
389 |
-
// check for WebTV before IE
|
390 |
-
// (3) (deprecated) Galeon is based on Firefox and needs to be
|
391 |
-
// tested before Firefox is tested
|
392 |
-
// (4) OmniWeb is based on Safari so OmniWeb check must occur
|
393 |
-
// before Safari
|
394 |
-
// (5) Netscape 9+ is based on Firefox so Netscape checks
|
395 |
-
// before FireFox are necessary
|
396 |
-
$this->checkBrowserWebTv() ||
|
397 |
-
$this->checkBrowserInternetExplorer() ||
|
398 |
-
$this->checkBrowserOpera() ||
|
399 |
-
$this->checkBrowserGaleon() ||
|
400 |
-
$this->checkBrowserNetscapeNavigator9Plus() ||
|
401 |
-
$this->checkBrowserFirefox() ||
|
402 |
-
$this->checkBrowserChrome() ||
|
403 |
-
$this->checkBrowserOmniWeb() ||
|
404 |
-
|
405 |
-
// Common mobile
|
406 |
-
$this->checkBrowserAndroid() ||
|
407 |
-
$this->checkBrowseriPad() ||
|
408 |
-
$this->checkBrowseriPod() ||
|
409 |
-
$this->checkBrowseriPhone() ||
|
410 |
-
$this->checkBrowserBlackBerry() ||
|
411 |
-
$this->checkBrowserNokia() ||
|
412 |
-
|
413 |
-
// Common bots
|
414 |
-
$this->checkBrowserGoogleBot() ||
|
415 |
-
$this->checkBrowserMSNBot() ||
|
416 |
-
$this->checkBrowserSlurp() ||
|
417 |
-
|
418 |
-
// WebKit base check (post mobile and others)
|
419 |
-
$this->checkBrowserSafari() ||
|
420 |
-
|
421 |
-
// Everyone else
|
422 |
-
$this->checkBrowserNetPositive() ||
|
423 |
-
$this->checkBrowserFirebird() ||
|
424 |
-
$this->checkBrowserKonqueror() ||
|
425 |
-
$this->checkBrowserIcab() ||
|
426 |
-
$this->checkBrowserPhoenix() ||
|
427 |
-
$this->checkBrowserAmaya() ||
|
428 |
-
$this->checkBrowserLynx() ||
|
429 |
-
|
430 |
-
$this->checkBrowserShiretoko() ||
|
431 |
-
$this->checkBrowserIceCat() ||
|
432 |
-
$this->checkBrowserW3CValidator() ||
|
433 |
-
$this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
|
434 |
-
);
|
435 |
-
}
|
436 |
-
|
437 |
-
/**
|
438 |
-
* Determine if the user is using a BlackBerry (last updated 1.7)
|
439 |
-
* @return boolean True if the browser is the BlackBerry browser otherwise false
|
440 |
-
*/
|
441 |
-
function checkBrowserBlackBerry() {
|
442 |
-
if( stripos($this->_agent,'blackberry') !== false ) {
|
443 |
-
$aresult = explode("/",stristr($this->_agent,"BlackBerry"));
|
444 |
-
$aversion = explode(' ',$aresult[1]);
|
445 |
-
$this->setVersion($aversion[0]);
|
446 |
-
$this->_browser_name = $this->BROWSER_BLACKBERRY;
|
447 |
-
$this->setMobile(true);
|
448 |
-
return true;
|
449 |
-
}
|
450 |
-
return false;
|
451 |
-
}
|
452 |
-
|
453 |
-
/**
|
454 |
-
* Determine if the user is using an AOL User Agent (last updated 1.7)
|
455 |
-
* @return boolean True if the browser is from AOL otherwise false
|
456 |
-
*/
|
457 |
-
function checkForAol() {
|
458 |
-
$this->setAol(false);
|
459 |
-
$this->setAolVersion($this->VERSION_UNKNOWN);
|
460 |
-
|
461 |
-
if( stripos($this->_agent,'aol') !== false ) {
|
462 |
-
$aversion = explode(' ',stristr($this->_agent, 'AOL'));
|
463 |
-
$this->setAol(true);
|
464 |
-
$this->setAolVersion(preg_replace('/[^0-9\.a-z]/i', '', $aversion[1]));
|
465 |
-
return true;
|
466 |
-
}
|
467 |
-
return false;
|
468 |
-
}
|
469 |
-
|
470 |
-
/**
|
471 |
-
* Determine if the browser is the GoogleBot or not (last updated 1.7)
|
472 |
-
* @return boolean True if the browser is the GoogletBot otherwise false
|
473 |
-
*/
|
474 |
-
function checkBrowserGoogleBot() {
|
475 |
-
if( stripos($this->_agent,'googlebot') !== false ) {
|
476 |
-
$aresult = explode('/',stristr($this->_agent,'googlebot'));
|
477 |
-
$aversion = explode(' ',$aresult[1]);
|
478 |
-
$this->setVersion(str_replace(';','',$aversion[0]));
|
479 |
-
$this->_browser_name = $this->BROWSER_GOOGLEBOT;
|
480 |
-
$this->setRobot(true);
|
481 |
-
return true;
|
482 |
-
}
|
483 |
-
return false;
|
484 |
-
}
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Determine if the browser is the MSNBot or not (last updated 1.9)
|
488 |
-
* @return boolean True if the browser is the MSNBot otherwise false
|
489 |
-
*/
|
490 |
-
function checkBrowserMSNBot() {
|
491 |
-
if( stripos($this->_agent,"msnbot") !== false ) {
|
492 |
-
$aresult = explode("/",stristr($this->_agent,"msnbot"));
|
493 |
-
$aversion = explode(" ",$aresult[1]);
|
494 |
-
$this->setVersion(str_replace(";","",$aversion[0]));
|
495 |
-
$this->_browser_name = $this->BROWSER_MSNBOT;
|
496 |
-
$this->setRobot(true);
|
497 |
-
return true;
|
498 |
-
}
|
499 |
-
return false;
|
500 |
-
}
|
501 |
-
|
502 |
-
/**
|
503 |
-
* Determine if the browser is the W3C Validator or not (last updated 1.7)
|
504 |
-
* @return boolean True if the browser is the W3C Validator otherwise false
|
505 |
-
*/
|
506 |
-
function checkBrowserW3CValidator() {
|
507 |
-
if( stripos($this->_agent,'W3C-checklink') !== false ) {
|
508 |
-
$aresult = explode('/',stristr($this->_agent,'W3C-checklink'));
|
509 |
-
$aversion = explode(' ',$aresult[1]);
|
510 |
-
$this->setVersion($aversion[0]);
|
511 |
-
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
512 |
-
return true;
|
513 |
-
}
|
514 |
-
else if( stripos($this->_agent,'W3C_Validator') !== false ) {
|
515 |
-
// Some of the Validator versions do not delineate w/ a slash - add it back in
|
516 |
-
$ua = str_replace("W3C_Validator ", "W3C_Validator/", $this->_agent);
|
517 |
-
$aresult = explode('/',stristr($ua,'W3C_Validator'));
|
518 |
-
$aversion = explode(' ',$aresult[1]);
|
519 |
-
$this->setVersion($aversion[0]);
|
520 |
-
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
521 |
-
return true;
|
522 |
-
}
|
523 |
-
return false;
|
524 |
-
}
|
525 |
-
|
526 |
-
/**
|
527 |
-
* Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
|
528 |
-
* @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
|
529 |
-
*/
|
530 |
-
function checkBrowserSlurp() {
|
531 |
-
if( stripos($this->_agent,'slurp') !== false ) {
|
532 |
-
$aresult = explode('/',stristr($this->_agent,'Slurp'));
|
533 |
-
$aversion = explode(' ',$aresult[1]);
|
534 |
-
$this->setVersion($aversion[0]);
|
535 |
-
$this->_browser_name = $this->BROWSER_SLURP;
|
536 |
-
$this->setRobot(true);
|
537 |
-
$this->setMobile(false);
|
538 |
-
return true;
|
539 |
-
}
|
540 |
-
return false;
|
541 |
-
}
|
542 |
-
|
543 |
-
/**
|
544 |
-
* Determine if the browser is Internet Explorer or not (last updated 1.7)
|
545 |
-
* @return boolean True if the browser is Internet Explorer otherwise false
|
546 |
-
*/
|
547 |
-
function checkBrowserInternetExplorer() {
|
548 |
-
|
549 |
-
// Test for v1 - v1.5 IE
|
550 |
-
if( stripos($this->_agent,'microsoft internet explorer') !== false ) {
|
551 |
-
$this->setBrowser($this->BROWSER_IE);
|
552 |
-
$this->setVersion('1.0');
|
553 |
-
$aresult = stristr($this->_agent, '/');
|
554 |
-
if( preg_match('/308|425|426|474|0b1/i', $aresult) ) {
|
555 |
-
$this->setVersion('1.5');
|
556 |
-
}
|
557 |
-
return true;
|
558 |
-
}
|
559 |
-
// Test for versions > 1.5
|
560 |
-
else if( stripos($this->_agent,'msie') !== false && stripos($this->_agent,'opera') === false ) {
|
561 |
-
// See if the browser is the odd MSN Explorer
|
562 |
-
if( stripos($this->_agent,'msnb') !== false ) {
|
563 |
-
$aresult = explode(' ',stristr(str_replace(';','; ',$this->_agent),'MSN'));
|
564 |
-
$this->setBrowser( $this->BROWSER_MSN );
|
565 |
-
$this->setVersion(str_replace(array('(',')',';'),'',$aresult[1]));
|
566 |
-
return true;
|
567 |
-
}
|
568 |
-
$aresult = explode(' ',stristr(str_replace(';','; ',$this->_agent),'msie'));
|
569 |
-
$this->setBrowser( $this->BROWSER_IE );
|
570 |
-
$this->setVersion(str_replace(array('(',')',';'),'',$aresult[1]));
|
571 |
-
return true;
|
572 |
-
}
|
573 |
-
// Test for Pocket IE
|
574 |
-
else if( stripos($this->_agent,'mspie') !== false || stripos($this->_agent,'pocket') !== false ) {
|
575 |
-
$aresult = explode(' ',stristr($this->_agent,'mspie'));
|
576 |
-
$this->setPlatform( $this->PLATFORM_WINDOWS_CE );
|
577 |
-
$this->setBrowser( $this->BROWSER_POCKET_IE );
|
578 |
-
$this->setMobile(true);
|
579 |
-
|
580 |
-
if( stripos($this->_agent,'mspie') !== false ) {
|
581 |
-
$this->setVersion($aresult[1]);
|
582 |
-
}
|
583 |
-
else {
|
584 |
-
$aversion = explode('/',$this->_agent);
|
585 |
-
$this->setVersion($aversion[1]);
|
586 |
-
}
|
587 |
-
return true;
|
588 |
-
}
|
589 |
-
return false;
|
590 |
-
}
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Determine if the browser is Opera or not (last updated 1.7)
|
594 |
-
* @return boolean True if the browser is Opera otherwise false
|
595 |
-
*/
|
596 |
-
function checkBrowserOpera() {
|
597 |
-
if( stripos($this->_agent,'opera mini') !== false ) {
|
598 |
-
$resultant = stristr($this->_agent, 'opera mini');
|
599 |
-
if( preg_match('/\//',$resultant) ) {
|
600 |
-
$aresult = explode('/',$resultant);
|
601 |
-
$aversion = explode(' ',$aresult[1]);
|
602 |
-
$this->setVersion($aversion[0]);
|
603 |
-
}
|
604 |
-
else {
|
605 |
-
$aversion = explode(' ',stristr($resultant,'opera mini'));
|
606 |
-
$this->setVersion($aversion[1]);
|
607 |
-
}
|
608 |
-
$this->_browser_name = $this->BROWSER_OPERA_MINI;
|
609 |
-
$this->setMobile(true);
|
610 |
-
return true;
|
611 |
-
}
|
612 |
-
else if( stripos($this->_agent,'opera') !== false ) {
|
613 |
-
$resultant = stristr($this->_agent, 'opera');
|
614 |
-
if( preg_match('/Version\/(10.*)$/',$resultant,$matches) ) {
|
615 |
-
$this->setVersion($matches[1]);
|
616 |
-
}
|
617 |
-
else if( preg_match('/\//',$resultant) ) {
|
618 |
-
$aresult = explode('/',str_replace("("," ",$resultant));
|
619 |
-
$aversion = explode(' ',$aresult[1]);
|
620 |
-
$this->setVersion($aversion[0]);
|
621 |
-
}
|
622 |
-
else {
|
623 |
-
$aversion = explode(' ',stristr($resultant,'opera'));
|
624 |
-
$this->setVersion(isset($aversion[1])?$aversion[1]:"");
|
625 |
-
}
|
626 |
-
$this->_browser_name = $this->BROWSER_OPERA;
|
627 |
-
return true;
|
628 |
-
}
|
629 |
-
return false;
|
630 |
-
}
|
631 |
-
|
632 |
-
/**
|
633 |
-
* Determine if the browser is Chrome or not (last updated 1.7)
|
634 |
-
* @return boolean True if the browser is Chrome otherwise false
|
635 |
-
*/
|
636 |
-
function checkBrowserChrome() {
|
637 |
-
if( stripos($this->_agent,'Chrome') !== false ) {
|
638 |
-
$aresult = explode('/',stristr($this->_agent,'Chrome'));
|
639 |
-
$aversion = explode(' ',$aresult[1]);
|
640 |
-
$this->setVersion($aversion[0]);
|
641 |
-
$this->setBrowser($this->BROWSER_CHROME);
|
642 |
-
return true;
|
643 |
-
}
|
644 |
-
return false;
|
645 |
-
}
|
646 |
-
|
647 |
-
|
648 |
-
/**
|
649 |
-
* Determine if the browser is WebTv or not (last updated 1.7)
|
650 |
-
* @return boolean True if the browser is WebTv otherwise false
|
651 |
-
*/
|
652 |
-
function checkBrowserWebTv() {
|
653 |
-
if( stripos($this->_agent,'webtv') !== false ) {
|
654 |
-
$aresult = explode('/',stristr($this->_agent,'webtv'));
|
655 |
-
$aversion = explode(' ',$aresult[1]);
|
656 |
-
$this->setVersion($aversion[0]);
|
657 |
-
$this->setBrowser($this->BROWSER_WEBTV);
|
658 |
-
return true;
|
659 |
-
}
|
660 |
-
return false;
|
661 |
-
}
|
662 |
-
|
663 |
-
/**
|
664 |
-
* Determine if the browser is NetPositive or not (last updated 1.7)
|
665 |
-
* @return boolean True if the browser is NetPositive otherwise false
|
666 |
-
*/
|
667 |
-
function checkBrowserNetPositive() {
|
668 |
-
if( stripos($this->_agent,'NetPositive') !== false ) {
|
669 |
-
$aresult = explode('/',stristr($this->_agent,'NetPositive'));
|
670 |
-
$aversion = explode(' ',$aresult[1]);
|
671 |
-
$this->setVersion(str_replace(array('(',')',';'),'',$aversion[0]));
|
672 |
-
$this->setBrowser($this->BROWSER_NETPOSITIVE);
|
673 |
-
return true;
|
674 |
-
}
|
675 |
-
return false;
|
676 |
-
}
|
677 |
-
|
678 |
-
/**
|
679 |
-
* Determine if the browser is Galeon or not (last updated 1.7)
|
680 |
-
* @return boolean True if the browser is Galeon otherwise false
|
681 |
-
*/
|
682 |
-
function checkBrowserGaleon() {
|
683 |
-
if( stripos($this->_agent,'galeon') !== false ) {
|
684 |
-
$aresult = explode(' ',stristr($this->_agent,'galeon'));
|
685 |
-
$aversion = explode('/',$aresult[0]);
|
686 |
-
$this->setVersion($aversion[1]);
|
687 |
-
$this->setBrowser($this->BROWSER_GALEON);
|
688 |
-
return true;
|
689 |
-
}
|
690 |
-
return false;
|
691 |
-
}
|
692 |
-
|
693 |
-
/**
|
694 |
-
* Determine if the browser is Konqueror or not (last updated 1.7)
|
695 |
-
* @return boolean True if the browser is Konqueror otherwise false
|
696 |
-
*/
|
697 |
-
function checkBrowserKonqueror() {
|
698 |
-
if( stripos($this->_agent,'Konqueror') !== false ) {
|
699 |
-
$aresult = explode(' ',stristr($this->_agent,'Konqueror'));
|
700 |
-
$aversion = explode('/',$aresult[0]);
|
701 |
-
$this->setVersion($aversion[1]);
|
702 |
-
$this->setBrowser($this->BROWSER_KONQUEROR);
|
703 |
-
return true;
|
704 |
-
}
|
705 |
-
return false;
|
706 |
-
}
|
707 |
-
|
708 |
-
/**
|
709 |
-
* Determine if the browser is iCab or not (last updated 1.7)
|
710 |
-
* @return boolean True if the browser is iCab otherwise false
|
711 |
-
*/
|
712 |
-
function checkBrowserIcab() {
|
713 |
-
if( stripos($this->_agent,'icab') !== false ) {
|
714 |
-
$aversion = explode(' ',stristr(str_replace('/',' ',$this->_agent),'icab'));
|
715 |
-
$this->setVersion($aversion[1]);
|
716 |
-
$this->setBrowser($this->BROWSER_ICAB);
|
717 |
-
return true;
|
718 |
-
}
|
719 |
-
return false;
|
720 |
-
}
|
721 |
-
|
722 |
-
/**
|
723 |
-
* Determine if the browser is OmniWeb or not (last updated 1.7)
|
724 |
-
* @return boolean True if the browser is OmniWeb otherwise false
|
725 |
-
*/
|
726 |
-
function checkBrowserOmniWeb() {
|
727 |
-
if( stripos($this->_agent,'omniweb') !== false ) {
|
728 |
-
$aresult = explode('/',stristr($this->_agent,'omniweb'));
|
729 |
-
$aversion = explode(' ',isset($aresult[1])?$aresult[1]:"");
|
730 |
-
$this->setVersion($aversion[0]);
|
731 |
-
$this->setBrowser($this->BROWSER_OMNIWEB);
|
732 |
-
return true;
|
733 |
-
}
|
734 |
-
return false;
|
735 |
-
}
|
736 |
-
|
737 |
-
/**
|
738 |
-
* Determine if the browser is Phoenix or not (last updated 1.7)
|
739 |
-
* @return boolean True if the browser is Phoenix otherwise false
|
740 |
-
*/
|
741 |
-
function checkBrowserPhoenix() {
|
742 |
-
if( stripos($this->_agent,'Phoenix') !== false ) {
|
743 |
-
$aversion = explode('/',stristr($this->_agent,'Phoenix'));
|
744 |
-
$this->setVersion($aversion[1]);
|
745 |
-
$this->setBrowser($this->BROWSER_PHOENIX);
|
746 |
-
return true;
|
747 |
-
}
|
748 |
-
return false;
|
749 |
-
}
|
750 |
-
|
751 |
-
/**
|
752 |
-
* Determine if the browser is Firebird or not (last updated 1.7)
|
753 |
-
* @return boolean True if the browser is Firebird otherwise false
|
754 |
-
*/
|
755 |
-
function checkBrowserFirebird() {
|
756 |
-
if( stripos($this->_agent,'Firebird') !== false ) {
|
757 |
-
$aversion = explode('/',stristr($this->_agent,'Firebird'));
|
758 |
-
$this->setVersion($aversion[1]);
|
759 |
-
$this->setBrowser($this->BROWSER_FIREBIRD);
|
760 |
-
return true;
|
761 |
-
}
|
762 |
-
return false;
|
763 |
-
}
|
764 |
-
|
765 |
-
/**
|
766 |
-
* Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
|
767 |
-
* NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
|
768 |
-
* @return boolean True if the browser is Netscape Navigator 9+ otherwise false
|
769 |
-
*/
|
770 |
-
function checkBrowserNetscapeNavigator9Plus() {
|
771 |
-
if( stripos($this->_agent,'Firefox') !== false && preg_match('/Navigator\/([^ ]*)/i',$this->_agent,$matches) ) {
|
772 |
-
$this->setVersion($matches[1]);
|
773 |
-
$this->setBrowser($this->BROWSER_NETSCAPE_NAVIGATOR);
|
774 |
-
return true;
|
775 |
-
}
|
776 |
-
else if( stripos($this->_agent,'Firefox') === false && preg_match('/Netscape6?\/([^ ]*)/i',$this->_agent,$matches) ) {
|
777 |
-
$this->setVersion($matches[1]);
|
778 |
-
$this->setBrowser($this->BROWSER_NETSCAPE_NAVIGATOR);
|
779 |
-
return true;
|
780 |
-
}
|
781 |
-
return false;
|
782 |
-
}
|
783 |
-
|
784 |
-
/**
|
785 |
-
* Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
|
786 |
-
* @return boolean True if the browser is Shiretoko otherwise false
|
787 |
-
*/
|
788 |
-
function checkBrowserShiretoko() {
|
789 |
-
if( stripos($this->_agent,'Mozilla') !== false && preg_match('/Shiretoko\/([^ ]*)/i',$this->_agent,$matches) ) {
|
790 |
-
$this->setVersion($matches[1]);
|
791 |
-
$this->setBrowser($this->BROWSER_SHIRETOKO);
|
792 |
-
return true;
|
793 |
-
}
|
794 |
-
return false;
|
795 |
-
}
|
796 |
-
|
797 |
-
/**
|
798 |
-
* Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
|
799 |
-
* @return boolean True if the browser is Ice Cat otherwise false
|
800 |
-
*/
|
801 |
-
function checkBrowserIceCat() {
|
802 |
-
if( stripos($this->_agent,'Mozilla') !== false && preg_match('/IceCat\/([^ ]*)/i',$this->_agent,$matches) ) {
|
803 |
-
$this->setVersion($matches[1]);
|
804 |
-
$this->setBrowser($this->BROWSER_ICECAT);
|
805 |
-
return true;
|
806 |
-
}
|
807 |
-
return false;
|
808 |
-
}
|
809 |
-
|
810 |
-
/**
|
811 |
-
* Determine if the browser is Nokia or not (last updated 1.7)
|
812 |
-
* @return boolean True if the browser is Nokia otherwise false
|
813 |
-
*/
|
814 |
-
function checkBrowserNokia() {
|
815 |
-
if( preg_match("/Nokia([^\/]+)\/([^ SP]+)/i",$this->_agent,$matches) ) {
|
816 |
-
$this->setVersion($matches[2]);
|
817 |
-
if( stripos($this->_agent,'Series60') !== false || strpos($this->_agent,'S60') !== false ) {
|
818 |
-
$this->setBrowser($this->BROWSER_NOKIA_S60);
|
819 |
-
}
|
820 |
-
else {
|
821 |
-
$this->setBrowser( $this->BROWSER_NOKIA );
|
822 |
-
}
|
823 |
-
$this->setMobile(true);
|
824 |
-
return true;
|
825 |
-
}
|
826 |
-
return false;
|
827 |
-
}
|
828 |
-
|
829 |
-
/**
|
830 |
-
* Determine if the browser is Firefox or not (last updated 1.7)
|
831 |
-
* @return boolean True if the browser is Firefox otherwise false
|
832 |
-
*/
|
833 |
-
function checkBrowserFirefox() {
|
834 |
-
if( stripos($this->_agent,'safari') === false ) {
|
835 |
-
if( preg_match("/Firefox[\/ \(]([^ ;\)]+)/i",$this->_agent,$matches) ) {
|
836 |
-
$this->setVersion($matches[1]);
|
837 |
-
$this->setBrowser($this->BROWSER_FIREFOX);
|
838 |
-
return true;
|
839 |
-
}
|
840 |
-
else if( preg_match("/Firefox$/i",$this->_agent,$matches) ) {
|
841 |
-
$this->setVersion("");
|
842 |
-
$this->setBrowser($this->BROWSER_FIREFOX);
|
843 |
-
return true;
|
844 |
-
}
|
845 |
-
}
|
846 |
-
return false;
|
847 |
-
}
|
848 |
-
|
849 |
-
/**
|
850 |
-
* Determine if the browser is Firefox or not (last updated 1.7)
|
851 |
-
* @return boolean True if the browser is Firefox otherwise false
|
852 |
-
*/
|
853 |
-
function checkBrowserIceweasel() {
|
854 |
-
if( stripos($this->_agent,'Iceweasel') !== false ) {
|
855 |
-
$aresult = explode('/',stristr($this->_agent,'Iceweasel'));
|
856 |
-
$aversion = explode(' ',$aresult[1]);
|
857 |
-
$this->setVersion($aversion[0]);
|
858 |
-
$this->setBrowser($this->BROWSER_ICEWEASEL);
|
859 |
-
return true;
|
860 |
-
}
|
861 |
-
return false;
|
862 |
-
}
|
863 |
-
/**
|
864 |
-
* Determine if the browser is Mozilla or not (last updated 1.7)
|
865 |
-
* @return boolean True if the browser is Mozilla otherwise false
|
866 |
-
*/
|
867 |
-
function checkBrowserMozilla() {
|
868 |
-
if( stripos($this->_agent,'mozilla') !== false && preg_match('/rv:[0-9].[0-9][a-b]?/i',$this->_agent) && stripos($this->_agent,'netscape') === false) {
|
869 |
-
$aversion = explode(' ',stristr($this->_agent,'rv:'));
|
870 |
-
preg_match('/rv:[0-9].[0-9][a-b]?/i',$this->_agent,$aversion);
|
871 |
-
$this->setVersion(str_replace('rv:','',$aversion[0]));
|
872 |
-
$this->setBrowser($this->BROWSER_MOZILLA);
|
873 |
-
return true;
|
874 |
-
}
|
875 |
-
else if( stripos($this->_agent,'mozilla') !== false && preg_match('/rv:[0-9]\.[0-9]/i',$this->_agent) && stripos($this->_agent,'netscape') === false ) {
|
876 |
-
$aversion = explode('',stristr($this->_agent,'rv:'));
|
877 |
-
$this->setVersion(str_replace('rv:','',$aversion[0]));
|
878 |
-
$this->setBrowser($this->BROWSER_MOZILLA);
|
879 |
-
return true;
|
880 |
-
}
|
881 |
-
else if( stripos($this->_agent,'mozilla') !== false && preg_match('/mozilla\/([^ ]*)/i',$this->_agent,$matches) && stripos($this->_agent,'netscape') === false ) {
|
882 |
-
$this->setVersion($matches[1]);
|
883 |
-
$this->setBrowser($this->BROWSER_MOZILLA);
|
884 |
-
return true;
|
885 |
-
}
|
886 |
-
return false;
|
887 |
-
}
|
888 |
-
|
889 |
-
/**
|
890 |
-
* Determine if the browser is Lynx or not (last updated 1.7)
|
891 |
-
* @return boolean True if the browser is Lynx otherwise false
|
892 |
-
*/
|
893 |
-
function checkBrowserLynx() {
|
894 |
-
if( stripos($this->_agent,'lynx') !== false ) {
|
895 |
-
$aresult = explode('/',stristr($this->_agent,'Lynx'));
|
896 |
-
$aversion = explode(' ',(isset($aresult[1])?$aresult[1]:""));
|
897 |
-
$this->setVersion($aversion[0]);
|
898 |
-
$this->setBrowser($this->BROWSER_LYNX);
|
899 |
-
return true;
|
900 |
-
}
|
901 |
-
return false;
|
902 |
-
}
|
903 |
-
|
904 |
-
/**
|
905 |
-
* Determine if the browser is Amaya or not (last updated 1.7)
|
906 |
-
* @return boolean True if the browser is Amaya otherwise false
|
907 |
-
*/
|
908 |
-
function checkBrowserAmaya() {
|
909 |
-
if( stripos($this->_agent,'amaya') !== false ) {
|
910 |
-
$aresult = explode('/',stristr($this->_agent,'Amaya'));
|
911 |
-
$aversion = explode(' ',$aresult[1]);
|
912 |
-
$this->setVersion($aversion[0]);
|
913 |
-
$this->setBrowser($this->BROWSER_AMAYA);
|
914 |
-
return true;
|
915 |
-
}
|
916 |
-
return false;
|
917 |
-
}
|
918 |
-
|
919 |
-
/**
|
920 |
-
* Determine if the browser is Safari or not (last updated 1.7)
|
921 |
-
* @return boolean True if the browser is Safari otherwise false
|
922 |
-
*/
|
923 |
-
function checkBrowserSafari() {
|
924 |
-
if( stripos($this->_agent,'Safari') !== false && stripos($this->_agent,'iPhone') === false && stripos($this->_agent,'iPod') === false ) {
|
925 |
-
$aresult = explode('/',stristr($this->_agent,'Version'));
|
926 |
-
if( isset($aresult[1]) ) {
|
927 |
-
$aversion = explode(' ',$aresult[1]);
|
928 |
-
$this->setVersion($aversion[0]);
|
929 |
-
}
|
930 |
-
else {
|
931 |
-
$this->setVersion($this->VERSION_UNKNOWN);
|
932 |
-
}
|
933 |
-
$this->setBrowser($this->BROWSER_SAFARI);
|
934 |
-
return true;
|
935 |
-
}
|
936 |
-
return false;
|
937 |
-
}
|
938 |
-
|
939 |
-
/**
|
940 |
-
* Determine if the browser is iPhone or not (last updated 1.7)
|
941 |
-
* @return boolean True if the browser is iPhone otherwise false
|
942 |
-
*/
|
943 |
-
function checkBrowseriPhone() {
|
944 |
-
if( stripos($this->_agent,'iPhone') !== false ) {
|
945 |
-
$aresult = explode('/',stristr($this->_agent,'Version'));
|
946 |
-
if( isset($aresult[1]) ) {
|
947 |
-
$aversion = explode(' ',$aresult[1]);
|
948 |
-
$this->setVersion($aversion[0]);
|
949 |
-
}
|
950 |
-
else {
|
951 |
-
$this->setVersion($this->VERSION_UNKNOWN);
|
952 |
-
}
|
953 |
-
$this->setMobile(true);
|
954 |
-
$this->setBrowser($this->BROWSER_IPHONE);
|
955 |
-
return true;
|
956 |
-
}
|
957 |
-
return false;
|
958 |
-
}
|
959 |
-
|
960 |
-
/**
|
961 |
-
* Determine if the browser is iPod or not (last updated 1.7)
|
962 |
-
* @return boolean True if the browser is iPod otherwise false
|
963 |
-
*/
|
964 |
-
function checkBrowseriPad() {
|
965 |
-
if( stripos($this->_agent,'iPad') !== false ) {
|
966 |
-
$aresult = explode('/',stristr($this->_agent,'Version'));
|
967 |
-
if( isset($aresult[1]) ) {
|
968 |
-
$aversion = explode(' ',$aresult[1]);
|
969 |
-
$this->setVersion($aversion[0]);
|
970 |
-
}
|
971 |
-
else {
|
972 |
-
$this->setVersion($this->VERSION_UNKNOWN);
|
973 |
-
}
|
974 |
-
$this->setMobile(true);
|
975 |
-
$this->setBrowser($this->BROWSER_IPAD);
|
976 |
-
return true;
|
977 |
-
}
|
978 |
-
return false;
|
979 |
-
}
|
980 |
-
|
981 |
-
/**
|
982 |
-
* Determine if the browser is iPod or not (last updated 1.7)
|
983 |
-
* @return boolean True if the browser is iPod otherwise false
|
984 |
-
*/
|
985 |
-
function checkBrowseriPod() {
|
986 |
-
if( stripos($this->_agent,'iPod') !== false ) {
|
987 |
-
$aresult = explode('/',stristr($this->_agent,'Version'));
|
988 |
-
if( isset($aresult[1]) ) {
|
989 |
-
$aversion = explode(' ',$aresult[1]);
|
990 |
-
$this->setVersion($aversion[0]);
|
991 |
-
}
|
992 |
-
else {
|
993 |
-
$this->setVersion($this->VERSION_UNKNOWN);
|
994 |
-
}
|
995 |
-
$this->setMobile(true);
|
996 |
-
$this->setBrowser($this->BROWSER_IPOD);
|
997 |
-
return true;
|
998 |
-
}
|
999 |
-
return false;
|
1000 |
-
}
|
1001 |
-
|
1002 |
-
/**
|
1003 |
-
* Determine if the browser is Android or not (last updated 1.7)
|
1004 |
-
* @return boolean True if the browser is Android otherwise false
|
1005 |
-
*/
|
1006 |
-
function checkBrowserAndroid() {
|
1007 |
-
if( stripos($this->_agent,'Android') !== false ) {
|
1008 |
-
$aresult = explode(' ',stristr($this->_agent,'Android'));
|
1009 |
-
if( isset($aresult[1]) ) {
|
1010 |
-
$aversion = explode(' ',$aresult[1]);
|
1011 |
-
$this->setVersion($aversion[0]);
|
1012 |
-
}
|
1013 |
-
else {
|
1014 |
-
$this->setVersion($this->VERSION_UNKNOWN);
|
1015 |
-
}
|
1016 |
-
$this->setMobile(true);
|
1017 |
-
$this->setBrowser($this->BROWSER_ANDROID);
|
1018 |
-
return true;
|
1019 |
-
}
|
1020 |
-
return false;
|
1021 |
-
}
|
1022 |
-
|
1023 |
-
/**
|
1024 |
-
* Determine the user's platform (last updated 1.7)
|
1025 |
-
*/
|
1026 |
-
function checkPlatform() {
|
1027 |
-
if( stripos($this->_agent, 'windows') !== false ) {
|
1028 |
-
$this->_platform = $this->PLATFORM_WINDOWS;
|
1029 |
-
}
|
1030 |
-
else if( stripos($this->_agent, 'iPad') !== false ) {
|
1031 |
-
$this->_platform = $this->PLATFORM_IPAD;
|
1032 |
-
}
|
1033 |
-
else if( stripos($this->_agent, 'iPod') !== false ) {
|
1034 |
-
$this->_platform = $this->PLATFORM_IPOD;
|
1035 |
-
}
|
1036 |
-
else if( stripos($this->_agent, 'iPhone') !== false ) {
|
1037 |
-
$this->_platform = $this->PLATFORM_IPHONE;
|
1038 |
-
}
|
1039 |
-
elseif( stripos($this->_agent, 'mac') !== false ) {
|
1040 |
-
$this->_platform = $this->PLATFORM_APPLE;
|
1041 |
-
}
|
1042 |
-
elseif( stripos($this->_agent, 'android') !== false ) {
|
1043 |
-
$this->_platform = $this->PLATFORM_ANDROID;
|
1044 |
-
}
|
1045 |
-
elseif( stripos($this->_agent, 'linux') !== false ) {
|
1046 |
-
$this->_platform = $this->PLATFORM_LINUX;
|
1047 |
-
}
|
1048 |
-
else if( stripos($this->_agent, 'Nokia') !== false ) {
|
1049 |
-
$this->_platform = $this->PLATFORM_NOKIA;
|
1050 |
-
}
|
1051 |
-
else if( stripos($this->_agent, 'BlackBerry') !== false ) {
|
1052 |
-
$this->_platform = $this->PLATFORM_BLACKBERRY;
|
1053 |
-
}
|
1054 |
-
elseif( stripos($this->_agent,'FreeBSD') !== false ) {
|
1055 |
-
$this->_platform = $this->PLATFORM_FREEBSD;
|
1056 |
-
}
|
1057 |
-
elseif( stripos($this->_agent,'OpenBSD') !== false ) {
|
1058 |
-
$this->_platform = $this->PLATFORM_OPENBSD;
|
1059 |
-
}
|
1060 |
-
elseif( stripos($this->_agent,'NetBSD') !== false ) {
|
1061 |
-
$this->_platform = $this->PLATFORM_NETBSD;
|
1062 |
-
}
|
1063 |
-
elseif( stripos($this->_agent, 'OpenSolaris') !== false ) {
|
1064 |
-
$this->_platform = $this->PLATFORM_OPENSOLARIS;
|
1065 |
-
}
|
1066 |
-
elseif( stripos($this->_agent, 'SunOS') !== false ) {
|
1067 |
-
$this->_platform = $this->PLATFORM_SUNOS;
|
1068 |
-
}
|
1069 |
-
elseif( stripos($this->_agent, 'OS\/2') !== false ) {
|
1070 |
-
$this->_platform = $this->PLATFORM_OS2;
|
1071 |
-
}
|
1072 |
-
elseif( stripos($this->_agent, 'BeOS') !== false ) {
|
1073 |
-
$this->_platform = $this->PLATFORM_BEOS;
|
1074 |
-
}
|
1075 |
-
elseif( stripos($this->_agent, 'win') !== false ) {
|
1076 |
-
$this->_platform = $this->PLATFORM_WINDOWS;
|
1077 |
-
}
|
1078 |
-
|
1079 |
-
}
|
1080 |
-
}
|
1081 |
-
|
1082 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Modified to remove var
|
4 |
+
* Chris Christoff on 12/26/2012
|
5 |
+
* Changes: Changes vars to publics
|
6 |
+
*
|
7 |
+
* Modified to work for EDD by
|
8 |
+
* Chris Christoff on 12/23/2012
|
9 |
+
* Changes: Removed the browser string return and added spacing. Also removed return HTML formatting.
|
10 |
+
*
|
11 |
+
* Modified to add formatted User Agent string for EDD System Info by
|
12 |
+
* Chris Christoff on 12/23/2012
|
13 |
+
* Changes: Split user string and add formatting so we can print a nicely
|
14 |
+
* formatted user agent string on the EDD System Info
|
15 |
+
*
|
16 |
+
* File: Browser.php
|
17 |
+
* Author: Chris Schuld (http://chrisschuld.com/)
|
18 |
+
* Last Modified: August 20th, 2010
|
19 |
+
* @version 1.9
|
20 |
+
* @package PegasusPHP
|
21 |
+
*
|
22 |
+
* Copyright (C) 2008-2010 Chris Schuld (chris@chrisschuld.com)
|
23 |
+
*
|
24 |
+
* This program is free software; you can redistribute it and/or
|
25 |
+
* modify it under the terms of the GNU General Public License as
|
26 |
+
* published by the Free Software Foundation; either version 2 of
|
27 |
+
* the License, or (at your option) any later version.
|
28 |
+
*
|
29 |
+
* This program is distributed in the hope that it will be useful,
|
30 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
31 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
32 |
+
* GNU General Public License for more details at:
|
33 |
+
* http://www.gnu.org/copyleft/gpl.html
|
34 |
+
*
|
35 |
+
*
|
36 |
+
* Typical Usage:
|
37 |
+
*
|
38 |
+
* $browser = new Browser();
|
39 |
+
* if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
|
40 |
+
* echo 'You have FireFox version 2 or greater';
|
41 |
+
* }
|
42 |
+
*
|
43 |
+
* User Agents Sampled from: http://www.useragentstring.com/
|
44 |
+
*
|
45 |
+
* This implementation is based on the original work from Gary White
|
46 |
+
* http://apptools.com/phptools/browser/
|
47 |
+
*
|
48 |
+
* UPDATES:
|
49 |
+
*
|
50 |
+
* 2010-08-20 (v1.9):
|
51 |
+
* + Added MSN Explorer Browser (legacy)
|
52 |
+
* + Added Bing/MSN Robot (Thanks Rob MacDonald)
|
53 |
+
* + Added the Android Platform (PLATFORM_ANDROID)
|
54 |
+
* + Fixed issue with Android 1.6/2.2 (Thanks Tom Hirashima)
|
55 |
+
*
|
56 |
+
* 2010-04-27 (v1.8):
|
57 |
+
* + Added iPad Support
|
58 |
+
*
|
59 |
+
* 2010-03-07 (v1.7):
|
60 |
+
* + *MAJOR* Rebuild (preg_match and other "slow" routine removal(s))
|
61 |
+
* + Almost allof Gary's original code has been replaced
|
62 |
+
* + Large PHPUNIT testing environment created to validate new releases and additions
|
63 |
+
* + Added FreeBSD Platform
|
64 |
+
* + Added OpenBSD Platform
|
65 |
+
* + Added NetBSD Platform
|
66 |
+
* + Added SunOS Platform
|
67 |
+
* + Added OpenSolaris Platform
|
68 |
+
* + Added support of the Iceweazel Browser
|
69 |
+
* + Added isChromeFrame() call to check if chromeframe is in use
|
70 |
+
* + Moved the Opera check in front of the Firefox check due to legacy Opera User Agents
|
71 |
+
* + Added the __toString() method (Thanks Deano)
|
72 |
+
*
|
73 |
+
* 2009-11-15:
|
74 |
+
* + Updated the checkes for Firefox
|
75 |
+
* + Added the NOKIA platform
|
76 |
+
* + Added Checks for the NOKIA brower(s)
|
77 |
+
*
|
78 |
+
* 2009-11-08:
|
79 |
+
* + PHP 5.3 Support
|
80 |
+
* + Added support for BlackBerry OS and BlackBerry browser
|
81 |
+
* + Added support for the Opera Mini browser
|
82 |
+
* + Added additional documenation
|
83 |
+
* + Added support for isRobot() and isMobile()
|
84 |
+
* + Added support for Opera version 10
|
85 |
+
* + Added support for deprecated Netscape Navigator version 9
|
86 |
+
* + Added support for IceCat
|
87 |
+
* + Added support for Shiretoko
|
88 |
+
*
|
89 |
+
* 2010-04-27 (v1.8):
|
90 |
+
* + Added iPad Support
|
91 |
+
*
|
92 |
+
* 2009-08-18:
|
93 |
+
* + Updated to support PHP 5.3 - removed all deprecated function calls
|
94 |
+
* + Updated to remove all double quotes (") -- converted to single quotes (')
|
95 |
+
*
|
96 |
+
* 2009-04-27:
|
97 |
+
* + Updated the IE check to remove a typo and bug (thanks John)
|
98 |
+
*
|
99 |
+
* 2009-04-22:
|
100 |
+
* + Added detection for GoogleBot
|
101 |
+
* + Added detection for the W3C Validator.
|
102 |
+
* + Added detection for Yahoo! Slurp
|
103 |
+
*
|
104 |
+
* 2009-03-14:
|
105 |
+
* + Added detection for iPods.
|
106 |
+
* + Added Platform detection for iPhones
|
107 |
+
* + Added Platform detection for iPods
|
108 |
+
*
|
109 |
+
* 2009-02-16: (Rick Hale)
|
110 |
+
* + Added version detection for Android phones.
|
111 |
+
*
|
112 |
+
* 2008-12-09:
|
113 |
+
* + Removed unused constant
|
114 |
+
*
|
115 |
+
* 2008-11-07:
|
116 |
+
* + Added Google's Chrome to the detection list
|
117 |
+
* + Added isBrowser(string) to the list of functions special thanks to
|
118 |
+
* Daniel 'mavrick' Lang for the function concept (http://mavrick.id.au)
|
119 |
+
*
|
120 |
+
*
|
121 |
+
* Gary White noted: "Since browser detection is so unreliable, I am
|
122 |
+
* no longer maintaining this script. You are free to use and or
|
123 |
+
* modify/update it as you want, however the author assumes no
|
124 |
+
* responsibility for the accuracy of the detected values."
|
125 |
+
*
|
126 |
+
* Anyone experienced with Gary's script might be interested in these notes:
|
127 |
+
*
|
128 |
+
* Added class constants
|
129 |
+
* Added detection and version detection for Google's Chrome
|
130 |
+
* Updated the version detection for Amaya
|
131 |
+
* Updated the version detection for Firefox
|
132 |
+
* Updated the version detection for Lynx
|
133 |
+
* Updated the version detection for WebTV
|
134 |
+
* Updated the version detection for NetPositive
|
135 |
+
* Updated the version detection for IE
|
136 |
+
* Updated the version detection for OmniWeb
|
137 |
+
* Updated the version detection for iCab
|
138 |
+
* Updated the version detection for Safari
|
139 |
+
* Updated Safari to remove mobile devices (iPhone)
|
140 |
+
* Added detection for iPhone
|
141 |
+
* Added detection for robots
|
142 |
+
* Added detection for mobile devices
|
143 |
+
* Added detection for BlackBerry
|
144 |
+
* Removed Netscape checks (matches heavily with firefox & mozilla)
|
145 |
+
*
|
146 |
+
*/
|
147 |
+
|
148 |
+
class Browser {
|
149 |
+
public $_agent = '';
|
150 |
+
public $_browser_name = '';
|
151 |
+
public $_version = '';
|
152 |
+
public $_platform = '';
|
153 |
+
public $_os = '';
|
154 |
+
public $_is_aol = false;
|
155 |
+
public $_is_mobile = false;
|
156 |
+
public $_is_robot = false;
|
157 |
+
public $_aol_version = '';
|
158 |
+
|
159 |
+
public $BROWSER_UNKNOWN = 'unknown';
|
160 |
+
public $VERSION_UNKNOWN = 'unknown';
|
161 |
+
|
162 |
+
public $BROWSER_OPERA = 'Opera'; // Http://www.opera.com/
|
163 |
+
public $BROWSER_OPERA_MINI = 'Opera Mini'; // Http://www.opera.com/mini/
|
164 |
+
public $BROWSER_WEBTV = 'WebTV'; // Http://www.webtv.net/pc/
|
165 |
+
public $BROWSER_IE = 'Internet Explorer'; // Http://www.microsoft.com/ie/
|
166 |
+
public $BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // Http://en.wikipedia.org/wiki/Internet_Explorer_Mobile
|
167 |
+
public $BROWSER_KONQUEROR = 'Konqueror'; // Http://www.konqueror.org/
|
168 |
+
public $BROWSER_ICAB = 'iCab'; // Http://www.icab.de/
|
169 |
+
public $BROWSER_OMNIWEB = 'OmniWeb'; // Http://www.omnigroup.com/applications/omniweb/
|
170 |
+
public $BROWSER_FIREBIRD = 'Firebird'; // Http://www.ibphoenix.com/
|
171 |
+
public $BROWSER_FIREFOX = 'Firefox'; // Http://www.mozilla.com/en-US/firefox/firefox.html
|
172 |
+
public $BROWSER_ICEWEASEL = 'Iceweasel'; // Http://www.geticeweasel.org/
|
173 |
+
public $BROWSER_SHIRETOKO = 'Shiretoko'; // Http://wiki.mozilla.org/Projects/shiretoko
|
174 |
+
public $BROWSER_MOZILLA = 'Mozilla'; // Http://www.mozilla.com/en-US/
|
175 |
+
public $BROWSER_AMAYA = 'Amaya'; // Http://www.w3.org/Amaya/
|
176 |
+
public $BROWSER_LYNX = 'Lynx'; // Http://en.wikipedia.org/wiki/Lynx
|
177 |
+
public $BROWSER_SAFARI = 'Safari'; // Http://apple.com
|
178 |
+
public $BROWSER_IPHONE = 'iPhone'; // Http://apple.com
|
179 |
+
public $BROWSER_IPOD = 'iPod'; // Http://apple.com
|
180 |
+
public $BROWSER_IPAD = 'iPad'; // Http://apple.com
|
181 |
+
public $BROWSER_CHROME = 'Chrome'; // Http://www.google.com/chrome
|
182 |
+
public $BROWSER_ANDROID = 'Android'; // Http://www.android.com/
|
183 |
+
public $BROWSER_GOOGLEBOT = 'GoogleBot'; // Http://en.wikipedia.org/wiki/Googlebot
|
184 |
+
public $BROWSER_SLURP = 'Yahoo! Slurp'; // Http://en.wikipedia.org/wiki/Yahoo!_Slurp
|
185 |
+
public $BROWSER_W3CVALIDATOR = 'W3C Validator'; // Http://validator.w3.org/
|
186 |
+
public $BROWSER_BLACKBERRY = 'BlackBerry'; // Http://www.blackberry.com/
|
187 |
+
public $BROWSER_ICECAT = 'IceCat'; // Http://en.wikipedia.org/wiki/GNU_IceCat
|
188 |
+
public $BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // Http://en.wikipedia.org/wiki/Web_Browser_for_S60
|
189 |
+
public $BROWSER_NOKIA = 'Nokia Browser'; // * all other WAP-based browsers on the Nokia Platform
|
190 |
+
public $BROWSER_MSN = 'MSN Browser'; // Http://explorer.msn.com/
|
191 |
+
public $BROWSER_MSNBOT = 'MSN Bot'; // Http://search.msn.com/msnbot.htm
|
192 |
+
// Http://en.wikipedia.org/wiki/Msnbot (used for Bing as well)
|
193 |
+
|
194 |
+
public $BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // Http://browser.netscape.com/ (DEPRECATED)
|
195 |
+
public $BROWSER_GALEON = 'Galeon'; // Http://galeon.sourceforge.net/ (DEPRECATED)
|
196 |
+
public $BROWSER_NETPOSITIVE = 'NetPositive'; // Http://en.wikipedia.org/wiki/NetPositive (DEPRECATED)
|
197 |
+
public $BROWSER_PHOENIX = 'Phoenix'; // Http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED)
|
198 |
+
|
199 |
+
public $PLATFORM_UNKNOWN = 'unknown';
|
200 |
+
public $PLATFORM_WINDOWS = 'Windows';
|
201 |
+
public $PLATFORM_WINDOWS_CE = 'Windows CE';
|
202 |
+
public $PLATFORM_APPLE = 'Apple';
|
203 |
+
public $PLATFORM_LINUX = 'Linux';
|
204 |
+
public $PLATFORM_OS2 = 'OS/2';
|
205 |
+
public $PLATFORM_BEOS = 'BeOS';
|
206 |
+
public $PLATFORM_IPHONE = 'iPhone';
|
207 |
+
public $PLATFORM_IPOD = 'iPod';
|
208 |
+
public $PLATFORM_IPAD = 'iPad';
|
209 |
+
public $PLATFORM_BLACKBERRY = 'BlackBerry';
|
210 |
+
public $PLATFORM_NOKIA = 'Nokia';
|
211 |
+
public $PLATFORM_FREEBSD = 'FreeBSD';
|
212 |
+
public $PLATFORM_OPENBSD = 'OpenBSD';
|
213 |
+
public $PLATFORM_NETBSD = 'NetBSD';
|
214 |
+
public $PLATFORM_SUNOS = 'SunOS';
|
215 |
+
public $PLATFORM_OPENSOLARIS = 'OpenSolaris';
|
216 |
+
public $PLATFORM_ANDROID = 'Android';
|
217 |
+
|
218 |
+
public $OPERATING_SYSTEM_UNKNOWN = 'unknown';
|
219 |
+
|
220 |
+
function Browser($useragent="") {
|
221 |
+
$this->reset();
|
222 |
+
if( $useragent != "" ) {
|
223 |
+
$this->setUserAgent($useragent);
|
224 |
+
}
|
225 |
+
else {
|
226 |
+
$this->determine();
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Reset all properties
|
232 |
+
*/
|
233 |
+
function reset() {
|
234 |
+
$this->_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "";
|
235 |
+
$this->_browser_name = $this->BROWSER_UNKNOWN;
|
236 |
+
$this->_version = $this->VERSION_UNKNOWN;
|
237 |
+
$this->_platform = $this->PLATFORM_UNKNOWN;
|
238 |
+
$this->_os = $this->OPERATING_SYSTEM_UNKNOWN;
|
239 |
+
$this->_is_aol = false;
|
240 |
+
$this->_is_mobile = false;
|
241 |
+
$this->_is_robot = false;
|
242 |
+
$this->_aol_version = $this->VERSION_UNKNOWN;
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Check to see if the specific browser is valid
|
247 |
+
* @param string $browserName
|
248 |
+
* @return True if the browser is the specified browser
|
249 |
+
*/
|
250 |
+
function isBrowser($browserName) { return( 0 == strcasecmp($this->_browser_name, trim($browserName))); }
|
251 |
+
|
252 |
+
/**
|
253 |
+
* The name of the browser. All return types are from the class contants
|
254 |
+
* @return string Name of the browser
|
255 |
+
*/
|
256 |
+
function getBrowser() { return $this->_browser_name; }
|
257 |
+
/**
|
258 |
+
* Set the name of the browser
|
259 |
+
* @param $browser The name of the Browser
|
260 |
+
*/
|
261 |
+
function setBrowser($browser) { return $this->_browser_name = $browser; }
|
262 |
+
/**
|
263 |
+
* The name of the platform. All return types are from the class contants
|
264 |
+
* @return string Name of the browser
|
265 |
+
*/
|
266 |
+
function getPlatform() { return $this->_platform; }
|
267 |
+
/**
|
268 |
+
* Set the name of the platform
|
269 |
+
* @param $platform The name of the Platform
|
270 |
+
*/
|
271 |
+
function setPlatform($platform) { return $this->_platform = $platform; }
|
272 |
+
/**
|
273 |
+
* The version of the browser.
|
274 |
+
* @return string Version of the browser (will only contain alpha-numeric characters and a period)
|
275 |
+
*/
|
276 |
+
function getVersion() { return $this->_version; }
|
277 |
+
/**
|
278 |
+
* Set the version of the browser
|
279 |
+
* @param $version The version of the Browser
|
280 |
+
*/
|
281 |
+
function setVersion($version) { $this->_version = preg_replace('/[^0-9,.,a-z,A-Z-]/','',$version); }
|
282 |
+
/**
|
283 |
+
* The version of AOL.
|
284 |
+
* @return string Version of AOL (will only contain alpha-numeric characters and a period)
|
285 |
+
*/
|
286 |
+
function getAolVersion() { return $this->_aol_version; }
|
287 |
+
/**
|
288 |
+
* Set the version of AOL
|
289 |
+
* @param $version The version of AOL
|
290 |
+
*/
|
291 |
+
function setAolVersion($version) { $this->_aol_version = preg_replace('/[^0-9,.,a-z,A-Z]/','',$version); }
|
292 |
+
/**
|
293 |
+
* Is the browser from AOL?
|
294 |
+
* @return boolean True if the browser is from AOL otherwise false
|
295 |
+
*/
|
296 |
+
function isAol() { return $this->_is_aol; }
|
297 |
+
/**
|
298 |
+
* Is the browser from a mobile device?
|
299 |
+
* @return boolean True if the browser is from a mobile device otherwise false
|
300 |
+
*/
|
301 |
+
function isMobile() { return $this->_is_mobile; }
|
302 |
+
/**
|
303 |
+
* Is the browser from a robot (ex Slurp,GoogleBot)?
|
304 |
+
* @return boolean True if the browser is from a robot otherwise false
|
305 |
+
*/
|
306 |
+
function isRobot() { return $this->_is_robot; }
|
307 |
+
/**
|
308 |
+
* Set the browser to be from AOL
|
309 |
+
* @param $isAol
|
310 |
+
*/
|
311 |
+
function setAol($isAol) { $this->_is_aol = $isAol; }
|
312 |
+
/**
|
313 |
+
* Set the Browser to be mobile
|
314 |
+
* @param boolean $value is the browser a mobile brower or not
|
315 |
+
*/
|
316 |
+
function setMobile($value=true) { $this->_is_mobile = $value; }
|
317 |
+
/**
|
318 |
+
* Set the Browser to be a robot
|
319 |
+
* @param boolean $value is the browser a robot or not
|
320 |
+
*/
|
321 |
+
function setRobot($value=true) { $this->_is_robot = $value; }
|
322 |
+
/**
|
323 |
+
* Get the user agent value in use to determine the browser
|
324 |
+
* @return string The user agent from the HTTP header
|
325 |
+
*/
|
326 |
+
function getUserAgent() { return $this->_agent; }
|
327 |
+
/**
|
328 |
+
* Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
|
329 |
+
* @param $agent_string The value for the User Agent
|
330 |
+
*/
|
331 |
+
function setUserAgent($agent_string) {
|
332 |
+
$this->reset();
|
333 |
+
$this->_agent = $agent_string;
|
334 |
+
$this->determine();
|
335 |
+
}
|
336 |
+
/**
|
337 |
+
* Used to determine if the browser is actually "chromeframe"
|
338 |
+
* @since 1.7
|
339 |
+
* @return boolean True if the browser is using chromeframe
|
340 |
+
*/
|
341 |
+
function isChromeFrame() {
|
342 |
+
return( strpos($this->_agent,"chromeframe") !== false );
|
343 |
+
}
|
344 |
+
/**
|
345 |
+
* Returns a formatted string with a summary of the details of the browser.
|
346 |
+
* @return string formatted string with a summary of the browser
|
347 |
+
*/
|
348 |
+
function __toString() {
|
349 |
+
$text1 = $this->getUserAgent(); //grabs the UA (user agent) string
|
350 |
+
$UAline1 = substr($text1, 0, 32); //the first line we print should only be the first 32 characters of the UA string
|
351 |
+
$text2 = $this->getUserAgent();//now we grab it again and save it to a string
|
352 |
+
$towrapUA = str_replace($UAline1, '', $text2);//the rest of the printoff (other than first line) is equivolent
|
353 |
+
// To the whole string minus the part we printed off. IE
|
354 |
+
// User Agent: thefirst32charactersfromUAline1
|
355 |
+
// the rest of it is now stored in
|
356 |
+
// $text2 to be printed off
|
357 |
+
// But we need to add spaces before each line that is split other than line 1
|
358 |
+
$space = '';
|
359 |
+
for($i = 0; $i < 25; $i++) {
|
360 |
+
$space .= ' ';
|
361 |
+
}
|
362 |
+
// Now we split the remaining string of UA ($text2) into lines that are prefixed by spaces for formatting
|
363 |
+
$wordwrapped = chunk_split($towrapUA, 32, "\n $space");
|
364 |
+
return "Platform: {$this->getPlatform()} \n".
|
365 |
+
"Browser Name: {$this->getBrowser()} \n" .
|
366 |
+
"Browser Version: {$this->getVersion()} \n" .
|
367 |
+
"User Agent String: $UAline1 \n\t\t\t " .
|
368 |
+
"$wordwrapped";
|
369 |
+
}
|
370 |
+
/**
|
371 |
+
* Protected routine to calculate and determine what the browser is in use (including platform)
|
372 |
+
*/
|
373 |
+
function determine() {
|
374 |
+
$this->checkPlatform();
|
375 |
+
$this->checkBrowsers();
|
376 |
+
$this->checkForAol();
|
377 |
+
}
|
378 |
+
/**
|
379 |
+
* Protected routine to determine the browser type
|
380 |
+
* @return boolean True if the browser was detected otherwise false
|
381 |
+
*/
|
382 |
+
function checkBrowsers() {
|
383 |
+
return (
|
384 |
+
// Well-known, well-used
|
385 |
+
// Special Notes:
|
386 |
+
// (1) Opera must be checked before FireFox due to the odd
|
387 |
+
// user agents used in some older versions of Opera
|
388 |
+
// (2) WebTV is strapped onto Internet Explorer so we must
|
389 |
+
// check for WebTV before IE
|
390 |
+
// (3) (deprecated) Galeon is based on Firefox and needs to be
|
391 |
+
// tested before Firefox is tested
|
392 |
+
// (4) OmniWeb is based on Safari so OmniWeb check must occur
|
393 |
+
// before Safari
|
394 |
+
// (5) Netscape 9+ is based on Firefox so Netscape checks
|
395 |
+
// before FireFox are necessary
|
396 |
+
$this->checkBrowserWebTv() ||
|
397 |
+
$this->checkBrowserInternetExplorer() ||
|
398 |
+
$this->checkBrowserOpera() ||
|
399 |
+
$this->checkBrowserGaleon() ||
|
400 |
+
$this->checkBrowserNetscapeNavigator9Plus() ||
|
401 |
+
$this->checkBrowserFirefox() ||
|
402 |
+
$this->checkBrowserChrome() ||
|
403 |
+
$this->checkBrowserOmniWeb() ||
|
404 |
+
|
405 |
+
// Common mobile
|
406 |
+
$this->checkBrowserAndroid() ||
|
407 |
+
$this->checkBrowseriPad() ||
|
408 |
+
$this->checkBrowseriPod() ||
|
409 |
+
$this->checkBrowseriPhone() ||
|
410 |
+
$this->checkBrowserBlackBerry() ||
|
411 |
+
$this->checkBrowserNokia() ||
|
412 |
+
|
413 |
+
// Common bots
|
414 |
+
$this->checkBrowserGoogleBot() ||
|
415 |
+
$this->checkBrowserMSNBot() ||
|
416 |
+
$this->checkBrowserSlurp() ||
|
417 |
+
|
418 |
+
// WebKit base check (post mobile and others)
|
419 |
+
$this->checkBrowserSafari() ||
|
420 |
+
|
421 |
+
// Everyone else
|
422 |
+
$this->checkBrowserNetPositive() ||
|
423 |
+
$this->checkBrowserFirebird() ||
|
424 |
+
$this->checkBrowserKonqueror() ||
|
425 |
+
$this->checkBrowserIcab() ||
|
426 |
+
$this->checkBrowserPhoenix() ||
|
427 |
+
$this->checkBrowserAmaya() ||
|
428 |
+
$this->checkBrowserLynx() ||
|
429 |
+
|
430 |
+
$this->checkBrowserShiretoko() ||
|
431 |
+
$this->checkBrowserIceCat() ||
|
432 |
+
$this->checkBrowserW3CValidator() ||
|
433 |
+
$this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
|
434 |
+
);
|
435 |
+
}
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Determine if the user is using a BlackBerry (last updated 1.7)
|
439 |
+
* @return boolean True if the browser is the BlackBerry browser otherwise false
|
440 |
+
*/
|
441 |
+
function checkBrowserBlackBerry() {
|
442 |
+
if( stripos($this->_agent,'blackberry') !== false ) {
|
443 |
+
$aresult = explode("/",stristr($this->_agent,"BlackBerry"));
|
444 |
+
$aversion = explode(' ',$aresult[1]);
|
445 |
+
$this->setVersion($aversion[0]);
|
446 |
+
$this->_browser_name = $this->BROWSER_BLACKBERRY;
|
447 |
+
$this->setMobile(true);
|
448 |
+
return true;
|
449 |
+
}
|
450 |
+
return false;
|
451 |
+
}
|
452 |
+
|
453 |
+
/**
|
454 |
+
* Determine if the user is using an AOL User Agent (last updated 1.7)
|
455 |
+
* @return boolean True if the browser is from AOL otherwise false
|
456 |
+
*/
|
457 |
+
function checkForAol() {
|
458 |
+
$this->setAol(false);
|
459 |
+
$this->setAolVersion($this->VERSION_UNKNOWN);
|
460 |
+
|
461 |
+
if( stripos($this->_agent,'aol') !== false ) {
|
462 |
+
$aversion = explode(' ',stristr($this->_agent, 'AOL'));
|
463 |
+
$this->setAol(true);
|
464 |
+
$this->setAolVersion(preg_replace('/[^0-9\.a-z]/i', '', $aversion[1]));
|
465 |
+
return true;
|
466 |
+
}
|
467 |
+
return false;
|
468 |
+
}
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Determine if the browser is the GoogleBot or not (last updated 1.7)
|
472 |
+
* @return boolean True if the browser is the GoogletBot otherwise false
|
473 |
+
*/
|
474 |
+
function checkBrowserGoogleBot() {
|
475 |
+
if( stripos($this->_agent,'googlebot') !== false ) {
|
476 |
+
$aresult = explode('/',stristr($this->_agent,'googlebot'));
|
477 |
+
$aversion = explode(' ',$aresult[1]);
|
478 |
+
$this->setVersion(str_replace(';','',$aversion[0]));
|
479 |
+
$this->_browser_name = $this->BROWSER_GOOGLEBOT;
|
480 |
+
$this->setRobot(true);
|
481 |
+
return true;
|
482 |
+
}
|
483 |
+
return false;
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Determine if the browser is the MSNBot or not (last updated 1.9)
|
488 |
+
* @return boolean True if the browser is the MSNBot otherwise false
|
489 |
+
*/
|
490 |
+
function checkBrowserMSNBot() {
|
491 |
+
if( stripos($this->_agent,"msnbot") !== false ) {
|
492 |
+
$aresult = explode("/",stristr($this->_agent,"msnbot"));
|
493 |
+
$aversion = explode(" ",$aresult[1]);
|
494 |
+
$this->setVersion(str_replace(";","",$aversion[0]));
|
495 |
+
$this->_browser_name = $this->BROWSER_MSNBOT;
|
496 |
+
$this->setRobot(true);
|
497 |
+
return true;
|
498 |
+
}
|
499 |
+
return false;
|
500 |
+
}
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Determine if the browser is the W3C Validator or not (last updated 1.7)
|
504 |
+
* @return boolean True if the browser is the W3C Validator otherwise false
|
505 |
+
*/
|
506 |
+
function checkBrowserW3CValidator() {
|
507 |
+
if( stripos($this->_agent,'W3C-checklink') !== false ) {
|
508 |
+
$aresult = explode('/',stristr($this->_agent,'W3C-checklink'));
|
509 |
+
$aversion = explode(' ',$aresult[1]);
|
510 |
+
$this->setVersion($aversion[0]);
|
511 |
+
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
512 |
+
return true;
|
513 |
+
}
|
514 |
+
else if( stripos($this->_agent,'W3C_Validator') !== false ) {
|
515 |
+
// Some of the Validator versions do not delineate w/ a slash - add it back in
|
516 |
+
$ua = str_replace("W3C_Validator ", "W3C_Validator/", $this->_agent);
|
517 |
+
$aresult = explode('/',stristr($ua,'W3C_Validator'));
|
518 |
+
$aversion = explode(' ',$aresult[1]);
|
519 |
+
$this->setVersion($aversion[0]);
|
520 |
+
$this->_browser_name = $this->BROWSER_W3CVALIDATOR;
|
521 |
+
return true;
|
522 |
+
}
|
523 |
+
return false;
|
524 |
+
}
|
525 |
+
|
526 |
+
/**
|
527 |
+
* Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
|
528 |
+
* @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
|
529 |
+
*/
|
530 |
+
function checkBrowserSlurp() {
|
531 |
+
if( stripos($this->_agent,'slurp') !== false ) {
|
532 |
+
$aresult = explode('/',stristr($this->_agent,'Slurp'));
|
533 |
+
$aversion = explode(' ',$aresult[1]);
|
534 |
+
$this->setVersion($aversion[0]);
|
535 |
+
$this->_browser_name = $this->BROWSER_SLURP;
|
536 |
+
$this->setRobot(true);
|
537 |
+
$this->setMobile(false);
|
538 |
+
return true;
|
539 |
+
}
|
540 |
+
return false;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Determine if the browser is Internet Explorer or not (last updated 1.7)
|
545 |
+
* @return boolean True if the browser is Internet Explorer otherwise false
|
546 |
+
*/
|
547 |
+
function checkBrowserInternetExplorer() {
|
548 |
+
|
549 |
+
// Test for v1 - v1.5 IE
|
550 |
+
if( stripos($this->_agent,'microsoft internet explorer') !== false ) {
|
551 |
+
$this->setBrowser($this->BROWSER_IE);
|
552 |
+
$this->setVersion('1.0');
|
553 |
+
$aresult = stristr($this->_agent, '/');
|
554 |
+
if( preg_match('/308|425|426|474|0b1/i', $aresult) ) {
|
555 |
+
$this->setVersion('1.5');
|
556 |
+
}
|
557 |
+
return true;
|
558 |
+
}
|
559 |
+
// Test for versions > 1.5
|
560 |
+
else if( stripos($this->_agent,'msie') !== false && stripos($this->_agent,'opera') === false ) {
|
561 |
+
// See if the browser is the odd MSN Explorer
|
562 |
+
if( stripos($this->_agent,'msnb') !== false ) {
|
563 |
+
$aresult = explode(' ',stristr(str_replace(';','; ',$this->_agent),'MSN'));
|
564 |
+
$this->setBrowser( $this->BROWSER_MSN );
|
565 |
+
$this->setVersion(str_replace(array('(',')',';'),'',$aresult[1]));
|
566 |
+
return true;
|
567 |
+
}
|
568 |
+
$aresult = explode(' ',stristr(str_replace(';','; ',$this->_agent),'msie'));
|
569 |
+
$this->setBrowser( $this->BROWSER_IE );
|
570 |
+
$this->setVersion(str_replace(array('(',')',';'),'',$aresult[1]));
|
571 |
+
return true;
|
572 |
+
}
|
573 |
+
// Test for Pocket IE
|
574 |
+
else if( stripos($this->_agent,'mspie') !== false || stripos($this->_agent,'pocket') !== false ) {
|
575 |
+
$aresult = explode(' ',stristr($this->_agent,'mspie'));
|
576 |
+
$this->setPlatform( $this->PLATFORM_WINDOWS_CE );
|
577 |
+
$this->setBrowser( $this->BROWSER_POCKET_IE );
|
578 |
+
$this->setMobile(true);
|
579 |
+
|
580 |
+
if( stripos($this->_agent,'mspie') !== false ) {
|
581 |
+
$this->setVersion($aresult[1]);
|
582 |
+
}
|
583 |
+
else {
|
584 |
+
$aversion = explode('/',$this->_agent);
|
585 |
+
$this->setVersion($aversion[1]);
|
586 |
+
}
|
587 |
+
return true;
|
588 |
+
}
|
589 |
+
return false;
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Determine if the browser is Opera or not (last updated 1.7)
|
594 |
+
* @return boolean True if the browser is Opera otherwise false
|
595 |
+
*/
|
596 |
+
function checkBrowserOpera() {
|
597 |
+
if( stripos($this->_agent,'opera mini') !== false ) {
|
598 |
+
$resultant = stristr($this->_agent, 'opera mini');
|
599 |
+
if( preg_match('/\//',$resultant) ) {
|
600 |
+
$aresult = explode('/',$resultant);
|
601 |
+
$aversion = explode(' ',$aresult[1]);
|
602 |
+
$this->setVersion($aversion[0]);
|
603 |
+
}
|
604 |
+
else {
|
605 |
+
$aversion = explode(' ',stristr($resultant,'opera mini'));
|
606 |
+
$this->setVersion($aversion[1]);
|
607 |
+
}
|
608 |
+
$this->_browser_name = $this->BROWSER_OPERA_MINI;
|
609 |
+
$this->setMobile(true);
|
610 |
+
return true;
|
611 |
+
}
|
612 |
+
else if( stripos($this->_agent,'opera') !== false ) {
|
613 |
+
$resultant = stristr($this->_agent, 'opera');
|
614 |
+
if( preg_match('/Version\/(10.*)$/',$resultant,$matches) ) {
|
615 |
+
$this->setVersion($matches[1]);
|
616 |
+
}
|
617 |
+
else if( preg_match('/\//',$resultant) ) {
|
618 |
+
$aresult = explode('/',str_replace("("," ",$resultant));
|
619 |
+
$aversion = explode(' ',$aresult[1]);
|
620 |
+
$this->setVersion($aversion[0]);
|
621 |
+
}
|
622 |
+
else {
|
623 |
+
$aversion = explode(' ',stristr($resultant,'opera'));
|
624 |
+
$this->setVersion(isset($aversion[1])?$aversion[1]:"");
|
625 |
+
}
|
626 |
+
$this->_browser_name = $this->BROWSER_OPERA;
|
627 |
+
return true;
|
628 |
+
}
|
629 |
+
return false;
|
630 |
+
}
|
631 |
+
|
632 |
+
/**
|
633 |
+
* Determine if the browser is Chrome or not (last updated 1.7)
|
634 |
+
* @return boolean True if the browser is Chrome otherwise false
|
635 |
+
*/
|
636 |
+
function checkBrowserChrome() {
|
637 |
+
if( stripos($this->_agent,'Chrome') !== false ) {
|
638 |
+
$aresult = explode('/',stristr($this->_agent,'Chrome'));
|
639 |
+
$aversion = explode(' ',$aresult[1]);
|
640 |
+
$this->setVersion($aversion[0]);
|
641 |
+
$this->setBrowser($this->BROWSER_CHROME);
|
642 |
+
return true;
|
643 |
+
}
|
644 |
+
return false;
|
645 |
+
}
|
646 |
+
|
647 |
+
|
648 |
+
/**
|
649 |
+
* Determine if the browser is WebTv or not (last updated 1.7)
|
650 |
+
* @return boolean True if the browser is WebTv otherwise false
|
651 |
+
*/
|
652 |
+
function checkBrowserWebTv() {
|
653 |
+
if( stripos($this->_agent,'webtv') !== false ) {
|
654 |
+
$aresult = explode('/',stristr($this->_agent,'webtv'));
|
655 |
+
$aversion = explode(' ',$aresult[1]);
|
656 |
+
$this->setVersion($aversion[0]);
|
657 |
+
$this->setBrowser($this->BROWSER_WEBTV);
|
658 |
+
return true;
|
659 |
+
}
|
660 |
+
return false;
|
661 |
+
}
|
662 |
+
|
663 |
+
/**
|
664 |
+
* Determine if the browser is NetPositive or not (last updated 1.7)
|
665 |
+
* @return boolean True if the browser is NetPositive otherwise false
|
666 |
+
*/
|
667 |
+
function checkBrowserNetPositive() {
|
668 |
+
if( stripos($this->_agent,'NetPositive') !== false ) {
|
669 |
+
$aresult = explode('/',stristr($this->_agent,'NetPositive'));
|
670 |
+
$aversion = explode(' ',$aresult[1]);
|
671 |
+
$this->setVersion(str_replace(array('(',')',';'),'',$aversion[0]));
|
672 |
+
$this->setBrowser($this->BROWSER_NETPOSITIVE);
|
673 |
+
return true;
|
674 |
+
}
|
675 |
+
return false;
|
676 |
+
}
|
677 |
+
|
678 |
+
/**
|
679 |
+
* Determine if the browser is Galeon or not (last updated 1.7)
|
680 |
+
* @return boolean True if the browser is Galeon otherwise false
|
681 |
+
*/
|
682 |
+
function checkBrowserGaleon() {
|
683 |
+
if( stripos($this->_agent,'galeon') !== false ) {
|
684 |
+
$aresult = explode(' ',stristr($this->_agent,'galeon'));
|
685 |
+
$aversion = explode('/',$aresult[0]);
|
686 |
+
$this->setVersion($aversion[1]);
|
687 |
+
$this->setBrowser($this->BROWSER_GALEON);
|
688 |
+
return true;
|
689 |
+
}
|
690 |
+
return false;
|
691 |
+
}
|
692 |
+
|
693 |
+
/**
|
694 |
+
* Determine if the browser is Konqueror or not (last updated 1.7)
|
695 |
+
* @return boolean True if the browser is Konqueror otherwise false
|
696 |
+
*/
|
697 |
+
function checkBrowserKonqueror() {
|
698 |
+
if( stripos($this->_agent,'Konqueror') !== false ) {
|
699 |
+
$aresult = explode(' ',stristr($this->_agent,'Konqueror'));
|
700 |
+
$aversion = explode('/',$aresult[0]);
|
701 |
+
$this->setVersion($aversion[1]);
|
702 |
+
$this->setBrowser($this->BROWSER_KONQUEROR);
|
703 |
+
return true;
|
704 |
+
}
|
705 |
+
return false;
|
706 |
+
}
|
707 |
+
|
708 |
+
/**
|
709 |
+
* Determine if the browser is iCab or not (last updated 1.7)
|
710 |
+
* @return boolean True if the browser is iCab otherwise false
|
711 |
+
*/
|
712 |
+
function checkBrowserIcab() {
|
713 |
+
if( stripos($this->_agent,'icab') !== false ) {
|
714 |
+
$aversion = explode(' ',stristr(str_replace('/',' ',$this->_agent),'icab'));
|
715 |
+
$this->setVersion($aversion[1]);
|
716 |
+
$this->setBrowser($this->BROWSER_ICAB);
|
717 |
+
return true;
|
718 |
+
}
|
719 |
+
return false;
|
720 |
+
}
|
721 |
+
|
722 |
+
/**
|
723 |
+
* Determine if the browser is OmniWeb or not (last updated 1.7)
|
724 |
+
* @return boolean True if the browser is OmniWeb otherwise false
|
725 |
+
*/
|
726 |
+
function checkBrowserOmniWeb() {
|
727 |
+
if( stripos($this->_agent,'omniweb') !== false ) {
|
728 |
+
$aresult = explode('/',stristr($this->_agent,'omniweb'));
|
729 |
+
$aversion = explode(' ',isset($aresult[1])?$aresult[1]:"");
|
730 |
+
$this->setVersion($aversion[0]);
|
731 |
+
$this->setBrowser($this->BROWSER_OMNIWEB);
|
732 |
+
return true;
|
733 |
+
}
|
734 |
+
return false;
|
735 |
+
}
|
736 |
+
|
737 |
+
/**
|
738 |
+
* Determine if the browser is Phoenix or not (last updated 1.7)
|
739 |
+
* @return boolean True if the browser is Phoenix otherwise false
|
740 |
+
*/
|
741 |
+
function checkBrowserPhoenix() {
|
742 |
+
if( stripos($this->_agent,'Phoenix') !== false ) {
|
743 |
+
$aversion = explode('/',stristr($this->_agent,'Phoenix'));
|
744 |
+
$this->setVersion($aversion[1]);
|
745 |
+
$this->setBrowser($this->BROWSER_PHOENIX);
|
746 |
+
return true;
|
747 |
+
}
|
748 |
+
return false;
|
749 |
+
}
|
750 |
+
|
751 |
+
/**
|
752 |
+
* Determine if the browser is Firebird or not (last updated 1.7)
|
753 |
+
* @return boolean True if the browser is Firebird otherwise false
|
754 |
+
*/
|
755 |
+
function checkBrowserFirebird() {
|
756 |
+
if( stripos($this->_agent,'Firebird') !== false ) {
|
757 |
+
$aversion = explode('/',stristr($this->_agent,'Firebird'));
|
758 |
+
$this->setVersion($aversion[1]);
|
759 |
+
$this->setBrowser($this->BROWSER_FIREBIRD);
|
760 |
+
return true;
|
761 |
+
}
|
762 |
+
return false;
|
763 |
+
}
|
764 |
+
|
765 |
+
/**
|
766 |
+
* Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
|
767 |
+
* NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
|
768 |
+
* @return boolean True if the browser is Netscape Navigator 9+ otherwise false
|
769 |
+
*/
|
770 |
+
function checkBrowserNetscapeNavigator9Plus() {
|
771 |
+
if( stripos($this->_agent,'Firefox') !== false && preg_match('/Navigator\/([^ ]*)/i',$this->_agent,$matches) ) {
|
772 |
+
$this->setVersion($matches[1]);
|
773 |
+
$this->setBrowser($this->BROWSER_NETSCAPE_NAVIGATOR);
|
774 |
+
return true;
|
775 |
+
}
|
776 |
+
else if( stripos($this->_agent,'Firefox') === false && preg_match('/Netscape6?\/([^ ]*)/i',$this->_agent,$matches) ) {
|
777 |
+
$this->setVersion($matches[1]);
|
778 |
+
$this->setBrowser($this->BROWSER_NETSCAPE_NAVIGATOR);
|
779 |
+
return true;
|
780 |
+
}
|
781 |
+
return false;
|
782 |
+
}
|
783 |
+
|
784 |
+
/**
|
785 |
+
* Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
|
786 |
+
* @return boolean True if the browser is Shiretoko otherwise false
|
787 |
+
*/
|
788 |
+
function checkBrowserShiretoko() {
|
789 |
+
if( stripos($this->_agent,'Mozilla') !== false && preg_match('/Shiretoko\/([^ ]*)/i',$this->_agent,$matches) ) {
|
790 |
+
$this->setVersion($matches[1]);
|
791 |
+
$this->setBrowser($this->BROWSER_SHIRETOKO);
|
792 |
+
return true;
|
793 |
+
}
|
794 |
+
return false;
|
795 |
+
}
|
796 |
+
|
797 |
+
/**
|
798 |
+
* Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
|
799 |
+
* @return boolean True if the browser is Ice Cat otherwise false
|
800 |
+
*/
|
801 |
+
function checkBrowserIceCat() {
|
802 |
+
if( stripos($this->_agent,'Mozilla') !== false && preg_match('/IceCat\/([^ ]*)/i',$this->_agent,$matches) ) {
|
803 |
+
$this->setVersion($matches[1]);
|
804 |
+
$this->setBrowser($this->BROWSER_ICECAT);
|
805 |
+
return true;
|
806 |
+
}
|
807 |
+
return false;
|
808 |
+
}
|
809 |
+
|
810 |
+
/**
|
811 |
+
* Determine if the browser is Nokia or not (last updated 1.7)
|
812 |
+
* @return boolean True if the browser is Nokia otherwise false
|
813 |
+
*/
|
814 |
+
function checkBrowserNokia() {
|
815 |
+
if( preg_match("/Nokia([^\/]+)\/([^ SP]+)/i",$this->_agent,$matches) ) {
|
816 |
+
$this->setVersion($matches[2]);
|
817 |
+
if( stripos($this->_agent,'Series60') !== false || strpos($this->_agent,'S60') !== false ) {
|
818 |
+
$this->setBrowser($this->BROWSER_NOKIA_S60);
|
819 |
+
}
|
820 |
+
else {
|
821 |
+
$this->setBrowser( $this->BROWSER_NOKIA );
|
822 |
+
}
|
823 |
+
$this->setMobile(true);
|
824 |
+
return true;
|
825 |
+
}
|
826 |
+
return false;
|
827 |
+
}
|
828 |
+
|
829 |
+
/**
|
830 |
+
* Determine if the browser is Firefox or not (last updated 1.7)
|
831 |
+
* @return boolean True if the browser is Firefox otherwise false
|
832 |
+
*/
|
833 |
+
function checkBrowserFirefox() {
|
834 |
+
if( stripos($this->_agent,'safari') === false ) {
|
835 |
+
if( preg_match("/Firefox[\/ \(]([^ ;\)]+)/i",$this->_agent,$matches) ) {
|
836 |
+
$this->setVersion($matches[1]);
|
837 |
+
$this->setBrowser($this->BROWSER_FIREFOX);
|
838 |
+
return true;
|
839 |
+
}
|
840 |
+
else if( preg_match("/Firefox$/i",$this->_agent,$matches) ) {
|
841 |
+
$this->setVersion("");
|
842 |
+
$this->setBrowser($this->BROWSER_FIREFOX);
|
843 |
+
return true;
|
844 |
+
}
|
845 |
+
}
|
846 |
+
return false;
|
847 |
+
}
|
848 |
+
|
849 |
+
/**
|
850 |
+
* Determine if the browser is Firefox or not (last updated 1.7)
|
851 |
+
* @return boolean True if the browser is Firefox otherwise false
|
852 |
+
*/
|
853 |
+
function checkBrowserIceweasel() {
|
854 |
+
if( stripos($this->_agent,'Iceweasel') !== false ) {
|
855 |
+
$aresult = explode('/',stristr($this->_agent,'Iceweasel'));
|
856 |
+
$aversion = explode(' ',$aresult[1]);
|
857 |
+
$this->setVersion($aversion[0]);
|
858 |
+
$this->setBrowser($this->BROWSER_ICEWEASEL);
|
859 |
+
return true;
|
860 |
+
}
|
861 |
+
return false;
|
862 |
+
}
|
863 |
+
/**
|
864 |
+
* Determine if the browser is Mozilla or not (last updated 1.7)
|
865 |
+
* @return boolean True if the browser is Mozilla otherwise false
|
866 |
+
*/
|
867 |
+
function checkBrowserMozilla() {
|
868 |
+
if( stripos($this->_agent,'mozilla') !== false && preg_match('/rv:[0-9].[0-9][a-b]?/i',$this->_agent) && stripos($this->_agent,'netscape') === false) {
|
869 |
+
$aversion = explode(' ',stristr($this->_agent,'rv:'));
|
870 |
+
preg_match('/rv:[0-9].[0-9][a-b]?/i',$this->_agent,$aversion);
|
871 |
+
$this->setVersion(str_replace('rv:','',$aversion[0]));
|
872 |
+
$this->setBrowser($this->BROWSER_MOZILLA);
|
873 |
+
return true;
|
874 |
+
}
|
875 |
+
else if( stripos($this->_agent,'mozilla') !== false && preg_match('/rv:[0-9]\.[0-9]/i',$this->_agent) && stripos($this->_agent,'netscape') === false ) {
|
876 |
+
$aversion = explode('',stristr($this->_agent,'rv:'));
|
877 |
+
$this->setVersion(str_replace('rv:','',$aversion[0]));
|
878 |
+
$this->setBrowser($this->BROWSER_MOZILLA);
|
879 |
+
return true;
|
880 |
+
}
|
881 |
+
else if( stripos($this->_agent,'mozilla') !== false && preg_match('/mozilla\/([^ ]*)/i',$this->_agent,$matches) && stripos($this->_agent,'netscape') === false ) {
|
882 |
+
$this->setVersion($matches[1]);
|
883 |
+
$this->setBrowser($this->BROWSER_MOZILLA);
|
884 |
+
return true;
|
885 |
+
}
|
886 |
+
return false;
|
887 |
+
}
|
888 |
+
|
889 |
+
/**
|
890 |
+
* Determine if the browser is Lynx or not (last updated 1.7)
|
891 |
+
* @return boolean True if the browser is Lynx otherwise false
|
892 |
+
*/
|
893 |
+
function checkBrowserLynx() {
|
894 |
+
if( stripos($this->_agent,'lynx') !== false ) {
|
895 |
+
$aresult = explode('/',stristr($this->_agent,'Lynx'));
|
896 |
+
$aversion = explode(' ',(isset($aresult[1])?$aresult[1]:""));
|
897 |
+
$this->setVersion($aversion[0]);
|
898 |
+
$this->setBrowser($this->BROWSER_LYNX);
|
899 |
+
return true;
|
900 |
+
}
|
901 |
+
return false;
|
902 |
+
}
|
903 |
+
|
904 |
+
/**
|
905 |
+
* Determine if the browser is Amaya or not (last updated 1.7)
|
906 |
+
* @return boolean True if the browser is Amaya otherwise false
|
907 |
+
*/
|
908 |
+
function checkBrowserAmaya() {
|
909 |
+
if( stripos($this->_agent,'amaya') !== false ) {
|
910 |
+
$aresult = explode('/',stristr($this->_agent,'Amaya'));
|
911 |
+
$aversion = explode(' ',$aresult[1]);
|
912 |
+
$this->setVersion($aversion[0]);
|
913 |
+
$this->setBrowser($this->BROWSER_AMAYA);
|
914 |
+
return true;
|
915 |
+
}
|
916 |
+
return false;
|
917 |
+
}
|
918 |
+
|
919 |
+
/**
|
920 |
+
* Determine if the browser is Safari or not (last updated 1.7)
|
921 |
+
* @return boolean True if the browser is Safari otherwise false
|
922 |
+
*/
|
923 |
+
function checkBrowserSafari() {
|
924 |
+
if( stripos($this->_agent,'Safari') !== false && stripos($this->_agent,'iPhone') === false && stripos($this->_agent,'iPod') === false ) {
|
925 |
+
$aresult = explode('/',stristr($this->_agent,'Version'));
|
926 |
+
if( isset($aresult[1]) ) {
|
927 |
+
$aversion = explode(' ',$aresult[1]);
|
928 |
+
$this->setVersion($aversion[0]);
|
929 |
+
}
|
930 |
+
else {
|
931 |
+
$this->setVersion($this->VERSION_UNKNOWN);
|
932 |
+
}
|
933 |
+
$this->setBrowser($this->BROWSER_SAFARI);
|
934 |
+
return true;
|
935 |
+
}
|
936 |
+
return false;
|
937 |
+
}
|
938 |
+
|
939 |
+
/**
|
940 |
+
* Determine if the browser is iPhone or not (last updated 1.7)
|
941 |
+
* @return boolean True if the browser is iPhone otherwise false
|
942 |
+
*/
|
943 |
+
function checkBrowseriPhone() {
|
944 |
+
if( stripos($this->_agent,'iPhone') !== false ) {
|
945 |
+
$aresult = explode('/',stristr($this->_agent,'Version'));
|
946 |
+
if( isset($aresult[1]) ) {
|
947 |
+
$aversion = explode(' ',$aresult[1]);
|
948 |
+
$this->setVersion($aversion[0]);
|
949 |
+
}
|
950 |
+
else {
|
951 |
+
$this->setVersion($this->VERSION_UNKNOWN);
|
952 |
+
}
|
953 |
+
$this->setMobile(true);
|
954 |
+
$this->setBrowser($this->BROWSER_IPHONE);
|
955 |
+
return true;
|
956 |
+
}
|
957 |
+
return false;
|
958 |
+
}
|
959 |
+
|
960 |
+
/**
|
961 |
+
* Determine if the browser is iPod or not (last updated 1.7)
|
962 |
+
* @return boolean True if the browser is iPod otherwise false
|
963 |
+
*/
|
964 |
+
function checkBrowseriPad() {
|
965 |
+
if( stripos($this->_agent,'iPad') !== false ) {
|
966 |
+
$aresult = explode('/',stristr($this->_agent,'Version'));
|
967 |
+
if( isset($aresult[1]) ) {
|
968 |
+
$aversion = explode(' ',$aresult[1]);
|
969 |
+
$this->setVersion($aversion[0]);
|
970 |
+
}
|
971 |
+
else {
|
972 |
+
$this->setVersion($this->VERSION_UNKNOWN);
|
973 |
+
}
|
974 |
+
$this->setMobile(true);
|
975 |
+
$this->setBrowser($this->BROWSER_IPAD);
|
976 |
+
return true;
|
977 |
+
}
|
978 |
+
return false;
|
979 |
+
}
|
980 |
+
|
981 |
+
/**
|
982 |
+
* Determine if the browser is iPod or not (last updated 1.7)
|
983 |
+
* @return boolean True if the browser is iPod otherwise false
|
984 |
+
*/
|
985 |
+
function checkBrowseriPod() {
|
986 |
+
if( stripos($this->_agent,'iPod') !== false ) {
|
987 |
+
$aresult = explode('/',stristr($this->_agent,'Version'));
|
988 |
+
if( isset($aresult[1]) ) {
|
989 |
+
$aversion = explode(' ',$aresult[1]);
|
990 |
+
$this->setVersion($aversion[0]);
|
991 |
+
}
|
992 |
+
else {
|
993 |
+
$this->setVersion($this->VERSION_UNKNOWN);
|
994 |
+
}
|
995 |
+
$this->setMobile(true);
|
996 |
+
$this->setBrowser($this->BROWSER_IPOD);
|
997 |
+
return true;
|
998 |
+
}
|
999 |
+
return false;
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
/**
|
1003 |
+
* Determine if the browser is Android or not (last updated 1.7)
|
1004 |
+
* @return boolean True if the browser is Android otherwise false
|
1005 |
+
*/
|
1006 |
+
function checkBrowserAndroid() {
|
1007 |
+
if( stripos($this->_agent,'Android') !== false ) {
|
1008 |
+
$aresult = explode(' ',stristr($this->_agent,'Android'));
|
1009 |
+
if( isset($aresult[1]) ) {
|
1010 |
+
$aversion = explode(' ',$aresult[1]);
|
1011 |
+
$this->setVersion($aversion[0]);
|
1012 |
+
}
|
1013 |
+
else {
|
1014 |
+
$this->setVersion($this->VERSION_UNKNOWN);
|
1015 |
+
}
|
1016 |
+
$this->setMobile(true);
|
1017 |
+
$this->setBrowser($this->BROWSER_ANDROID);
|
1018 |
+
return true;
|
1019 |
+
}
|
1020 |
+
return false;
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
/**
|
1024 |
+
* Determine the user's platform (last updated 1.7)
|
1025 |
+
*/
|
1026 |
+
function checkPlatform() {
|
1027 |
+
if( stripos($this->_agent, 'windows') !== false ) {
|
1028 |
+
$this->_platform = $this->PLATFORM_WINDOWS;
|
1029 |
+
}
|
1030 |
+
else if( stripos($this->_agent, 'iPad') !== false ) {
|
1031 |
+
$this->_platform = $this->PLATFORM_IPAD;
|
1032 |
+
}
|
1033 |
+
else if( stripos($this->_agent, 'iPod') !== false ) {
|
1034 |
+
$this->_platform = $this->PLATFORM_IPOD;
|
1035 |
+
}
|
1036 |
+
else if( stripos($this->_agent, 'iPhone') !== false ) {
|
1037 |
+
$this->_platform = $this->PLATFORM_IPHONE;
|
1038 |
+
}
|
1039 |
+
elseif( stripos($this->_agent, 'mac') !== false ) {
|
1040 |
+
$this->_platform = $this->PLATFORM_APPLE;
|
1041 |
+
}
|
1042 |
+
elseif( stripos($this->_agent, 'android') !== false ) {
|
1043 |
+
$this->_platform = $this->PLATFORM_ANDROID;
|
1044 |
+
}
|
1045 |
+
elseif( stripos($this->_agent, 'linux') !== false ) {
|
1046 |
+
$this->_platform = $this->PLATFORM_LINUX;
|
1047 |
+
}
|
1048 |
+
else if( stripos($this->_agent, 'Nokia') !== false ) {
|
1049 |
+
$this->_platform = $this->PLATFORM_NOKIA;
|
1050 |
+
}
|
1051 |
+
else if( stripos($this->_agent, 'BlackBerry') !== false ) {
|
1052 |
+
$this->_platform = $this->PLATFORM_BLACKBERRY;
|
1053 |
+
}
|
1054 |
+
elseif( stripos($this->_agent,'FreeBSD') !== false ) {
|
1055 |
+
$this->_platform = $this->PLATFORM_FREEBSD;
|
1056 |
+
}
|
1057 |
+
elseif( stripos($this->_agent,'OpenBSD') !== false ) {
|
1058 |
+
$this->_platform = $this->PLATFORM_OPENBSD;
|
1059 |
+
}
|
1060 |
+
elseif( stripos($this->_agent,'NetBSD') !== false ) {
|
1061 |
+
$this->_platform = $this->PLATFORM_NETBSD;
|
1062 |
+
}
|
1063 |
+
elseif( stripos($this->_agent, 'OpenSolaris') !== false ) {
|
1064 |
+
$this->_platform = $this->PLATFORM_OPENSOLARIS;
|
1065 |
+
}
|
1066 |
+
elseif( stripos($this->_agent, 'SunOS') !== false ) {
|
1067 |
+
$this->_platform = $this->PLATFORM_SUNOS;
|
1068 |
+
}
|
1069 |
+
elseif( stripos($this->_agent, 'OS\/2') !== false ) {
|
1070 |
+
$this->_platform = $this->PLATFORM_OS2;
|
1071 |
+
}
|
1072 |
+
elseif( stripos($this->_agent, 'BeOS') !== false ) {
|
1073 |
+
$this->_platform = $this->PLATFORM_BEOS;
|
1074 |
+
}
|
1075 |
+
elseif( stripos($this->_agent, 'win') !== false ) {
|
1076 |
+
$this->_platform = $this->PLATFORM_WINDOWS;
|
1077 |
+
}
|
1078 |
+
|
1079 |
+
}
|
1080 |
+
}
|
1081 |
+
|
1082 |
+
?>
|
includes/libraries/php-markdown/markdown.php
CHANGED
@@ -1,2932 +1,2932 @@
|
|
1 |
-
<?php
|
2 |
-
#
|
3 |
-
# Markdown Extra - A text-to-HTML conversion tool for web writers
|
4 |
-
#
|
5 |
-
# PHP Markdown & Extra
|
6 |
-
# Copyright (c) 2004-2009 Michel Fortin
|
7 |
-
# <http://michelf.com/projects/php-markdown/>
|
8 |
-
#
|
9 |
-
# Original Markdown
|
10 |
-
# Copyright (c) 2004-2006 John Gruber
|
11 |
-
# <http://daringfireball.net/projects/markdown/>
|
12 |
-
#
|
13 |
-
|
14 |
-
|
15 |
-
define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
|
16 |
-
define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009
|
17 |
-
|
18 |
-
|
19 |
-
#
|
20 |
-
# Global default settings:
|
21 |
-
#
|
22 |
-
|
23 |
-
# Change to ">" for HTML output
|
24 |
-
@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />");
|
25 |
-
|
26 |
-
# Define the width of a tab for code blocks.
|
27 |
-
@define( 'MARKDOWN_TAB_WIDTH', 4 );
|
28 |
-
|
29 |
-
# Optional title attribute for footnote links and backlinks.
|
30 |
-
@define( 'MARKDOWN_FN_LINK_TITLE', "" );
|
31 |
-
@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" );
|
32 |
-
|
33 |
-
# Optional class attribute for footnote links and backlinks.
|
34 |
-
@define( 'MARKDOWN_FN_LINK_CLASS', "" );
|
35 |
-
@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
|
36 |
-
|
37 |
-
|
38 |
-
#
|
39 |
-
# WordPress settings:
|
40 |
-
#
|
41 |
-
|
42 |
-
# Change to false to remove Markdown from posts and/or comments.
|
43 |
-
@define( 'MARKDOWN_WP_POSTS', true );
|
44 |
-
@define( 'MARKDOWN_WP_COMMENTS', true );
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
### Standard Function Interface ###
|
49 |
-
|
50 |
-
@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' );
|
51 |
-
|
52 |
-
function Markdown($text) {
|
53 |
-
#
|
54 |
-
# Initialize the parser and return the result of its transform method.
|
55 |
-
#
|
56 |
-
# Setup static parser variable.
|
57 |
-
static $parser;
|
58 |
-
if (!isset($parser)) {
|
59 |
-
$parser_class = MARKDOWN_PARSER_CLASS;
|
60 |
-
$parser = new $parser_class;
|
61 |
-
}
|
62 |
-
|
63 |
-
# Transform text using parser.
|
64 |
-
return $parser->transform($text);
|
65 |
-
}
|
66 |
-
|
67 |
-
|
68 |
-
### WordPress Plugin Interface ###
|
69 |
-
|
70 |
-
/*
|
71 |
-
Plugin Name: Markdown Extra
|
72 |
-
Plugin URI: http://michelf.com/projects/php-markdown/
|
73 |
-
Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>
|
74 |
-
Version: 1.2.4
|
75 |
-
Author: Michel Fortin
|
76 |
-
Author URI: http://michelf.com/
|
77 |
-
*/
|
78 |
-
|
79 |
-
if (isset($wp_version)) {
|
80 |
-
# More details about how it works here:
|
81 |
-
# <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
|
82 |
-
|
83 |
-
# Post content and excerpts
|
84 |
-
# - Remove WordPress paragraph generator.
|
85 |
-
# - Run Markdown on excerpt, then remove all tags.
|
86 |
-
# - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
|
87 |
-
if (MARKDOWN_WP_POSTS) {
|
88 |
-
remove_filter('the_content', 'wpautop');
|
89 |
-
remove_filter('the_content_rss', 'wpautop');
|
90 |
-
remove_filter('the_excerpt', 'wpautop');
|
91 |
-
add_filter('the_content', 'mdwp_MarkdownPost', 6);
|
92 |
-
add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
|
93 |
-
add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
|
94 |
-
add_filter('get_the_excerpt', 'trim', 7);
|
95 |
-
add_filter('the_excerpt', 'mdwp_add_p');
|
96 |
-
add_filter('the_excerpt_rss', 'mdwp_strip_p');
|
97 |
-
|
98 |
-
remove_filter('content_save_pre', 'balanceTags', 50);
|
99 |
-
remove_filter('excerpt_save_pre', 'balanceTags', 50);
|
100 |
-
add_filter('the_content', 'balanceTags', 50);
|
101 |
-
add_filter('get_the_excerpt', 'balanceTags', 9);
|
102 |
-
}
|
103 |
-
|
104 |
-
# Add a footnote id prefix to posts when inside a loop.
|
105 |
-
function mdwp_MarkdownPost($text) {
|
106 |
-
static $parser;
|
107 |
-
if (!$parser) {
|
108 |
-
$parser_class = MARKDOWN_PARSER_CLASS;
|
109 |
-
$parser = new $parser_class;
|
110 |
-
}
|
111 |
-
if (is_single() || is_page() || is_feed()) {
|
112 |
-
$parser->fn_id_prefix = "";
|
113 |
-
} else {
|
114 |
-
$parser->fn_id_prefix = get_the_ID() . ".";
|
115 |
-
}
|
116 |
-
return $parser->transform($text);
|
117 |
-
}
|
118 |
-
|
119 |
-
# Comments
|
120 |
-
# - Remove WordPress paragraph generator.
|
121 |
-
# - Remove WordPress auto-link generator.
|
122 |
-
# - Scramble important tags before passing them to the kses filter.
|
123 |
-
# - Run Markdown on excerpt then remove paragraph tags.
|
124 |
-
if (MARKDOWN_WP_COMMENTS) {
|
125 |
-
remove_filter('comment_text', 'wpautop', 30);
|
126 |
-
remove_filter('comment_text', 'make_clickable');
|
127 |
-
add_filter('pre_comment_content', 'Markdown', 6);
|
128 |
-
add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
|
129 |
-
add_filter('pre_comment_content', 'mdwp_show_tags', 12);
|
130 |
-
add_filter('get_comment_text', 'Markdown', 6);
|
131 |
-
add_filter('get_comment_excerpt', 'Markdown', 6);
|
132 |
-
add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
|
133 |
-
|
134 |
-
global $mdwp_hidden_tags, $mdwp_placeholders;
|
135 |
-
$mdwp_hidden_tags = explode(' ',
|
136 |
-
'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
|
137 |
-
$mdwp_placeholders = explode(' ', str_rot13(
|
138 |
-
'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
|
139 |
-
'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
|
140 |
-
}
|
141 |
-
|
142 |
-
function mdwp_add_p($text) {
|
143 |
-
if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
|
144 |
-
$text = '<p>'.$text.'</p>';
|
145 |
-
$text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
|
146 |
-
}
|
147 |
-
return $text;
|
148 |
-
}
|
149 |
-
|
150 |
-
function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
|
151 |
-
|
152 |
-
function mdwp_hide_tags($text) {
|
153 |
-
global $mdwp_hidden_tags, $mdwp_placeholders;
|
154 |
-
return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
|
155 |
-
}
|
156 |
-
function mdwp_show_tags($text) {
|
157 |
-
global $mdwp_hidden_tags, $mdwp_placeholders;
|
158 |
-
return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
|
159 |
-
}
|
160 |
-
}
|
161 |
-
|
162 |
-
|
163 |
-
### bBlog Plugin Info ###
|
164 |
-
|
165 |
-
function identify_modifier_markdown() {
|
166 |
-
return array(
|
167 |
-
'name' => 'markdown',
|
168 |
-
'type' => 'modifier',
|
169 |
-
'nicename' => 'PHP Markdown Extra',
|
170 |
-
'description' => 'A text-to-HTML conversion tool for web writers',
|
171 |
-
'authors' => 'Michel Fortin and John Gruber',
|
172 |
-
'licence' => 'GPL',
|
173 |
-
'version' => MARKDOWNEXTRA_VERSION,
|
174 |
-
'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
|
175 |
-
);
|
176 |
-
}
|
177 |
-
|
178 |
-
|
179 |
-
### Smarty Modifier Interface ###
|
180 |
-
|
181 |
-
function smarty_modifier_markdown($text) {
|
182 |
-
return Markdown($text);
|
183 |
-
}
|
184 |
-
|
185 |
-
|
186 |
-
### Textile Compatibility Mode ###
|
187 |
-
|
188 |
-
# Rename this file to "classTextile.php" and it can replace Textile everywhere.
|
189 |
-
|
190 |
-
if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
|
191 |
-
# Try to include PHP SmartyPants. Should be in the same directory.
|
192 |
-
@include_once 'smartypants.php';
|
193 |
-
# Fake Textile class. It calls Markdown instead.
|
194 |
-
class Textile {
|
195 |
-
function TextileThis($text, $lite='', $encode='') {
|
196 |
-
if ($lite == '' && $encode == '') $text = Markdown($text);
|
197 |
-
if (function_exists('SmartyPants')) $text = SmartyPants($text);
|
198 |
-
return $text;
|
199 |
-
}
|
200 |
-
# Fake restricted version: restrictions are not supported for now.
|
201 |
-
function TextileRestricted($text, $lite='', $noimage='') {
|
202 |
-
return $this->TextileThis($text, $lite);
|
203 |
-
}
|
204 |
-
# Workaround to ensure compatibility with TextPattern 4.0.3.
|
205 |
-
function blockLite($text) { return $text; }
|
206 |
-
}
|
207 |
-
}
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
#
|
212 |
-
# Markdown Parser Class
|
213 |
-
#
|
214 |
-
|
215 |
-
class Markdown_Parser {
|
216 |
-
|
217 |
-
# Regex to match balanced [brackets].
|
218 |
-
# Needed to insert a maximum bracked depth while converting to PHP.
|
219 |
-
var $nested_brackets_depth = 6;
|
220 |
-
var $nested_brackets_re;
|
221 |
-
|
222 |
-
var $nested_url_parenthesis_depth = 4;
|
223 |
-
var $nested_url_parenthesis_re;
|
224 |
-
|
225 |
-
# Table of hash values for escaped characters:
|
226 |
-
var $escape_chars = '\`*_{}[]()>#+-.!';
|
227 |
-
var $escape_chars_re;
|
228 |
-
|
229 |
-
# Change to ">" for HTML output.
|
230 |
-
var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
|
231 |
-
var $tab_width = MARKDOWN_TAB_WIDTH;
|
232 |
-
|
233 |
-
# Change to `true` to disallow markup or entities.
|
234 |
-
var $no_markup = false;
|
235 |
-
var $no_entities = false;
|
236 |
-
|
237 |
-
# Predefined urls and titles for reference links and images.
|
238 |
-
var $predef_urls = array();
|
239 |
-
var $predef_titles = array();
|
240 |
-
|
241 |
-
|
242 |
-
function Markdown_Parser() {
|
243 |
-
#
|
244 |
-
# Constructor function. Initialize appropriate member variables.
|
245 |
-
#
|
246 |
-
$this->_initDetab();
|
247 |
-
$this->prepareItalicsAndBold();
|
248 |
-
|
249 |
-
$this->nested_brackets_re =
|
250 |
-
str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
|
251 |
-
str_repeat('\])*', $this->nested_brackets_depth);
|
252 |
-
|
253 |
-
$this->nested_url_parenthesis_re =
|
254 |
-
str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
|
255 |
-
str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
|
256 |
-
|
257 |
-
$this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
|
258 |
-
|
259 |
-
# Sort document, block, and span gamut in ascendent priority order.
|
260 |
-
asort($this->document_gamut);
|
261 |
-
asort($this->block_gamut);
|
262 |
-
asort($this->span_gamut);
|
263 |
-
}
|
264 |
-
|
265 |
-
|
266 |
-
# Internal hashes used during transformation.
|
267 |
-
var $urls = array();
|
268 |
-
var $titles = array();
|
269 |
-
var $html_hashes = array();
|
270 |
-
|
271 |
-
# Status flag to avoid invalid nesting.
|
272 |
-
var $in_anchor = false;
|
273 |
-
|
274 |
-
|
275 |
-
function setup() {
|
276 |
-
#
|
277 |
-
# Called before the transformation process starts to setup parser
|
278 |
-
# states.
|
279 |
-
#
|
280 |
-
# Clear global hashes.
|
281 |
-
$this->urls = $this->predef_urls;
|
282 |
-
$this->titles = $this->predef_titles;
|
283 |
-
$this->html_hashes = array();
|
284 |
-
|
285 |
-
$in_anchor = false;
|
286 |
-
}
|
287 |
-
|
288 |
-
function teardown() {
|
289 |
-
#
|
290 |
-
# Called after the transformation process to clear any variable
|
291 |
-
# which may be taking up memory unnecessarly.
|
292 |
-
#
|
293 |
-
$this->urls = array();
|
294 |
-
$this->titles = array();
|
295 |
-
$this->html_hashes = array();
|
296 |
-
}
|
297 |
-
|
298 |
-
|
299 |
-
function transform($text) {
|
300 |
-
#
|
301 |
-
# Main function. Performs some preprocessing on the input text
|
302 |
-
# and pass it through the document gamut.
|
303 |
-
#
|
304 |
-
$this->setup();
|
305 |
-
|
306 |
-
# Remove UTF-8 BOM and marker character in input, if present.
|
307 |
-
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
|
308 |
-
|
309 |
-
# Standardize line endings:
|
310 |
-
# DOS to Unix and Mac to Unix
|
311 |
-
$text = preg_replace('{\r\n?}', "\n", $text);
|
312 |
-
|
313 |
-
# Make sure $text ends with a couple of newlines:
|
314 |
-
$text .= "\n\n";
|
315 |
-
|
316 |
-
# Convert all tabs to spaces.
|
317 |
-
$text = $this->detab($text);
|
318 |
-
|
319 |
-
# Turn block-level HTML blocks into hash entries
|
320 |
-
$text = $this->hashHTMLBlocks($text);
|
321 |
-
|
322 |
-
# Strip any lines consisting only of spaces and tabs.
|
323 |
-
# This makes subsequent regexen easier to write, because we can
|
324 |
-
# match consecutive blank lines with /\n+/ instead of something
|
325 |
-
# contorted like /[ ]*\n+/ .
|
326 |
-
$text = preg_replace('/^[ ]+$/m', '', $text);
|
327 |
-
|
328 |
-
# Run document gamut methods.
|
329 |
-
foreach ($this->document_gamut as $method => $priority) {
|
330 |
-
$text = $this->$method($text);
|
331 |
-
}
|
332 |
-
|
333 |
-
$this->teardown();
|
334 |
-
|
335 |
-
return $text . "\n";
|
336 |
-
}
|
337 |
-
|
338 |
-
var $document_gamut = array(
|
339 |
-
# Strip link definitions, store in hashes.
|
340 |
-
"stripLinkDefinitions" => 20,
|
341 |
-
|
342 |
-
"runBasicBlockGamut" => 30,
|
343 |
-
);
|
344 |
-
|
345 |
-
|
346 |
-
function stripLinkDefinitions($text) {
|
347 |
-
#
|
348 |
-
# Strips link definitions from text, stores the URLs and titles in
|
349 |
-
# hash references.
|
350 |
-
#
|
351 |
-
$less_than_tab = $this->tab_width - 1;
|
352 |
-
|
353 |
-
# Link defs are in the form: ^[id]: url "optional title"
|
354 |
-
$text = preg_replace_callback('{
|
355 |
-
^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
|
356 |
-
[ ]*
|
357 |
-
\n? # maybe *one* newline
|
358 |
-
[ ]*
|
359 |
-
(?:
|
360 |
-
<(.+?)> # url = $2
|
361 |
-
|
|
362 |
-
(\S+?) # url = $3
|
363 |
-
)
|
364 |
-
[ ]*
|
365 |
-
\n? # maybe one newline
|
366 |
-
[ ]*
|
367 |
-
(?:
|
368 |
-
(?<=\s) # lookbehind for whitespace
|
369 |
-
["(]
|
370 |
-
(.*?) # title = $4
|
371 |
-
[")]
|
372 |
-
[ ]*
|
373 |
-
)? # title is optional
|
374 |
-
(?:\n+|\Z)
|
375 |
-
}xm',
|
376 |
-
array(&$this, '_stripLinkDefinitions_callback'),
|
377 |
-
$text);
|
378 |
-
return $text;
|
379 |
-
}
|
380 |
-
function _stripLinkDefinitions_callback($matches) {
|
381 |
-
$link_id = strtolower($matches[1]);
|
382 |
-
$url = $matches[2] == '' ? $matches[3] : $matches[2];
|
383 |
-
$this->urls[$link_id] = $url;
|
384 |
-
$this->titles[$link_id] =& $matches[4];
|
385 |
-
return ''; # String that will replace the block
|
386 |
-
}
|
387 |
-
|
388 |
-
|
389 |
-
function hashHTMLBlocks($text) {
|
390 |
-
if ($this->no_markup) return $text;
|
391 |
-
|
392 |
-
$less_than_tab = $this->tab_width - 1;
|
393 |
-
|
394 |
-
# Hashify HTML blocks:
|
395 |
-
# We only want to do this for block-level HTML tags, such as headers,
|
396 |
-
# lists, and tables. That's because we still want to wrap <p>s around
|
397 |
-
# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
|
398 |
-
# phrase emphasis, and spans. The list of tags we're looking for is
|
399 |
-
# hard-coded:
|
400 |
-
#
|
401 |
-
# * List "a" is made of tags which can be both inline or block-level.
|
402 |
-
# These will be treated block-level when the start tag is alone on
|
403 |
-
# its line, otherwise they're not matched here and will be taken as
|
404 |
-
# inline later.
|
405 |
-
# * List "b" is made of tags which are always block-level;
|
406 |
-
#
|
407 |
-
$block_tags_a_re = 'ins|del';
|
408 |
-
$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
|
409 |
-
'script|noscript|form|fieldset|iframe|math';
|
410 |
-
|
411 |
-
# Regular expression for the content of a block tag.
|
412 |
-
$nested_tags_level = 4;
|
413 |
-
$attr = '
|
414 |
-
(?> # optional tag attributes
|
415 |
-
\s # starts with whitespace
|
416 |
-
(?>
|
417 |
-
[^>"/]+ # text outside quotes
|
418 |
-
|
|
419 |
-
/+(?!>) # slash not followed by ">"
|
420 |
-
|
|
421 |
-
"[^"]*" # text inside double quotes (tolerate ">")
|
422 |
-
|
|
423 |
-
\'[^\']*\' # text inside single quotes (tolerate ">")
|
424 |
-
)*
|
425 |
-
)?
|
426 |
-
';
|
427 |
-
$content =
|
428 |
-
str_repeat('
|
429 |
-
(?>
|
430 |
-
[^<]+ # content without tag
|
431 |
-
|
|
432 |
-
<\2 # nested opening tag
|
433 |
-
'.$attr.' # attributes
|
434 |
-
(?>
|
435 |
-
/>
|
436 |
-
|
|
437 |
-
>', $nested_tags_level). # end of opening tag
|
438 |
-
'.*?'. # last level nested tag content
|
439 |
-
str_repeat('
|
440 |
-
</\2\s*> # closing nested tag
|
441 |
-
)
|
442 |
-
|
|
443 |
-
<(?!/\2\s*> # other tags with a different name
|
444 |
-
)
|
445 |
-
)*',
|
446 |
-
$nested_tags_level);
|
447 |
-
$content2 = str_replace('\2', '\3', $content);
|
448 |
-
|
449 |
-
# First, look for nested blocks, e.g.:
|
450 |
-
# <div>
|
451 |
-
# <div>
|
452 |
-
# tags for inner block must be indented.
|
453 |
-
# </div>
|
454 |
-
# </div>
|
455 |
-
#
|
456 |
-
# The outermost tags must start at the left margin for this to match, and
|
457 |
-
# the inner nested divs must be indented.
|
458 |
-
# We need to do this before the next, more liberal match, because the next
|
459 |
-
# match will start at the first `<div>` and stop at the first `</div>`.
|
460 |
-
$text = preg_replace_callback('{(?>
|
461 |
-
(?>
|
462 |
-
(?<=\n\n) # Starting after a blank line
|
463 |
-
| # or
|
464 |
-
\A\n? # the beginning of the doc
|
465 |
-
)
|
466 |
-
( # save in $1
|
467 |
-
|
468 |
-
# Match from `\n<tag>` to `</tag>\n`, handling nested tags
|
469 |
-
# in between.
|
470 |
-
|
471 |
-
[ ]{0,'.$less_than_tab.'}
|
472 |
-
<('.$block_tags_b_re.')# start tag = $2
|
473 |
-
'.$attr.'> # attributes followed by > and \n
|
474 |
-
'.$content.' # content, support nesting
|
475 |
-
</\2> # the matching end tag
|
476 |
-
[ ]* # trailing spaces/tabs
|
477 |
-
(?=\n+|\Z) # followed by a newline or end of document
|
478 |
-
|
479 |
-
| # Special version for tags of group a.
|
480 |
-
|
481 |
-
[ ]{0,'.$less_than_tab.'}
|
482 |
-
<('.$block_tags_a_re.')# start tag = $3
|
483 |
-
'.$attr.'>[ ]*\n # attributes followed by >
|
484 |
-
'.$content2.' # content, support nesting
|
485 |
-
</\3> # the matching end tag
|
486 |
-
[ ]* # trailing spaces/tabs
|
487 |
-
(?=\n+|\Z) # followed by a newline or end of document
|
488 |
-
|
489 |
-
| # Special case just for <hr />. It was easier to make a special
|
490 |
-
# case than to make the other regex more complicated.
|
491 |
-
|
492 |
-
[ ]{0,'.$less_than_tab.'}
|
493 |
-
<(hr) # start tag = $2
|
494 |
-
'.$attr.' # attributes
|
495 |
-
/?> # the matching end tag
|
496 |
-
[ ]*
|
497 |
-
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
498 |
-
|
499 |
-
| # Special case for standalone HTML comments:
|
500 |
-
|
501 |
-
[ ]{0,'.$less_than_tab.'}
|
502 |
-
(?s:
|
503 |
-
<!-- .*? -->
|
504 |
-
)
|
505 |
-
[ ]*
|
506 |
-
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
507 |
-
|
508 |
-
| # PHP and ASP-style processor instructions (<? and <%)
|
509 |
-
|
510 |
-
[ ]{0,'.$less_than_tab.'}
|
511 |
-
(?s:
|
512 |
-
<([?%]) # $2
|
513 |
-
.*?
|
514 |
-
\2>
|
515 |
-
)
|
516 |
-
[ ]*
|
517 |
-
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
518 |
-
|
519 |
-
)
|
520 |
-
)}Sxmi',
|
521 |
-
array(&$this, '_hashHTMLBlocks_callback'),
|
522 |
-
$text);
|
523 |
-
|
524 |
-
return $text;
|
525 |
-
}
|
526 |
-
function _hashHTMLBlocks_callback($matches) {
|
527 |
-
$text = $matches[1];
|
528 |
-
$key = $this->hashBlock($text);
|
529 |
-
return "\n\n$key\n\n";
|
530 |
-
}
|
531 |
-
|
532 |
-
|
533 |
-
function hashPart($text, $boundary = 'X') {
|
534 |
-
#
|
535 |
-
# Called whenever a tag must be hashed when a function insert an atomic
|
536 |
-
# element in the text stream. Passing $text to through this function gives
|
537 |
-
# a unique text-token which will be reverted back when calling unhash.
|
538 |
-
#
|
539 |
-
# The $boundary argument specify what character should be used to surround
|
540 |
-
# the token. By convension, "B" is used for block elements that needs not
|
541 |
-
# to be wrapped into paragraph tags at the end, ":" is used for elements
|
542 |
-
# that are word separators and "X" is used in the general case.
|
543 |
-
#
|
544 |
-
# Swap back any tag hash found in $text so we do not have to `unhash`
|
545 |
-
# multiple times at the end.
|
546 |
-
$text = $this->unhash($text);
|
547 |
-
|
548 |
-
# Then hash the block.
|
549 |
-
static $i = 0;
|
550 |
-
$key = "$boundary\x1A" . ++$i . $boundary;
|
551 |
-
$this->html_hashes[$key] = $text;
|
552 |
-
return $key; # String that will replace the tag.
|
553 |
-
}
|
554 |
-
|
555 |
-
|
556 |
-
function hashBlock($text) {
|
557 |
-
#
|
558 |
-
# Shortcut function for hashPart with block-level boundaries.
|
559 |
-
#
|
560 |
-
return $this->hashPart($text, 'B');
|
561 |
-
}
|
562 |
-
|
563 |
-
|
564 |
-
var $block_gamut = array(
|
565 |
-
#
|
566 |
-
# These are all the transformations that form block-level
|
567 |
-
# tags like paragraphs, headers, and list items.
|
568 |
-
#
|
569 |
-
"doHeaders" => 10,
|
570 |
-
"doHorizontalRules" => 20,
|
571 |
-
|
572 |
-
"doLists" => 40,
|
573 |
-
"doCodeBlocks" => 50,
|
574 |
-
"doBlockQuotes" => 60,
|
575 |
-
);
|
576 |
-
|
577 |
-
function runBlockGamut($text) {
|
578 |
-
#
|
579 |
-
# Run block gamut tranformations.
|
580 |
-
#
|
581 |
-
# We need to escape raw HTML in Markdown source before doing anything
|
582 |
-
# else. This need to be done for each block, and not only at the
|
583 |
-
# begining in the Markdown function since hashed blocks can be part of
|
584 |
-
# list items and could have been indented. Indented blocks would have
|
585 |
-
# been seen as a code block in a previous pass of hashHTMLBlocks.
|
586 |
-
$text = $this->hashHTMLBlocks($text);
|
587 |
-
|
588 |
-
return $this->runBasicBlockGamut($text);
|
589 |
-
}
|
590 |
-
|
591 |
-
function runBasicBlockGamut($text) {
|
592 |
-
#
|
593 |
-
# Run block gamut tranformations, without hashing HTML blocks. This is
|
594 |
-
# useful when HTML blocks are known to be already hashed, like in the first
|
595 |
-
# whole-document pass.
|
596 |
-
#
|
597 |
-
foreach ($this->block_gamut as $method => $priority) {
|
598 |
-
$text = $this->$method($text);
|
599 |
-
}
|
600 |
-
|
601 |
-
# Finally form paragraph and restore hashed blocks.
|
602 |
-
$text = $this->formParagraphs($text);
|
603 |
-
|
604 |
-
return $text;
|
605 |
-
}
|
606 |
-
|
607 |
-
|
608 |
-
function doHorizontalRules($text) {
|
609 |
-
# Do Horizontal Rules:
|
610 |
-
return preg_replace(
|
611 |
-
'{
|
612 |
-
^[ ]{0,3} # Leading space
|
613 |
-
([-*_]) # $1: First marker
|
614 |
-
(?> # Repeated marker group
|
615 |
-
[ ]{0,2} # Zero, one, or two spaces.
|
616 |
-
\1 # Marker character
|
617 |
-
){2,} # Group repeated at least twice
|
618 |
-
[ ]* # Tailing spaces
|
619 |
-
$ # End of line.
|
620 |
-
}mx',
|
621 |
-
"\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
|
622 |
-
$text);
|
623 |
-
}
|
624 |
-
|
625 |
-
|
626 |
-
var $span_gamut = array(
|
627 |
-
#
|
628 |
-
# These are all the transformations that occur *within* block-level
|
629 |
-
# tags like paragraphs, headers, and list items.
|
630 |
-
#
|
631 |
-
# Process character escapes, code spans, and inline HTML
|
632 |
-
# in one shot.
|
633 |
-
"parseSpan" => -30,
|
634 |
-
|
635 |
-
# Process anchor and image tags. Images must come first,
|
636 |
-
# because ![foo][f] looks like an anchor.
|
637 |
-
"doImages" => 10,
|
638 |
-
"doAnchors" => 20,
|
639 |
-
|
640 |
-
# Make links out of things like `<http://example.com/>`
|
641 |
-
# Must come after doAnchors, because you can use < and >
|
642 |
-
# delimiters in inline links like [this](<url>).
|
643 |
-
"doAutoLinks" => 30,
|
644 |
-
"encodeAmpsAndAngles" => 40,
|
645 |
-
|
646 |
-
"doItalicsAndBold" => 50,
|
647 |
-
"doHardBreaks" => 60,
|
648 |
-
);
|
649 |
-
|
650 |
-
function runSpanGamut($text) {
|
651 |
-
#
|
652 |
-
# Run span gamut tranformations.
|
653 |
-
#
|
654 |
-
foreach ($this->span_gamut as $method => $priority) {
|
655 |
-
$text = $this->$method($text);
|
656 |
-
}
|
657 |
-
|
658 |
-
return $text;
|
659 |
-
}
|
660 |
-
|
661 |
-
|
662 |
-
function doHardBreaks($text) {
|
663 |
-
# Do hard breaks:
|
664 |
-
return preg_replace_callback('/ {2,}\n/',
|
665 |
-
array(&$this, '_doHardBreaks_callback'), $text);
|
666 |
-
}
|
667 |
-
function _doHardBreaks_callback($matches) {
|
668 |
-
return $this->hashPart("<br$this->empty_element_suffix\n");
|
669 |
-
}
|
670 |
-
|
671 |
-
|
672 |
-
function doAnchors($text) {
|
673 |
-
#
|
674 |
-
# Turn Markdown link shortcuts into XHTML <a> tags.
|
675 |
-
#
|
676 |
-
if ($this->in_anchor) return $text;
|
677 |
-
$this->in_anchor = true;
|
678 |
-
|
679 |
-
#
|
680 |
-
# First, handle reference-style links: [link text] [id]
|
681 |
-
#
|
682 |
-
$text = preg_replace_callback('{
|
683 |
-
( # wrap whole match in $1
|
684 |
-
\[
|
685 |
-
('.$this->nested_brackets_re.') # link text = $2
|
686 |
-
\]
|
687 |
-
|
688 |
-
[ ]? # one optional space
|
689 |
-
(?:\n[ ]*)? # one optional newline followed by spaces
|
690 |
-
|
691 |
-
\[
|
692 |
-
(.*?) # id = $3
|
693 |
-
\]
|
694 |
-
)
|
695 |
-
}xs',
|
696 |
-
array(&$this, '_doAnchors_reference_callback'), $text);
|
697 |
-
|
698 |
-
#
|
699 |
-
# Next, inline-style links: [link text](url "optional title")
|
700 |
-
#
|
701 |
-
$text = preg_replace_callback('{
|
702 |
-
( # wrap whole match in $1
|
703 |
-
\[
|
704 |
-
('.$this->nested_brackets_re.') # link text = $2
|
705 |
-
\]
|
706 |
-
\( # literal paren
|
707 |
-
[ \n]*
|
708 |
-
(?:
|
709 |
-
<(.+?)> # href = $3
|
710 |
-
|
|
711 |
-
('.$this->nested_url_parenthesis_re.') # href = $4
|
712 |
-
)
|
713 |
-
[ \n]*
|
714 |
-
( # $5
|
715 |
-
([\'"]) # quote char = $6
|
716 |
-
(.*?) # Title = $7
|
717 |
-
\6 # matching quote
|
718 |
-
[ \n]* # ignore any spaces/tabs between closing quote and )
|
719 |
-
)? # title is optional
|
720 |
-
\)
|
721 |
-
)
|
722 |
-
}xs',
|
723 |
-
array(&$this, '_doAnchors_inline_callback'), $text);
|
724 |
-
|
725 |
-
#
|
726 |
-
# Last, handle reference-style shortcuts: [link text]
|
727 |
-
# These must come last in case you've also got [link text][1]
|
728 |
-
# or [link text](/foo)
|
729 |
-
#
|
730 |
-
$text = preg_replace_callback('{
|
731 |
-
( # wrap whole match in $1
|
732 |
-
\[
|
733 |
-
([^\[\]]+) # link text = $2; can\'t contain [ or ]
|
734 |
-
\]
|
735 |
-
)
|
736 |
-
}xs',
|
737 |
-
array(&$this, '_doAnchors_reference_callback'), $text);
|
738 |
-
|
739 |
-
$this->in_anchor = false;
|
740 |
-
return $text;
|
741 |
-
}
|
742 |
-
function _doAnchors_reference_callback($matches) {
|
743 |
-
$whole_match = $matches[1];
|
744 |
-
$link_text = $matches[2];
|
745 |
-
$link_id =& $matches[3];
|
746 |
-
|
747 |
-
if ($link_id == "") {
|
748 |
-
# for shortcut links like [this][] or [this].
|
749 |
-
$link_id = $link_text;
|
750 |
-
}
|
751 |
-
|
752 |
-
# lower-case and turn embedded newlines into spaces
|
753 |
-
$link_id = strtolower($link_id);
|
754 |
-
$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
|
755 |
-
|
756 |
-
if (isset($this->urls[$link_id])) {
|
757 |
-
$url = $this->urls[$link_id];
|
758 |
-
$url = $this->encodeAttribute($url);
|
759 |
-
|
760 |
-
$result = "<a href=\"$url\"";
|
761 |
-
if ( isset( $this->titles[$link_id] ) ) {
|
762 |
-
$title = $this->titles[$link_id];
|
763 |
-
$title = $this->encodeAttribute($title);
|
764 |
-
$result .= " title=\"$title\"";
|
765 |
-
}
|
766 |
-
|
767 |
-
$link_text = $this->runSpanGamut($link_text);
|
768 |
-
$result .= ">$link_text</a>";
|
769 |
-
$result = $this->hashPart($result);
|
770 |
-
}
|
771 |
-
else {
|
772 |
-
$result = $whole_match;
|
773 |
-
}
|
774 |
-
return $result;
|
775 |
-
}
|
776 |
-
function _doAnchors_inline_callback($matches) {
|
777 |
-
$whole_match = $matches[1];
|
778 |
-
$link_text = $this->runSpanGamut($matches[2]);
|
779 |
-
$url = $matches[3] == '' ? $matches[4] : $matches[3];
|
780 |
-
$title =& $matches[7];
|
781 |
-
|
782 |
-
$url = $this->encodeAttribute($url);
|
783 |
-
|
784 |
-
$result = "<a href=\"$url\"";
|
785 |
-
if (isset($title)) {
|
786 |
-
$title = $this->encodeAttribute($title);
|
787 |
-
$result .= " title=\"$title\"";
|
788 |
-
}
|
789 |
-
|
790 |
-
$link_text = $this->runSpanGamut($link_text);
|
791 |
-
$result .= ">$link_text</a>";
|
792 |
-
|
793 |
-
return $this->hashPart($result);
|
794 |
-
}
|
795 |
-
|
796 |
-
|
797 |
-
function doImages($text) {
|
798 |
-
#
|
799 |
-
# Turn Markdown image shortcuts into <img> tags.
|
800 |
-
#
|
801 |
-
#
|
802 |
-
# First, handle reference-style labeled images: ![alt text][id]
|
803 |
-
#
|
804 |
-
$text = preg_replace_callback('{
|
805 |
-
( # wrap whole match in $1
|
806 |
-
!\[
|
807 |
-
('.$this->nested_brackets_re.') # alt text = $2
|
808 |
-
\]
|
809 |
-
|
810 |
-
[ ]? # one optional space
|
811 |
-
(?:\n[ ]*)? # one optional newline followed by spaces
|
812 |
-
|
813 |
-
\[
|
814 |
-
(.*?) # id = $3
|
815 |
-
\]
|
816 |
-
|
817 |
-
)
|
818 |
-
}xs',
|
819 |
-
array(&$this, '_doImages_reference_callback'), $text);
|
820 |
-
|
821 |
-
#
|
822 |
-
# Next, handle inline images: ![alt text](url "optional title")
|
823 |
-
# Don't forget: encode * and _
|
824 |
-
#
|
825 |
-
$text = preg_replace_callback('{
|
826 |
-
( # wrap whole match in $1
|
827 |
-
!\[
|
828 |
-
('.$this->nested_brackets_re.') # alt text = $2
|
829 |
-
\]
|
830 |
-
\s? # One optional whitespace character
|
831 |
-
\( # literal paren
|
832 |
-
[ \n]*
|
833 |
-
(?:
|
834 |
-
<(\S*)> # src url = $3
|
835 |
-
|
|
836 |
-
('.$this->nested_url_parenthesis_re.') # src url = $4
|
837 |
-
)
|
838 |
-
[ \n]*
|
839 |
-
( # $5
|
840 |
-
([\'"]) # quote char = $6
|
841 |
-
(.*?) # title = $7
|
842 |
-
\6 # matching quote
|
843 |
-
[ \n]*
|
844 |
-
)? # title is optional
|
845 |
-
\)
|
846 |
-
)
|
847 |
-
}xs',
|
848 |
-
array(&$this, '_doImages_inline_callback'), $text);
|
849 |
-
|
850 |
-
return $text;
|
851 |
-
}
|
852 |
-
function _doImages_reference_callback($matches) {
|
853 |
-
$whole_match = $matches[1];
|
854 |
-
$alt_text = $matches[2];
|
855 |
-
$link_id = strtolower($matches[3]);
|
856 |
-
|
857 |
-
if ($link_id == "") {
|
858 |
-
$link_id = strtolower($alt_text); # for shortcut links like ![this][].
|
859 |
-
}
|
860 |
-
|
861 |
-
$alt_text = $this->encodeAttribute($alt_text);
|
862 |
-
if (isset($this->urls[$link_id])) {
|
863 |
-
$url = $this->encodeAttribute($this->urls[$link_id]);
|
864 |
-
$result = "<img src=\"$url\" alt=\"$alt_text\"";
|
865 |
-
if (isset($this->titles[$link_id])) {
|
866 |
-
$title = $this->titles[$link_id];
|
867 |
-
$title = $this->encodeAttribute($title);
|
868 |
-
$result .= " title=\"$title\"";
|
869 |
-
}
|
870 |
-
$result .= $this->empty_element_suffix;
|
871 |
-
$result = $this->hashPart($result);
|
872 |
-
}
|
873 |
-
else {
|
874 |
-
# If there's no such link ID, leave intact:
|
875 |
-
$result = $whole_match;
|
876 |
-
}
|
877 |
-
|
878 |
-
return $result;
|
879 |
-
}
|
880 |
-
function _doImages_inline_callback($matches) {
|
881 |
-
$whole_match = $matches[1];
|
882 |
-
$alt_text = $matches[2];
|
883 |
-
$url = $matches[3] == '' ? $matches[4] : $matches[3];
|
884 |
-
$title =& $matches[7];
|
885 |
-
|
886 |
-
$alt_text = $this->encodeAttribute($alt_text);
|
887 |
-
$url = $this->encodeAttribute($url);
|
888 |
-
$result = "<img src=\"$url\" alt=\"$alt_text\"";
|
889 |
-
if (isset($title)) {
|
890 |
-
$title = $this->encodeAttribute($title);
|
891 |
-
$result .= " title=\"$title\""; # $title already quoted
|
892 |
-
}
|
893 |
-
$result .= $this->empty_element_suffix;
|
894 |
-
|
895 |
-
return $this->hashPart($result);
|
896 |
-
}
|
897 |
-
|
898 |
-
|
899 |
-
function doHeaders($text) {
|
900 |
-
# Setext-style headers:
|
901 |
-
# Header 1
|
902 |
-
# ========
|
903 |
-
#
|
904 |
-
# Header 2
|
905 |
-
# --------
|
906 |
-
#
|
907 |
-
$text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
|
908 |
-
array(&$this, '_doHeaders_callback_setext'), $text);
|
909 |
-
|
910 |
-
# atx-style headers:
|
911 |
-
# # Header 1
|
912 |
-
# ## Header 2
|
913 |
-
# ## Header 2 with closing hashes ##
|
914 |
-
# ...
|
915 |
-
# ###### Header 6
|
916 |
-
#
|
917 |
-
$text = preg_replace_callback('{
|
918 |
-
^(\#{1,6}) # $1 = string of #\'s
|
919 |
-
[ ]*
|
920 |
-
(.+?) # $2 = Header text
|
921 |
-
[ ]*
|
922 |
-
\#* # optional closing #\'s (not counted)
|
923 |
-
\n+
|
924 |
-
}xm',
|
925 |
-
array(&$this, '_doHeaders_callback_atx'), $text);
|
926 |
-
|
927 |
-
return $text;
|
928 |
-
}
|
929 |
-
function _doHeaders_callback_setext($matches) {
|
930 |
-
# Terrible hack to check we haven't found an empty list item.
|
931 |
-
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
|
932 |
-
return $matches[0];
|
933 |
-
|
934 |
-
$level = $matches[2]{0} == '=' ? 1 : 2;
|
935 |
-
$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
|
936 |
-
return "\n" . $this->hashBlock($block) . "\n\n";
|
937 |
-
}
|
938 |
-
function _doHeaders_callback_atx($matches) {
|
939 |
-
$level = strlen($matches[1]);
|
940 |
-
$block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
|
941 |
-
return "\n" . $this->hashBlock($block) . "\n\n";
|
942 |
-
}
|
943 |
-
|
944 |
-
|
945 |
-
function doLists($text) {
|
946 |
-
#
|
947 |
-
# Form HTML ordered (numbered) and unordered (bulleted) lists.
|
948 |
-
#
|
949 |
-
$less_than_tab = $this->tab_width - 1;
|
950 |
-
|
951 |
-
# Re-usable patterns to match list item bullets and number markers:
|
952 |
-
$marker_ul_re = '[*+-]';
|
953 |
-
$marker_ol_re = '\d+[.]';
|
954 |
-
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
|
955 |
-
|
956 |
-
$markers_relist = array(
|
957 |
-
$marker_ul_re => $marker_ol_re,
|
958 |
-
$marker_ol_re => $marker_ul_re,
|
959 |
-
);
|
960 |
-
|
961 |
-
foreach ($markers_relist as $marker_re => $other_marker_re) {
|
962 |
-
# Re-usable pattern to match any entirel ul or ol list:
|
963 |
-
$whole_list_re = '
|
964 |
-
( # $1 = whole list
|
965 |
-
( # $2
|
966 |
-
([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
|
967 |
-
('.$marker_re.') # $4 = first list item marker
|
968 |
-
[ ]+
|
969 |
-
)
|
970 |
-
(?s:.+?)
|
971 |
-
( # $5
|
972 |
-
\z
|
973 |
-
|
|
974 |
-
\n{2,}
|
975 |
-
(?=\S)
|
976 |
-
(?! # Negative lookahead for another list item marker
|
977 |
-
[ ]*
|
978 |
-
'.$marker_re.'[ ]+
|
979 |
-
)
|
980 |
-
|
|
981 |
-
(?= # Lookahead for another kind of list
|
982 |
-
\n
|
983 |
-
\3 # Must have the same indentation
|
984 |
-
'.$other_marker_re.'[ ]+
|
985 |
-
)
|
986 |
-
)
|
987 |
-
)
|
988 |
-
'; // mx
|
989 |
-
|
990 |
-
# We use a different prefix before nested lists than top-level lists.
|
991 |
-
# See extended comment in _ProcessListItems().
|
992 |
-
|
993 |
-
if ($this->list_level) {
|
994 |
-
$text = preg_replace_callback('{
|
995 |
-
^
|
996 |
-
'.$whole_list_re.'
|
997 |
-
}mx',
|
998 |
-
array(&$this, '_doLists_callback'), $text);
|
999 |
-
}
|
1000 |
-
else {
|
1001 |
-
$text = preg_replace_callback('{
|
1002 |
-
(?:(?<=\n)\n|\A\n?) # Must eat the newline
|
1003 |
-
'.$whole_list_re.'
|
1004 |
-
}mx',
|
1005 |
-
array(&$this, '_doLists_callback'), $text);
|
1006 |
-
}
|
1007 |
-
}
|
1008 |
-
|
1009 |
-
return $text;
|
1010 |
-
}
|
1011 |
-
function _doLists_callback($matches) {
|
1012 |
-
# Re-usable patterns to match list item bullets and number markers:
|
1013 |
-
$marker_ul_re = '[*+-]';
|
1014 |
-
$marker_ol_re = '\d+[.]';
|
1015 |
-
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
|
1016 |
-
|
1017 |
-
$list = $matches[1];
|
1018 |
-
$list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
|
1019 |
-
|
1020 |
-
$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
|
1021 |
-
|
1022 |
-
$list .= "\n";
|
1023 |
-
$result = $this->processListItems($list, $marker_any_re);
|
1024 |
-
|
1025 |
-
$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
|
1026 |
-
return "\n". $result ."\n\n";
|
1027 |
-
}
|
1028 |
-
|
1029 |
-
var $list_level = 0;
|
1030 |
-
|
1031 |
-
function processListItems($list_str, $marker_any_re) {
|
1032 |
-
#
|
1033 |
-
# Process the contents of a single ordered or unordered list, splitting it
|
1034 |
-
# into individual list items.
|
1035 |
-
#
|
1036 |
-
# The $this->list_level global keeps track of when we're inside a list.
|
1037 |
-
# Each time we enter a list, we increment it; when we leave a list,
|
1038 |
-
# we decrement. If it's zero, we're not in a list anymore.
|
1039 |
-
#
|
1040 |
-
# We do this because when we're not inside a list, we want to treat
|
1041 |
-
# something like this:
|
1042 |
-
#
|
1043 |
-
# I recommend upgrading to version
|
1044 |
-
# 8. Oops, now this line is treated
|
1045 |
-
# as a sub-list.
|
1046 |
-
#
|
1047 |
-
# As a single paragraph, despite the fact that the second line starts
|
1048 |
-
# with a digit-period-space sequence.
|
1049 |
-
#
|
1050 |
-
# Whereas when we're inside a list (or sub-list), that line will be
|
1051 |
-
# treated as the start of a sub-list. What a kludge, huh? This is
|
1052 |
-
# an aspect of Markdown's syntax that's hard to parse perfectly
|
1053 |
-
# without resorting to mind-reading. Perhaps the solution is to
|
1054 |
-
# change the syntax rules such that sub-lists must start with a
|
1055 |
-
# starting cardinal number; e.g. "1." or "a.".
|
1056 |
-
|
1057 |
-
$this->list_level++;
|
1058 |
-
|
1059 |
-
# trim trailing blank lines:
|
1060 |
-
$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
|
1061 |
-
|
1062 |
-
$list_str = preg_replace_callback('{
|
1063 |
-
(\n)? # leading line = $1
|
1064 |
-
(^[ ]*) # leading whitespace = $2
|
1065 |
-
('.$marker_any_re.' # list marker and space = $3
|
1066 |
-
(?:[ ]+|(?=\n)) # space only required if item is not empty
|
1067 |
-
)
|
1068 |
-
((?s:.*?)) # list item text = $4
|
1069 |
-
(?:(\n+(?=\n))|\n) # tailing blank line = $5
|
1070 |
-
(?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
|
1071 |
-
}xm',
|
1072 |
-
array(&$this, '_processListItems_callback'), $list_str);
|
1073 |
-
|
1074 |
-
$this->list_level--;
|
1075 |
-
return $list_str;
|
1076 |
-
}
|
1077 |
-
function _processListItems_callback($matches) {
|
1078 |
-
$item = $matches[4];
|
1079 |
-
$leading_line =& $matches[1];
|
1080 |
-
$leading_space =& $matches[2];
|
1081 |
-
$marker_space = $matches[3];
|
1082 |
-
$tailing_blank_line =& $matches[5];
|
1083 |
-
|
1084 |
-
if ($leading_line || $tailing_blank_line ||
|
1085 |
-
preg_match('/\n{2,}/', $item))
|
1086 |
-
{
|
1087 |
-
# Replace marker with the appropriate whitespace indentation
|
1088 |
-
$item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
|
1089 |
-
$item = $this->runBlockGamut($this->outdent($item)."\n");
|
1090 |
-
}
|
1091 |
-
else {
|
1092 |
-
# Recursion for sub-lists:
|
1093 |
-
$item = $this->doLists($this->outdent($item));
|
1094 |
-
$item = preg_replace('/\n+$/', '', $item);
|
1095 |
-
$item = $this->runSpanGamut($item);
|
1096 |
-
}
|
1097 |
-
|
1098 |
-
return "<li>" . $item . "</li>\n";
|
1099 |
-
}
|
1100 |
-
|
1101 |
-
|
1102 |
-
function doCodeBlocks($text) {
|
1103 |
-
#
|
1104 |
-
# Process Markdown `<pre><code>` blocks.
|
1105 |
-
#
|
1106 |
-
$text = preg_replace_callback('{
|
1107 |
-
(?:\n\n|\A\n?)
|
1108 |
-
( # $1 = the code block -- one or more lines, starting with a space/tab
|
1109 |
-
(?>
|
1110 |
-
[ ]{'.$this->tab_width.'} # Lines must start with a tab or a tab-width of spaces
|
1111 |
-
.*\n+
|
1112 |
-
)+
|
1113 |
-
)
|
1114 |
-
((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
|
1115 |
-
}xm',
|
1116 |
-
array(&$this, '_doCodeBlocks_callback'), $text);
|
1117 |
-
|
1118 |
-
return $text;
|
1119 |
-
}
|
1120 |
-
function _doCodeBlocks_callback($matches) {
|
1121 |
-
$codeblock = $matches[1];
|
1122 |
-
|
1123 |
-
$codeblock = $this->outdent($codeblock);
|
1124 |
-
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
|
1125 |
-
|
1126 |
-
# trim leading newlines and trailing newlines
|
1127 |
-
$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
|
1128 |
-
|
1129 |
-
$codeblock = "<pre><code>$codeblock\n</code></pre>";
|
1130 |
-
return "\n\n".$this->hashBlock($codeblock)."\n\n";
|
1131 |
-
}
|
1132 |
-
|
1133 |
-
|
1134 |
-
function makeCodeSpan($code) {
|
1135 |
-
#
|
1136 |
-
# Create a code span markup for $code. Called from handleSpanToken.
|
1137 |
-
#
|
1138 |
-
$code = htmlspecialchars(trim($code), ENT_NOQUOTES);
|
1139 |
-
return $this->hashPart("<code>$code</code>");
|
1140 |
-
}
|
1141 |
-
|
1142 |
-
|
1143 |
-
var $em_relist = array(
|
1144 |
-
'' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![.,:;]\s)',
|
1145 |
-
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
|
1146 |
-
'_' => '(?<=\S|^)(?<!_)_(?!_)',
|
1147 |
-
);
|
1148 |
-
var $strong_relist = array(
|
1149 |
-
'' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
|
1150 |
-
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
|
1151 |
-
'__' => '(?<=\S|^)(?<!_)__(?!_)',
|
1152 |
-
);
|
1153 |
-
var $em_strong_relist = array(
|
1154 |
-
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
|
1155 |
-
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
|
1156 |
-
'___' => '(?<=\S|^)(?<!_)___(?!_)',
|
1157 |
-
);
|
1158 |
-
var $em_strong_prepared_relist;
|
1159 |
-
|
1160 |
-
function prepareItalicsAndBold() {
|
1161 |
-
#
|
1162 |
-
# Prepare regular expressions for searching emphasis tokens in any
|
1163 |
-
# context.
|
1164 |
-
#
|
1165 |
-
foreach ($this->em_relist as $em => $em_re) {
|
1166 |
-
foreach ($this->strong_relist as $strong => $strong_re) {
|
1167 |
-
# Construct list of allowed token expressions.
|
1168 |
-
$token_relist = array();
|
1169 |
-
if (isset($this->em_strong_relist["$em$strong"])) {
|
1170 |
-
$token_relist[] = $this->em_strong_relist["$em$strong"];
|
1171 |
-
}
|
1172 |
-
$token_relist[] = $em_re;
|
1173 |
-
$token_relist[] = $strong_re;
|
1174 |
-
|
1175 |
-
# Construct master expression from list.
|
1176 |
-
$token_re = '{('. implode('|', $token_relist) .')}';
|
1177 |
-
$this->em_strong_prepared_relist["$em$strong"] = $token_re;
|
1178 |
-
}
|
1179 |
-
}
|
1180 |
-
}
|
1181 |
-
|
1182 |
-
function doItalicsAndBold($text) {
|
1183 |
-
$token_stack = array('');
|
1184 |
-
$text_stack = array('');
|
1185 |
-
$em = '';
|
1186 |
-
$strong = '';
|
1187 |
-
$tree_char_em = false;
|
1188 |
-
|
1189 |
-
while (1) {
|
1190 |
-
#
|
1191 |
-
# Get prepared regular expression for seraching emphasis tokens
|
1192 |
-
# in current context.
|
1193 |
-
#
|
1194 |
-
$token_re = $this->em_strong_prepared_relist["$em$strong"];
|
1195 |
-
|
1196 |
-
#
|
1197 |
-
# Each loop iteration search for the next emphasis token.
|
1198 |
-
# Each token is then passed to handleSpanToken.
|
1199 |
-
#
|
1200 |
-
$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
|
1201 |
-
$text_stack[0] .= $parts[0];
|
1202 |
-
$token =& $parts[1];
|
1203 |
-
$text =& $parts[2];
|
1204 |
-
|
1205 |
-
if (empty($token)) {
|
1206 |
-
# Reached end of text span: empty stack without emitting.
|
1207 |
-
# any more emphasis.
|
1208 |
-
while ($token_stack[0]) {
|
1209 |
-
$text_stack[1] .= array_shift($token_stack);
|
1210 |
-
$text_stack[0] .= array_shift($text_stack);
|
1211 |
-
}
|
1212 |
-
break;
|
1213 |
-
}
|
1214 |
-
|
1215 |
-
$token_len = strlen($token);
|
1216 |
-
if ($tree_char_em) {
|
1217 |
-
# Reached closing marker while inside a three-char emphasis.
|
1218 |
-
if ($token_len == 3) {
|
1219 |
-
# Three-char closing marker, close em and strong.
|
1220 |
-
array_shift($token_stack);
|
1221 |
-
$span = array_shift($text_stack);
|
1222 |
-
$span = $this->runSpanGamut($span);
|
1223 |
-
$span = "<strong><em>$span</em></strong>";
|
1224 |
-
$text_stack[0] .= $this->hashPart($span);
|
1225 |
-
$em = '';
|
1226 |
-
$strong = '';
|
1227 |
-
} else {
|
1228 |
-
# Other closing marker: close one em or strong and
|
1229 |
-
# change current token state to match the other
|
1230 |
-
$token_stack[0] = str_repeat($token{0}, 3-$token_len);
|
1231 |
-
$tag = $token_len == 2 ? "strong" : "em";
|
1232 |
-
$span = $text_stack[0];
|
1233 |
-
$span = $this->runSpanGamut($span);
|
1234 |
-
$span = "<$tag>$span</$tag>";
|
1235 |
-
$text_stack[0] = $this->hashPart($span);
|
1236 |
-
$$tag = ''; # $$tag stands for $em or $strong
|
1237 |
-
}
|
1238 |
-
$tree_char_em = false;
|
1239 |
-
} else if ($token_len == 3) {
|
1240 |
-
if ($em) {
|
1241 |
-
# Reached closing marker for both em and strong.
|
1242 |
-
# Closing strong marker:
|
1243 |
-
for ($i = 0; $i < 2; ++$i) {
|
1244 |
-
$shifted_token = array_shift($token_stack);
|
1245 |
-
$tag = strlen($shifted_token) == 2 ? "strong" : "em";
|
1246 |
-
$span = array_shift($text_stack);
|
1247 |
-
$span = $this->runSpanGamut($span);
|
1248 |
-
$span = "<$tag>$span</$tag>";
|
1249 |
-
$text_stack[0] .= $this->hashPart($span);
|
1250 |
-
$$tag = ''; # $$tag stands for $em or $strong
|
1251 |
-
}
|
1252 |
-
} else {
|
1253 |
-
# Reached opening three-char emphasis marker. Push on token
|
1254 |
-
# stack; will be handled by the special condition above.
|
1255 |
-
$em = $token{0};
|
1256 |
-
$strong = "$em$em";
|
1257 |
-
array_unshift($token_stack, $token);
|
1258 |
-
array_unshift($text_stack, '');
|
1259 |
-
$tree_char_em = true;
|
1260 |
-
}
|
1261 |
-
} else if ($token_len == 2) {
|
1262 |
-
if ($strong) {
|
1263 |
-
# Unwind any dangling emphasis marker:
|
1264 |
-
if (strlen($token_stack[0]) == 1) {
|
1265 |
-
$text_stack[1] .= array_shift($token_stack);
|
1266 |
-
$text_stack[0] .= array_shift($text_stack);
|
1267 |
-
}
|
1268 |
-
# Closing strong marker:
|
1269 |
-
array_shift($token_stack);
|
1270 |
-
$span = array_shift($text_stack);
|
1271 |
-
$span = $this->runSpanGamut($span);
|
1272 |
-
$span = "<strong>$span</strong>";
|
1273 |
-
$text_stack[0] .= $this->hashPart($span);
|
1274 |
-
$strong = '';
|
1275 |
-
} else {
|
1276 |
-
array_unshift($token_stack, $token);
|
1277 |
-
array_unshift($text_stack, '');
|
1278 |
-
$strong = $token;
|
1279 |
-
}
|
1280 |
-
} else {
|
1281 |
-
# Here $token_len == 1
|
1282 |
-
if ($em) {
|
1283 |
-
if (strlen($token_stack[0]) == 1) {
|
1284 |
-
# Closing emphasis marker:
|
1285 |
-
array_shift($token_stack);
|
1286 |
-
$span = array_shift($text_stack);
|
1287 |
-
$span = $this->runSpanGamut($span);
|
1288 |
-
$span = "<em>$span</em>";
|
1289 |
-
$text_stack[0] .= $this->hashPart($span);
|
1290 |
-
$em = '';
|
1291 |
-
} else {
|
1292 |
-
$text_stack[0] .= $token;
|
1293 |
-
}
|
1294 |
-
} else {
|
1295 |
-
array_unshift($token_stack, $token);
|
1296 |
-
array_unshift($text_stack, '');
|
1297 |
-
$em = $token;
|
1298 |
-
}
|
1299 |
-
}
|
1300 |
-
}
|
1301 |
-
return $text_stack[0];
|
1302 |
-
}
|
1303 |
-
|
1304 |
-
|
1305 |
-
function doBlockQuotes($text) {
|
1306 |
-
$text = preg_replace_callback('/
|
1307 |
-
( # Wrap whole match in $1
|
1308 |
-
(?>
|
1309 |
-
^[ ]*>[ ]? # ">" at the start of a line
|
1310 |
-
.+\n # rest of the first line
|
1311 |
-
(.+\n)* # subsequent consecutive lines
|
1312 |
-
\n* # blanks
|
1313 |
-
)+
|
1314 |
-
)
|
1315 |
-
/xm',
|
1316 |
-
array(&$this, '_doBlockQuotes_callback'), $text);
|
1317 |
-
|
1318 |
-
return $text;
|
1319 |
-
}
|
1320 |
-
function _doBlockQuotes_callback($matches) {
|
1321 |
-
$bq = $matches[1];
|
1322 |
-
# trim one level of quoting - trim whitespace-only lines
|
1323 |
-
$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
|
1324 |
-
$bq = $this->runBlockGamut($bq); # recurse
|
1325 |
-
|
1326 |
-
$bq = preg_replace('/^/m', " ", $bq);
|
1327 |
-
# These leading spaces cause problem with <pre> content,
|
1328 |
-
# so we need to fix that:
|
1329 |
-
$bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
|
1330 |
-
array(&$this, '_doBlockQuotes_callback2'), $bq);
|
1331 |
-
|
1332 |
-
return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
|
1333 |
-
}
|
1334 |
-
function _doBlockQuotes_callback2($matches) {
|
1335 |
-
$pre = $matches[1];
|
1336 |
-
$pre = preg_replace('/^ /m', '', $pre);
|
1337 |
-
return $pre;
|
1338 |
-
}
|
1339 |
-
|
1340 |
-
|
1341 |
-
function formParagraphs($text) {
|
1342 |
-
#
|
1343 |
-
# Params:
|
1344 |
-
# $text - string to process with html <p> tags
|
1345 |
-
#
|
1346 |
-
# Strip leading and trailing lines:
|
1347 |
-
$text = preg_replace('/\A\n+|\n+\z/', '', $text);
|
1348 |
-
|
1349 |
-
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
|
1350 |
-
|
1351 |
-
#
|
1352 |
-
# Wrap <p> tags and unhashify HTML blocks
|
1353 |
-
#
|
1354 |
-
foreach ($grafs as $key => $value) {
|
1355 |
-
if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
|
1356 |
-
# Is a paragraph.
|
1357 |
-
$value = $this->runSpanGamut($value);
|
1358 |
-
$value = preg_replace('/^([ ]*)/', "<p>", $value);
|
1359 |
-
$value .= "</p>";
|
1360 |
-
$grafs[$key] = $this->unhash($value);
|
1361 |
-
}
|
1362 |
-
else {
|
1363 |
-
# Is a block.
|
1364 |
-
# Modify elements of @grafs in-place...
|
1365 |
-
$graf = $value;
|
1366 |
-
$block = $this->html_hashes[$graf];
|
1367 |
-
$graf = $block;
|
1368 |
-
// if (preg_match('{
|
1369 |
-
// \A
|
1370 |
-
// ( # $1 = <div> tag
|
1371 |
-
// <div \s+
|
1372 |
-
// [^>]*
|
1373 |
-
// \b
|
1374 |
-
// markdown\s*=\s* ([\'"]) # $2 = attr quote char
|
1375 |
-
// 1
|
1376 |
-
// \2
|
1377 |
-
// [^>]*
|
1378 |
-
// >
|
1379 |
-
// )
|
1380 |
-
// ( # $3 = contents
|
1381 |
-
// .*
|
1382 |
-
// )
|
1383 |
-
// (</div>) # $4 = closing tag
|
1384 |
-
// \z
|
1385 |
-
// }xs', $block, $matches))
|
1386 |
-
// {
|
1387 |
-
// list(, $div_open, , $div_content, $div_close) = $matches;
|
1388 |
-
//
|
1389 |
-
// # We can't call Markdown(), because that resets the hash;
|
1390 |
-
// # that initialization code should be pulled into its own sub, though.
|
1391 |
-
// $div_content = $this->hashHTMLBlocks($div_content);
|
1392 |
-
//
|
1393 |
-
// # Run document gamut methods on the content.
|
1394 |
-
// foreach ($this->document_gamut as $method => $priority) {
|
1395 |
-
// $div_content = $this->$method($div_content);
|
1396 |
-
// }
|
1397 |
-
//
|
1398 |
-
// $div_open = preg_replace(
|
1399 |
-
// '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
|
1400 |
-
//
|
1401 |
-
// $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
|
1402 |
-
// }
|
1403 |
-
$grafs[$key] = $graf;
|
1404 |
-
}
|
1405 |
-
}
|
1406 |
-
|
1407 |
-
return implode("\n\n", $grafs);
|
1408 |
-
}
|
1409 |
-
|
1410 |
-
|
1411 |
-
function encodeAttribute($text) {
|
1412 |
-
#
|
1413 |
-
# Encode text for a double-quoted HTML attribute. This function
|
1414 |
-
# is *not* suitable for attributes enclosed in single quotes.
|
1415 |
-
#
|
1416 |
-
$text = $this->encodeAmpsAndAngles($text);
|
1417 |
-
$text = str_replace('"', '"', $text);
|
1418 |
-
return $text;
|
1419 |
-
}
|
1420 |
-
|
1421 |
-
|
1422 |
-
function encodeAmpsAndAngles($text) {
|
1423 |
-
#
|
1424 |
-
# Smart processing for ampersands and angle brackets that need to
|
1425 |
-
# be encoded. Valid character entities are left alone unless the
|
1426 |
-
# no-entities mode is set.
|
1427 |
-
#
|
1428 |
-
if ($this->no_entities) {
|
1429 |
-
$text = str_replace('&', '&', $text);
|
1430 |
-
} else {
|
1431 |
-
# Ampersand-encoding based entirely on Nat Irons's Amputator
|
1432 |
-
# MT plugin: <http://bumppo.net/projects/amputator/>
|
1433 |
-
$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
|
1434 |
-
'&', $text);;
|
1435 |
-
}
|
1436 |
-
# Encode remaining <'s
|
1437 |
-
$text = str_replace('<', '<', $text);
|
1438 |
-
|
1439 |
-
return $text;
|
1440 |
-
}
|
1441 |
-
|
1442 |
-
|
1443 |
-
function doAutoLinks($text) {
|
1444 |
-
$text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
|
1445 |
-
array(&$this, '_doAutoLinks_url_callback'), $text);
|
1446 |
-
|
1447 |
-
# Email addresses: <address@domain.foo>
|
1448 |
-
$text = preg_replace_callback('{
|
1449 |
-
<
|
1450 |
-
(?:mailto:)?
|
1451 |
-
(
|
1452 |
-
(?:
|
1453 |
-
[-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
|
1454 |
-
|
|
1455 |
-
".*?"
|
1456 |
-
)
|
1457 |
-
\@
|
1458 |
-
(?:
|
1459 |
-
[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
|
1460 |
-
|
|
1461 |
-
\[[\d.a-fA-F:]+\] # IPv4 & IPv6
|
1462 |
-
)
|
1463 |
-
)
|
1464 |
-
>
|
1465 |
-
}xi',
|
1466 |
-
array(&$this, '_doAutoLinks_email_callback'), $text);
|
1467 |
-
|
1468 |
-
return $text;
|
1469 |
-
}
|
1470 |
-
function _doAutoLinks_url_callback($matches) {
|
1471 |
-
$url = $this->encodeAttribute($matches[1]);
|
1472 |
-
$link = "<a href=\"$url\">$url</a>";
|
1473 |
-
return $this->hashPart($link);
|
1474 |
-
}
|
1475 |
-
function _doAutoLinks_email_callback($matches) {
|
1476 |
-
$address = $matches[1];
|
1477 |
-
$link = $this->encodeEmailAddress($address);
|
1478 |
-
return $this->hashPart($link);
|
1479 |
-
}
|
1480 |
-
|
1481 |
-
|
1482 |
-
function encodeEmailAddress($addr) {
|
1483 |
-
#
|
1484 |
-
# Input: an email address, e.g. "foo@example.com"
|
1485 |
-
#
|
1486 |
-
# Output: the email address as a mailto link, with each character
|
1487 |
-
# of the address encoded as either a decimal or hex entity, in
|
1488 |
-
# the hopes of foiling most address harvesting spam bots. E.g.:
|
1489 |
-
#
|
1490 |
-
# <p><a href="mailto:foo
|
1491 |
-
# @example.co
|
1492 |
-
# m">foo@exampl
|
1493 |
-
# e.com</a></p>
|
1494 |
-
#
|
1495 |
-
# Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
|
1496 |
-
# With some optimizations by Milian Wolff.
|
1497 |
-
#
|
1498 |
-
$addr = "mailto:" . $addr;
|
1499 |
-
$chars = preg_split('/(?<!^)(?!$)/', $addr);
|
1500 |
-
$seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
|
1501 |
-
|
1502 |
-
foreach ($chars as $key => $char) {
|
1503 |
-
$ord = ord($char);
|
1504 |
-
# Ignore non-ascii chars.
|
1505 |
-
if ($ord < 128) {
|
1506 |
-
$r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
|
1507 |
-
# roughly 10% raw, 45% hex, 45% dec
|
1508 |
-
# '@' *must* be encoded. I insist.
|
1509 |
-
if ($r > 90 && $char != '@') /* do nothing */;
|
1510 |
-
else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
|
1511 |
-
else $chars[$key] = '&#'.$ord.';';
|
1512 |
-
}
|
1513 |
-
}
|
1514 |
-
|
1515 |
-
$addr = implode('', $chars);
|
1516 |
-
$text = implode('', array_slice($chars, 7)); # text without `mailto:`
|
1517 |
-
$addr = "<a href=\"$addr\">$text</a>";
|
1518 |
-
|
1519 |
-
return $addr;
|
1520 |
-
}
|
1521 |
-
|
1522 |
-
|
1523 |
-
function parseSpan($str) {
|
1524 |
-
#
|
1525 |
-
# Take the string $str and parse it into tokens, hashing embeded HTML,
|
1526 |
-
# escaped characters and handling code spans.
|
1527 |
-
#
|
1528 |
-
$output = '';
|
1529 |
-
|
1530 |
-
$span_re = '{
|
1531 |
-
(
|
1532 |
-
\\\\'.$this->escape_chars_re.'
|
1533 |
-
|
|
1534 |
-
(?<![`\\\\])
|
1535 |
-
`+ # code span marker
|
1536 |
-
'.( $this->no_markup ? '' : '
|
1537 |
-
|
|
1538 |
-
<!-- .*? --> # comment
|
1539 |
-
|
|
1540 |
-
<\?.*?\?> | <%.*?%> # processing instruction
|
1541 |
-
|
|
1542 |
-
<[/!$]?[-a-zA-Z0-9:_]+ # regular tags
|
1543 |
-
(?>
|
1544 |
-
\s
|
1545 |
-
(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
|
1546 |
-
)?
|
1547 |
-
>
|
1548 |
-
').'
|
1549 |
-
)
|
1550 |
-
}xs';
|
1551 |
-
|
1552 |
-
while (1) {
|
1553 |
-
#
|
1554 |
-
# Each loop iteration seach for either the next tag, the next
|
1555 |
-
# openning code span marker, or the next escaped character.
|
1556 |
-
# Each token is then passed to handleSpanToken.
|
1557 |
-
#
|
1558 |
-
$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
|
1559 |
-
|
1560 |
-
# Create token from text preceding tag.
|
1561 |
-
if ($parts[0] != "") {
|
1562 |
-
$output .= $parts[0];
|
1563 |
-
}
|
1564 |
-
|
1565 |
-
# Check if we reach the end.
|
1566 |
-
if (isset($parts[1])) {
|
1567 |
-
$output .= $this->handleSpanToken($parts[1], $parts[2]);
|
1568 |
-
$str = $parts[2];
|
1569 |
-
}
|
1570 |
-
else {
|
1571 |
-
break;
|
1572 |
-
}
|
1573 |
-
}
|
1574 |
-
|
1575 |
-
return $output;
|
1576 |
-
}
|
1577 |
-
|
1578 |
-
|
1579 |
-
function handleSpanToken($token, &$str) {
|
1580 |
-
#
|
1581 |
-
# Handle $token provided by parseSpan by determining its nature and
|
1582 |
-
# returning the corresponding value that should replace it.
|
1583 |
-
#
|
1584 |
-
switch ($token{0}) {
|
1585 |
-
case "\\":
|
1586 |
-
return $this->hashPart("&#". ord($token{1}). ";");
|
1587 |
-
case "`":
|
1588 |
-
# Search for end marker in remaining text.
|
1589 |
-
if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
|
1590 |
-
$str, $matches))
|
1591 |
-
{
|
1592 |
-
$str = $matches[2];
|
1593 |
-
$codespan = $this->makeCodeSpan($matches[1]);
|
1594 |
-
return $this->hashPart($codespan);
|
1595 |
-
}
|
1596 |
-
return $token; // return as text since no ending marker found.
|
1597 |
-
default:
|
1598 |
-
return $this->hashPart($token);
|
1599 |
-
}
|
1600 |
-
}
|
1601 |
-
|
1602 |
-
|
1603 |
-
function outdent($text) {
|
1604 |
-
#
|
1605 |
-
# Remove one level of line-leading tabs or spaces
|
1606 |
-
#
|
1607 |
-
return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
|
1608 |
-
}
|
1609 |
-
|
1610 |
-
|
1611 |
-
# String length function for detab. `_initDetab` will create a function to
|
1612 |
-
# hanlde UTF-8 if the default function does not exist.
|
1613 |
-
var $utf8_strlen = 'mb_strlen';
|
1614 |
-
|
1615 |
-
function detab($text) {
|
1616 |
-
#
|
1617 |
-
# Replace tabs with the appropriate amount of space.
|
1618 |
-
#
|
1619 |
-
# For each line we separate the line in blocks delemited by
|
1620 |
-
# tab characters. Then we reconstruct every line by adding the
|
1621 |
-
# appropriate number of space between each blocks.
|
1622 |
-
|
1623 |
-
$text = preg_replace_callback('/^.*\t.*$/m',
|
1624 |
-
array(&$this, '_detab_callback'), $text);
|
1625 |
-
|
1626 |
-
return $text;
|
1627 |
-
}
|
1628 |
-
function _detab_callback($matches) {
|
1629 |
-
$line = $matches[0];
|
1630 |
-
$strlen = $this->utf8_strlen; # strlen function for UTF-8.
|
1631 |
-
|
1632 |
-
# Split in blocks.
|
1633 |
-
$blocks = explode("\t", $line);
|
1634 |
-
# Add each blocks to the line.
|
1635 |
-
$line = $blocks[0];
|
1636 |
-
unset($blocks[0]); # Do not add first block twice.
|
1637 |
-
foreach ($blocks as $block) {
|
1638 |
-
# Calculate amount of space, insert spaces, insert block.
|
1639 |
-
$amount = $this->tab_width -
|
1640 |
-
$strlen($line, 'UTF-8') % $this->tab_width;
|
1641 |
-
$line .= str_repeat(" ", $amount) . $block;
|
1642 |
-
}
|
1643 |
-
return $line;
|
1644 |
-
}
|
1645 |
-
function _initDetab() {
|
1646 |
-
#
|
1647 |
-
# Check for the availability of the function in the `utf8_strlen` property
|
1648 |
-
# (initially `mb_strlen`). If the function is not available, create a
|
1649 |
-
# function that will loosely count the number of UTF-8 characters with a
|
1650 |
-
# regular expression.
|
1651 |
-
#
|
1652 |
-
if (function_exists($this->utf8_strlen)) return;
|
1653 |
-
$this->utf8_strlen = create_function('$text', 'return preg_match_all(
|
1654 |
-
"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
|
1655 |
-
$text, $m);');
|
1656 |
-
}
|
1657 |
-
|
1658 |
-
|
1659 |
-
function unhash($text) {
|
1660 |
-
#
|
1661 |
-
# Swap back in all the tags hashed by _HashHTMLBlocks.
|
1662 |
-
#
|
1663 |
-
return preg_replace_callback('/(.)\x1A[0-9]+\1/',
|
1664 |
-
array(&$this, '_unhash_callback'), $text);
|
1665 |
-
}
|
1666 |
-
function _unhash_callback($matches) {
|
1667 |
-
return $this->html_hashes[$matches[0]];
|
1668 |
-
}
|
1669 |
-
|
1670 |
-
}
|
1671 |
-
|
1672 |
-
|
1673 |
-
#
|
1674 |
-
# Markdown Extra Parser Class
|
1675 |
-
#
|
1676 |
-
|
1677 |
-
class MarkdownExtra_Parser extends Markdown_Parser {
|
1678 |
-
|
1679 |
-
# Prefix for footnote ids.
|
1680 |
-
var $fn_id_prefix = "";
|
1681 |
-
|
1682 |
-
# Optional title attribute for footnote links and backlinks.
|
1683 |
-
var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
|
1684 |
-
var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
|
1685 |
-
|
1686 |
-
# Optional class attribute for footnote links and backlinks.
|
1687 |
-
var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
|
1688 |
-
var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
|
1689 |
-
|
1690 |
-
# Predefined abbreviations.
|
1691 |
-
var $predef_abbr = array();
|
1692 |
-
|
1693 |
-
|
1694 |
-
function MarkdownExtra_Parser() {
|
1695 |
-
#
|
1696 |
-
# Constructor function. Initialize the parser object.
|
1697 |
-
#
|
1698 |
-
# Add extra escapable characters before parent constructor
|
1699 |
-
# initialize the table.
|
1700 |
-
$this->escape_chars .= ':|';
|
1701 |
-
|
1702 |
-
# Insert extra document, block, and span transformations.
|
1703 |
-
# Parent constructor will do the sorting.
|
1704 |
-
$this->document_gamut += array(
|
1705 |
-
"doFencedCodeBlocks" => 5,
|
1706 |
-
"stripFootnotes" => 15,
|
1707 |
-
"stripAbbreviations" => 25,
|
1708 |
-
"appendFootnotes" => 50,
|
1709 |
-
);
|
1710 |
-
$this->block_gamut += array(
|
1711 |
-
"doFencedCodeBlocks" => 5,
|
1712 |
-
"doTables" => 15,
|
1713 |
-
"doDefLists" => 45,
|
1714 |
-
);
|
1715 |
-
$this->span_gamut += array(
|
1716 |
-
"doFootnotes" => 5,
|
1717 |
-
"doAbbreviations" => 70,
|
1718 |
-
);
|
1719 |
-
|
1720 |
-
parent::Markdown_Parser();
|
1721 |
-
}
|
1722 |
-
|
1723 |
-
|
1724 |
-
# Extra variables used during extra transformations.
|
1725 |
-
var $footnotes = array();
|
1726 |
-
var $footnotes_ordered = array();
|
1727 |
-
var $abbr_desciptions = array();
|
1728 |
-
var $abbr_word_re = '';
|
1729 |
-
|
1730 |
-
# Give the current footnote number.
|
1731 |
-
var $footnote_counter = 1;
|
1732 |
-
|
1733 |
-
|
1734 |
-
function setup() {
|
1735 |
-
#
|
1736 |
-
# Setting up Extra-specific variables.
|
1737 |
-
#
|
1738 |
-
parent::setup();
|
1739 |
-
|
1740 |
-
$this->footnotes = array();
|
1741 |
-
$this->footnotes_ordered = array();
|
1742 |
-
$this->abbr_desciptions = array();
|
1743 |
-
$this->abbr_word_re = '';
|
1744 |
-
$this->footnote_counter = 1;
|
1745 |
-
|
1746 |
-
foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
|
1747 |
-
if ($this->abbr_word_re)
|
1748 |
-
$this->abbr_word_re .= '|';
|
1749 |
-
$this->abbr_word_re .= preg_quote($abbr_word);
|
1750 |
-
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
|
1751 |
-
}
|
1752 |
-
}
|
1753 |
-
|
1754 |
-
function teardown() {
|
1755 |
-
#
|
1756 |
-
# Clearing Extra-specific variables.
|
1757 |
-
#
|
1758 |
-
$this->footnotes = array();
|
1759 |
-
$this->footnotes_ordered = array();
|
1760 |
-
$this->abbr_desciptions = array();
|
1761 |
-
$this->abbr_word_re = '';
|
1762 |
-
|
1763 |
-
parent::teardown();
|
1764 |
-
}
|
1765 |
-
|
1766 |
-
|
1767 |
-
### HTML Block Parser ###
|
1768 |
-
|
1769 |
-
# Tags that are always treated as block tags:
|
1770 |
-
var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
|
1771 |
-
|
1772 |
-
# Tags treated as block tags only if the opening tag is alone on it's line:
|
1773 |
-
var $context_block_tags_re = 'script|noscript|math|ins|del';
|
1774 |
-
|
1775 |
-
# Tags where markdown="1" default to span mode:
|
1776 |
-
var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
|
1777 |
-
|
1778 |
-
# Tags which must not have their contents modified, no matter where
|
1779 |
-
# they appear:
|
1780 |
-
var $clean_tags_re = 'script|math';
|
1781 |
-
|
1782 |
-
# Tags that do not need to be closed.
|
1783 |
-
var $auto_close_tags_re = 'hr|img';
|
1784 |
-
|
1785 |
-
|
1786 |
-
function hashHTMLBlocks($text) {
|
1787 |
-
#
|
1788 |
-
# Hashify HTML Blocks and "clean tags".
|
1789 |
-
#
|
1790 |
-
# We only want to do this for block-level HTML tags, such as headers,
|
1791 |
-
# lists, and tables. That's because we still want to wrap <p>s around
|
1792 |
-
# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
|
1793 |
-
# phrase emphasis, and spans. The list of tags we're looking for is
|
1794 |
-
# hard-coded.
|
1795 |
-
#
|
1796 |
-
# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
|
1797 |
-
# _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
|
1798 |
-
# attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
|
1799 |
-
# _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
|
1800 |
-
# These two functions are calling each other. It's recursive!
|
1801 |
-
#
|
1802 |
-
#
|
1803 |
-
# Call the HTML-in-Markdown hasher.
|
1804 |
-
#
|
1805 |
-
list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
|
1806 |
-
|
1807 |
-
return $text;
|
1808 |
-
}
|
1809 |
-
function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
|
1810 |
-
$enclosing_tag_re = '', $span = false)
|
1811 |
-
{
|
1812 |
-
#
|
1813 |
-
# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
|
1814 |
-
#
|
1815 |
-
# * $indent is the number of space to be ignored when checking for code
|
1816 |
-
# blocks. This is important because if we don't take the indent into
|
1817 |
-
# account, something like this (which looks right) won't work as expected:
|
1818 |
-
#
|
1819 |
-
# <div>
|
1820 |
-
# <div markdown="1">
|
1821 |
-
# Hello World. <-- Is this a Markdown code block or text?
|
1822 |
-
# </div> <-- Is this a Markdown code block or a real tag?
|
1823 |
-
# <div>
|
1824 |
-
#
|
1825 |
-
# If you don't like this, just don't indent the tag on which
|
1826 |
-
# you apply the markdown="1" attribute.
|
1827 |
-
#
|
1828 |
-
# * If $enclosing_tag_re is not empty, stops at the first unmatched closing
|
1829 |
-
# tag with that name. Nested tags supported.
|
1830 |
-
#
|
1831 |
-
# * If $span is true, text inside must treated as span. So any double
|
1832 |
-
# newline will be replaced by a single newline so that it does not create
|
1833 |
-
# paragraphs.
|
1834 |
-
#
|
1835 |
-
# Returns an array of that form: ( processed text , remaining text )
|
1836 |
-
#
|
1837 |
-
if ($text === '') return array('', '');
|
1838 |
-
|
1839 |
-
# Regex to check for the presense of newlines around a block tag.
|
1840 |
-
$newline_before_re = '/(?:^\n?|\n\n)*$/';
|
1841 |
-
$newline_after_re =
|
1842 |
-
'{
|
1843 |
-
^ # Start of text following the tag.
|
1844 |
-
(?>[ ]*<!--.*?-->)? # Optional comment.
|
1845 |
-
[ ]*\n # Must be followed by newline.
|
1846 |
-
}xs';
|
1847 |
-
|
1848 |
-
# Regex to match any tag.
|
1849 |
-
$block_tag_re =
|
1850 |
-
'{
|
1851 |
-
( # $2: Capture hole tag.
|
1852 |
-
</? # Any opening or closing tag.
|
1853 |
-
(?> # Tag name.
|
1854 |
-
'.$this->block_tags_re.' |
|
1855 |
-
'.$this->context_block_tags_re.' |
|
1856 |
-
'.$this->clean_tags_re.' |
|
1857 |
-
(?!\s)'.$enclosing_tag_re.'
|
1858 |
-
)
|
1859 |
-
(?:
|
1860 |
-
(?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
|
1861 |
-
(?>
|
1862 |
-
".*?" | # Double quotes (can contain `>`)
|
1863 |
-
\'.*?\' | # Single quotes (can contain `>`)
|
1864 |
-
.+? # Anything but quotes and `>`.
|
1865 |
-
)*?
|
1866 |
-
)?
|
1867 |
-
> # End of tag.
|
1868 |
-
|
|
1869 |
-
<!-- .*? --> # HTML Comment
|
1870 |
-
|
|
1871 |
-
<\?.*?\?> | <%.*?%> # Processing instruction
|
1872 |
-
|
|
1873 |
-
<!\[CDATA\[.*?\]\]> # CData Block
|
1874 |
-
|
|
1875 |
-
# Code span marker
|
1876 |
-
`+
|
1877 |
-
'. ( !$span ? ' # If not in span.
|
1878 |
-
|
|
1879 |
-
# Indented code block
|
1880 |
-
(?: ^[ ]*\n | ^ | \n[ ]*\n )
|
1881 |
-
[ ]{'.($indent+4).'}[^\n]* \n
|
1882 |
-
(?>
|
1883 |
-
(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
|
1884 |
-
)*
|
1885 |
-
|
|
1886 |
-
# Fenced code block marker
|
1887 |
-
(?> ^ | \n )
|
1888 |
-
[ ]{'.($indent).'}~~~+[ ]*\n
|
1889 |
-
' : '' ). ' # End (if not is span).
|
1890 |
-
)
|
1891 |
-
}xs';
|
1892 |
-
|
1893 |
-
|
1894 |
-
$depth = 0; # Current depth inside the tag tree.
|
1895 |
-
$parsed = ""; # Parsed text that will be returned.
|
1896 |
-
|
1897 |
-
#
|
1898 |
-
# Loop through every tag until we find the closing tag of the parent
|
1899 |
-
# or loop until reaching the end of text if no parent tag specified.
|
1900 |
-
#
|
1901 |
-
do {
|
1902 |
-
#
|
1903 |
-
# Split the text using the first $tag_match pattern found.
|
1904 |
-
# Text before pattern will be first in the array, text after
|
1905 |
-
# pattern will be at the end, and between will be any catches made
|
1906 |
-
# by the pattern.
|
1907 |
-
#
|
1908 |
-
$parts = preg_split($block_tag_re, $text, 2,
|
1909 |
-
PREG_SPLIT_DELIM_CAPTURE);
|
1910 |
-
|
1911 |
-
# If in Markdown span mode, add a empty-string span-level hash
|
1912 |
-
# after each newline to prevent triggering any block element.
|
1913 |
-
if ($span) {
|
1914 |
-
$void = $this->hashPart("", ':');
|
1915 |
-
$newline = "$void\n";
|
1916 |
-
$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
|
1917 |
-
}
|
1918 |
-
|
1919 |
-
$parsed .= $parts[0]; # Text before current tag.
|
1920 |
-
|
1921 |
-
# If end of $text has been reached. Stop loop.
|
1922 |
-
if (count($parts) < 3) {
|
1923 |
-
$text = "";
|
1924 |
-
break;
|
1925 |
-
}
|
1926 |
-
|
1927 |
-
$tag = $parts[1]; # Tag to handle.
|
1928 |
-
$text = $parts[2]; # Remaining text after current tag.
|
1929 |
-
$tag_re = preg_quote($tag); # For use in a regular expression.
|
1930 |
-
|
1931 |
-
#
|
1932 |
-
# Check for: Code span marker
|
1933 |
-
#
|
1934 |
-
if ($tag{0} == "`") {
|
1935 |
-
# Find corresponding end marker.
|
1936 |
-
$tag_re = preg_quote($tag);
|
1937 |
-
if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
|
1938 |
-
$text, $matches))
|
1939 |
-
{
|
1940 |
-
# End marker found: pass text unchanged until marker.
|
1941 |
-
$parsed .= $tag . $matches[0];
|
1942 |
-
$text = substr($text, strlen($matches[0]));
|
1943 |
-
}
|
1944 |
-
else {
|
1945 |
-
# Unmatched marker: just skip it.
|
1946 |
-
$parsed .= $tag;
|
1947 |
-
}
|
1948 |
-
}
|
1949 |
-
#
|
1950 |
-
# Check for: Indented code block.
|
1951 |
-
#
|
1952 |
-
else if ($tag{0} == "\n" || $tag{0} == " ") {
|
1953 |
-
# Indented code block: pass it unchanged, will be handled
|
1954 |
-
# later.
|
1955 |
-
$parsed .= $tag;
|
1956 |
-
}
|
1957 |
-
#
|
1958 |
-
# Check for: Fenced code block marker.
|
1959 |
-
#
|
1960 |
-
else if ($tag{0} == "~") {
|
1961 |
-
# Fenced code block marker: find matching end marker.
|
1962 |
-
$tag_re = preg_quote(trim($tag));
|
1963 |
-
if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
|
1964 |
-
$matches))
|
1965 |
-
{
|
1966 |
-
# End marker found: pass text unchanged until marker.
|
1967 |
-
$parsed .= $tag . $matches[0];
|
1968 |
-
$text = substr($text, strlen($matches[0]));
|
1969 |
-
}
|
1970 |
-
else {
|
1971 |
-
# No end marker: just skip it.
|
1972 |
-
$parsed .= $tag;
|
1973 |
-
}
|
1974 |
-
}
|
1975 |
-
#
|
1976 |
-
# Check for: Opening Block level tag or
|
1977 |
-
# Opening Context Block tag (like ins and del)
|
1978 |
-
# used as a block tag (tag is alone on it's line).
|
1979 |
-
#
|
1980 |
-
else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
|
1981 |
-
( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
|
1982 |
-
preg_match($newline_before_re, $parsed) &&
|
1983 |
-
preg_match($newline_after_re, $text) )
|
1984 |
-
)
|
1985 |
-
{
|
1986 |
-
# Need to parse tag and following text using the HTML parser.
|
1987 |
-
list($block_text, $text) =
|
1988 |
-
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
|
1989 |
-
|
1990 |
-
# Make sure it stays outside of any paragraph by adding newlines.
|
1991 |
-
$parsed .= "\n\n$block_text\n\n";
|
1992 |
-
}
|
1993 |
-
#
|
1994 |
-
# Check for: Clean tag (like script, math)
|
1995 |
-
# HTML Comments, processing instructions.
|
1996 |
-
#
|
1997 |
-
else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
|
1998 |
-
$tag{1} == '!' || $tag{1} == '?')
|
1999 |
-
{
|
2000 |
-
# Need to parse tag and following text using the HTML parser.
|
2001 |
-
# (don't check for markdown attribute)
|
2002 |
-
list($block_text, $text) =
|
2003 |
-
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
|
2004 |
-
|
2005 |
-
$parsed .= $block_text;
|
2006 |
-
}
|
2007 |
-
#
|
2008 |
-
# Check for: Tag with same name as enclosing tag.
|
2009 |
-
#
|
2010 |
-
else if ($enclosing_tag_re !== '' &&
|
2011 |
-
# Same name as enclosing tag.
|
2012 |
-
preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
|
2013 |
-
{
|
2014 |
-
#
|
2015 |
-
# Increase/decrease nested tag count.
|
2016 |
-
#
|
2017 |
-
if ($tag{1} == '/') $depth--;
|
2018 |
-
else if ($tag{strlen($tag)-2} != '/') $depth++;
|
2019 |
-
|
2020 |
-
if ($depth < 0) {
|
2021 |
-
#
|
2022 |
-
# Going out of parent element. Clean up and break so we
|
2023 |
-
# return to the calling function.
|
2024 |
-
#
|
2025 |
-
$text = $tag . $text;
|
2026 |
-
break;
|
2027 |
-
}
|
2028 |
-
|
2029 |
-
$parsed .= $tag;
|
2030 |
-
}
|
2031 |
-
else {
|
2032 |
-
$parsed .= $tag;
|
2033 |
-
}
|
2034 |
-
} while ($depth >= 0);
|
2035 |
-
|
2036 |
-
return array($parsed, $text);
|
2037 |
-
}
|
2038 |
-
function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
|
2039 |
-
#
|
2040 |
-
# Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
|
2041 |
-
#
|
2042 |
-
# * Calls $hash_method to convert any blocks.
|
2043 |
-
# * Stops when the first opening tag closes.
|
2044 |
-
# * $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
|
2045 |
-
# (it is not inside clean tags)
|
2046 |
-
#
|
2047 |
-
# Returns an array of that form: ( processed text , remaining text )
|
2048 |
-
#
|
2049 |
-
if ($text === '') return array('', '');
|
2050 |
-
|
2051 |
-
# Regex to match `markdown` attribute inside of a tag.
|
2052 |
-
$markdown_attr_re = '
|
2053 |
-
{
|
2054 |
-
\s* # Eat whitespace before the `markdown` attribute
|
2055 |
-
markdown
|
2056 |
-
\s*=\s*
|
2057 |
-
(?>
|
2058 |
-
(["\']) # $1: quote delimiter
|
2059 |
-
(.*?) # $2: attribute value
|
2060 |
-
\1 # matching delimiter
|
2061 |
-
|
|
2062 |
-
([^\s>]*) # $3: unquoted attribute value
|
2063 |
-
)
|
2064 |
-
() # $4: make $3 always defined (avoid warnings)
|
2065 |
-
}xs';
|
2066 |
-
|
2067 |
-
# Regex to match any tag.
|
2068 |
-
$tag_re = '{
|
2069 |
-
( # $2: Capture hole tag.
|
2070 |
-
</? # Any opening or closing tag.
|
2071 |
-
[\w:$]+ # Tag name.
|
2072 |
-
(?:
|
2073 |
-
(?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
|
2074 |
-
(?>
|
2075 |
-
".*?" | # Double quotes (can contain `>`)
|
2076 |
-
\'.*?\' | # Single quotes (can contain `>`)
|
2077 |
-
.+? # Anything but quotes and `>`.
|
2078 |
-
)*?
|
2079 |
-
)?
|
2080 |
-
> # End of tag.
|
2081 |
-
|
|
2082 |
-
<!-- .*? --> # HTML Comment
|
2083 |
-
|
|
2084 |
-
<\?.*?\?> | <%.*?%> # Processing instruction
|
2085 |
-
|
|
2086 |
-
<!\[CDATA\[.*?\]\]> # CData Block
|
2087 |
-
)
|
2088 |
-
}xs';
|
2089 |
-
|
2090 |
-
$original_text = $text; # Save original text in case of faliure.
|
2091 |
-
|
2092 |
-
$depth = 0; # Current depth inside the tag tree.
|
2093 |
-
$block_text = ""; # Temporary text holder for current text.
|
2094 |
-
$parsed = ""; # Parsed text that will be returned.
|
2095 |
-
|
2096 |
-
#
|
2097 |
-
# Get the name of the starting tag.
|
2098 |
-
# (This pattern makes $base_tag_name_re safe without quoting.)
|
2099 |
-
#
|
2100 |
-
if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
|
2101 |
-
$base_tag_name_re = $matches[1];
|
2102 |
-
|
2103 |
-
#
|
2104 |
-
# Loop through every tag until we find the corresponding closing tag.
|
2105 |
-
#
|
2106 |
-
do {
|
2107 |
-
#
|
2108 |
-
# Split the text using the first $tag_match pattern found.
|
2109 |
-
# Text before pattern will be first in the array, text after
|
2110 |
-
# pattern will be at the end, and between will be any catches made
|
2111 |
-
# by the pattern.
|
2112 |
-
#
|
2113 |
-
$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
|
2114 |
-
|
2115 |
-
if (count($parts) < 3) {
|
2116 |
-
#
|
2117 |
-
# End of $text reached with unbalenced tag(s).
|
2118 |
-
# In that case, we return original text unchanged and pass the
|
2119 |
-
# first character as filtered to prevent an infinite loop in the
|
2120 |
-
# parent function.
|
2121 |
-
#
|
2122 |
-
return array($original_text{0}, substr($original_text, 1));
|
2123 |
-
}
|
2124 |
-
|
2125 |
-
$block_text .= $parts[0]; # Text before current tag.
|
2126 |
-
$tag = $parts[1]; # Tag to handle.
|
2127 |
-
$text = $parts[2]; # Remaining text after current tag.
|
2128 |
-
|
2129 |
-
#
|
2130 |
-
# Check for: Auto-close tag (like <hr/>)
|
2131 |
-
# Comments and Processing Instructions.
|
2132 |
-
#
|
2133 |
-
if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
|
2134 |
-
$tag{1} == '!' || $tag{1} == '?')
|
2135 |
-
{
|
2136 |
-
# Just add the tag to the block as if it was text.
|
2137 |
-
$block_text .= $tag;
|
2138 |
-
}
|
2139 |
-
else {
|
2140 |
-
#
|
2141 |
-
# Increase/decrease nested tag count. Only do so if
|
2142 |
-
# the tag's name match base tag's.
|
2143 |
-
#
|
2144 |
-
if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
|
2145 |
-
if ($tag{1} == '/') $depth--;
|
2146 |
-
else if ($tag{strlen($tag)-2} != '/') $depth++;
|
2147 |
-
}
|
2148 |
-
|
2149 |
-
#
|
2150 |
-
# Check for `markdown="1"` attribute and handle it.
|
2151 |
-
#
|
2152 |
-
if ($md_attr &&
|
2153 |
-
preg_match($markdown_attr_re, $tag, $attr_m) &&
|
2154 |
-
preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
|
2155 |
-
{
|
2156 |
-
# Remove `markdown` attribute from opening tag.
|
2157 |
-
$tag = preg_replace($markdown_attr_re, '', $tag);
|
2158 |
-
|
2159 |
-
# Check if text inside this tag must be parsed in span mode.
|
2160 |
-
$this->mode = $attr_m[2] . $attr_m[3];
|
2161 |
-
$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
|
2162 |
-
preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
|
2163 |
-
|
2164 |
-
# Calculate indent before tag.
|
2165 |
-
if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
|
2166 |
-
$strlen = $this->utf8_strlen;
|
2167 |
-
$indent = $strlen($matches[1], 'UTF-8');
|
2168 |
-
} else {
|
2169 |
-
$indent = 0;
|
2170 |
-
}
|
2171 |
-
|
2172 |
-
# End preceding block with this tag.
|
2173 |
-
$block_text .= $tag;
|
2174 |
-
$parsed .= $this->$hash_method($block_text);
|
2175 |
-
|
2176 |
-
# Get enclosing tag name for the ParseMarkdown function.
|
2177 |
-
# (This pattern makes $tag_name_re safe without quoting.)
|
2178 |
-
preg_match('/^<([\w:$]*)\b/', $tag, $matches);
|
2179 |
-
$tag_name_re = $matches[1];
|
2180 |
-
|
2181 |
-
# Parse the content using the HTML-in-Markdown parser.
|
2182 |
-
list ($block_text, $text)
|
2183 |
-
= $this->_hashHTMLBlocks_inMarkdown($text, $indent,
|
2184 |
-
$tag_name_re, $span_mode);
|
2185 |
-
|
2186 |
-
# Outdent markdown text.
|
2187 |
-
if ($indent > 0) {
|
2188 |
-
$block_text = preg_replace("/^[ ]{1,$indent}/m", "",
|
2189 |
-
$block_text);
|
2190 |
-
}
|
2191 |
-
|
2192 |
-
# Append tag content to parsed text.
|
2193 |
-
if (!$span_mode) $parsed .= "\n\n$block_text\n\n";
|
2194 |
-
else $parsed .= "$block_text";
|
2195 |
-
|
2196 |
-
# Start over a new block.
|
2197 |
-
$block_text = "";
|
2198 |
-
}
|
2199 |
-
else $block_text .= $tag;
|
2200 |
-
}
|
2201 |
-
|
2202 |
-
} while ($depth > 0);
|
2203 |
-
|
2204 |
-
#
|
2205 |
-
# Hash last block text that wasn't processed inside the loop.
|
2206 |
-
#
|
2207 |
-
$parsed .= $this->$hash_method($block_text);
|
2208 |
-
|
2209 |
-
return array($parsed, $text);
|
2210 |
-
}
|
2211 |
-
|
2212 |
-
|
2213 |
-
function hashClean($text) {
|
2214 |
-
#
|
2215 |
-
# Called whenever a tag must be hashed when a function insert a "clean" tag
|
2216 |
-
# in $text, it pass through this function and is automaticaly escaped,
|
2217 |
-
# blocking invalid nested overlap.
|
2218 |
-
#
|
2219 |
-
return $this->hashPart($text, 'C');
|
2220 |
-
}
|
2221 |
-
|
2222 |
-
|
2223 |
-
function doHeaders($text) {
|
2224 |
-
#
|
2225 |
-
# Redefined to add id attribute support.
|
2226 |
-
#
|
2227 |
-
# Setext-style headers:
|
2228 |
-
# Header 1 {#header1}
|
2229 |
-
# ========
|
2230 |
-
#
|
2231 |
-
# Header 2 {#header2}
|
2232 |
-
# --------
|
2233 |
-
#
|
2234 |
-
$text = preg_replace_callback(
|
2235 |
-
'{
|
2236 |
-
(^.+?) # $1: Header text
|
2237 |
-
(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute
|
2238 |
-
[ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer
|
2239 |
-
}mx',
|
2240 |
-
array(&$this, '_doHeaders_callback_setext'), $text);
|
2241 |
-
|
2242 |
-
# atx-style headers:
|
2243 |
-
# # Header 1 {#header1}
|
2244 |
-
# ## Header 2 {#header2}
|
2245 |
-
# ## Header 2 with closing hashes ## {#header3}
|
2246 |
-
# ...
|
2247 |
-
# ###### Header 6 {#header2}
|
2248 |
-
#
|
2249 |
-
$text = preg_replace_callback('{
|
2250 |
-
^(\#{1,6}) # $1 = string of #\'s
|
2251 |
-
[ ]*
|
2252 |
-
(.+?) # $2 = Header text
|
2253 |
-
[ ]*
|
2254 |
-
\#* # optional closing #\'s (not counted)
|
2255 |
-
(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute
|
2256 |
-
[ ]*
|
2257 |
-
\n+
|
2258 |
-
}xm',
|
2259 |
-
array(&$this, '_doHeaders_callback_atx'), $text);
|
2260 |
-
|
2261 |
-
return $text;
|
2262 |
-
}
|
2263 |
-
function _doHeaders_attr($attr) {
|
2264 |
-
if (empty($attr)) return "";
|
2265 |
-
return " id=\"$attr\"";
|
2266 |
-
}
|
2267 |
-
function _doHeaders_callback_setext($matches) {
|
2268 |
-
if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
|
2269 |
-
return $matches[0];
|
2270 |
-
$level = $matches[3]{0} == '=' ? 1 : 2;
|
2271 |
-
$attr = $this->_doHeaders_attr($id =& $matches[2]);
|
2272 |
-
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
|
2273 |
-
return "\n" . $this->hashBlock($block) . "\n\n";
|
2274 |
-
}
|
2275 |
-
function _doHeaders_callback_atx($matches) {
|
2276 |
-
$level = strlen($matches[1]);
|
2277 |
-
$attr = $this->_doHeaders_attr($id =& $matches[3]);
|
2278 |
-
$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
|
2279 |
-
return "\n" . $this->hashBlock($block) . "\n\n";
|
2280 |
-
}
|
2281 |
-
|
2282 |
-
|
2283 |
-
function doTables($text) {
|
2284 |
-
#
|
2285 |
-
# Form HTML tables.
|
2286 |
-
#
|
2287 |
-
$less_than_tab = $this->tab_width - 1;
|
2288 |
-
#
|
2289 |
-
# Find tables with leading pipe.
|
2290 |
-
#
|
2291 |
-
# | Header 1 | Header 2
|
2292 |
-
# | -------- | --------
|
2293 |
-
# | Cell 1 | Cell 2
|
2294 |
-
# | Cell 3 | Cell 4
|
2295 |
-
#
|
2296 |
-
$text = preg_replace_callback('
|
2297 |
-
{
|
2298 |
-
^ # Start of a line
|
2299 |
-
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2300 |
-
[|] # Optional leading pipe (present)
|
2301 |
-
(.+) \n # $1: Header row (at least one pipe)
|
2302 |
-
|
2303 |
-
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2304 |
-
[|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline
|
2305 |
-
|
2306 |
-
( # $3: Cells
|
2307 |
-
(?>
|
2308 |
-
[ ]* # Allowed whitespace.
|
2309 |
-
[|] .* \n # Row content.
|
2310 |
-
)*
|
2311 |
-
)
|
2312 |
-
(?=\n|\Z) # Stop at final double newline.
|
2313 |
-
}xm',
|
2314 |
-
array(&$this, '_doTable_leadingPipe_callback'), $text);
|
2315 |
-
|
2316 |
-
#
|
2317 |
-
# Find tables without leading pipe.
|
2318 |
-
#
|
2319 |
-
# Header 1 | Header 2
|
2320 |
-
# -------- | --------
|
2321 |
-
# Cell 1 | Cell 2
|
2322 |
-
# Cell 3 | Cell 4
|
2323 |
-
#
|
2324 |
-
$text = preg_replace_callback('
|
2325 |
-
{
|
2326 |
-
^ # Start of a line
|
2327 |
-
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2328 |
-
(\S.*[|].*) \n # $1: Header row (at least one pipe)
|
2329 |
-
|
2330 |
-
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2331 |
-
([-:]+[ ]*[|][-| :]*) \n # $2: Header underline
|
2332 |
-
|
2333 |
-
( # $3: Cells
|
2334 |
-
(?>
|
2335 |
-
.* [|] .* \n # Row content
|
2336 |
-
)*
|
2337 |
-
)
|
2338 |
-
(?=\n|\Z) # Stop at final double newline.
|
2339 |
-
}xm',
|
2340 |
-
array(&$this, '_DoTable_callback'), $text);
|
2341 |
-
|
2342 |
-
return $text;
|
2343 |
-
}
|
2344 |
-
function _doTable_leadingPipe_callback($matches) {
|
2345 |
-
$head = $matches[1];
|
2346 |
-
$underline = $matches[2];
|
2347 |
-
$content = $matches[3];
|
2348 |
-
|
2349 |
-
# Remove leading pipe for each row.
|
2350 |
-
$content = preg_replace('/^ *[|]/m', '', $content);
|
2351 |
-
|
2352 |
-
return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
|
2353 |
-
}
|
2354 |
-
function _doTable_callback($matches) {
|
2355 |
-
$head = $matches[1];
|
2356 |
-
$underline = $matches[2];
|
2357 |
-
$content = $matches[3];
|
2358 |
-
|
2359 |
-
# Remove any tailing pipes for each line.
|
2360 |
-
$head = preg_replace('/[|] *$/m', '', $head);
|
2361 |
-
$underline = preg_replace('/[|] *$/m', '', $underline);
|
2362 |
-
$content = preg_replace('/[|] *$/m', '', $content);
|
2363 |
-
|
2364 |
-
# Reading alignement from header underline.
|
2365 |
-
$separators = preg_split('/ *[|] */', $underline);
|
2366 |
-
foreach ($separators as $n => $s) {
|
2367 |
-
if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"';
|
2368 |
-
else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
|
2369 |
-
else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
|
2370 |
-
else $attr[$n] = '';
|
2371 |
-
}
|
2372 |
-
|
2373 |
-
# Parsing span elements, including code spans, character escapes,
|
2374 |
-
# and inline HTML tags, so that pipes inside those gets ignored.
|
2375 |
-
$head = $this->parseSpan($head);
|
2376 |
-
$headers = preg_split('/ *[|] */', $head);
|
2377 |
-
$col_count = count($headers);
|
2378 |
-
|
2379 |
-
# Write column headers.
|
2380 |
-
$text = "<table>\n";
|
2381 |
-
$text .= "<thead>\n";
|
2382 |
-
$text .= "<tr>\n";
|
2383 |
-
foreach ($headers as $n => $header)
|
2384 |
-
$text .= " <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
|
2385 |
-
$text .= "</tr>\n";
|
2386 |
-
$text .= "</thead>\n";
|
2387 |
-
|
2388 |
-
# Split content by row.
|
2389 |
-
$rows = explode("\n", trim($content, "\n"));
|
2390 |
-
|
2391 |
-
$text .= "<tbody>\n";
|
2392 |
-
foreach ($rows as $row) {
|
2393 |
-
# Parsing span elements, including code spans, character escapes,
|
2394 |
-
# and inline HTML tags, so that pipes inside those gets ignored.
|
2395 |
-
$row = $this->parseSpan($row);
|
2396 |
-
|
2397 |
-
# Split row by cell.
|
2398 |
-
$row_cells = preg_split('/ *[|] */', $row, $col_count);
|
2399 |
-
$row_cells = array_pad($row_cells, $col_count, '');
|
2400 |
-
|
2401 |
-
$text .= "<tr>\n";
|
2402 |
-
foreach ($row_cells as $n => $cell)
|
2403 |
-
$text .= " <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
|
2404 |
-
$text .= "</tr>\n";
|
2405 |
-
}
|
2406 |
-
$text .= "</tbody>\n";
|
2407 |
-
$text .= "</table>";
|
2408 |
-
|
2409 |
-
return $this->hashBlock($text) . "\n";
|
2410 |
-
}
|
2411 |
-
|
2412 |
-
|
2413 |
-
function doDefLists($text) {
|
2414 |
-
#
|
2415 |
-
# Form HTML definition lists.
|
2416 |
-
#
|
2417 |
-
$less_than_tab = $this->tab_width - 1;
|
2418 |
-
|
2419 |
-
# Re-usable pattern to match any entire dl list:
|
2420 |
-
$whole_list_re = '(?>
|
2421 |
-
( # $1 = whole list
|
2422 |
-
( # $2
|
2423 |
-
[ ]{0,'.$less_than_tab.'}
|
2424 |
-
((?>.*\S.*\n)+) # $3 = defined term
|
2425 |
-
\n?
|
2426 |
-
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2427 |
-
)
|
2428 |
-
(?s:.+?)
|
2429 |
-
( # $4
|
2430 |
-
\z
|
2431 |
-
|
|
2432 |
-
\n{2,}
|
2433 |
-
(?=\S)
|
2434 |
-
(?! # Negative lookahead for another term
|
2435 |
-
[ ]{0,'.$less_than_tab.'}
|
2436 |
-
(?: \S.*\n )+? # defined term
|
2437 |
-
\n?
|
2438 |
-
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2439 |
-
)
|
2440 |
-
(?! # Negative lookahead for another definition
|
2441 |
-
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2442 |
-
)
|
2443 |
-
)
|
2444 |
-
)
|
2445 |
-
)'; // mx
|
2446 |
-
|
2447 |
-
$text = preg_replace_callback('{
|
2448 |
-
(?>\A\n?|(?<=\n\n))
|
2449 |
-
'.$whole_list_re.'
|
2450 |
-
}mx',
|
2451 |
-
array(&$this, '_doDefLists_callback'), $text);
|
2452 |
-
|
2453 |
-
return $text;
|
2454 |
-
}
|
2455 |
-
function _doDefLists_callback($matches) {
|
2456 |
-
# Re-usable patterns to match list item bullets and number markers:
|
2457 |
-
$list = $matches[1];
|
2458 |
-
|
2459 |
-
# Turn double returns into triple returns, so that we can make a
|
2460 |
-
# paragraph for the last item in a list, if necessary:
|
2461 |
-
$result = trim($this->processDefListItems($list));
|
2462 |
-
$result = "<dl>\n" . $result . "\n</dl>";
|
2463 |
-
return $this->hashBlock($result) . "\n\n";
|
2464 |
-
}
|
2465 |
-
|
2466 |
-
|
2467 |
-
function processDefListItems($list_str) {
|
2468 |
-
#
|
2469 |
-
# Process the contents of a single definition list, splitting it
|
2470 |
-
# into individual term and definition list items.
|
2471 |
-
#
|
2472 |
-
$less_than_tab = $this->tab_width - 1;
|
2473 |
-
|
2474 |
-
# trim trailing blank lines:
|
2475 |
-
$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
|
2476 |
-
|
2477 |
-
# Process definition terms.
|
2478 |
-
$list_str = preg_replace_callback('{
|
2479 |
-
(?>\A\n?|\n\n+) # leading line
|
2480 |
-
( # definition terms = $1
|
2481 |
-
[ ]{0,'.$less_than_tab.'} # leading whitespace
|
2482 |
-
(?![:][ ]|[ ]) # negative lookahead for a definition
|
2483 |
-
# mark (colon) or more whitespace.
|
2484 |
-
(?> \S.* \n)+? # actual term (not whitespace).
|
2485 |
-
)
|
2486 |
-
(?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
|
2487 |
-
# with a definition mark.
|
2488 |
-
}xm',
|
2489 |
-
array(&$this, '_processDefListItems_callback_dt'), $list_str);
|
2490 |
-
|
2491 |
-
# Process actual definitions.
|
2492 |
-
$list_str = preg_replace_callback('{
|
2493 |
-
\n(\n+)? # leading line = $1
|
2494 |
-
( # marker space = $2
|
2495 |
-
[ ]{0,'.$less_than_tab.'} # whitespace before colon
|
2496 |
-
[:][ ]+ # definition mark (colon)
|
2497 |
-
)
|
2498 |
-
((?s:.+?)) # definition text = $3
|
2499 |
-
(?= \n+ # stop at next definition mark,
|
2500 |
-
(?: # next term or end of text
|
2501 |
-
[ ]{0,'.$less_than_tab.'} [:][ ] |
|
2502 |
-
<dt> | \z
|
2503 |
-
)
|
2504 |
-
)
|
2505 |
-
}xm',
|
2506 |
-
array(&$this, '_processDefListItems_callback_dd'), $list_str);
|
2507 |
-
|
2508 |
-
return $list_str;
|
2509 |
-
}
|
2510 |
-
function _processDefListItems_callback_dt($matches) {
|
2511 |
-
$terms = explode("\n", trim($matches[1]));
|
2512 |
-
$text = '';
|
2513 |
-
foreach ($terms as $term) {
|
2514 |
-
$term = $this->runSpanGamut(trim($term));
|
2515 |
-
$text .= "\n<dt>" . $term . "</dt>";
|
2516 |
-
}
|
2517 |
-
return $text . "\n";
|
2518 |
-
}
|
2519 |
-
function _processDefListItems_callback_dd($matches) {
|
2520 |
-
$leading_line = $matches[1];
|
2521 |
-
$marker_space = $matches[2];
|
2522 |
-
$def = $matches[3];
|
2523 |
-
|
2524 |
-
if ($leading_line || preg_match('/\n{2,}/', $def)) {
|
2525 |
-
# Replace marker with the appropriate whitespace indentation
|
2526 |
-
$def = str_repeat(' ', strlen($marker_space)) . $def;
|
2527 |
-
$def = $this->runBlockGamut($this->outdent($def . "\n\n"));
|
2528 |
-
$def = "\n". $def ."\n";
|
2529 |
-
}
|
2530 |
-
else {
|
2531 |
-
$def = rtrim($def);
|
2532 |
-
$def = $this->runSpanGamut($this->outdent($def));
|
2533 |
-
}
|
2534 |
-
|
2535 |
-
return "\n<dd>" . $def . "</dd>\n";
|
2536 |
-
}
|
2537 |
-
|
2538 |
-
|
2539 |
-
function doFencedCodeBlocks($text) {
|
2540 |
-
#
|
2541 |
-
# Adding the fenced code block syntax to regular Markdown:
|
2542 |
-
#
|
2543 |
-
# ~~~
|
2544 |
-
# Code block
|
2545 |
-
# ~~~
|
2546 |
-
#
|
2547 |
-
$less_than_tab = $this->tab_width;
|
2548 |
-
|
2549 |
-
$text = preg_replace_callback('{
|
2550 |
-
(?:\n|\A)
|
2551 |
-
# 1: Opening marker
|
2552 |
-
(
|
2553 |
-
~{3,} # Marker: three tilde or more.
|
2554 |
-
)
|
2555 |
-
[ ]* \n # Whitespace and newline following marker.
|
2556 |
-
|
2557 |
-
# 2: Content
|
2558 |
-
(
|
2559 |
-
(?>
|
2560 |
-
(?!\1 [ ]* \n) # Not a closing marker.
|
2561 |
-
.*\n+
|
2562 |
-
)+
|
2563 |
-
)
|
2564 |
-
|
2565 |
-
# Closing marker.
|
2566 |
-
\1 [ ]* \n
|
2567 |
-
}xm',
|
2568 |
-
array(&$this, '_doFencedCodeBlocks_callback'), $text);
|
2569 |
-
|
2570 |
-
return $text;
|
2571 |
-
}
|
2572 |
-
function _doFencedCodeBlocks_callback($matches) {
|
2573 |
-
$codeblock = $matches[2];
|
2574 |
-
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
|
2575 |
-
$codeblock = preg_replace_callback('/^\n+/',
|
2576 |
-
array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
|
2577 |
-
$codeblock = "<pre><code>$codeblock</code></pre>";
|
2578 |
-
return "\n\n".$this->hashBlock($codeblock)."\n\n";
|
2579 |
-
}
|
2580 |
-
function _doFencedCodeBlocks_newlines($matches) {
|
2581 |
-
return str_repeat("<br$this->empty_element_suffix",
|
2582 |
-
strlen($matches[0]));
|
2583 |
-
}
|
2584 |
-
|
2585 |
-
|
2586 |
-
#
|
2587 |
-
# Redefining emphasis markers so that emphasis by underscore does not
|
2588 |
-
# work in the middle of a word.
|
2589 |
-
#
|
2590 |
-
var $em_relist = array(
|
2591 |
-
'' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![.,:;]\s)',
|
2592 |
-
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
|
2593 |
-
'_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
|
2594 |
-
);
|
2595 |
-
var $strong_relist = array(
|
2596 |
-
'' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![.,:;]\s)',
|
2597 |
-
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
|
2598 |
-
'__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
|
2599 |
-
);
|
2600 |
-
var $em_strong_relist = array(
|
2601 |
-
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![.,:;]\s)',
|
2602 |
-
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
|
2603 |
-
'___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
|
2604 |
-
);
|
2605 |
-
|
2606 |
-
|
2607 |
-
function formParagraphs($text) {
|
2608 |
-
#
|
2609 |
-
# Params:
|
2610 |
-
# $text - string to process with html <p> tags
|
2611 |
-
#
|
2612 |
-
# Strip leading and trailing lines:
|
2613 |
-
$text = preg_replace('/\A\n+|\n+\z/', '', $text);
|
2614 |
-
|
2615 |
-
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
|
2616 |
-
|
2617 |
-
#
|
2618 |
-
# Wrap <p> tags and unhashify HTML blocks
|
2619 |
-
#
|
2620 |
-
foreach ($grafs as $key => $value) {
|
2621 |
-
$value = trim($this->runSpanGamut($value));
|
2622 |
-
|
2623 |
-
# Check if this should be enclosed in a paragraph.
|
2624 |
-
# Clean tag hashes & block tag hashes are left alone.
|
2625 |
-
$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
|
2626 |
-
|
2627 |
-
if ($is_p) {
|
2628 |
-
$value = "<p>$value</p>";
|
2629 |
-
}
|
2630 |
-
$grafs[$key] = $value;
|
2631 |
-
}
|
2632 |
-
|
2633 |
-
# Join grafs in one text, then unhash HTML tags.
|
2634 |
-
$text = implode("\n\n", $grafs);
|
2635 |
-
|
2636 |
-
# Finish by removing any tag hashes still present in $text.
|
2637 |
-
$text = $this->unhash($text);
|
2638 |
-
|
2639 |
-
return $text;
|
2640 |
-
}
|
2641 |
-
|
2642 |
-
|
2643 |
-
### Footnotes
|
2644 |
-
|
2645 |
-
function stripFootnotes($text) {
|
2646 |
-
#
|
2647 |
-
# Strips link definitions from text, stores the URLs and titles in
|
2648 |
-
# hash references.
|
2649 |
-
#
|
2650 |
-
$less_than_tab = $this->tab_width - 1;
|
2651 |
-
|
2652 |
-
# Link defs are in the form: [^id]: url "optional title"
|
2653 |
-
$text = preg_replace_callback('{
|
2654 |
-
^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1
|
2655 |
-
[ ]*
|
2656 |
-
\n? # maybe *one* newline
|
2657 |
-
( # text = $2 (no blank lines allowed)
|
2658 |
-
(?:
|
2659 |
-
.+ # actual text
|
2660 |
-
|
|
2661 |
-
\n # newlines but
|
2662 |
-
(?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
|
2663 |
-
(?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
|
2664 |
-
# by non-indented content
|
2665 |
-
)*
|
2666 |
-
)
|
2667 |
-
}xm',
|
2668 |
-
array(&$this, '_stripFootnotes_callback'),
|
2669 |
-
$text);
|
2670 |
-
return $text;
|
2671 |
-
}
|
2672 |
-
function _stripFootnotes_callback($matches) {
|
2673 |
-
$note_id = $this->fn_id_prefix . $matches[1];
|
2674 |
-
$this->footnotes[$note_id] = $this->outdent($matches[2]);
|
2675 |
-
return ''; # String that will replace the block
|
2676 |
-
}
|
2677 |
-
|
2678 |
-
|
2679 |
-
function doFootnotes($text) {
|
2680 |
-
#
|
2681 |
-
# Replace footnote references in $text [^id] with a special text-token
|
2682 |
-
# which will be replaced by the actual footnote marker in appendFootnotes.
|
2683 |
-
#
|
2684 |
-
if (!$this->in_anchor) {
|
2685 |
-
$text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
|
2686 |
-
}
|
2687 |
-
return $text;
|
2688 |
-
}
|
2689 |
-
|
2690 |
-
|
2691 |
-
function appendFootnotes($text) {
|
2692 |
-
#
|
2693 |
-
# Append footnote list to text.
|
2694 |
-
#
|
2695 |
-
$text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
|
2696 |
-
array(&$this, '_appendFootnotes_callback'), $text);
|
2697 |
-
|
2698 |
-
if (!empty($this->footnotes_ordered)) {
|
2699 |
-
$text .= "\n\n";
|
2700 |
-
$text .= "<div class=\"footnotes\">\n";
|
2701 |
-
$text .= "<hr". $this->empty_element_suffix ."\n";
|
2702 |
-
$text .= "<ol>\n\n";
|
2703 |
-
|
2704 |
-
$attr = " rev=\"footnote\"";
|
2705 |
-
if ($this->fn_backlink_class != "") {
|
2706 |
-
$class = $this->fn_backlink_class;
|
2707 |
-
$class = $this->encodeAttribute($class);
|
2708 |
-
$attr .= " class=\"$class\"";
|
2709 |
-
}
|
2710 |
-
if ($this->fn_backlink_title != "") {
|
2711 |
-
$title = $this->fn_backlink_title;
|
2712 |
-
$title = $this->encodeAttribute($title);
|
2713 |
-
$attr .= " title=\"$title\"";
|
2714 |
-
}
|
2715 |
-
$num = 0;
|
2716 |
-
|
2717 |
-
while (!empty($this->footnotes_ordered)) {
|
2718 |
-
$footnote = reset($this->footnotes_ordered);
|
2719 |
-
$note_id = key($this->footnotes_ordered);
|
2720 |
-
unset($this->footnotes_ordered[$note_id]);
|
2721 |
-
|
2722 |
-
$footnote .= "\n"; # Need to append newline before parsing.
|
2723 |
-
$footnote = $this->runBlockGamut("$footnote\n");
|
2724 |
-
$footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
|
2725 |
-
array(&$this, '_appendFootnotes_callback'), $footnote);
|
2726 |
-
|
2727 |
-
$attr = str_replace("%%", ++$num, $attr);
|
2728 |
-
$note_id = $this->encodeAttribute($note_id);
|
2729 |
-
|
2730 |
-
# Add backlink to last paragraph; create new paragraph if needed.
|
2731 |
-
$backlink = "<a href=\"#fnref:$note_id\"$attr>↩</a>";
|
2732 |
-
if (preg_match('{</p>$}', $footnote)) {
|
2733 |
-
$footnote = substr($footnote, 0, -4) . " $backlink</p>";
|
2734 |
-
} else {
|
2735 |
-
$footnote .= "\n\n<p>$backlink</p>";
|
2736 |
-
}
|
2737 |
-
|
2738 |
-
$text .= "<li id=\"fn:$note_id\">\n";
|
2739 |
-
$text .= $footnote . "\n";
|
2740 |
-
$text .= "</li>\n\n";
|
2741 |
-
}
|
2742 |
-
|
2743 |
-
$text .= "</ol>\n";
|
2744 |
-
$text .= "</div>";
|
2745 |
-
}
|
2746 |
-
return $text;
|
2747 |
-
}
|
2748 |
-
function _appendFootnotes_callback($matches) {
|
2749 |
-
$node_id = $this->fn_id_prefix . $matches[1];
|
2750 |
-
|
2751 |
-
# Create footnote marker only if it has a corresponding footnote *and*
|
2752 |
-
# the footnote hasn't been used by another marker.
|
2753 |
-
if (isset($this->footnotes[$node_id])) {
|
2754 |
-
# Transfert footnote content to the ordered list.
|
2755 |
-
$this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
|
2756 |
-
unset($this->footnotes[$node_id]);
|
2757 |
-
|
2758 |
-
$num = $this->footnote_counter++;
|
2759 |
-
$attr = " rel=\"footnote\"";
|
2760 |
-
if ($this->fn_link_class != "") {
|
2761 |
-
$class = $this->fn_link_class;
|
2762 |
-
$class = $this->encodeAttribute($class);
|
2763 |
-
$attr .= " class=\"$class\"";
|
2764 |
-
}
|
2765 |
-
if ($this->fn_link_title != "") {
|
2766 |
-
$title = $this->fn_link_title;
|
2767 |
-
$title = $this->encodeAttribute($title);
|
2768 |
-
$attr .= " title=\"$title\"";
|
2769 |
-
}
|
2770 |
-
|
2771 |
-
$attr = str_replace("%%", $num, $attr);
|
2772 |
-
$node_id = $this->encodeAttribute($node_id);
|
2773 |
-
|
2774 |
-
return
|
2775 |
-
"<sup id=\"fnref:$node_id\">".
|
2776 |
-
"<a href=\"#fn:$node_id\"$attr>$num</a>".
|
2777 |
-
"</sup>";
|
2778 |
-
}
|
2779 |
-
|
2780 |
-
return "[^".$matches[1]."]";
|
2781 |
-
}
|
2782 |
-
|
2783 |
-
|
2784 |
-
### Abbreviations ###
|
2785 |
-
|
2786 |
-
function stripAbbreviations($text) {
|
2787 |
-
#
|
2788 |
-
# Strips abbreviations from text, stores titles in hash references.
|
2789 |
-
#
|
2790 |
-
$less_than_tab = $this->tab_width - 1;
|
2791 |
-
|
2792 |
-
# Link defs are in the form: [id]*: url "optional title"
|
2793 |
-
$text = preg_replace_callback('{
|
2794 |
-
^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1
|
2795 |
-
(.*) # text = $2 (no blank lines allowed)
|
2796 |
-
}xm',
|
2797 |
-
array(&$this, '_stripAbbreviations_callback'),
|
2798 |
-
$text);
|
2799 |
-
return $text;
|
2800 |
-
}
|
2801 |
-
function _stripAbbreviations_callback($matches) {
|
2802 |
-
$abbr_word = $matches[1];
|
2803 |
-
$abbr_desc = $matches[2];
|
2804 |
-
if ($this->abbr_word_re)
|
2805 |
-
$this->abbr_word_re .= '|';
|
2806 |
-
$this->abbr_word_re .= preg_quote($abbr_word);
|
2807 |
-
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
|
2808 |
-
return ''; # String that will replace the block
|
2809 |
-
}
|
2810 |
-
|
2811 |
-
|
2812 |
-
function doAbbreviations($text) {
|
2813 |
-
#
|
2814 |
-
# Find defined abbreviations in text and wrap them in <abbr> elements.
|
2815 |
-
#
|
2816 |
-
if ($this->abbr_word_re) {
|
2817 |
-
// cannot use the /x modifier because abbr_word_re may
|
2818 |
-
// contain significant spaces:
|
2819 |
-
$text = preg_replace_callback('{'.
|
2820 |
-
'(?<![\w\x1A])'.
|
2821 |
-
'(?:'.$this->abbr_word_re.')'.
|
2822 |
-
'(?![\w\x1A])'.
|
2823 |
-
'}',
|
2824 |
-
array(&$this, '_doAbbreviations_callback'), $text);
|
2825 |
-
}
|
2826 |
-
return $text;
|
2827 |
-
}
|
2828 |
-
function _doAbbreviations_callback($matches) {
|
2829 |
-
$abbr = $matches[0];
|
2830 |
-
if (isset($this->abbr_desciptions[$abbr])) {
|
2831 |
-
$desc = $this->abbr_desciptions[$abbr];
|
2832 |
-
if (empty($desc)) {
|
2833 |
-
return $this->hashPart("<abbr>$abbr</abbr>");
|
2834 |
-
} else {
|
2835 |
-
$desc = $this->encodeAttribute($desc);
|
2836 |
-
return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
|
2837 |
-
}
|
2838 |
-
} else {
|
2839 |
-
return $matches[0];
|
2840 |
-
}
|
2841 |
-
}
|
2842 |
-
|
2843 |
-
}
|
2844 |
-
|
2845 |
-
|
2846 |
-
/*
|
2847 |
-
|
2848 |
-
PHP Markdown Extra
|
2849 |
-
==================
|
2850 |
-
|
2851 |
-
Description
|
2852 |
-
-----------
|
2853 |
-
|
2854 |
-
This is a PHP port of the original Markdown formatter written in Perl
|
2855 |
-
by John Gruber. This special "Extra" version of PHP Markdown features
|
2856 |
-
further enhancements to the syntax for making additional constructs
|
2857 |
-
such as tables and definition list.
|
2858 |
-
|
2859 |
-
Markdown is a text-to-HTML filter; it translates an easy-to-read /
|
2860 |
-
easy-to-write structured text format into HTML. Markdown's text format
|
2861 |
-
is most similar to that of plain text email, and supports features such
|
2862 |
-
as headers, *emphasis*, code blocks, blockquotes, and links.
|
2863 |
-
|
2864 |
-
Markdown's syntax is designed not as a generic markup language, but
|
2865 |
-
specifically to serve as a front-end to (X)HTML. You can use span-level
|
2866 |
-
HTML tags anywhere in a Markdown document, and you can use block level
|
2867 |
-
HTML tags (like <div> and <table> as well).
|
2868 |
-
|
2869 |
-
For more information about Markdown's syntax, see:
|
2870 |
-
|
2871 |
-
<http://daringfireball.net/projects/markdown/>
|
2872 |
-
|
2873 |
-
|
2874 |
-
Bugs
|
2875 |
-
----
|
2876 |
-
|
2877 |
-
To file bug reports please send email to:
|
2878 |
-
|
2879 |
-
<michel.fortin@michelf.com>
|
2880 |
-
|
2881 |
-
Please include with your report: (1) the example input; (2) the output you
|
2882 |
-
expected; (3) the output Markdown actually produced.
|
2883 |
-
|
2884 |
-
|
2885 |
-
Version History
|
2886 |
-
---------------
|
2887 |
-
|
2888 |
-
See the readme file for detailed release notes for this version.
|
2889 |
-
|
2890 |
-
|
2891 |
-
Copyright and License
|
2892 |
-
---------------------
|
2893 |
-
|
2894 |
-
PHP Markdown & Extra
|
2895 |
-
Copyright (c) 2004-2009 Michel Fortin
|
2896 |
-
<http://michelf.com/>
|
2897 |
-
All rights reserved.
|
2898 |
-
|
2899 |
-
Based on Markdown
|
2900 |
-
Copyright (c) 2003-2006 John Gruber
|
2901 |
-
<http://daringfireball.net/>
|
2902 |
-
All rights reserved.
|
2903 |
-
|
2904 |
-
Redistribution and use in source and binary forms, with or without
|
2905 |
-
modification, are permitted provided that the following conditions are
|
2906 |
-
met:
|
2907 |
-
|
2908 |
-
* Redistributions of source code must retain the above copyright notice,
|
2909 |
-
this list of conditions and the following disclaimer.
|
2910 |
-
|
2911 |
-
* Redistributions in binary form must reproduce the above copyright
|
2912 |
-
notice, this list of conditions and the following disclaimer in the
|
2913 |
-
documentation and/or other materials provided with the distribution.
|
2914 |
-
|
2915 |
-
* Neither the name "Markdown" nor the names of its contributors may
|
2916 |
-
be used to endorse or promote products derived from this software
|
2917 |
-
without specific prior written permission.
|
2918 |
-
|
2919 |
-
This software is provided by the copyright holders and contributors "as
|
2920 |
-
is" and any express or implied warranties, including, but not limited
|
2921 |
-
to, the implied warranties of merchantability and fitness for a
|
2922 |
-
particular purpose are disclaimed. In no event shall the copyright owner
|
2923 |
-
or contributors be liable for any direct, indirect, incidental, special,
|
2924 |
-
exemplary, or consequential damages (including, but not limited to,
|
2925 |
-
procurement of substitute goods or services; loss of use, data, or
|
2926 |
-
profits; or business interruption) however caused and on any theory of
|
2927 |
-
liability, whether in contract, strict liability, or tort (including
|
2928 |
-
negligence or otherwise) arising in any way out of the use of this
|
2929 |
-
software, even if advised of the possibility of such damage.
|
2930 |
-
|
2931 |
-
*/
|
2932 |
?>
|
1 |
+
<?php
|
2 |
+
#
|
3 |
+
# Markdown Extra - A text-to-HTML conversion tool for web writers
|
4 |
+
#
|
5 |
+
# PHP Markdown & Extra
|
6 |
+
# Copyright (c) 2004-2009 Michel Fortin
|
7 |
+
# <http://michelf.com/projects/php-markdown/>
|
8 |
+
#
|
9 |
+
# Original Markdown
|
10 |
+
# Copyright (c) 2004-2006 John Gruber
|
11 |
+
# <http://daringfireball.net/projects/markdown/>
|
12 |
+
#
|
13 |
+
|
14 |
+
|
15 |
+
define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
|
16 |
+
define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009
|
17 |
+
|
18 |
+
|
19 |
+
#
|
20 |
+
# Global default settings:
|
21 |
+
#
|
22 |
+
|
23 |
+
# Change to ">" for HTML output
|
24 |
+
@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />");
|
25 |
+
|
26 |
+
# Define the width of a tab for code blocks.
|
27 |
+
@define( 'MARKDOWN_TAB_WIDTH', 4 );
|
28 |
+
|
29 |
+
# Optional title attribute for footnote links and backlinks.
|
30 |
+
@define( 'MARKDOWN_FN_LINK_TITLE', "" );
|
31 |
+
@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" );
|
32 |
+
|
33 |
+
# Optional class attribute for footnote links and backlinks.
|
34 |
+
@define( 'MARKDOWN_FN_LINK_CLASS', "" );
|
35 |
+
@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
|
36 |
+
|
37 |
+
|
38 |
+
#
|
39 |
+
# WordPress settings:
|
40 |
+
#
|
41 |
+
|
42 |
+
# Change to false to remove Markdown from posts and/or comments.
|
43 |
+
@define( 'MARKDOWN_WP_POSTS', true );
|
44 |
+
@define( 'MARKDOWN_WP_COMMENTS', true );
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
### Standard Function Interface ###
|
49 |
+
|
50 |
+
@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' );
|
51 |
+
|
52 |
+
function Markdown($text) {
|
53 |
+
#
|
54 |
+
# Initialize the parser and return the result of its transform method.
|
55 |
+
#
|
56 |
+
# Setup static parser variable.
|
57 |
+
static $parser;
|
58 |
+
if (!isset($parser)) {
|
59 |
+
$parser_class = MARKDOWN_PARSER_CLASS;
|
60 |
+
$parser = new $parser_class;
|
61 |
+
}
|
62 |
+
|
63 |
+
# Transform text using parser.
|
64 |
+
return $parser->transform($text);
|
65 |
+
}
|
66 |
+
|
67 |
+
|
68 |
+
### WordPress Plugin Interface ###
|
69 |
+
|
70 |
+
/*
|
71 |
+
Plugin Name: Markdown Extra
|
72 |
+
Plugin URI: http://michelf.com/projects/php-markdown/
|
73 |
+
Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>
|
74 |
+
Version: 1.2.4
|
75 |
+
Author: Michel Fortin
|
76 |
+
Author URI: http://michelf.com/
|
77 |
+
*/
|
78 |
+
|
79 |
+
if (isset($wp_version)) {
|
80 |
+
# More details about how it works here:
|
81 |
+
# <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
|
82 |
+
|
83 |
+
# Post content and excerpts
|
84 |
+
# - Remove WordPress paragraph generator.
|
85 |
+
# - Run Markdown on excerpt, then remove all tags.
|
86 |
+
# - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
|
87 |
+
if (MARKDOWN_WP_POSTS) {
|
88 |
+
remove_filter('the_content', 'wpautop');
|
89 |
+
remove_filter('the_content_rss', 'wpautop');
|
90 |
+
remove_filter('the_excerpt', 'wpautop');
|
91 |
+
add_filter('the_content', 'mdwp_MarkdownPost', 6);
|
92 |
+
add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
|
93 |
+
add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
|
94 |
+
add_filter('get_the_excerpt', 'trim', 7);
|
95 |
+
add_filter('the_excerpt', 'mdwp_add_p');
|
96 |
+
add_filter('the_excerpt_rss', 'mdwp_strip_p');
|
97 |
+
|
98 |
+
remove_filter('content_save_pre', 'balanceTags', 50);
|
99 |
+
remove_filter('excerpt_save_pre', 'balanceTags', 50);
|
100 |
+
add_filter('the_content', 'balanceTags', 50);
|
101 |
+
add_filter('get_the_excerpt', 'balanceTags', 9);
|
102 |
+
}
|
103 |
+
|
104 |
+
# Add a footnote id prefix to posts when inside a loop.
|
105 |
+
function mdwp_MarkdownPost($text) {
|
106 |
+
static $parser;
|
107 |
+
if (!$parser) {
|
108 |
+
$parser_class = MARKDOWN_PARSER_CLASS;
|
109 |
+
$parser = new $parser_class;
|
110 |
+
}
|
111 |
+
if (is_single() || is_page() || is_feed()) {
|
112 |
+
$parser->fn_id_prefix = "";
|
113 |
+
} else {
|
114 |
+
$parser->fn_id_prefix = get_the_ID() . ".";
|
115 |
+
}
|
116 |
+
return $parser->transform($text);
|
117 |
+
}
|
118 |
+
|
119 |
+
# Comments
|
120 |
+
# - Remove WordPress paragraph generator.
|
121 |
+
# - Remove WordPress auto-link generator.
|
122 |
+
# - Scramble important tags before passing them to the kses filter.
|
123 |
+
# - Run Markdown on excerpt then remove paragraph tags.
|
124 |
+
if (MARKDOWN_WP_COMMENTS) {
|
125 |
+
remove_filter('comment_text', 'wpautop', 30);
|
126 |
+
remove_filter('comment_text', 'make_clickable');
|
127 |
+
add_filter('pre_comment_content', 'Markdown', 6);
|
128 |
+
add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
|
129 |
+
add_filter('pre_comment_content', 'mdwp_show_tags', 12);
|
130 |
+
add_filter('get_comment_text', 'Markdown', 6);
|
131 |
+
add_filter('get_comment_excerpt', 'Markdown', 6);
|
132 |
+
add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
|
133 |
+
|
134 |
+
global $mdwp_hidden_tags, $mdwp_placeholders;
|
135 |
+
$mdwp_hidden_tags = explode(' ',
|
136 |
+
'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
|
137 |
+
$mdwp_placeholders = explode(' ', str_rot13(
|
138 |
+
'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
|
139 |
+
'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
|
140 |
+
}
|
141 |
+
|
142 |
+
function mdwp_add_p($text) {
|
143 |
+
if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
|
144 |
+
$text = '<p>'.$text.'</p>';
|
145 |
+
$text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
|
146 |
+
}
|
147 |
+
return $text;
|
148 |
+
}
|
149 |
+
|
150 |
+
function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
|
151 |
+
|
152 |
+
function mdwp_hide_tags($text) {
|
153 |
+
global $mdwp_hidden_tags, $mdwp_placeholders;
|
154 |
+
return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
|
155 |
+
}
|
156 |
+
function mdwp_show_tags($text) {
|
157 |
+
global $mdwp_hidden_tags, $mdwp_placeholders;
|
158 |
+
return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
|
163 |
+
### bBlog Plugin Info ###
|
164 |
+
|
165 |
+
function identify_modifier_markdown() {
|
166 |
+
return array(
|
167 |
+
'name' => 'markdown',
|
168 |
+
'type' => 'modifier',
|
169 |
+
'nicename' => 'PHP Markdown Extra',
|
170 |
+
'description' => 'A text-to-HTML conversion tool for web writers',
|
171 |
+
'authors' => 'Michel Fortin and John Gruber',
|
172 |
+
'licence' => 'GPL',
|
173 |
+
'version' => MARKDOWNEXTRA_VERSION,
|
174 |
+
'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
|
175 |
+
);
|
176 |
+
}
|
177 |
+
|
178 |
+
|
179 |
+
### Smarty Modifier Interface ###
|
180 |
+
|
181 |
+
function smarty_modifier_markdown($text) {
|
182 |
+
return Markdown($text);
|
183 |
+
}
|
184 |
+
|
185 |
+
|
186 |
+
### Textile Compatibility Mode ###
|
187 |
+
|
188 |
+
# Rename this file to "classTextile.php" and it can replace Textile everywhere.
|
189 |
+
|
190 |
+
if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
|
191 |
+
# Try to include PHP SmartyPants. Should be in the same directory.
|
192 |
+
@include_once 'smartypants.php';
|
193 |
+
# Fake Textile class. It calls Markdown instead.
|
194 |
+
class Textile {
|
195 |
+
function TextileThis($text, $lite='', $encode='') {
|
196 |
+
if ($lite == '' && $encode == '') $text = Markdown($text);
|
197 |
+
if (function_exists('SmartyPants')) $text = SmartyPants($text);
|
198 |
+
return $text;
|
199 |
+
}
|
200 |
+
# Fake restricted version: restrictions are not supported for now.
|
201 |
+
function TextileRestricted($text, $lite='', $noimage='') {
|
202 |
+
return $this->TextileThis($text, $lite);
|
203 |
+
}
|
204 |
+
# Workaround to ensure compatibility with TextPattern 4.0.3.
|
205 |
+
function blockLite($text) { return $text; }
|
206 |
+
}
|
207 |
+
}
|
208 |
+
|
209 |
+
|
210 |
+
|
211 |
+
#
|
212 |
+
# Markdown Parser Class
|
213 |
+
#
|
214 |
+
|
215 |
+
class Markdown_Parser {
|
216 |
+
|
217 |
+
# Regex to match balanced [brackets].
|
218 |
+
# Needed to insert a maximum bracked depth while converting to PHP.
|
219 |
+
var $nested_brackets_depth = 6;
|
220 |
+
var $nested_brackets_re;
|
221 |
+
|
222 |
+
var $nested_url_parenthesis_depth = 4;
|
223 |
+
var $nested_url_parenthesis_re;
|
224 |
+
|
225 |
+
# Table of hash values for escaped characters:
|
226 |
+
var $escape_chars = '\`*_{}[]()>#+-.!';
|
227 |
+
var $escape_chars_re;
|
228 |
+
|
229 |
+
# Change to ">" for HTML output.
|
230 |
+
var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
|
231 |
+
var $tab_width = MARKDOWN_TAB_WIDTH;
|
232 |
+
|
233 |
+
# Change to `true` to disallow markup or entities.
|
234 |
+
var $no_markup = false;
|
235 |
+
var $no_entities = false;
|
236 |
+
|
237 |
+
# Predefined urls and titles for reference links and images.
|
238 |
+
var $predef_urls = array();
|
239 |
+
var $predef_titles = array();
|
240 |
+
|
241 |
+
|
242 |
+
function Markdown_Parser() {
|
243 |
+
#
|
244 |
+
# Constructor function. Initialize appropriate member variables.
|
245 |
+
#
|
246 |
+
$this->_initDetab();
|
247 |
+
$this->prepareItalicsAndBold();
|
248 |
+
|
249 |
+
$this->nested_brackets_re =
|
250 |
+
str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
|
251 |
+
str_repeat('\])*', $this->nested_brackets_depth);
|
252 |
+
|
253 |
+
$this->nested_url_parenthesis_re =
|
254 |
+
str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
|
255 |
+
str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
|
256 |
+
|
257 |
+
$this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
|
258 |
+
|
259 |
+
# Sort document, block, and span gamut in ascendent priority order.
|
260 |
+
asort($this->document_gamut);
|
261 |
+
asort($this->block_gamut);
|
262 |
+
asort($this->span_gamut);
|
263 |
+
}
|
264 |
+
|
265 |
+
|
266 |
+
# Internal hashes used during transformation.
|
267 |
+
var $urls = array();
|
268 |
+
var $titles = array();
|
269 |
+
var $html_hashes = array();
|
270 |
+
|
271 |
+
# Status flag to avoid invalid nesting.
|
272 |
+
var $in_anchor = false;
|
273 |
+
|
274 |
+
|
275 |
+
function setup() {
|
276 |
+
#
|
277 |
+
# Called before the transformation process starts to setup parser
|
278 |
+
# states.
|
279 |
+
#
|
280 |
+
# Clear global hashes.
|
281 |
+
$this->urls = $this->predef_urls;
|
282 |
+
$this->titles = $this->predef_titles;
|
283 |
+
$this->html_hashes = array();
|
284 |
+
|
285 |
+
$in_anchor = false;
|
286 |
+
}
|
287 |
+
|
288 |
+
function teardown() {
|
289 |
+
#
|
290 |
+
# Called after the transformation process to clear any variable
|
291 |
+
# which may be taking up memory unnecessarly.
|
292 |
+
#
|
293 |
+
$this->urls = array();
|
294 |
+
$this->titles = array();
|
295 |
+
$this->html_hashes = array();
|
296 |
+
}
|
297 |
+
|
298 |
+
|
299 |
+
function transform($text) {
|
300 |
+
#
|
301 |
+
# Main function. Performs some preprocessing on the input text
|
302 |
+
# and pass it through the document gamut.
|
303 |
+
#
|
304 |
+
$this->setup();
|
305 |
+
|
306 |
+
# Remove UTF-8 BOM and marker character in input, if present.
|
307 |
+
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
|
308 |
+
|
309 |
+
# Standardize line endings:
|
310 |
+
# DOS to Unix and Mac to Unix
|
311 |
+
$text = preg_replace('{\r\n?}', "\n", $text);
|
312 |
+
|
313 |
+
# Make sure $text ends with a couple of newlines:
|
314 |
+
$text .= "\n\n";
|
315 |
+
|
316 |
+
# Convert all tabs to spaces.
|
317 |
+
$text = $this->detab($text);
|
318 |
+
|
319 |
+
# Turn block-level HTML blocks into hash entries
|
320 |
+
$text = $this->hashHTMLBlocks($text);
|
321 |
+
|
322 |
+
# Strip any lines consisting only of spaces and tabs.
|
323 |
+
# This makes subsequent regexen easier to write, because we can
|
324 |
+
# match consecutive blank lines with /\n+/ instead of something
|
325 |
+
# contorted like /[ ]*\n+/ .
|
326 |
+
$text = preg_replace('/^[ ]+$/m', '', $text);
|
327 |
+
|
328 |
+
# Run document gamut methods.
|
329 |
+
foreach ($this->document_gamut as $method => $priority) {
|
330 |
+
$text = $this->$method($text);
|
331 |
+
}
|
332 |
+
|
333 |
+
$this->teardown();
|
334 |
+
|
335 |
+
return $text . "\n";
|
336 |
+
}
|
337 |
+
|
338 |
+
var $document_gamut = array(
|
339 |
+
# Strip link definitions, store in hashes.
|
340 |
+
"stripLinkDefinitions" => 20,
|
341 |
+
|
342 |
+
"runBasicBlockGamut" => 30,
|
343 |
+
);
|
344 |
+
|
345 |
+
|
346 |
+
function stripLinkDefinitions($text) {
|
347 |
+
#
|
348 |
+
# Strips link definitions from text, stores the URLs and titles in
|
349 |
+
# hash references.
|
350 |
+
#
|
351 |
+
$less_than_tab = $this->tab_width - 1;
|
352 |
+
|
353 |
+
# Link defs are in the form: ^[id]: url "optional title"
|
354 |
+
$text = preg_replace_callback('{
|
355 |
+
^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
|
356 |
+
[ ]*
|
357 |
+
\n? # maybe *one* newline
|
358 |
+
[ ]*
|
359 |
+
(?:
|
360 |
+
<(.+?)> # url = $2
|
361 |
+
|
|
362 |
+
(\S+?) # url = $3
|
363 |
+
)
|
364 |
+
[ ]*
|
365 |
+
\n? # maybe one newline
|
366 |
+
[ ]*
|
367 |
+
(?:
|
368 |
+
(?<=\s) # lookbehind for whitespace
|
369 |
+
["(]
|
370 |
+
(.*?) # title = $4
|
371 |
+
[")]
|
372 |
+
[ ]*
|
373 |
+
)? # title is optional
|
374 |
+
(?:\n+|\Z)
|
375 |
+
}xm',
|
376 |
+
array(&$this, '_stripLinkDefinitions_callback'),
|
377 |
+
$text);
|
378 |
+
return $text;
|
379 |
+
}
|
380 |
+
function _stripLinkDefinitions_callback($matches) {
|
381 |
+
$link_id = strtolower($matches[1]);
|
382 |
+
$url = $matches[2] == '' ? $matches[3] : $matches[2];
|
383 |
+
$this->urls[$link_id] = $url;
|
384 |
+
$this->titles[$link_id] =& $matches[4];
|
385 |
+
return ''; # String that will replace the block
|
386 |
+
}
|
387 |
+
|
388 |
+
|
389 |
+
function hashHTMLBlocks($text) {
|
390 |
+
if ($this->no_markup) return $text;
|
391 |
+
|
392 |
+
$less_than_tab = $this->tab_width - 1;
|
393 |
+
|
394 |
+
# Hashify HTML blocks:
|
395 |
+
# We only want to do this for block-level HTML tags, such as headers,
|
396 |
+
# lists, and tables. That's because we still want to wrap <p>s around
|
397 |
+
# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
|
398 |
+
# phrase emphasis, and spans. The list of tags we're looking for is
|
399 |
+
# hard-coded:
|
400 |
+
#
|
401 |
+
# * List "a" is made of tags which can be both inline or block-level.
|
402 |
+
# These will be treated block-level when the start tag is alone on
|
403 |
+
# its line, otherwise they're not matched here and will be taken as
|
404 |
+
# inline later.
|
405 |
+
# * List "b" is made of tags which are always block-level;
|
406 |
+
#
|
407 |
+
$block_tags_a_re = 'ins|del';
|
408 |
+
$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
|
409 |
+
'script|noscript|form|fieldset|iframe|math';
|
410 |
+
|
411 |
+
# Regular expression for the content of a block tag.
|
412 |
+
$nested_tags_level = 4;
|
413 |
+
$attr = '
|
414 |
+
(?> # optional tag attributes
|
415 |
+
\s # starts with whitespace
|
416 |
+
(?>
|
417 |
+
[^>"/]+ # text outside quotes
|
418 |
+
|
|
419 |
+
/+(?!>) # slash not followed by ">"
|
420 |
+
|
|
421 |
+
"[^"]*" # text inside double quotes (tolerate ">")
|
422 |
+
|
|
423 |
+
\'[^\']*\' # text inside single quotes (tolerate ">")
|
424 |
+
)*
|
425 |
+
)?
|
426 |
+
';
|
427 |
+
$content =
|
428 |
+
str_repeat('
|
429 |
+
(?>
|
430 |
+
[^<]+ # content without tag
|
431 |
+
|
|
432 |
+
<\2 # nested opening tag
|
433 |
+
'.$attr.' # attributes
|
434 |
+
(?>
|
435 |
+
/>
|
436 |
+
|
|
437 |
+
>', $nested_tags_level). # end of opening tag
|
438 |
+
'.*?'. # last level nested tag content
|
439 |
+
str_repeat('
|
440 |
+
</\2\s*> # closing nested tag
|
441 |
+
)
|
442 |
+
|
|
443 |
+
<(?!/\2\s*> # other tags with a different name
|
444 |
+
)
|
445 |
+
)*',
|
446 |
+
$nested_tags_level);
|
447 |
+
$content2 = str_replace('\2', '\3', $content);
|
448 |
+
|
449 |
+
# First, look for nested blocks, e.g.:
|
450 |
+
# <div>
|
451 |
+
# <div>
|
452 |
+
# tags for inner block must be indented.
|
453 |
+
# </div>
|
454 |
+
# </div>
|
455 |
+
#
|
456 |
+
# The outermost tags must start at the left margin for this to match, and
|
457 |
+
# the inner nested divs must be indented.
|
458 |
+
# We need to do this before the next, more liberal match, because the next
|
459 |
+
# match will start at the first `<div>` and stop at the first `</div>`.
|
460 |
+
$text = preg_replace_callback('{(?>
|
461 |
+
(?>
|
462 |
+
(?<=\n\n) # Starting after a blank line
|
463 |
+
| # or
|
464 |
+
\A\n? # the beginning of the doc
|
465 |
+
)
|
466 |
+
( # save in $1
|
467 |
+
|
468 |
+
# Match from `\n<tag>` to `</tag>\n`, handling nested tags
|
469 |
+
# in between.
|
470 |
+
|
471 |
+
[ ]{0,'.$less_than_tab.'}
|
472 |
+
<('.$block_tags_b_re.')# start tag = $2
|
473 |
+
'.$attr.'> # attributes followed by > and \n
|
474 |
+
'.$content.' # content, support nesting
|
475 |
+
</\2> # the matching end tag
|
476 |
+
[ ]* # trailing spaces/tabs
|
477 |
+
(?=\n+|\Z) # followed by a newline or end of document
|
478 |
+
|
479 |
+
| # Special version for tags of group a.
|
480 |
+
|
481 |
+
[ ]{0,'.$less_than_tab.'}
|
482 |
+
<('.$block_tags_a_re.')# start tag = $3
|
483 |
+
'.$attr.'>[ ]*\n # attributes followed by >
|
484 |
+
'.$content2.' # content, support nesting
|
485 |
+
</\3> # the matching end tag
|
486 |
+
[ ]* # trailing spaces/tabs
|
487 |
+
(?=\n+|\Z) # followed by a newline or end of document
|
488 |
+
|
489 |
+
| # Special case just for <hr />. It was easier to make a special
|
490 |
+
# case than to make the other regex more complicated.
|
491 |
+
|
492 |
+
[ ]{0,'.$less_than_tab.'}
|
493 |
+
<(hr) # start tag = $2
|
494 |
+
'.$attr.' # attributes
|
495 |
+
/?> # the matching end tag
|
496 |
+
[ ]*
|
497 |
+
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
498 |
+
|
499 |
+
| # Special case for standalone HTML comments:
|
500 |
+
|
501 |
+
[ ]{0,'.$less_than_tab.'}
|
502 |
+
(?s:
|
503 |
+
<!-- .*? -->
|
504 |
+
)
|
505 |
+
[ ]*
|
506 |
+
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
507 |
+
|
508 |
+
| # PHP and ASP-style processor instructions (<? and <%)
|
509 |
+
|
510 |
+
[ ]{0,'.$less_than_tab.'}
|
511 |
+
(?s:
|
512 |
+
<([?%]) # $2
|
513 |
+
.*?
|
514 |
+
\2>
|
515 |
+
)
|
516 |
+
[ ]*
|
517 |
+
(?=\n{2,}|\Z) # followed by a blank line or end of document
|
518 |
+
|
519 |
+
)
|
520 |
+
)}Sxmi',
|
521 |
+
array(&$this, '_hashHTMLBlocks_callback'),
|
522 |
+
$text);
|
523 |
+
|
524 |
+
return $text;
|
525 |
+
}
|
526 |
+
function _hashHTMLBlocks_callback($matches) {
|
527 |
+
$text = $matches[1];
|
528 |
+
$key = $this->hashBlock($text);
|
529 |
+
return "\n\n$key\n\n";
|
530 |
+
}
|
531 |
+
|
532 |
+
|
533 |
+
function hashPart($text, $boundary = 'X') {
|
534 |
+
#
|
535 |
+
# Called whenever a tag must be hashed when a function insert an atomic
|
536 |
+
# element in the text stream. Passing $text to through this function gives
|
537 |
+
# a unique text-token which will be reverted back when calling unhash.
|
538 |
+
#
|
539 |
+
# The $boundary argument specify what character should be used to surround
|
540 |
+
# the token. By convension, "B" is used for block elements that needs not
|
541 |
+
# to be wrapped into paragraph tags at the end, ":" is used for elements
|
542 |
+
# that are word separators and "X" is used in the general case.
|
543 |
+
#
|
544 |
+
# Swap back any tag hash found in $text so we do not have to `unhash`
|
545 |
+
# multiple times at the end.
|
546 |
+
$text = $this->unhash($text);
|
547 |
+
|
548 |
+
# Then hash the block.
|
549 |
+
static $i = 0;
|
550 |
+
$key = "$boundary\x1A" . ++$i . $boundary;
|
551 |
+
$this->html_hashes[$key] = $text;
|
552 |
+
return $key; # String that will replace the tag.
|
553 |
+
}
|
554 |
+
|
555 |
+
|
556 |
+
function hashBlock($text) {
|
557 |
+
#
|
558 |
+
# Shortcut function for hashPart with block-level boundaries.
|
559 |
+
#
|
560 |
+
return $this->hashPart($text, 'B');
|
561 |
+
}
|
562 |
+
|
563 |
+
|
564 |
+
var $block_gamut = array(
|
565 |
+
#
|
566 |
+
# These are all the transformations that form block-level
|
567 |
+
# tags like paragraphs, headers, and list items.
|
568 |
+
#
|
569 |
+
"doHeaders" => 10,
|
570 |
+
"doHorizontalRules" => 20,
|
571 |
+
|
572 |
+
"doLists" => 40,
|
573 |
+
"doCodeBlocks" => 50,
|
574 |
+
"doBlockQuotes" => 60,
|
575 |
+
);
|
576 |
+
|
577 |
+
function runBlockGamut($text) {
|
578 |
+
#
|
579 |
+
# Run block gamut tranformations.
|
580 |
+
#
|
581 |
+
# We need to escape raw HTML in Markdown source before doing anything
|
582 |
+
# else. This need to be done for each block, and not only at the
|
583 |
+
# begining in the Markdown function since hashed blocks can be part of
|
584 |
+
# list items and could have been indented. Indented blocks would have
|
585 |
+
# been seen as a code block in a previous pass of hashHTMLBlocks.
|
586 |
+
$text = $this->hashHTMLBlocks($text);
|
587 |
+
|
588 |
+
return $this->runBasicBlockGamut($text);
|
589 |
+
}
|
590 |
+
|
591 |
+
function runBasicBlockGamut($text) {
|
592 |
+
#
|
593 |
+
# Run block gamut tranformations, without hashing HTML blocks. This is
|
594 |
+
# useful when HTML blocks are known to be already hashed, like in the first
|
595 |
+
# whole-document pass.
|
596 |
+
#
|
597 |
+
foreach ($this->block_gamut as $method => $priority) {
|
598 |
+
$text = $this->$method($text);
|
599 |
+
}
|
600 |
+
|
601 |
+
# Finally form paragraph and restore hashed blocks.
|
602 |
+
$text = $this->formParagraphs($text);
|
603 |
+
|
604 |
+
return $text;
|
605 |
+
}
|
606 |
+
|
607 |
+
|
608 |
+
function doHorizontalRules($text) {
|
609 |
+
# Do Horizontal Rules:
|
610 |
+
return preg_replace(
|
611 |
+
'{
|
612 |
+
^[ ]{0,3} # Leading space
|
613 |
+
([-*_]) # $1: First marker
|
614 |
+
(?> # Repeated marker group
|
615 |
+
[ ]{0,2} # Zero, one, or two spaces.
|
616 |
+
\1 # Marker character
|
617 |
+
){2,} # Group repeated at least twice
|
618 |
+
[ ]* # Tailing spaces
|
619 |
+
$ # End of line.
|
620 |
+
}mx',
|
621 |
+
"\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
|
622 |
+
$text);
|
623 |
+
}
|
624 |
+
|
625 |
+
|
626 |
+
var $span_gamut = array(
|
627 |
+
#
|
628 |
+
# These are all the transformations that occur *within* block-level
|
629 |
+
# tags like paragraphs, headers, and list items.
|
630 |
+
#
|
631 |
+
# Process character escapes, code spans, and inline HTML
|
632 |
+
# in one shot.
|
633 |
+
"parseSpan" => -30,
|
634 |
+
|
635 |
+
# Process anchor and image tags. Images must come first,
|
636 |
+
# because ![foo][f] looks like an anchor.
|
637 |
+
"doImages" => 10,
|
638 |
+
"doAnchors" => 20,
|
639 |
+
|
640 |
+
# Make links out of things like `<http://example.com/>`
|
641 |
+
# Must come after doAnchors, because you can use < and >
|
642 |
+
# delimiters in inline links like [this](<url>).
|
643 |
+
"doAutoLinks" => 30,
|
644 |
+
"encodeAmpsAndAngles" => 40,
|
645 |
+
|
646 |
+
"doItalicsAndBold" => 50,
|
647 |
+
"doHardBreaks" => 60,
|
648 |
+
);
|
649 |
+
|
650 |
+
function runSpanGamut($text) {
|
651 |
+
#
|
652 |
+
# Run span gamut tranformations.
|
653 |
+
#
|
654 |
+
foreach ($this->span_gamut as $method => $priority) {
|
655 |
+
$text = $this->$method($text);
|
656 |
+
}
|
657 |
+
|
658 |
+
return $text;
|
659 |
+
}
|
660 |
+
|
661 |
+
|
662 |
+
function doHardBreaks($text) {
|
663 |
+
# Do hard breaks:
|
664 |
+
return preg_replace_callback('/ {2,}\n/',
|
665 |
+
array(&$this, '_doHardBreaks_callback'), $text);
|
666 |
+
}
|
667 |
+
function _doHardBreaks_callback($matches) {
|
668 |
+
return $this->hashPart("<br$this->empty_element_suffix\n");
|
669 |
+
}
|
670 |
+
|
671 |
+
|
672 |
+
function doAnchors($text) {
|
673 |
+
#
|
674 |
+
# Turn Markdown link shortcuts into XHTML <a> tags.
|
675 |
+
#
|
676 |
+
if ($this->in_anchor) return $text;
|
677 |
+
$this->in_anchor = true;
|
678 |
+
|
679 |
+
#
|
680 |
+
# First, handle reference-style links: [link text] [id]
|
681 |
+
#
|
682 |
+
$text = preg_replace_callback('{
|
683 |
+
( # wrap whole match in $1
|
684 |
+
\[
|
685 |
+
('.$this->nested_brackets_re.') # link text = $2
|
686 |
+
\]
|
687 |
+
|
688 |
+
[ ]? # one optional space
|
689 |
+
(?:\n[ ]*)? # one optional newline followed by spaces
|
690 |
+
|
691 |
+
\[
|
692 |
+
(.*?) # id = $3
|
693 |
+
\]
|
694 |
+
)
|
695 |
+
}xs',
|
696 |
+
array(&$this, '_doAnchors_reference_callback'), $text);
|
697 |
+
|
698 |
+
#
|
699 |
+
# Next, inline-style links: [link text](url "optional title")
|
700 |
+
#
|
701 |
+
$text = preg_replace_callback('{
|
702 |
+
( # wrap whole match in $1
|
703 |
+
\[
|
704 |
+
('.$this->nested_brackets_re.') # link text = $2
|
705 |
+
\]
|
706 |
+
\( # literal paren
|
707 |
+
[ \n]*
|
708 |
+
(?:
|
709 |
+
<(.+?)> # href = $3
|
710 |
+
|
|
711 |
+
('.$this->nested_url_parenthesis_re.') # href = $4
|
712 |
+
)
|
713 |
+
[ \n]*
|
714 |
+
( # $5
|
715 |
+
([\'"]) # quote char = $6
|
716 |
+
(.*?) # Title = $7
|
717 |
+
\6 # matching quote
|
718 |
+
[ \n]* # ignore any spaces/tabs between closing quote and )
|
719 |
+
)? # title is optional
|
720 |
+
\)
|
721 |
+
)
|
722 |
+
}xs',
|
723 |
+
array(&$this, '_doAnchors_inline_callback'), $text);
|
724 |
+
|
725 |
+
#
|
726 |
+
# Last, handle reference-style shortcuts: [link text]
|
727 |
+
# These must come last in case you've also got [link text][1]
|
728 |
+
# or [link text](/foo)
|
729 |
+
#
|
730 |
+
$text = preg_replace_callback('{
|
731 |
+
( # wrap whole match in $1
|
732 |
+
\[
|
733 |
+
([^\[\]]+) # link text = $2; can\'t contain [ or ]
|
734 |
+
\]
|
735 |
+
)
|
736 |
+
}xs',
|
737 |
+
array(&$this, '_doAnchors_reference_callback'), $text);
|
738 |
+
|
739 |
+
$this->in_anchor = false;
|
740 |
+
return $text;
|
741 |
+
}
|
742 |
+
function _doAnchors_reference_callback($matches) {
|
743 |
+
$whole_match = $matches[1];
|
744 |
+
$link_text = $matches[2];
|
745 |
+
$link_id =& $matches[3];
|
746 |
+
|
747 |
+
if ($link_id == "") {
|
748 |
+
# for shortcut links like [this][] or [this].
|
749 |
+
$link_id = $link_text;
|
750 |
+
}
|
751 |
+
|
752 |
+
# lower-case and turn embedded newlines into spaces
|
753 |
+
$link_id = strtolower($link_id);
|
754 |
+
$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
|
755 |
+
|
756 |
+
if (isset($this->urls[$link_id])) {
|
757 |
+
$url = $this->urls[$link_id];
|
758 |
+
$url = $this->encodeAttribute($url);
|
759 |
+
|
760 |
+
$result = "<a href=\"$url\"";
|
761 |
+
if ( isset( $this->titles[$link_id] ) ) {
|
762 |
+
$title = $this->titles[$link_id];
|
763 |
+
$title = $this->encodeAttribute($title);
|
764 |
+
$result .= " title=\"$title\"";
|
765 |
+
}
|
766 |
+
|
767 |
+
$link_text = $this->runSpanGamut($link_text);
|
768 |
+
$result .= ">$link_text</a>";
|
769 |
+
$result = $this->hashPart($result);
|
770 |
+
}
|
771 |
+
else {
|
772 |
+
$result = $whole_match;
|
773 |
+
}
|
774 |
+
return $result;
|
775 |
+
}
|
776 |
+
function _doAnchors_inline_callback($matches) {
|
777 |
+
$whole_match = $matches[1];
|
778 |
+
$link_text = $this->runSpanGamut($matches[2]);
|
779 |
+
$url = $matches[3] == '' ? $matches[4] : $matches[3];
|
780 |
+
$title =& $matches[7];
|
781 |
+
|
782 |
+
$url = $this->encodeAttribute($url);
|
783 |
+
|
784 |
+
$result = "<a href=\"$url\"";
|
785 |
+
if (isset($title)) {
|
786 |
+
$title = $this->encodeAttribute($title);
|
787 |
+
$result .= " title=\"$title\"";
|
788 |
+
}
|
789 |
+
|
790 |
+
$link_text = $this->runSpanGamut($link_text);
|
791 |
+
$result .= ">$link_text</a>";
|
792 |
+
|
793 |
+
return $this->hashPart($result);
|
794 |
+
}
|
795 |
+
|
796 |
+
|
797 |
+
function doImages($text) {
|
798 |
+
#
|
799 |
+
# Turn Markdown image shortcuts into <img> tags.
|
800 |
+
#
|
801 |
+
#
|
802 |
+
# First, handle reference-style labeled images: ![alt text][id]
|
803 |
+
#
|
804 |
+
$text = preg_replace_callback('{
|
805 |
+
( # wrap whole match in $1
|
806 |
+
!\[
|
807 |
+
('.$this->nested_brackets_re.') # alt text = $2
|
808 |
+
\]
|
809 |
+
|
810 |
+
[ ]? # one optional space
|
811 |
+
(?:\n[ ]*)? # one optional newline followed by spaces
|
812 |
+
|
813 |
+
\[
|
814 |
+
(.*?) # id = $3
|
815 |
+
\]
|
816 |
+
|
817 |
+
)
|
818 |
+
}xs',
|
819 |
+
array(&$this, '_doImages_reference_callback'), $text);
|
820 |
+
|
821 |
+
#
|
822 |
+
# Next, handle inline images: ![alt text](url "optional title")
|
823 |
+
# Don't forget: encode * and _
|
824 |
+
#
|
825 |
+
$text = preg_replace_callback('{
|
826 |
+
( # wrap whole match in $1
|
827 |
+
!\[
|
828 |
+
('.$this->nested_brackets_re.') # alt text = $2
|
829 |
+
\]
|
830 |
+
\s? # One optional whitespace character
|
831 |
+
\( # literal paren
|
832 |
+
[ \n]*
|
833 |
+
(?:
|
834 |
+
<(\S*)> # src url = $3
|
835 |
+
|
|
836 |
+
('.$this->nested_url_parenthesis_re.') # src url = $4
|
837 |
+
)
|
838 |
+
[ \n]*
|
839 |
+
( # $5
|
840 |
+
([\'"]) # quote char = $6
|
841 |
+
(.*?) # title = $7
|
842 |
+
\6 # matching quote
|
843 |
+
[ \n]*
|
844 |
+
)? # title is optional
|
845 |
+
\)
|
846 |
+
)
|
847 |
+
}xs',
|
848 |
+
array(&$this, '_doImages_inline_callback'), $text);
|
849 |
+
|
850 |
+
return $text;
|
851 |
+
}
|
852 |
+
function _doImages_reference_callback($matches) {
|
853 |
+
$whole_match = $matches[1];
|
854 |
+
$alt_text = $matches[2];
|
855 |
+
$link_id = strtolower($matches[3]);
|
856 |
+
|
857 |
+
if ($link_id == "") {
|
858 |
+
$link_id = strtolower($alt_text); # for shortcut links like ![this][].
|
859 |
+
}
|
860 |
+
|
861 |
+
$alt_text = $this->encodeAttribute($alt_text);
|
862 |
+
if (isset($this->urls[$link_id])) {
|
863 |
+
$url = $this->encodeAttribute($this->urls[$link_id]);
|
864 |
+
$result = "<img src=\"$url\" alt=\"$alt_text\"";
|
865 |
+
if (isset($this->titles[$link_id])) {
|
866 |
+
$title = $this->titles[$link_id];
|
867 |
+
$title = $this->encodeAttribute($title);
|
868 |
+
$result .= " title=\"$title\"";
|
869 |
+
}
|
870 |
+
$result .= $this->empty_element_suffix;
|
871 |
+
$result = $this->hashPart($result);
|
872 |
+
}
|
873 |
+
else {
|
874 |
+
# If there's no such link ID, leave intact:
|
875 |
+
$result = $whole_match;
|
876 |
+
}
|
877 |
+
|
878 |
+
return $result;
|
879 |
+
}
|
880 |
+
function _doImages_inline_callback($matches) {
|
881 |
+
$whole_match = $matches[1];
|
882 |
+
$alt_text = $matches[2];
|
883 |
+
$url = $matches[3] == '' ? $matches[4] : $matches[3];
|
884 |
+
$title =& $matches[7];
|
885 |
+
|
886 |
+
$alt_text = $this->encodeAttribute($alt_text);
|
887 |
+
$url = $this->encodeAttribute($url);
|
888 |
+
$result = "<img src=\"$url\" alt=\"$alt_text\"";
|
889 |
+
if (isset($title)) {
|
890 |
+
$title = $this->encodeAttribute($title);
|
891 |
+
$result .= " title=\"$title\""; # $title already quoted
|
892 |
+
}
|
893 |
+
$result .= $this->empty_element_suffix;
|
894 |
+
|
895 |
+
return $this->hashPart($result);
|
896 |
+
}
|
897 |
+
|
898 |
+
|
899 |
+
function doHeaders($text) {
|
900 |
+
# Setext-style headers:
|
901 |
+
# Header 1
|
902 |
+
# ========
|
903 |
+
#
|
904 |
+
# Header 2
|
905 |
+
# --------
|
906 |
+
#
|
907 |
+
$text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
|
908 |
+
array(&$this, '_doHeaders_callback_setext'), $text);
|
909 |
+
|
910 |
+
# atx-style headers:
|
911 |
+
# # Header 1
|
912 |
+
# ## Header 2
|
913 |
+
# ## Header 2 with closing hashes ##
|
914 |
+
# ...
|
915 |
+
# ###### Header 6
|
916 |
+
#
|
917 |
+
$text = preg_replace_callback('{
|
918 |
+
^(\#{1,6}) # $1 = string of #\'s
|
919 |
+
[ ]*
|
920 |
+
(.+?) # $2 = Header text
|
921 |
+
[ ]*
|
922 |
+
\#* # optional closing #\'s (not counted)
|
923 |
+
\n+
|
924 |
+
}xm',
|
925 |
+
array(&$this, '_doHeaders_callback_atx'), $text);
|
926 |
+
|
927 |
+
return $text;
|
928 |
+
}
|
929 |
+
function _doHeaders_callback_setext($matches) {
|
930 |
+
# Terrible hack to check we haven't found an empty list item.
|
931 |
+
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
|
932 |
+
return $matches[0];
|
933 |
+
|
934 |
+
$level = $matches[2]{0} == '=' ? 1 : 2;
|
935 |
+
$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
|
936 |
+
return "\n" . $this->hashBlock($block) . "\n\n";
|
937 |
+
}
|
938 |
+
function _doHeaders_callback_atx($matches) {
|
939 |
+
$level = strlen($matches[1]);
|
940 |
+
$block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
|
941 |
+
return "\n" . $this->hashBlock($block) . "\n\n";
|
942 |
+
}
|
943 |
+
|
944 |
+
|
945 |
+
function doLists($text) {
|
946 |
+
#
|
947 |
+
# Form HTML ordered (numbered) and unordered (bulleted) lists.
|
948 |
+
#
|
949 |
+
$less_than_tab = $this->tab_width - 1;
|
950 |
+
|
951 |
+
# Re-usable patterns to match list item bullets and number markers:
|
952 |
+
$marker_ul_re = '[*+-]';
|
953 |
+
$marker_ol_re = '\d+[.]';
|
954 |
+
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
|
955 |
+
|
956 |
+
$markers_relist = array(
|
957 |
+
$marker_ul_re => $marker_ol_re,
|
958 |
+
$marker_ol_re => $marker_ul_re,
|
959 |
+
);
|
960 |
+
|
961 |
+
foreach ($markers_relist as $marker_re => $other_marker_re) {
|
962 |
+
# Re-usable pattern to match any entirel ul or ol list:
|
963 |
+
$whole_list_re = '
|
964 |
+
( # $1 = whole list
|
965 |
+
( # $2
|
966 |
+
([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
|
967 |
+
('.$marker_re.') # $4 = first list item marker
|
968 |
+
[ ]+
|
969 |
+
)
|
970 |
+
(?s:.+?)
|
971 |
+
( # $5
|
972 |
+
\z
|
973 |
+
|
|
974 |
+
\n{2,}
|
975 |
+
(?=\S)
|
976 |
+
(?! # Negative lookahead for another list item marker
|
977 |
+
[ ]*
|
978 |
+
'.$marker_re.'[ ]+
|
979 |
+
)
|
980 |
+
|
|
981 |
+
(?= # Lookahead for another kind of list
|
982 |
+
\n
|
983 |
+
\3 # Must have the same indentation
|
984 |
+
'.$other_marker_re.'[ ]+
|
985 |
+
)
|
986 |
+
)
|
987 |
+
)
|
988 |
+
'; // mx
|
989 |
+
|
990 |
+
# We use a different prefix before nested lists than top-level lists.
|
991 |
+
# See extended comment in _ProcessListItems().
|
992 |
+
|
993 |
+
if ($this->list_level) {
|
994 |
+
$text = preg_replace_callback('{
|
995 |
+
^
|
996 |
+
'.$whole_list_re.'
|
997 |
+
}mx',
|
998 |
+
array(&$this, '_doLists_callback'), $text);
|
999 |
+
}
|
1000 |
+
else {
|
1001 |
+
$text = preg_replace_callback('{
|
1002 |
+
(?:(?<=\n)\n|\A\n?) # Must eat the newline
|
1003 |
+
'.$whole_list_re.'
|
1004 |
+
}mx',
|
1005 |
+
array(&$this, '_doLists_callback'), $text);
|
1006 |
+
}
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
return $text;
|
1010 |
+
}
|
1011 |
+
function _doLists_callback($matches) {
|
1012 |
+
# Re-usable patterns to match list item bullets and number markers:
|
1013 |
+
$marker_ul_re = '[*+-]';
|
1014 |
+
$marker_ol_re = '\d+[.]';
|
1015 |
+
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
|
1016 |
+
|
1017 |
+
$list = $matches[1];
|
1018 |
+
$list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
|
1019 |
+
|
1020 |
+
$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
|
1021 |
+
|
1022 |
+
$list .= "\n";
|
1023 |
+
$result = $this->processListItems($list, $marker_any_re);
|
1024 |
+
|
1025 |
+
$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
|
1026 |
+
return "\n". $result ."\n\n";
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
var $list_level = 0;
|
1030 |
+
|
1031 |
+
function processListItems($list_str, $marker_any_re) {
|
1032 |
+
#
|
1033 |
+
# Process the contents of a single ordered or unordered list, splitting it
|
1034 |
+
# into individual list items.
|
1035 |
+
#
|
1036 |
+
# The $this->list_level global keeps track of when we're inside a list.
|
1037 |
+
# Each time we enter a list, we increment it; when we leave a list,
|
1038 |
+
# we decrement. If it's zero, we're not in a list anymore.
|
1039 |
+
#
|
1040 |
+
# We do this because when we're not inside a list, we want to treat
|
1041 |
+
# something like this:
|
1042 |
+
#
|
1043 |
+
# I recommend upgrading to version
|
1044 |
+
# 8. Oops, now this line is treated
|
1045 |
+
# as a sub-list.
|
1046 |
+
#
|
1047 |
+
# As a single paragraph, despite the fact that the second line starts
|
1048 |
+
# with a digit-period-space sequence.
|
1049 |
+
#
|
1050 |
+
# Whereas when we're inside a list (or sub-list), that line will be
|
1051 |
+
# treated as the start of a sub-list. What a kludge, huh? This is
|
1052 |
+
# an aspect of Markdown's syntax that's hard to parse perfectly
|
1053 |
+
# without resorting to mind-reading. Perhaps the solution is to
|
1054 |
+
# change the syntax rules such that sub-lists must start with a
|
1055 |
+
# starting cardinal number; e.g. "1." or "a.".
|
1056 |
+
|
1057 |
+
$this->list_level++;
|
1058 |
+
|
1059 |
+
# trim trailing blank lines:
|
1060 |
+
$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
|
1061 |
+
|
1062 |
+
$list_str = preg_replace_callback('{
|
1063 |
+
(\n)? # leading line = $1
|
1064 |
+
(^[ ]*) # leading whitespace = $2
|
1065 |
+
('.$marker_any_re.' # list marker and space = $3
|
1066 |
+
(?:[ ]+|(?=\n)) # space only required if item is not empty
|
1067 |
+
)
|
1068 |
+
((?s:.*?)) # list item text = $4
|
1069 |
+
(?:(\n+(?=\n))|\n) # tailing blank line = $5
|
1070 |
+
(?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
|
1071 |
+
}xm',
|
1072 |
+
array(&$this, '_processListItems_callback'), $list_str);
|
1073 |
+
|
1074 |
+
$this->list_level--;
|
1075 |
+
return $list_str;
|
1076 |
+
}
|
1077 |
+
function _processListItems_callback($matches) {
|
1078 |
+
$item = $matches[4];
|
1079 |
+
$leading_line =& $matches[1];
|
1080 |
+
$leading_space =& $matches[2];
|
1081 |
+
$marker_space = $matches[3];
|
1082 |
+
$tailing_blank_line =& $matches[5];
|
1083 |
+
|
1084 |
+
if ($leading_line || $tailing_blank_line ||
|
1085 |
+
preg_match('/\n{2,}/', $item))
|
1086 |
+
{
|
1087 |
+
# Replace marker with the appropriate whitespace indentation
|
1088 |
+
$item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
|
1089 |
+
$item = $this->runBlockGamut($this->outdent($item)."\n");
|
1090 |
+
}
|
1091 |
+
else {
|
1092 |
+
# Recursion for sub-lists:
|
1093 |
+
$item = $this->doLists($this->outdent($item));
|
1094 |
+
$item = preg_replace('/\n+$/', '', $item);
|
1095 |
+
$item = $this->runSpanGamut($item);
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
return "<li>" . $item . "</li>\n";
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
|
1102 |
+
function doCodeBlocks($text) {
|
1103 |
+
#
|
1104 |
+
# Process Markdown `<pre><code>` blocks.
|
1105 |
+
#
|
1106 |
+
$text = preg_replace_callback('{
|
1107 |
+
(?:\n\n|\A\n?)
|
1108 |
+
( # $1 = the code block -- one or more lines, starting with a space/tab
|
1109 |
+
(?>
|
1110 |
+
[ ]{'.$this->tab_width.'} # Lines must start with a tab or a tab-width of spaces
|
1111 |
+
.*\n+
|
1112 |
+
)+
|
1113 |
+
)
|
1114 |
+
((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
|
1115 |
+
}xm',
|
1116 |
+
array(&$this, '_doCodeBlocks_callback'), $text);
|
1117 |
+
|
1118 |
+
return $text;
|
1119 |
+
}
|
1120 |
+
function _doCodeBlocks_callback($matches) {
|
1121 |
+
$codeblock = $matches[1];
|
1122 |
+
|
1123 |
+
$codeblock = $this->outdent($codeblock);
|
1124 |
+
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
|
1125 |
+
|
1126 |
+
# trim leading newlines and trailing newlines
|
1127 |
+
$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
|
1128 |
+
|
1129 |
+
$codeblock = "<pre><code>$codeblock\n</code></pre>";
|
1130 |
+
return "\n\n".$this->hashBlock($codeblock)."\n\n";
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
|
1134 |
+
function makeCodeSpan($code) {
|
1135 |
+
#
|
1136 |
+
# Create a code span markup for $code. Called from handleSpanToken.
|
1137 |
+
#
|
1138 |
+
$code = htmlspecialchars(trim($code), ENT_NOQUOTES);
|
1139 |
+
return $this->hashPart("<code>$code</code>");
|
1140 |
+
}
|
1141 |
+
|
1142 |
+
|
1143 |
+
var $em_relist = array(
|
1144 |
+
'' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![.,:;]\s)',
|
1145 |
+
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
|
1146 |
+
'_' => '(?<=\S|^)(?<!_)_(?!_)',
|
1147 |
+
);
|
1148 |
+
var $strong_relist = array(
|
1149 |
+
'' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
|
1150 |
+
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
|
1151 |
+
'__' => '(?<=\S|^)(?<!_)__(?!_)',
|
1152 |
+
);
|
1153 |
+
var $em_strong_relist = array(
|
1154 |
+
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
|
1155 |
+
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
|
1156 |
+
'___' => '(?<=\S|^)(?<!_)___(?!_)',
|
1157 |
+
);
|
1158 |
+
var $em_strong_prepared_relist;
|
1159 |
+
|
1160 |
+
function prepareItalicsAndBold() {
|
1161 |
+
#
|
1162 |
+
# Prepare regular expressions for searching emphasis tokens in any
|
1163 |
+
# context.
|
1164 |
+
#
|
1165 |
+
foreach ($this->em_relist as $em => $em_re) {
|
1166 |
+
foreach ($this->strong_relist as $strong => $strong_re) {
|
1167 |
+
# Construct list of allowed token expressions.
|
1168 |
+
$token_relist = array();
|
1169 |
+
if (isset($this->em_strong_relist["$em$strong"])) {
|
1170 |
+
$token_relist[] = $this->em_strong_relist["$em$strong"];
|
1171 |
+
}
|
1172 |
+
$token_relist[] = $em_re;
|
1173 |
+
$token_relist[] = $strong_re;
|
1174 |
+
|
1175 |
+
# Construct master expression from list.
|
1176 |
+
$token_re = '{('. implode('|', $token_relist) .')}';
|
1177 |
+
$this->em_strong_prepared_relist["$em$strong"] = $token_re;
|
1178 |
+
}
|
1179 |
+
}
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
function doItalicsAndBold($text) {
|
1183 |
+
$token_stack = array('');
|
1184 |
+
$text_stack = array('');
|
1185 |
+
$em = '';
|
1186 |
+
$strong = '';
|
1187 |
+
$tree_char_em = false;
|
1188 |
+
|
1189 |
+
while (1) {
|
1190 |
+
#
|
1191 |
+
# Get prepared regular expression for seraching emphasis tokens
|
1192 |
+
# in current context.
|
1193 |
+
#
|
1194 |
+
$token_re = $this->em_strong_prepared_relist["$em$strong"];
|
1195 |
+
|
1196 |
+
#
|
1197 |
+
# Each loop iteration search for the next emphasis token.
|
1198 |
+
# Each token is then passed to handleSpanToken.
|
1199 |
+
#
|
1200 |
+
$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
|
1201 |
+
$text_stack[0] .= $parts[0];
|
1202 |
+
$token =& $parts[1];
|
1203 |
+
$text =& $parts[2];
|
1204 |
+
|
1205 |
+
if (empty($token)) {
|
1206 |
+
# Reached end of text span: empty stack without emitting.
|
1207 |
+
# any more emphasis.
|
1208 |
+
while ($token_stack[0]) {
|
1209 |
+
$text_stack[1] .= array_shift($token_stack);
|
1210 |
+
$text_stack[0] .= array_shift($text_stack);
|
1211 |
+
}
|
1212 |
+
break;
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
$token_len = strlen($token);
|
1216 |
+
if ($tree_char_em) {
|
1217 |
+
# Reached closing marker while inside a three-char emphasis.
|
1218 |
+
if ($token_len == 3) {
|
1219 |
+
# Three-char closing marker, close em and strong.
|
1220 |
+
array_shift($token_stack);
|
1221 |
+
$span = array_shift($text_stack);
|
1222 |
+
$span = $this->runSpanGamut($span);
|
1223 |
+
$span = "<strong><em>$span</em></strong>";
|
1224 |
+
$text_stack[0] .= $this->hashPart($span);
|
1225 |
+
$em = '';
|
1226 |
+
$strong = '';
|
1227 |
+
} else {
|
1228 |
+
# Other closing marker: close one em or strong and
|
1229 |
+
# change current token state to match the other
|
1230 |
+
$token_stack[0] = str_repeat($token{0}, 3-$token_len);
|
1231 |
+
$tag = $token_len == 2 ? "strong" : "em";
|
1232 |
+
$span = $text_stack[0];
|
1233 |
+
$span = $this->runSpanGamut($span);
|
1234 |
+
$span = "<$tag>$span</$tag>";
|
1235 |
+
$text_stack[0] = $this->hashPart($span);
|
1236 |
+
$$tag = ''; # $$tag stands for $em or $strong
|
1237 |
+
}
|
1238 |
+
$tree_char_em = false;
|
1239 |
+
} else if ($token_len == 3) {
|
1240 |
+
if ($em) {
|
1241 |
+
# Reached closing marker for both em and strong.
|
1242 |
+
# Closing strong marker:
|
1243 |
+
for ($i = 0; $i < 2; ++$i) {
|
1244 |
+
$shifted_token = array_shift($token_stack);
|
1245 |
+
$tag = strlen($shifted_token) == 2 ? "strong" : "em";
|
1246 |
+
$span = array_shift($text_stack);
|
1247 |
+
$span = $this->runSpanGamut($span);
|
1248 |
+
$span = "<$tag>$span</$tag>";
|
1249 |
+
$text_stack[0] .= $this->hashPart($span);
|
1250 |
+
$$tag = ''; # $$tag stands for $em or $strong
|
1251 |
+
}
|
1252 |
+
} else {
|
1253 |
+
# Reached opening three-char emphasis marker. Push on token
|
1254 |
+
# stack; will be handled by the special condition above.
|
1255 |
+
$em = $token{0};
|
1256 |
+
$strong = "$em$em";
|
1257 |
+
array_unshift($token_stack, $token);
|
1258 |
+
array_unshift($text_stack, '');
|
1259 |
+
$tree_char_em = true;
|
1260 |
+
}
|
1261 |
+
} else if ($token_len == 2) {
|
1262 |
+
if ($strong) {
|
1263 |
+
# Unwind any dangling emphasis marker:
|
1264 |
+
if (strlen($token_stack[0]) == 1) {
|
1265 |
+
$text_stack[1] .= array_shift($token_stack);
|
1266 |
+
$text_stack[0] .= array_shift($text_stack);
|
1267 |
+
}
|
1268 |
+
# Closing strong marker:
|
1269 |
+
array_shift($token_stack);
|
1270 |
+
$span = array_shift($text_stack);
|
1271 |
+
$span = $this->runSpanGamut($span);
|
1272 |
+
$span = "<strong>$span</strong>";
|
1273 |
+
$text_stack[0] .= $this->hashPart($span);
|
1274 |
+
$strong = '';
|
1275 |
+
} else {
|
1276 |
+
array_unshift($token_stack, $token);
|
1277 |
+
array_unshift($text_stack, '');
|
1278 |
+
$strong = $token;
|
1279 |
+
}
|
1280 |
+
} else {
|
1281 |
+
# Here $token_len == 1
|
1282 |
+
if ($em) {
|
1283 |
+
if (strlen($token_stack[0]) == 1) {
|
1284 |
+
# Closing emphasis marker:
|
1285 |
+
array_shift($token_stack);
|
1286 |
+
$span = array_shift($text_stack);
|
1287 |
+
$span = $this->runSpanGamut($span);
|
1288 |
+
$span = "<em>$span</em>";
|
1289 |
+
$text_stack[0] .= $this->hashPart($span);
|
1290 |
+
$em = '';
|
1291 |
+
} else {
|
1292 |
+
$text_stack[0] .= $token;
|
1293 |
+
}
|
1294 |
+
} else {
|
1295 |
+
array_unshift($token_stack, $token);
|
1296 |
+
array_unshift($text_stack, '');
|
1297 |
+
$em = $token;
|
1298 |
+
}
|
1299 |
+
}
|
1300 |
+
}
|
1301 |
+
return $text_stack[0];
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
|
1305 |
+
function doBlockQuotes($text) {
|
1306 |
+
$text = preg_replace_callback('/
|
1307 |
+
( # Wrap whole match in $1
|
1308 |
+
(?>
|
1309 |
+
^[ ]*>[ ]? # ">" at the start of a line
|
1310 |
+
.+\n # rest of the first line
|
1311 |
+
(.+\n)* # subsequent consecutive lines
|
1312 |
+
\n* # blanks
|
1313 |
+
)+
|
1314 |
+
)
|
1315 |
+
/xm',
|
1316 |
+
array(&$this, '_doBlockQuotes_callback'), $text);
|
1317 |
+
|
1318 |
+
return $text;
|
1319 |
+
}
|
1320 |
+
function _doBlockQuotes_callback($matches) {
|
1321 |
+
$bq = $matches[1];
|
1322 |
+
# trim one level of quoting - trim whitespace-only lines
|
1323 |
+
$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
|
1324 |
+
$bq = $this->runBlockGamut($bq); # recurse
|
1325 |
+
|
1326 |
+
$bq = preg_replace('/^/m', " ", $bq);
|
1327 |
+
# These leading spaces cause problem with <pre> content,
|
1328 |
+
# so we need to fix that:
|
1329 |
+
$bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
|
1330 |
+
array(&$this, '_doBlockQuotes_callback2'), $bq);
|
1331 |
+
|
1332 |
+
return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
|
1333 |
+
}
|
1334 |
+
function _doBlockQuotes_callback2($matches) {
|
1335 |
+
$pre = $matches[1];
|
1336 |
+
$pre = preg_replace('/^ /m', '', $pre);
|
1337 |
+
return $pre;
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
|
1341 |
+
function formParagraphs($text) {
|
1342 |
+
#
|
1343 |
+
# Params:
|
1344 |
+
# $text - string to process with html <p> tags
|
1345 |
+
#
|
1346 |
+
# Strip leading and trailing lines:
|
1347 |
+
$text = preg_replace('/\A\n+|\n+\z/', '', $text);
|
1348 |
+
|
1349 |
+
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
|
1350 |
+
|
1351 |
+
#
|
1352 |
+
# Wrap <p> tags and unhashify HTML blocks
|
1353 |
+
#
|
1354 |
+
foreach ($grafs as $key => $value) {
|
1355 |
+
if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
|
1356 |
+
# Is a paragraph.
|
1357 |
+
$value = $this->runSpanGamut($value);
|
1358 |
+
$value = preg_replace('/^([ ]*)/', "<p>", $value);
|
1359 |
+
$value .= "</p>";
|
1360 |
+
$grafs[$key] = $this->unhash($value);
|
1361 |
+
}
|
1362 |
+
else {
|
1363 |
+
# Is a block.
|
1364 |
+
# Modify elements of @grafs in-place...
|
1365 |
+
$graf = $value;
|
1366 |
+
$block = $this->html_hashes[$graf];
|
1367 |
+
$graf = $block;
|
1368 |
+
// if (preg_match('{
|
1369 |
+
// \A
|
1370 |
+
// ( # $1 = <div> tag
|
1371 |
+
// <div \s+
|
1372 |
+
// [^>]*
|
1373 |
+
// \b
|
1374 |
+
// markdown\s*=\s* ([\'"]) # $2 = attr quote char
|
1375 |
+
// 1
|
1376 |
+
// \2
|
1377 |
+
// [^>]*
|
1378 |
+
// >
|
1379 |
+
// )
|
1380 |
+
// ( # $3 = contents
|
1381 |
+
// .*
|
1382 |
+
// )
|
1383 |
+
// (</div>) # $4 = closing tag
|
1384 |
+
// \z
|
1385 |
+
// }xs', $block, $matches))
|
1386 |
+
// {
|
1387 |
+
// list(, $div_open, , $div_content, $div_close) = $matches;
|
1388 |
+
//
|
1389 |
+
// # We can't call Markdown(), because that resets the hash;
|
1390 |
+
// # that initialization code should be pulled into its own sub, though.
|
1391 |
+
// $div_content = $this->hashHTMLBlocks($div_content);
|
1392 |
+
//
|
1393 |
+
// # Run document gamut methods on the content.
|
1394 |
+
// foreach ($this->document_gamut as $method => $priority) {
|
1395 |
+
// $div_content = $this->$method($div_content);
|
1396 |
+
// }
|
1397 |
+
//
|
1398 |
+
// $div_open = preg_replace(
|
1399 |
+
// '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
|
1400 |
+
//
|
1401 |
+
// $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
|
1402 |
+
// }
|
1403 |
+
$grafs[$key] = $graf;
|
1404 |
+
}
|
1405 |
+
}
|
1406 |
+
|
1407 |
+
return implode("\n\n", $grafs);
|
1408 |
+
}
|
1409 |
+
|
1410 |
+
|
1411 |
+
function encodeAttribute($text) {
|
1412 |
+
#
|
1413 |
+
# Encode text for a double-quoted HTML attribute. This function
|
1414 |
+
# is *not* suitable for attributes enclosed in single quotes.
|
1415 |
+
#
|
1416 |
+
$text = $this->encodeAmpsAndAngles($text);
|
1417 |
+
$text = str_replace('"', '"', $text);
|
1418 |
+
return $text;
|
1419 |
+
}
|
1420 |
+
|
1421 |
+
|
1422 |
+
function encodeAmpsAndAngles($text) {
|
1423 |
+
#
|
1424 |
+
# Smart processing for ampersands and angle brackets that need to
|
1425 |
+
# be encoded. Valid character entities are left alone unless the
|
1426 |
+
# no-entities mode is set.
|
1427 |
+
#
|
1428 |
+
if ($this->no_entities) {
|
1429 |
+
$text = str_replace('&', '&', $text);
|
1430 |
+
} else {
|
1431 |
+
# Ampersand-encoding based entirely on Nat Irons's Amputator
|
1432 |
+
# MT plugin: <http://bumppo.net/projects/amputator/>
|
1433 |
+
$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
|
1434 |
+
'&', $text);;
|
1435 |
+
}
|
1436 |
+
# Encode remaining <'s
|
1437 |
+
$text = str_replace('<', '<', $text);
|
1438 |
+
|
1439 |
+
return $text;
|
1440 |
+
}
|
1441 |
+
|
1442 |
+
|
1443 |
+
function doAutoLinks($text) {
|
1444 |
+
$text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
|
1445 |
+
array(&$this, '_doAutoLinks_url_callback'), $text);
|
1446 |
+
|
1447 |
+
# Email addresses: <address@domain.foo>
|
1448 |
+
$text = preg_replace_callback('{
|
1449 |
+
<
|
1450 |
+
(?:mailto:)?
|
1451 |
+
(
|
1452 |
+
(?:
|
1453 |
+
[-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
|
1454 |
+
|
|
1455 |
+
".*?"
|
1456 |
+
)
|
1457 |
+
\@
|
1458 |
+
(?:
|
1459 |
+
[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
|
1460 |
+
|
|
1461 |
+
\[[\d.a-fA-F:]+\] # IPv4 & IPv6
|
1462 |
+
)
|
1463 |
+
)
|
1464 |
+
>
|
1465 |
+
}xi',
|
1466 |
+
array(&$this, '_doAutoLinks_email_callback'), $text);
|
1467 |
+
|
1468 |
+
return $text;
|
1469 |
+
}
|
1470 |
+
function _doAutoLinks_url_callback($matches) {
|
1471 |
+
$url = $this->encodeAttribute($matches[1]);
|
1472 |
+
$link = "<a href=\"$url\">$url</a>";
|
1473 |
+
return $this->hashPart($link);
|
1474 |
+
}
|
1475 |
+
function _doAutoLinks_email_callback($matches) {
|
1476 |
+
$address = $matches[1];
|
1477 |
+
$link = $this->encodeEmailAddress($address);
|
1478 |
+
return $this->hashPart($link);
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
|
1482 |
+
function encodeEmailAddress($addr) {
|
1483 |
+
#
|
1484 |
+
# Input: an email address, e.g. "foo@example.com"
|
1485 |
+
#
|
1486 |
+
# Output: the email address as a mailto link, with each character
|
1487 |
+
# of the address encoded as either a decimal or hex entity, in
|
1488 |
+
# the hopes of foiling most address harvesting spam bots. E.g.:
|
1489 |
+
#
|
1490 |
+
# <p><a href="mailto:foo
|
1491 |
+
# @example.co
|
1492 |
+
# m">foo@exampl
|
1493 |
+
# e.com</a></p>
|
1494 |
+
#
|
1495 |
+
# Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
|
1496 |
+
# With some optimizations by Milian Wolff.
|
1497 |
+
#
|
1498 |
+
$addr = "mailto:" . $addr;
|
1499 |
+
$chars = preg_split('/(?<!^)(?!$)/', $addr);
|
1500 |
+
$seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
|
1501 |
+
|
1502 |
+
foreach ($chars as $key => $char) {
|
1503 |
+
$ord = ord($char);
|
1504 |
+
# Ignore non-ascii chars.
|
1505 |
+
if ($ord < 128) {
|
1506 |
+
$r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
|
1507 |
+
# roughly 10% raw, 45% hex, 45% dec
|
1508 |
+
# '@' *must* be encoded. I insist.
|
1509 |
+
if ($r > 90 && $char != '@') /* do nothing */;
|
1510 |
+
else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
|
1511 |
+
else $chars[$key] = '&#'.$ord.';';
|
1512 |
+
}
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
$addr = implode('', $chars);
|
1516 |
+
$text = implode('', array_slice($chars, 7)); # text without `mailto:`
|
1517 |
+
$addr = "<a href=\"$addr\">$text</a>";
|
1518 |
+
|
1519 |
+
return $addr;
|
1520 |
+
}
|
1521 |
+
|
1522 |
+
|
1523 |
+
function parseSpan($str) {
|
1524 |
+
#
|
1525 |
+
# Take the string $str and parse it into tokens, hashing embeded HTML,
|
1526 |
+
# escaped characters and handling code spans.
|
1527 |
+
#
|
1528 |
+
$output = '';
|
1529 |
+
|
1530 |
+
$span_re = '{
|
1531 |
+
(
|
1532 |
+
\\\\'.$this->escape_chars_re.'
|
1533 |
+
|
|
1534 |
+
(?<![`\\\\])
|
1535 |
+
`+ # code span marker
|
1536 |
+
'.( $this->no_markup ? '' : '
|
1537 |
+
|
|
1538 |
+
<!-- .*? --> # comment
|
1539 |
+
|
|
1540 |
+
<\?.*?\?> | <%.*?%> # processing instruction
|
1541 |
+
|
|
1542 |
+
<[/!$]?[-a-zA-Z0-9:_]+ # regular tags
|
1543 |
+
(?>
|
1544 |
+
\s
|
1545 |
+
(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
|
1546 |
+
)?
|
1547 |
+
>
|
1548 |
+
').'
|
1549 |
+
)
|
1550 |
+
}xs';
|
1551 |
+
|
1552 |
+
while (1) {
|
1553 |
+
#
|
1554 |
+
# Each loop iteration seach for either the next tag, the next
|
1555 |
+
# openning code span marker, or the next escaped character.
|
1556 |
+
# Each token is then passed to handleSpanToken.
|
1557 |
+
#
|
1558 |
+
$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
|
1559 |
+
|
1560 |
+
# Create token from text preceding tag.
|
1561 |
+
if ($parts[0] != "") {
|
1562 |
+
$output .= $parts[0];
|
1563 |
+
}
|
1564 |
+
|
1565 |
+
# Check if we reach the end.
|
1566 |
+
if (isset($parts[1])) {
|
1567 |
+
$output .= $this->handleSpanToken($parts[1], $parts[2]);
|
1568 |
+
$str = $parts[2];
|
1569 |
+
}
|
1570 |
+
else {
|
1571 |
+
break;
|
1572 |
+
}
|
1573 |
+
}
|
1574 |
+
|
1575 |
+
return $output;
|
1576 |
+
}
|
1577 |
+
|
1578 |
+
|
1579 |
+
function handleSpanToken($token, &$str) {
|
1580 |
+
#
|
1581 |
+
# Handle $token provided by parseSpan by determining its nature and
|
1582 |
+
# returning the corresponding value that should replace it.
|
1583 |
+
#
|
1584 |
+
switch ($token{0}) {
|
1585 |
+
case "\\":
|
1586 |
+
return $this->hashPart("&#". ord($token{1}). ";");
|
1587 |
+
case "`":
|
1588 |
+
# Search for end marker in remaining text.
|
1589 |
+
if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
|
1590 |
+
$str, $matches))
|
1591 |
+
{
|
1592 |
+
$str = $matches[2];
|
1593 |
+
$codespan = $this->makeCodeSpan($matches[1]);
|
1594 |
+
return $this->hashPart($codespan);
|
1595 |
+
}
|
1596 |
+
return $token; // return as text since no ending marker found.
|
1597 |
+
default:
|
1598 |
+
return $this->hashPart($token);
|
1599 |
+
}
|
1600 |
+
}
|
1601 |
+
|
1602 |
+
|
1603 |
+
function outdent($text) {
|
1604 |
+
#
|
1605 |
+
# Remove one level of line-leading tabs or spaces
|
1606 |
+
#
|
1607 |
+
return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
|
1608 |
+
}
|
1609 |
+
|
1610 |
+
|
1611 |
+
# String length function for detab. `_initDetab` will create a function to
|
1612 |
+
# hanlde UTF-8 if the default function does not exist.
|
1613 |
+
var $utf8_strlen = 'mb_strlen';
|
1614 |
+
|
1615 |
+
function detab($text) {
|
1616 |
+
#
|
1617 |
+
# Replace tabs with the appropriate amount of space.
|
1618 |
+
#
|
1619 |
+
# For each line we separate the line in blocks delemited by
|
1620 |
+
# tab characters. Then we reconstruct every line by adding the
|
1621 |
+
# appropriate number of space between each blocks.
|
1622 |
+
|
1623 |
+
$text = preg_replace_callback('/^.*\t.*$/m',
|
1624 |
+
array(&$this, '_detab_callback'), $text);
|
1625 |
+
|
1626 |
+
return $text;
|
1627 |
+
}
|
1628 |
+
function _detab_callback($matches) {
|
1629 |
+
$line = $matches[0];
|
1630 |
+
$strlen = $this->utf8_strlen; # strlen function for UTF-8.
|
1631 |
+
|
1632 |
+
# Split in blocks.
|
1633 |
+
$blocks = explode("\t", $line);
|
1634 |
+
# Add each blocks to the line.
|
1635 |
+
$line = $blocks[0];
|
1636 |
+
unset($blocks[0]); # Do not add first block twice.
|
1637 |
+
foreach ($blocks as $block) {
|
1638 |
+
# Calculate amount of space, insert spaces, insert block.
|
1639 |
+
$amount = $this->tab_width -
|
1640 |
+
$strlen($line, 'UTF-8') % $this->tab_width;
|
1641 |
+
$line .= str_repeat(" ", $amount) . $block;
|
1642 |
+
}
|
1643 |
+
return $line;
|
1644 |
+
}
|
1645 |
+
function _initDetab() {
|
1646 |
+
#
|
1647 |
+
# Check for the availability of the function in the `utf8_strlen` property
|
1648 |
+
# (initially `mb_strlen`). If the function is not available, create a
|
1649 |
+
# function that will loosely count the number of UTF-8 characters with a
|
1650 |
+
# regular expression.
|
1651 |
+
#
|
1652 |
+
if (function_exists($this->utf8_strlen)) return;
|
1653 |
+
$this->utf8_strlen = create_function('$text', 'return preg_match_all(
|
1654 |
+
"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
|
1655 |
+
$text, $m);');
|
1656 |
+
}
|
1657 |
+
|
1658 |
+
|
1659 |
+
function unhash($text) {
|
1660 |
+
#
|
1661 |
+
# Swap back in all the tags hashed by _HashHTMLBlocks.
|
1662 |
+
#
|
1663 |
+
return preg_replace_callback('/(.)\x1A[0-9]+\1/',
|
1664 |
+
array(&$this, '_unhash_callback'), $text);
|
1665 |
+
}
|
1666 |
+
function _unhash_callback($matches) {
|
1667 |
+
return $this->html_hashes[$matches[0]];
|
1668 |
+
}
|
1669 |
+
|
1670 |
+
}
|
1671 |
+
|
1672 |
+
|
1673 |
+
#
|
1674 |
+
# Markdown Extra Parser Class
|
1675 |
+
#
|
1676 |
+
|
1677 |
+
class MarkdownExtra_Parser extends Markdown_Parser {
|
1678 |
+
|
1679 |
+
# Prefix for footnote ids.
|
1680 |
+
var $fn_id_prefix = "";
|
1681 |
+
|
1682 |
+
# Optional title attribute for footnote links and backlinks.
|
1683 |
+
var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
|
1684 |
+
var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
|
1685 |
+
|
1686 |
+
# Optional class attribute for footnote links and backlinks.
|
1687 |
+
var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
|
1688 |
+
var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
|
1689 |
+
|
1690 |
+
# Predefined abbreviations.
|
1691 |
+
var $predef_abbr = array();
|
1692 |
+
|
1693 |
+
|
1694 |
+
function MarkdownExtra_Parser() {
|
1695 |
+
#
|
1696 |
+
# Constructor function. Initialize the parser object.
|
1697 |
+
#
|
1698 |
+
# Add extra escapable characters before parent constructor
|
1699 |
+
# initialize the table.
|
1700 |
+
$this->escape_chars .= ':|';
|
1701 |
+
|
1702 |
+
# Insert extra document, block, and span transformations.
|
1703 |
+
# Parent constructor will do the sorting.
|
1704 |
+
$this->document_gamut += array(
|
1705 |
+
"doFencedCodeBlocks" => 5,
|
1706 |
+
"stripFootnotes" => 15,
|
1707 |
+
"stripAbbreviations" => 25,
|
1708 |
+
"appendFootnotes" => 50,
|
1709 |
+
);
|
1710 |
+
$this->block_gamut += array(
|
1711 |
+
"doFencedCodeBlocks" => 5,
|
1712 |
+
"doTables" => 15,
|
1713 |
+
"doDefLists" => 45,
|
1714 |
+
);
|
1715 |
+
$this->span_gamut += array(
|
1716 |
+
"doFootnotes" => 5,
|
1717 |
+
"doAbbreviations" => 70,
|
1718 |
+
);
|
1719 |
+
|
1720 |
+
parent::Markdown_Parser();
|
1721 |
+
}
|
1722 |
+
|
1723 |
+
|
1724 |
+
# Extra variables used during extra transformations.
|
1725 |
+
var $footnotes = array();
|
1726 |
+
var $footnotes_ordered = array();
|
1727 |
+
var $abbr_desciptions = array();
|
1728 |
+
var $abbr_word_re = '';
|
1729 |
+
|
1730 |
+
# Give the current footnote number.
|
1731 |
+
var $footnote_counter = 1;
|
1732 |
+
|
1733 |
+
|
1734 |
+
function setup() {
|
1735 |
+
#
|
1736 |
+
# Setting up Extra-specific variables.
|
1737 |
+
#
|
1738 |
+
parent::setup();
|
1739 |
+
|
1740 |
+
$this->footnotes = array();
|
1741 |
+
$this->footnotes_ordered = array();
|
1742 |
+
$this->abbr_desciptions = array();
|
1743 |
+
$this->abbr_word_re = '';
|
1744 |
+
$this->footnote_counter = 1;
|
1745 |
+
|
1746 |
+
foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
|
1747 |
+
if ($this->abbr_word_re)
|
1748 |
+
$this->abbr_word_re .= '|';
|
1749 |
+
$this->abbr_word_re .= preg_quote($abbr_word);
|
1750 |
+
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
|
1751 |
+
}
|
1752 |
+
}
|
1753 |
+
|
1754 |
+
function teardown() {
|
1755 |
+
#
|
1756 |
+
# Clearing Extra-specific variables.
|
1757 |
+
#
|
1758 |
+
$this->footnotes = array();
|
1759 |
+
$this->footnotes_ordered = array();
|
1760 |
+
$this->abbr_desciptions = array();
|
1761 |
+
$this->abbr_word_re = '';
|
1762 |
+
|
1763 |
+
parent::teardown();
|
1764 |
+
}
|
1765 |
+
|
1766 |
+
|
1767 |
+
### HTML Block Parser ###
|
1768 |
+
|
1769 |
+
# Tags that are always treated as block tags:
|
1770 |
+
var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
|
1771 |
+
|
1772 |
+
# Tags treated as block tags only if the opening tag is alone on it's line:
|
1773 |
+
var $context_block_tags_re = 'script|noscript|math|ins|del';
|
1774 |
+
|
1775 |
+
# Tags where markdown="1" default to span mode:
|
1776 |
+
var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
|
1777 |
+
|
1778 |
+
# Tags which must not have their contents modified, no matter where
|
1779 |
+
# they appear:
|
1780 |
+
var $clean_tags_re = 'script|math';
|
1781 |
+
|
1782 |
+
# Tags that do not need to be closed.
|
1783 |
+
var $auto_close_tags_re = 'hr|img';
|
1784 |
+
|
1785 |
+
|
1786 |
+
function hashHTMLBlocks($text) {
|
1787 |
+
#
|
1788 |
+
# Hashify HTML Blocks and "clean tags".
|
1789 |
+
#
|
1790 |
+
# We only want to do this for block-level HTML tags, such as headers,
|
1791 |
+
# lists, and tables. That's because we still want to wrap <p>s around
|
1792 |
+
# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
|
1793 |
+
# phrase emphasis, and spans. The list of tags we're looking for is
|
1794 |
+
# hard-coded.
|
1795 |
+
#
|
1796 |
+
# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
|
1797 |
+
# _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
|
1798 |
+
# attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
|
1799 |
+
# _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
|
1800 |
+
# These two functions are calling each other. It's recursive!
|
1801 |
+
#
|
1802 |
+
#
|
1803 |
+
# Call the HTML-in-Markdown hasher.
|
1804 |
+
#
|
1805 |
+
list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
|
1806 |
+
|
1807 |
+
return $text;
|
1808 |
+
}
|
1809 |
+
function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
|
1810 |
+
$enclosing_tag_re = '', $span = false)
|
1811 |
+
{
|
1812 |
+
#
|
1813 |
+
# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
|
1814 |
+
#
|
1815 |
+
# * $indent is the number of space to be ignored when checking for code
|
1816 |
+
# blocks. This is important because if we don't take the indent into
|
1817 |
+
# account, something like this (which looks right) won't work as expected:
|
1818 |
+
#
|
1819 |
+
# <div>
|
1820 |
+
# <div markdown="1">
|
1821 |
+
# Hello World. <-- Is this a Markdown code block or text?
|
1822 |
+
# </div> <-- Is this a Markdown code block or a real tag?
|
1823 |
+
# <div>
|
1824 |
+
#
|
1825 |
+
# If you don't like this, just don't indent the tag on which
|
1826 |
+
# you apply the markdown="1" attribute.
|
1827 |
+
#
|
1828 |
+
# * If $enclosing_tag_re is not empty, stops at the first unmatched closing
|
1829 |
+
# tag with that name. Nested tags supported.
|
1830 |
+
#
|
1831 |
+
# * If $span is true, text inside must treated as span. So any double
|
1832 |
+
# newline will be replaced by a single newline so that it does not create
|
1833 |
+
# paragraphs.
|
1834 |
+
#
|
1835 |
+
# Returns an array of that form: ( processed text , remaining text )
|
1836 |
+
#
|
1837 |
+
if ($text === '') return array('', '');
|
1838 |
+
|
1839 |
+
# Regex to check for the presense of newlines around a block tag.
|
1840 |
+
$newline_before_re = '/(?:^\n?|\n\n)*$/';
|
1841 |
+
$newline_after_re =
|
1842 |
+
'{
|
1843 |
+
^ # Start of text following the tag.
|
1844 |
+
(?>[ ]*<!--.*?-->)? # Optional comment.
|
1845 |
+
[ ]*\n # Must be followed by newline.
|
1846 |
+
}xs';
|
1847 |
+
|
1848 |
+
# Regex to match any tag.
|
1849 |
+
$block_tag_re =
|
1850 |
+
'{
|
1851 |
+
( # $2: Capture hole tag.
|
1852 |
+
</? # Any opening or closing tag.
|
1853 |
+
(?> # Tag name.
|
1854 |
+
'.$this->block_tags_re.' |
|
1855 |
+
'.$this->context_block_tags_re.' |
|
1856 |
+
'.$this->clean_tags_re.' |
|
1857 |
+
(?!\s)'.$enclosing_tag_re.'
|
1858 |
+
)
|
1859 |
+
(?:
|
1860 |
+
(?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
|
1861 |
+
(?>
|
1862 |
+
".*?" | # Double quotes (can contain `>`)
|
1863 |
+
\'.*?\' | # Single quotes (can contain `>`)
|
1864 |
+
.+? # Anything but quotes and `>`.
|
1865 |
+
)*?
|
1866 |
+
)?
|
1867 |
+
> # End of tag.
|
1868 |
+
|
|
1869 |
+
<!-- .*? --> # HTML Comment
|
1870 |
+
|
|
1871 |
+
<\?.*?\?> | <%.*?%> # Processing instruction
|
1872 |
+
|
|
1873 |
+
<!\[CDATA\[.*?\]\]> # CData Block
|
1874 |
+
|
|
1875 |
+
# Code span marker
|
1876 |
+
`+
|
1877 |
+
'. ( !$span ? ' # If not in span.
|
1878 |
+
|
|
1879 |
+
# Indented code block
|
1880 |
+
(?: ^[ ]*\n | ^ | \n[ ]*\n )
|
1881 |
+
[ ]{'.($indent+4).'}[^\n]* \n
|
1882 |
+
(?>
|
1883 |
+
(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
|
1884 |
+
)*
|
1885 |
+
|
|
1886 |
+
# Fenced code block marker
|
1887 |
+
(?> ^ | \n )
|
1888 |
+
[ ]{'.($indent).'}~~~+[ ]*\n
|
1889 |
+
' : '' ). ' # End (if not is span).
|
1890 |
+
)
|
1891 |
+
}xs';
|
1892 |
+
|
1893 |
+
|
1894 |
+
$depth = 0; # Current depth inside the tag tree.
|
1895 |
+
$parsed = ""; # Parsed text that will be returned.
|
1896 |
+
|
1897 |
+
#
|
1898 |
+
# Loop through every tag until we find the closing tag of the parent
|
1899 |
+
# or loop until reaching the end of text if no parent tag specified.
|
1900 |
+
#
|
1901 |
+
do {
|
1902 |
+
#
|
1903 |
+
# Split the text using the first $tag_match pattern found.
|
1904 |
+
# Text before pattern will be first in the array, text after
|
1905 |
+
# pattern will be at the end, and between will be any catches made
|
1906 |
+
# by the pattern.
|
1907 |
+
#
|
1908 |
+
$parts = preg_split($block_tag_re, $text, 2,
|
1909 |
+
PREG_SPLIT_DELIM_CAPTURE);
|
1910 |
+
|
1911 |
+
# If in Markdown span mode, add a empty-string span-level hash
|
1912 |
+
# after each newline to prevent triggering any block element.
|
1913 |
+
if ($span) {
|
1914 |
+
$void = $this->hashPart("", ':');
|
1915 |
+
$newline = "$void\n";
|
1916 |
+
$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
|
1917 |
+
}
|
1918 |
+
|
1919 |
+
$parsed .= $parts[0]; # Text before current tag.
|
1920 |
+
|
1921 |
+
# If end of $text has been reached. Stop loop.
|
1922 |
+
if (count($parts) < 3) {
|
1923 |
+
$text = "";
|
1924 |
+
break;
|
1925 |
+
}
|
1926 |
+
|
1927 |
+
$tag = $parts[1]; # Tag to handle.
|
1928 |
+
$text = $parts[2]; # Remaining text after current tag.
|
1929 |
+
$tag_re = preg_quote($tag); # For use in a regular expression.
|
1930 |
+
|
1931 |
+
#
|
1932 |
+
# Check for: Code span marker
|
1933 |
+
#
|
1934 |
+
if ($tag{0} == "`") {
|
1935 |
+
# Find corresponding end marker.
|
1936 |
+
$tag_re = preg_quote($tag);
|
1937 |
+
if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
|
1938 |
+
$text, $matches))
|
1939 |
+
{
|
1940 |
+
# End marker found: pass text unchanged until marker.
|
1941 |
+
$parsed .= $tag . $matches[0];
|
1942 |
+
$text = substr($text, strlen($matches[0]));
|
1943 |
+
}
|
1944 |
+
else {
|
1945 |
+
# Unmatched marker: just skip it.
|
1946 |
+
$parsed .= $tag;
|
1947 |
+
}
|
1948 |
+
}
|
1949 |
+
#
|
1950 |
+
# Check for: Indented code block.
|
1951 |
+
#
|
1952 |
+
else if ($tag{0} == "\n" || $tag{0} == " ") {
|
1953 |
+
# Indented code block: pass it unchanged, will be handled
|
1954 |
+
# later.
|
1955 |
+
$parsed .= $tag;
|
1956 |
+
}
|
1957 |
+
#
|
1958 |
+
# Check for: Fenced code block marker.
|
1959 |
+
#
|
1960 |
+
else if ($tag{0} == "~") {
|
1961 |
+
# Fenced code block marker: find matching end marker.
|
1962 |
+
$tag_re = preg_quote(trim($tag));
|
1963 |
+
if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
|
1964 |
+
$matches))
|
1965 |
+
{
|
1966 |
+
# End marker found: pass text unchanged until marker.
|
1967 |
+
$parsed .= $tag . $matches[0];
|
1968 |
+
$text = substr($text, strlen($matches[0]));
|
1969 |
+
}
|
1970 |
+
else {
|
1971 |
+
# No end marker: just skip it.
|
1972 |
+
$parsed .= $tag;
|
1973 |
+
}
|
1974 |
+
}
|
1975 |
+
#
|
1976 |
+
# Check for: Opening Block level tag or
|
1977 |
+
# Opening Context Block tag (like ins and del)
|
1978 |
+
# used as a block tag (tag is alone on it's line).
|
1979 |
+
#
|
1980 |
+
else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
|
1981 |
+
( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
|
1982 |
+
preg_match($newline_before_re, $parsed) &&
|
1983 |
+
preg_match($newline_after_re, $text) )
|
1984 |
+
)
|
1985 |
+
{
|
1986 |
+
# Need to parse tag and following text using the HTML parser.
|
1987 |
+
list($block_text, $text) =
|
1988 |
+
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
|
1989 |
+
|
1990 |
+
# Make sure it stays outside of any paragraph by adding newlines.
|
1991 |
+
$parsed .= "\n\n$block_text\n\n";
|
1992 |
+
}
|
1993 |
+
#
|
1994 |
+
# Check for: Clean tag (like script, math)
|
1995 |
+
# HTML Comments, processing instructions.
|
1996 |
+
#
|
1997 |
+
else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
|
1998 |
+
$tag{1} == '!' || $tag{1} == '?')
|
1999 |
+
{
|
2000 |
+
# Need to parse tag and following text using the HTML parser.
|
2001 |
+
# (don't check for markdown attribute)
|
2002 |
+
list($block_text, $text) =
|
2003 |
+
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
|
2004 |
+
|
2005 |
+
$parsed .= $block_text;
|
2006 |
+
}
|
2007 |
+
#
|
2008 |
+
# Check for: Tag with same name as enclosing tag.
|
2009 |
+
#
|
2010 |
+
else if ($enclosing_tag_re !== '' &&
|
2011 |
+
# Same name as enclosing tag.
|
2012 |
+
preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
|
2013 |
+
{
|
2014 |
+
#
|
2015 |
+
# Increase/decrease nested tag count.
|
2016 |
+
#
|
2017 |
+
if ($tag{1} == '/') $depth--;
|
2018 |
+
else if ($tag{strlen($tag)-2} != '/') $depth++;
|
2019 |
+
|
2020 |
+
if ($depth < 0) {
|
2021 |
+
#
|
2022 |
+
# Going out of parent element. Clean up and break so we
|
2023 |
+
# return to the calling function.
|
2024 |
+
#
|
2025 |
+
$text = $tag . $text;
|
2026 |
+
break;
|
2027 |
+
}
|
2028 |
+
|
2029 |
+
$parsed .= $tag;
|
2030 |
+
}
|
2031 |
+
else {
|
2032 |
+
$parsed .= $tag;
|
2033 |
+
}
|
2034 |
+
} while ($depth >= 0);
|
2035 |
+
|
2036 |
+
return array($parsed, $text);
|
2037 |
+
}
|
2038 |
+
function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
|
2039 |
+
#
|
2040 |
+
# Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
|
2041 |
+
#
|
2042 |
+
# * Calls $hash_method to convert any blocks.
|
2043 |
+
# * Stops when the first opening tag closes.
|
2044 |
+
# * $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
|
2045 |
+
# (it is not inside clean tags)
|
2046 |
+
#
|
2047 |
+
# Returns an array of that form: ( processed text , remaining text )
|
2048 |
+
#
|
2049 |
+
if ($text === '') return array('', '');
|
2050 |
+
|
2051 |
+
# Regex to match `markdown` attribute inside of a tag.
|
2052 |
+
$markdown_attr_re = '
|
2053 |
+
{
|
2054 |
+
\s* # Eat whitespace before the `markdown` attribute
|
2055 |
+
markdown
|
2056 |
+
\s*=\s*
|
2057 |
+
(?>
|
2058 |
+
(["\']) # $1: quote delimiter
|
2059 |
+
(.*?) # $2: attribute value
|
2060 |
+
\1 # matching delimiter
|
2061 |
+
|
|
2062 |
+
([^\s>]*) # $3: unquoted attribute value
|
2063 |
+
)
|
2064 |
+
() # $4: make $3 always defined (avoid warnings)
|
2065 |
+
}xs';
|
2066 |
+
|
2067 |
+
# Regex to match any tag.
|
2068 |
+
$tag_re = '{
|
2069 |
+
( # $2: Capture hole tag.
|
2070 |
+
</? # Any opening or closing tag.
|
2071 |
+
[\w:$]+ # Tag name.
|
2072 |
+
(?:
|
2073 |
+
(?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
|
2074 |
+
(?>
|
2075 |
+
".*?" | # Double quotes (can contain `>`)
|
2076 |
+
\'.*?\' | # Single quotes (can contain `>`)
|
2077 |
+
.+? # Anything but quotes and `>`.
|
2078 |
+
)*?
|
2079 |
+
)?
|
2080 |
+
> # End of tag.
|
2081 |
+
|
|
2082 |
+
<!-- .*? --> # HTML Comment
|
2083 |
+
|
|
2084 |
+
<\?.*?\?> | <%.*?%> # Processing instruction
|
2085 |
+
|
|
2086 |
+
<!\[CDATA\[.*?\]\]> # CData Block
|
2087 |
+
)
|
2088 |
+
}xs';
|
2089 |
+
|
2090 |
+
$original_text = $text; # Save original text in case of faliure.
|
2091 |
+
|
2092 |
+
$depth = 0; # Current depth inside the tag tree.
|
2093 |
+
$block_text = ""; # Temporary text holder for current text.
|
2094 |
+
$parsed = ""; # Parsed text that will be returned.
|
2095 |
+
|
2096 |
+
#
|
2097 |
+
# Get the name of the starting tag.
|
2098 |
+
# (This pattern makes $base_tag_name_re safe without quoting.)
|
2099 |
+
#
|
2100 |
+
if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
|
2101 |
+
$base_tag_name_re = $matches[1];
|
2102 |
+
|
2103 |
+
#
|
2104 |
+
# Loop through every tag until we find the corresponding closing tag.
|
2105 |
+
#
|
2106 |
+
do {
|
2107 |
+
#
|
2108 |
+
# Split the text using the first $tag_match pattern found.
|
2109 |
+
# Text before pattern will be first in the array, text after
|
2110 |
+
# pattern will be at the end, and between will be any catches made
|
2111 |
+
# by the pattern.
|
2112 |
+
#
|
2113 |
+
$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
|
2114 |
+
|
2115 |
+
if (count($parts) < 3) {
|
2116 |
+
#
|
2117 |
+
# End of $text reached with unbalenced tag(s).
|
2118 |
+
# In that case, we return original text unchanged and pass the
|
2119 |
+
# first character as filtered to prevent an infinite loop in the
|
2120 |
+
# parent function.
|
2121 |
+
#
|
2122 |
+
return array($original_text{0}, substr($original_text, 1));
|
2123 |
+
}
|
2124 |
+
|
2125 |
+
$block_text .= $parts[0]; # Text before current tag.
|
2126 |
+
$tag = $parts[1]; # Tag to handle.
|
2127 |
+
$text = $parts[2]; # Remaining text after current tag.
|
2128 |
+
|
2129 |
+
#
|
2130 |
+
# Check for: Auto-close tag (like <hr/>)
|
2131 |
+
# Comments and Processing Instructions.
|
2132 |
+
#
|
2133 |
+
if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
|
2134 |
+
$tag{1} == '!' || $tag{1} == '?')
|
2135 |
+
{
|
2136 |
+
# Just add the tag to the block as if it was text.
|
2137 |
+
$block_text .= $tag;
|
2138 |
+
}
|
2139 |
+
else {
|
2140 |
+
#
|
2141 |
+
# Increase/decrease nested tag count. Only do so if
|
2142 |
+
# the tag's name match base tag's.
|
2143 |
+
#
|
2144 |
+
if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
|
2145 |
+
if ($tag{1} == '/') $depth--;
|
2146 |
+
else if ($tag{strlen($tag)-2} != '/') $depth++;
|
2147 |
+
}
|
2148 |
+
|
2149 |
+
#
|
2150 |
+
# Check for `markdown="1"` attribute and handle it.
|
2151 |
+
#
|
2152 |
+
if ($md_attr &&
|
2153 |
+
preg_match($markdown_attr_re, $tag, $attr_m) &&
|
2154 |
+
preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
|
2155 |
+
{
|
2156 |
+
# Remove `markdown` attribute from opening tag.
|
2157 |
+
$tag = preg_replace($markdown_attr_re, '', $tag);
|
2158 |
+
|
2159 |
+
# Check if text inside this tag must be parsed in span mode.
|
2160 |
+
$this->mode = $attr_m[2] . $attr_m[3];
|
2161 |
+
$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
|
2162 |
+
preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
|
2163 |
+
|
2164 |
+
# Calculate indent before tag.
|
2165 |
+
if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
|
2166 |
+
$strlen = $this->utf8_strlen;
|
2167 |
+
$indent = $strlen($matches[1], 'UTF-8');
|
2168 |
+
} else {
|
2169 |
+
$indent = 0;
|
2170 |
+
}
|
2171 |
+
|
2172 |
+
# End preceding block with this tag.
|
2173 |
+
$block_text .= $tag;
|
2174 |
+
$parsed .= $this->$hash_method($block_text);
|
2175 |
+
|
2176 |
+
# Get enclosing tag name for the ParseMarkdown function.
|
2177 |
+
# (This pattern makes $tag_name_re safe without quoting.)
|
2178 |
+
preg_match('/^<([\w:$]*)\b/', $tag, $matches);
|
2179 |
+
$tag_name_re = $matches[1];
|
2180 |
+
|
2181 |
+
# Parse the content using the HTML-in-Markdown parser.
|
2182 |
+
list ($block_text, $text)
|
2183 |
+
= $this->_hashHTMLBlocks_inMarkdown($text, $indent,
|
2184 |
+
$tag_name_re, $span_mode);
|
2185 |
+
|
2186 |
+
# Outdent markdown text.
|
2187 |
+
if ($indent > 0) {
|
2188 |
+
$block_text = preg_replace("/^[ ]{1,$indent}/m", "",
|
2189 |
+
$block_text);
|
2190 |
+
}
|
2191 |
+
|
2192 |
+
# Append tag content to parsed text.
|
2193 |
+
if (!$span_mode) $parsed .= "\n\n$block_text\n\n";
|
2194 |
+
else $parsed .= "$block_text";
|
2195 |
+
|
2196 |
+
# Start over a new block.
|
2197 |
+
$block_text = "";
|
2198 |
+
}
|
2199 |
+
else $block_text .= $tag;
|
2200 |
+
}
|
2201 |
+
|
2202 |
+
} while ($depth > 0);
|
2203 |
+
|
2204 |
+
#
|
2205 |
+
# Hash last block text that wasn't processed inside the loop.
|
2206 |
+
#
|
2207 |
+
$parsed .= $this->$hash_method($block_text);
|
2208 |
+
|
2209 |
+
return array($parsed, $text);
|
2210 |
+
}
|
2211 |
+
|
2212 |
+
|
2213 |
+
function hashClean($text) {
|
2214 |
+
#
|
2215 |
+
# Called whenever a tag must be hashed when a function insert a "clean" tag
|
2216 |
+
# in $text, it pass through this function and is automaticaly escaped,
|
2217 |
+
# blocking invalid nested overlap.
|
2218 |
+
#
|
2219 |
+
return $this->hashPart($text, 'C');
|
2220 |
+
}
|
2221 |
+
|
2222 |
+
|
2223 |
+
function doHeaders($text) {
|
2224 |
+
#
|
2225 |
+
# Redefined to add id attribute support.
|
2226 |
+
#
|
2227 |
+
# Setext-style headers:
|
2228 |
+
# Header 1 {#header1}
|
2229 |
+
# ========
|
2230 |
+
#
|
2231 |
+
# Header 2 {#header2}
|
2232 |
+
# --------
|
2233 |
+
#
|
2234 |
+
$text = preg_replace_callback(
|
2235 |
+
'{
|
2236 |
+
(^.+?) # $1: Header text
|
2237 |
+
(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute
|
2238 |
+
[ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer
|
2239 |
+
}mx',
|
2240 |
+
array(&$this, '_doHeaders_callback_setext'), $text);
|
2241 |
+
|
2242 |
+
# atx-style headers:
|
2243 |
+
# # Header 1 {#header1}
|
2244 |
+
# ## Header 2 {#header2}
|
2245 |
+
# ## Header 2 with closing hashes ## {#header3}
|
2246 |
+
# ...
|
2247 |
+
# ###### Header 6 {#header2}
|
2248 |
+
#
|
2249 |
+
$text = preg_replace_callback('{
|
2250 |
+
^(\#{1,6}) # $1 = string of #\'s
|
2251 |
+
[ ]*
|
2252 |
+
(.+?) # $2 = Header text
|
2253 |
+
[ ]*
|
2254 |
+
\#* # optional closing #\'s (not counted)
|
2255 |
+
(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute
|
2256 |
+
[ ]*
|
2257 |
+
\n+
|
2258 |
+
}xm',
|
2259 |
+
array(&$this, '_doHeaders_callback_atx'), $text);
|
2260 |
+
|
2261 |
+
return $text;
|
2262 |
+
}
|
2263 |
+
function _doHeaders_attr($attr) {
|
2264 |
+
if (empty($attr)) return "";
|
2265 |
+
return " id=\"$attr\"";
|
2266 |
+
}
|
2267 |
+
function _doHeaders_callback_setext($matches) {
|
2268 |
+
if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
|
2269 |
+
return $matches[0];
|
2270 |
+
$level = $matches[3]{0} == '=' ? 1 : 2;
|
2271 |
+
$attr = $this->_doHeaders_attr($id =& $matches[2]);
|
2272 |
+
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
|
2273 |
+
return "\n" . $this->hashBlock($block) . "\n\n";
|
2274 |
+
}
|
2275 |
+
function _doHeaders_callback_atx($matches) {
|
2276 |
+
$level = strlen($matches[1]);
|
2277 |
+
$attr = $this->_doHeaders_attr($id =& $matches[3]);
|
2278 |
+
$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
|
2279 |
+
return "\n" . $this->hashBlock($block) . "\n\n";
|
2280 |
+
}
|
2281 |
+
|
2282 |
+
|
2283 |
+
function doTables($text) {
|
2284 |
+
#
|
2285 |
+
# Form HTML tables.
|
2286 |
+
#
|
2287 |
+
$less_than_tab = $this->tab_width - 1;
|
2288 |
+
#
|
2289 |
+
# Find tables with leading pipe.
|
2290 |
+
#
|
2291 |
+
# | Header 1 | Header 2
|
2292 |
+
# | -------- | --------
|
2293 |
+
# | Cell 1 | Cell 2
|
2294 |
+
# | Cell 3 | Cell 4
|
2295 |
+
#
|
2296 |
+
$text = preg_replace_callback('
|
2297 |
+
{
|
2298 |
+
^ # Start of a line
|
2299 |
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2300 |
+
[|] # Optional leading pipe (present)
|
2301 |
+
(.+) \n # $1: Header row (at least one pipe)
|
2302 |
+
|
2303 |
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2304 |
+
[|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline
|
2305 |
+
|
2306 |
+
( # $3: Cells
|
2307 |
+
(?>
|
2308 |
+
[ ]* # Allowed whitespace.
|
2309 |
+
[|] .* \n # Row content.
|
2310 |
+
)*
|
2311 |
+
)
|
2312 |
+
(?=\n|\Z) # Stop at final double newline.
|
2313 |
+
}xm',
|
2314 |
+
array(&$this, '_doTable_leadingPipe_callback'), $text);
|
2315 |
+
|
2316 |
+
#
|
2317 |
+
# Find tables without leading pipe.
|
2318 |
+
#
|
2319 |
+
# Header 1 | Header 2
|
2320 |
+
# -------- | --------
|
2321 |
+
# Cell 1 | Cell 2
|
2322 |
+
# Cell 3 | Cell 4
|
2323 |
+
#
|
2324 |
+
$text = preg_replace_callback('
|
2325 |
+
{
|
2326 |
+
^ # Start of a line
|
2327 |
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2328 |
+
(\S.*[|].*) \n # $1: Header row (at least one pipe)
|
2329 |
+
|
2330 |
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
|
2331 |
+
([-:]+[ ]*[|][-| :]*) \n # $2: Header underline
|
2332 |
+
|
2333 |
+
( # $3: Cells
|
2334 |
+
(?>
|
2335 |
+
.* [|] .* \n # Row content
|
2336 |
+
)*
|
2337 |
+
)
|
2338 |
+
(?=\n|\Z) # Stop at final double newline.
|
2339 |
+
}xm',
|
2340 |
+
array(&$this, '_DoTable_callback'), $text);
|
2341 |
+
|
2342 |
+
return $text;
|
2343 |
+
}
|
2344 |
+
function _doTable_leadingPipe_callback($matches) {
|
2345 |
+
$head = $matches[1];
|
2346 |
+
$underline = $matches[2];
|
2347 |
+
$content = $matches[3];
|
2348 |
+
|
2349 |
+
# Remove leading pipe for each row.
|
2350 |
+
$content = preg_replace('/^ *[|]/m', '', $content);
|
2351 |
+
|
2352 |
+
return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
|
2353 |
+
}
|
2354 |
+
function _doTable_callback($matches) {
|
2355 |
+
$head = $matches[1];
|
2356 |
+
$underline = $matches[2];
|
2357 |
+
$content = $matches[3];
|
2358 |
+
|
2359 |
+
# Remove any tailing pipes for each line.
|
2360 |
+
$head = preg_replace('/[|] *$/m', '', $head);
|
2361 |
+
$underline = preg_replace('/[|] *$/m', '', $underline);
|
2362 |
+
$content = preg_replace('/[|] *$/m', '', $content);
|
2363 |
+
|
2364 |
+
# Reading alignement from header underline.
|
2365 |
+
$separators = preg_split('/ *[|] */', $underline);
|
2366 |
+
foreach ($separators as $n => $s) {
|
2367 |
+
if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"';
|
2368 |
+
else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
|
2369 |
+
else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
|
2370 |
+
else $attr[$n] = '';
|
2371 |
+
}
|
2372 |
+
|
2373 |
+
# Parsing span elements, including code spans, character escapes,
|
2374 |
+
# and inline HTML tags, so that pipes inside those gets ignored.
|
2375 |
+
$head = $this->parseSpan($head);
|
2376 |
+
$headers = preg_split('/ *[|] */', $head);
|
2377 |
+
$col_count = count($headers);
|
2378 |
+
|
2379 |
+
# Write column headers.
|
2380 |
+
$text = "<table>\n";
|
2381 |
+
$text .= "<thead>\n";
|
2382 |
+
$text .= "<tr>\n";
|
2383 |
+
foreach ($headers as $n => $header)
|
2384 |
+
$text .= " <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
|
2385 |
+
$text .= "</tr>\n";
|
2386 |
+
$text .= "</thead>\n";
|
2387 |
+
|
2388 |
+
# Split content by row.
|
2389 |
+
$rows = explode("\n", trim($content, "\n"));
|
2390 |
+
|
2391 |
+
$text .= "<tbody>\n";
|
2392 |
+
foreach ($rows as $row) {
|
2393 |
+
# Parsing span elements, including code spans, character escapes,
|
2394 |
+
# and inline HTML tags, so that pipes inside those gets ignored.
|
2395 |
+
$row = $this->parseSpan($row);
|
2396 |
+
|
2397 |
+
# Split row by cell.
|
2398 |
+
$row_cells = preg_split('/ *[|] */', $row, $col_count);
|
2399 |
+
$row_cells = array_pad($row_cells, $col_count, '');
|
2400 |
+
|
2401 |
+
$text .= "<tr>\n";
|
2402 |
+
foreach ($row_cells as $n => $cell)
|
2403 |
+
$text .= " <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
|
2404 |
+
$text .= "</tr>\n";
|
2405 |
+
}
|
2406 |
+
$text .= "</tbody>\n";
|
2407 |
+
$text .= "</table>";
|
2408 |
+
|
2409 |
+
return $this->hashBlock($text) . "\n";
|
2410 |
+
}
|
2411 |
+
|
2412 |
+
|
2413 |
+
function doDefLists($text) {
|
2414 |
+
#
|
2415 |
+
# Form HTML definition lists.
|
2416 |
+
#
|
2417 |
+
$less_than_tab = $this->tab_width - 1;
|
2418 |
+
|
2419 |
+
# Re-usable pattern to match any entire dl list:
|
2420 |
+
$whole_list_re = '(?>
|
2421 |
+
( # $1 = whole list
|
2422 |
+
( # $2
|
2423 |
+
[ ]{0,'.$less_than_tab.'}
|
2424 |
+
((?>.*\S.*\n)+) # $3 = defined term
|
2425 |
+
\n?
|
2426 |
+
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2427 |
+
)
|
2428 |
+
(?s:.+?)
|
2429 |
+
( # $4
|
2430 |
+
\z
|
2431 |
+
|
|
2432 |
+
\n{2,}
|
2433 |
+
(?=\S)
|
2434 |
+
(?! # Negative lookahead for another term
|
2435 |
+
[ ]{0,'.$less_than_tab.'}
|
2436 |
+
(?: \S.*\n )+? # defined term
|
2437 |
+
\n?
|
2438 |
+
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2439 |
+
)
|
2440 |
+
(?! # Negative lookahead for another definition
|
2441 |
+
[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
|
2442 |
+
)
|
2443 |
+
)
|
2444 |
+
)
|
2445 |
+
)'; // mx
|
2446 |
+
|
2447 |
+
$text = preg_replace_callback('{
|
2448 |
+
(?>\A\n?|(?<=\n\n))
|
2449 |
+
'.$whole_list_re.'
|
2450 |
+
}mx',
|
2451 |
+
array(&$this, '_doDefLists_callback'), $text);
|
2452 |
+
|
2453 |
+
return $text;
|
2454 |
+
}
|
2455 |
+
function _doDefLists_callback($matches) {
|
2456 |
+
# Re-usable patterns to match list item bullets and number markers:
|
2457 |
+
$list = $matches[1];
|
2458 |
+
|
2459 |
+
# Turn double returns into triple returns, so that we can make a
|
2460 |
+
# paragraph for the last item in a list, if necessary:
|
2461 |
+
$result = trim($this->processDefListItems($list));
|
2462 |
+
$result = "<dl>\n" . $result . "\n</dl>";
|
2463 |
+
return $this->hashBlock($result) . "\n\n";
|
2464 |
+
}
|
2465 |
+
|
2466 |
+
|
2467 |
+
function processDefListItems($list_str) {
|
2468 |
+
#
|
2469 |
+
# Process the contents of a single definition list, splitting it
|
2470 |
+
# into individual term and definition list items.
|
2471 |
+
#
|
2472 |
+
$less_than_tab = $this->tab_width - 1;
|
2473 |
+
|
2474 |
+
# trim trailing blank lines:
|
2475 |
+
$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
|
2476 |
+
|
2477 |
+
# Process definition terms.
|
2478 |
+
$list_str = preg_replace_callback('{
|
2479 |
+
(?>\A\n?|\n\n+) # leading line
|
2480 |
+
( # definition terms = $1
|
2481 |
+
[ ]{0,'.$less_than_tab.'} # leading whitespace
|
2482 |
+
(?![:][ ]|[ ]) # negative lookahead for a definition
|
2483 |
+
# mark (colon) or more whitespace.
|
2484 |
+
(?> \S.* \n)+? # actual term (not whitespace).
|
2485 |
+
)
|
2486 |
+
(?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
|
2487 |
+
# with a definition mark.
|
2488 |
+
}xm',
|
2489 |
+
array(&$this, '_processDefListItems_callback_dt'), $list_str);
|
2490 |
+
|
2491 |
+
# Process actual definitions.
|
2492 |
+
$list_str = preg_replace_callback('{
|
2493 |
+
\n(\n+)? # leading line = $1
|
2494 |
+
( # marker space = $2
|
2495 |
+
[ ]{0,'.$less_than_tab.'} # whitespace before colon
|
2496 |
+
[:][ ]+ # definition mark (colon)
|
2497 |
+
)
|
2498 |
+
((?s:.+?)) # definition text = $3
|
2499 |
+
(?= \n+ # stop at next definition mark,
|
2500 |
+
(?: # next term or end of text
|
2501 |
+
[ ]{0,'.$less_than_tab.'} [:][ ] |
|
2502 |
+
<dt> | \z
|
2503 |
+
)
|
2504 |
+
)
|
2505 |
+
}xm',
|
2506 |
+
array(&$this, '_processDefListItems_callback_dd'), $list_str);
|
2507 |
+
|
2508 |
+
return $list_str;
|
2509 |
+
}
|
2510 |
+
function _processDefListItems_callback_dt($matches) {
|
2511 |
+
$terms = explode("\n", trim($matches[1]));
|
2512 |
+
$text = '';
|
2513 |
+
foreach ($terms as $term) {
|
2514 |
+
$term = $this->runSpanGamut(trim($term));
|
2515 |
+
$text .= "\n<dt>" . $term . "</dt>";
|
2516 |
+
}
|
2517 |
+
return $text . "\n";
|
2518 |
+
}
|
2519 |
+
function _processDefListItems_callback_dd($matches) {
|
2520 |
+
$leading_line = $matches[1];
|
2521 |
+
$marker_space = $matches[2];
|
2522 |
+
$def = $matches[3];
|
2523 |
+
|
2524 |
+
if ($leading_line || preg_match('/\n{2,}/', $def)) {
|
2525 |
+
# Replace marker with the appropriate whitespace indentation
|
2526 |
+
$def = str_repeat(' ', strlen($marker_space)) . $def;
|
2527 |
+
$def = $this->runBlockGamut($this->outdent($def . "\n\n"));
|
2528 |
+
$def = "\n". $def ."\n";
|
2529 |
+
}
|
2530 |
+
else {
|
2531 |
+
$def = rtrim($def);
|
2532 |
+
$def = $this->runSpanGamut($this->outdent($def));
|
2533 |
+
}
|
2534 |
+
|
2535 |
+
return "\n<dd>" . $def . "</dd>\n";
|
2536 |
+
}
|
2537 |
+
|
2538 |
+
|
2539 |
+
function doFencedCodeBlocks($text) {
|
2540 |
+
#
|
2541 |
+
# Adding the fenced code block syntax to regular Markdown:
|
2542 |
+
#
|
2543 |
+
# ~~~
|
2544 |
+
# Code block
|
2545 |
+
# ~~~
|
2546 |
+
#
|
2547 |
+
$less_than_tab = $this->tab_width;
|
2548 |
+
|
2549 |
+
$text = preg_replace_callback('{
|
2550 |
+
(?:\n|\A)
|
2551 |
+
# 1: Opening marker
|
2552 |
+
(
|
2553 |
+
~{3,} # Marker: three tilde or more.
|
2554 |
+
)
|
2555 |
+
[ ]* \n # Whitespace and newline following marker.
|
2556 |
+
|
2557 |
+
# 2: Content
|
2558 |
+
(
|
2559 |
+
(?>
|
2560 |
+
(?!\1 [ ]* \n) # Not a closing marker.
|
2561 |
+
.*\n+
|
2562 |
+
)+
|
2563 |
+
)
|
2564 |
+
|
2565 |
+
# Closing marker.
|
2566 |
+
\1 [ ]* \n
|
2567 |
+
}xm',
|
2568 |
+
array(&$this, '_doFencedCodeBlocks_callback'), $text);
|
2569 |
+
|
2570 |
+
return $text;
|
2571 |
+
}
|
2572 |
+
function _doFencedCodeBlocks_callback($matches) {
|
2573 |
+
$codeblock = $matches[2];
|
2574 |
+
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
|
2575 |
+
$codeblock = preg_replace_callback('/^\n+/',
|
2576 |
+
array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
|
2577 |
+
$codeblock = "<pre><code>$codeblock</code></pre>";
|
2578 |
+
return "\n\n".$this->hashBlock($codeblock)."\n\n";
|
2579 |
+
}
|
2580 |
+
function _doFencedCodeBlocks_newlines($matches) {
|
2581 |
+
return str_repeat("<br$this->empty_element_suffix",
|
2582 |
+
strlen($matches[0]));
|
2583 |
+
}
|
2584 |
+
|
2585 |
+
|
2586 |
+
#
|
2587 |
+
# Redefining emphasis markers so that emphasis by underscore does not
|
2588 |
+
# work in the middle of a word.
|
2589 |
+
#
|
2590 |
+
var $em_relist = array(
|
2591 |
+
'' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![.,:;]\s)',
|
2592 |
+
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
|
2593 |
+
'_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
|
2594 |
+
);
|
2595 |
+
var $strong_relist = array(
|
2596 |
+
'' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![.,:;]\s)',
|
2597 |
+
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
|
2598 |
+
'__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
|
2599 |
+
);
|
2600 |
+
var $em_strong_relist = array(
|
2601 |
+
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![.,:;]\s)',
|
2602 |
+
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
|
2603 |
+
'___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
|
2604 |
+
);
|
2605 |
+
|
2606 |
+
|
2607 |
+
function formParagraphs($text) {
|
2608 |
+
#
|
2609 |
+
# Params:
|
2610 |
+
# $text - string to process with html <p> tags
|
2611 |
+
#
|
2612 |
+
# Strip leading and trailing lines:
|
2613 |
+
$text = preg_replace('/\A\n+|\n+\z/', '', $text);
|
2614 |
+
|
2615 |
+
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
|
2616 |
+
|
2617 |
+
#
|
2618 |
+
# Wrap <p> tags and unhashify HTML blocks
|
2619 |
+
#
|
2620 |
+
foreach ($grafs as $key => $value) {
|
2621 |
+
$value = trim($this->runSpanGamut($value));
|
2622 |
+
|
2623 |
+
# Check if this should be enclosed in a paragraph.
|
2624 |
+
# Clean tag hashes & block tag hashes are left alone.
|
2625 |
+
$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
|
2626 |
+
|
2627 |
+
if ($is_p) {
|
2628 |
+
$value = "<p>$value</p>";
|
2629 |
+
}
|
2630 |
+
$grafs[$key] = $value;
|
2631 |
+
}
|
2632 |
+
|
2633 |
+
# Join grafs in one text, then unhash HTML tags.
|
2634 |
+
$text = implode("\n\n", $grafs);
|
2635 |
+
|
2636 |
+
# Finish by removing any tag hashes still present in $text.
|
2637 |
+
$text = $this->unhash($text);
|
2638 |
+
|
2639 |
+
return $text;
|
2640 |
+
}
|
2641 |
+
|
2642 |
+
|
2643 |
+
### Footnotes
|
2644 |
+
|
2645 |
+
function stripFootnotes($text) {
|
2646 |
+
#
|
2647 |
+
# Strips link definitions from text, stores the URLs and titles in
|
2648 |
+
# hash references.
|
2649 |
+
#
|
2650 |
+
$less_than_tab = $this->tab_width - 1;
|
2651 |
+
|
2652 |
+
# Link defs are in the form: [^id]: url "optional title"
|
2653 |
+
$text = preg_replace_callback('{
|
2654 |
+
^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1
|
2655 |
+
[ ]*
|
2656 |
+
\n? # maybe *one* newline
|
2657 |
+
( # text = $2 (no blank lines allowed)
|
2658 |
+
(?:
|
2659 |
+
.+ # actual text
|
2660 |
+
|
|
2661 |
+
\n # newlines but
|
2662 |
+
(?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
|
2663 |
+
(?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
|
2664 |
+
# by non-indented content
|
2665 |
+
)*
|
2666 |
+
)
|
2667 |
+
}xm',
|
2668 |
+
array(&$this, '_stripFootnotes_callback'),
|
2669 |
+
$text);
|
2670 |
+
return $text;
|
2671 |
+
}
|
2672 |
+
function _stripFootnotes_callback($matches) {
|
2673 |
+
$note_id = $this->fn_id_prefix . $matches[1];
|
2674 |
+
$this->footnotes[$note_id] = $this->outdent($matches[2]);
|
2675 |
+
return ''; # String that will replace the block
|
2676 |
+
}
|
2677 |
+
|
2678 |
+
|
2679 |
+
function doFootnotes($text) {
|
2680 |
+
#
|
2681 |
+
# Replace footnote references in $text [^id] with a special text-token
|
2682 |
+
# which will be replaced by the actual footnote marker in appendFootnotes.
|
2683 |
+
#
|
2684 |
+
if (!$this->in_anchor) {
|
2685 |
+
$text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
|
2686 |
+
}
|
2687 |
+
return $text;
|
2688 |
+
}
|
2689 |
+
|
2690 |
+
|
2691 |
+
function appendFootnotes($text) {
|
2692 |
+
#
|
2693 |
+
# Append footnote list to text.
|
2694 |
+
#
|
2695 |
+
$text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
|
2696 |
+
array(&$this, '_appendFootnotes_callback'), $text);
|
2697 |
+
|
2698 |
+
if (!empty($this->footnotes_ordered)) {
|
2699 |
+
$text .= "\n\n";
|
2700 |
+
$text .= "<div class=\"footnotes\">\n";
|
2701 |
+
$text .= "<hr". $this->empty_element_suffix ."\n";
|
2702 |
+
$text .= "<ol>\n\n";
|
2703 |
+
|
2704 |
+
$attr = " rev=\"footnote\"";
|
2705 |
+
if ($this->fn_backlink_class != "") {
|
2706 |
+
$class = $this->fn_backlink_class;
|
2707 |
+
$class = $this->encodeAttribute($class);
|
2708 |
+
$attr .= " class=\"$class\"";
|
2709 |
+
}
|
2710 |
+
if ($this->fn_backlink_title != "") {
|
2711 |
+
$title = $this->fn_backlink_title;
|
2712 |
+
$title = $this->encodeAttribute($title);
|
2713 |
+
$attr .= " title=\"$title\"";
|
2714 |
+
}
|
2715 |
+
$num = 0;
|
2716 |
+
|
2717 |
+
while (!empty($this->footnotes_ordered)) {
|
2718 |
+
$footnote = reset($this->footnotes_ordered);
|
2719 |
+
$note_id = key($this->footnotes_ordered);
|
2720 |
+
unset($this->footnotes_ordered[$note_id]);
|
2721 |
+
|
2722 |
+
$footnote .= "\n"; # Need to append newline before parsing.
|
2723 |
+
$footnote = $this->runBlockGamut("$footnote\n");
|
2724 |
+
$footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
|
2725 |
+
array(&$this, '_appendFootnotes_callback'), $footnote);
|
2726 |
+
|
2727 |
+
$attr = str_replace("%%", ++$num, $attr);
|
2728 |
+
$note_id = $this->encodeAttribute($note_id);
|
2729 |
+
|
2730 |
+
# Add backlink to last paragraph; create new paragraph if needed.
|
2731 |
+
$backlink = "<a href=\"#fnref:$note_id\"$attr>↩</a>";
|
2732 |
+
if (preg_match('{</p>$}', $footnote)) {
|
2733 |
+
$footnote = substr($footnote, 0, -4) . " $backlink</p>";
|
2734 |
+
} else {
|
2735 |
+
$footnote .= "\n\n<p>$backlink</p>";
|
2736 |
+
}
|
2737 |
+
|
2738 |
+
$text .= "<li id=\"fn:$note_id\">\n";
|
2739 |
+
$text .= $footnote . "\n";
|
2740 |
+
$text .= "</li>\n\n";
|
2741 |
+
}
|
2742 |
+
|
2743 |
+
$text .= "</ol>\n";
|
2744 |
+
$text .= "</div>";
|
2745 |
+
}
|
2746 |
+
return $text;
|
2747 |
+
}
|
2748 |
+
function _appendFootnotes_callback($matches) {
|
2749 |
+
$node_id = $this->fn_id_prefix . $matches[1];
|
2750 |
+
|
2751 |
+
# Create footnote marker only if it has a corresponding footnote *and*
|
2752 |
+
# the footnote hasn't been used by another marker.
|
2753 |
+
if (isset($this->footnotes[$node_id])) {
|
2754 |
+
# Transfert footnote content to the ordered list.
|
2755 |
+
$this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
|
2756 |
+
unset($this->footnotes[$node_id]);
|
2757 |
+
|
2758 |
+
$num = $this->footnote_counter++;
|
2759 |
+
$attr = " rel=\"footnote\"";
|
2760 |
+
if ($this->fn_link_class != "") {
|
2761 |
+
$class = $this->fn_link_class;
|
2762 |
+
$class = $this->encodeAttribute($class);
|
2763 |
+
$attr .= " class=\"$class\"";
|
2764 |
+
}
|
2765 |
+
if ($this->fn_link_title != "") {
|
2766 |
+
$title = $this->fn_link_title;
|
2767 |
+
$title = $this->encodeAttribute($title);
|
2768 |
+
$attr .= " title=\"$title\"";
|
2769 |
+
}
|
2770 |
+
|
2771 |
+
$attr = str_replace("%%", $num, $attr);
|
2772 |
+
$node_id = $this->encodeAttribute($node_id);
|
2773 |
+
|
2774 |
+
return
|
2775 |
+
"<sup id=\"fnref:$node_id\">".
|
2776 |
+
"<a href=\"#fn:$node_id\"$attr>$num</a>".
|
2777 |
+
"</sup>";
|
2778 |
+
}
|
2779 |
+
|
2780 |
+
return "[^".$matches[1]."]";
|
2781 |
+
}
|
2782 |
+
|
2783 |
+
|
2784 |
+
### Abbreviations ###
|
2785 |
+
|
2786 |
+
function stripAbbreviations($text) {
|
2787 |
+
#
|
2788 |
+
# Strips abbreviations from text, stores titles in hash references.
|
2789 |
+
#
|
2790 |
+
$less_than_tab = $this->tab_width - 1;
|
2791 |
+
|
2792 |
+
# Link defs are in the form: [id]*: url "optional title"
|
2793 |
+
$text = preg_replace_callback('{
|
2794 |
+
^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1
|
2795 |
+
(.*) # text = $2 (no blank lines allowed)
|
2796 |
+
}xm',
|
2797 |
+
array(&$this, '_stripAbbreviations_callback'),
|
2798 |
+
$text);
|
2799 |
+
return $text;
|
2800 |
+
}
|
2801 |
+
function _stripAbbreviations_callback($matches) {
|
2802 |
+
$abbr_word = $matches[1];
|
2803 |
+
$abbr_desc = $matches[2];
|
2804 |
+
if ($this->abbr_word_re)
|
2805 |
+
$this->abbr_word_re .= '|';
|
2806 |
+
$this->abbr_word_re .= preg_quote($abbr_word);
|
2807 |
+
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
|
2808 |
+
return ''; # String that will replace the block
|
2809 |
+
}
|
2810 |
+
|
2811 |
+
|
2812 |
+
function doAbbreviations($text) {
|
2813 |
+
#
|
2814 |
+
# Find defined abbreviations in text and wrap them in <abbr> elements.
|
2815 |
+
#
|
2816 |
+
if ($this->abbr_word_re) {
|
2817 |
+
// cannot use the /x modifier because abbr_word_re may
|
2818 |
+
// contain significant spaces:
|
2819 |
+
$text = preg_replace_callback('{'.
|
2820 |
+
'(?<![\w\x1A])'.
|
2821 |
+
'(?:'.$this->abbr_word_re.')'.
|
2822 |
+
'(?![\w\x1A])'.
|
2823 |
+
'}',
|
2824 |
+
array(&$this, '_doAbbreviations_callback'), $text);
|
2825 |
+
}
|
2826 |
+
return $text;
|
2827 |
+
}
|
2828 |
+
function _doAbbreviations_callback($matches) {
|
2829 |
+
$abbr = $matches[0];
|
2830 |
+
if (isset($this->abbr_desciptions[$abbr])) {
|
2831 |
+
$desc = $this->abbr_desciptions[$abbr];
|
2832 |
+
if (empty($desc)) {
|
2833 |
+
return $this->hashPart("<abbr>$abbr</abbr>");
|
2834 |
+
} else {
|
2835 |
+
$desc = $this->encodeAttribute($desc);
|
2836 |
+
return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
|
2837 |
+
}
|
2838 |
+
} else {
|
2839 |
+
return $matches[0];
|
2840 |
+
}
|
2841 |
+
}
|
2842 |
+
|
2843 |
+
}
|
2844 |
+
|
2845 |
+
|
2846 |
+
/*
|
2847 |
+
|
2848 |
+
PHP Markdown Extra
|
2849 |
+
==================
|
2850 |
+
|
2851 |
+
Description
|
2852 |
+
-----------
|
2853 |
+
|
2854 |
+
This is a PHP port of the original Markdown formatter written in Perl
|
2855 |
+
by John Gruber. This special "Extra" version of PHP Markdown features
|
2856 |
+
further enhancements to the syntax for making additional constructs
|
2857 |
+
such as tables and definition list.
|
2858 |
+
|
2859 |
+
Markdown is a text-to-HTML filter; it translates an easy-to-read /
|
2860 |
+
easy-to-write structured text format into HTML. Markdown's text format
|
2861 |
+
is most similar to that of plain text email, and supports features such
|
2862 |
+
as headers, *emphasis*, code blocks, blockquotes, and links.
|
2863 |
+
|
2864 |
+
Markdown's syntax is designed not as a generic markup language, but
|
2865 |
+
specifically to serve as a front-end to (X)HTML. You can use span-level
|
2866 |
+
HTML tags anywhere in a Markdown document, and you can use block level
|
2867 |
+
HTML tags (like <div> and <table> as well).
|
2868 |
+
|
2869 |
+
For more information about Markdown's syntax, see:
|
2870 |
+
|
2871 |
+
<http://daringfireball.net/projects/markdown/>
|
2872 |
+
|
2873 |
+
|
2874 |
+
Bugs
|
2875 |
+
----
|
2876 |
+
|
2877 |
+
To file bug reports please send email to:
|
2878 |
+
|
2879 |
+
<michel.fortin@michelf.com>
|
2880 |
+
|
2881 |
+
Please include with your report: (1) the example input; (2) the output you
|
2882 |
+
expected; (3) the output Markdown actually produced.
|
2883 |
+
|
2884 |
+
|
2885 |
+
Version History
|
2886 |
+
---------------
|
2887 |
+
|
2888 |
+
See the readme file for detailed release notes for this version.
|
2889 |
+
|
2890 |
+
|
2891 |
+
Copyright and License
|
2892 |
+
---------------------
|
2893 |
+
|
2894 |
+
PHP Markdown & Extra
|
2895 |
+
Copyright (c) 2004-2009 Michel Fortin
|
2896 |
+
<http://michelf.com/>
|
2897 |
+
All rights reserved.
|
2898 |
+
|
2899 |
+
Based on Markdown
|
2900 |
+
Copyright (c) 2003-2006 John Gruber
|
2901 |
+
<http://daringfireball.net/>
|
2902 |
+
All rights reserved.
|
2903 |
+
|
2904 |
+
Redistribution and use in source and binary forms, with or without
|
2905 |
+
modification, are permitted provided that the following conditions are
|
2906 |
+
met:
|
2907 |
+
|
2908 |
+
* Redistributions of source code must retain the above copyright notice,
|
2909 |
+
this list of conditions and the following disclaimer.
|
2910 |
+
|
2911 |
+
* Redistributions in binary form must reproduce the above copyright
|
2912 |
+
notice, this list of conditions and the following disclaimer in the
|
2913 |
+
documentation and/or other materials provided with the distribution.
|
2914 |
+
|
2915 |
+
* Neither the name "Markdown" nor the names of its contributors may
|
2916 |
+
be used to endorse or promote products derived from this software
|
2917 |
+
without specific prior written permission.
|
2918 |
+
|
2919 |
+
This software is provided by the copyright holders and contributors "as
|
2920 |
+
is" and any express or implied warranties, including, but not limited
|
2921 |
+
to, the implied warranties of merchantability and fitness for a
|
2922 |
+
particular purpose are disclaimed. In no event shall the copyright owner
|
2923 |
+
or contributors be liable for any direct, indirect, incidental, special,
|
2924 |
+
exemplary, or consequential damages (including, but not limited to,
|
2925 |
+
procurement of substitute goods or services; loss of use, data, or
|
2926 |
+
profits; or business interruption) however caused and on any theory of
|
2927 |
+
liability, whether in contract, strict liability, or tort (including
|
2928 |
+
negligence or otherwise) arising in any way out of the use of this
|
2929 |
+
software, even if advised of the possibility of such damage.
|
2930 |
+
|
2931 |
+
*/
|
2932 |
?>
|
includes/licensing.php
CHANGED
@@ -1,771 +1,771 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* What to print in place of license code chars.
|
5 |
-
* This must not be a symbol that is considered to be a valid license key char.
|
6 |
-
*
|
7 |
-
* @since 4.6.10
|
8 |
-
*/
|
9 |
-
define( 'WPRSS_LICENSE_KEY_MASK_CHAR', '•' );
|
10 |
-
/**
|
11 |
-
* How many characters of the license code to print as is.
|
12 |
-
* Use negative value to indicate that characters at the end of the key are excluded.
|
13 |
-
*
|
14 |
-
* @since 4.6.10
|
15 |
-
*/
|
16 |
-
define( 'WPRSS_LICENSE_KEY_MASK_EXCLUDE_AMOUNT', -4 );
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Returns all registered addons.
|
20 |
-
*
|
21 |
-
* @since 4.4.5
|
22 |
-
*/
|
23 |
-
function wprss_get_addons() {
|
24 |
-
return apply_filters( 'wprss_register_addon', array() );
|
25 |
-
}
|
26 |
-
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Calls the EDD Software Licensing API to perform licensing tasks on the addon's store server.
|
30 |
-
*
|
31 |
-
* @since 4.4.5
|
32 |
-
*/
|
33 |
-
function wprss_edd_licensing_api( $addon, $license_key = NULL, $action = 'check_license', $return = 'license' ) {
|
34 |
-
// If no license argument was given
|
35 |
-
if ( $license_key === NULL ) {
|
36 |
-
// Get the license key
|
37 |
-
$license_key = wprss_get_license_key( $addon );
|
38 |
-
}
|
39 |
-
// Get the license status from the DB
|
40 |
-
$license_status = wprss_get_license_status( $addon );
|
41 |
-
|
42 |
-
// Prepare constants
|
43 |
-
$item_name = strtoupper( $addon );
|
44 |
-
$item_name_constant = constant( "WPRSS_{$item_name}_SL_ITEM_NAME" );
|
45 |
-
$store_url_constant = constant( "WPRSS_{$item_name}_SL_STORE_URL" );
|
46 |
-
|
47 |
-
// data to send in our API request
|
48 |
-
$api_params = array(
|
49 |
-
'edd_action' => $action,
|
50 |
-
'license' => sanitize_text_field( $license_key ),
|
51 |
-
'item_name' => urlencode( $item_name_constant ),
|
52 |
-
'url' => urlencode( network_site_url() ),
|
53 |
-
'time' => time(),
|
54 |
-
);
|
55 |
-
|
56 |
-
// Send the request to the API
|
57 |
-
$response = wp_remote_get( add_query_arg( $api_params, $store_url_constant ) );
|
58 |
-
|
59 |
-
// If the response is an error, return the value in the DB
|
60 |
-
if ( is_wp_error( $response ) ) {
|
61 |
-
return $license_status;
|
62 |
-
}
|
63 |
-
|
64 |
-
// decode the license data
|
65 |
-
$license_data = json_decode( wp_remote_retrieve_body( $response ) );
|
66 |
-
|
67 |
-
// Update the DB option
|
68 |
-
$license_statuses = get_option( 'wprss_settings_license_statuses' );
|
69 |
-
$license_statuses["{$addon}_license_status"] = $license_data->license;
|
70 |
-
$license_statuses["{$addon}_license_expires"] = $license_data->expires;
|
71 |
-
update_option( 'wprss_settings_license_statuses', $license_statuses );
|
72 |
-
|
73 |
-
// Return the data
|
74 |
-
if ( strtoupper( $return ) === 'ALL' ) {
|
75 |
-
return $license_data;
|
76 |
-
} else {
|
77 |
-
return $license_data->$return;
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Returns the license status. Also updates the status in the DB.
|
84 |
-
*
|
85 |
-
* @since 4.4.5
|
86 |
-
*/
|
87 |
-
function wprss_edd_check_license( $addon, $license_key = NULL, $return = 'license' ) {
|
88 |
-
return wprss_edd_licensing_api( $addon, $license_key, 'check_license', $return );
|
89 |
-
}
|
90 |
-
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Activates an addon's license.
|
94 |
-
*
|
95 |
-
* @since 4.4.5
|
96 |
-
*/
|
97 |
-
function wprss_edd_activate_license( $addon, $license_key = NULL ) {
|
98 |
-
return wprss_edd_licensing_api( $addon, $license_key, 'activate_license' );
|
99 |
-
}
|
100 |
-
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Deactivates an addon's license.
|
104 |
-
*
|
105 |
-
* @since 4.4.5
|
106 |
-
*/
|
107 |
-
function wprss_edd_deactivate_license( $addon, $license_key = NULL ) {
|
108 |
-
return wprss_edd_licensing_api( $addon, $license_key, 'deactivate_license' );
|
109 |
-
}
|
110 |
-
|
111 |
-
|
112 |
-
/**
|
113 |
-
* Returns an array of the default license settings. Used for plugin activation.
|
114 |
-
*
|
115 |
-
* @since 4.4.5
|
116 |
-
*
|
117 |
-
*/
|
118 |
-
function wprss_default_license_settings( $addon ) {
|
119 |
-
// Set up the default license settings
|
120 |
-
$settings = apply_filters(
|
121 |
-
'wprss_default_license_settings',
|
122 |
-
array(
|
123 |
-
"{$addon}_license_key" => FALSE,
|
124 |
-
"{$addon}_license_status" => 'invalid',
|
125 |
-
"{$addon}_license_expires" => NULL
|
126 |
-
)
|
127 |
-
);
|
128 |
-
|
129 |
-
// Return the default settings
|
130 |
-
return $settings;
|
131 |
-
}
|
132 |
-
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Returns the saved license code.
|
136 |
-
*
|
137 |
-
* @since 4.4.5
|
138 |
-
*/
|
139 |
-
function wprss_get_license_key( $addon ) {
|
140 |
-
// Get default and current options
|
141 |
-
$defaults = wprss_default_license_settings( $addon );
|
142 |
-
$keys = get_option( 'wprss_settings_license_keys', array() );
|
143 |
-
// Prepare the array key and target
|
144 |
-
$k = "{$addon}_license_key";
|
145 |
-
// Return the appropriate value
|
146 |
-
return isset( $keys["{$addon}_license_key"] )? $keys[$k] : $defaults[$k];
|
147 |
-
}
|
148 |
-
|
149 |
-
|
150 |
-
/**
|
151 |
-
* Returns the saved license code.
|
152 |
-
*
|
153 |
-
* @since 4.4.5
|
154 |
-
*/
|
155 |
-
function wprss_get_license_status( $addon ) {
|
156 |
-
// Get the default and current options
|
157 |
-
$defaults = wprss_default_license_settings( $addon );
|
158 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
159 |
-
// Prepare the key
|
160 |
-
$k = "{$addon}_license_status";
|
161 |
-
// Return the appropriate value
|
162 |
-
return isset( $statuses["{$addon}_license_status"] )? $statuses[$k] : $defaults[$k];
|
163 |
-
}
|
164 |
-
|
165 |
-
|
166 |
-
/**
|
167 |
-
* Returns the saved license expiry.
|
168 |
-
*
|
169 |
-
* @since 4.6.7
|
170 |
-
*/
|
171 |
-
function wprss_get_license_expiry( $addon ) {
|
172 |
-
// Get default and current options
|
173 |
-
$defaults = wprss_default_license_settings( $addon );
|
174 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
175 |
-
// Prepare the key
|
176 |
-
$k = "{$addon}_license_expires";
|
177 |
-
// Return the appropriate value
|
178 |
-
return isset( $statuses[$k] ) ? $statuses[$k] : $defaults[$k];
|
179 |
-
}
|
180 |
-
|
181 |
-
|
182 |
-
add_action( 'admin_init', 'wprss_check_to_show_license_notice');
|
183 |
-
/**
|
184 |
-
* Checks whether there are any invalid or expired licenses.
|
185 |
-
*
|
186 |
-
* @since 4.6.10
|
187 |
-
* @return BOOL which is TRUE if any addons are unlicensed, FALSE otherwise.
|
188 |
-
*/
|
189 |
-
function wprss_unlicensed_addons_exist() {
|
190 |
-
// Get the license statuses including expiry dates.
|
191 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
192 |
-
|
193 |
-
foreach ($statuses as $key => $value) {
|
194 |
-
if ( strpos($key, '_license_status') > 0 ) {
|
195 |
-
if ( $value !== 'valid') {
|
196 |
-
return TRUE;
|
197 |
-
}
|
198 |
-
} else if ( strpos($key, '_license_expires') > 0 ) {
|
199 |
-
// Check invalid expiry dates.
|
200 |
-
$expires = strtotime( substr( $value, 0, strpos( $value, " " ) ) );
|
201 |
-
|
202 |
-
if ( $expires == 0 || ( $expires < strtotime("+2 weeks") ) ) {
|
203 |
-
return TRUE;
|
204 |
-
}
|
205 |
-
}
|
206 |
-
}
|
207 |
-
|
208 |
-
return FALSE;
|
209 |
-
}
|
210 |
-
|
211 |
-
/**
|
212 |
-
* Check if any add-ons have a valid license and return a boolean.
|
213 |
-
*
|
214 |
-
* @since 4.6.8
|
215 |
-
*/
|
216 |
-
function wprss_is_premium_user() {
|
217 |
-
// Iterate through license statuses looking for a valid one.
|
218 |
-
$statuses = get_option('wprss_settings_license_statuses', array());
|
219 |
-
foreach ($statuses as $key => $value) {
|
220 |
-
// If we're looking at a license status key...
|
221 |
-
if (strpos($key, '_license_status') !== FALSE) {
|
222 |
-
// ...and the license is valid...
|
223 |
-
if ($value === 'valid') {
|
224 |
-
return TRUE;
|
225 |
-
}
|
226 |
-
}
|
227 |
-
}
|
228 |
-
|
229 |
-
return FALSE;
|
230 |
-
}
|
231 |
-
|
232 |
-
/**
|
233 |
-
* Returns an array of addon IDs that are licensed.
|
234 |
-
*
|
235 |
-
* @since 4.6.10
|
236 |
-
* @return Array of addon ID strings that have a valid license status.
|
237 |
-
*/
|
238 |
-
function wprss_get_licensed_addons() {
|
239 |
-
$addons = array();
|
240 |
-
|
241 |
-
// Get the license statuses.
|
242 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
243 |
-
|
244 |
-
foreach ($statuses as $key => $value) {
|
245 |
-
if ( strpos($key, '_license_status') > 0 ) {
|
246 |
-
if ( $value === 'valid') {
|
247 |
-
$addons[] = strtoupper( substr( $key, 0, strpos( $key, "_" ) ) );
|
248 |
-
}
|
249 |
-
}
|
250 |
-
}
|
251 |
-
|
252 |
-
return $addons;
|
253 |
-
|
254 |
-
}
|
255 |
-
|
256 |
-
|
257 |
-
/**
|
258 |
-
* Checks whether we should show the invalid/expired license notices.
|
259 |
-
*
|
260 |
-
* @since 4.6.10
|
261 |
-
*/
|
262 |
-
function wprss_check_to_show_license_notice() {
|
263 |
-
// Check if we found any of the licenses to be invalid, expiring or expired
|
264 |
-
// so that we can show the appropriate license nag.
|
265 |
-
if (wprss_unlicensed_addons_exist()) {
|
266 |
-
add_action( 'all_admin_notices', 'wprss_show_license_notice' );
|
267 |
-
}
|
268 |
-
}
|
269 |
-
|
270 |
-
|
271 |
-
/**
|
272 |
-
* Shows an admin notice for any invalid/expired licenses.
|
273 |
-
*
|
274 |
-
* @since 4.6.9
|
275 |
-
*/
|
276 |
-
function wprss_show_license_notice() {
|
277 |
-
// Get the license statuses including expiry dates.
|
278 |
-
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
279 |
-
|
280 |
-
// Array of notices to show.
|
281 |
-
$notices = array();
|
282 |
-
|
283 |
-
foreach ($statuses as $key => $value) {
|
284 |
-
if ( strpos($key, '_license_status') > 0 ) {
|
285 |
-
if ( $value === 'expired' ) {
|
286 |
-
// License is expired, but we'll show the notice for this when checking the *_license_expires key.
|
287 |
-
|
288 |
-
continue;
|
289 |
-
|
290 |
-
} else if ( $value !== 'valid' ) {
|
291 |
-
// The license is invalid or unactivated.
|
292 |
-
|
293 |
-
$uid = strtoupper( substr( $key, 0, strpos( $key, "_" ) ) );
|
294 |
-
|
295 |
-
// Check if the plugin is currently activated.
|
296 |
-
if ( !defined("WPRSS_{$uid}_SL_ITEM_NAME") ) {
|
297 |
-
continue;
|
298 |
-
} else {
|
299 |
-
$plugin = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
300 |
-
}
|
301 |
-
|
302 |
-
$msg = sprintf(
|
303 |
-
__( 'Remember to <a href="%s">enter your plugin license code</a> for the WP RSS Aggregator <b>%s</b> add-on to benefit from updates and support.', WPRSS_TEXT_DOMAIN ),
|
304 |
-
esc_attr(admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' )),
|
305 |
-
$plugin
|
306 |
-
);
|
307 |
-
|
308 |
-
// Save the notice we're going to display
|
309 |
-
$notices[$uid] = '<div id="wprss-license-notice-' . $uid . '" class="error wprss-license-notice"><p>' . $msg . '</p></div>';
|
310 |
-
}
|
311 |
-
} else if ( strpos($key, '_license_expires') > 0 ) {
|
312 |
-
// Check for expired licenses
|
313 |
-
|
314 |
-
$expires = strtotime( substr( $value, 0, strpos( $value, " " ) ) );
|
315 |
-
$id = substr( $key, 0, strpos( $key, "_" ) );
|
316 |
-
$uid = strtoupper($id);
|
317 |
-
|
318 |
-
// Check if the plugin is currently activated.
|
319 |
-
if ( !defined("WPRSS_{$uid}_SL_ITEM_NAME") ) {
|
320 |
-
continue;
|
321 |
-
} else {
|
322 |
-
$plugin = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
323 |
-
}
|
324 |
-
|
325 |
-
if ( $expires < strtotime("+2 weeks") ) {
|
326 |
-
// The license is expired or expiring soon.
|
327 |
-
$license_key = wprss_get_license_key($id);
|
328 |
-
$msg = sprintf(
|
329 |
-
__('<a href="%s">Save 30%% on your license renewal</a> for the WP RSS Aggregator <b>%s</b> add-on and continue receiving updates and support.', WPRSS_TEXT_DOMAIN),
|
330 |
-
esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $license_key),
|
331 |
-
$plugin
|
332 |
-
);
|
333 |
-
|
334 |
-
// User can hide expiring/expired license messages.
|
335 |
-
$hide = '<a href="#" class="ajax-close-addon-notice" style="float:right;" data-addon="categories" data-notice="license">' .
|
336 |
-
__('Dismiss this notification', WPRSS_TEXT_DOMAIN) . '</a>';
|
337 |
-
|
338 |
-
// Only show this notice if there isn't already a notice to show for this add-on.
|
339 |
-
if ( !isset($notices[$uid]) ) {
|
340 |
-
$notices[$uid] = '<div class="error wprss-license-notice"><p>' . $msg . $hide . '</p></div>';
|
341 |
-
}
|
342 |
-
}
|
343 |
-
}
|
344 |
-
}
|
345 |
-
|
346 |
-
// Display the notices
|
347 |
-
foreach ($notices as $notice) {
|
348 |
-
echo $notice;
|
349 |
-
}
|
350 |
-
}
|
351 |
-
|
352 |
-
|
353 |
-
add_action( 'wp_ajax_wprss_ajax_manage_license', 'wprss_ajax_manage_license' );
|
354 |
-
/**
|
355 |
-
* Handles the AJAX request to check a license.
|
356 |
-
*
|
357 |
-
* @since 4.7
|
358 |
-
*/
|
359 |
-
function wprss_ajax_manage_license() {
|
360 |
-
// Get and sanitize the addon ID we're checking.
|
361 |
-
if ( isset($_GET['addon']) ) {
|
362 |
-
$addon = sanitize_text_field($_GET['addon']);
|
363 |
-
} else {
|
364 |
-
wprss_echo_error_and_die( __('No addon ID', WPRSS_TEXT_DOMAIN ));
|
365 |
-
}
|
366 |
-
|
367 |
-
// Check what we've been asked to do with the license.
|
368 |
-
if ( isset($_GET['event']) ) {
|
369 |
-
$event = sanitize_text_field($_GET['event']);
|
370 |
-
|
371 |
-
if ($event !== 'activate' && $event !== 'deactivate') {
|
372 |
-
wprss_echo_error_and_die( __('Invalid event specified', WPRSS_TEXT_DOMAIN), $addon);
|
373 |
-
}
|
374 |
-
} else {
|
375 |
-
wprss_echo_error_and_die( __('No event specified', WPRSS_TEXT_DOMAIN), $addon);
|
376 |
-
}
|
377 |
-
|
378 |
-
// Get and sanitize the license that was entered.
|
379 |
-
if ( isset($_GET['license']) ) {
|
380 |
-
$license = sanitize_text_field($_GET['license']);
|
381 |
-
} else {
|
382 |
-
wprss_echo_error_and_die( __('No license', WPRSS_TEXT_DOMAIN), $addon);
|
383 |
-
}
|
384 |
-
|
385 |
-
// Check the nonce for this particular add-on's validation button.
|
386 |
-
if ( isset($_GET['nonce']) ) {
|
387 |
-
$nonce = sanitize_text_field($_GET['nonce']);
|
388 |
-
$nonce_id = "wprss_{$addon}_license_nonce";
|
389 |
-
|
390 |
-
if ( !wp_verify_nonce($nonce, $nonce_id) ) {
|
391 |
-
wprss_echo_error_and_die( __('Bad nonce', WPRSS_TEXT_DOMAIN), $addon);
|
392 |
-
}
|
393 |
-
} else {
|
394 |
-
wprss_echo_error_and_die( __('No nonce', WPRSS_TEXT_DOMAIN), $addon);
|
395 |
-
}
|
396 |
-
|
397 |
-
$license_keys = get_option('wprss_settings_license_keys', array());
|
398 |
-
// Check if the license key was obfuscated on the client's end.
|
399 |
-
if ( wprss_license_key_is_obfuscated( $license ) ) {
|
400 |
-
// If so, use the stored license key for de/activation.
|
401 |
-
$license = $license_keys[$addon . '_license_key'];
|
402 |
-
} else {
|
403 |
-
// Otherwise, update the license key stored in the DB.
|
404 |
-
$license_keys[$addon . '_license_key'] = $license;
|
405 |
-
update_option('wprss_settings_license_keys', $license_keys);
|
406 |
-
}
|
407 |
-
|
408 |
-
// Call the appropriate EDD licensing function.
|
409 |
-
if ($event === 'activate') {
|
410 |
-
$status = wprss_edd_activate_license($addon, $license);
|
411 |
-
} else if ($event === 'deactivate') {
|
412 |
-
$status = wprss_edd_deactivate_license($addon, $license);
|
413 |
-
} else {
|
414 |
-
wprss_echo_error_and_die( __('Invalid event specified', WPRSS_TEXT_DOMAIN), $addon);
|
415 |
-
}
|
416 |
-
|
417 |
-
// Assemble the JSON data to return.
|
418 |
-
$ret = array();
|
419 |
-
|
420 |
-
// Set the validity of the license.
|
421 |
-
if ( $status === 'site_inactive' ) $status = 'inactive';
|
422 |
-
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
423 |
-
$ret['validity'] = $status;
|
424 |
-
|
425 |
-
// Set the addon ID for use in the callback.
|
426 |
-
$ret['addon'] = $addon;
|
427 |
-
|
428 |
-
// Set the HTML markup for the new button and validity display.
|
429 |
-
$ret['html'] = wprss_get_activate_license_button($addon);
|
430 |
-
|
431 |
-
$ret['licensedAddons'] = wprss_get_licensed_addons();
|
432 |
-
|
433 |
-
// Return the JSON data.
|
434 |
-
echo json_encode($ret);
|
435 |
-
die();
|
436 |
-
}
|
437 |
-
|
438 |
-
|
439 |
-
add_action( 'wp_ajax_wprss_ajax_fetch_license', 'wprss_ajax_fetch_license' );
|
440 |
-
/**
|
441 |
-
* Handles the AJAX request to fetch a license's information.
|
442 |
-
*
|
443 |
-
* @since 4.7
|
444 |
-
*/
|
445 |
-
function wprss_ajax_fetch_license() {
|
446 |
-
// Get and sanitize the addon ID we're checking.
|
447 |
-
if ( isset($_GET['addon']) ) {
|
448 |
-
$addon = sanitize_text_field($_GET['addon']);
|
449 |
-
} else {
|
450 |
-
wprss_echo_error_and_die( __('No addon ID', WPRSS_TEXT_DOMAIN ));
|
451 |
-
}
|
452 |
-
|
453 |
-
// Get the license information from EDD
|
454 |
-
$ret = wprss_edd_check_license( $addon, NULL, 'ALL' );
|
455 |
-
|
456 |
-
echo json_encode($ret);
|
457 |
-
die();
|
458 |
-
}
|
459 |
-
|
460 |
-
|
461 |
-
/**
|
462 |
-
* Helper function that echoes a JSON error along with the new
|
463 |
-
* activate/deactivate license button HTML markup and then die()s.
|
464 |
-
*
|
465 |
-
* @since 4.7
|
466 |
-
*/
|
467 |
-
function wprss_echo_error_and_die($msg, $addon = '') {
|
468 |
-
$ret = array(
|
469 |
-
'error' => $msg,
|
470 |
-
'html' => wprss_get_activate_license_button($addon)
|
471 |
-
);
|
472 |
-
|
473 |
-
echo json_encode($ret);
|
474 |
-
die();
|
475 |
-
}
|
476 |
-
|
477 |
-
|
478 |
-
add_action( 'wprss_admin_init', 'wprss_license_settings', 100 );
|
479 |
-
/**
|
480 |
-
* Adds the license sections and settings for registered add-ons.
|
481 |
-
*
|
482 |
-
* @since 4.4.5
|
483 |
-
*/
|
484 |
-
function wprss_license_settings() {
|
485 |
-
$addons = wprss_get_addons();
|
486 |
-
foreach( $addons as $addon_id => $addon_name ) {
|
487 |
-
// Settings Section
|
488 |
-
add_settings_section(
|
489 |
-
"wprss_settings_{$addon_id}_licenses_section",
|
490 |
-
$addon_name .' '. __( 'License', WPRSS_TEXT_DOMAIN ),
|
491 |
-
'__return_empty_string',
|
492 |
-
'wprss_settings_license_keys'
|
493 |
-
);
|
494 |
-
// License key field
|
495 |
-
add_settings_field(
|
496 |
-
"wprss_settings_{$addon_id}_license",
|
497 |
-
__( 'License Key', WPRSS_TEXT_DOMAIN ),
|
498 |
-
'wprss_license_key_field',
|
499 |
-
'wprss_settings_license_keys',
|
500 |
-
"wprss_settings_{$addon_id}_licenses_section",
|
501 |
-
array( $addon_id )
|
502 |
-
);
|
503 |
-
// Activate license button
|
504 |
-
add_settings_field(
|
505 |
-
"wprss_settings_{$addon_id}_activate_license",
|
506 |
-
__( 'Activate License', WPRSS_TEXT_DOMAIN ),
|
507 |
-
'wprss_activate_license_button',
|
508 |
-
'wprss_settings_license_keys',
|
509 |
-
"wprss_settings_{$addon_id}_licenses_section",
|
510 |
-
array( $addon_id )
|
511 |
-
);
|
512 |
-
}
|
513 |
-
}
|
514 |
-
|
515 |
-
|
516 |
-
/**
|
517 |
-
* Renders the license field for a particular add-on.
|
518 |
-
*
|
519 |
-
* @since 4.4.5
|
520 |
-
*/
|
521 |
-
function wprss_license_key_field( $args ) {
|
522 |
-
$addon_id = $args[0];
|
523 |
-
$license_key = wprss_get_license_key( $addon_id );
|
524 |
-
$license_key_length = strlen( $license_key );
|
525 |
-
$mask_char = WPRSS_LICENSE_KEY_MASK_CHAR;
|
526 |
-
// How many chars to show
|
527 |
-
$mask_exclude_amount = WPRSS_LICENSE_KEY_MASK_EXCLUDE_AMOUNT;
|
528 |
-
$mask_exclude_amount = abs( $mask_exclude_amount ) > ($license_key_length - 1)
|
529 |
-
? ($license_key_length - 1) * ( $mask_exclude_amount < 0 ? -1 : 1 ) // Making sure to preserve position of mask
|
530 |
-
: $mask_exclude_amount;
|
531 |
-
// How many chars to mask. Always at least one char will be masked.
|
532 |
-
$mask_length = $license_key_length - abs( $mask_exclude_amount );
|
533 |
-
$mask = $mask_length > 0 ? str_repeat( $mask_char, $mask_length ) : '';
|
534 |
-
$excluded_chars = mb_substr( $license_key, $mask_exclude_amount < 0 ? $mask_length : 0, abs( $mask_exclude_amount ) );
|
535 |
-
$displayed_key = sprintf( $mask_exclude_amount > 0 ? '%1$s%2$s' : '%2$s%1$s', $excluded_chars, $mask); ?>
|
536 |
-
<input id="wprss-<?php echo $addon_id ?>-license-key" name="wprss_settings_license_keys[<?php echo $addon_id ?>_license_key]"
|
537 |
-
type="text" value="<?php echo esc_attr( $displayed_key ) ?>" style="width: 300px;"
|
538 |
-
/>
|
539 |
-
<label class="description" for="wprss-<?php echo $addon_id ?>-license-key">
|
540 |
-
<?php _e( 'Enter your license key', WPRSS_TEXT_DOMAIN ) ?>
|
541 |
-
</label><?php
|
542 |
-
}
|
543 |
-
|
544 |
-
|
545 |
-
/**
|
546 |
-
* Renders the activate/deactivate license button for a particular add-on.
|
547 |
-
*
|
548 |
-
* @since 4.4.5
|
549 |
-
*/
|
550 |
-
function wprss_activate_license_button( $args ) {
|
551 |
-
$addon_id = $args[0];
|
552 |
-
$data = wprss_edd_check_license( $addon_id, NULL, 'ALL' );
|
553 |
-
$status = is_string( $data ) ? $data : $data->license;
|
554 |
-
if ( $status === 'site_inactive' ) $status = 'inactive';
|
555 |
-
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
556 |
-
|
557 |
-
$valid = $status == 'valid';
|
558 |
-
$btn_text = $valid ? 'Deactivate License' : 'Activate License';
|
559 |
-
$btn_name = "wprss_{$addon_id}_license_" . ( $valid? 'deactivate' : 'activate' );
|
560 |
-
$btn_class = "button-" . ( $valid ? 'deactivate' : 'activate' ) . "-license";
|
561 |
-
wp_nonce_field( "wprss_{$addon_id}_license_nonce", "wprss_{$addon_id}_license_nonce", false ); ?>
|
562 |
-
|
563 |
-
<input type="button" class="<?php echo $btn_class; ?> button-process-license button-secondary" name="<?php echo $btn_name; ?>" value="<?php _e( $btn_text, WPRSS_TEXT_DOMAIN ); ?>" />
|
564 |
-
<span id="wprss-<?php echo $addon_id; ?>-license-status-text">
|
565 |
-
<strong><?php _e('Status', WPRSS_TEXT_DOMAIN); ?>:
|
566 |
-
<span class="wprss-<?php echo $addon_id; ?>-license-<?php echo $status; ?>">
|
567 |
-
<?php _e( ucfirst($status), WPRSS_TEXT_DOMAIN ); ?>
|
568 |
-
<?php if ( $status === 'valid' ) : ?>
|
569 |
-
<i class="fa fa-check"></i>
|
570 |
-
<?php elseif( $status === 'invalid' || $status === 'expired' ): ?>
|
571 |
-
<i class="fa fa-times"></i>
|
572 |
-
<?php elseif( $status === 'inactive' ): ?>
|
573 |
-
<i class="fa fa-warning"></i>
|
574 |
-
<?php endif; ?>
|
575 |
-
</strong>
|
576 |
-
</span>
|
577 |
-
</span>
|
578 |
-
|
579 |
-
<p>
|
580 |
-
<?php
|
581 |
-
$license_key = wprss_get_license_key( $addon_id );
|
582 |
-
if ( ! empty( $license_key ) ) :
|
583 |
-
if ( is_object( $data ) ) :
|
584 |
-
$acts_current = $data->site_count;
|
585 |
-
$acts_left = $data->activations_left;
|
586 |
-
$acts_limit = $data->license_limit;
|
587 |
-
$expires = $data->expires;
|
588 |
-
$expires = substr( $expires, 0, strpos( $expires, " " ) );
|
589 |
-
|
590 |
-
// If the license key is garbage, don't show any of the data.
|
591 |
-
if ( !empty($data->payment_id) && !empty($data->license_limit ) ) :
|
592 |
-
?>
|
593 |
-
<small>
|
594 |
-
<?php if ( $status !== 'valid' && $acts_left === 0 ) : ?>
|
595 |
-
<?php $account_url = 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=' . $data->payment_id; ?>
|
596 |
-
<a href="<?php echo $account_url; ?>"><?php _e("No activations left. Click here to manage the sites you've activated licenses on.", WPRSS_TEXT_DOMAIN); ?></a>
|
597 |
-
<br/>
|
598 |
-
<?php endif; ?>
|
599 |
-
<?php if ( strtotime($expires) < strtotime("+2 weeks") ) : ?>
|
600 |
-
<?php $renewal_url = esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $license_key); ?>
|
601 |
-
<a href="<?php echo $renewal_url; ?>"><?php _e('Renew your license to continue receiving updates and support.', WPRSS_TEXT_DOMAIN); ?></a>
|
602 |
-
<br/>
|
603 |
-
<?php endif; ?>
|
604 |
-
<strong><?php _e('Activations', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
605 |
-
<?php echo $acts_current.'/'.$acts_limit; ?> (<?php echo $acts_left; ?> left)
|
606 |
-
<br/>
|
607 |
-
<strong><?php _e('Expires on', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
608 |
-
<code><?php echo $expires; ?></code>
|
609 |
-
<br/>
|
610 |
-
<strong><?php _e('Registered to', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
611 |
-
<?php echo $data->customer_name; ?> (<code><?php echo $data->customer_email; ?></code>)
|
612 |
-
</small>
|
613 |
-
<?php endif; ?>
|
614 |
-
<?php else: ?>
|
615 |
-
<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>
|
616 |
-
<?php endif; ?>
|
617 |
-
<?php endif;
|
618 |
-
?>
|
619 |
-
</p>
|
620 |
-
|
621 |
-
<style type="text/css">
|
622 |
-
.wprss-<?php echo $addon_id; ?>-license-valid {
|
623 |
-
color: green;
|
624 |
-
}
|
625 |
-
.wprss-<?php echo $addon_id; ?>-license-invalid, .wprss-<?php echo $addon_id; ?>-license-expired {
|
626 |
-
color: #b71919;
|
627 |
-
}
|
628 |
-
.wprss-<?php echo $addon_id; ?>-license-inactive {
|
629 |
-
color: #d19e5b;
|
630 |
-
}
|
631 |
-
#wprss-<?php echo $addon_id; ?>-license-status-text {
|
632 |
-
margin-left: 8px;
|
633 |
-
line-height: 27px;
|
634 |
-
vertical-align: middle;
|
635 |
-
}
|
636 |
-
</style>
|
637 |
-
|
638 |
-
|
639 |
-
<?php
|
640 |
-
}
|
641 |
-
|
642 |
-
|
643 |
-
/**
|
644 |
-
* Returns the activate/deactivate license button markup for a particular add-on.
|
645 |
-
*
|
646 |
-
* @since 4.7
|
647 |
-
*/
|
648 |
-
function wprss_get_activate_license_button( $addon ) {
|
649 |
-
// Buffer the output from the rendering function.
|
650 |
-
ob_start();
|
651 |
-
|
652 |
-
wprss_activate_license_button(array($addon));
|
653 |
-
$ret = ob_get_contents();
|
654 |
-
|
655 |
-
ob_end_clean();
|
656 |
-
|
657 |
-
return $ret;
|
658 |
-
}
|
659 |
-
|
660 |
-
|
661 |
-
add_action( 'admin_init', 'wprss_process_addon_license', 10 );
|
662 |
-
/**
|
663 |
-
* Handles the activation/deactivation process
|
664 |
-
*
|
665 |
-
* @since 1.0
|
666 |
-
*/
|
667 |
-
function wprss_process_addon_license() {
|
668 |
-
$addons = wprss_get_addons();
|
669 |
-
|
670 |
-
// Get for each registered addon
|
671 |
-
foreach( $addons as $id => $name ) {
|
672 |
-
|
673 |
-
// listen for our activate button to be clicked
|
674 |
-
if( isset( $_POST["wprss_{$id}_license_activate"] ) || isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
675 |
-
// run a quick security check
|
676 |
-
if( ! check_admin_referer( "wprss_{$id}_license_nonce", "wprss_{$id}_license_nonce" ) )
|
677 |
-
continue; // get out if we didn't click the Activate/Deactivate button
|
678 |
-
}
|
679 |
-
|
680 |
-
// retrieve the license keys and statuses from the database
|
681 |
-
$license = wprss_get_license_key( $id );
|
682 |
-
$license_statuses = get_option( 'wprss_settings_license_statuses' );
|
683 |
-
|
684 |
-
// If the license is not saved in DB, but is included in POST
|
685 |
-
if ( $license == '' && !empty($_POST['wprss_settings_license_keys'][$id.'_license_key']) ) {
|
686 |
-
// Use the license given in POST
|
687 |
-
$license = $_POST['wprss_settings_license_keys'][$id.'_license_key'];
|
688 |
-
}
|
689 |
-
|
690 |
-
// Prepare the action to take
|
691 |
-
if ( isset( $_POST["wprss_{$id}_license_activate"] ) ) {
|
692 |
-
wprss_edd_activate_license( $id, $license );
|
693 |
-
}
|
694 |
-
elseif ( isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
695 |
-
wprss_edd_deactivate_license( $id, $license );
|
696 |
-
}
|
697 |
-
}
|
698 |
-
}
|
699 |
-
|
700 |
-
|
701 |
-
add_action( 'init', 'wprss_setup_edd_updater' );
|
702 |
-
/**
|
703 |
-
* Sets up the EDD updater for all registered add-ons.
|
704 |
-
*
|
705 |
-
* @since 4.6.3
|
706 |
-
*/
|
707 |
-
function wprss_setup_edd_updater() {
|
708 |
-
// Get all registered addons
|
709 |
-
$addons = wprss_get_addons();
|
710 |
-
|
711 |
-
// retrieve our license key from the DB
|
712 |
-
$licenses = get_option( 'wprss_settings_license_keys' );
|
713 |
-
|
714 |
-
// setup the updater
|
715 |
-
if ( !class_exists( 'EDD_SL_Plugin_Updater' ) ) {
|
716 |
-
// load our custom updater
|
717 |
-
include ( WPRSS_INC . 'libraries/EDD_licensing/EDD_SL_Plugin_Updater.php' );
|
718 |
-
}
|
719 |
-
|
720 |
-
// Iterate the addons
|
721 |
-
foreach( $addons as $id => $name ) {
|
722 |
-
// Prepare the data
|
723 |
-
$license = wprss_get_license_key( $id );
|
724 |
-
$uid = strtoupper( $id );
|
725 |
-
$name = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
726 |
-
$version = constant("WPRSS_{$uid}_VERSION");
|
727 |
-
$path = constant("WPRSS_{$uid}_PATH");
|
728 |
-
// Set up an updater
|
729 |
-
$edd_updater = new EDD_SL_Plugin_Updater( WPRSS_SL_STORE_URL, $path, array(
|
730 |
-
'version' => $version, // current version number
|
731 |
-
'license' => $license, // license key (used get_option above to retrieve from DB)
|
732 |
-
'item_name' => $name, // name of this plugin
|
733 |
-
'author' => 'Jean Galea' // author of this plugin
|
734 |
-
));
|
735 |
-
}
|
736 |
-
}
|
737 |
-
|
738 |
-
|
739 |
-
add_filter( 'wprss_settings_license_key_is_valid', 'wprss_license_validate_key_for_save', 10, 2 );
|
740 |
-
/**
|
741 |
-
* Invalidates the key if it is obfuscated, causing the saved version to be used.
|
742 |
-
* This meanst that the new key will not be saved, as it is considered then to be unchanged.
|
743 |
-
*
|
744 |
-
* @since 4.6.10
|
745 |
-
* @param bool $is_valid Indicates whether the key is currently considered to be valid.
|
746 |
-
* @param string $key The license key in question
|
747 |
-
* @return Whether or not the key is still to be considered valid.
|
748 |
-
*/
|
749 |
-
function wprss_license_validate_key_for_save( $is_valid, $key ) {
|
750 |
-
if ( wprss_license_key_is_obfuscated( $key ) )
|
751 |
-
return false;
|
752 |
-
|
753 |
-
return $is_valid;
|
754 |
-
}
|
755 |
-
|
756 |
-
|
757 |
-
/**
|
758 |
-
* Determines whether or not the license key in question is obfuscated.
|
759 |
-
*
|
760 |
-
* This is achieved by searching for the mask character in the key. Because the
|
761 |
-
* mask character cannot be a valid license character, the presence of at least
|
762 |
-
* one such character indicates that the key is obfuscated.
|
763 |
-
*
|
764 |
-
* @since 4.6.10
|
765 |
-
* @param string $key The license key in question.
|
766 |
-
* @return bool Whether or not this key is obfuscated.
|
767 |
-
*/
|
768 |
-
function wprss_license_key_is_obfuscated( $key ) {
|
769 |
-
$char = WPRSS_LICENSE_KEY_MASK_CHAR;
|
770 |
-
return mb_stripos( $key, $char ) !== false;
|
771 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* What to print in place of license code chars.
|
5 |
+
* This must not be a symbol that is considered to be a valid license key char.
|
6 |
+
*
|
7 |
+
* @since 4.6.10
|
8 |
+
*/
|
9 |
+
define( 'WPRSS_LICENSE_KEY_MASK_CHAR', '•' );
|
10 |
+
/**
|
11 |
+
* How many characters of the license code to print as is.
|
12 |
+
* Use negative value to indicate that characters at the end of the key are excluded.
|
13 |
+
*
|
14 |
+
* @since 4.6.10
|
15 |
+
*/
|
16 |
+
define( 'WPRSS_LICENSE_KEY_MASK_EXCLUDE_AMOUNT', -4 );
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Returns all registered addons.
|
20 |
+
*
|
21 |
+
* @since 4.4.5
|
22 |
+
*/
|
23 |
+
function wprss_get_addons() {
|
24 |
+
return apply_filters( 'wprss_register_addon', array() );
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Calls the EDD Software Licensing API to perform licensing tasks on the addon's store server.
|
30 |
+
*
|
31 |
+
* @since 4.4.5
|
32 |
+
*/
|
33 |
+
function wprss_edd_licensing_api( $addon, $license_key = NULL, $action = 'check_license', $return = 'license' ) {
|
34 |
+
// If no license argument was given
|
35 |
+
if ( $license_key === NULL ) {
|
36 |
+
// Get the license key
|
37 |
+
$license_key = wprss_get_license_key( $addon );
|
38 |
+
}
|
39 |
+
// Get the license status from the DB
|
40 |
+
$license_status = wprss_get_license_status( $addon );
|
41 |
+
|
42 |
+
// Prepare constants
|
43 |
+
$item_name = strtoupper( $addon );
|
44 |
+
$item_name_constant = constant( "WPRSS_{$item_name}_SL_ITEM_NAME" );
|
45 |
+
$store_url_constant = constant( "WPRSS_{$item_name}_SL_STORE_URL" );
|
46 |
+
|
47 |
+
// data to send in our API request
|
48 |
+
$api_params = array(
|
49 |
+
'edd_action' => $action,
|
50 |
+
'license' => sanitize_text_field( $license_key ),
|
51 |
+
'item_name' => urlencode( $item_name_constant ),
|
52 |
+
'url' => urlencode( network_site_url() ),
|
53 |
+
'time' => time(),
|
54 |
+
);
|
55 |
+
|
56 |
+
// Send the request to the API
|
57 |
+
$response = wp_remote_get( add_query_arg( $api_params, $store_url_constant ) );
|
58 |
+
|
59 |
+
// If the response is an error, return the value in the DB
|
60 |
+
if ( is_wp_error( $response ) ) {
|
61 |
+
return $license_status;
|
62 |
+
}
|
63 |
+
|
64 |
+
// decode the license data
|
65 |
+
$license_data = json_decode( wp_remote_retrieve_body( $response ) );
|
66 |
+
|
67 |
+
// Update the DB option
|
68 |
+
$license_statuses = get_option( 'wprss_settings_license_statuses' );
|
69 |
+
$license_statuses["{$addon}_license_status"] = $license_data->license;
|
70 |
+
$license_statuses["{$addon}_license_expires"] = $license_data->expires;
|
71 |
+
update_option( 'wprss_settings_license_statuses', $license_statuses );
|
72 |
+
|
73 |
+
// Return the data
|
74 |
+
if ( strtoupper( $return ) === 'ALL' ) {
|
75 |
+
return $license_data;
|
76 |
+
} else {
|
77 |
+
return $license_data->$return;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Returns the license status. Also updates the status in the DB.
|
84 |
+
*
|
85 |
+
* @since 4.4.5
|
86 |
+
*/
|
87 |
+
function wprss_edd_check_license( $addon, $license_key = NULL, $return = 'license' ) {
|
88 |
+
return wprss_edd_licensing_api( $addon, $license_key, 'check_license', $return );
|
89 |
+
}
|
90 |
+
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Activates an addon's license.
|
94 |
+
*
|
95 |
+
* @since 4.4.5
|
96 |
+
*/
|
97 |
+
function wprss_edd_activate_license( $addon, $license_key = NULL ) {
|
98 |
+
return wprss_edd_licensing_api( $addon, $license_key, 'activate_license' );
|
99 |
+
}
|
100 |
+
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Deactivates an addon's license.
|
104 |
+
*
|
105 |
+
* @since 4.4.5
|
106 |
+
*/
|
107 |
+
function wprss_edd_deactivate_license( $addon, $license_key = NULL ) {
|
108 |
+
return wprss_edd_licensing_api( $addon, $license_key, 'deactivate_license' );
|
109 |
+
}
|
110 |
+
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Returns an array of the default license settings. Used for plugin activation.
|
114 |
+
*
|
115 |
+
* @since 4.4.5
|
116 |
+
*
|
117 |
+
*/
|
118 |
+
function wprss_default_license_settings( $addon ) {
|
119 |
+
// Set up the default license settings
|
120 |
+
$settings = apply_filters(
|
121 |
+
'wprss_default_license_settings',
|
122 |
+
array(
|
123 |
+
"{$addon}_license_key" => FALSE,
|
124 |
+
"{$addon}_license_status" => 'invalid',
|
125 |
+
"{$addon}_license_expires" => NULL
|
126 |
+
)
|
127 |
+
);
|
128 |
+
|
129 |
+
// Return the default settings
|
130 |
+
return $settings;
|
131 |
+
}
|
132 |
+
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Returns the saved license code.
|
136 |
+
*
|
137 |
+
* @since 4.4.5
|
138 |
+
*/
|
139 |
+
function wprss_get_license_key( $addon ) {
|
140 |
+
// Get default and current options
|
141 |
+
$defaults = wprss_default_license_settings( $addon );
|
142 |
+
$keys = get_option( 'wprss_settings_license_keys', array() );
|
143 |
+
// Prepare the array key and target
|
144 |
+
$k = "{$addon}_license_key";
|
145 |
+
// Return the appropriate value
|
146 |
+
return isset( $keys["{$addon}_license_key"] )? $keys[$k] : $defaults[$k];
|
147 |
+
}
|
148 |
+
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Returns the saved license code.
|
152 |
+
*
|
153 |
+
* @since 4.4.5
|
154 |
+
*/
|
155 |
+
function wprss_get_license_status( $addon ) {
|
156 |
+
// Get the default and current options
|
157 |
+
$defaults = wprss_default_license_settings( $addon );
|
158 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
159 |
+
// Prepare the key
|
160 |
+
$k = "{$addon}_license_status";
|
161 |
+
// Return the appropriate value
|
162 |
+
return isset( $statuses["{$addon}_license_status"] )? $statuses[$k] : $defaults[$k];
|
163 |
+
}
|
164 |
+
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Returns the saved license expiry.
|
168 |
+
*
|
169 |
+
* @since 4.6.7
|
170 |
+
*/
|
171 |
+
function wprss_get_license_expiry( $addon ) {
|
172 |
+
// Get default and current options
|
173 |
+
$defaults = wprss_default_license_settings( $addon );
|
174 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
175 |
+
// Prepare the key
|
176 |
+
$k = "{$addon}_license_expires";
|
177 |
+
// Return the appropriate value
|
178 |
+
return isset( $statuses[$k] ) ? $statuses[$k] : $defaults[$k];
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
add_action( 'admin_init', 'wprss_check_to_show_license_notice');
|
183 |
+
/**
|
184 |
+
* Checks whether there are any invalid or expired licenses.
|
185 |
+
*
|
186 |
+
* @since 4.6.10
|
187 |
+
* @return BOOL which is TRUE if any addons are unlicensed, FALSE otherwise.
|
188 |
+
*/
|
189 |
+
function wprss_unlicensed_addons_exist() {
|
190 |
+
// Get the license statuses including expiry dates.
|
191 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
192 |
+
|
193 |
+
foreach ($statuses as $key => $value) {
|
194 |
+
if ( strpos($key, '_license_status') > 0 ) {
|
195 |
+
if ( $value !== 'valid') {
|
196 |
+
return TRUE;
|
197 |
+
}
|
198 |
+
} else if ( strpos($key, '_license_expires') > 0 ) {
|
199 |
+
// Check invalid expiry dates.
|
200 |
+
$expires = strtotime( substr( $value, 0, strpos( $value, " " ) ) );
|
201 |
+
|
202 |
+
if ( $expires == 0 || ( $expires < strtotime("+2 weeks") ) ) {
|
203 |
+
return TRUE;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
return FALSE;
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Check if any add-ons have a valid license and return a boolean.
|
213 |
+
*
|
214 |
+
* @since 4.6.8
|
215 |
+
*/
|
216 |
+
function wprss_is_premium_user() {
|
217 |
+
// Iterate through license statuses looking for a valid one.
|
218 |
+
$statuses = get_option('wprss_settings_license_statuses', array());
|
219 |
+
foreach ($statuses as $key => $value) {
|
220 |
+
// If we're looking at a license status key...
|
221 |
+
if (strpos($key, '_license_status') !== FALSE) {
|
222 |
+
// ...and the license is valid...
|
223 |
+
if ($value === 'valid') {
|
224 |
+
return TRUE;
|
225 |
+
}
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
return FALSE;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Returns an array of addon IDs that are licensed.
|
234 |
+
*
|
235 |
+
* @since 4.6.10
|
236 |
+
* @return Array of addon ID strings that have a valid license status.
|
237 |
+
*/
|
238 |
+
function wprss_get_licensed_addons() {
|
239 |
+
$addons = array();
|
240 |
+
|
241 |
+
// Get the license statuses.
|
242 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
243 |
+
|
244 |
+
foreach ($statuses as $key => $value) {
|
245 |
+
if ( strpos($key, '_license_status') > 0 ) {
|
246 |
+
if ( $value === 'valid') {
|
247 |
+
$addons[] = strtoupper( substr( $key, 0, strpos( $key, "_" ) ) );
|
248 |
+
}
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
return $addons;
|
253 |
+
|
254 |
+
}
|
255 |
+
|
256 |
+
|
257 |
+
/**
|
258 |
+
* Checks whether we should show the invalid/expired license notices.
|
259 |
+
*
|
260 |
+
* @since 4.6.10
|
261 |
+
*/
|
262 |
+
function wprss_check_to_show_license_notice() {
|
263 |
+
// Check if we found any of the licenses to be invalid, expiring or expired
|
264 |
+
// so that we can show the appropriate license nag.
|
265 |
+
if (wprss_unlicensed_addons_exist()) {
|
266 |
+
add_action( 'all_admin_notices', 'wprss_show_license_notice' );
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Shows an admin notice for any invalid/expired licenses.
|
273 |
+
*
|
274 |
+
* @since 4.6.9
|
275 |
+
*/
|
276 |
+
function wprss_show_license_notice() {
|
277 |
+
// Get the license statuses including expiry dates.
|
278 |
+
$statuses = get_option( 'wprss_settings_license_statuses', array() );
|
279 |
+
|
280 |
+
// Array of notices to show.
|
281 |
+
$notices = array();
|
282 |
+
|
283 |
+
foreach ($statuses as $key => $value) {
|
284 |
+
if ( strpos($key, '_license_status') > 0 ) {
|
285 |
+
if ( $value === 'expired' ) {
|
286 |
+
// License is expired, but we'll show the notice for this when checking the *_license_expires key.
|
287 |
+
|
288 |
+
continue;
|
289 |
+
|
290 |
+
} else if ( $value !== 'valid' ) {
|
291 |
+
// The license is invalid or unactivated.
|
292 |
+
|
293 |
+
$uid = strtoupper( substr( $key, 0, strpos( $key, "_" ) ) );
|
294 |
+
|
295 |
+
// Check if the plugin is currently activated.
|
296 |
+
if ( !defined("WPRSS_{$uid}_SL_ITEM_NAME") ) {
|
297 |
+
continue;
|
298 |
+
} else {
|
299 |
+
$plugin = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
300 |
+
}
|
301 |
+
|
302 |
+
$msg = sprintf(
|
303 |
+
__( 'Remember to <a href="%s">enter your plugin license code</a> for the WP RSS Aggregator <b>%s</b> add-on to benefit from updates and support.', WPRSS_TEXT_DOMAIN ),
|
304 |
+
esc_attr(admin_url( 'edit.php?post_type=wprss_feed&page=wprss-aggregator-settings&tab=licenses_settings' )),
|
305 |
+
$plugin
|
306 |
+
);
|
307 |
+
|
308 |
+
// Save the notice we're going to display
|
309 |
+
$notices[$uid] = '<div id="wprss-license-notice-' . $uid . '" class="error wprss-license-notice"><p>' . $msg . '</p></div>';
|
310 |
+
}
|
311 |
+
} else if ( strpos($key, '_license_expires') > 0 ) {
|
312 |
+
// Check for expired licenses
|
313 |
+
|
314 |
+
$expires = strtotime( substr( $value, 0, strpos( $value, " " ) ) );
|
315 |
+
$id = substr( $key, 0, strpos( $key, "_" ) );
|
316 |
+
$uid = strtoupper($id);
|
317 |
+
|
318 |
+
// Check if the plugin is currently activated.
|
319 |
+
if ( !defined("WPRSS_{$uid}_SL_ITEM_NAME") ) {
|
320 |
+
continue;
|
321 |
+
} else {
|
322 |
+
$plugin = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
323 |
+
}
|
324 |
+
|
325 |
+
if ( $expires < strtotime("+2 weeks") ) {
|
326 |
+
// The license is expired or expiring soon.
|
327 |
+
$license_key = wprss_get_license_key($id);
|
328 |
+
$msg = sprintf(
|
329 |
+
__('<a href="%s">Save 30%% on your license renewal</a> for the WP RSS Aggregator <b>%s</b> add-on and continue receiving updates and support.', WPRSS_TEXT_DOMAIN),
|
330 |
+
esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $license_key),
|
331 |
+
$plugin
|
332 |
+
);
|
333 |
+
|
334 |
+
// User can hide expiring/expired license messages.
|
335 |
+
$hide = '<a href="#" class="ajax-close-addon-notice" style="float:right;" data-addon="categories" data-notice="license">' .
|
336 |
+
__('Dismiss this notification', WPRSS_TEXT_DOMAIN) . '</a>';
|
337 |
+
|
338 |
+
// Only show this notice if there isn't already a notice to show for this add-on.
|
339 |
+
if ( !isset($notices[$uid]) ) {
|
340 |
+
$notices[$uid] = '<div class="error wprss-license-notice"><p>' . $msg . $hide . '</p></div>';
|
341 |
+
}
|
342 |
+
}
|
343 |
+
}
|
344 |
+
}
|
345 |
+
|
346 |
+
// Display the notices
|
347 |
+
foreach ($notices as $notice) {
|
348 |
+
echo $notice;
|
349 |
+
}
|
350 |
+
}
|
351 |
+
|
352 |
+
|
353 |
+
add_action( 'wp_ajax_wprss_ajax_manage_license', 'wprss_ajax_manage_license' );
|
354 |
+
/**
|
355 |
+
* Handles the AJAX request to check a license.
|
356 |
+
*
|
357 |
+
* @since 4.7
|
358 |
+
*/
|
359 |
+
function wprss_ajax_manage_license() {
|
360 |
+
// Get and sanitize the addon ID we're checking.
|
361 |
+
if ( isset($_GET['addon']) ) {
|
362 |
+
$addon = sanitize_text_field($_GET['addon']);
|
363 |
+
} else {
|
364 |
+
wprss_echo_error_and_die( __('No addon ID', WPRSS_TEXT_DOMAIN ));
|
365 |
+
}
|
366 |
+
|
367 |
+
// Check what we've been asked to do with the license.
|
368 |
+
if ( isset($_GET['event']) ) {
|
369 |
+
$event = sanitize_text_field($_GET['event']);
|
370 |
+
|
371 |
+
if ($event !== 'activate' && $event !== 'deactivate') {
|
372 |
+
wprss_echo_error_and_die( __('Invalid event specified', WPRSS_TEXT_DOMAIN), $addon);
|
373 |
+
}
|
374 |
+
} else {
|
375 |
+
wprss_echo_error_and_die( __('No event specified', WPRSS_TEXT_DOMAIN), $addon);
|
376 |
+
}
|
377 |
+
|
378 |
+
// Get and sanitize the license that was entered.
|
379 |
+
if ( isset($_GET['license']) ) {
|
380 |
+
$license = sanitize_text_field($_GET['license']);
|
381 |
+
} else {
|
382 |
+
wprss_echo_error_and_die( __('No license', WPRSS_TEXT_DOMAIN), $addon);
|
383 |
+
}
|
384 |
+
|
385 |
+
// Check the nonce for this particular add-on's validation button.
|
386 |
+
if ( isset($_GET['nonce']) ) {
|
387 |
+
$nonce = sanitize_text_field($_GET['nonce']);
|
388 |
+
$nonce_id = "wprss_{$addon}_license_nonce";
|
389 |
+
|
390 |
+
if ( !wp_verify_nonce($nonce, $nonce_id) ) {
|
391 |
+
wprss_echo_error_and_die( __('Bad nonce', WPRSS_TEXT_DOMAIN), $addon);
|
392 |
+
}
|
393 |
+
} else {
|
394 |
+
wprss_echo_error_and_die( __('No nonce', WPRSS_TEXT_DOMAIN), $addon);
|
395 |
+
}
|
396 |
+
|
397 |
+
$license_keys = get_option('wprss_settings_license_keys', array());
|
398 |
+
// Check if the license key was obfuscated on the client's end.
|
399 |
+
if ( wprss_license_key_is_obfuscated( $license ) ) {
|
400 |
+
// If so, use the stored license key for de/activation.
|
401 |
+
$license = $license_keys[$addon . '_license_key'];
|
402 |
+
} else {
|
403 |
+
// Otherwise, update the license key stored in the DB.
|
404 |
+
$license_keys[$addon . '_license_key'] = $license;
|
405 |
+
update_option('wprss_settings_license_keys', $license_keys);
|
406 |
+
}
|
407 |
+
|
408 |
+
// Call the appropriate EDD licensing function.
|
409 |
+
if ($event === 'activate') {
|
410 |
+
$status = wprss_edd_activate_license($addon, $license);
|
411 |
+
} else if ($event === 'deactivate') {
|
412 |
+
$status = wprss_edd_deactivate_license($addon, $license);
|
413 |
+
} else {
|
414 |
+
wprss_echo_error_and_die( __('Invalid event specified', WPRSS_TEXT_DOMAIN), $addon);
|
415 |
+
}
|
416 |
+
|
417 |
+
// Assemble the JSON data to return.
|
418 |
+
$ret = array();
|
419 |
+
|
420 |
+
// Set the validity of the license.
|
421 |
+
if ( $status === 'site_inactive' ) $status = 'inactive';
|
422 |
+
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
423 |
+
$ret['validity'] = $status;
|
424 |
+
|
425 |
+
// Set the addon ID for use in the callback.
|
426 |
+
$ret['addon'] = $addon;
|
427 |
+
|
428 |
+
// Set the HTML markup for the new button and validity display.
|
429 |
+
$ret['html'] = wprss_get_activate_license_button($addon);
|
430 |
+
|
431 |
+
$ret['licensedAddons'] = wprss_get_licensed_addons();
|
432 |
+
|
433 |
+
// Return the JSON data.
|
434 |
+
echo json_encode($ret);
|
435 |
+
die();
|
436 |
+
}
|
437 |
+
|
438 |
+
|
439 |
+
add_action( 'wp_ajax_wprss_ajax_fetch_license', 'wprss_ajax_fetch_license' );
|
440 |
+
/**
|
441 |
+
* Handles the AJAX request to fetch a license's information.
|
442 |
+
*
|
443 |
+
* @since 4.7
|
444 |
+
*/
|
445 |
+
function wprss_ajax_fetch_license() {
|
446 |
+
// Get and sanitize the addon ID we're checking.
|
447 |
+
if ( isset($_GET['addon']) ) {
|
448 |
+
$addon = sanitize_text_field($_GET['addon']);
|
449 |
+
} else {
|
450 |
+
wprss_echo_error_and_die( __('No addon ID', WPRSS_TEXT_DOMAIN ));
|
451 |
+
}
|
452 |
+
|
453 |
+
// Get the license information from EDD
|
454 |
+
$ret = wprss_edd_check_license( $addon, NULL, 'ALL' );
|
455 |
+
|
456 |
+
echo json_encode($ret);
|
457 |
+
die();
|
458 |
+
}
|
459 |
+
|
460 |
+
|
461 |
+
/**
|
462 |
+
* Helper function that echoes a JSON error along with the new
|
463 |
+
* activate/deactivate license button HTML markup and then die()s.
|
464 |
+
*
|
465 |
+
* @since 4.7
|
466 |
+
*/
|
467 |
+
function wprss_echo_error_and_die($msg, $addon = '') {
|
468 |
+
$ret = array(
|
469 |
+
'error' => $msg,
|
470 |
+
'html' => wprss_get_activate_license_button($addon)
|
471 |
+
);
|
472 |
+
|
473 |
+
echo json_encode($ret);
|
474 |
+
die();
|
475 |
+
}
|
476 |
+
|
477 |
+
|
478 |
+
add_action( 'wprss_admin_init', 'wprss_license_settings', 100 );
|
479 |
+
/**
|
480 |
+
* Adds the license sections and settings for registered add-ons.
|
481 |
+
*
|
482 |
+
* @since 4.4.5
|
483 |
+
*/
|
484 |
+
function wprss_license_settings() {
|
485 |
+
$addons = wprss_get_addons();
|
486 |
+
foreach( $addons as $addon_id => $addon_name ) {
|
487 |
+
// Settings Section
|
488 |
+
add_settings_section(
|
489 |
+
"wprss_settings_{$addon_id}_licenses_section",
|
490 |
+
$addon_name .' '. __( 'License', WPRSS_TEXT_DOMAIN ),
|
491 |
+
'__return_empty_string',
|
492 |
+
'wprss_settings_license_keys'
|
493 |
+
);
|
494 |
+
// License key field
|
495 |
+
add_settings_field(
|
496 |
+
"wprss_settings_{$addon_id}_license",
|
497 |
+
__( 'License Key', WPRSS_TEXT_DOMAIN ),
|
498 |
+
'wprss_license_key_field',
|
499 |
+
'wprss_settings_license_keys',
|
500 |
+
"wprss_settings_{$addon_id}_licenses_section",
|
501 |
+
array( $addon_id )
|
502 |
+
);
|
503 |
+
// Activate license button
|
504 |
+
add_settings_field(
|
505 |
+
"wprss_settings_{$addon_id}_activate_license",
|
506 |
+
__( 'Activate License', WPRSS_TEXT_DOMAIN ),
|
507 |
+
'wprss_activate_license_button',
|
508 |
+
'wprss_settings_license_keys',
|
509 |
+
"wprss_settings_{$addon_id}_licenses_section",
|
510 |
+
array( $addon_id )
|
511 |
+
);
|
512 |
+
}
|
513 |
+
}
|
514 |
+
|
515 |
+
|
516 |
+
/**
|
517 |
+
* Renders the license field for a particular add-on.
|
518 |
+
*
|
519 |
+
* @since 4.4.5
|
520 |
+
*/
|
521 |
+
function wprss_license_key_field( $args ) {
|
522 |
+
$addon_id = $args[0];
|
523 |
+
$license_key = wprss_get_license_key( $addon_id );
|
524 |
+
$license_key_length = strlen( $license_key );
|
525 |
+
$mask_char = WPRSS_LICENSE_KEY_MASK_CHAR;
|
526 |
+
// How many chars to show
|
527 |
+
$mask_exclude_amount = WPRSS_LICENSE_KEY_MASK_EXCLUDE_AMOUNT;
|
528 |
+
$mask_exclude_amount = abs( $mask_exclude_amount ) > ($license_key_length - 1)
|
529 |
+
? ($license_key_length - 1) * ( $mask_exclude_amount < 0 ? -1 : 1 ) // Making sure to preserve position of mask
|
530 |
+
: $mask_exclude_amount;
|
531 |
+
// How many chars to mask. Always at least one char will be masked.
|
532 |
+
$mask_length = $license_key_length - abs( $mask_exclude_amount );
|
533 |
+
$mask = $mask_length > 0 ? str_repeat( $mask_char, $mask_length ) : '';
|
534 |
+
$excluded_chars = mb_substr( $license_key, $mask_exclude_amount < 0 ? $mask_length : 0, abs( $mask_exclude_amount ) );
|
535 |
+
$displayed_key = sprintf( $mask_exclude_amount > 0 ? '%1$s%2$s' : '%2$s%1$s', $excluded_chars, $mask); ?>
|
536 |
+
<input id="wprss-<?php echo $addon_id ?>-license-key" name="wprss_settings_license_keys[<?php echo $addon_id ?>_license_key]"
|
537 |
+
type="text" value="<?php echo esc_attr( $displayed_key ) ?>" style="width: 300px;"
|
538 |
+
/>
|
539 |
+
<label class="description" for="wprss-<?php echo $addon_id ?>-license-key">
|
540 |
+
<?php _e( 'Enter your license key', WPRSS_TEXT_DOMAIN ) ?>
|
541 |
+
</label><?php
|
542 |
+
}
|
543 |
+
|
544 |
+
|
545 |
+
/**
|
546 |
+
* Renders the activate/deactivate license button for a particular add-on.
|
547 |
+
*
|
548 |
+
* @since 4.4.5
|
549 |
+
*/
|
550 |
+
function wprss_activate_license_button( $args ) {
|
551 |
+
$addon_id = $args[0];
|
552 |
+
$data = wprss_edd_check_license( $addon_id, NULL, 'ALL' );
|
553 |
+
$status = is_string( $data ) ? $data : $data->license;
|
554 |
+
if ( $status === 'site_inactive' ) $status = 'inactive';
|
555 |
+
if ( $status === 'item_name_mismatch' ) $status = 'invalid';
|
556 |
+
|
557 |
+
$valid = $status == 'valid';
|
558 |
+
$btn_text = $valid ? 'Deactivate License' : 'Activate License';
|
559 |
+
$btn_name = "wprss_{$addon_id}_license_" . ( $valid? 'deactivate' : 'activate' );
|
560 |
+
$btn_class = "button-" . ( $valid ? 'deactivate' : 'activate' ) . "-license";
|
561 |
+
wp_nonce_field( "wprss_{$addon_id}_license_nonce", "wprss_{$addon_id}_license_nonce", false ); ?>
|
562 |
+
|
563 |
+
<input type="button" class="<?php echo $btn_class; ?> button-process-license button-secondary" name="<?php echo $btn_name; ?>" value="<?php _e( $btn_text, WPRSS_TEXT_DOMAIN ); ?>" />
|
564 |
+
<span id="wprss-<?php echo $addon_id; ?>-license-status-text">
|
565 |
+
<strong><?php _e('Status', WPRSS_TEXT_DOMAIN); ?>:
|
566 |
+
<span class="wprss-<?php echo $addon_id; ?>-license-<?php echo $status; ?>">
|
567 |
+
<?php _e( ucfirst($status), WPRSS_TEXT_DOMAIN ); ?>
|
568 |
+
<?php if ( $status === 'valid' ) : ?>
|
569 |
+
<i class="fa fa-check"></i>
|
570 |
+
<?php elseif( $status === 'invalid' || $status === 'expired' ): ?>
|
571 |
+
<i class="fa fa-times"></i>
|
572 |
+
<?php elseif( $status === 'inactive' ): ?>
|
573 |
+
<i class="fa fa-warning"></i>
|
574 |
+
<?php endif; ?>
|
575 |
+
</strong>
|
576 |
+
</span>
|
577 |
+
</span>
|
578 |
+
|
579 |
+
<p>
|
580 |
+
<?php
|
581 |
+
$license_key = wprss_get_license_key( $addon_id );
|
582 |
+
if ( ! empty( $license_key ) ) :
|
583 |
+
if ( is_object( $data ) ) :
|
584 |
+
$acts_current = $data->site_count;
|
585 |
+
$acts_left = $data->activations_left;
|
586 |
+
$acts_limit = $data->license_limit;
|
587 |
+
$expires = $data->expires;
|
588 |
+
$expires = substr( $expires, 0, strpos( $expires, " " ) );
|
589 |
+
|
590 |
+
// If the license key is garbage, don't show any of the data.
|
591 |
+
if ( !empty($data->payment_id) && !empty($data->license_limit ) ) :
|
592 |
+
?>
|
593 |
+
<small>
|
594 |
+
<?php if ( $status !== 'valid' && $acts_left === 0 ) : ?>
|
595 |
+
<?php $account_url = 'https://www.wprssaggregator.com/account/?action=manage_licenses&payment_id=' . $data->payment_id; ?>
|
596 |
+
<a href="<?php echo $account_url; ?>"><?php _e("No activations left. Click here to manage the sites you've activated licenses on.", WPRSS_TEXT_DOMAIN); ?></a>
|
597 |
+
<br/>
|
598 |
+
<?php endif; ?>
|
599 |
+
<?php if ( strtotime($expires) < strtotime("+2 weeks") ) : ?>
|
600 |
+
<?php $renewal_url = esc_attr(WPRSS_SL_STORE_URL . '/checkout/?edd_license_key=' . $license_key); ?>
|
601 |
+
<a href="<?php echo $renewal_url; ?>"><?php _e('Renew your license to continue receiving updates and support.', WPRSS_TEXT_DOMAIN); ?></a>
|
602 |
+
<br/>
|
603 |
+
<?php endif; ?>
|
604 |
+
<strong><?php _e('Activations', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
605 |
+
<?php echo $acts_current.'/'.$acts_limit; ?> (<?php echo $acts_left; ?> left)
|
606 |
+
<br/>
|
607 |
+
<strong><?php _e('Expires on', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
608 |
+
<code><?php echo $expires; ?></code>
|
609 |
+
<br/>
|
610 |
+
<strong><?php _e('Registered to', WPRSS_TEXT_DOMAIN); ?>:</strong>
|
611 |
+
<?php echo $data->customer_name; ?> (<code><?php echo $data->customer_email; ?></code>)
|
612 |
+
</small>
|
613 |
+
<?php endif; ?>
|
614 |
+
<?php else: ?>
|
615 |
+
<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>
|
616 |
+
<?php endif; ?>
|
617 |
+
<?php endif;
|
618 |
+
?>
|
619 |
+
</p>
|
620 |
+
|
621 |
+
<style type="text/css">
|
622 |
+
.wprss-<?php echo $addon_id; ?>-license-valid {
|
623 |
+
color: green;
|
624 |
+
}
|
625 |
+
.wprss-<?php echo $addon_id; ?>-license-invalid, .wprss-<?php echo $addon_id; ?>-license-expired {
|
626 |
+
color: #b71919;
|
627 |
+
}
|
628 |
+
.wprss-<?php echo $addon_id; ?>-license-inactive {
|
629 |
+
color: #d19e5b;
|
630 |
+
}
|
631 |
+
#wprss-<?php echo $addon_id; ?>-license-status-text {
|
632 |
+
margin-left: 8px;
|
633 |
+
line-height: 27px;
|
634 |
+
vertical-align: middle;
|
635 |
+
}
|
636 |
+
</style>
|
637 |
+
|
638 |
+
|
639 |
+
<?php
|
640 |
+
}
|
641 |
+
|
642 |
+
|
643 |
+
/**
|
644 |
+
* Returns the activate/deactivate license button markup for a particular add-on.
|
645 |
+
*
|
646 |
+
* @since 4.7
|
647 |
+
*/
|
648 |
+
function wprss_get_activate_license_button( $addon ) {
|
649 |
+
// Buffer the output from the rendering function.
|
650 |
+
ob_start();
|
651 |
+
|
652 |
+
wprss_activate_license_button(array($addon));
|
653 |
+
$ret = ob_get_contents();
|
654 |
+
|
655 |
+
ob_end_clean();
|
656 |
+
|
657 |
+
return $ret;
|
658 |
+
}
|
659 |
+
|
660 |
+
|
661 |
+
add_action( 'admin_init', 'wprss_process_addon_license', 10 );
|
662 |
+
/**
|
663 |
+
* Handles the activation/deactivation process
|
664 |
+
*
|
665 |
+
* @since 1.0
|
666 |
+
*/
|
667 |
+
function wprss_process_addon_license() {
|
668 |
+
$addons = wprss_get_addons();
|
669 |
+
|
670 |
+
// Get for each registered addon
|
671 |
+
foreach( $addons as $id => $name ) {
|
672 |
+
|
673 |
+
// listen for our activate button to be clicked
|
674 |
+
if( isset( $_POST["wprss_{$id}_license_activate"] ) || isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
675 |
+
// run a quick security check
|
676 |
+
if( ! check_admin_referer( "wprss_{$id}_license_nonce", "wprss_{$id}_license_nonce" ) )
|
677 |
+
continue; // get out if we didn't click the Activate/Deactivate button
|
678 |
+
}
|
679 |
+
|
680 |
+
// retrieve the license keys and statuses from the database
|
681 |
+
$license = wprss_get_license_key( $id );
|
682 |
+
$license_statuses = get_option( 'wprss_settings_license_statuses' );
|
683 |
+
|
684 |
+
// If the license is not saved in DB, but is included in POST
|
685 |
+
if ( $license == '' && !empty($_POST['wprss_settings_license_keys'][$id.'_license_key']) ) {
|
686 |
+
// Use the license given in POST
|
687 |
+
$license = $_POST['wprss_settings_license_keys'][$id.'_license_key'];
|
688 |
+
}
|
689 |
+
|
690 |
+
// Prepare the action to take
|
691 |
+
if ( isset( $_POST["wprss_{$id}_license_activate"] ) ) {
|
692 |
+
wprss_edd_activate_license( $id, $license );
|
693 |
+
}
|
694 |
+
elseif ( isset( $_POST["wprss_{$id}_license_deactivate"] ) ) {
|
695 |
+
wprss_edd_deactivate_license( $id, $license );
|
696 |
+
}
|
697 |
+
}
|
698 |
+
}
|
699 |
+
|
700 |
+
|
701 |
+
add_action( 'init', 'wprss_setup_edd_updater' );
|
702 |
+
/**
|
703 |
+
* Sets up the EDD updater for all registered add-ons.
|
704 |
+
*
|
705 |
+
* @since 4.6.3
|
706 |
+
*/
|
707 |
+
function wprss_setup_edd_updater() {
|
708 |
+
// Get all registered addons
|
709 |
+
$addons = wprss_get_addons();
|
710 |
+
|
711 |
+
// retrieve our license key from the DB
|
712 |
+
$licenses = get_option( 'wprss_settings_license_keys' );
|
713 |
+
|
714 |
+
// setup the updater
|
715 |
+
if ( !class_exists( 'EDD_SL_Plugin_Updater' ) ) {
|
716 |
+
// load our custom updater
|
717 |
+
include ( WPRSS_INC . 'libraries/EDD_licensing/EDD_SL_Plugin_Updater.php' );
|
718 |
+
}
|
719 |
+
|
720 |
+
// Iterate the addons
|
721 |
+
foreach( $addons as $id => $name ) {
|
722 |
+
// Prepare the data
|
723 |
+
$license = wprss_get_license_key( $id );
|
724 |
+
$uid = strtoupper( $id );
|
725 |
+
$name = constant("WPRSS_{$uid}_SL_ITEM_NAME");
|
726 |
+
$version = constant("WPRSS_{$uid}_VERSION");
|
727 |
+
$path = constant("WPRSS_{$uid}_PATH");
|
728 |
+
// Set up an updater
|
729 |
+
$edd_updater = new EDD_SL_Plugin_Updater( WPRSS_SL_STORE_URL, $path, array(
|
730 |
+
'version' => $version, // current version number
|
731 |
+
'license' => $license, // license key (used get_option above to retrieve from DB)
|
732 |
+
'item_name' => $name, // name of this plugin
|
733 |
+
'author' => 'Jean Galea' // author of this plugin
|
734 |
+
));
|
735 |
+
}
|
736 |
+
}
|
737 |
+
|
738 |
+
|
739 |
+
add_filter( 'wprss_settings_license_key_is_valid', 'wprss_license_validate_key_for_save', 10, 2 );
|
740 |
+
/**
|
741 |
+
* Invalidates the key if it is obfuscated, causing the saved version to be used.
|
742 |
+
* This meanst that the new key will not be saved, as it is considered then to be unchanged.
|
743 |
+
*
|
744 |
+
* @since 4.6.10
|
745 |
+
* @param bool $is_valid Indicates whether the key is currently considered to be valid.
|
746 |
+
* @param string $key The license key in question
|
747 |
+
* @return Whether or not the key is still to be considered valid.
|
748 |
+
*/
|
749 |
+
function wprss_license_validate_key_for_save( $is_valid, $key ) {
|
750 |
+
if ( wprss_license_key_is_obfuscated( $key ) )
|
751 |
+
return false;
|
752 |
+
|
753 |
+
return $is_valid;
|
754 |
+
}
|
755 |
+
|
756 |
+
|
757 |
+
/**
|
758 |
+
* Determines whether or not the license key in question is obfuscated.
|
759 |
+
*
|
760 |
+
* This is achieved by searching for the mask character in the key. Because the
|
761 |
+
* mask character cannot be a valid license character, the presence of at least
|
762 |
+
* one such character indicates that the key is obfuscated.
|
763 |
+
*
|
764 |
+
* @since 4.6.10
|
765 |
+
* @param string $key The license key in question.
|
766 |
+
* @return bool Whether or not this key is obfuscated.
|
767 |
+
*/
|
768 |
+
function wprss_license_key_is_obfuscated( $key ) {
|
769 |
+
$char = WPRSS_LICENSE_KEY_MASK_CHAR;
|
770 |
+
return mb_stripos( $key, $char ) !== false;
|
771 |
+
}
|
includes/misc-functions.php
CHANGED
@@ -1,333 +1,333 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* WPRSS Let To Num
|
4 |
-
*
|
5 |
-
* Does Size Conversions
|
6 |
-
*
|
7 |
-
* @since 3.1
|
8 |
-
* @author Chris Christoff
|
9 |
-
* @return $ret
|
10 |
-
*/
|
11 |
-
function wprss_let_to_num( $v ) {
|
12 |
-
$l = substr( $v, -1 );
|
13 |
-
$ret = substr( $v, 0, -1 );
|
14 |
-
|
15 |
-
switch ( strtoupper( $l ) ) {
|
16 |
-
case 'P':
|
17 |
-
$ret *= 1024;
|
18 |
-
case 'T':
|
19 |
-
$ret *= 1024;
|
20 |
-
case 'G':
|
21 |
-
$ret *= 1024;
|
22 |
-
case 'M':
|
23 |
-
$ret *= 1024;
|
24 |
-
case 'K':
|
25 |
-
$ret *= 1024;
|
26 |
-
break;
|
27 |
-
}
|
28 |
-
|
29 |
-
return $ret;
|
30 |
-
}
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
/**
|
36 |
-
* An enhanced version of WP's media_sideload_image function.
|
37 |
-
*
|
38 |
-
* If media_sideload_image fails, the file is downloaded manually
|
39 |
-
* as an image, inserted as an attachment, and attached to the post.
|
40 |
-
*
|
41 |
-
* @since 3.5.1
|
42 |
-
*/
|
43 |
-
function wprss_media_sideload_image( $file, $post_id, $desc = null ) {
|
44 |
-
try {
|
45 |
-
|
46 |
-
if ( ! empty( $file ) ) {
|
47 |
-
|
48 |
-
// Download file to temp location
|
49 |
-
$tmp = download_url( $file );
|
50 |
-
|
51 |
-
// Set variables for storage
|
52 |
-
// fix file filename for query strings
|
53 |
-
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
|
54 |
-
|
55 |
-
if ( count( $matches ) > 0 ) {
|
56 |
-
$file_array['name'] = basename( $matches[0] );
|
57 |
-
}
|
58 |
-
else {
|
59 |
-
preg_match( '/[\/\?\=\&]([^\/\?\=\&]*)[\?]*$/i', $file, $matches2 );
|
60 |
-
if ( count( $matches2 ) > 1 ) {
|
61 |
-
$file_array['name'] = $matches2[1] . '.png';
|
62 |
-
} else {
|
63 |
-
@unlink( $tmp );
|
64 |
-
return "<img src='$file' alt='' />";
|
65 |
-
}
|
66 |
-
}
|
67 |
-
$file_array['tmp_name'] = $tmp;
|
68 |
-
|
69 |
-
// If error storing temporarily, unlink
|
70 |
-
if ( is_wp_error( $tmp ) ) {
|
71 |
-
@unlink( $file_array['tmp_name'] );
|
72 |
-
$file_array['tmp_name'] = '';
|
73 |
-
}
|
74 |
-
|
75 |
-
// do the validation and storage stuff
|
76 |
-
$id = media_handle_sideload( $file_array, $post_id, $desc );
|
77 |
-
// If error storing permanently, unlink
|
78 |
-
if ( is_wp_error($id) ) {
|
79 |
-
@unlink( $file_array['tmp_name'] );
|
80 |
-
return "<img src='$file' alt='' />";
|
81 |
-
}
|
82 |
-
|
83 |
-
$src = wp_get_attachment_url( $id );
|
84 |
-
}
|
85 |
-
|
86 |
-
// Finally check to make sure the file has been saved, then return the html
|
87 |
-
if ( ! empty( $src ) ) {
|
88 |
-
$alt = isset( $desc )? esc_attr($desc) : '';
|
89 |
-
$html = "<img src='$src' alt='$alt' />";
|
90 |
-
return $html;
|
91 |
-
}
|
92 |
-
|
93 |
-
}
|
94 |
-
catch( Exception $e ) {
|
95 |
-
return "<img src='$file' alt='' />";
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Trims the given text by a fixed number of words, and preserving HTML.
|
102 |
-
*
|
103 |
-
* Collapses all white space, trims the text up to a certain number of words, and
|
104 |
-
* preserves all HTML markup. HTML tags do not count as words.
|
105 |
-
* Uses WordPress `wp_trim_words` internally.
|
106 |
-
* Uses mostly trivial regex. Works by removing, then re-adding tags.
|
107 |
-
* Just as well closes open tags by counting them.
|
108 |
-
*
|
109 |
-
* @param string $text The text to trim.
|
110 |
-
* @param string $max_words The maximum number of words.
|
111 |
-
* @param array $allowed_tags The allows tags. Regular array of tag names.
|
112 |
-
* @return string The trimmed text.
|
113 |
-
*/
|
114 |
-
function wprss_trim_words( $text, $max_words, $allowed_tags = array() ) {
|
115 |
-
// See http://haacked.com/archive/2004/10/25/usingregularexpressionstomatchhtml.aspx/
|
116 |
-
$html_regex = <<<EOS
|
117 |
-
(</?(\w+)(?:(?:\s+\w+(?:\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)/?>)
|
118 |
-
EOS;
|
119 |
-
$html_regex_str = sprintf ('!%1$s!', $html_regex );
|
120 |
-
// Collapsing single-line white space
|
121 |
-
$text = preg_replace( '!\s+!', ' ', $text );
|
122 |
-
|
123 |
-
// Enum of tag types
|
124 |
-
$tag_type = array(
|
125 |
-
'opening' => 1,
|
126 |
-
'closing' => 2,
|
127 |
-
'self-closing' => 0
|
128 |
-
);
|
129 |
-
|
130 |
-
/*
|
131 |
-
* Split text using tags as delimiters.
|
132 |
-
* The resulting array is a sequence of elements as follows:
|
133 |
-
* 0 - The complete tag that it was delimited by
|
134 |
-
* 1 - The name of that tag
|
135 |
-
* 2 - The text that follows it until the next tag
|
136 |
-
*
|
137 |
-
* Each element contains 2 indexes:
|
138 |
-
* 0 - The element content
|
139 |
-
* 1 - The position in the original string, at which it was found
|
140 |
-
*
|
141 |
-
* For instance:
|
142 |
-
* <span>hello</span> how do <em>you do</em>?
|
143 |
-
*
|
144 |
-
* Will result in an array (not actaul structure) containing:
|
145 |
-
* <span>, span, hello, </span>, span, how do, <em>, em, you do, </em>, em, ?
|
146 |
-
*/
|
147 |
-
$text_array = preg_split(
|
148 |
-
$html_regex_str, // Match HTML Regex above
|
149 |
-
$text, // Split the text
|
150 |
-
-1, // No split limit
|
151 |
-
// FLAGS
|
152 |
-
PREG_SPLIT_DELIM_CAPTURE // Capture delimiters (html tags)
|
153 |
-
| PREG_SPLIT_OFFSET_CAPTURE // Record the string offset of each part
|
154 |
-
);
|
155 |
-
/*
|
156 |
-
* Get first element of the array (leading text with no HTML), and add it to a string.
|
157 |
-
* This string will contain the plain text (no HTML) only after the follow foreach loop.
|
158 |
-
*/
|
159 |
-
$text_start = array_shift( $text_array );
|
160 |
-
$plain_text = $text_start[0];
|
161 |
-
|
162 |
-
/*
|
163 |
-
* Chunk the array in groups of 3. This will take each 3 consecutive elements
|
164 |
-
* and group them together.
|
165 |
-
*/
|
166 |
-
$pieces = array_chunk( $text_array, 3 );
|
167 |
-
|
168 |
-
|
169 |
-
/*
|
170 |
-
* Iterate over each group and:
|
171 |
-
* 1. Generate plain text without HTML
|
172 |
-
* 2. Add apropriate tag type to each group
|
173 |
-
*/
|
174 |
-
foreach ( $pieces as $_idx => $_piece ) {
|
175 |
-
// Get the data
|
176 |
-
$tag_piece = $_piece[0];
|
177 |
-
$text_piece = $_piece[2];
|
178 |
-
// Compile all plain text together
|
179 |
-
$plain_text .= $text_piece[0];
|
180 |
-
// Check the tag and assign the proper tag type
|
181 |
-
$tag = $tag_piece[0];
|
182 |
-
$pieces[ $_idx ][1][2] =
|
183 |
-
( substr( $tag, 0, 2 ) === '</' )?
|
184 |
-
$tag_type['closing'] :
|
185 |
-
( substr( $tag, strlen( $tag ) - 3, 2 ) == '/>' )?
|
186 |
-
$tag_type['self-closing'] :
|
187 |
-
$tag_type['opening'];
|
188 |
-
}
|
189 |
-
|
190 |
-
// Stock trimming of words
|
191 |
-
$plain_text = wp_trim_words_wprss( $plain_text, $max_words );
|
192 |
-
|
193 |
-
/*
|
194 |
-
* Put the tags back, using the offsets recorded
|
195 |
-
* This is where the sweet magic happens
|
196 |
-
*/
|
197 |
-
|
198 |
-
// Cache to only check `in_array` once for each tag type
|
199 |
-
$allowed_tags_cache = array();
|
200 |
-
// For counting open tags
|
201 |
-
$tags_to_close = array();
|
202 |
-
// Since some tags will not be included...
|
203 |
-
$tag_position_offset = 0;
|
204 |
-
$text = $plain_text;
|
205 |
-
|
206 |
-
// Iterate the groups once more
|
207 |
-
foreach ( $pieces as $_idx => $_piece ) {
|
208 |
-
// Tag and tagname
|
209 |
-
$_tag_piece = $_piece[0];
|
210 |
-
$_tag_name_piece = $_piece[1];
|
211 |
-
// Name of the tag
|
212 |
-
$_tag_name = strtolower( $_tag_name_piece[0] );
|
213 |
-
// Tag type
|
214 |
-
$_tag_type = $_tag_name_piece[2];
|
215 |
-
// Text of the tag
|
216 |
-
$_tag = $_tag_piece[0];
|
217 |
-
// Position of the tag in the original string
|
218 |
-
$_tag_position = $_tag_piece[1];
|
219 |
-
$_actual_tag_position = $_tag_position - $tag_position_offset;
|
220 |
-
|
221 |
-
// Caching result
|
222 |
-
if ( !isset( $allowed_tags_cache[$_tag_name] ) )
|
223 |
-
$allowed_tags_cache[$_tag_name] = in_array( $_tag_name, $allowed_tags );
|
224 |
-
|
225 |
-
// Whether to stop (tag position is outside the trimmed text)
|
226 |
-
if( $_actual_tag_position >= strlen( $text ) ) break;
|
227 |
-
|
228 |
-
// Whether to skip tag
|
229 |
-
if ( !$allowed_tags_cache[$_tag_name] ) {
|
230 |
-
$tag_position_offset += strlen( $_tag ); // To correct for removed chars
|
231 |
-
continue;
|
232 |
-
}
|
233 |
-
|
234 |
-
// If the tag is an opening tag, record it in $tags_to_close
|
235 |
-
if( $_tag_type === $tag_type['opening'] )
|
236 |
-
array_push( $tags_to_close, $_tag_name );
|
237 |
-
// If it is a closing tag, remove it from $tags_to_close
|
238 |
-
elseif( $_tag_type === $tag_type['closing'] )
|
239 |
-
array_pop( $tags_to_close );
|
240 |
-
|
241 |
-
// Inserting tag back into place
|
242 |
-
$text = substr_replace( $text, $_tag, $_actual_tag_position, 0);
|
243 |
-
}
|
244 |
-
|
245 |
-
// Add the appropriate closing tags to all unclosed tags
|
246 |
-
foreach( $tags_to_close as $_tag_name ) {
|
247 |
-
$text .= sprintf('</%1$s>', $_tag_name);
|
248 |
-
}
|
249 |
-
|
250 |
-
return $text;
|
251 |
-
}
|
252 |
-
|
253 |
-
|
254 |
-
/**
|
255 |
-
* Clone of wp_trim_words, without using the PREG_SPLIT_NO_EMPTY flag for preg_split
|
256 |
-
*
|
257 |
-
* Trims text to a certain number of words.
|
258 |
-
* This function is localized. For languages that count 'words' by the individual
|
259 |
-
* character (such as East Asian languages), the $num_words argument will apply
|
260 |
-
* to the number of individual characters.
|
261 |
-
*
|
262 |
-
* @param string $text Text to trim.
|
263 |
-
* @param int $num_words Number of words. Default 55.
|
264 |
-
* @param string $more Optional. What to append if $text needs to be trimmed. Default '…'.
|
265 |
-
* @return string Trimmed text.
|
266 |
-
*/
|
267 |
-
function wp_trim_words_wprss( $text, $num_words = 55, $more = null ) {
|
268 |
-
if ( null === $more ) {
|
269 |
-
$more = __( '…' );
|
270 |
-
}
|
271 |
-
$original_text = $text;
|
272 |
-
/* translators: If your word count is based on single characters (East Asian characters),
|
273 |
-
enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
|
274 |
-
if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
|
275 |
-
$text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
|
276 |
-
preg_match_all( '/./u', $text, $words_array );
|
277 |
-
$words_array = array_slice( $words_array[0], 0, $num_words + 1 );
|
278 |
-
$sep = '';
|
279 |
-
} else {
|
280 |
-
$words_array = preg_split( "/[\n\r\t ]/", $text, $num_words + 1 );
|
281 |
-
$sep = ' ';
|
282 |
-
}
|
283 |
-
if ( count( $words_array ) > $num_words ) {
|
284 |
-
array_pop( $words_array );
|
285 |
-
$text = implode( $sep, $words_array );
|
286 |
-
$text = $text . $more;
|
287 |
-
} else {
|
288 |
-
$text = implode( $sep, $words_array );
|
289 |
-
}
|
290 |
-
/**
|
291 |
-
* Filter the text content after words have been trimmed.
|
292 |
-
*
|
293 |
-
* @since 3.3.0
|
294 |
-
*
|
295 |
-
* @param string $text The trimmed text.
|
296 |
-
* @param int $num_words The number of words to trim the text to. Default 5.
|
297 |
-
* @param string $more An optional string to append to the end of the trimmed text, e.g. ….
|
298 |
-
* @param string $original_text The text before it was trimmed.
|
299 |
-
*/
|
300 |
-
return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
|
301 |
-
}
|
302 |
-
|
303 |
-
|
304 |
-
function wprss_validate_url( $url ) {
|
305 |
-
$expression =
|
306 |
-
'(' . # Capture 1: entire matched URL
|
307 |
-
'(?:' .
|
308 |
-
'[a-z][
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|