Version Description
Download this release
Release Info
Developer | radgeek |
Plugin | FeedWordPress |
Version | 2010.0528 |
Comparing to | |
See all releases |
Code changes from version 2010.0127 to 2010.0528
- ChangeLog.text +183 -5
- MagpieRSS-upgrade/rss-functions.php +0 -4
- MagpieRSS-upgrade/rss.php +0 -2045
- admin-ui.php +17 -9
- authors-page.php +8 -18
- backend-page.php +21 -5
- categories-page.php +6 -16
- compatability.php +25 -1
- feedfinder.class.php +25 -12
- feeds-page.php +49 -40
- feedtime.class.php +126 -0
- feedwordpress.php +332 -234
- magpiefromsimplepie.class.php +775 -0
- magpiemocklink.class.php +16 -3
- posts-page.php +112 -68
- readme.txt +41 -80
- syndicatedlink.class.php +70 -19
- syndicatedpost.class.php +1406 -1014
- syndication.php +23 -27
- updatedpostscontrol.class.php +1 -1
ChangeLog.text
CHANGED
@@ -2,13 +2,191 @@ FeedWordPress Change Log
|
|
2 |
========================
|
3 |
Changes from 2009.0707 to Trunk
|
4 |
-------------------------------
|
5 |
-
* NEW INTERFACE HOOKS
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
Changes from 2009.0618 to 2009.0707
|
14 |
-----------------------------------
|
2 |
========================
|
3 |
Changes from 2009.0707 to Trunk
|
4 |
-------------------------------
|
|
|
5 |
|
6 |
+
### Compatibility ###
|
7 |
+
|
8 |
+
* SIMPLEPIE IS NOW USED TO PARSE FEEDS; NO MORE MAGPIERSS UPGRADES NEEDED:
|
9 |
+
One of the biggest changes in this release is that FeedWordPress no
|
10 |
+
longer depends on MagpieRSS to parse feeds, and has switched to the much
|
11 |
+
more up-to-date and flexible SimplePie feed parser, which is included as
|
12 |
+
a standard part of WordPress versions 2.8 and later. Using SimplePie will
|
13 |
+
hopefully allow for better handling of feeds going further, and will
|
14 |
+
allow me greater flexibility in determining how exactly the feed parser
|
15 |
+
will operate. It also means that FeedWordPress no longer requires
|
16 |
+
special upgrades to the WordPress core MagpieRSS files, and should
|
17 |
+
eliminate quite a bit of complexity.
|
18 |
+
|
19 |
+
* MAGPIERSS COMPATIBILITY LAYER FOR EXISTING FILTERS AND ADD-ONS: However,
|
20 |
+
I have also implemented a compatibility layer to ensure that existing
|
21 |
+
filters and add-ons for FeedWordPress which depended on the MagpieRSS
|
22 |
+
data format *should not be broken* by the switch to SimplePie. Going
|
23 |
+
forward, I recommend that new filters and add-ons be written to take
|
24 |
+
advantage of the SimplePie object representations of items, feeds, etc.,
|
25 |
+
rather than the MagpieRSS arrays, but the MagpieRSS arrays will still
|
26 |
+
be available and older filters should continue to work as they have in
|
27 |
+
the past.
|
28 |
+
|
29 |
+
* COMPATIBILITY WITH WORDPRESS 2.9.x and 3.0: This release has been tested
|
30 |
+
for the existing WordPress 2.9.x branch and with the upcoming release of
|
31 |
+
WordPress 3.0. Changes in the user interface JavaScript between WordPress
|
32 |
+
2.8.x and WordPress 2.9 caused the tag box interface element to break in
|
33 |
+
the Syndication --> Categories & Tags settings page; changes in the API
|
34 |
+
functions for adding new authors caused fatal errors under certain
|
35 |
+
conditions in WordPress 3.0. These breakages have been fixed.
|
36 |
+
|
37 |
+
* DROPPED LEGACY SUPPORT FOR WORDPRESS PRIOR TO 2.8: Because SimplePie is
|
38 |
+
not included with versions of WordPress prior to 2.8, I have chosen to
|
39 |
+
drop legacy support for WordPress versions 1.5 through 2.7. If you are
|
40 |
+
using FeedWordPress with a version of WordPress before 2.8, you will
|
41 |
+
have to upgrade your installation of WordPress in order to take
|
42 |
+
advantage of this release.
|
43 |
+
|
44 |
+
* PHP 5.3 COMPATIBILITY: A couple of compatibility issues, which were
|
45 |
+
causing fatal errors amd ugly warnings for users of PHP 5.3,
|
46 |
+
have been eliminated.
|
47 |
|
48 |
+
### Features and Processing ###
|
49 |
+
|
50 |
+
* INTERFACE REORGANIZATION: The interface restructuring, began with
|
51 |
+
Version 2009.0612, has been completed. Catch-all settings pages have
|
52 |
+
been eliminated entirely for pages that cover each aspect of handling
|
53 |
+
a feed: Feeds & Updates, Posts & Links, Authors, Categories & Tags,
|
54 |
+
and Back End handling of the database and diagnostic information.
|
55 |
+
Extensive new interface hooks allow add-on modules to significantly
|
56 |
+
change or extend the FeedWordPress admin interface and workflow.
|
57 |
+
|
58 |
+
* STORING INFORMATION FROM THE FEED IN CUSTOM FIELDS: Many users
|
59 |
+
have written to request the ability to store information from elements
|
60 |
+
in the feed in a custom field on each post. (So that, for example, if
|
61 |
+
post includes a `itunes:duration` element, you could store the contents
|
62 |
+
in a Custom Field called `duration` on the post (for a Theme to access
|
63 |
+
later). The Custom Post Settings under Syndication --> Posts & Links now
|
64 |
+
allow you to access any item or feed tag, using a syntax similar to
|
65 |
+
a much-simplified version of XPath. See Posts & Links settings for
|
66 |
+
details.
|
67 |
+
|
68 |
+
* UPDATE-FREEZING ON MANUALLY EDITED POSTS: FeedWordPress now allows you
|
69 |
+
to mark posts that have been manually edited, so that the changes you
|
70 |
+
make will not be overwritten by later updates from the feed. If you make
|
71 |
+
manual edits to a particular post, just check the "Manual editing"
|
72 |
+
checkbox in order to protect your changes from being overwritten. If you
|
73 |
+
want to block *all* posts from being updated after they are imported
|
74 |
+
for the first time, a new "Updated Posts" setting in Posts & Links
|
75 |
+
allows you to freeze all posts from a particular feed, or all syndicated
|
76 |
+
posts.
|
77 |
+
|
78 |
+
* SETTING: FEED-BY-FEED SETTINGS FOR WHERE PERMALINKS POINT TO: You've
|
79 |
+
always been able to tell FeedWordPress whether permalinks for posts
|
80 |
+
should point to the original source of the story or the local copy. Now
|
81 |
+
you can choose different policies for different feeds, instead of one
|
82 |
+
global policy for all feeds. (Of course, you can still use a global
|
83 |
+
default if you prefer.)
|
84 |
+
|
85 |
+
* SETTING: USER CONTROL OVER TIMING BASIS. You can now determine the
|
86 |
+
schedule on which feeds are considered ready to poll for updates --
|
87 |
+
by default feeds become ready for polling after about 1 hour. You can
|
88 |
+
now increase or decrease the time window under Syndication --> Feeds &
|
89 |
+
Updates. (However, please pay *CAREFUL ATTENTION* to the recommendations
|
90 |
+
and DO NOT set the scheduling lower than 60 minutes unless you are
|
91 |
+
ABSOLUTELY SURE that you have specific permission from webmaster who
|
92 |
+
provides that specific feed to poll more frequently than that. If you
|
93 |
+
set this too low (and about 60 minutes is the polite minimum if you
|
94 |
+
haven't been given a different figure), most webmasters will consider
|
95 |
+
the frequent hits on their server as rude, or even downright abusive.
|
96 |
+
|
97 |
+
* OTHER SETTINGS: New settings also include the ability to stop FWP from
|
98 |
+
resolving relative URLs within syndicated content, and the ability to
|
99 |
+
choose whether FeedWordPress should indicate the comment feed from the
|
100 |
+
original source, or the local comment feed, when providing the comment
|
101 |
+
feed URL for a syndicated post.
|
102 |
+
|
103 |
+
### PARSING ###
|
104 |
+
|
105 |
+
* BETTER DATE HANDLING -- FEWER FLASHBACKS TO 1969 and 1970: FeedWordPress
|
106 |
+
has made some bugfixes and some improvements in the logic for parsing
|
107 |
+
dates. This should allow FeedWordPress to correctly parse more dates in
|
108 |
+
more feeds; and, in the last resort, when FeedWordPress fails to
|
109 |
+
correctly parse a date, to fall back to a more intelligent default. This
|
110 |
+
should hopefully avoid most or all error conditions that have resulted
|
111 |
+
in articles being erroneously dated to the dawn of the Unix epoch
|
112 |
+
(31 December 1969 or 1 January 1970).
|
113 |
+
|
114 |
+
* FULL-TEXT "EXCERPTS" NOW PROPERLY SHORTENED. Based on a straightforward
|
115 |
+
reading of the existing RSS specs, it's reasonable for the
|
116 |
+
rss:description element to be read as a plaintext summary or excerpt for
|
117 |
+
the item containing the description -- with the full text of the item,
|
118 |
+
if available, in another, better-suited element, such as the de facto
|
119 |
+
standard content:encoded extension element. The problem is that uses of
|
120 |
+
RSS rarely have much to do with anything like a straightforward reading
|
121 |
+
of the specs. As a result, many actual RSS producers in the wild put the
|
122 |
+
full text of the article in a description element. But since
|
123 |
+
FeedWordPress has treated this text as a summary, this produces
|
124 |
+
aggregated posts with lengthy "excerpts" containing the full text of the
|
125 |
+
article. This release of FeedWordPress fixes the problem by doing a
|
126 |
+
little digging before treating rss:description as a summary: if the
|
127 |
+
description element is used properly as a plain text summary, then
|
128 |
+
FeedWordPress will take the summary provided by the feed, rather than
|
129 |
+
recreating its own excerpt from the full text; but if an RSS item has no
|
130 |
+
full-text element other than description, FeedWordPress will treat the
|
131 |
+
description element as the full text of the article, and generate a
|
132 |
+
shortened excerpt automatically from that text.
|
133 |
+
|
134 |
+
### API ###
|
135 |
+
|
136 |
+
* TEMPLATE API: new template tags `get_local_permalink()` and
|
137 |
+
`the_local_permalink()` allow you to access the permalink for a post on
|
138 |
+
your aggregator site, even when FeedWordPress is rewriting permalinks to
|
139 |
+
point to the original source site.
|
140 |
+
|
141 |
+
* NEW HOOKS FOR ADD-ONS AND FILTERS: I have added a number of new hooks
|
142 |
+
which allow add-on modules to filter more precisely, gather information
|
143 |
+
at more points, and to enhance the FeedWordPress admin interface. For
|
144 |
+
a list of new hooks and documentation, see the FeedWordPress
|
145 |
+
documentation wiki at
|
146 |
+
<http://feedwordpress.radgeek.com/wiki/add-ons-and-filters>
|
147 |
+
|
148 |
+
* FILTER API: A number of new utility methods have been added to the
|
149 |
+
SyndicatedPost class to make it easier for filters and add-ons to
|
150 |
+
|
151 |
+
* FILTER API: Globals $fwp_channel and $fwp_feedmeta DEPRECATED. These
|
152 |
+
global variables, originally introduced to allow filters access to
|
153 |
+
information about the source feed in `syndicated_item` filters (which
|
154 |
+
were passed in through global variables rather than as parameters
|
155 |
+
because of a bug in WP 1.5 which was then fixed in 1.5.1) have been
|
156 |
+
DEPRECATED. If you have any filters or add-ons which still depend on
|
157 |
+
these global variables, you should see about fixing them to access data
|
158 |
+
about the source feed using the SyndicatedPost::link element instead.
|
159 |
+
For documentation, see the FeedWordPress documentation wiki at
|
160 |
+
<http://feedwordpress.radgeek.com/wiki/syndicatedpost> and
|
161 |
+
<http://feedwordpress.radgeek.com/wiki/syndicatedlink>.
|
162 |
+
|
163 |
+
* DIAGNOSTICS: I've included a number of new diagnostic options and
|
164 |
+
messages, which should allow an experienced user to better investigate
|
165 |
+
any problems that may crop up.
|
166 |
+
|
167 |
+
### Bug Fixes ###
|
168 |
+
|
169 |
+
* BUGFIX: & IN PERMALINKS NO LONGER CAUSING ATOM OR HTML VALIDATION
|
170 |
+
EFFORTS: Many users reported an issue in which syndicating a feed with
|
171 |
+
special XML characters in the URLs (& was the most common, since it is
|
172 |
+
used to separate HTTP GET parameters) would cause the aggregator's
|
173 |
+
feeds to produce invalid (malformed) XML. This update addresses the
|
174 |
+
issue in Atom feeds. Unfortunately, it has not been technically possible
|
175 |
+
to address the problem in RSS 2.0 feeds, due to limitations on
|
176 |
+
WordPress's internal templates for RSS feeds.
|
177 |
+
|
178 |
+
* BUGFIX: BROKEN URLS IN "POPULAR POSTS" AND SIMILAR PLUGINS SHOULD NO
|
179 |
+
LONGER BE BROKEN. A number of users noticed an issue where plugins and
|
180 |
+
templates that listed posts in locations outside of the post loop
|
181 |
+
(for example, "Popular Posts"-style plugins that listed posts in the
|
182 |
+
sidebar), often produced the wrong URL for post links. (Typically, all
|
183 |
+
the posts listed would get the same wrong URL.) This should now be
|
184 |
+
fixed. Thanks to Björn for sending in a quick fix!
|
185 |
+
|
186 |
+
* MINOR BUGFIXES: This release includes a number of fixes to minor bugs
|
187 |
+
and compatibility issues, including: silent failures of the "Syndicate"
|
188 |
+
button, "Illegal Offset Type" error messages from MagpieRSS,
|
189 |
+
|
190 |
|
191 |
Changes from 2009.0618 to 2009.0707
|
192 |
-----------------------------------
|
MagpieRSS-upgrade/rss-functions.php
DELETED
@@ -1,4 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
// Deprecated. Use rss.php instead.
|
3 |
-
require_once (ABSPATH . WPINC . '/rss.php');
|
4 |
-
?>
|
|
|
|
|
|
|
|
MagpieRSS-upgrade/rss.php
DELETED
@@ -1,2045 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/* Project: MagpieRSS: a simple RSS integration tool
|
3 |
-
* File: A compiled file for RSS syndication
|
4 |
-
* Author: Kellan Elliot-McCrea <kellan@protest.net>
|
5 |
-
* WordPress development team <http://www.wordpress.org/>
|
6 |
-
* Charles Johnson <technophilia@radgeek.com>
|
7 |
-
* Version: 2010.0122
|
8 |
-
* License: GPL
|
9 |
-
*
|
10 |
-
* Provenance:
|
11 |
-
*
|
12 |
-
* This is a drop-in replacement for the `rss-functions.php` provided with the
|
13 |
-
* WordPress 1.5 distribution, which upgrades the version of MagpieRSS from 0.51
|
14 |
-
* to 0.8a. The update improves handling of character encoding, supports
|
15 |
-
* multiple categories for posts (using <dc:subject> or <category>), supports
|
16 |
-
* Atom 1.0, and implements many other useful features. The file is derived from
|
17 |
-
* a combination of (1) the WordPress development team's modifications to
|
18 |
-
* MagpieRSS 0.51 and (2) the latest bleeding-edge updates to the "official"
|
19 |
-
* MagpieRSS software, including Kellan's original work and some substantial
|
20 |
-
* updates by Charles Johnson. All possible through the magic of the GPL. Yay
|
21 |
-
* for free software!
|
22 |
-
*
|
23 |
-
* Differences from the main branch of MagpieRSS:
|
24 |
-
*
|
25 |
-
* 1. Everything in rss_parse.inc, rss_fetch.inc, rss_cache.inc, and
|
26 |
-
* rss_utils.inc is included in one file.
|
27 |
-
*
|
28 |
-
* 2. MagpieRSS returns the WordPress version as the user agent, rather than
|
29 |
-
* Magpie
|
30 |
-
*
|
31 |
-
* 3. class RSSCache is a modified version by WordPress developers, which
|
32 |
-
* caches feeds in the WordPress database (in the options table), rather
|
33 |
-
* than writing external files directly.
|
34 |
-
*
|
35 |
-
* 4. There are two WordPress-specific functions, get_rss() and wp_rss()
|
36 |
-
*
|
37 |
-
* Differences from the version of MagpieRSS packaged with WordPress:
|
38 |
-
*
|
39 |
-
* 1. Support for translation between multiple character encodings. Under
|
40 |
-
* PHP 5 this is very nicely handled by the XML parsing library. Under PHP
|
41 |
-
* 4 we need to do a little bit of work ourselves, using either iconv or
|
42 |
-
* mb_convert_encoding if it is not one of the (extremely limited) number
|
43 |
-
* of character sets that PHP 4's XML module can handle natively.
|
44 |
-
*
|
45 |
-
* 2. Numerous bug fixes.
|
46 |
-
*
|
47 |
-
* 3. The parser class MagpieRSS has been substantially revised to better
|
48 |
-
* support popular features such as enclosures and multiple categories,
|
49 |
-
* and to support the new Atom 1.0 IETF standard. (Atom feeds are
|
50 |
-
* normalized so as to make the data available using terminology from
|
51 |
-
* either Atom 0.3 or Atom 1.0. Atom 0.3 backward-compatibility is provided
|
52 |
-
* to allow existing software to easily begin accepting Atom 1.0 data; new
|
53 |
-
* software SHOULD NOT depend on the 0.3 terminology, but rather use the
|
54 |
-
* normalization as a convenient way to keep supporting 0.3 feeds while
|
55 |
-
* they linger in the world.)
|
56 |
-
*
|
57 |
-
* The upgraded MagpieRSS can also now handle some content constructs that
|
58 |
-
* had not been handled well by previous versions of Magpie (such as the
|
59 |
-
* use of namespaced XHTML in <xhtml:body> or <xhtml:div> elements to
|
60 |
-
* provide the full content of posts in RSS 2.0 feeds).
|
61 |
-
*
|
62 |
-
* Unlike previous versions of MagpieRSS, this version can parse multiple
|
63 |
-
* instances of the same child element in item/entry and channel/feed
|
64 |
-
* containers. This is done using simple counters next to the element
|
65 |
-
* names: the first <category> element on an RSS item, for example, can be
|
66 |
-
* found in $item['category'] (thus preserving backward compatibility); the
|
67 |
-
* second in $item['category#2'], the third in $item['category#3'], and so
|
68 |
-
* on. The number of categories applied to the item can be found in
|
69 |
-
* $item['category#']
|
70 |
-
*
|
71 |
-
* Also unlike previous versions of MagpieRSS, this version allows you to
|
72 |
-
* access the values of elements' attributes as well as the content they
|
73 |
-
* contain. This can be done using a simple syntax inspired by XPath: to
|
74 |
-
* access the type attribute of an RSS 2.0 enclosure, for example, you
|
75 |
-
* need only access `$item['enclosure@type']`. A comma-separated list of
|
76 |
-
* attributes for the enclosure element is stored in `$item['enclosure@']`.
|
77 |
-
* (This syntax interacts easily with the syntax for multiple categories;
|
78 |
-
* for example, the value of the `scheme` attribute for the fourth category
|
79 |
-
* element on a particular item is stored in `$item['category#4@scheme']`.)
|
80 |
-
*
|
81 |
-
* Note also that this implementation IS NOT backward-compatible with the
|
82 |
-
* kludges that were used to hack in support for multiple categories and
|
83 |
-
* for enclosures in upgraded versions of MagpieRSS distributed with
|
84 |
-
* previous versions of FeedWordPress. If your hacks or filter plugins
|
85 |
-
* depended on the old way of doing things... well, I warned you that they
|
86 |
-
* might not be permanent. Sorry!
|
87 |
-
*/
|
88 |
-
|
89 |
-
define('RSS', 'RSS');
|
90 |
-
define('ATOM', 'Atom');
|
91 |
-
|
92 |
-
################################################################################
|
93 |
-
## WordPress: make some settings WordPress-appropriate #########################
|
94 |
-
################################################################################
|
95 |
-
|
96 |
-
define('MAGPIE_USER_AGENT', 'WordPress/' . $wp_version . '(+http://www.wordpress.org)');
|
97 |
-
|
98 |
-
$wp_encoding = get_option('blog_charset', /*default=*/ 'ISO-8859-1');
|
99 |
-
define('MAGPIE_OUTPUT_ENCODING', ($wp_encoding?$wp_encoding:'ISO-8859-1'));
|
100 |
-
|
101 |
-
################################################################################
|
102 |
-
## rss_parse.inc: from MagpieRSS 0.85 ##########################################
|
103 |
-
################################################################################
|
104 |
-
|
105 |
-
/**
|
106 |
-
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
|
107 |
-
*
|
108 |
-
* see: rss_fetch.inc for a simpler interface with integrated caching support
|
109 |
-
*
|
110 |
-
*/
|
111 |
-
class MagpieRSS {
|
112 |
-
var $parser;
|
113 |
-
|
114 |
-
var $current_item = array(); // item currently being parsed
|
115 |
-
var $items = array(); // collection of parsed items
|
116 |
-
var $channel = array(); // hash of channel fields
|
117 |
-
var $textinput = array();
|
118 |
-
var $image = array();
|
119 |
-
var $feed_type;
|
120 |
-
var $feed_version;
|
121 |
-
var $encoding = ''; // output encoding of parsed rss
|
122 |
-
|
123 |
-
var $_source_encoding = ''; // only set if we have to parse xml prolog
|
124 |
-
|
125 |
-
var $ERROR = "";
|
126 |
-
var $WARNING = "";
|
127 |
-
|
128 |
-
// define some constants
|
129 |
-
var $_XMLNS_FAMILIAR = array (
|
130 |
-
'http://www.w3.org/2005/Atom' => 'atom' /* 1.0 */,
|
131 |
-
'http://purl.org/atom/ns#' => 'atom' /* pre-1.0 */,
|
132 |
-
'http://purl.org/rss/1.0/' => 'rss' /* 1.0 */,
|
133 |
-
'http://backend.userland.com/RSS2' => 'rss' /* 2.0 */,
|
134 |
-
'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf',
|
135 |
-
'http://www.w3.org/1999/xhtml' => 'xhtml',
|
136 |
-
'http://purl.org/dc/elements/1.1/' => 'dc',
|
137 |
-
'http://purl.org/dc/terms/' => 'dcterms',
|
138 |
-
'http://purl.org/rss/1.0/modules/content/' => 'content',
|
139 |
-
'http://purl.org/rss/1.0/modules/syndication/' => 'sy',
|
140 |
-
'http://purl.org/rss/1.0/modules/taxonomy/' => 'taxo',
|
141 |
-
'http://purl.org/rss/1.0/modules/dc/' => 'dc',
|
142 |
-
'http://wellformedweb.org/CommentAPI/' => 'wfw',
|
143 |
-
'http://webns.net/mvcb/' => 'admin',
|
144 |
-
'http://purl.org/rss/1.0/modules/annotate/' => 'annotate',
|
145 |
-
'http://xmlns.com/foaf/0.1/' => 'foaf',
|
146 |
-
'http://madskills.com/public/xml/rss/module/trackback/' => 'trackback',
|
147 |
-
'http://web.resource.org/cc/' => 'cc',
|
148 |
-
'http://search.yahoo.com/mrss' => 'media',
|
149 |
-
'http://search.yahoo.com/mrss/' => 'media',
|
150 |
-
'http://video.search.yahoo.com/mrss' => 'media',
|
151 |
-
'http://video.search.yahoo.com/mrss/' => 'media',
|
152 |
-
);
|
153 |
-
|
154 |
-
var $_XMLBASE_RESOLVE = array (
|
155 |
-
// Atom 0.3 and 1.0 xml:base support
|
156 |
-
'atom' => array (
|
157 |
-
'link' => array ('href' => true),
|
158 |
-
'content' => array ('src' => true, '*xml' => true, '*html' => true),
|
159 |
-
'summary' => array ('*xml' => true, '*html' => true),
|
160 |
-
'title' => array ('*xml' => true, '*html' => true),
|
161 |
-
'rights' => array ('*xml' => true, '*html' => true),
|
162 |
-
'subtitle' => array ('*xml' => true, '*html' => true),
|
163 |
-
'info' => array('*xml' => true, '*html' => true),
|
164 |
-
'tagline' => array('*xml' => true, '*html' => true),
|
165 |
-
'copyright' => array ('*xml' => true, '*html' => true),
|
166 |
-
'generator' => array ('uri' => true, 'url' => true),
|
167 |
-
'uri' => array ('*content' => true),
|
168 |
-
'url' => array ('*content' => true),
|
169 |
-
'icon' => array ('*content' => true),
|
170 |
-
'logo' => array ('*content' => true),
|
171 |
-
),
|
172 |
-
|
173 |
-
// for inline namespaced XHTML
|
174 |
-
'xhtml' => array (
|
175 |
-
'a' => array ('href' => true),
|
176 |
-
'applet' => array('codebase' => true),
|
177 |
-
'area' => array('href' => true),
|
178 |
-
'blockquote' => array('cite' => true),
|
179 |
-
'body' => array('background' => true),
|
180 |
-
'del' => array('cite' => true),
|
181 |
-
'form' => array('action' => true),
|
182 |
-
'frame' => array('longdesc' => true, 'src' => true),
|
183 |
-
'iframe' => array('longdesc' => true, 'iframe' => true, 'src' => true),
|
184 |
-
'head' => array('profile' => true),
|
185 |
-
'img' => array('longdesc' => true, 'src' => true, 'usemap' => true),
|
186 |
-
'input' => array('src' => true, 'usemap' => true),
|
187 |
-
'ins' => array('cite' => true),
|
188 |
-
'link' => array('href' => true),
|
189 |
-
'object' => array('classid' => true, 'codebase' => true, 'data' => true, 'usemap' => true),
|
190 |
-
'q' => array('cite' => true),
|
191 |
-
'script' => array('src' => true),
|
192 |
-
),
|
193 |
-
);
|
194 |
-
|
195 |
-
var $_ATOM_CONTENT_CONSTRUCTS = array(
|
196 |
-
'content', 'summary', 'title', /* common */
|
197 |
-
'info', 'tagline', 'copyright', /* Atom 0.3 */
|
198 |
-
'rights', 'subtitle', /* Atom 1.0 */
|
199 |
-
);
|
200 |
-
var $_XHTML_CONTENT_CONSTRUCTS = array('body', 'div');
|
201 |
-
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
|
202 |
-
|
203 |
-
// parser variables, useless if you're not a parser, treat as private
|
204 |
-
var $stack = array('element' => array (), 'ns' => array (), 'xmlns' => array (), 'xml:base' => array ()); // stack of XML data
|
205 |
-
|
206 |
-
var $inchannel = false;
|
207 |
-
var $initem = false;
|
208 |
-
|
209 |
-
var $incontent = array(); // non-empty if in namespaced XML content field
|
210 |
-
var $xml_escape = false; // true when accepting namespaced XML
|
211 |
-
var $exclude_top = false; // true when Atom 1.0 type="xhtml"
|
212 |
-
|
213 |
-
var $intextinput = false;
|
214 |
-
var $inimage = false;
|
215 |
-
var $root_namespaces = array();
|
216 |
-
var $current_namespace = false;
|
217 |
-
var $working_namespace_table = array();
|
218 |
-
|
219 |
-
/**
|
220 |
-
* Set up XML parser, parse source, and return populated RSS object..
|
221 |
-
*
|
222 |
-
* @param string $source string containing the RSS to be parsed
|
223 |
-
*
|
224 |
-
* NOTE: Probably a good idea to leave the encoding options alone unless
|
225 |
-
* you know what you're doing as PHP's character set support is
|
226 |
-
* a little weird.
|
227 |
-
*
|
228 |
-
* NOTE: A lot of this is unnecessary but harmless with PHP5
|
229 |
-
*
|
230 |
-
*
|
231 |
-
* @param string $output_encoding output the parsed RSS in this character
|
232 |
-
* set defaults to ISO-8859-1 as this is PHP's
|
233 |
-
* default.
|
234 |
-
*
|
235 |
-
* NOTE: might be changed to UTF-8 in future
|
236 |
-
* versions.
|
237 |
-
*
|
238 |
-
* @param string $input_encoding the character set of the incoming RSS source.
|
239 |
-
* Leave blank and Magpie will try to figure it
|
240 |
-
* out.
|
241 |
-
*
|
242 |
-
*
|
243 |
-
* @param bool $detect_encoding if false Magpie won't attempt to detect
|
244 |
-
* source encoding. (caveat emptor)
|
245 |
-
*
|
246 |
-
*/
|
247 |
-
function MagpieRSS ($source, $output_encoding='ISO-8859-1',
|
248 |
-
$input_encoding=null, $detect_encoding=true, $base_uri=null)
|
249 |
-
{
|
250 |
-
# if PHP xml isn't compiled in, die
|
251 |
-
#
|
252 |
-
if (!function_exists('xml_parser_create')) {
|
253 |
-
$this->error( "Failed to load PHP's XML Extension. " .
|
254 |
-
"http://www.php.net/manual/en/ref.xml.php",
|
255 |
-
E_USER_ERROR );
|
256 |
-
}
|
257 |
-
|
258 |
-
list($parser, $source) = $this->create_parser($source,
|
259 |
-
$output_encoding, $input_encoding, $detect_encoding);
|
260 |
-
|
261 |
-
|
262 |
-
if (!is_resource($parser)) {
|
263 |
-
$this->error( "Failed to create an instance of PHP's XML parser. " .
|
264 |
-
"http://www.php.net/manual/en/ref.xml.php",
|
265 |
-
E_USER_ERROR );
|
266 |
-
}
|
267 |
-
|
268 |
-
|
269 |
-
$this->parser = $parser;
|
270 |
-
|
271 |
-
# pass in parser, and a reference to this object
|
272 |
-
# setup handlers
|
273 |
-
#
|
274 |
-
xml_set_object( $this->parser, $this );
|
275 |
-
xml_set_element_handler($this->parser,
|
276 |
-
'feed_start_element', 'feed_end_element' );
|
277 |
-
|
278 |
-
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
|
279 |
-
|
280 |
-
$this->stack['xml:base'] = array($base_uri);
|
281 |
-
|
282 |
-
$status = xml_parse( $this->parser, $source );
|
283 |
-
|
284 |
-
if (! $status ) {
|
285 |
-
$errorcode = xml_get_error_code( $this->parser );
|
286 |
-
if ( $errorcode != XML_ERROR_NONE ) {
|
287 |
-
$xml_error = xml_error_string( $errorcode );
|
288 |
-
$error_line = xml_get_current_line_number($this->parser);
|
289 |
-
$error_col = xml_get_current_column_number($this->parser);
|
290 |
-
$errormsg = "$xml_error at line $error_line, column $error_col";
|
291 |
-
|
292 |
-
$this->error( $errormsg );
|
293 |
-
}
|
294 |
-
}
|
295 |
-
|
296 |
-
xml_parser_free( $this->parser );
|
297 |
-
|
298 |
-
$this->normalize();
|
299 |
-
}
|
300 |
-
|
301 |
-
function feed_start_element($p, $element, &$attributes) {
|
302 |
-
$el = strtolower($element);
|
303 |
-
|
304 |
-
$namespaces = end($this->stack['xmlns']);
|
305 |
-
$baseuri = end($this->stack['xml:base']);
|
306 |
-
|
307 |
-
if (isset($attributes['xml:base'])) {
|
308 |
-
$baseuri = Relative_URI::resolve($attributes['xml:base'], $baseuri);
|
309 |
-
}
|
310 |
-
array_push($this->stack['xml:base'], $baseuri);
|
311 |
-
|
312 |
-
// scan for xml namespace declarations. ugly ugly ugly.
|
313 |
-
// theoretically we could use xml_set_start_namespace_decl_handler and
|
314 |
-
// xml_set_end_namespace_decl_handler to handle this more elegantly, but
|
315 |
-
// support for these is buggy
|
316 |
-
foreach ($attributes as $attr => $value) {
|
317 |
-
if ( preg_match('/^xmlns(\:([A-Z_a-z].*))?$/', $attr, $match) ) {
|
318 |
-
$ns = (isset($match[2]) ? $match[2] : '');
|
319 |
-
$namespaces[$ns] = $value;
|
320 |
-
}
|
321 |
-
}
|
322 |
-
|
323 |
-
array_push($this->stack['xmlns'], $namespaces);
|
324 |
-
|
325 |
-
// check for a namespace, and split if found
|
326 |
-
// Don't munge content tags
|
327 |
-
$ns = $this->xmlns($element);
|
328 |
-
if ( empty($this->incontent) ) {
|
329 |
-
$el = strtolower($ns['element']);
|
330 |
-
$this->current_namespace = $ns['effective'];
|
331 |
-
array_push($this->stack['ns'], $ns['effective']);
|
332 |
-
}
|
333 |
-
|
334 |
-
$nsc = $ns['canonical']; $nse = $ns['element'];
|
335 |
-
if ( isset($this->_XMLBASE_RESOLVE[$nsc][$nse]) ) {
|
336 |
-
if (isset($this->_XMLBASE_RESOLVE[$nsc][$nse]['*xml'])) {
|
337 |
-
$attributes['xml:base'] = $baseuri;
|
338 |
-
}
|
339 |
-
foreach ($attributes as $key => $value) {
|
340 |
-
if (isset($this->_XMLBASE_RESOLVE[$nsc][$nse][strtolower($key)])) {
|
341 |
-
$attributes[$key] = Relative_URI::resolve($attributes[$key], $baseuri);
|
342 |
-
}
|
343 |
-
}
|
344 |
-
}
|
345 |
-
|
346 |
-
$attrs = array_change_key_case($attributes, CASE_LOWER);
|
347 |
-
|
348 |
-
# if feed type isn't set, then this is first element of feed
|
349 |
-
# identify feed from root element
|
350 |
-
#
|
351 |
-
if (!isset($this->feed_type) ) {
|
352 |
-
if ( $el == 'rdf' ) {
|
353 |
-
$this->feed_type = RSS;
|
354 |
-
$this->root_namespaces = array('rss', 'rdf');
|
355 |
-
$this->feed_version = '1.0';
|
356 |
-
}
|
357 |
-
elseif ( $el == 'rss' ) {
|
358 |
-
$this->feed_type = RSS;
|
359 |
-
$this->root_namespaces = array('rss');
|
360 |
-
$this->feed_version = $attrs['version'];
|
361 |
-
}
|
362 |
-
elseif ( $el == 'feed' ) {
|
363 |
-
$this->feed_type = ATOM;
|
364 |
-
$this->root_namespaces = array('atom');
|
365 |
-
if ($ns['uri'] == 'http://www.w3.org/2005/Atom') { // Atom 1.0
|
366 |
-
$this->feed_version = '1.0';
|
367 |
-
}
|
368 |
-
else { // Atom 0.3, probably.
|
369 |
-
$this->feed_version = $attrs['version'];
|
370 |
-
}
|
371 |
-
$this->inchannel = true;
|
372 |
-
}
|
373 |
-
return;
|
374 |
-
}
|
375 |
-
|
376 |
-
// if we're inside a namespaced content construct, treat tags as text
|
377 |
-
if ( !empty($this->incontent) )
|
378 |
-
{
|
379 |
-
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
380 |
-
if ($ns['effective']=='xhtml') {
|
381 |
-
$tag = $ns['element'];
|
382 |
-
}
|
383 |
-
else {
|
384 |
-
$tag = $element;
|
385 |
-
$xmlns = 'xmlns';
|
386 |
-
if (strlen($ns['prefix'])>0) {
|
387 |
-
$xmlns = $xmlns . ':' . $ns['prefix'];
|
388 |
-
}
|
389 |
-
$attributes[$xmlns] = $ns['uri']; // make sure it's visible
|
390 |
-
}
|
391 |
-
|
392 |
-
// if tags are inlined, then flatten
|
393 |
-
$attrs_str = join(' ',
|
394 |
-
array_map(array($this, 'map_attrs'),
|
395 |
-
array_keys($attributes),
|
396 |
-
array_values($attributes) )
|
397 |
-
);
|
398 |
-
|
399 |
-
if (strlen($attrs_str) > 0) { $attrs_str = ' '.$attrs_str; }
|
400 |
-
$this->append_content( "<{$tag}{$attrs_str}>" );
|
401 |
-
}
|
402 |
-
array_push($this->incontent, $ns); // stack for parsing content XML
|
403 |
-
}
|
404 |
-
|
405 |
-
elseif ( $el == 'channel' ) {
|
406 |
-
$this->inchannel = true;
|
407 |
-
}
|
408 |
-
|
409 |
-
elseif ($el == 'item' or $el == 'entry' )
|
410 |
-
{
|
411 |
-
$this->initem = true;
|
412 |
-
if ( isset($attrs['rdf:about']) ) {
|
413 |
-
$this->current_item['about'] = $attrs['rdf:about'];
|
414 |
-
}
|
415 |
-
}
|
416 |
-
|
417 |
-
// if we're in the default namespace of an RSS feed,
|
418 |
-
// record textinput or image fields
|
419 |
-
elseif (
|
420 |
-
$this->feed_type == RSS and
|
421 |
-
$this->current_namespace == '' and
|
422 |
-
$el == 'textinput' )
|
423 |
-
{
|
424 |
-
$this->intextinput = true;
|
425 |
-
}
|
426 |
-
|
427 |
-
elseif (
|
428 |
-
$this->feed_type == RSS and
|
429 |
-
$this->current_namespace == '' and
|
430 |
-
$el == 'image' )
|
431 |
-
{
|
432 |
-
$this->inimage = true;
|
433 |
-
}
|
434 |
-
|
435 |
-
// set stack[0] to current element
|
436 |
-
else {
|
437 |
-
// Atom support many links per containing element.
|
438 |
-
// Magpie treats link elements of type rel='alternate'
|
439 |
-
// as being equivalent to RSS's simple link element.
|
440 |
-
|
441 |
-
$atom_link = false;
|
442 |
-
if ( ($ns['canonical']=='atom') and $el == 'link') {
|
443 |
-
$atom_link = true;
|
444 |
-
if (isset($attrs['rel']) and $attrs['rel'] != 'alternate') {
|
445 |
-
$el = $el . "_" . $attrs['rel']; // pseudo-element names for Atom link elements
|
446 |
-
}
|
447 |
-
}
|
448 |
-
# handle atom content constructs
|
449 |
-
elseif ( ($ns['canonical']=='atom') and in_array($el, $this->_ATOM_CONTENT_CONSTRUCTS) )
|
450 |
-
{
|
451 |
-
// avoid clashing w/ RSS mod_content
|
452 |
-
if ($el == 'content' ) {
|
453 |
-
$el = 'atom_content';
|
454 |
-
}
|
455 |
-
|
456 |
-
// assume that everything accepts namespaced XML
|
457 |
-
// (that will pass through some non-validating feeds;
|
458 |
-
// but so what? this isn't a validating parser)
|
459 |
-
$this->incontent = array();
|
460 |
-
array_push($this->incontent, $ns); // start a stack
|
461 |
-
|
462 |
-
$this->xml_escape = $this->accepts_namespaced_xml($attrs);
|
463 |
-
|
464 |
-
if ( isset($attrs['type']) and trim(strtolower($attrs['type']))=='xhtml') {
|
465 |
-
$this->exclude_top = true;
|
466 |
-
} else {
|
467 |
-
$this->exclude_top = false;
|
468 |
-
}
|
469 |
-
}
|
470 |
-
# Handle inline XHTML body elements --CWJ
|
471 |
-
elseif ($ns['effective']=='xhtml' and in_array($el, $this->_XHTML_CONTENT_CONSTRUCTS)) {
|
472 |
-
$this->current_namespace = 'xhtml';
|
473 |
-
$this->incontent = array();
|
474 |
-
array_push($this->incontent, $ns); // start a stack
|
475 |
-
|
476 |
-
$this->xml_escape = true;
|
477 |
-
$this->exclude_top = false;
|
478 |
-
}
|
479 |
-
|
480 |
-
array_unshift($this->stack['element'], $el);
|
481 |
-
$elpath = join('_', array_reverse($this->stack['element']));
|
482 |
-
|
483 |
-
$n = $this->element_count($elpath);
|
484 |
-
$this->element_count($elpath, $n+1);
|
485 |
-
|
486 |
-
if ($n > 0) {
|
487 |
-
array_shift($this->stack['element']);
|
488 |
-
array_unshift($this->stack['element'], $el.'#'.($n+1));
|
489 |
-
$elpath = join('_', array_reverse($this->stack['element']));
|
490 |
-
}
|
491 |
-
|
492 |
-
// this makes the baby Jesus cry, but we can't do it in normalize()
|
493 |
-
// because we've made the element name for Atom links unpredictable
|
494 |
-
// by tacking on the relation to the end. -CWJ
|
495 |
-
if ($atom_link and isset($attrs['href'])) {
|
496 |
-
$this->append($elpath, $attrs['href']);
|
497 |
-
}
|
498 |
-
|
499 |
-
// add attributes
|
500 |
-
if (count($attrs) > 0) {
|
501 |
-
$this->append($elpath.'@', join(',', array_keys($attrs)));
|
502 |
-
foreach ($attrs as $attr => $value) {
|
503 |
-
$this->append($elpath.'@'.$attr, $value);
|
504 |
-
}
|
505 |
-
}
|
506 |
-
}
|
507 |
-
}
|
508 |
-
|
509 |
-
function feed_cdata ($p, $text) {
|
510 |
-
if ($this->incontent) {
|
511 |
-
if ($this->xml_escape) { $text = htmlspecialchars($text, ENT_COMPAT, $this->encoding); }
|
512 |
-
$this->append_content( $text );
|
513 |
-
} else {
|
514 |
-
$current_el = join('_', array_reverse($this->stack['element']));
|
515 |
-
$this->append($current_el, $text);
|
516 |
-
}
|
517 |
-
}
|
518 |
-
|
519 |
-
function feed_end_element ($p, $el) {
|
520 |
-
$closer = $this->xmlns($el);
|
521 |
-
|
522 |
-
if ( $this->incontent ) {
|
523 |
-
$opener = array_pop($this->incontent);
|
524 |
-
|
525 |
-
// balance tags properly
|
526 |
-
// note: i don't think this is actually neccessary
|
527 |
-
if ($opener != $closer) {
|
528 |
-
array_push($this->incontent, $opener);
|
529 |
-
$this->append_content("<$el />");
|
530 |
-
} elseif ($this->incontent) { // are we in the content construct still?
|
531 |
-
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
532 |
-
if ($closer['effective']=='xhtml') {
|
533 |
-
$tag = $closer['element'];
|
534 |
-
}
|
535 |
-
else {
|
536 |
-
$tag = $el;
|
537 |
-
}
|
538 |
-
$this->append_content("</$tag>");
|
539 |
-
}
|
540 |
-
} else { // if we're done with the content construct, shift the opening of the content construct off the normal stack
|
541 |
-
array_shift( $this->stack['element'] );
|
542 |
-
}
|
543 |
-
}
|
544 |
-
elseif ($closer['effective'] == '') {
|
545 |
-
$el = strtolower($closer['element']);
|
546 |
-
if ( $el == 'item' or $el == 'entry' ) {
|
547 |
-
$this->items[] = $this->current_item;
|
548 |
-
$this->current_item = array();
|
549 |
-
$this->initem = false;
|
550 |
-
$this->current_category = 0;
|
551 |
-
}
|
552 |
-
elseif ($this->feed_type == RSS and $el == 'textinput' ) {
|
553 |
-
$this->intextinput = false;
|
554 |
-
}
|
555 |
-
elseif ($this->feed_type == RSS and $el == 'image' ) {
|
556 |
-
$this->inimage = false;
|
557 |
-
}
|
558 |
-
elseif ($el == 'channel' or $el == 'feed' ) {
|
559 |
-
$this->inchannel = false;
|
560 |
-
} else {
|
561 |
-
$nsc = $closer['canonical']; $nse = $closer['element'];
|
562 |
-
if (isset($this->_XMLBASE_RESOLVE[$nsc][$nse]['*content'])) {
|
563 |
-
// Resolve relative URI in content of tag
|
564 |
-
$this->dereference_current_element();
|
565 |
-
}
|
566 |
-
array_shift( $this->stack['element'] );
|
567 |
-
}
|
568 |
-
} else {
|
569 |
-
$nsc = $closer['canonical']; $nse = strtolower($closer['element']);
|
570 |
-
if (isset($this->_XMLBASE_RESOLVE[$nsc][$nse]['*content'])) {
|
571 |
-
// Resolve relative URI in content of tag
|
572 |
-
$this->dereference_current_element();
|
573 |
-
}
|
574 |
-
array_shift( $this->stack['element'] );
|
575 |
-
}
|
576 |
-
|
577 |
-
if ( !$this->incontent ) { // Don't munge the namespace after finishing with elements in namespaced content constructs -CWJ
|
578 |
-
$this->current_namespace = array_pop($this->stack['ns']);
|
579 |
-
}
|
580 |
-
array_pop($this->stack['xmlns']);
|
581 |
-
array_pop($this->stack['xml:base']);
|
582 |
-
}
|
583 |
-
|
584 |
-
// Namespace handling functions
|
585 |
-
function xmlns ($element) {
|
586 |
-
$namespaces = end($this->stack['xmlns']);
|
587 |
-
$ns = '';
|
588 |
-
if ( strpos( $element, ':' ) ) {
|
589 |
-
list($ns, $element) = split( ':', $element, 2);
|
590 |
-
}
|
591 |
-
|
592 |
-
$uri = (isset($namespaces[$ns]) ? $namespaces[$ns] : null);
|
593 |
-
|
594 |
-
if (!is_null($uri)) {
|
595 |
-
$canonical = (
|
596 |
-
isset($this->_XMLNS_FAMILIAR[$uri])
|
597 |
-
? $this->_XMLNS_FAMILIAR[$uri]
|
598 |
-
: $uri
|
599 |
-
);
|
600 |
-
} else {
|
601 |
-
$canonical = $ns;
|
602 |
-
}
|
603 |
-
|
604 |
-
if (in_array($canonical, $this->root_namespaces)) {
|
605 |
-
$effective = '';
|
606 |
-
} else {
|
607 |
-
$effective = $canonical;
|
608 |
-
}
|
609 |
-
|
610 |
-
return array('effective' => $effective, 'canonical' => $canonical, 'prefix' => $ns, 'uri' => $uri, 'element' => $element);
|
611 |
-
}
|
612 |
-
|
613 |
-
// Utility functions for accessing data structure
|
614 |
-
|
615 |
-
// for smart, namespace-aware methods...
|
616 |
-
function magpie_data ($el, $method, $text = NULL) {
|
617 |
-
$ret = NULL;
|
618 |
-
if ($el) {
|
619 |
-
if (is_array($method)) {
|
620 |
-
$el = $this->{$method['key']}($el);
|
621 |
-
$method = $method['value'];
|
622 |
-
}
|
623 |
-
|
624 |
-
if ( $this->current_namespace ) {
|
625 |
-
if ( $this->initem ) {
|
626 |
-
$ret = $this->{$method} (
|
627 |
-
$this->current_item[ $this->current_namespace ][ $el ],
|
628 |
-
$text
|
629 |
-
);
|
630 |
-
}
|
631 |
-
elseif ($this->inchannel) {
|
632 |
-
$ret = $this->{$method} (
|
633 |
-
$this->channel[ $this->current_namespace][ $el ],
|
634 |
-
$text
|
635 |
-
);
|
636 |
-
}
|
637 |
-
elseif ($this->intextinput) {
|
638 |
-
$ret = $this->{$method} (
|
639 |
-
$this->textinput[ $this->current_namespace][ $el ],
|
640 |
-
$text
|
641 |
-
);
|
642 |
-
}
|
643 |
-
elseif ($this->inimage) {
|
644 |
-
$ret = $this->{$method} (
|
645 |
-
$this->image[ $this->current_namespace ][ $el ], $text );
|
646 |
-
}
|
647 |
-
}
|
648 |
-
else {
|
649 |
-
if ( $this->initem ) {
|
650 |
-
$ret = $this->{$method} (
|
651 |
-
$this->current_item[ $el ], $text);
|
652 |
-
}
|
653 |
-
elseif ($this->intextinput) {
|
654 |
-
$ret = $this->{$method} (
|
655 |
-
$this->textinput[ $el ], $text );
|
656 |
-
}
|
657 |
-
elseif ($this->inimage) {
|
658 |
-
$ret = $this->{$method} (
|
659 |
-
$this->image[ $el ], $text );
|
660 |
-
}
|
661 |
-
elseif ($this->inchannel) {
|
662 |
-
$ret = $this->{$method} (
|
663 |
-
$this->channel[ $el ], $text );
|
664 |
-
}
|
665 |
-
}
|
666 |
-
}
|
667 |
-
return $ret;
|
668 |
-
}
|
669 |
-
|
670 |
-
function concat (&$str1, $str2="") {
|
671 |
-
if (!isset($str1) ) {
|
672 |
-
$str1="";
|
673 |
-
}
|
674 |
-
$str1 .= $str2;
|
675 |
-
}
|
676 |
-
|
677 |
-
function retrieve_value (&$el, $text /*ignore*/) {
|
678 |
-
return $el;
|
679 |
-
}
|
680 |
-
function replace_value (&$el, $text) {
|
681 |
-
$el = $text;
|
682 |
-
}
|
683 |
-
function counter_key ($el) {
|
684 |
-
return $el.'#';
|
685 |
-
}
|
686 |
-
|
687 |
-
|
688 |
-
function append_content($text) {
|
689 |
-
$construct = reset($this->incontent);
|
690 |
-
$ns = $construct['effective'];
|
691 |
-
|
692 |
-
// Keeping data about parent elements is necessary to
|
693 |
-
// properly handle atom:source and its children elements
|
694 |
-
$tag = join('_', array_reverse($this->stack['element']));
|
695 |
-
|
696 |
-
if ( $this->initem ) {
|
697 |
-
if ($ns) {
|
698 |
-
$this->concat( $this->current_item[$ns][$tag], $text );
|
699 |
-
} else {
|
700 |
-
$this->concat( $this->current_item[$tag], $text );
|
701 |
-
}
|
702 |
-
}
|
703 |
-
elseif ( $this->inchannel ) {
|
704 |
-
if ($this->current_namespace) {
|
705 |
-
$this->concat( $this->channel[$ns][$tag], $text );
|
706 |
-
} else {
|
707 |
-
$this->concat( $this->channel[$tag], $text );
|
708 |
-
}
|
709 |
-
}
|
710 |
-
}
|
711 |
-
|
712 |
-
// smart append - field and namespace aware
|
713 |
-
function append($el, $text) {
|
714 |
-
$this->magpie_data($el, 'concat', $text);
|
715 |
-
}
|
716 |
-
|
717 |
-
function dereference_current_element () {
|
718 |
-
$el = join('_', array_reverse($this->stack['element']));
|
719 |
-
$base = end($this->stack['xml:base']);
|
720 |
-
$uri = $this->magpie_data($el, 'retrieve_value');
|
721 |
-
$this->magpie_data($el, 'replace_value', Relative_URI::resolve($uri, $base));
|
722 |
-
}
|
723 |
-
|
724 |
-
// smart count - field and namespace aware
|
725 |
-
function element_count ($el, $set = NULL) {
|
726 |
-
if (!is_null($set)) {
|
727 |
-
$ret = $this->magpie_data($el, array('key' => 'counter_key', 'value' => 'replace_value'), $set);
|
728 |
-
}
|
729 |
-
$ret = $this->magpie_data($el, array('key' => 'counter_key', 'value' => 'retrieve_value'));
|
730 |
-
return ($ret ? $ret : 0);
|
731 |
-
}
|
732 |
-
|
733 |
-
function normalize_enclosure (&$source, $from, &$dest, $to, $i) {
|
734 |
-
$id_from = $this->element_id($from, $i);
|
735 |
-
$id_to = $this->element_id($to, $i);
|
736 |
-
if (isset($source["{$id_from}@"])) {
|
737 |
-
foreach (explode(',', $source["{$id_from}@"]) as $attr) {
|
738 |
-
if ($from=='link_enclosure' and $attr=='href') { // from Atom
|
739 |
-
$dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"];
|
740 |
-
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
741 |
-
}
|
742 |
-
elseif ($from=='enclosure' and $attr=='url') { // from RSS
|
743 |
-
$dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"];
|
744 |
-
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
745 |
-
}
|
746 |
-
else {
|
747 |
-
$dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"];
|
748 |
-
}
|
749 |
-
}
|
750 |
-
}
|
751 |
-
}
|
752 |
-
|
753 |
-
function normalize_atom_person (&$source, $person, &$dest, $to, $i) {
|
754 |
-
$id = $this->element_id($person, $i);
|
755 |
-
$id_to = $this->element_id($to, $i);
|
756 |
-
|
757 |
-
// Atom 0.3 <=> Atom 1.0
|
758 |
-
if ($this->feed_version >= 1.0) { $used = 'uri'; $norm = 'url'; }
|
759 |
-
else { $used = 'url'; $norm = 'uri'; }
|
760 |
-
|
761 |
-
if (isset($source["{$id}_{$used}"])) {
|
762 |
-
$dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"];
|
763 |
-
}
|
764 |
-
|
765 |
-
// Atom to RSS 2.0 and Dublin Core
|
766 |
-
// RSS 2.0 person strings should be valid e-mail addresses if possible.
|
767 |
-
if (isset($source["{$id}_email"])) {
|
768 |
-
$rss_author = $source["{$id}_email"];
|
769 |
-
}
|
770 |
-
if (isset($source["{$id}_name"])) {
|
771 |
-
$rss_author = $source["{$id}_name"]
|
772 |
-
. (isset($rss_author) ? " <$rss_author>" : '');
|
773 |
-
}
|
774 |
-
if (isset($rss_author)) {
|
775 |
-
$source[$id] = $rss_author; // goes to top-level author or contributor
|
776 |
-
$dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor
|
777 |
-
}
|
778 |
-
}
|
779 |
-
|
780 |
-
// Normalize Atom 1.0 and RSS 2.0 categories to Dublin Core...
|
781 |
-
function normalize_category (&$source, $from, &$dest, $to, $i) {
|
782 |
-
$cat_id = $this->element_id($from, $i);
|
783 |
-
$dc_id = $this->element_id($to, $i);
|
784 |
-
|
785 |
-
// first normalize category elements: Atom 1.0 <=> RSS 2.0
|
786 |
-
if ( isset($source["{$cat_id}@term"]) ) { // category identifier
|
787 |
-
$source[$cat_id] = $source["{$cat_id}@term"];
|
788 |
-
} elseif ( $this->feed_type == RSS ) {
|
789 |
-
$source["{$cat_id}@term"] = $source[$cat_id];
|
790 |
-
}
|
791 |
-
|
792 |
-
if ( isset($source["{$cat_id}@scheme"]) ) { // URI to taxonomy
|
793 |
-
$source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"];
|
794 |
-
} elseif ( isset($source["{$cat_id}@domain"]) ) {
|
795 |
-
$source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"];
|
796 |
-
}
|
797 |
-
|
798 |
-
// Now put the identifier into dc:subject
|
799 |
-
$dest[$dc_id] = $source[$cat_id];
|
800 |
-
}
|
801 |
-
|
802 |
-
// ... or vice versa
|
803 |
-
function normalize_dc_subject (&$source, $from, &$dest, $to, $i) {
|
804 |
-
$dc_id = $this->element_id($from, $i);
|
805 |
-
$cat_id = $this->element_id($to, $i);
|
806 |
-
|
807 |
-
$dest[$cat_id] = $source[$dc_id]; // RSS 2.0
|
808 |
-
$dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0
|
809 |
-
}
|
810 |
-
|
811 |
-
// simplify the logic for normalize(). Makes sure that count of elements and
|
812 |
-
// each of multiple elements is normalized properly. If you need to mess
|
813 |
-
// with things like attributes or change formats or the like, pass it a
|
814 |
-
// callback to handle each element.
|
815 |
-
function normalize_element (&$source, $from, &$dest, $to, $via = NULL) {
|
816 |
-
if (isset($source[$from]) or isset($source["{$from}#"])) {
|
817 |
-
if (isset($source["{$from}#"])) {
|
818 |
-
$n = $source["{$from}#"];
|
819 |
-
$dest["{$to}#"] = $source["{$from}#"];
|
820 |
-
}
|
821 |
-
else { $n = 1; }
|
822 |
-
|
823 |
-
for ($i = 1; $i <= $n; $i++) {
|
824 |
-
if (isset($via)) { // custom callback for ninja attacks
|
825 |
-
$this->{$via}($source, $from, $dest, $to, $i);
|
826 |
-
}
|
827 |
-
else { // just make it the same
|
828 |
-
$from_id = $this->element_id($from, $i);
|
829 |
-
$to_id = $this->element_id($to, $i);
|
830 |
-
$dest[$to_id] = $source[$from_id];
|
831 |
-
}
|
832 |
-
}
|
833 |
-
}
|
834 |
-
}
|
835 |
-
|
836 |
-
function normalize () {
|
837 |
-
// if atom populate rss fields and normalize 0.3 and 1.0 feeds
|
838 |
-
if ( $this->is_atom() ) {
|
839 |
-
// Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!)
|
840 |
-
if ($this->feed_version < 1.0) {
|
841 |
-
$this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle');
|
842 |
-
$this->normalize_element($this->channel, 'copyright', $this->channel, 'rights');
|
843 |
-
$this->normalize_element($this->channel, 'modified', $this->channel, 'updated');
|
844 |
-
} else {
|
845 |
-
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline');
|
846 |
-
$this->normalize_element($this->channel, 'rights', $this->channel, 'copyright');
|
847 |
-
$this->normalize_element($this->channel, 'updated', $this->channel, 'modified');
|
848 |
-
}
|
849 |
-
$this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person');
|
850 |
-
$this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person');
|
851 |
-
|
852 |
-
// Atom elements to RSS elements
|
853 |
-
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'description');
|
854 |
-
|
855 |
-
if ( isset($this->channel['logo']) ) {
|
856 |
-
$this->normalize_element($this->channel, 'logo', $this->image, 'url');
|
857 |
-
$this->normalize_element($this->channel, 'link', $this->image, 'link');
|
858 |
-
$this->normalize_element($this->channel, 'title', $this->image, 'title');
|
859 |
-
}
|
860 |
-
|
861 |
-
for ( $i = 0; $i < count($this->items); $i++) {
|
862 |
-
$item = $this->items[$i];
|
863 |
-
|
864 |
-
// Atom 1.0 elements <=> Atom 0.3 elements
|
865 |
-
if ($this->feed_version < 1.0) {
|
866 |
-
$this->normalize_element($item, 'modified', $item, 'updated');
|
867 |
-
$this->normalize_element($item, 'issued', $item, 'published');
|
868 |
-
} else {
|
869 |
-
$this->normalize_element($item, 'updated', $item, 'modified');
|
870 |
-
$this->normalize_element($item, 'published', $item, 'issued');
|
871 |
-
}
|
872 |
-
|
873 |
-
// "If an atom:entry element does not contain
|
874 |
-
// atom:author elements, then the atom:author elements
|
875 |
-
// of the contained atom:source element are considered
|
876 |
-
// to apply. In an Atom Feed Document, the atom:author
|
877 |
-
// elements of the containing atom:feed element are
|
878 |
-
// considered to apply to the entry if there are no
|
879 |
-
// atom:author elements in the locations described
|
880 |
-
// above." <http://atompub.org/2005/08/17/draft-ietf-atompub-format-11.html#rfc.section.4.2.1>
|
881 |
-
if (!isset($item["author#"])) {
|
882 |
-
if (isset($item["source_author#"])) { // from aggregation source
|
883 |
-
$source = $item;
|
884 |
-
$author = "source_author";
|
885 |
-
} elseif (isset($this->channel["author#"])) { // from containing feed
|
886 |
-
$source = $this->channel;
|
887 |
-
$author = "author";
|
888 |
-
} else {
|
889 |
-
$author = null;
|
890 |
-
}
|
891 |
-
|
892 |
-
if (!is_null($author)) {
|
893 |
-
$item["author#"] = $source["{$author}#"];
|
894 |
-
for ($au = 1; $au <= $item["author#"]; $au++) {
|
895 |
-
$id_to = $this->element_id('author', $au);
|
896 |
-
$id_from = $this->element_id($author, $au);
|
897 |
-
|
898 |
-
$item[$id_to] = $source[$id_from];
|
899 |
-
foreach (array('name', 'email', 'uri', 'url') as $what) {
|
900 |
-
if (isset($source["{$id_from}_{$what}"])) {
|
901 |
-
$item["{$id_to}_{$what}"] = $source["{$id_from}_{$what}"];
|
902 |
-
}
|
903 |
-
}
|
904 |
-
}
|
905 |
-
}
|
906 |
-
}
|
907 |
-
|
908 |
-
// Atom elements to RSS elements
|
909 |
-
$this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person');
|
910 |
-
$this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person');
|
911 |
-
$this->normalize_element($item, 'summary', $item, 'description');
|
912 |
-
$this->normalize_element($item, 'atom_content', $item['content'], 'encoded');
|
913 |
-
$this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure');
|
914 |
-
|
915 |
-
// Categories
|
916 |
-
if ( isset($item['category#']) ) { // Atom 1.0 categories to dc:subject and RSS 2.0 categories
|
917 |
-
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
918 |
-
}
|
919 |
-
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
920 |
-
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
921 |
-
}
|
922 |
-
|
923 |
-
// Normalized item timestamp
|
924 |
-
$atom_date = (isset($item['published']) ) ? $item['published'] : $item['updated'];
|
925 |
-
if ( $atom_date ) {
|
926 |
-
$epoch = @parse_w3cdtf($atom_date);
|
927 |
-
if ($epoch and $epoch > 0) {
|
928 |
-
$item['date_timestamp'] = $epoch;
|
929 |
-
}
|
930 |
-
}
|
931 |
-
|
932 |
-
$this->items[$i] = $item;
|
933 |
-
}
|
934 |
-
}
|
935 |
-
elseif ( $this->is_rss() ) {
|
936 |
-
// RSS elements to Atom elements
|
937 |
-
$this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3
|
938 |
-
$this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!)
|
939 |
-
$this->normalize_element($this->image, 'url', $this->channel, 'logo');
|
940 |
-
|
941 |
-
for ( $i = 0; $i < count($this->items); $i++) {
|
942 |
-
$item = $this->items[$i];
|
943 |
-
|
944 |
-
// RSS elements to Atom elements
|
945 |
-
$this->normalize_element($item, 'description', $item, 'summary');
|
946 |
-
$this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure');
|
947 |
-
|
948 |
-
// Categories
|
949 |
-
if ( isset($item['category#']) ) { // RSS 2.0 categories to dc:subject and Atom 1.0 categories
|
950 |
-
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
951 |
-
}
|
952 |
-
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
953 |
-
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
954 |
-
}
|
955 |
-
|
956 |
-
// Normalized item timestamp
|
957 |
-
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
|
958 |
-
$epoch = @parse_w3cdtf($item['dc']['date']);
|
959 |
-
if ($epoch and $epoch > 0) {
|
960 |
-
$item['date_timestamp'] = $epoch;
|
961 |
-
}
|
962 |
-
}
|
963 |
-
elseif ( isset($item['pubdate']) ) {
|
964 |
-
$epoch = @strtotime($item['pubdate']);
|
965 |
-
if ($epoch > 0) {
|
966 |
-
$item['date_timestamp'] = $epoch;
|
967 |
-
}
|
968 |
-
}
|
969 |
-
|
970 |
-
$this->items[$i] = $item;
|
971 |
-
}
|
972 |
-
}
|
973 |
-
}
|
974 |
-
|
975 |
-
|
976 |
-
function is_rss () {
|
977 |
-
if ( $this->feed_type == RSS ) {
|
978 |
-
return $this->feed_version;
|
979 |
-
}
|
980 |
-
else {
|
981 |
-
return false;
|
982 |
-
}
|
983 |
-
}
|
984 |
-
|
985 |
-
function is_atom() {
|
986 |
-
if ( $this->feed_type == ATOM ) {
|
987 |
-
return $this->feed_version;
|
988 |
-
}
|
989 |
-
else {
|
990 |
-
return false;
|
991 |
-
}
|
992 |
-
}
|
993 |
-
|
994 |
-
/**
|
995 |
-
* return XML parser, and possibly re-encoded source
|
996 |
-
*
|
997 |
-
*/
|
998 |
-
function create_parser($source, $out_enc, $in_enc, $detect) {
|
999 |
-
if ( substr(phpversion(),0,1) == 5) {
|
1000 |
-
$parser = $this->php5_create_parser($in_enc, $detect);
|
1001 |
-
}
|
1002 |
-
else {
|
1003 |
-
list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
|
1004 |
-
}
|
1005 |
-
if ($out_enc) {
|
1006 |
-
$this->encoding = $out_enc;
|
1007 |
-
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
|
1008 |
-
}
|
1009 |
-
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
|
1010 |
-
return array($parser, $source);
|
1011 |
-
}
|
1012 |
-
|
1013 |
-
/**
|
1014 |
-
* Instantiate an XML parser under PHP5
|
1015 |
-
*
|
1016 |
-
* PHP5 will do a fine job of detecting input encoding
|
1017 |
-
* if passed an empty string as the encoding.
|
1018 |
-
*
|
1019 |
-
* All hail libxml2!
|
1020 |
-
*
|
1021 |
-
*/
|
1022 |
-
function php5_create_parser($in_enc, $detect) {
|
1023 |
-
// by default php5 does a fine job of detecting input encodings
|
1024 |
-
if(!$detect && $in_enc) {
|
1025 |
-
return xml_parser_create($in_enc);
|
1026 |
-
}
|
1027 |
-
else {
|
1028 |
-
return xml_parser_create('');
|
1029 |
-
}
|
1030 |
-
}
|
1031 |
-
|
1032 |
-
/**
|
1033 |
-
* Instaniate an XML parser under PHP4
|
1034 |
-
*
|
1035 |
-
* Unfortunately PHP4's support for character encodings
|
1036 |
-
* and especially XML and character encodings sucks. As
|
1037 |
-
* long as the documents you parse only contain characters
|
1038 |
-
* from the ISO-8859-1 character set (a superset of ASCII,
|
1039 |
-
* and a subset of UTF-8) you're fine. However once you
|
1040 |
-
* step out of that comfy little world things get mad, bad,
|
1041 |
-
* and dangerous to know.
|
1042 |
-
*
|
1043 |
-
* The following code is based on SJM's work with FoF
|
1044 |
-
* @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
|
1045 |
-
*
|
1046 |
-
*/
|
1047 |
-
function php4_create_parser($source, $in_enc, $detect) {
|
1048 |
-
if ( !$detect ) {
|
1049 |
-
return array(xml_parser_create($in_enc), $source);
|
1050 |
-
}
|
1051 |
-
|
1052 |
-
if (!$in_enc) {
|
1053 |
-
if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
|
1054 |
-
$in_enc = strtoupper($m[1]);
|
1055 |
-
$this->source_encoding = $in_enc;
|
1056 |
-
}
|
1057 |
-
else {
|
1058 |
-
$in_enc = 'UTF-8';
|
1059 |
-
}
|
1060 |
-
}
|
1061 |
-
|
1062 |
-
if ($this->known_encoding($in_enc)) {
|
1063 |
-
return array(xml_parser_create($in_enc), $source);
|
1064 |
-
}
|
1065 |
-
|
1066 |
-
// the dectected encoding is not one of the simple encodings PHP knows
|
1067 |
-
|
1068 |
-
// attempt to use the iconv extension to
|
1069 |
-
// cast the XML to a known encoding
|
1070 |
-
// @see http://php.net/iconv
|
1071 |
-
|
1072 |
-
if (function_exists('iconv')) {
|
1073 |
-
$encoded_source = iconv($in_enc,'UTF-8', $source);
|
1074 |
-
if ($encoded_source) {
|
1075 |
-
return array(xml_parser_create('UTF-8'), $encoded_source);
|
1076 |
-
}
|
1077 |
-
}
|
1078 |
-
|
1079 |
-
// iconv didn't work, try mb_convert_encoding
|
1080 |
-
// @see http://php.net/mbstring
|
1081 |
-
if(function_exists('mb_convert_encoding')) {
|
1082 |
-
$encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
|
1083 |
-
if ($encoded_source) {
|
1084 |
-
return array(xml_parser_create('UTF-8'), $encoded_source);
|
1085 |
-
}
|
1086 |
-
}
|
1087 |
-
|
1088 |
-
// else
|
1089 |
-
$this->error("Feed is in an unsupported character encoding. ($in_enc) " .
|
1090 |
-
"You may see strange artifacts, and mangled characters.",
|
1091 |
-
E_USER_NOTICE);
|
1092 |
-
|
1093 |
-
return array(xml_parser_create(), $source);
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
function known_encoding($enc) {
|
1097 |
-
$enc = strtoupper($enc);
|
1098 |
-
if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) {
|
1099 |
-
return $enc;
|
1100 |
-
}
|
1101 |
-
else {
|
1102 |
-
return false;
|
1103 |
-
}
|
1104 |
-
}
|
1105 |
-
|
1106 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1107 |
-
// append PHP's error message if track_errors enabled
|
1108 |
-
if ( isset($php_errormsg) ) {
|
1109 |
-
$errormsg .= " ($php_errormsg)";
|
1110 |
-
}
|
1111 |
-
if ( MAGPIE_DEBUG ) {
|
1112 |
-
trigger_error( $errormsg, $lvl);
|
1113 |
-
}
|
1114 |
-
else {
|
1115 |
-
error_log( $errormsg, 0);
|
1116 |
-
}
|
1117 |
-
|
1118 |
-
$notices = E_USER_NOTICE|E_NOTICE;
|
1119 |
-
if ( $lvl&$notices ) {
|
1120 |
-
$this->WARNING = $errormsg;
|
1121 |
-
} else {
|
1122 |
-
$this->ERROR = $errormsg;
|
1123 |
-
}
|
1124 |
-
}
|
1125 |
-
|
1126 |
-
// magic ID function for multiple elemenets.
|
1127 |
-
// can be called as static MagpieRSS::element_id()
|
1128 |
-
function element_id ($el, $counter) {
|
1129 |
-
return $el . (($counter > 1) ? '#'.$counter : '');
|
1130 |
-
}
|
1131 |
-
|
1132 |
-
function map_attrs($k, $v) {
|
1133 |
-
return $k.'="'.htmlspecialchars($v, ENT_COMPAT, $this->encoding).'"';
|
1134 |
-
}
|
1135 |
-
|
1136 |
-
function accepts_namespaced_xml ($attrs) {
|
1137 |
-
$mode = (isset($attrs['mode']) ? trim(strtolower($attrs['mode'])) : 'xml');
|
1138 |
-
$type = (isset($attrs['type']) ? trim(strtolower($attrs['type'])) : null);
|
1139 |
-
if ($this->feed_type == ATOM and $this->feed_version < 1.0) {
|
1140 |
-
if ($mode=='xml' and preg_match(':[/+](html|xml)$:i', $type)) {
|
1141 |
-
$ret = true;
|
1142 |
-
} else {
|
1143 |
-
$ret = false;
|
1144 |
-
}
|
1145 |
-
} elseif ($this->feed_type == ATOM and $this->feed_version >= 1.0) {
|
1146 |
-
if ($type=='xhtml' or preg_match(':[/+]xml$:i', $type)) {
|
1147 |
-
$ret = true;
|
1148 |
-
} else {
|
1149 |
-
$ret = false;
|
1150 |
-
}
|
1151 |
-
} else {
|
1152 |
-
$ret = false; // Don't munge unless you're sure
|
1153 |
-
}
|
1154 |
-
return $ret;
|
1155 |
-
}
|
1156 |
-
} // end class RSS
|
1157 |
-
|
1158 |
-
|
1159 |
-
// patch to support medieval versions of PHP4.1.x,
|
1160 |
-
// courtesy, Ryan Currie, ryan@digibliss.com
|
1161 |
-
|
1162 |
-
if (!function_exists('array_change_key_case')) {
|
1163 |
-
define("CASE_UPPER",1);
|
1164 |
-
define("CASE_LOWER",0);
|
1165 |
-
|
1166 |
-
|
1167 |
-
function array_change_key_case($array,$case=CASE_LOWER) {
|
1168 |
-
if ($case==CASE_LOWER) $cmd='strtolower';
|
1169 |
-
elseif ($case==CASE_UPPER) $cmd='strtoupper';
|
1170 |
-
foreach($array as $key=>$value) {
|
1171 |
-
$output[$cmd($key)]=$value;
|
1172 |
-
}
|
1173 |
-
return $output;
|
1174 |
-
}
|
1175 |
-
|
1176 |
-
}
|
1177 |
-
|
1178 |
-
################################################################################
|
1179 |
-
## WordPress: Load in Snoopy from wp-includes ##################################
|
1180 |
-
################################################################################
|
1181 |
-
|
1182 |
-
if (!function_exists('wp_remote_request')) :
|
1183 |
-
require_once( dirname(__FILE__) . '/class-snoopy.php');
|
1184 |
-
endif;
|
1185 |
-
|
1186 |
-
################################################################################
|
1187 |
-
## rss_fetch.inc: from MagpieRSS 0.8a ##########################################
|
1188 |
-
################################################################################
|
1189 |
-
|
1190 |
-
/*=======================================================================*\
|
1191 |
-
Function: fetch_rss:
|
1192 |
-
Purpose: return RSS object for the give url
|
1193 |
-
maintain the cache
|
1194 |
-
Input: url of RSS file
|
1195 |
-
Output: parsed RSS object (see rss_parse.inc)
|
1196 |
-
|
1197 |
-
NOTES ON CACHEING:
|
1198 |
-
If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache.
|
1199 |
-
|
1200 |
-
NOTES ON RETRIEVING REMOTE FILES:
|
1201 |
-
If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will
|
1202 |
-
return a cached object, and touch the cache object upon recieving a
|
1203 |
-
304.
|
1204 |
-
|
1205 |
-
NOTES ON FAILED REQUESTS:
|
1206 |
-
If there is an HTTP error while fetching an RSS object, the cached
|
1207 |
-
version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off)
|
1208 |
-
\*=======================================================================*/
|
1209 |
-
|
1210 |
-
define('MAGPIE_VERSION', '2010.0122');
|
1211 |
-
|
1212 |
-
$MAGPIE_ERROR = "";
|
1213 |
-
|
1214 |
-
function fetch_rss ($url) {
|
1215 |
-
// initialize constants
|
1216 |
-
init();
|
1217 |
-
|
1218 |
-
if ( !isset($url) ) {
|
1219 |
-
error("fetch_rss called without a url");
|
1220 |
-
return false;
|
1221 |
-
}
|
1222 |
-
|
1223 |
-
// if cache is disabled
|
1224 |
-
if ( !MAGPIE_CACHE_ON ) {
|
1225 |
-
// fetch file, and parse it
|
1226 |
-
$resp = _fetch_remote_file( $url );
|
1227 |
-
if ( is_success( $resp->status ) ) {
|
1228 |
-
return _response_to_rss( $resp, $url );
|
1229 |
-
}
|
1230 |
-
else {
|
1231 |
-
error("Failed to fetch $url and cache is off");
|
1232 |
-
return false;
|
1233 |
-
}
|
1234 |
-
}
|
1235 |
-
// else cache is ON
|
1236 |
-
else {
|
1237 |
-
// Flow
|
1238 |
-
// 1. check cache
|
1239 |
-
// 2. if there is a hit, make sure its fresh
|
1240 |
-
// 3. if cached obj fails freshness check, fetch remote
|
1241 |
-
// 4. if remote fails, return stale object, or error
|
1242 |
-
|
1243 |
-
$cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
|
1244 |
-
|
1245 |
-
if (MAGPIE_DEBUG and $cache->ERROR) {
|
1246 |
-
debug($cache->ERROR, E_USER_WARNING);
|
1247 |
-
}
|
1248 |
-
|
1249 |
-
|
1250 |
-
$cache_status = 0; // response of check_cache
|
1251 |
-
$request_headers = array(); // HTTP headers to send with fetch
|
1252 |
-
$rss = 0; // parsed RSS object
|
1253 |
-
$errormsg = 0; // errors, if any
|
1254 |
-
|
1255 |
-
// store parsed XML by desired output encoding
|
1256 |
-
// as character munging happens at parse time
|
1257 |
-
$cache_key = $url . MAGPIE_OUTPUT_ENCODING;
|
1258 |
-
|
1259 |
-
if (!$cache->ERROR) {
|
1260 |
-
// return cache HIT, MISS, or STALE
|
1261 |
-
$cache_status = $cache->check_cache( $cache_key);
|
1262 |
-
}
|
1263 |
-
|
1264 |
-
// if object cached, and cache is fresh, return cached obj
|
1265 |
-
if ( $cache_status == 'HIT' ) {
|
1266 |
-
$rss = $cache->get( $cache_key );
|
1267 |
-
if ( isset($rss) and $rss ) {
|
1268 |
-
// should be cache age
|
1269 |
-
$rss->from_cache = 1;
|
1270 |
-
if ( MAGPIE_DEBUG > 1) {
|
1271 |
-
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
|
1272 |
-
}
|
1273 |
-
return $rss;
|
1274 |
-
}
|
1275 |
-
}
|
1276 |
-
|
1277 |
-
// else attempt a conditional get
|
1278 |
-
|
1279 |
-
// setup headers
|
1280 |
-
if ( $cache_status == 'STALE' ) {
|
1281 |
-
$rss = $cache->get( $cache_key );
|
1282 |
-
if ( $rss and isset($rss->etag) and $rss->last_modified ) {
|
1283 |
-
$request_headers['If-None-Match'] = $rss->etag;
|
1284 |
-
$request_headers['If-Last-Modified'] = $rss->last_modified;
|
1285 |
-
}
|
1286 |
-
}
|
1287 |
-
|
1288 |
-
$resp = _fetch_remote_file( $url, $request_headers );
|
1289 |
-
|
1290 |
-
if (isset($resp) and $resp) {
|
1291 |
-
if ($resp->status == '304' ) {
|
1292 |
-
// we have the most current copy
|
1293 |
-
if ( MAGPIE_DEBUG > 1) {
|
1294 |
-
debug("Got 304 for $url");
|
1295 |
-
}
|
1296 |
-
// reset cache on 304 (at minutillo insistent prodding)
|
1297 |
-
$cache->set($cache_key, $rss);
|
1298 |
-
return $rss;
|
1299 |
-
}
|
1300 |
-
elseif ( is_success( $resp->status ) ) {
|
1301 |
-
$rss = _response_to_rss( $resp, $url );
|
1302 |
-
if ( $rss ) {
|
1303 |
-
if (MAGPIE_DEBUG > 1) {
|
1304 |
-
debug("Fetch successful");
|
1305 |
-
}
|
1306 |
-
// add object to cache
|
1307 |
-
$cache->set( $cache_key, $rss );
|
1308 |
-
return $rss;
|
1309 |
-
}
|
1310 |
-
}
|
1311 |
-
else {
|
1312 |
-
$errormsg = "Failed to fetch $url ";
|
1313 |
-
if ( $resp->status == '-100' ) {
|
1314 |
-
$errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)";
|
1315 |
-
}
|
1316 |
-
elseif ( $resp->error ) {
|
1317 |
-
# compensate for Snoopy's annoying habbit to tacking
|
1318 |
-
# on '\n'
|
1319 |
-
$http_error = substr($resp->error, 0, -2);
|
1320 |
-
$errormsg .= "(HTTP Error: $http_error)";
|
1321 |
-
}
|
1322 |
-
else {
|
1323 |
-
$errormsg .= "(HTTP Response: " . $resp->response_code .')';
|
1324 |
-
}
|
1325 |
-
}
|
1326 |
-
}
|
1327 |
-
else {
|
1328 |
-
$errormsg = "Unable to retrieve RSS file for unknown reasons.";
|
1329 |
-
}
|
1330 |
-
|
1331 |
-
// else fetch failed
|
1332 |
-
debug("MagpieRSS fetch failed [$errormsg]");
|
1333 |
-
|
1334 |
-
// attempt to return cached object
|
1335 |
-
if ($rss) {
|
1336 |
-
if ( MAGPIE_DEBUG ) {
|
1337 |
-
debug("Returning STALE object for $url");
|
1338 |
-
}
|
1339 |
-
return $rss;
|
1340 |
-
}
|
1341 |
-
|
1342 |
-
// else we totally failed
|
1343 |
-
error( $errormsg );
|
1344 |
-
|
1345 |
-
return false;
|
1346 |
-
|
1347 |
-
} // end if ( !MAGPIE_CACHE_ON ) {
|
1348 |
-
} // end fetch_rss()
|
1349 |
-
|
1350 |
-
/*=======================================================================*\
|
1351 |
-
Function: error
|
1352 |
-
Purpose: set MAGPIE_ERROR, and trigger error
|
1353 |
-
\*=======================================================================*/
|
1354 |
-
|
1355 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1356 |
-
global $MAGPIE_ERROR;
|
1357 |
-
|
1358 |
-
// append PHP's error message if track_errors enabled
|
1359 |
-
if ( isset($php_errormsg) ) {
|
1360 |
-
$errormsg .= " ($php_errormsg)";
|
1361 |
-
}
|
1362 |
-
if ( $errormsg ) {
|
1363 |
-
$errormsg = "MagpieRSS: $errormsg";
|
1364 |
-
$MAGPIE_ERROR = $errormsg;
|
1365 |
-
if ( MAGPIE_DEBUG ) {
|
1366 |
-
trigger_error( $errormsg, $lvl);
|
1367 |
-
} else {
|
1368 |
-
error_log($errormsg, 0);
|
1369 |
-
}
|
1370 |
-
}
|
1371 |
-
}
|
1372 |
-
|
1373 |
-
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1374 |
-
trigger_error("MagpieRSS [debug] $debugmsg", $lvl);
|
1375 |
-
}
|
1376 |
-
|
1377 |
-
/*=======================================================================*\
|
1378 |
-
Function: magpie_error
|
1379 |
-
Purpose: accessor for the magpie error variable
|
1380 |
-
\*=======================================================================*/
|
1381 |
-
function magpie_error ($errormsg="") {
|
1382 |
-
global $MAGPIE_ERROR;
|
1383 |
-
|
1384 |
-
if ( isset($errormsg) and $errormsg ) {
|
1385 |
-
$MAGPIE_ERROR = $errormsg;
|
1386 |
-
}
|
1387 |
-
|
1388 |
-
return $MAGPIE_ERROR;
|
1389 |
-
}
|
1390 |
-
|
1391 |
-
/*=======================================================================*\
|
1392 |
-
Function: _fetch_remote_file
|
1393 |
-
Purpose: retrieve an arbitrary remote file
|
1394 |
-
Input: url of the remote file
|
1395 |
-
headers to send along with the request (optional)
|
1396 |
-
Output: an HTTP response object (see Snoopy.class.inc)
|
1397 |
-
\*=======================================================================*/
|
1398 |
-
function _fetch_remote_file ($url, $headers = "" ) {
|
1399 |
-
// Ensure that we have constants set up, since they are used below.
|
1400 |
-
init();
|
1401 |
-
|
1402 |
-
// WordPress 2.7 has deprecated Snoopy. It's still there, for now, but
|
1403 |
-
// I'd rather not rely on it.
|
1404 |
-
if (function_exists('wp_remote_request')) :
|
1405 |
-
$resp = wp_remote_request($url, array(
|
1406 |
-
'headers' => $headers,
|
1407 |
-
'timeout' => MAGPIE_FETCH_TIME_OUT
|
1408 |
-
));
|
1409 |
-
|
1410 |
-
if ( is_wp_error($resp) ) :
|
1411 |
-
$error = $resp->get_error_messages();
|
1412 |
-
|
1413 |
-
$client = new stdClass;
|
1414 |
-
$client->status = 500;
|
1415 |
-
$client->response_code = 500;
|
1416 |
-
$client->error = implode(" / ", $error). "\n"; //\n = Snoopy compatibility
|
1417 |
-
else :
|
1418 |
-
$client = new stdClass;
|
1419 |
-
$client->status = $resp['response']['code'];
|
1420 |
-
$client->response_code = $resp['response']['code'];
|
1421 |
-
$client->headers = $resp['headers'];
|
1422 |
-
$client->results = $resp['body'];
|
1423 |
-
endif;
|
1424 |
-
else :
|
1425 |
-
// Snoopy is an HTTP client in PHP
|
1426 |
-
$client = new Snoopy();
|
1427 |
-
$client->agent = MAGPIE_USER_AGENT;
|
1428 |
-
$client->read_timeout = MAGPIE_FETCH_TIME_OUT;
|
1429 |
-
$client->use_gzip = MAGPIE_USE_GZIP;
|
1430 |
-
if (is_array($headers) ) {
|
1431 |
-
$client->rawheaders = $headers;
|
1432 |
-
}
|
1433 |
-
@$client->fetch($url);
|
1434 |
-
endif;
|
1435 |
-
return $client;
|
1436 |
-
}
|
1437 |
-
|
1438 |
-
/*=======================================================================*\
|
1439 |
-
Function: _response_to_rss
|
1440 |
-
Purpose: parse an HTTP response object into an RSS object
|
1441 |
-
Input: an HTTP response object (see Snoopy)
|
1442 |
-
Output: parsed RSS object (see rss_parse)
|
1443 |
-
\*=======================================================================*/
|
1444 |
-
function _response_to_rss ($resp, $url = null) {
|
1445 |
-
$rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING, $url );
|
1446 |
-
|
1447 |
-
// if RSS parsed successfully
|
1448 |
-
if ( $rss and !$rss->ERROR) {
|
1449 |
-
$rss->http_status = $resp->status;
|
1450 |
-
|
1451 |
-
// find Etag, and Last-Modified
|
1452 |
-
foreach($resp->headers as $index => $h) {
|
1453 |
-
if (is_string($index)) :
|
1454 |
-
$field = $index;
|
1455 |
-
$val = $h;
|
1456 |
-
elseif (strpos($h, ": ")) :
|
1457 |
-
list($field, $val) = explode(": ", $h, 2);
|
1458 |
-
else :
|
1459 |
-
$field = $h; $val = '';
|
1460 |
-
endif;
|
1461 |
-
|
1462 |
-
$rss->header[$field] = $val;
|
1463 |
-
|
1464 |
-
if ( $field == 'ETag' ) :
|
1465 |
-
$rss->etag = $val;
|
1466 |
-
elseif ( $field == 'Last-Modified' ) :
|
1467 |
-
$rss->last_modified = $val;
|
1468 |
-
endif;
|
1469 |
-
}
|
1470 |
-
|
1471 |
-
return $rss;
|
1472 |
-
} // else construct error message
|
1473 |
-
else {
|
1474 |
-
$errormsg = "Failed to parse RSS file.";
|
1475 |
-
|
1476 |
-
if ($rss) {
|
1477 |
-
$errormsg .= " (" . $rss->ERROR . ")";
|
1478 |
-
}
|
1479 |
-
error($errormsg);
|
1480 |
-
|
1481 |
-
return false;
|
1482 |
-
} // end if ($rss and !$rss->error)
|
1483 |
-
}
|
1484 |
-
|
1485 |
-
/*=======================================================================*\
|
1486 |
-
Function: init
|
1487 |
-
Purpose: setup constants with default values
|
1488 |
-
check for user overrides
|
1489 |
-
\*=======================================================================*/
|
1490 |
-
function init () {
|
1491 |
-
if ( defined('MAGPIE_INITALIZED') ) {
|
1492 |
-
return;
|
1493 |
-
}
|
1494 |
-
else {
|
1495 |
-
define('MAGPIE_INITALIZED', true);
|
1496 |
-
}
|
1497 |
-
|
1498 |
-
if ( !defined('MAGPIE_CACHE_ON') ) {
|
1499 |
-
define('MAGPIE_CACHE_ON', true);
|
1500 |
-
}
|
1501 |
-
|
1502 |
-
if ( !defined('MAGPIE_CACHE_DIR') ) {
|
1503 |
-
define('MAGPIE_CACHE_DIR', './cache');
|
1504 |
-
}
|
1505 |
-
|
1506 |
-
if ( !defined('MAGPIE_CACHE_AGE') ) {
|
1507 |
-
define('MAGPIE_CACHE_AGE', 60*60); // one hour
|
1508 |
-
}
|
1509 |
-
|
1510 |
-
if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
|
1511 |
-
define('MAGPIE_CACHE_FRESH_ONLY', false);
|
1512 |
-
}
|
1513 |
-
|
1514 |
-
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
|
1515 |
-
define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1');
|
1516 |
-
}
|
1517 |
-
|
1518 |
-
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
|
1519 |
-
define('MAGPIE_INPUT_ENCODING', null);
|
1520 |
-
}
|
1521 |
-
|
1522 |
-
if ( !defined('MAGPIE_DETECT_ENCODING') ) {
|
1523 |
-
define('MAGPIE_DETECT_ENCODING', true);
|
1524 |
-
}
|
1525 |
-
|
1526 |
-
if ( !defined('MAGPIE_DEBUG') ) {
|
1527 |
-
define('MAGPIE_DEBUG', 0);
|
1528 |
-
}
|
1529 |
-
|
1530 |
-
if ( !defined('MAGPIE_USER_AGENT') ) {
|
1531 |
-
$ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net';
|
1532 |
-
|
1533 |
-
if ( MAGPIE_CACHE_ON ) {
|
1534 |
-
$ua = $ua . ')';
|
1535 |
-
}
|
1536 |
-
else {
|
1537 |
-
$ua = $ua . '; No cache)';
|
1538 |
-
}
|
1539 |
-
|
1540 |
-
define('MAGPIE_USER_AGENT', $ua);
|
1541 |
-
}
|
1542 |
-
|
1543 |
-
if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
|
1544 |
-
define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout
|
1545 |
-
}
|
1546 |
-
|
1547 |
-
// use gzip encoding to fetch rss files if supported?
|
1548 |
-
if ( !defined('MAGPIE_USE_GZIP') ) {
|
1549 |
-
define('MAGPIE_USE_GZIP', true);
|
1550 |
-
}
|
1551 |
-
}
|
1552 |
-
|
1553 |
-
// NOTE: the following code should really be in Snoopy, or at least
|
1554 |
-
// somewhere other then rss_fetch!
|
1555 |
-
|
1556 |
-
/*=======================================================================*\
|
1557 |
-
HTTP STATUS CODE PREDICATES
|
1558 |
-
These functions attempt to classify an HTTP status code
|
1559 |
-
based on RFC 2616 and RFC 2518.
|
1560 |
-
|
1561 |
-
All of them take an HTTP status code as input, and return true or false
|
1562 |
-
|
1563 |
-
All this code is adapted from LWP's HTTP::Status.
|
1564 |
-
\*=======================================================================*/
|
1565 |
-
|
1566 |
-
|
1567 |
-
/*=======================================================================*\
|
1568 |
-
Function: is_info
|
1569 |
-
Purpose: return true if Informational status code
|
1570 |
-
\*=======================================================================*/
|
1571 |
-
function is_info ($sc) {
|
1572 |
-
return $sc >= 100 && $sc < 200;
|
1573 |
-
}
|
1574 |
-
|
1575 |
-
/*=======================================================================*\
|
1576 |
-
Function: is_success
|
1577 |
-
Purpose: return true if Successful status code
|
1578 |
-
\*=======================================================================*/
|
1579 |
-
function is_success ($sc) {
|
1580 |
-
return $sc >= 200 && $sc < 300;
|
1581 |
-
}
|
1582 |
-
|
1583 |
-
/*=======================================================================*\
|
1584 |
-
Function: is_redirect
|
1585 |
-
Purpose: return true if Redirection status code
|
1586 |
-
\*=======================================================================*/
|
1587 |
-
function is_redirect ($sc) {
|
1588 |
-
return $sc >= 300 && $sc < 400;
|
1589 |
-
}
|
1590 |
-
|
1591 |
-
/*=======================================================================*\
|
1592 |
-
Function: is_error
|
1593 |
-
Purpose: return true if Error status code
|
1594 |
-
\*=======================================================================*/
|
1595 |
-
function is_error ($sc) {
|
1596 |
-
return $sc >= 400 && $sc < 600;
|
1597 |
-
}
|
1598 |
-
|
1599 |
-
/*=======================================================================*\
|
1600 |
-
Function: is_client_error
|
1601 |
-
Purpose: return true if Error status code, and its a client error
|
1602 |
-
\*=======================================================================*/
|
1603 |
-
function is_client_error ($sc) {
|
1604 |
-
return $sc >= 400 && $sc < 500;
|
1605 |
-
}
|
1606 |
-
|
1607 |
-
/*=======================================================================*\
|
1608 |
-
Function: is_client_error
|
1609 |
-
Purpose: return true if Error status code, and its a server error
|
1610 |
-
\*=======================================================================*/
|
1611 |
-
function is_server_error ($sc) {
|
1612 |
-
return $sc >= 500 && $sc < 600;
|
1613 |
-
}
|
1614 |
-
|
1615 |
-
################################################################################
|
1616 |
-
## rss_cache.inc: from WordPress 1.5 ###########################################
|
1617 |
-
################################################################################
|
1618 |
-
|
1619 |
-
class RSSCache {
|
1620 |
-
var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
|
1621 |
-
var $MAX_AGE = 43200; // when are files stale, default twelve hours
|
1622 |
-
var $ERROR = ''; // accumulate error messages
|
1623 |
-
|
1624 |
-
function RSSCache ($base='', $age='') {
|
1625 |
-
if ( $base ) {
|
1626 |
-
$this->BASE_CACHE = $base;
|
1627 |
-
}
|
1628 |
-
if ( $age ) {
|
1629 |
-
$this->MAX_AGE = $age;
|
1630 |
-
}
|
1631 |
-
|
1632 |
-
}
|
1633 |
-
|
1634 |
-
/*=======================================================================*\
|
1635 |
-
Function: set
|
1636 |
-
Purpose: add an item to the cache, keyed on url
|
1637 |
-
Input: url from wich the rss file was fetched
|
1638 |
-
Output: true on sucess
|
1639 |
-
\*=======================================================================*/
|
1640 |
-
function set ($url, $rss) {
|
1641 |
-
global $wpdb;
|
1642 |
-
$cache_option = 'rss_' . $this->file_name( $url );
|
1643 |
-
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1644 |
-
|
1645 |
-
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_option'") )
|
1646 |
-
add_option($cache_option, '', '', 'no');
|
1647 |
-
if ( !$wpdb->get_var("SELECT option_name FROM $wpdb->options WHERE option_name = '$cache_timestamp'") )
|
1648 |
-
add_option($cache_timestamp, '', '', 'no');
|
1649 |
-
|
1650 |
-
update_option($cache_option, $rss);
|
1651 |
-
update_option($cache_timestamp, time() );
|
1652 |
-
|
1653 |
-
return $cache_option;
|
1654 |
-
}
|
1655 |
-
|
1656 |
-
/*=======================================================================*\
|
1657 |
-
Function: get
|
1658 |
-
Purpose: fetch an item from the cache
|
1659 |
-
Input: url from wich the rss file was fetched
|
1660 |
-
Output: cached object on HIT, false on MISS
|
1661 |
-
\*=======================================================================*/
|
1662 |
-
function get ($url) {
|
1663 |
-
$this->ERROR = "";
|
1664 |
-
$cache_option = 'rss_' . $this->file_name( $url );
|
1665 |
-
|
1666 |
-
if ( ! get_option( $cache_option ) ) {
|
1667 |
-
$this->debug(
|
1668 |
-
"Cache doesn't contain: $url (cache option: $cache_option)"
|
1669 |
-
);
|
1670 |
-
return 0;
|
1671 |
-
}
|
1672 |
-
|
1673 |
-
$rss = get_option( $cache_option );
|
1674 |
-
|
1675 |
-
// failsafe; seems to break at odd points in WP MU
|
1676 |
-
if (is_string($rss)) {
|
1677 |
-
$rss = $this->unserialize($rss);
|
1678 |
-
}
|
1679 |
-
|
1680 |
-
return $rss;
|
1681 |
-
}
|
1682 |
-
|
1683 |
-
/*=======================================================================*\
|
1684 |
-
Function: check_cache
|
1685 |
-
Purpose: check a url for membership in the cache
|
1686 |
-
and whether the object is older then MAX_AGE (ie. STALE)
|
1687 |
-
Input: url from wich the rss file was fetched
|
1688 |
-
Output: cached object on HIT, false on MISS
|
1689 |
-
\*=======================================================================*/
|
1690 |
-
function check_cache ( $url ) {
|
1691 |
-
$this->ERROR = "";
|
1692 |
-
$cache_option = $this->file_name( $url );
|
1693 |
-
$cache_timestamp = 'rss_' . $this->file_name( $url ) . '_ts';
|
1694 |
-
|
1695 |
-
if ( $mtime = get_option($cache_timestamp) ) {
|
1696 |
-
// find how long ago the file was added to the cache
|
1697 |
-
// and whether that is longer then MAX_AGE
|
1698 |
-
$age = time() - $mtime;
|
1699 |
-
if ( $this->MAX_AGE > $age ) {
|
1700 |
-
// object exists and is current
|
1701 |
-
return 'HIT';
|
1702 |
-
}
|
1703 |
-
else {
|
1704 |
-
// object exists but is old
|
1705 |
-
return 'STALE';
|
1706 |
-
}
|
1707 |
-
}
|
1708 |
-
else {
|
1709 |
-
// object does not exist
|
1710 |
-
return 'MISS';
|
1711 |
-
}
|
1712 |
-
}
|
1713 |
-
|
1714 |
-
/*=======================================================================*\
|
1715 |
-
Function: serialize
|
1716 |
-
\*=======================================================================*/
|
1717 |
-
function serialize ( $rss ) {
|
1718 |
-
return serialize( $rss );
|
1719 |
-
}
|
1720 |
-
|
1721 |
-
/*=======================================================================*\
|
1722 |
-
Function: unserialize
|
1723 |
-
\*=======================================================================*/
|
1724 |
-
function unserialize ( $data ) {
|
1725 |
-
return unserialize( $data );
|
1726 |
-
}
|
1727 |
-
|
1728 |
-
/*=======================================================================*\
|
1729 |
-
Function: file_name
|
1730 |
-
Purpose: map url to location in cache
|
1731 |
-
Input: url from wich the rss file was fetched
|
1732 |
-
Output: a file name
|
1733 |
-
\*=======================================================================*/
|
1734 |
-
function file_name ($url) {
|
1735 |
-
return md5( $url );
|
1736 |
-
}
|
1737 |
-
|
1738 |
-
/*=======================================================================*\
|
1739 |
-
Function: error
|
1740 |
-
Purpose: register error
|
1741 |
-
\*=======================================================================*/
|
1742 |
-
function error ($errormsg, $lvl=E_USER_WARNING) {
|
1743 |
-
// append PHP's error message if track_errors enabled
|
1744 |
-
if ( isset($php_errormsg) ) {
|
1745 |
-
$errormsg .= " ($php_errormsg)";
|
1746 |
-
}
|
1747 |
-
$this->ERROR = $errormsg;
|
1748 |
-
if ( MAGPIE_DEBUG ) {
|
1749 |
-
trigger_error( $errormsg, $lvl);
|
1750 |
-
}
|
1751 |
-
else {
|
1752 |
-
error_log( $errormsg, 0);
|
1753 |
-
}
|
1754 |
-
}
|
1755 |
-
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
|
1756 |
-
if ( MAGPIE_DEBUG ) {
|
1757 |
-
$this->error("MagpieRSS [debug] $debugmsg", $lvl);
|
1758 |
-
}
|
1759 |
-
}
|
1760 |
-
}
|
1761 |
-
|
1762 |
-
################################################################################
|
1763 |
-
## rss_utils.inc: from MagpieRSS 0.8a ##########################################
|
1764 |
-
################################################################################
|
1765 |
-
|
1766 |
-
/*======================================================================*\
|
1767 |
-
Function: parse_w3cdtf
|
1768 |
-
Purpose: parse a W3CDTF date into unix epoch
|
1769 |
-
|
1770 |
-
NOTE: http://www.w3.org/TR/NOTE-datetime
|
1771 |
-
\*======================================================================*/
|
1772 |
-
|
1773 |
-
function parse_w3cdtf ( $date_str ) {
|
1774 |
-
|
1775 |
-
# regex to match wc3dtf
|
1776 |
-
$pat = "/^\s*(\d{4})(-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(\.\d+)?)?(?:([-+])(\d{2}):?(\d{2})|(Z))?)?)?)?\s*\$/";
|
1777 |
-
|
1778 |
-
if ( preg_match( $pat, $date_str, $match ) ) {
|
1779 |
-
list( $year, $month, $day, $hours, $minutes, $seconds) =
|
1780 |
-
array( $match[1], $match[3], $match[5], $match[7], $match[8], $match[10]);
|
1781 |
-
|
1782 |
-
# W3C dates can omit the time, the day of the month, or even the month.
|
1783 |
-
# Fill in any blanks using information from the present moment. --CWJ
|
1784 |
-
$default['hr'] = (int) gmdate('H');
|
1785 |
-
$default['day'] = (int) gmdate('d');
|
1786 |
-
$default['month'] = (int) gmdate('m');
|
1787 |
-
|
1788 |
-
if (is_null($hours)) : $hours = $default['hr']; $minutes = 0; $seconds = 0; endif;
|
1789 |
-
if (is_null($day)) : $day = $default['day']; endif;
|
1790 |
-
if (is_null($month)) : $month = $default['month']; endif;
|
1791 |
-
|
1792 |
-
# calc epoch for current date assuming GMT
|
1793 |
-
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
|
1794 |
-
|
1795 |
-
$offset = 0;
|
1796 |
-
if ( $match[15] == 'Z' ) {
|
1797 |
-
# zulu time, aka GMT
|
1798 |
-
}
|
1799 |
-
else {
|
1800 |
-
list( $tz_mod, $tz_hour, $tz_min ) =
|
1801 |
-
array( $match[12], $match[13], $match[14]);
|
1802 |
-
|
1803 |
-
# zero out the variables
|
1804 |
-
if ( ! $tz_hour ) { $tz_hour = 0; }
|
1805 |
-
if ( ! $tz_min ) { $tz_min = 0; }
|
1806 |
-
|
1807 |
-
$offset_secs = (($tz_hour*60)+$tz_min)*60;
|
1808 |
-
|
1809 |
-
# is timezone ahead of GMT? then subtract offset
|
1810 |
-
#
|
1811 |
-
if ( $tz_mod == '+' ) {
|
1812 |
-
$offset_secs = $offset_secs * -1;
|
1813 |
-
}
|
1814 |
-
|
1815 |
-
$offset = $offset_secs;
|
1816 |
-
}
|
1817 |
-
$epoch = $epoch + $offset;
|
1818 |
-
return $epoch;
|
1819 |
-
}
|
1820 |
-
else {
|
1821 |
-
return -1;
|
1822 |
-
}
|
1823 |
-
}
|
1824 |
-
|
1825 |
-
# Relative URI static class: PHP class for resolving relative URLs
|
1826 |
-
#
|
1827 |
-
# This class is derived (under the terms of the GPL) from URL Class 0.3 by
|
1828 |
-
# Keyvan Minoukadeh <keyvan@k1m.com>, which is great but more than we need
|
1829 |
-
# for MagpieRSS's purposes. The class has been stripped down to a single
|
1830 |
-
# public method: Relative_URI::resolve($url, $base), which resolves the URI in
|
1831 |
-
# $url relative to the URI in $base
|
1832 |
-
#
|
1833 |
-
# FeedWordPress also uses this class. So if we have it loaded in, don't load it
|
1834 |
-
# again.
|
1835 |
-
#
|
1836 |
-
# -- Charles Johnson <technophilia@radgeek.com>
|
1837 |
-
if (!class_exists('Relative_URI')) {
|
1838 |
-
class Relative_URI
|
1839 |
-
{
|
1840 |
-
// Resolve relative URI in $url against the base URI in $base. If $base
|
1841 |
-
// is not supplied, then we use the REQUEST_URI of this script.
|
1842 |
-
//
|
1843 |
-
// I'm hoping this method reflects RFC 2396 Section 5.2
|
1844 |
-
function resolve ($url, $base = NULL)
|
1845 |
-
{
|
1846 |
-
if (is_null($base)):
|
1847 |
-
$base = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
|
1848 |
-
endif;
|
1849 |
-
|
1850 |
-
$base = Relative_URI::_encode(trim($base));
|
1851 |
-
$uri_parts = Relative_URI::_parse_url($base);
|
1852 |
-
|
1853 |
-
$url = Relative_URI::_encode(trim($url));
|
1854 |
-
$parts = Relative_URI::_parse_url($url);
|
1855 |
-
|
1856 |
-
$uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
|
1857 |
-
$uri_parts['query'] = (isset($parts['query']) ? $parts['query'] : null);
|
1858 |
-
|
1859 |
-
// if path is empty, and scheme, host, and query are undefined,
|
1860 |
-
// the URL is referring the base URL
|
1861 |
-
|
1862 |
-
if (($parts['path'] == '') && !isset($parts['scheme']) && !isset($parts['host']) && !isset($parts['query'])) {
|
1863 |
-
// If the URI is empty or only a fragment, return the base URI
|
1864 |
-
return $base . (isset($parts['fragment']) ? '#'.$parts['fragment'] : '');
|
1865 |
-
} elseif (isset($parts['scheme'])) {
|
1866 |
-
// If the scheme is set, then the URI is absolute.
|
1867 |
-
return $url;
|
1868 |
-
} elseif (isset($parts['host'])) {
|
1869 |
-
$uri_parts['host'] = $parts['host'];
|
1870 |
-
$uri_parts['path'] = $parts['path'];
|
1871 |
-
} else {
|
1872 |
-
// We have a relative path but not a host.
|
1873 |
-
|
1874 |
-
// start ugly fix:
|
1875 |
-
// prepend slash to path if base host is set, base path is not set, and url path is not absolute
|
1876 |
-
if ($uri_parts['host'] && ($uri_parts['path'] == '')
|
1877 |
-
&& (strlen($parts['path']) > 0)
|
1878 |
-
&& (substr($parts['path'], 0, 1) != '/')) {
|
1879 |
-
$parts['path'] = '/'.$parts['path'];
|
1880 |
-
} // end ugly fix
|
1881 |
-
|
1882 |
-
if (substr($parts['path'], 0, 1) == '/') {
|
1883 |
-
$uri_parts['path'] = $parts['path'];
|
1884 |
-
} else {
|
1885 |
-
// copy base path excluding any characters after the last (right-most) slash character
|
1886 |
-
$buffer = substr($uri_parts['path'], 0, (int)strrpos($uri_parts['path'], '/')+1);
|
1887 |
-
// append relative path
|
1888 |
-
$buffer .= $parts['path'];
|
1889 |
-
// remove "./" where "." is a complete path segment.
|
1890 |
-
$buffer = str_replace('/./', '/', $buffer);
|
1891 |
-
if (substr($buffer, 0, 2) == './') {
|
1892 |
-
$buffer = substr($buffer, 2);
|
1893 |
-
}
|
1894 |
-
// if buffer ends with "." as a complete path segment, remove it
|
1895 |
-
if (substr($buffer, -2) == '/.') {
|
1896 |
-
$buffer = substr($buffer, 0, -1);
|
1897 |
-
}
|
1898 |
-
// remove "<segment>/../" where <segment> is a complete path segment not equal to ".."
|
1899 |
-
$search_finished = false;
|
1900 |
-
$segment = explode('/', $buffer);
|
1901 |
-
while (!$search_finished) {
|
1902 |
-
for ($x=0; $x+1 < count($segment);) {
|
1903 |
-
if (($segment[$x] != '') && ($segment[$x] != '..') && ($segment[$x+1] == '..')) {
|
1904 |
-
if ($x+2 == count($segment)) $segment[] = '';
|
1905 |
-
unset($segment[$x], $segment[$x+1]);
|
1906 |
-
$segment = array_values($segment);
|
1907 |
-
continue 2;
|
1908 |
-
} else {
|
1909 |
-
$x++;
|
1910 |
-
}
|
1911 |
-
}
|
1912 |
-
$search_finished = true;
|
1913 |
-
}
|
1914 |
-
$buffer = (count($segment) == 1) ? '/' : implode('/', $segment);
|
1915 |
-
$uri_parts['path'] = $buffer;
|
1916 |
-
|
1917 |
-
}
|
1918 |
-
}
|
1919 |
-
|
1920 |
-
// If we've gotten to this point, we can try to put the pieces
|
1921 |
-
// back together.
|
1922 |
-
$ret = '';
|
1923 |
-
if (isset($uri_parts['scheme'])) $ret .= $uri_parts['scheme'].':';
|
1924 |
-
if (isset($uri_parts['user'])) {
|
1925 |
-
$ret .= $uri_parts['user'];
|
1926 |
-
if (isset($uri_parts['pass'])) $ret .= ':'.$uri_parts['parts'];
|
1927 |
-
$ret .= '@';
|
1928 |
-
}
|
1929 |
-
if (isset($uri_parts['host'])) {
|
1930 |
-
$ret .= '//'.$uri_parts['host'];
|
1931 |
-
if (isset($uri_parts['port'])) $ret .= ':'.$uri_parts['port'];
|
1932 |
-
}
|
1933 |
-
$ret .= $uri_parts['path'];
|
1934 |
-
if (isset($uri_parts['query'])) $ret .= '?'.$uri_parts['query'];
|
1935 |
-
if (isset($uri_parts['fragment'])) $ret .= '#'.$uri_parts['fragment'];
|
1936 |
-
|
1937 |
-
return $ret;
|
1938 |
-
}
|
1939 |
-
|
1940 |
-
/**
|
1941 |
-
* Parse URL
|
1942 |
-
*
|
1943 |
-
* Regular expression grabbed from RFC 2396 Appendix B.
|
1944 |
-
* This is a replacement for PHPs builtin parse_url().
|
1945 |
-
* @param string $url
|
1946 |
-
* @access private
|
1947 |
-
* @return array
|
1948 |
-
*/
|
1949 |
-
function _parse_url($url)
|
1950 |
-
{
|
1951 |
-
// I'm using this pattern instead of parse_url() as there's a few strings where parse_url()
|
1952 |
-
// generates a warning.
|
1953 |
-
if (preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!', $url, $match)) {
|
1954 |
-
$parts = array();
|
1955 |
-
if ($match[1] != '') $parts['scheme'] = $match[2];
|
1956 |
-
if ($match[3] != '') $parts['auth'] = $match[4];
|
1957 |
-
// parse auth
|
1958 |
-
if (isset($parts['auth'])) {
|
1959 |
-
// store user info
|
1960 |
-
if (($at_pos = strpos($parts['auth'], '@')) !== false) {
|
1961 |
-
$userinfo = explode(':', substr($parts['auth'], 0, $at_pos), 2);
|
1962 |
-
$parts['user'] = $userinfo[0];
|
1963 |
-
if (isset($userinfo[1])) $parts['pass'] = $userinfo[1];
|
1964 |
-
$parts['auth'] = substr($parts['auth'], $at_pos+1);
|
1965 |
-
}
|
1966 |
-
// get port number
|
1967 |
-
if ($port_pos = strrpos($parts['auth'], ':')) {
|
1968 |
-
$parts['host'] = substr($parts['auth'], 0, $port_pos);
|
1969 |
-
$parts['port'] = (int)substr($parts['auth'], $port_pos+1);
|
1970 |
-
if ($parts['port'] < 1) $parts['port'] = null;
|
1971 |
-
} else {
|
1972 |
-
$parts['host'] = $parts['auth'];
|
1973 |
-
}
|
1974 |
-
}
|
1975 |
-
unset($parts['auth']);
|
1976 |
-
$parts['path'] = $match[5];
|
1977 |
-
if (isset($match[6]) && ($match[6] != '')) $parts['query'] = $match[7];
|
1978 |
-
if (isset($match[8]) && ($match[8] != '')) $parts['fragment'] = $match[9];
|
1979 |
-
return $parts;
|
1980 |
-
}
|
1981 |
-
// shouldn't reach here
|
1982 |
-
return array('path'=>'');
|
1983 |
-
}
|
1984 |
-
|
1985 |
-
function _encode($string)
|
1986 |
-
{
|
1987 |
-
static $replace = array();
|
1988 |
-
if (!count($replace)) {
|
1989 |
-
$find = array(32, 34, 60, 62, 123, 124, 125, 91, 92, 93, 94, 96, 127);
|
1990 |
-
$find = array_merge(range(0, 31), $find);
|
1991 |
-
$find = array_map('chr', $find);
|
1992 |
-
foreach ($find as $char) {
|
1993 |
-
$replace[$char] = '%'.bin2hex($char);
|
1994 |
-
}
|
1995 |
-
}
|
1996 |
-
// escape control characters and a few other characters
|
1997 |
-
$encoded = strtr($string, $replace);
|
1998 |
-
// remove any character outside the hex range: 21 - 7E (see www.asciitable.com)
|
1999 |
-
return preg_replace('/[^\x21-\x7e]/', '', $encoded);
|
2000 |
-
}
|
2001 |
-
} // class Relative_URI
|
2002 |
-
}
|
2003 |
-
|
2004 |
-
################################################################################
|
2005 |
-
## WordPress: wp_rss(), get_rss() ##############################################
|
2006 |
-
################################################################################
|
2007 |
-
|
2008 |
-
function wp_rss ($url, $num) {
|
2009 |
-
//ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
|
2010 |
-
$num_items = $num;
|
2011 |
-
$rss = fetch_rss($url);
|
2012 |
-
if ( $rss ) {
|
2013 |
-
echo "<ul>";
|
2014 |
-
$rss->items = array_slice($rss->items, 0, $num_items);
|
2015 |
-
foreach ($rss->items as $item ) {
|
2016 |
-
echo "<li>\n";
|
2017 |
-
echo "<a href='$item[link]' title='$item[description]'>";
|
2018 |
-
echo htmlentities($item['title']);
|
2019 |
-
echo "</a><br />\n";
|
2020 |
-
echo "</li>\n";
|
2021 |
-
}
|
2022 |
-
echo "</ul>";
|
2023 |
-
}
|
2024 |
-
else {
|
2025 |
-
echo "an error has occured the feed is probably down, try again later.";
|
2026 |
-
}
|
2027 |
-
}
|
2028 |
-
|
2029 |
-
function get_rss ($uri, $num = 5) { // Like get posts, but for RSS
|
2030 |
-
$rss = fetch_rss($url);
|
2031 |
-
if ( $rss ) {
|
2032 |
-
$rss->items = array_slice($rss->items, 0, $num_items);
|
2033 |
-
foreach ($rss->items as $item ) {
|
2034 |
-
echo "<li>\n";
|
2035 |
-
echo "<a href='$item[link]' title='$item[description]'>";
|
2036 |
-
echo htmlentities($item['title']);
|
2037 |
-
echo "</a><br />\n";
|
2038 |
-
echo "</li>\n";
|
2039 |
-
}
|
2040 |
-
return $posts;
|
2041 |
-
} else {
|
2042 |
-
return false;
|
2043 |
-
}
|
2044 |
-
}
|
2045 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
admin-ui.php
CHANGED
@@ -52,7 +52,7 @@ class FeedWordPressAdminPage {
|
|
52 |
/*static*/ function submitted_link () {
|
53 |
$link_id = FeedWordPressAdminPage::submitted_link_id();
|
54 |
if (is_numeric($link_id) and $link_id) :
|
55 |
-
$link
|
56 |
else :
|
57 |
$link = NULL;
|
58 |
endif;
|
@@ -62,7 +62,7 @@ class FeedWordPressAdminPage {
|
|
62 |
function stamp_link_id ($field = null) {
|
63 |
if (is_null($field)) : $field = 'save_link_id'; endif;
|
64 |
?>
|
65 |
-
<input type="hidden" name="<?php print
|
66 |
<?php
|
67 |
} /* FeedWordPressAdminPage::stamp_link_id () */
|
68 |
|
@@ -133,7 +133,7 @@ class FeedWordPressAdminPage {
|
|
133 |
position:relative;
|
134 |
}
|
135 |
.fwpfs {
|
136 |
-
color: #dddddd;
|
137 |
background:#797979 url(<?php bloginfo('home') ?>/wp-admin/images/fav.png) repeat-x scroll left center;
|
138 |
border-color:#777777 #777777 #666666 !important; -moz-border-radius-bottomleft:12px;
|
139 |
-moz-border-radius-bottomright:12px;
|
@@ -179,7 +179,7 @@ class FeedWordPressAdminPage {
|
|
179 |
<select name="link_id" class="fwpfs" style="max-width: 20.0em;">
|
180 |
<option value="*"<?php if ($this->for_default_settings()) : ?> selected="selected"<?php endif; ?>>- defaults for all feeds -</option>
|
181 |
<?php if ($links) : foreach ($links as $ddlink) : ?>
|
182 |
-
<option value="<?php print (int) $ddlink->link_id; ?>"<?php if (!is_null($this->link) and ($this->link->id==$ddlink->link_id)) : ?> selected="selected"<?php endif; ?>><?php print
|
183 |
<?php endforeach; endif; ?>
|
184 |
</select>
|
185 |
<input class="button" type="submit" name="go" value="<?php _e('Go') ?> »" />
|
@@ -190,12 +190,12 @@ class FeedWordPressAdminPage {
|
|
190 |
function display_sheet_header ($pagename = 'Syndication', $all = false) {
|
191 |
if (FeedWordPressCompatibility::test_version(FWP_SCHEMA_27)) :
|
192 |
?>
|
193 |
-
<div class="icon32"><img src="<?php print
|
194 |
<?php
|
195 |
endif;
|
196 |
?>
|
197 |
|
198 |
-
<h2><?php print
|
199 |
<?php
|
200 |
}
|
201 |
|
@@ -211,7 +211,7 @@ class FeedWordPressAdminPage {
|
|
211 |
if (!is_null($mesg)) :
|
212 |
?>
|
213 |
<div class="updated">
|
214 |
-
<p><?php print
|
215 |
</div>
|
216 |
<?php
|
217 |
endif;
|
@@ -221,7 +221,7 @@ class FeedWordPressAdminPage {
|
|
221 |
if ($this->for_feed_settings()) :
|
222 |
?>
|
223 |
<p>These settings only affect posts syndicated from
|
224 |
-
<strong><?php echo
|
225 |
<?php
|
226 |
else :
|
227 |
?>
|
@@ -508,7 +508,15 @@ function update_feeds_mention ($feed) {
|
|
508 |
flush();
|
509 |
}
|
510 |
function update_feeds_finish ($feed, $added, $dt) {
|
511 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
512 |
}
|
513 |
|
514 |
function fwp_author_list () {
|
52 |
/*static*/ function submitted_link () {
|
53 |
$link_id = FeedWordPressAdminPage::submitted_link_id();
|
54 |
if (is_numeric($link_id) and $link_id) :
|
55 |
+
$link = new SyndicatedLink($link_id);
|
56 |
else :
|
57 |
$link = NULL;
|
58 |
endif;
|
62 |
function stamp_link_id ($field = null) {
|
63 |
if (is_null($field)) : $field = 'save_link_id'; endif;
|
64 |
?>
|
65 |
+
<input type="hidden" name="<?php print esc_html($field); ?>" value="<?php print ($this->for_feed_settings() ? $this->link->id : '*'); ?>" />
|
66 |
<?php
|
67 |
} /* FeedWordPressAdminPage::stamp_link_id () */
|
68 |
|
133 |
position:relative;
|
134 |
}
|
135 |
.fwpfs {
|
136 |
+
color: #dddddd !important; background-color: #333 !important;
|
137 |
background:#797979 url(<?php bloginfo('home') ?>/wp-admin/images/fav.png) repeat-x scroll left center;
|
138 |
border-color:#777777 #777777 #666666 !important; -moz-border-radius-bottomleft:12px;
|
139 |
-moz-border-radius-bottomright:12px;
|
179 |
<select name="link_id" class="fwpfs" style="max-width: 20.0em;">
|
180 |
<option value="*"<?php if ($this->for_default_settings()) : ?> selected="selected"<?php endif; ?>>- defaults for all feeds -</option>
|
181 |
<?php if ($links) : foreach ($links as $ddlink) : ?>
|
182 |
+
<option value="<?php print (int) $ddlink->link_id; ?>"<?php if (!is_null($this->link) and ($this->link->id==$ddlink->link_id)) : ?> selected="selected"<?php endif; ?>><?php print esc_html($ddlink->link_name); ?></option>
|
183 |
<?php endforeach; endif; ?>
|
184 |
</select>
|
185 |
<input class="button" type="submit" name="go" value="<?php _e('Go') ?> »" />
|
190 |
function display_sheet_header ($pagename = 'Syndication', $all = false) {
|
191 |
if (FeedWordPressCompatibility::test_version(FWP_SCHEMA_27)) :
|
192 |
?>
|
193 |
+
<div class="icon32"><img src="<?php print esc_html(WP_PLUGIN_URL.'/'.$GLOBALS['fwp_path'].'/feedwordpress.png'); ?>" alt="" /></div>
|
194 |
<?php
|
195 |
endif;
|
196 |
?>
|
197 |
|
198 |
+
<h2><?php print esc_html(__($pagename.($all ? '' : ' Settings'))); ?><?php if ($this->for_feed_settings()) : ?>: <?php echo esc_html($this->link->link->link_name); ?><?php endif; ?></h2>
|
199 |
<?php
|
200 |
}
|
201 |
|
211 |
if (!is_null($mesg)) :
|
212 |
?>
|
213 |
<div class="updated">
|
214 |
+
<p><?php print esc_html($mesg); ?></p>
|
215 |
</div>
|
216 |
<?php
|
217 |
endif;
|
221 |
if ($this->for_feed_settings()) :
|
222 |
?>
|
223 |
<p>These settings only affect posts syndicated from
|
224 |
+
<strong><?php echo esc_html($this->link->link->link_name); ?></strong>.</p>
|
225 |
<?php
|
226 |
else :
|
227 |
?>
|
508 |
flush();
|
509 |
}
|
510 |
function update_feeds_finish ($feed, $added, $dt) {
|
511 |
+
if (is_wp_error($added)) :
|
512 |
+
$mesgs = $added->get_error_messages();
|
513 |
+
foreach ($mesgs as $mesg) :
|
514 |
+
echo "<br/><strong>Feed error:</strong> <code>$mesg</code>";
|
515 |
+
endforeach;
|
516 |
+
echo "</li>\n";
|
517 |
+
else :
|
518 |
+
echo " completed in $dt second".(($dt==1)?'':'s')."</li>\n";
|
519 |
+
endif;
|
520 |
}
|
521 |
|
522 |
function fwp_author_list () {
|
authors-page.php
CHANGED
@@ -289,24 +289,14 @@ function fwp_authors_page () {
|
|
289 |
endif;
|
290 |
endif;
|
291 |
endif;
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
$alter_set = implode(", ", $alter);
|
296 |
-
|
297 |
-
// issue update query
|
298 |
-
$result = $wpdb->query("
|
299 |
-
UPDATE $wpdb->links
|
300 |
-
SET $alter_set
|
301 |
-
WHERE link_id='$link_id'
|
302 |
-
");
|
303 |
$updated_link = true;
|
304 |
-
|
305 |
-
// reload
|
306 |
-
|
307 |
-
|
308 |
-
endif;
|
309 |
-
$link =& new SyndicatedLink($link_id);
|
310 |
else :
|
311 |
if ('newuser'==$GLOBALS['fwp_post']['unfamiliar_author']) :
|
312 |
$newuser_name = trim($GLOBALS['fwp_post']['unfamiliar_author_newuser']);
|
@@ -361,7 +351,7 @@ function fwp_authors_page () {
|
|
361 |
?>
|
362 |
<div class="updated"><p>Syndicated author settings updated.</p></div>
|
363 |
<?php elseif (!is_null($mesg)) : ?>
|
364 |
-
<div class="updated"><p><?php print
|
365 |
<?php endif;
|
366 |
|
367 |
if (function_exists('add_meta_box')) :
|
289 |
endif;
|
290 |
endif;
|
291 |
endif;
|
292 |
+
|
293 |
+
// Save settings
|
294 |
+
$link->save_settings(/*reload=*/ true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
$updated_link = true;
|
296 |
+
|
297 |
+
// Reset, reload
|
298 |
+
unset($link);
|
299 |
+
$link = new SyndicatedLink($link_id);
|
|
|
|
|
300 |
else :
|
301 |
if ('newuser'==$GLOBALS['fwp_post']['unfamiliar_author']) :
|
302 |
$newuser_name = trim($GLOBALS['fwp_post']['unfamiliar_author_newuser']);
|
351 |
?>
|
352 |
<div class="updated"><p>Syndicated author settings updated.</p></div>
|
353 |
<?php elseif (!is_null($mesg)) : ?>
|
354 |
+
<div class="updated"><p><?php print esc_html($mesg); ?></p></div>
|
355 |
<?php endif;
|
356 |
|
357 |
if (function_exists('add_meta_box')) :
|
backend-page.php
CHANGED
@@ -77,10 +77,14 @@ class FeedWordPressBackendPage extends FeedWordPressAdminPage {
|
|
77 |
|
78 |
if (isset($post['create_index'])) :
|
79 |
FeedWordPress::create_guid_index();
|
80 |
-
$this->updated = __('
|
81 |
endif;
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
84 |
FeedWordPress::clear_cache();
|
85 |
$this->updated = __("Cleared all cached feeds from WordPress database.");
|
86 |
endif;
|
@@ -98,9 +102,21 @@ and force FeedWordPress to make a fresh scan for updates on syndicated feeds.</p
|
|
98 |
|
99 |
<tr style="vertical-align: top">
|
100 |
<th width="33%" scope="row">Guid index:</th>
|
101 |
-
<td width="67%"
|
|
|
102 |
<p>Creating this index may significantly improve performance on some large
|
103 |
-
FeedWordPress installations.</p
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
</tr>
|
105 |
</table>
|
106 |
<?php
|
77 |
|
78 |
if (isset($post['create_index'])) :
|
79 |
FeedWordPress::create_guid_index();
|
80 |
+
$this->updated = __('guid column index created on database table.');
|
81 |
endif;
|
82 |
+
if (isset($post['remove_index'])) :
|
83 |
+
FeedWordPress::remove_guid_index();
|
84 |
+
$this->updated = __('guid column index removed from database table.');
|
85 |
+
endif;
|
86 |
+
|
87 |
+
if (isset($post['clear_cache'])) :
|
88 |
FeedWordPress::clear_cache();
|
89 |
$this->updated = __("Cleared all cached feeds from WordPress database.");
|
90 |
endif;
|
102 |
|
103 |
<tr style="vertical-align: top">
|
104 |
<th width="33%" scope="row">Guid index:</th>
|
105 |
+
<td width="67%"><?php if (!FeedWordPress::has_guid_index()) : ?>
|
106 |
+
<input class="button" type="submit" name="create_index" value="Create index on guid column in posts database table" />
|
107 |
<p>Creating this index may significantly improve performance on some large
|
108 |
+
FeedWordPress installations.</p>
|
109 |
+
<?php else : ?>
|
110 |
+
|
111 |
+
<p>You have already created an index on the guid column in the WordPress posts
|
112 |
+
table. If you'd like to remove the index for any reason, you can do so here.</p>
|
113 |
+
|
114 |
+
<input class="button" type="submit" name="remove_index" value="Remove index on guid column in posts database table" />
|
115 |
+
|
116 |
+
<?php endif; ?>
|
117 |
+
|
118 |
+
|
119 |
+
</td>
|
120 |
</tr>
|
121 |
</table>
|
122 |
<?php
|
categories-page.php
CHANGED
@@ -164,23 +164,13 @@ function fwp_categories_page () {
|
|
164 |
endif;
|
165 |
endif;
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
$alter_set = implode(", ", $alter);
|
170 |
-
|
171 |
-
// issue update query
|
172 |
-
$result = $wpdb->query("
|
173 |
-
UPDATE $wpdb->links
|
174 |
-
SET $alter_set
|
175 |
-
WHERE link_id='$link_id'
|
176 |
-
");
|
177 |
$catsPage->updated = true;
|
178 |
-
|
179 |
-
// reload
|
180 |
-
|
181 |
-
|
182 |
-
endif;
|
183 |
-
$link =& new SyndicatedLink($link_id);
|
184 |
else :
|
185 |
// Categories
|
186 |
if (!empty($saveCats)) :
|
164 |
endif;
|
165 |
endif;
|
166 |
|
167 |
+
// Save settings
|
168 |
+
$link->save_settings(/*reload=*/ true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
$catsPage->updated = true;
|
170 |
+
|
171 |
+
// Reset, reload
|
172 |
+
unset($link);
|
173 |
+
$link = new SyndicatedLink($link_id);
|
|
|
|
|
174 |
else :
|
175 |
// Categories
|
176 |
if (!empty($saveCats)) :
|
compatability.php
CHANGED
@@ -213,6 +213,30 @@ if (!function_exists('wp_die')) {
|
|
213 |
} /* wp_die() */
|
214 |
} /* if */
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
function fwp_category_checklist ($post_id = 0, $descendents_and_self = 0, $selected_cats = false) {
|
217 |
if (function_exists('wp_category_checklist')) :
|
218 |
wp_category_checklist($post_id, $descendents_and_self, $selected_cats);
|
@@ -259,7 +283,7 @@ function fwp_upgrade_page () {
|
|
259 |
echo "<div class=\"wrap\">\n";
|
260 |
echo "<h2>Upgrading FeedWordPress...</h2>";
|
261 |
|
262 |
-
$feedwordpress
|
263 |
$feedwordpress->upgrade_database($ver);
|
264 |
echo "<p><strong>Done!</strong> Upgraded database to version ".FEEDWORDPRESS_VERSION.".</p>\n";
|
265 |
echo "<form action=\"\" method=\"get\">\n";
|
213 |
} /* wp_die() */
|
214 |
} /* if */
|
215 |
|
216 |
+
if (!function_exists('add_post_meta')) {
|
217 |
+
function add_post_meta ($postId, $key, $value, $unique) {
|
218 |
+
global $wpdb;
|
219 |
+
|
220 |
+
$postId = (int) $postId;
|
221 |
+
$key = $wpdb->escape($key);
|
222 |
+
$value = $wpdb->escape($value);
|
223 |
+
|
224 |
+
$result = $wpdb->query("
|
225 |
+
INSERT INTO $wpdb->postmeta
|
226 |
+
SET
|
227 |
+
post_id='$postId',
|
228 |
+
meta_key='$key',
|
229 |
+
meta_value='$value'
|
230 |
+
");
|
231 |
+
if (!$result) :
|
232 |
+
$err = mysql_error();
|
233 |
+
if (FEEDWORDPRESS_DEBUG) :
|
234 |
+
echo "[DEBUG:".date('Y-m-d H:i:S')."][feedwordpress]: post metadata insertion FAILED for field '$key' := '$value': [$err]";
|
235 |
+
endif;
|
236 |
+
endif;
|
237 |
+
} /* add_post_meta() */
|
238 |
+
} /* if */
|
239 |
+
|
240 |
function fwp_category_checklist ($post_id = 0, $descendents_and_self = 0, $selected_cats = false) {
|
241 |
if (function_exists('wp_category_checklist')) :
|
242 |
wp_category_checklist($post_id, $descendents_and_self, $selected_cats);
|
283 |
echo "<div class=\"wrap\">\n";
|
284 |
echo "<h2>Upgrading FeedWordPress...</h2>";
|
285 |
|
286 |
+
$feedwordpress = new FeedWordPress;
|
287 |
$feedwordpress->upgrade_database($ver);
|
288 |
echo "<p><strong>Done!</strong> Upgraded database to version ".FEEDWORDPRESS_VERSION.".</p>\n";
|
289 |
echo "<form action=\"\" method=\"get\">\n";
|
feedfinder.class.php
CHANGED
@@ -55,9 +55,9 @@ class FeedFinder {
|
|
55 |
foreach ($href as $u) {
|
56 |
$the_uri = Relative_URI::resolve($u, $this->uri);
|
57 |
if ($this->verify) {
|
58 |
-
$feed
|
59 |
if ($feed->is_feed()) $ret[] = $the_uri;
|
60 |
-
$feed
|
61 |
} else {
|
62 |
$ret[] = $the_uri;
|
63 |
}
|
@@ -75,16 +75,24 @@ class FeedFinder {
|
|
75 |
function status ($uri = NULL) {
|
76 |
$this->_get($uri);
|
77 |
|
78 |
-
if (isset($this->_response
|
79 |
-
$ret = $this->_response
|
80 |
else :
|
81 |
$ret = NULL;
|
82 |
endif;
|
83 |
return $ret;
|
84 |
}
|
85 |
|
86 |
-
function error () {
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
89 |
|
90 |
function is_feed ($uri = NULL) {
|
@@ -111,15 +119,20 @@ class FeedFinder {
|
|
111 |
$headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
|
112 |
$headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
|
113 |
|
114 |
-
// Use
|
115 |
-
$client =
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
else :
|
|
|
119 |
$this->_error = NULL;
|
120 |
endif;
|
121 |
-
$this->_response = $client;
|
122 |
-
$this->_data = $client->results;
|
123 |
|
124 |
// Kilroy was here
|
125 |
$this->_cache_uri = $this->uri;
|
55 |
foreach ($href as $u) {
|
56 |
$the_uri = Relative_URI::resolve($u, $this->uri);
|
57 |
if ($this->verify) {
|
58 |
+
$feed = new FeedFinder($the_uri);
|
59 |
if ($feed->is_feed()) $ret[] = $the_uri;
|
60 |
+
unset($feed);
|
61 |
} else {
|
62 |
$ret[] = $the_uri;
|
63 |
}
|
75 |
function status ($uri = NULL) {
|
76 |
$this->_get($uri);
|
77 |
|
78 |
+
if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
|
79 |
+
$ret = $this->_response['response']['code'];
|
80 |
else :
|
81 |
$ret = NULL;
|
82 |
endif;
|
83 |
return $ret;
|
84 |
}
|
85 |
|
86 |
+
function error ($index = NULL) {
|
87 |
+
$message = NULL;
|
88 |
+
if (count($this->_error) > 0) :
|
89 |
+
if (is_scalar($index) and !is_null($index)) :
|
90 |
+
$message = $this->_error[$index];
|
91 |
+
else :
|
92 |
+
$message = implode(" / ", $this->_error)."\n";
|
93 |
+
endif;
|
94 |
+
endif;
|
95 |
+
return $message;
|
96 |
}
|
97 |
|
98 |
function is_feed ($uri = NULL) {
|
119 |
$headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
|
120 |
$headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
|
121 |
|
122 |
+
// Use WordPress API function
|
123 |
+
$client = wp_remote_request($this->uri, array(
|
124 |
+
'headers' => $headers,
|
125 |
+
'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT,
|
126 |
+
));
|
127 |
+
|
128 |
+
$this->_response = $client;
|
129 |
+
if (is_wp_error($client)) :
|
130 |
+
$this->_data = NULL;
|
131 |
+
$this->_error = $client->get_error_messages();
|
132 |
else :
|
133 |
+
$this->_data = $client['body'];
|
134 |
$this->_error = NULL;
|
135 |
endif;
|
|
|
|
|
136 |
|
137 |
// Kilroy was here
|
138 |
$this->_cache_uri = $this->uri;
|
feeds-page.php
CHANGED
@@ -82,6 +82,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
|
|
82 |
'postmeta',
|
83 |
'resolve relative',
|
84 |
'freeze updates',
|
|
|
85 |
'update/.*',
|
86 |
'feed/.*',
|
87 |
'link/.*',
|
@@ -330,9 +331,9 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
330 |
function feed_information_box ($page, $box = NULL) {
|
331 |
global $wpdb;
|
332 |
if ($page->for_feed_settings()) :
|
333 |
-
$info['name'] =
|
334 |
-
$info['description'] =
|
335 |
-
$info['url'] =
|
336 |
$rss_url = $page->link->link->link_rss;
|
337 |
|
338 |
$hardcode['name'] = $page->link->hardcode('name');
|
@@ -383,9 +384,9 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
383 |
|
384 |
<tr>
|
385 |
<th scope="row"><?php _e('Feed URL:') ?></th>
|
386 |
-
<td><a href="<?php echo
|
387 |
(<a href="<?php echo FEEDVALIDATOR_URI; ?>?url=<?php echo urlencode($rss_url); ?>"
|
388 |
-
title="Check feed <<?php echo
|
389 |
<input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /></td>
|
390 |
</tr>
|
391 |
|
@@ -438,7 +439,7 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
438 |
if ($row->cat_id == $cat_id) :
|
439 |
echo " selected='selected'";
|
440 |
endif;
|
441 |
-
echo ">$row->cat_id: ".
|
442 |
echo "</option>\n";
|
443 |
endforeach;
|
444 |
?></select></p>
|
@@ -501,9 +502,9 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
501 |
if (!preg_match("\007^((".implode(')|(', $page->special_settings)."))$\007i", $key)) :
|
502 |
?>
|
503 |
<tr style="vertical-align:top">
|
504 |
-
<th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo
|
505 |
-
<input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo
|
506 |
-
<td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo
|
507 |
<td width="10%"><select name="notes[<?php echo $i; ?>][action]">
|
508 |
<option value="update">save changes</option>
|
509 |
<option value="delete">delete this setting</option>
|
@@ -531,9 +532,9 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
531 |
|
532 |
if ($this->for_feed_settings()) : // Existing feed?
|
533 |
if (is_null($lookup)) : $lookup = $this->link->link->link_url; endif;
|
534 |
-
$name =
|
535 |
else: // Or a new subscription to add?
|
536 |
-
$name = "Subscribe to <code>".
|
537 |
endif;
|
538 |
?>
|
539 |
<style type="text/css">
|
@@ -565,12 +566,14 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
565 |
<h2>Feed Finder: <?php echo $name; ?></h2>
|
566 |
|
567 |
<?php
|
568 |
-
$f
|
569 |
$feeds = $f->find();
|
570 |
if (count($feeds) > 0):
|
571 |
foreach ($feeds as $key => $f):
|
572 |
-
$
|
573 |
-
|
|
|
|
|
574 |
$feed_title = isset($rss->channel['title'])?$rss->channel['title']:$rss->channel['link'];
|
575 |
$feed_link = isset($rss->channel['link'])?$rss->channel['link']:'';
|
576 |
$feed_type = ($rss->feed_type ? $rss->feed_type : 'Unknown');
|
@@ -594,23 +597,24 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
594 |
// and homepage URL for the new Link.
|
595 |
if (!$this->for_feed_settings()):
|
596 |
?>
|
597 |
-
<input type="hidden" name="feed_title" value="<?php echo
|
598 |
-
<input type="hidden" name="feed_link" value="<?php echo
|
599 |
<?php
|
600 |
endif;
|
601 |
?>
|
602 |
|
603 |
-
<input type="hidden" name="feed" value="<?php echo
|
604 |
<input type="hidden" name="action" value="switchfeed" />
|
605 |
|
606 |
<div>
|
607 |
<div class="feed-sample">
|
608 |
-
|
609 |
<?php
|
610 |
-
|
|
|
|
|
611 |
// Prepare to display Sample Item
|
612 |
-
$link
|
613 |
-
$post
|
614 |
?>
|
615 |
<h3>Sample Item</h3>
|
616 |
<ul>
|
@@ -621,13 +625,14 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
621 |
<?php print $post->post['post_content']; ?>
|
622 |
</div>
|
623 |
<?php
|
|
|
624 |
else:
|
625 |
-
if (
|
626 |
print '<div class="feed-problem">';
|
627 |
print "<h3>Problem:</h3>\n";
|
628 |
print "<p>FeedWordPress encountered the following error
|
629 |
when trying to retrieve this feed:</p>";
|
630 |
-
print '<p style="margin: 1.0em 3.0em"><code>'
|
631 |
print "<p>If you think this is a temporary problem, you can still force FeedWordPress to add the subscription. FeedWordPress will not be able to find any syndicated posts until this problem is resolved.</p>";
|
632 |
print "</div>";
|
633 |
endif;
|
@@ -643,10 +648,11 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
643 |
<h3>Feed Information</h3>
|
644 |
<ul>
|
645 |
<li><strong>Homepage:</strong> <a href="<?php echo $feed_link; ?>"><?php echo is_null($feed_title)?'<em>Unknown</em>':$feed_title; ?></a></li>
|
646 |
-
<li><strong>Feed URL:</strong> <a href="<?php echo
|
647 |
-
<li><strong>Encoding:</strong> <?php echo isset($rss->encoding)?
|
648 |
-
<li><strong>Description:</strong> <?php echo isset($rss->channel['description'])?
|
649 |
</ul>
|
|
|
650 |
<div class="submit"><input type="submit" name="Use" value="« Use this feed" /></div>
|
651 |
<div class="submit"><input type="submit" name="Cancel" value="« Cancel" /></div>
|
652 |
</div>
|
@@ -654,6 +660,8 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
654 |
</fieldset>
|
655 |
</form>
|
656 |
<?php
|
|
|
|
|
657 |
endforeach;
|
658 |
else:
|
659 |
print "<p><strong>".__('Error').":</strong> ".__("FeedWordPress couldn't find any feeds at").' <code><a href="'.htmlspecialchars($lookup).'">'.htmlspecialchars($lookup).'</a></code>';
|
@@ -740,7 +748,7 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
740 |
// We have a checkbox for "No," so if it's unchecked, mark as "Yes."
|
741 |
$this->link->settings["hardcode {$what}"] = (isset($post["hardcode_{$what}"]) ? $post["hardcode_{$what}"] : 'yes');
|
742 |
if (FeedWordPress::affirmative($this->link->settings, "hardcode {$what}")) :
|
743 |
-
$
|
744 |
endif;
|
745 |
endforeach;
|
746 |
|
@@ -787,23 +795,24 @@ contextual_appearance('time-limit', 'time-limit-box', null, 'yes');
|
|
787 |
$this->updatedPosts->accept_POST($post);
|
788 |
|
789 |
if ($this->for_feed_settings()) :
|
790 |
-
|
791 |
-
|
792 |
-
$alter_set = implode(", ", $alter);
|
793 |
|
794 |
// issue update query
|
795 |
-
|
796 |
-
UPDATE $wpdb->links
|
797 |
-
SET $alter_set
|
798 |
-
WHERE link_id='{$this->link->id}'
|
799 |
-
");
|
|
|
|
|
|
|
|
|
800 |
$this->updated = true;
|
801 |
|
802 |
-
// reload
|
803 |
-
|
804 |
-
|
805 |
-
endif;
|
806 |
-
$this->link = new SyndicatedLink($this->link->id);
|
807 |
endif;
|
808 |
|
809 |
// Probably a "Go" button for the drop-down
|
82 |
'postmeta',
|
83 |
'resolve relative',
|
84 |
'freeze updates',
|
85 |
+
'munge permalink',
|
86 |
'update/.*',
|
87 |
'feed/.*',
|
88 |
'link/.*',
|
331 |
function feed_information_box ($page, $box = NULL) {
|
332 |
global $wpdb;
|
333 |
if ($page->for_feed_settings()) :
|
334 |
+
$info['name'] = esc_html($page->link->link->link_name);
|
335 |
+
$info['description'] = esc_html($page->link->link->link_description);
|
336 |
+
$info['url'] = esc_html($page->link->link->link_url);
|
337 |
$rss_url = $page->link->link->link_rss;
|
338 |
|
339 |
$hardcode['name'] = $page->link->hardcode('name');
|
384 |
|
385 |
<tr>
|
386 |
<th scope="row"><?php _e('Feed URL:') ?></th>
|
387 |
+
<td><a href="<?php echo esc_html($rss_url); ?>"><?php echo esc_html($rss_url); ?></a>
|
388 |
(<a href="<?php echo FEEDVALIDATOR_URI; ?>?url=<?php echo urlencode($rss_url); ?>"
|
389 |
+
title="Check feed <<?php echo esc_html($rss_url); ?>> for validity">validate</a>)
|
390 |
<input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /></td>
|
391 |
</tr>
|
392 |
|
439 |
if ($row->cat_id == $cat_id) :
|
440 |
echo " selected='selected'";
|
441 |
endif;
|
442 |
+
echo ">$row->cat_id: ".esc_html($row->cat_name);
|
443 |
echo "</option>\n";
|
444 |
endforeach;
|
445 |
?></select></p>
|
502 |
if (!preg_match("\007^((".implode(')|(', $page->special_settings)."))$\007i", $key)) :
|
503 |
?>
|
504 |
<tr style="vertical-align:top">
|
505 |
+
<th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo esc_html($key); ?>" />
|
506 |
+
<input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo esc_html($key); ?>" /></th>
|
507 |
+
<td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo esc_html($value); ?></textarea></td>
|
508 |
<td width="10%"><select name="notes[<?php echo $i; ?>][action]">
|
509 |
<option value="update">save changes</option>
|
510 |
<option value="delete">delete this setting</option>
|
532 |
|
533 |
if ($this->for_feed_settings()) : // Existing feed?
|
534 |
if (is_null($lookup)) : $lookup = $this->link->link->link_url; endif;
|
535 |
+
$name = esc_html($this->link->link->link_name);
|
536 |
else: // Or a new subscription to add?
|
537 |
+
$name = "Subscribe to <code>".esc_html(feedwordpress_display_url($lookup))."</code>";
|
538 |
endif;
|
539 |
?>
|
540 |
<style type="text/css">
|
566 |
<h2>Feed Finder: <?php echo $name; ?></h2>
|
567 |
|
568 |
<?php
|
569 |
+
$f = new FeedFinder($lookup);
|
570 |
$feeds = $f->find();
|
571 |
if (count($feeds) > 0):
|
572 |
foreach ($feeds as $key => $f):
|
573 |
+
$pie = FeedWordPress::fetch($f);
|
574 |
+
$rss = (is_wp_error($pie) ? $pie : new MagpieFromSimplePie($pie));
|
575 |
+
|
576 |
+
if ($rss and !is_wp_error($rss)):
|
577 |
$feed_title = isset($rss->channel['title'])?$rss->channel['title']:$rss->channel['link'];
|
578 |
$feed_link = isset($rss->channel['link'])?$rss->channel['link']:'';
|
579 |
$feed_type = ($rss->feed_type ? $rss->feed_type : 'Unknown');
|
597 |
// and homepage URL for the new Link.
|
598 |
if (!$this->for_feed_settings()):
|
599 |
?>
|
600 |
+
<input type="hidden" name="feed_title" value="<?php echo esc_html($feed_title); ?>" />
|
601 |
+
<input type="hidden" name="feed_link" value="<?php echo esc_html($feed_link); ?>" />
|
602 |
<?php
|
603 |
endif;
|
604 |
?>
|
605 |
|
606 |
+
<input type="hidden" name="feed" value="<?php echo esc_html($f); ?>" />
|
607 |
<input type="hidden" name="action" value="switchfeed" />
|
608 |
|
609 |
<div>
|
610 |
<div class="feed-sample">
|
|
|
611 |
<?php
|
612 |
+
$link = NULL;
|
613 |
+
$post = NULL;
|
614 |
+
if (!is_wp_error($rss) and count($rss->items) > 0):
|
615 |
// Prepare to display Sample Item
|
616 |
+
$link = new MagpieMockLink(array('simplepie' => $pie, 'magpie' => $rss), $f);
|
617 |
+
$post = new SyndicatedPost(array('simplepie' => $rss->originals[0], 'magpie' => $rss->items[0]), $link);
|
618 |
?>
|
619 |
<h3>Sample Item</h3>
|
620 |
<ul>
|
625 |
<?php print $post->post['post_content']; ?>
|
626 |
</div>
|
627 |
<?php
|
628 |
+
do_action('feedwordpress_feed_finder_sample_item', $f, $post, $link);
|
629 |
else:
|
630 |
+
if (is_wp_error($rss)) :
|
631 |
print '<div class="feed-problem">';
|
632 |
print "<h3>Problem:</h3>\n";
|
633 |
print "<p>FeedWordPress encountered the following error
|
634 |
when trying to retrieve this feed:</p>";
|
635 |
+
print '<p style="margin: 1.0em 3.0em"><code>'.$rss->get_error_message().'</code></p>';
|
636 |
print "<p>If you think this is a temporary problem, you can still force FeedWordPress to add the subscription. FeedWordPress will not be able to find any syndicated posts until this problem is resolved.</p>";
|
637 |
print "</div>";
|
638 |
endif;
|
648 |
<h3>Feed Information</h3>
|
649 |
<ul>
|
650 |
<li><strong>Homepage:</strong> <a href="<?php echo $feed_link; ?>"><?php echo is_null($feed_title)?'<em>Unknown</em>':$feed_title; ?></a></li>
|
651 |
+
<li><strong>Feed URL:</strong> <a href="<?php echo esc_html($f); ?>"><?php echo esc_html($f); ?></a> (<a title="Check feed <<?php echo esc_html($f); ?>> for validity" href="http://feedvalidator.org/check.cgi?url=<?php echo urlencode($f); ?>">validate</a>)</li>
|
652 |
+
<li><strong>Encoding:</strong> <?php echo isset($rss->encoding)?esc_html($rss->encoding):"<em>Unknown</em>"; ?></li>
|
653 |
+
<li><strong>Description:</strong> <?php echo isset($rss->channel['description'])?esc_html($rss->channel['description']):"<em>Unknown</em>"; ?></li>
|
654 |
</ul>
|
655 |
+
<?php do_action('feedwordpress_feedfinder_form', $f, $post, $link, $this->for_feed_settings()); ?>
|
656 |
<div class="submit"><input type="submit" name="Use" value="« Use this feed" /></div>
|
657 |
<div class="submit"><input type="submit" name="Cancel" value="« Cancel" /></div>
|
658 |
</div>
|
660 |
</fieldset>
|
661 |
</form>
|
662 |
<?php
|
663 |
+
unset($link);
|
664 |
+
unset($post);
|
665 |
endforeach;
|
666 |
else:
|
667 |
print "<p><strong>".__('Error').":</strong> ".__("FeedWordPress couldn't find any feeds at").' <code><a href="'.htmlspecialchars($lookup).'">'.htmlspecialchars($lookup).'</a></code>';
|
748 |
// We have a checkbox for "No," so if it's unchecked, mark as "Yes."
|
749 |
$this->link->settings["hardcode {$what}"] = (isset($post["hardcode_{$what}"]) ? $post["hardcode_{$what}"] : 'yes');
|
750 |
if (FeedWordPress::affirmative($this->link->settings, "hardcode {$what}")) :
|
751 |
+
$this->link->link->{'link_'.$what} = $post['link'.$what];
|
752 |
endif;
|
753 |
endforeach;
|
754 |
|
795 |
$this->updatedPosts->accept_POST($post);
|
796 |
|
797 |
if ($this->for_feed_settings()) :
|
798 |
+
// Save changes to channel-level meta-data
|
799 |
+
//$alter_set = implode(", ", $alter);
|
|
|
800 |
|
801 |
// issue update query
|
802 |
+
//$result = $wpdb->query("
|
803 |
+
//UPDATE $wpdb->links
|
804 |
+
//SET $alter_set
|
805 |
+
//WHERE link_id='{$this->link->id}'
|
806 |
+
//");
|
807 |
+
|
808 |
+
// Save settings
|
809 |
+
$this->link->save_settings(/*reload=*/ true);
|
810 |
+
|
811 |
$this->updated = true;
|
812 |
|
813 |
+
// Reset, reload
|
814 |
+
$link_id = $this->link->id; unset($this->link);
|
815 |
+
$this->link = new SyndicatedLink($link_id);
|
|
|
|
|
816 |
endif;
|
817 |
|
818 |
// Probably a "Go" button for the drop-down
|
feedtime.class.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* class FeedTime: handle common date-time formats used in feeds.
|
4 |
+
*
|
5 |
+
*/
|
6 |
+
class FeedTime {
|
7 |
+
var $rep;
|
8 |
+
var $ts;
|
9 |
+
|
10 |
+
function FeedTime ($time) {
|
11 |
+
$this->set($time);
|
12 |
+
} /* FeedTime constructor */
|
13 |
+
|
14 |
+
function set ($time) {
|
15 |
+
$this->rep = $time;
|
16 |
+
$this->ts = NULL;
|
17 |
+
if (is_numeric($time)) : // Presumably a Unix-epoch timestamp
|
18 |
+
$this->ts = $this->rep;
|
19 |
+
elseif (is_string($time)) :
|
20 |
+
// First, try to parse it as a W3C date-time
|
21 |
+
$this->ts = $this->parse_w3cdtf();
|
22 |
+
|
23 |
+
if ($this->failed()) :
|
24 |
+
// In some versions of PHP, strtotime() does not support
|
25 |
+
// the UT timezone. Since UT is by definition within 1
|
26 |
+
// second of UTC, we'll just convert it here to avoid
|
27 |
+
// problems.
|
28 |
+
$time = preg_replace(
|
29 |
+
'/(\s)UT$/',
|
30 |
+
'$1UTC',
|
31 |
+
$time
|
32 |
+
);
|
33 |
+
$this->ts = strtotime($time);
|
34 |
+
endif;
|
35 |
+
endif;
|
36 |
+
} /* FeedTime::set() */
|
37 |
+
|
38 |
+
function timestamp () {
|
39 |
+
$unix = NULL;
|
40 |
+
if (!$this->failed()) :
|
41 |
+
$unix = $this->ts;
|
42 |
+
endif;
|
43 |
+
return $unix;
|
44 |
+
} /* FeedTime::timestamp() */
|
45 |
+
|
46 |
+
function failed () {
|
47 |
+
return (!is_numeric($this->ts) or !$this->ts or ($this->ts <= 0));
|
48 |
+
} /* FeedTime::failed() */
|
49 |
+
|
50 |
+
/**
|
51 |
+
* FeedTime::parse_w3cdtf() parses a W3C date-time format date into a
|
52 |
+
* Unix epoch timestamp. Derived from the parse_w3cdtf function included
|
53 |
+
* with MagpieRSS by Kellan Elliot-McCrea <kellan@protest.net>, with
|
54 |
+
* modifications and bugfixes by Charles Johnson
|
55 |
+
* <technophilia@radgeek.com>, under the terms of the GPL.
|
56 |
+
*/
|
57 |
+
function parse_w3cdtf () {
|
58 |
+
$unix = NULL; // Failure
|
59 |
+
|
60 |
+
# regex to match wc3dtf
|
61 |
+
$pat = "/^\s*
|
62 |
+
(\d{4})
|
63 |
+
(-
|
64 |
+
(\d{2})
|
65 |
+
(-
|
66 |
+
(\d{2})
|
67 |
+
(T
|
68 |
+
(\d{2})
|
69 |
+
:(\d{2})
|
70 |
+
(:
|
71 |
+
(\d{2})
|
72 |
+
(\.\d+)?
|
73 |
+
)?
|
74 |
+
(?:([-+])(\d{2}):?(\d{2})|(Z))?
|
75 |
+
)?
|
76 |
+
)?
|
77 |
+
)?
|
78 |
+
\s*\$
|
79 |
+
/x";
|
80 |
+
|
81 |
+
if ( preg_match( $pat, $this->rep, $match ) ) :
|
82 |
+
$year = (isset($match[1]) ? $match[1] : NULL);
|
83 |
+
$month = (isset($match[3]) ? $match[3] : NULL);
|
84 |
+
$day = (isset($match[5]) ? $match[5] : NULL);
|
85 |
+
$hours = (isset($match[7]) ? $match[7] : NULL);
|
86 |
+
$minutes = (isset($match[8]) ? $match[8] : NULL);
|
87 |
+
$seconds = (isset($match[10]) ? $match[10] : NULL);
|
88 |
+
|
89 |
+
# W3C dates can omit the time, the day of the month, or even the month.
|
90 |
+
# Fill in any blanks using information from the present moment. --CWJ
|
91 |
+
$default['hr'] = (int) gmdate('H');
|
92 |
+
$default['day'] = (int) gmdate('d');
|
93 |
+
$default['month'] = (int) gmdate('m');
|
94 |
+
|
95 |
+
if (is_null($hours)) : $hours = $default['hr']; $minutes = 0; $seconds = 0; endif;
|
96 |
+
if (is_null($day)) : $day = $default['day']; endif;
|
97 |
+
if (is_null($month)) : $month = $default['month']; endif;
|
98 |
+
|
99 |
+
# calc epoch for current date assuming GMT
|
100 |
+
$unix = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
|
101 |
+
|
102 |
+
$offset = 0;
|
103 |
+
if ( isset($match[15]) and $match[15] == 'Z' ) :
|
104 |
+
# zulu time, aka GMT
|
105 |
+
else :
|
106 |
+
$tz_mod = $match[12];
|
107 |
+
$tz_hour = $match[13];
|
108 |
+
$tz_min = $match[14];
|
109 |
+
|
110 |
+
# zero out the variables
|
111 |
+
if ( ! $tz_hour ) { $tz_hour = 0; }
|
112 |
+
if ( ! $tz_min ) { $tz_min = 0; }
|
113 |
+
|
114 |
+
$offset_secs = (($tz_hour*60)+$tz_min)*60;
|
115 |
+
|
116 |
+
# is timezone ahead of GMT? then subtract offset
|
117 |
+
if ( $tz_mod == '+' ) :
|
118 |
+
$offset_secs = $offset_secs * -1;
|
119 |
+
endif;
|
120 |
+
$offset = $offset_secs;
|
121 |
+
endif;
|
122 |
+
$unix = $unix + $offset;
|
123 |
+
endif;
|
124 |
+
return $unix;
|
125 |
+
} /* FeedTime::parse_w3cdtf () */
|
126 |
+
} /* class FeedTime */
|
feedwordpress.php
CHANGED
@@ -3,12 +3,17 @@
|
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://feedwordpress.radgeek.com/
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
-
Version: 2010.
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
10 |
*/
|
11 |
|
|
|
|
|
|
|
|
|
|
|
12 |
# This uses code derived from:
|
13 |
# - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
|
14 |
# - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
|
@@ -28,7 +33,7 @@ License: GPL
|
|
28 |
|
29 |
# -- Don't change these unless you know what you're doing...
|
30 |
|
31 |
-
define ('FEEDWORDPRESS_VERSION', '2010.
|
32 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
33 |
|
34 |
// Defaults
|
@@ -66,29 +71,29 @@ if (FEEDWORDPRESS_DEBUG) :
|
|
66 |
// Help us to pick out errors, if any.
|
67 |
ini_set('error_reporting', E_ALL & ~E_NOTICE);
|
68 |
ini_set('display_errors', true);
|
69 |
-
define('MAGPIE_DEBUG', true);
|
70 |
|
71 |
// When testing we don't want cache issues to interfere. But this is
|
72 |
// a VERY BAD SETTING for a production server. Webmasters will eat your
|
73 |
// face for breakfast if you use it, and the baby Jesus will cry. So
|
74 |
// make sure FEEDWORDPRESS_DEBUG is FALSE for any site that will be
|
75 |
// used for more than testing purposes!
|
76 |
-
define('
|
|
|
|
|
77 |
else :
|
78 |
-
|
79 |
-
|
80 |
-
define('
|
|
|
|
|
81 |
endif;
|
82 |
|
83 |
-
//
|
84 |
-
|
85 |
-
// this archive into wp-includes/rss.php
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
require_once (ABSPATH . WPINC . '/rss-functions.php');
|
91 |
-
endif;
|
92 |
|
93 |
if (isset($wp_db_version)) :
|
94 |
if ($wp_db_version >= FWP_SCHEMA_23) :
|
@@ -177,6 +182,13 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
|
|
177 |
# Filter in original permalinks if the user wants that
|
178 |
add_filter('post_link', 'syndication_permalink', 1);
|
179 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
# WTF? By default, wp_insert_link runs incoming link_url and link_rss
|
181 |
# URIs through default filters that include `wp_kses()`. But `wp_kses()`
|
182 |
# just happens to escape any occurrence of & to & -- which just
|
@@ -187,8 +199,6 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
|
|
187 |
# Admin menu
|
188 |
add_action('admin_menu', 'fwp_add_pages');
|
189 |
add_action('admin_notices', 'fwp_check_debug');
|
190 |
-
add_action('admin_notices', 'fwp_check_magpie');
|
191 |
-
add_action('init', 'feedwordpress_check_for_magpie_fix');
|
192 |
|
193 |
add_action('admin_menu', 'feedwordpress_add_post_edit_controls');
|
194 |
add_action('save_post', 'feedwordpress_save_post_edit_controls');
|
@@ -216,12 +226,16 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
|
|
216 |
add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
|
217 |
endif;
|
218 |
|
219 |
-
if (FeedWordPress::update_requested()
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
|
|
225 |
endif;
|
226 |
|
227 |
# Cron-less auto-update. Hooray!
|
@@ -242,42 +256,9 @@ else :
|
|
242 |
add_action('admin_menu', 'fwp_add_pages');
|
243 |
endif; // if (!FeedWordPress::needs_upgrade())
|
244 |
|
245 |
-
function feedwordpress_check_for_magpie_fix () {
|
246 |
-
if (isset($_POST['action']) and $_POST['action']=='fix_magpie_version') :
|
247 |
-
FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_fix_magpie', /*capability=*/ 'edit_files');
|
248 |
-
|
249 |
-
$back_to = $_SERVER['REQUEST_URI'];
|
250 |
-
if (isset($_POST['ignore'])) :
|
251 |
-
// kill error message by telling it we ignored the upgrade request for this version
|
252 |
-
update_option('feedwordpress_magpie_ignored_upgrade_to', EXPECTED_MAGPIE_VERSION);
|
253 |
-
$ret = 'ignored';
|
254 |
-
elseif (isset($_POST['upgrade'])) :
|
255 |
-
$source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
|
256 |
-
$destination = ABSPATH . WPINC . '/rss.php';
|
257 |
-
$success = @copy($source, $destination);
|
258 |
-
|
259 |
-
// Copy over rss-functions.php, too, to avoid collisions
|
260 |
-
// on pre-lapsarian versions of WordPress.
|
261 |
-
if ($success) :
|
262 |
-
$source = dirname(__FILE__)."/MagpieRSS-upgrade/rss-functions.php";
|
263 |
-
$destination = ABSPATH . WPINC . '/rss-functions.php';
|
264 |
-
$success = @copy($source, $destination);
|
265 |
-
endif;
|
266 |
-
$ret = (int) $success;
|
267 |
-
endif;
|
268 |
-
|
269 |
-
if (strpos($back_to, '?')===false) : $sep = '?';
|
270 |
-
else : $sep = '&';
|
271 |
-
endif;
|
272 |
-
|
273 |
-
header("Location: {$back_to}{$sep}feedwordpress_magpie_fix=".$ret);
|
274 |
-
exit;
|
275 |
-
endif;
|
276 |
-
} /* feedwordpress_check_for_magpie_fix() */
|
277 |
-
|
278 |
function feedwordpress_auto_update () {
|
279 |
if (FeedWordPress::stale()) :
|
280 |
-
$feedwordpress
|
281 |
$feedwordpress->update();
|
282 |
endif;
|
283 |
} /* feedwordpress_auto_update () */
|
@@ -287,7 +268,7 @@ function feedwordpress_update_magic_url () {
|
|
287 |
|
288 |
// Explicit update request in the HTTP request (e.g. from a cron job)
|
289 |
if (FeedWordPress::update_requested()) :
|
290 |
-
$feedwordpress
|
291 |
$feedwordpress->update(FeedWordPress::update_requested_url());
|
292 |
|
293 |
if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
|
@@ -386,11 +367,31 @@ function debug_out_feedwordpress_update_complete ($delta) {
|
|
386 |
: implode(' and ', $mesg))."\n");
|
387 |
}
|
388 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
389 |
################################################################################
|
390 |
## TEMPLATE API: functions to make your templates syndication-aware ############
|
391 |
################################################################################
|
392 |
|
393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
|
395 |
function get_syndication_source_link ($original = NULL, $id = NULL) {
|
396 |
if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
|
@@ -422,6 +423,7 @@ function feedwordpress_display_url ($url, $before = 60, $after = 0) {
|
|
422 |
$url = (isset($bits['user'])?$bits['user'].'@':'')
|
423 |
.(isset($bits['host'])?$bits['host']:'')
|
424 |
.(isset($bits['path'])?$bits['path']:'')
|
|
|
425 |
.(isset($bits['query'])?'?'.$bits['query']:'');
|
426 |
|
427 |
if (strlen($url) > ($before+$after)) :
|
@@ -502,20 +504,28 @@ function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_value
|
|
502 |
function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
|
503 |
|
504 |
$feedwordpress_linkcache = array (); // only load links from database once
|
|
|
|
|
505 |
|
506 |
-
|
507 |
-
global $wpdb, $feedwordpress_linkcache;
|
508 |
-
$feed_id = get_syndication_feed_id($id);
|
509 |
|
510 |
-
$
|
511 |
if (strlen($feed_id) > 0):
|
512 |
if (isset($feedwordpress_linkcache[$feed_id])) :
|
513 |
$link = $feedwordpress_linkcache[$feed_id];
|
514 |
else :
|
515 |
-
$link
|
516 |
$feedwordpress_linkcache[$feed_id] = $link;
|
517 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
518 |
|
|
|
|
|
519 |
$ret = $link->settings[$key];
|
520 |
endif;
|
521 |
return $ret;
|
@@ -528,11 +538,53 @@ function the_syndication_permalink ($id = NULL) {
|
|
528 |
echo get_syndication_permalink($id);
|
529 |
}
|
530 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
531 |
################################################################################
|
532 |
## FILTERS: syndication-aware handling of post data for templates and feeds ####
|
533 |
################################################################################
|
534 |
|
535 |
$feedwordpress_the_syndicated_content = NULL;
|
|
|
536 |
|
537 |
function feedwordpress_preserve_syndicated_content ($text) {
|
538 |
global $feedwordpress_the_syndicated_content;
|
@@ -585,14 +637,128 @@ function feedwordpress_item_feed_data () {
|
|
585 |
endif;
|
586 |
}
|
587 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
588 |
function syndication_permalink ($permalink = '') {
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
endif;
|
595 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
|
597 |
################################################################################
|
598 |
## ADMIN MENU ADD-ONS: register Dashboard management pages #####################
|
@@ -638,95 +804,6 @@ for a production server.</p>
|
|
638 |
endif;
|
639 |
} /* function fwp_check_debug () */
|
640 |
|
641 |
-
define('EXPECTED_MAGPIE_VERSION', '2010.0122');
|
642 |
-
function fwp_check_magpie () {
|
643 |
-
if (isset($_REQUEST['feedwordpress_magpie_fix'])) :
|
644 |
-
if ($_REQUEST['feedwordpress_magpie_fix']=='ignored') :
|
645 |
-
?>
|
646 |
-
<div class="updated fade">
|
647 |
-
<p>O.K., we'll ignore the problem for now. FeedWordPress will not display any
|
648 |
-
more error messages.</p>
|
649 |
-
</div>
|
650 |
-
<?php
|
651 |
-
elseif ((bool) $_REQUEST['feedwordpress_magpie_fix']) :
|
652 |
-
?>
|
653 |
-
<div class="updated fade">
|
654 |
-
<p>Congratulations! Your MagpieRSS has been successfully upgraded to the version
|
655 |
-
shipped with FeedWordPress.</p>
|
656 |
-
</div>
|
657 |
-
<?php
|
658 |
-
else :
|
659 |
-
$source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
|
660 |
-
$destination = ABSPATH . WPINC . '/rss.php';
|
661 |
-
$cmd = "cp '".htmlspecialchars(addslashes($source))."' '".htmlspecialchars(addslashes($destination))."'";
|
662 |
-
$cmd = wordwrap($cmd, /*width=*/ 75, /*break=*/ " \\\n\t");
|
663 |
-
|
664 |
-
?>
|
665 |
-
<div class="error">
|
666 |
-
<p><strong>FeedWordPress was unable to automatically upgrade your copy of MagpieRSS.</strong></p>
|
667 |
-
<p>It's likely that you need to change the file permissions on <code><?php print htmlspecialchars($source); ?></code>
|
668 |
-
to allow FeedWordPress to overwrite it.</p>
|
669 |
-
<p><strong>To perform the upgrade manually,</strong> you can
|
670 |
-
use a SFTP or FTP client to upload a copy of <code>rss.php</code> from the
|
671 |
-
<code>MagpieRSS-upgrades/</code> directory of your FeedWordPress archive so that
|
672 |
-
it overwrites <code><?php print htmlspecialchars($destination); ?></code>. Or,
|
673 |
-
if your web host provides shell access, you can issue the following command from
|
674 |
-
a command prompt to perform the upgrade:</p>
|
675 |
-
<pre>
|
676 |
-
<samp>$</samp> <kbd><?php print $cmd; ?></kbd>
|
677 |
-
</pre>
|
678 |
-
<p><strong>If you've fixed the file permissions,</strong> you can try the
|
679 |
-
automatic upgrade again.</p>
|
680 |
-
|
681 |
-
<?php feedwordpress_upgrade_old_and_busted_buttons(); ?>
|
682 |
-
</div>
|
683 |
-
<?php
|
684 |
-
endif;
|
685 |
-
else :
|
686 |
-
$magpie_version = FeedWordPress::magpie_version();
|
687 |
-
|
688 |
-
$ignored = get_option('feedwordpress_magpie_ignored_upgrade_to');
|
689 |
-
if (EXPECTED_MAGPIE_VERSION != $magpie_version and EXPECTED_MAGPIE_VERSION != $ignored) :
|
690 |
-
if (current_user_can('edit_files')) :
|
691 |
-
$youAre = 'you are';
|
692 |
-
$itIsRecommendedThatYou = 'It is <strong>strongly recommended</strong> that you';
|
693 |
-
else :
|
694 |
-
$youAre = 'this site is';
|
695 |
-
$itIsRecommendedThatYou = 'You may want to contact the administrator of the site; it is <strong>strongly recommended</strong> that they';
|
696 |
-
endif;
|
697 |
-
print '<div class="error">';
|
698 |
-
?>
|
699 |
-
<p style="font-style: italic"><strong>FeedWordPress has detected that <?php print $youAre; ?> currently using a version of
|
700 |
-
MagpieRSS other than the upgraded version that ships with this version of FeedWordPress.</strong></p>
|
701 |
-
<ul>
|
702 |
-
<li><strong>Currently running:</strong> MagpieRSS <?php print $magpie_version; ?></li>
|
703 |
-
<li><strong>Version included with FeedWordPress <?php print FEEDWORDPRESS_VERSION; ?>:</strong> MagpieRSS <?php print EXPECTED_MAGPIE_VERSION; ?></li>
|
704 |
-
</ul>
|
705 |
-
<p><?php print $itIsRecommendedThatYou; ?> install the upgraded
|
706 |
-
version of MagpieRSS supplied with FeedWordPress. The version of
|
707 |
-
MagpieRSS that ships with WordPress is very old and buggy, and
|
708 |
-
encounters a number of errors when trying to parse modern Atom
|
709 |
-
and RSS feeds.</p>
|
710 |
-
<?php
|
711 |
-
feedwordpress_upgrade_old_and_busted_buttons();
|
712 |
-
print '</div>';
|
713 |
-
endif;
|
714 |
-
endif;
|
715 |
-
}
|
716 |
-
|
717 |
-
function feedwordpress_upgrade_old_and_busted_buttons() {
|
718 |
-
if (current_user_can('edit_files')) :
|
719 |
-
?>
|
720 |
-
<form action="" method="post"><div>
|
721 |
-
<?php FeedWordPressCompatibility::stamp_nonce('feedwordpress_fix_magpie'); ?>
|
722 |
-
<input type="hidden" name="action" value="fix_magpie_version" />
|
723 |
-
<input class="button-secondary" type="submit" name="ignore" value="<?php _e('Ignore this problem'); ?>" />
|
724 |
-
<input class="button-primary" type="submit" name="upgrade" value="<?php _e('Upgrade'); ?>" />
|
725 |
-
</div></form>
|
726 |
-
<?php
|
727 |
-
endif;
|
728 |
-
}
|
729 |
-
|
730 |
################################################################################
|
731 |
## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
|
732 |
## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
|
@@ -797,8 +874,8 @@ function fwp_publish_post_hook ($post_id) {
|
|
797 |
if (is_syndicated($post->ID)) :
|
798 |
?>
|
799 |
<p>This is a syndicated post, which originally appeared at
|
800 |
-
<cite><?php print
|
801 |
-
<a href="<?php print
|
802 |
|
803 |
<p><input type="hidden" name="feedwordpress_noncename" id="feedwordpress_noncename" value="<?php print wp_create_nonce(plugin_basename(__FILE__)); ?>" />
|
804 |
<label><input type="checkbox" name="freeze_updates" value="yes" <?php if ($frozen_post) : ?>checked="checked"<?php endif; ?> /> <strong>Manual editing.</strong>
|
@@ -886,7 +963,7 @@ class FeedWordPress {
|
|
886 |
$this->feeds = array ();
|
887 |
$links = FeedWordPress::syndicated_links();
|
888 |
if ($links): foreach ($links as $link):
|
889 |
-
$this->feeds[]
|
890 |
endforeach; endif;
|
891 |
} // FeedWordPress::FeedWordPress ()
|
892 |
|
@@ -992,8 +1069,10 @@ class FeedWordPress {
|
|
992 |
$added = $feed->poll($crash_ts);
|
993 |
do_action('feedwordpress_check_feed_complete', $feed->settings, $added, time() - $start_ts);
|
994 |
|
995 |
-
if (
|
996 |
-
|
|
|
|
|
997 |
endif;
|
998 |
endforeach;
|
999 |
|
@@ -1149,6 +1228,17 @@ class FeedWordPress {
|
|
1149 |
return apply_filters('syndicated_post_use_aggregator_source_data', ($ret=='yes'));
|
1150 |
}
|
1151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1152 |
function syndicated_links () {
|
1153 |
$contributors = FeedWordPress::link_category_id();
|
1154 |
if (function_exists('get_bookmarks')) :
|
@@ -1234,55 +1324,11 @@ class FeedWordPress {
|
|
1234 |
if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
|
1235 |
|
1236 |
switch ($from) :
|
1237 |
-
case 0.96:
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
// Avoid duplicates
|
1243 |
-
$wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key = 'syndication_feed_id'");
|
1244 |
-
|
1245 |
-
// Look up all the link IDs
|
1246 |
-
$wpdb->query("
|
1247 |
-
CREATE TEMPORARY TABLE tmp_custom_values
|
1248 |
-
SELECT
|
1249 |
-
NULL AS meta_id,
|
1250 |
-
post_id,
|
1251 |
-
'syndication_feed_id' AS meta_key,
|
1252 |
-
link_id AS meta_value
|
1253 |
-
FROM `{$wpdb->postmeta}`, `{$wpdb->links}`
|
1254 |
-
WHERE
|
1255 |
-
meta_key='syndication_feed'
|
1256 |
-
AND meta_value=link_rss
|
1257 |
-
AND link_category = {$cat_id}
|
1258 |
-
");
|
1259 |
-
|
1260 |
-
// Now attach them to their posts
|
1261 |
-
$wpdb->query("INSERT INTO `{$wpdb->postmeta}` SELECT * FROM tmp_custom_values");
|
1262 |
-
|
1263 |
-
// And clean up after ourselves.
|
1264 |
-
$wpdb->query("DROP TABLE tmp_custom_values");
|
1265 |
-
|
1266 |
-
// Now fix the guids to avoid duplicate posts
|
1267 |
-
echo "<ul>";
|
1268 |
-
foreach ($this->feeds as $syndicatedLink) :
|
1269 |
-
$feed = $syndicatedLink->settings;
|
1270 |
-
echo "<li>Fixing post meta-data for <cite>".$feed['link/name']."</cite> … "; flush();
|
1271 |
-
$rss = @fetch_rss($feed['link/uri']);
|
1272 |
-
if (is_array($rss->items)) :
|
1273 |
-
foreach ($rss->items as $item) :
|
1274 |
-
$post = new SyndicatedPost($item, $syndicatedLink);
|
1275 |
-
$guid = $wpdb->escape($post->guid()); // new GUID algorithm
|
1276 |
-
$link = $wpdb->escape($item['link']);
|
1277 |
-
|
1278 |
-
$wpdb->query("
|
1279 |
-
UPDATE `{$wpdb->posts}` SET guid='{$guid}' WHERE guid='{$link}'
|
1280 |
-
");
|
1281 |
-
endforeach;
|
1282 |
-
endif;
|
1283 |
-
echo "<strong>complete.</strong></li>\n";
|
1284 |
-
endforeach;
|
1285 |
-
echo "</ul>\n";
|
1286 |
|
1287 |
// Mark the upgrade as successful.
|
1288 |
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
@@ -1290,6 +1336,25 @@ class FeedWordPress {
|
|
1290 |
echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
|
1291 |
} /* FeedWordPress::upgrade_database() */
|
1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1293 |
function create_guid_index () {
|
1294 |
global $wpdb;
|
1295 |
|
@@ -1298,26 +1363,68 @@ class FeedWordPress {
|
|
1298 |
");
|
1299 |
} /* FeedWordPress::create_guid_index () */
|
1300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1301 |
function clear_cache () {
|
1302 |
global $wpdb;
|
1303 |
|
1304 |
-
//
|
1305 |
-
//
|
1306 |
-
//
|
1307 |
-
//
|
1308 |
-
//
|
|
|
|
|
1309 |
$wpdb->query("
|
1310 |
DELETE FROM {$wpdb->options}
|
1311 |
-
WHERE
|
1312 |
");
|
1313 |
} /* FeedWordPress::clear_cache () */
|
1314 |
|
1315 |
-
function
|
1316 |
-
|
1317 |
-
|
|
|
1318 |
endif;
|
1319 |
-
return $
|
1320 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1321 |
|
1322 |
# Utility functions for handling text settings
|
1323 |
function negative ($f, $setting) {
|
@@ -1335,15 +1442,10 @@ class FeedWordPress {
|
|
1335 |
function critical_bug ($varname, $var, $line) {
|
1336 |
global $wp_version;
|
1337 |
|
1338 |
-
if (defined('MAGPIE_VERSION')) : $mv = MAGPIE_VERSION;
|
1339 |
-
else : $mv = 'WordPress '.$wp_version.' default.';
|
1340 |
-
endif;
|
1341 |
-
|
1342 |
echo '<p>There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
|
1343 |
echo "\n<plaintext>";
|
1344 |
echo "Triggered at line # ".$line."\n";
|
1345 |
echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n";
|
1346 |
-
echo "MagpieRSS version: {$mv}\n";
|
1347 |
echo "WordPress version: {$wp_version}\n";
|
1348 |
echo "PHP version: ".phpversion()."\n";
|
1349 |
echo "\n";
|
@@ -1371,7 +1473,7 @@ function feedwordpress_xmlrpc_hook ($args = array ()) {
|
|
1371 |
}
|
1372 |
|
1373 |
function feedwordpress_pong ($args) {
|
1374 |
-
$feedwordpress
|
1375 |
$delta = @$feedwordpress->update($args[1]);
|
1376 |
if (is_null($delta)):
|
1377 |
return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
|
@@ -1384,11 +1486,7 @@ function feedwordpress_pong ($args) {
|
|
1384 |
endif;
|
1385 |
}
|
1386 |
|
1387 |
-
|
1388 |
-
# in, don't load it again.
|
1389 |
-
if (!class_exists('Relative_URI')) {
|
1390 |
-
require_once(dirname(__FILE__) . '/relative_uri.class.php');
|
1391 |
-
}
|
1392 |
|
1393 |
// take your best guess at the realname and e-mail, given a string
|
1394 |
define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://feedwordpress.radgeek.com/
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
+
Version: 2010.0528
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
10 |
*/
|
11 |
|
12 |
+
/**
|
13 |
+
* @package FeedWordPress
|
14 |
+
* @version 2010.0528
|
15 |
+
*/
|
16 |
+
|
17 |
# This uses code derived from:
|
18 |
# - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
|
19 |
# - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
|
33 |
|
34 |
# -- Don't change these unless you know what you're doing...
|
35 |
|
36 |
+
define ('FEEDWORDPRESS_VERSION', '2010.0528');
|
37 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
38 |
|
39 |
// Defaults
|
71 |
// Help us to pick out errors, if any.
|
72 |
ini_set('error_reporting', E_ALL & ~E_NOTICE);
|
73 |
ini_set('display_errors', true);
|
|
|
74 |
|
75 |
// When testing we don't want cache issues to interfere. But this is
|
76 |
// a VERY BAD SETTING for a production server. Webmasters will eat your
|
77 |
// face for breakfast if you use it, and the baby Jesus will cry. So
|
78 |
// make sure FEEDWORDPRESS_DEBUG is FALSE for any site that will be
|
79 |
// used for more than testing purposes!
|
80 |
+
define('FEEDWORDPRESS_CACHE_AGE', 1);
|
81 |
+
define('FEEDWORDPRESS_CACHE_LIFETIME', 1);
|
82 |
+
define('FEEDWORDPRESS_FETCH_TIME_OUT', 60);
|
83 |
else :
|
84 |
+
// Hold onto data all day for conditional GET purposes,
|
85 |
+
// but consider it stale after 1 min (requiring a conditional GET)
|
86 |
+
define('FEEDWORDPRESS_CACHE_LIFETIME', 24*60*60);
|
87 |
+
define('FEEDWORDPRESS_CACHE_AGE', 1*60);
|
88 |
+
define('FEEDWORDPRESS_FETCH_TIME_OUT', 10);
|
89 |
endif;
|
90 |
|
91 |
+
// Use our the cache settings that we want.
|
92 |
+
add_filter('wp_feed_cache_transient_lifetime', array('FeedWordPress', 'cache_lifetime'));
|
|
|
93 |
|
94 |
+
// Ensure that we have SimplePie loaded up and ready to go.
|
95 |
+
// We no longer need a MagpieRSS upgrade module. Hallelujah!
|
96 |
+
require_once(ABSPATH . WPINC . '/feed.php');
|
|
|
|
|
97 |
|
98 |
if (isset($wp_db_version)) :
|
99 |
if ($wp_db_version >= FWP_SCHEMA_23) :
|
182 |
# Filter in original permalinks if the user wants that
|
183 |
add_filter('post_link', 'syndication_permalink', 1);
|
184 |
|
185 |
+
# When foreign URLs are used for permalinks in feeds or display
|
186 |
+
# contexts, they need to be escaped properly.
|
187 |
+
add_filter('the_permalink', 'syndication_permalink_escaped');
|
188 |
+
add_filter('the_permalink_rss', 'syndication_permalink_escaped');
|
189 |
+
|
190 |
+
add_filter('post_comments_feed_link', 'syndication_comments_feed_link');
|
191 |
+
|
192 |
# WTF? By default, wp_insert_link runs incoming link_url and link_rss
|
193 |
# URIs through default filters that include `wp_kses()`. But `wp_kses()`
|
194 |
# just happens to escape any occurrence of & to & -- which just
|
199 |
# Admin menu
|
200 |
add_action('admin_menu', 'fwp_add_pages');
|
201 |
add_action('admin_notices', 'fwp_check_debug');
|
|
|
|
|
202 |
|
203 |
add_action('admin_menu', 'feedwordpress_add_post_edit_controls');
|
204 |
add_action('save_post', 'feedwordpress_save_post_edit_controls');
|
226 |
add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
|
227 |
endif;
|
228 |
|
229 |
+
if (FeedWordPress::update_requested()) :
|
230 |
+
if (FEEDWORDPRESS_DEBUG) :
|
231 |
+
add_action('post_syndicated_item', 'debug_out_feedwordpress_post', 100);
|
232 |
+
add_action('update_syndicated_item', 'debug_out_feedwordpress_update_post', 100);
|
233 |
+
add_action('feedwordpress_update', 'debug_out_feedwordpress_update_feeds', 100);
|
234 |
+
add_action('feedwordpress_check_feed', 'debug_out_feedwordpress_check_feed', 100);
|
235 |
+
add_action('feedwordpress_update_complete', 'debug_out_feedwordpress_update_complete', 100);
|
236 |
+
endif;
|
237 |
+
|
238 |
+
add_action('feedwordpress_check_feed_complete', 'debug_out_feedwordpress_feed_error', 100, 3);
|
239 |
endif;
|
240 |
|
241 |
# Cron-less auto-update. Hooray!
|
256 |
add_action('admin_menu', 'fwp_add_pages');
|
257 |
endif; // if (!FeedWordPress::needs_upgrade())
|
258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
function feedwordpress_auto_update () {
|
260 |
if (FeedWordPress::stale()) :
|
261 |
+
$feedwordpress = new FeedWordPress;
|
262 |
$feedwordpress->update();
|
263 |
endif;
|
264 |
} /* feedwordpress_auto_update () */
|
268 |
|
269 |
// Explicit update request in the HTTP request (e.g. from a cron job)
|
270 |
if (FeedWordPress::update_requested()) :
|
271 |
+
$feedwordpress = new FeedWordPress;
|
272 |
$feedwordpress->update(FeedWordPress::update_requested_url());
|
273 |
|
274 |
if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
|
367 |
: implode(' and ', $mesg))."\n");
|
368 |
}
|
369 |
|
370 |
+
function debug_out_feedwordpress_feed_error ($feed, $added, $dt) {
|
371 |
+
if (is_wp_error($added)) :
|
372 |
+
$mesgs = $added->get_error_messages();
|
373 |
+
foreach ($mesgs as $mesg) :
|
374 |
+
echo "[feedwordpress] Error updating [{$feed['link/uri']}]: $mesg\n";
|
375 |
+
endforeach;
|
376 |
+
endif;
|
377 |
+
}
|
378 |
+
|
379 |
################################################################################
|
380 |
## TEMPLATE API: functions to make your templates syndication-aware ############
|
381 |
################################################################################
|
382 |
|
383 |
+
/**
|
384 |
+
* is_syndicated: Tests whether the current post in a Loop context, or a post
|
385 |
+
* given by ID number, was syndicated by FeedWordPress. Useful for templates
|
386 |
+
* to determine whether or not to retrieve syndication-related meta-data in
|
387 |
+
* displaying a post.
|
388 |
+
*
|
389 |
+
* @param int $id The post to check for syndicated status. Defaults to the current post in a Loop context.
|
390 |
+
* @return bool TRUE if the post's meta-data indicates it was syndicated; FALSE otherwise
|
391 |
+
*/
|
392 |
+
function is_syndicated ($id = NULL) {
|
393 |
+
return (strlen(get_syndication_feed_id($id)) > 0);
|
394 |
+
} /* function is_syndicated() */
|
395 |
|
396 |
function get_syndication_source_link ($original = NULL, $id = NULL) {
|
397 |
if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
|
423 |
$url = (isset($bits['user'])?$bits['user'].'@':'')
|
424 |
.(isset($bits['host'])?$bits['host']:'')
|
425 |
.(isset($bits['path'])?$bits['path']:'')
|
426 |
+
.(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
|
427 |
.(isset($bits['query'])?'?'.$bits['query']:'');
|
428 |
|
429 |
if (strlen($url) > ($before+$after)) :
|
504 |
function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
|
505 |
|
506 |
$feedwordpress_linkcache = array (); // only load links from database once
|
507 |
+
function get_syndication_feed_object ($id = NULL) {
|
508 |
+
global $feedwordpress_linkcache;
|
509 |
|
510 |
+
$link = NULL;
|
|
|
|
|
511 |
|
512 |
+
$feed_id = get_syndication_feed_id($id);
|
513 |
if (strlen($feed_id) > 0):
|
514 |
if (isset($feedwordpress_linkcache[$feed_id])) :
|
515 |
$link = $feedwordpress_linkcache[$feed_id];
|
516 |
else :
|
517 |
+
$link = new SyndicatedLink($feed_id);
|
518 |
$feedwordpress_linkcache[$feed_id] = $link;
|
519 |
endif;
|
520 |
+
endif;
|
521 |
+
return $link;
|
522 |
+
}
|
523 |
+
|
524 |
+
function get_feed_meta ($key, $id = NULL) {
|
525 |
+
$ret = NULL;
|
526 |
|
527 |
+
$link = get_syndication_feed_object($id);
|
528 |
+
if (is_object($link) and isset($link->settings[$key])) :
|
529 |
$ret = $link->settings[$key];
|
530 |
endif;
|
531 |
return $ret;
|
538 |
echo get_syndication_permalink($id);
|
539 |
}
|
540 |
|
541 |
+
/**
|
542 |
+
* get_local_permalink: returns a string containing the internal permalink
|
543 |
+
* for a post (whether syndicated or not) on your local WordPress installation.
|
544 |
+
* This may be useful if you want permalinks to point to the original source of
|
545 |
+
* an article for most purposes, but want to retrieve a URL for the local
|
546 |
+
* representation of the post for one or two limited purposes (for example,
|
547 |
+
* linking to a comments page on your local aggregator site).
|
548 |
+
*
|
549 |
+
* @param $id The numerical ID of the post to get the permalink for. If empty,
|
550 |
+
* defaults to the current post in a Loop context.
|
551 |
+
* @return string The URL of the local permalink for this post.
|
552 |
+
*
|
553 |
+
* @uses get_permalink()
|
554 |
+
* @global $feedwordpress_the_original_permalink
|
555 |
+
*
|
556 |
+
* @since 2010.0217
|
557 |
+
*/
|
558 |
+
function get_local_permalink ($id = NULL) {
|
559 |
+
global $feedwordpress_the_original_permalink;
|
560 |
+
|
561 |
+
// get permalink, and thus activate filter and force global to be filled
|
562 |
+
// with original URL.
|
563 |
+
$url = get_permalink($id);
|
564 |
+
return $feedwordpress_the_original_permalink;
|
565 |
+
} /* get_local_permalink() */
|
566 |
+
|
567 |
+
/**
|
568 |
+
* the_original_permalink: displays the contents of get_original_permalink()
|
569 |
+
*
|
570 |
+
* @param $id The numerical ID of the post to get the permalink for. If empty,
|
571 |
+
* defaults to the current post in a Loop context.
|
572 |
+
*
|
573 |
+
* @uses get_local_permalinks()
|
574 |
+
* @uses apply_filters
|
575 |
+
*
|
576 |
+
* @since 2010.0217
|
577 |
+
*/
|
578 |
+
function the_local_permalink ($id = NULL) {
|
579 |
+
print apply_filters('the_permalink', get_local_permalink($id));
|
580 |
+
} /* function the_local_permalink() */
|
581 |
+
|
582 |
################################################################################
|
583 |
## FILTERS: syndication-aware handling of post data for templates and feeds ####
|
584 |
################################################################################
|
585 |
|
586 |
$feedwordpress_the_syndicated_content = NULL;
|
587 |
+
$feedwordpress_the_original_permalink = NULL;
|
588 |
|
589 |
function feedwordpress_preserve_syndicated_content ($text) {
|
590 |
global $feedwordpress_the_syndicated_content;
|
637 |
endif;
|
638 |
}
|
639 |
|
640 |
+
/**
|
641 |
+
* syndication_permalink: Allow WordPress to use the original remote URL of
|
642 |
+
* syndicated posts as their permalink. Can be turned on or off by by setting in
|
643 |
+
* Syndication => Posts & Links. Saves the old internal permalink in a global
|
644 |
+
* variable for later use.
|
645 |
+
*
|
646 |
+
* @param string $permalink The internal permalink
|
647 |
+
* @return string The new permalink. Same as the old if the post is not
|
648 |
+
* syndicated, or if FWP is set to use internal permalinks, or if the post
|
649 |
+
* was syndicated, but didn't have a proper permalink recorded.
|
650 |
+
*
|
651 |
+
* @uses FeedWordPress::munge_permalinks()
|
652 |
+
* @uses get_syndication_permalink()
|
653 |
+
* @global $feedwordpress_the_original_permalink
|
654 |
+
*/
|
655 |
function syndication_permalink ($permalink = '') {
|
656 |
+
global $feedwordpress_the_original_permalink;
|
657 |
+
|
658 |
+
// Save the local permalink in case we need to retrieve it later.
|
659 |
+
$feedwordpress_the_original_permalink = $permalink;
|
660 |
+
|
661 |
+
// Map this permalink to a post ID so we can get the correct permalink
|
662 |
+
// even outside of the Post Loop. Props Björn.
|
663 |
+
$id = url_to_postid($permalink);
|
664 |
+
|
665 |
+
$munge = false;
|
666 |
+
$link = get_syndication_feed_object($id);
|
667 |
+
if (is_object($link)) :
|
668 |
+
$munge = ($link->setting('munge permalink', 'munge_permalink', 'yes') != 'no');
|
669 |
endif;
|
670 |
+
|
671 |
+
if ($munge):
|
672 |
+
$uri = get_syndication_permalink($id);
|
673 |
+
$permalink = ((strlen($uri) > 0) ? $uri : $permalink);
|
674 |
+
endif;
|
675 |
+
return $permalink;
|
676 |
+
} /* function syndication_permalink () */
|
677 |
+
|
678 |
+
/**
|
679 |
+
* syndication_permalink_escaped: Escape XML special characters in syndicated
|
680 |
+
* permalinks when used in feed contexts and HTML display contexts.
|
681 |
+
*
|
682 |
+
* @param string $permalink
|
683 |
+
* @return string
|
684 |
+
*
|
685 |
+
* @uses is_syndicated()
|
686 |
+
* @uses FeedWordPress::munge_permalinks()
|
687 |
+
*
|
688 |
+
*/
|
689 |
+
function syndication_permalink_escaped ($permalink) {
|
690 |
+
if (is_syndicated() and FeedWordPress::munge_permalinks()) :
|
691 |
+
// This is a foreign link; WordPress can't vouch for its not
|
692 |
+
// having any entities that need to be &-escaped. So we'll do
|
693 |
+
// it here.
|
694 |
+
$permalink = esc_html($permalink);
|
695 |
+
endif;
|
696 |
+
return $permalink;
|
697 |
+
} /* function syndication_permalink_escaped() */
|
698 |
+
|
699 |
+
/**
|
700 |
+
* syndication_comments_feed_link: Escape XML special characters in comments
|
701 |
+
* feed links
|
702 |
+
*
|
703 |
+
* @param string $link
|
704 |
+
* @return string
|
705 |
+
*
|
706 |
+
* @uses is_syndicated()
|
707 |
+
* @uses FeedWordPress::munge_permalinks()
|
708 |
+
*/
|
709 |
+
function syndication_comments_feed_link ($link) {
|
710 |
+
global $feedwordpress_the_original_permalink, $id;
|
711 |
+
|
712 |
+
if (is_syndicated() and FeedWordPress::munge_permalinks()) :
|
713 |
+
// If the source post provided a comment feed URL using
|
714 |
+
// wfw:commentRss or atom:link/@rel="replies" we can make use of
|
715 |
+
// that value here.
|
716 |
+
$source = get_syndication_feed_object();
|
717 |
+
$replacement = NULL;
|
718 |
+
if ($source->setting('munge comments feed links', 'munge_comments_feed_links', 'yes') != 'no') :
|
719 |
+
$commentFeeds = get_post_custom_values('wfw:commentRSS');
|
720 |
+
if (
|
721 |
+
is_array($commentFeeds)
|
722 |
+
and (count($commentFeeds) > 0)
|
723 |
+
and (strlen($commentFeeds[0]) > 0)
|
724 |
+
) :
|
725 |
+
$replacement = $commentFeeds[0];
|
726 |
+
|
727 |
+
// This is a foreign link; WordPress can't vouch for its not
|
728 |
+
// having any entities that need to be &-escaped. So we'll do it
|
729 |
+
// here.
|
730 |
+
$replacement = esc_html($replacement);
|
731 |
+
endif;
|
732 |
+
endif;
|
733 |
+
|
734 |
+
if (is_null($replacement)) :
|
735 |
+
// Q: How can we get the proper feed format, since the
|
736 |
+
// format is, stupidly, not passed to the filter?
|
737 |
+
// A: Kludge kludge kludge kludge!
|
738 |
+
$fancy_permalinks = ('' != get_option('permalink_structure'));
|
739 |
+
if ($fancy_permalinks) :
|
740 |
+
preg_match('|/feed(/([^/]+))?/?$|', $link, $ref);
|
741 |
+
|
742 |
+
$format = (isset($ref[2]) ? $ref[2] : '');
|
743 |
+
if (strlen($format) == 0) : $format = get_default_feed(); endif;
|
744 |
+
|
745 |
+
$replacement = trailingslashit($feedwordpress_the_original_permalink) . 'feed';
|
746 |
+
if ($format != get_default_feed()) :
|
747 |
+
$replacement .= '/'.$format;
|
748 |
+
endif;
|
749 |
+
$replacement = user_trailingslashit($replacement, 'single_feed');
|
750 |
+
else :
|
751 |
+
// No fancy permalinks = no problem
|
752 |
+
// WordPress doesn't call get_permalink() to
|
753 |
+
// generate the comment feed URL, so the
|
754 |
+
// comments feed link is never munged by FWP.
|
755 |
+
endif;
|
756 |
+
endif;
|
757 |
+
|
758 |
+
if (!is_null($replacement)) : $link = $replacement; endif;
|
759 |
+
endif;
|
760 |
+
return $link;
|
761 |
+
} /* function syndication_comments_feed_link() */
|
762 |
|
763 |
################################################################################
|
764 |
## ADMIN MENU ADD-ONS: register Dashboard management pages #####################
|
804 |
endif;
|
805 |
} /* function fwp_check_debug () */
|
806 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
807 |
################################################################################
|
808 |
## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
|
809 |
## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
|
874 |
if (is_syndicated($post->ID)) :
|
875 |
?>
|
876 |
<p>This is a syndicated post, which originally appeared at
|
877 |
+
<cite><?php print esc_html(get_syndication_source(NULL, $post->ID)); ?></cite>.
|
878 |
+
<a href="<?php print esc_html(get_syndication_permalink($post->ID)); ?>">View original post</a>.</p>
|
879 |
|
880 |
<p><input type="hidden" name="feedwordpress_noncename" id="feedwordpress_noncename" value="<?php print wp_create_nonce(plugin_basename(__FILE__)); ?>" />
|
881 |
<label><input type="checkbox" name="freeze_updates" value="yes" <?php if ($frozen_post) : ?>checked="checked"<?php endif; ?> /> <strong>Manual editing.</strong>
|
963 |
$this->feeds = array ();
|
964 |
$links = FeedWordPress::syndicated_links();
|
965 |
if ($links): foreach ($links as $link):
|
966 |
+
$this->feeds[] = new SyndicatedLink($link);
|
967 |
endforeach; endif;
|
968 |
} // FeedWordPress::FeedWordPress ()
|
969 |
|
1069 |
$added = $feed->poll($crash_ts);
|
1070 |
do_action('feedwordpress_check_feed_complete', $feed->settings, $added, time() - $start_ts);
|
1071 |
|
1072 |
+
if (is_array($added)) : // Success
|
1073 |
+
if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
|
1074 |
+
if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
|
1075 |
+
endif;
|
1076 |
endif;
|
1077 |
endforeach;
|
1078 |
|
1228 |
return apply_filters('syndicated_post_use_aggregator_source_data', ($ret=='yes'));
|
1229 |
}
|
1230 |
|
1231 |
+
/**
|
1232 |
+
* FeedWordPress::munge_permalinks: check whether or not FeedWordPress
|
1233 |
+
* should rewrite permalinks for syndicated items to reflect their
|
1234 |
+
* original location.
|
1235 |
+
*
|
1236 |
+
* @return bool TRUE if FeedWordPress SHOULD rewrite permalinks; FALSE otherwise
|
1237 |
+
*/
|
1238 |
+
/*static*/ function munge_permalinks () {
|
1239 |
+
return (get_option('feedwordpress_munge_permalink', /*default=*/ 'yes') != 'no');
|
1240 |
+
} /* FeedWordPress::munge_permalinks() */
|
1241 |
+
|
1242 |
function syndicated_links () {
|
1243 |
$contributors = FeedWordPress::link_category_id();
|
1244 |
if (function_exists('get_bookmarks')) :
|
1324 |
if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
|
1325 |
|
1326 |
switch ($from) :
|
1327 |
+
case 0.96:
|
1328 |
+
// Dropping legacy upgrade code. If anyone is still
|
1329 |
+
// using 0.96 and just now decided to upgrade, well, I'm
|
1330 |
+
// sorry about that. You'll just have to cope with a few
|
1331 |
+
// duplicate posts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1332 |
|
1333 |
// Mark the upgrade as successful.
|
1334 |
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1336 |
echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
|
1337 |
} /* FeedWordPress::upgrade_database() */
|
1338 |
|
1339 |
+
function has_guid_index () {
|
1340 |
+
global $wpdb;
|
1341 |
+
|
1342 |
+
$found = false; // Guilty until proven innocent.
|
1343 |
+
|
1344 |
+
$results = $wpdb->get_results("
|
1345 |
+
SHOW INDEXES FROM {$wpdb->posts}
|
1346 |
+
");
|
1347 |
+
if ($results) :
|
1348 |
+
foreach ($results as $index) :
|
1349 |
+
if (isset($index->Column_name)
|
1350 |
+
and ('guid' == $index->Column_name)) :
|
1351 |
+
$found = true;
|
1352 |
+
endif;
|
1353 |
+
endforeach;
|
1354 |
+
endif;
|
1355 |
+
return $found;
|
1356 |
+
} /* FeedWordPress::has_guid_index () */
|
1357 |
+
|
1358 |
function create_guid_index () {
|
1359 |
global $wpdb;
|
1360 |
|
1363 |
");
|
1364 |
} /* FeedWordPress::create_guid_index () */
|
1365 |
|
1366 |
+
function remove_guid_index () {
|
1367 |
+
global $wpdb;
|
1368 |
+
|
1369 |
+
$wpdb->query("
|
1370 |
+
DROP INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}
|
1371 |
+
");
|
1372 |
+
}
|
1373 |
+
|
1374 |
+
/*static*/ function fetch ($url) {
|
1375 |
+
require_once (ABSPATH . WPINC . '/class-feed.php');
|
1376 |
+
$feed = new SimplePie();
|
1377 |
+
$feed->set_feed_url($url);
|
1378 |
+
$feed->set_cache_class('WP_Feed_Cache');
|
1379 |
+
$feed->set_file_class('WP_SimplePie_File');
|
1380 |
+
$feed->set_cache_duration(FeedWordPress::cache_duration());
|
1381 |
+
$feed->init();
|
1382 |
+
$feed->handle_content_type();
|
1383 |
+
|
1384 |
+
if ($feed->error()) :
|
1385 |
+
$ret = new WP_Error('simplepie-error', $feed->error());
|
1386 |
+
else :
|
1387 |
+
$ret = $feed;
|
1388 |
+
endif;
|
1389 |
+
return $ret;
|
1390 |
+
} /* FeedWordPress::fetch () */
|
1391 |
+
|
1392 |
function clear_cache () {
|
1393 |
global $wpdb;
|
1394 |
|
1395 |
+
// The WordPress SimplePie module stores its cached feeds as
|
1396 |
+
// transient records in the options table. The data itself is
|
1397 |
+
// stored in `_transient_feed_{md5 of url}` and the last-modified
|
1398 |
+
// timestamp in `_transient_feed_mod_{md5 of url}`. Timeouts for
|
1399 |
+
// these records are stored in `_transient_timeout_feed_{md5}`.
|
1400 |
+
// Since the md5 is always 32 characters in length, the
|
1401 |
+
// option_name is always over 32 characters.
|
1402 |
$wpdb->query("
|
1403 |
DELETE FROM {$wpdb->options}
|
1404 |
+
WHERE option_name LIKE '_transient%_feed_%' AND LENGTH(option_name) > 32
|
1405 |
");
|
1406 |
} /* FeedWordPress::clear_cache () */
|
1407 |
|
1408 |
+
function cache_duration () {
|
1409 |
+
$duration = NULL;
|
1410 |
+
if (defined('FEEDWORDPRESS_CACHE_AGE')) :
|
1411 |
+
$duration = FEEDWORDPRESS_CACHE_AGE;
|
1412 |
endif;
|
1413 |
+
return $duration;
|
1414 |
}
|
1415 |
+
function cache_lifetime ($duration) {
|
1416 |
+
// Check for explicit setting of a lifetime duration
|
1417 |
+
if (defined('FEEDWORDPRESS_CACHE_LIFETIME')) :
|
1418 |
+
$duration = FEEDWORDPRESS_CACHE_LIFETIME;
|
1419 |
+
|
1420 |
+
// Fall back to the cache freshness duration
|
1421 |
+
elseif (defined('FEEDWORDPRESS_CACHE_AGE')) :
|
1422 |
+
$duration = FEEDWORDPRESS_CACHE_AGE;
|
1423 |
+
endif;
|
1424 |
+
|
1425 |
+
// Fall back to WordPress default
|
1426 |
+
return $duration;
|
1427 |
+
} /* FeedWordPress::cache_lifetime () */
|
1428 |
|
1429 |
# Utility functions for handling text settings
|
1430 |
function negative ($f, $setting) {
|
1442 |
function critical_bug ($varname, $var, $line) {
|
1443 |
global $wp_version;
|
1444 |
|
|
|
|
|
|
|
|
|
1445 |
echo '<p>There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
|
1446 |
echo "\n<plaintext>";
|
1447 |
echo "Triggered at line # ".$line."\n";
|
1448 |
echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n";
|
|
|
1449 |
echo "WordPress version: {$wp_version}\n";
|
1450 |
echo "PHP version: ".phpversion()."\n";
|
1451 |
echo "\n";
|
1473 |
}
|
1474 |
|
1475 |
function feedwordpress_pong ($args) {
|
1476 |
+
$feedwordpress = new FeedWordPress;
|
1477 |
$delta = @$feedwordpress->update($args[1]);
|
1478 |
if (is_null($delta)):
|
1479 |
return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
|
1486 |
endif;
|
1487 |
}
|
1488 |
|
1489 |
+
require_once(dirname(__FILE__) . '/relative_uri.class.php');
|
|
|
|
|
|
|
|
|
1490 |
|
1491 |
// take your best guess at the realname and e-mail, given a string
|
1492 |
define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
|
magpiefromsimplepie.class.php
ADDED
@@ -0,0 +1,775 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
require_once(dirname(__FILE__).'/feedtime.class.php');
|
3 |
+
|
4 |
+
/**
|
5 |
+
* class MagpieFromSimplePie: compatibility layer to prevent existing filters
|
6 |
+
* from breaking.
|
7 |
+
*
|
8 |
+
* @since 2010.0203
|
9 |
+
*
|
10 |
+
*/
|
11 |
+
|
12 |
+
class MagpieFromSimplePie {
|
13 |
+
var $pie;
|
14 |
+
var $originals;
|
15 |
+
|
16 |
+
var $channel;
|
17 |
+
var $items;
|
18 |
+
var $textinput = array ();
|
19 |
+
var $image = array();
|
20 |
+
|
21 |
+
var $feed_type;
|
22 |
+
var $feed_version;
|
23 |
+
|
24 |
+
var $_XMLNS_FAMILIAR = array (
|
25 |
+
'http://www.w3.org/2005/Atom' => 'atom' /* 1.0 */,
|
26 |
+
'http://purl.org/atom/ns#' => 'atom' /* pre-1.0 */,
|
27 |
+
'http://purl.org/rss/1.0/' => 'rss' /* 1.0 */,
|
28 |
+
'http://backend.userland.com/RSS2' => 'rss' /* 2.0 */,
|
29 |
+
'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf',
|
30 |
+
'http://www.w3.org/1999/xhtml' => 'xhtml',
|
31 |
+
'http://purl.org/dc/elements/1.1/' => 'dc',
|
32 |
+
'http://purl.org/dc/terms/' => 'dcterms',
|
33 |
+
'http://purl.org/rss/1.0/modules/content/' => 'content',
|
34 |
+
'http://purl.org/rss/1.0/modules/syndication/' => 'sy',
|
35 |
+
'http://purl.org/rss/1.0/modules/taxonomy/' => 'taxo',
|
36 |
+
'http://purl.org/rss/1.0/modules/dc/' => 'dc',
|
37 |
+
'http://wellformedweb.org/CommentAPI/' => 'wfw',
|
38 |
+
'http://webns.net/mvcb/' => 'admin',
|
39 |
+
'http://purl.org/rss/1.0/modules/annotate/' => 'annotate',
|
40 |
+
'http://xmlns.com/foaf/0.1/' => 'foaf',
|
41 |
+
'http://madskills.com/public/xml/rss/module/trackback/' => 'trackback',
|
42 |
+
'http://web.resource.org/cc/' => 'cc',
|
43 |
+
'http://search.yahoo.com/mrss' => 'media',
|
44 |
+
'http://search.yahoo.com/mrss/' => 'media',
|
45 |
+
'http://video.search.yahoo.com/mrss' => 'media',
|
46 |
+
'http://video.search.yahoo.com/mrss/' => 'media',
|
47 |
+
'http://purl.org/syndication/thread/1.0' => 'thr',
|
48 |
+
'http://purl.org/syndication/thread/1.0/' => 'thr',
|
49 |
+
'http://www.w3.org/XML/1998/namespace' => 'xml',
|
50 |
+
'http://www.itunes.com/dtds/podcast-1.0.dtd' => 'itunes',
|
51 |
+
'http://a9.com/-/spec/opensearchrss/1.0/' => 'openSearch',
|
52 |
+
'http://purl.org/rss/1.0/modules/slash/' => 'slash',
|
53 |
+
);
|
54 |
+
|
55 |
+
/**
|
56 |
+
* MagpieFromSimplePie constructor
|
57 |
+
*
|
58 |
+
* @param SimplePie $pie The feed to convert to MagpieRSS format.
|
59 |
+
*
|
60 |
+
* @uses MagpieFromSimplePie::processItemData
|
61 |
+
* @uses MagpieFromSimplePie::normalize
|
62 |
+
*/
|
63 |
+
function MagpieFromSimplePie ($pie) {
|
64 |
+
$this->pie = $pie;
|
65 |
+
$this->originals = $this->pie->get_items();
|
66 |
+
|
67 |
+
$this->channel = $this->processFeedData($this->pie->data);
|
68 |
+
foreach ($this->originals as $key => $item) :
|
69 |
+
$this->items[$key] = $this->processItemData($item->data);
|
70 |
+
endforeach;
|
71 |
+
|
72 |
+
$this->normalize();
|
73 |
+
|
74 |
+
// In case anyone goes poking around our private members (uh...)
|
75 |
+
$this->feed_type = ($this->is_atom() ? 'Atom' : 'RSS');
|
76 |
+
$this->feed_version = $this->feed_version();
|
77 |
+
} /* MagpieFromSimplePie constructor */
|
78 |
+
|
79 |
+
/**
|
80 |
+
* MagpieFromSimplePie::get_item: returns a MagpieRSS format array
|
81 |
+
* which is equivalent to the SimplePie_Item object from which this
|
82 |
+
* object was constructed.
|
83 |
+
*
|
84 |
+
* @return array A MagpieRSS format array representing this feed item.
|
85 |
+
*/
|
86 |
+
function get_items () {
|
87 |
+
return $this->items;
|
88 |
+
} /* MagpieFromSimplePie::get_item */
|
89 |
+
|
90 |
+
/**
|
91 |
+
* MagpieFromSimplePie::processFeedData
|
92 |
+
*
|
93 |
+
* @param array $data
|
94 |
+
* @return array
|
95 |
+
*
|
96 |
+
* @uses MagpieFromSimplePie::processChannelData()
|
97 |
+
*/
|
98 |
+
function processFeedData ($data) {
|
99 |
+
$ret = array();
|
100 |
+
if (isset($data['child'])) : foreach ($data['child'] as $ns => $elements) :
|
101 |
+
foreach ($elements as $name => $multi) :
|
102 |
+
foreach ($multi as $element) :
|
103 |
+
if ($name=='feed' or $name=='channel') :
|
104 |
+
// Don't need to process these
|
105 |
+
foreach (array(
|
106 |
+
'',
|
107 |
+
'http://www.w3.org/2005/Atom',
|
108 |
+
'http://purl.org/rss/1.0/',
|
109 |
+
'http://backend.userland.com/RSS2'
|
110 |
+
) as $ns) :
|
111 |
+
if (isset($element['child'][$ns]['entry'])) : unset($element['child'][$ns]['entry']); endif;
|
112 |
+
if (isset($element['child'][$ns]['item'])) : unset($element['child'][$ns]['item']); endif;
|
113 |
+
endforeach;
|
114 |
+
|
115 |
+
$ret = $this->processChannelData($element) + $ret;
|
116 |
+
elseif (in_array(strtolower($name), array('rss', 'rdf'))) :
|
117 |
+
// Drop down to get to <channel> element
|
118 |
+
$ret = $this->processFeedData($element) + $ret;
|
119 |
+
endif;
|
120 |
+
endforeach;
|
121 |
+
endforeach;
|
122 |
+
endforeach; endif;
|
123 |
+
return $ret;
|
124 |
+
} /* MagpieFromSimplePie::processFeedData() */
|
125 |
+
|
126 |
+
/**
|
127 |
+
* MagpieFromSimplePie::processChannelData
|
128 |
+
*
|
129 |
+
* @param array $data
|
130 |
+
* @param array $path
|
131 |
+
* @return array
|
132 |
+
*
|
133 |
+
* @uses MagpieFromSimplePie::handleAttributes
|
134 |
+
* @uses MagpieFromSimplePie::handleChildren
|
135 |
+
*/
|
136 |
+
function processChannelData ($data, $path = array()) {
|
137 |
+
$ret = array();
|
138 |
+
$tagPath = strtolower(implode('_', $path));
|
139 |
+
|
140 |
+
// Only process at the right level
|
141 |
+
if (strlen($tagPath) > 0
|
142 |
+
and isset($data['data'])
|
143 |
+
and strlen($data['data']) > 0) :
|
144 |
+
$ret[$tagPath] = $data['data'];
|
145 |
+
endif;
|
146 |
+
|
147 |
+
$ret = $this->handleAttributes($data, $path)
|
148 |
+
+ $this->handleChildren($data, $path, 'processChannelData')
|
149 |
+
+ $ret;
|
150 |
+
|
151 |
+
return $ret;
|
152 |
+
} /* MagpieFromSimplePie::processChannelData() */
|
153 |
+
|
154 |
+
/**
|
155 |
+
* MagpieFromSimplePie::processItemData
|
156 |
+
*
|
157 |
+
* @param array $data
|
158 |
+
* @param array $path
|
159 |
+
* @return array
|
160 |
+
*
|
161 |
+
* @uses MagpieFromSimplePie::handleAttributes
|
162 |
+
* @uses MagpieFromSimplePie::handleChildren
|
163 |
+
*/
|
164 |
+
function processItemData ($data, $path = array()) {
|
165 |
+
$ret = array();
|
166 |
+
$tagPath = strtolower(implode('_', $path));
|
167 |
+
|
168 |
+
if (strlen($tagPath) > 0 and isset($data['data']) and strlen($data['data']) > 0) :
|
169 |
+
$ret[$tagPath] = $data['data'];
|
170 |
+
endif;
|
171 |
+
|
172 |
+
// Set up xml:base to be recorded in array
|
173 |
+
if (isset($data['xml_base_explicit']) and $data['xml_base_explicit']) :
|
174 |
+
$data['attribs']['']['xml:base'] = $data['xml_base'];
|
175 |
+
endif;
|
176 |
+
|
177 |
+
$ret = $this->handleAttributes($data, $path)
|
178 |
+
+ $this->handleChildren($data, $path, 'processItemData')
|
179 |
+
+ $ret;
|
180 |
+
|
181 |
+
return $ret;
|
182 |
+
} /* MagpieFromSimplePie::processItemData() */
|
183 |
+
|
184 |
+
/**
|
185 |
+
* MagpieFromSimplePie::handleAttributes
|
186 |
+
*
|
187 |
+
* @param array $data
|
188 |
+
* @param array $path
|
189 |
+
* @return array
|
190 |
+
*/
|
191 |
+
function handleAttributes ($data, $path) {
|
192 |
+
$tagPath = strtolower(implode('_', $path));
|
193 |
+
$ret = array();
|
194 |
+
if (isset($data['attribs'])) : foreach ($data['attribs'] as $ns => $pairs) :
|
195 |
+
if (isset($this->_XMLNS_FAMILIAR[$ns])) :
|
196 |
+
$ns = $this->_XMLNS_FAMILIAR[$ns];
|
197 |
+
endif;
|
198 |
+
|
199 |
+
foreach ($pairs as $attr => $value) :
|
200 |
+
$attr = strtolower($attr);
|
201 |
+
if ($ns=='rdf' and $attr=='about') :
|
202 |
+
$ret['about'] = $value;
|
203 |
+
elseif (strlen($tagPath) > 0) :
|
204 |
+
if (strlen($ns) > 0 and $this->is_namespaced($ns, /*attrib=*/ true)) :
|
205 |
+
$attr = $ns.':'.$attr;
|
206 |
+
endif;
|
207 |
+
|
208 |
+
$ret[$tagPath.'@'.$attr] = $value;
|
209 |
+
if (isset($ret[$tagPath.'@']) and strlen($ret[$tagPath.'@'])>0) :
|
210 |
+
$ret[$tagPath.'@'] .= ',';
|
211 |
+
else :
|
212 |
+
$ret[$tagPath.'@'] = '';
|
213 |
+
endif;
|
214 |
+
$ret[$tagPath.'@'] .= $attr;
|
215 |
+
endif;
|
216 |
+
endforeach;
|
217 |
+
endforeach; endif;
|
218 |
+
return $ret;
|
219 |
+
} /* MagpieFromSimplePie::handleAttributes() */
|
220 |
+
|
221 |
+
var $inImage = false;
|
222 |
+
var $inTextInput = false;
|
223 |
+
|
224 |
+
/**
|
225 |
+
* MagpieFromSimplePie::handleChildren
|
226 |
+
*
|
227 |
+
* @param array $data
|
228 |
+
* @param array $path
|
229 |
+
* @return array
|
230 |
+
*
|
231 |
+
* @uses MagpieFromSimplePie::get_attrib
|
232 |
+
* @uses MagpieFromSimplePie::is_atom
|
233 |
+
* @uses MagpieFromSimplePie::increment_element
|
234 |
+
* @uses MagpieFromSimplePie::processItemData
|
235 |
+
*/
|
236 |
+
function handleChildren ($data, $path = array(), $method = 'processItemData') {
|
237 |
+
$tagPath = strtolower(implode('_', $path));
|
238 |
+
$ret = array();
|
239 |
+
if (isset($data['child'])) : foreach ($data['child'] as $ns => $elements) :
|
240 |
+
if (isset($this->_XMLNS_FAMILIAR[$ns])) :
|
241 |
+
$ns = $this->_XMLNS_FAMILIAR[$ns];
|
242 |
+
endif;
|
243 |
+
if (''==$ns) :
|
244 |
+
$ns = ($this->is_atom() ? 'atom' : 'rss');
|
245 |
+
endif;
|
246 |
+
|
247 |
+
foreach ($elements as $tag => $multi) : foreach ($multi as $element) :
|
248 |
+
$copyOver = NULL;
|
249 |
+
|
250 |
+
if ('image'==$tag and 'rss'==$ns) :
|
251 |
+
$this->inImage = true;
|
252 |
+
$childPath = array();
|
253 |
+
$co = NULL;
|
254 |
+
elseif ('textinput'==strtolower($tag) and 'rss'==$ns) :
|
255 |
+
$this->inTextInput = true;
|
256 |
+
$childPath = array();
|
257 |
+
$co = NULL;
|
258 |
+
else :
|
259 |
+
// Determine tag name; check #; increment #
|
260 |
+
$childTag = strtolower($tag);
|
261 |
+
if ('link'==$tag and 'atom'==$ns) :
|
262 |
+
$rel = $this->get_attrib(
|
263 |
+
/*ns=*/ array('', 'http://www.w3.org/2005/Atom'),
|
264 |
+
/*attr=*/ 'rel',
|
265 |
+
$element
|
266 |
+
);
|
267 |
+
if ($rel != 'alternate') :
|
268 |
+
$childTag .= '_'.$rel;
|
269 |
+
endif;
|
270 |
+
$copyOver = $this->get_attrib(
|
271 |
+
/*ns=*/ array('', 'http://www.w3.org/2005/Atom'),
|
272 |
+
/*attr=*/ 'href',
|
273 |
+
$element
|
274 |
+
);
|
275 |
+
elseif ('content'==$tag and 'atom'==$ns) :
|
276 |
+
$childTag = 'atom_'.$tag;
|
277 |
+
endif;
|
278 |
+
|
279 |
+
$childTag = $this->increment_element($ret, $childTag, $ns, $path);
|
280 |
+
$childPath = $path; $childPath[] = strtolower($childTag);
|
281 |
+
|
282 |
+
if (!is_null($copyOver)) :
|
283 |
+
$co = array();
|
284 |
+
$co[implode('_', $childPath)] = $copyOver;
|
285 |
+
else :
|
286 |
+
$co = NULL;
|
287 |
+
endif;
|
288 |
+
endif;
|
289 |
+
|
290 |
+
$arr = $this->{$method}($element, $childPath);
|
291 |
+
if ($co) :
|
292 |
+
$arr = $co + $arr; // Left-hand overwrites right-hand
|
293 |
+
endif;
|
294 |
+
|
295 |
+
if ($this->inImage) :
|
296 |
+
$this->image = $arr + $this->image;
|
297 |
+
|
298 |
+
// Close tag
|
299 |
+
if ('image'==$tag and 'rss'==$ns) : $this->inImage = false; endif;
|
300 |
+
elseif ($this->inTextInput) :
|
301 |
+
$this->textinput = $arr + $this->textinput;
|
302 |
+
|
303 |
+
// Close tag
|
304 |
+
if ('textinput'==$tag and 'rss'==$ns) : $this->inTextInput = false; endif;
|
305 |
+
elseif ($this->is_namespaced($ns)) :
|
306 |
+
if (!isset($ret[$ns])) : $ret[$ns] = array(); endif;
|
307 |
+
$ret[$ns] = $arr + $ret[$ns];
|
308 |
+
else :
|
309 |
+
$ret = $arr + $ret;
|
310 |
+
endif;
|
311 |
+
endforeach; endforeach;
|
312 |
+
|
313 |
+
endforeach; endif;
|
314 |
+
return $ret;
|
315 |
+
} /* MagpieFromSimplePie::handleChildren() */
|
316 |
+
|
317 |
+
/**
|
318 |
+
* MagpieFromSimplePie::get_attrib
|
319 |
+
*
|
320 |
+
* @param array $namespaces
|
321 |
+
* @param string $attr
|
322 |
+
* @param array $element
|
323 |
+
* @param mixed $default
|
324 |
+
*/
|
325 |
+
function get_attrib ($namespaces, $attr, $element, $default = NULL) {
|
326 |
+
$ret = $default;
|
327 |
+
if (isset($element['attribs'])) :
|
328 |
+
foreach ($namespaces as $ns) :
|
329 |
+
if (isset($element['attribs'][$ns])
|
330 |
+
and isset($element['attribs'][$ns][$attr])) :
|
331 |
+
$ret = $element['attribs'][$ns][$attr];
|
332 |
+
break;
|
333 |
+
endif;
|
334 |
+
endforeach;
|
335 |
+
endif;
|
336 |
+
return $ret;
|
337 |
+
} /* MagpieFromSimplePie::get_attrib */
|
338 |
+
|
339 |
+
/**
|
340 |
+
* MagpieFromSimplePie::normalize
|
341 |
+
*
|
342 |
+
* @uses MagpieFromSimplePie::is_atom
|
343 |
+
* @uses MagpieFromSimplePie::is_rss
|
344 |
+
* @uses MagpieFromSimplePie::normalize_element
|
345 |
+
* @uses MagpieFromSimplePie::normalize_author_inheritance
|
346 |
+
* @uses MagpieFromSimplePie::normalize_atom_person
|
347 |
+
* @uses MagpieFromSimplePie::normalize_enclosure
|
348 |
+
* @uses MagpieFromSimplePie::normalize_category
|
349 |
+
* @uses MagpieFromSimplePie::normalize_dc_subject
|
350 |
+
* @uses FeedTime
|
351 |
+
* @uses FeedTime::timestamp
|
352 |
+
*/
|
353 |
+
function normalize () {
|
354 |
+
// Normalize channel data
|
355 |
+
if ( $this->is_atom() ) :
|
356 |
+
// Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!)
|
357 |
+
if ($this->feed_version() < 1.0) :
|
358 |
+
$this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle');
|
359 |
+
$this->normalize_element($this->channel, 'copyright', $this->channel, 'rights');
|
360 |
+
$this->normalize_element($this->channel, 'modified', $this->channel, 'updated');
|
361 |
+
else :
|
362 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline');
|
363 |
+
$this->normalize_element($this->channel, 'rights', $this->channel, 'copyright');
|
364 |
+
$this->normalize_element($this->channel, 'updated', $this->channel, 'modified');
|
365 |
+
endif;
|
366 |
+
$this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person');
|
367 |
+
$this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person');
|
368 |
+
|
369 |
+
// Atom elements to RSS elements
|
370 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'description');
|
371 |
+
|
372 |
+
if ( isset($this->channel['logo']) ) :
|
373 |
+
$this->normalize_element($this->channel, 'logo', $this->image, 'url');
|
374 |
+
$this->normalize_element($this->channel, 'link', $this->image, 'link');
|
375 |
+
$this->normalize_element($this->channel, 'title', $this->image, 'title');
|
376 |
+
endif;
|
377 |
+
|
378 |
+
elseif ( $this->is_rss() ) :
|
379 |
+
// Normalize image element from where stupid MagpieRSS puts it
|
380 |
+
//$this->normalize_element($this->channel, 'image_title', $this->image, 'title');
|
381 |
+
//$this->normalize_element($this->channel, 'image_link', $this->image, 'link');
|
382 |
+
//$this->normalize_element($this->channel, 'image_url', $this->image, 'url');
|
383 |
+
|
384 |
+
// ... and, gag, textInput
|
385 |
+
//$this->normalize_element($this->channel, 'textinput_title', $this->textinput, 'title');
|
386 |
+
//$this->normalize_element($this->channel, 'textinput_link', $this->textinput, 'link');
|
387 |
+
//$this->normalize_element($this->channel, 'textinput_name', $this->textinput, 'name');
|
388 |
+
//$this->normalize_element($this->channel, 'textinput_description', $this->textinput, 'description');
|
389 |
+
|
390 |
+
// RSS elements to Atom elements
|
391 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3
|
392 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!)
|
393 |
+
$this->normalize_element($this->image, 'url', $this->channel, 'logo');
|
394 |
+
endif;
|
395 |
+
|
396 |
+
// Now loop through and normalize item data
|
397 |
+
for ( $i = 0; $i < count($this->items); $i++) :
|
398 |
+
$item = $this->items[$i];
|
399 |
+
|
400 |
+
// if atom populate rss fields and normalize 0.3 and 1.0 feeds
|
401 |
+
if ( $this->is_atom() ) :
|
402 |
+
// Atom 1.0 elements <=> Atom 0.3 elements
|
403 |
+
if ($this->feed_version() < 1.0) :
|
404 |
+
$this->normalize_element($item, 'modified', $item, 'updated');
|
405 |
+
$this->normalize_element($item, 'issued', $item, 'published');
|
406 |
+
else :
|
407 |
+
$this->normalize_element($item, 'updated', $item, 'modified');
|
408 |
+
$this->normalize_element($item, 'published', $item, 'issued');
|
409 |
+
endif;
|
410 |
+
|
411 |
+
$this->normalize_author_inheritance($item, $this->originals[$i]);
|
412 |
+
|
413 |
+
// Atom elements to RSS elements
|
414 |
+
$this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person');
|
415 |
+
$this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person');
|
416 |
+
$this->normalize_element($item, 'summary', $item, 'description');
|
417 |
+
$this->normalize_element($item, 'atom_content', $item['content'], 'encoded');
|
418 |
+
$this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure');
|
419 |
+
|
420 |
+
// Categories
|
421 |
+
if ( isset($item['category#']) ) : // Atom 1.0 categories to dc:subject and RSS 2.0 categories
|
422 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
423 |
+
elseif ( isset($item['dc']['subject#']) ) : // dc:subject to Atom 1.0 and RSS 2.0 categories
|
424 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
425 |
+
endif;
|
426 |
+
|
427 |
+
// Normalized item timestamp
|
428 |
+
$item_date = (isset($item['published']) ) ? $item['published'] : $item['updated'];
|
429 |
+
elseif ( $this->is_rss() ) :
|
430 |
+
// RSS elements to Atom elements
|
431 |
+
$this->normalize_element($item, 'description', $item, 'summary');
|
432 |
+
$this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure');
|
433 |
+
|
434 |
+
// Categories
|
435 |
+
if ( isset($item['category#']) ) : // RSS 2.0 categories to dc:subject and Atom 1.0 categories
|
436 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
437 |
+
elseif ( isset($item['dc']['subject#']) ) : // dc:subject to Atom 1.0 and RSS 2.0 categories
|
438 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
439 |
+
endif;
|
440 |
+
|
441 |
+
// Normalized item timestamp
|
442 |
+
if (isset($item['pubdate'])) :
|
443 |
+
$item_date = $item['pubdate'];
|
444 |
+
elseif (isset($item['dc']['date'])) :
|
445 |
+
$item_date = $item['dc']['date'];
|
446 |
+
else :
|
447 |
+
$item_date = null;
|
448 |
+
endif;
|
449 |
+
endif;
|
450 |
+
|
451 |
+
if ( $item_date ) :
|
452 |
+
$date_timestamp = new FeedTime($item_date);
|
453 |
+
|
454 |
+
if (!$date_timestamp->failed()) :
|
455 |
+
$item['date_timestamp'] = $date_timestamp->timestamp();
|
456 |
+
endif;
|
457 |
+
endif;
|
458 |
+
|
459 |
+
$this->items[$i] = $item;
|
460 |
+
endfor;
|
461 |
+
} /* MagpieFromSimplePie::normalize() */
|
462 |
+
|
463 |
+
/**
|
464 |
+
* MagpieFromSimplePie::normalize_author_inheritance
|
465 |
+
*
|
466 |
+
* @param SimplePie_Item $original
|
467 |
+
*
|
468 |
+
* @uses SimplePie_Item::get_authors
|
469 |
+
* @uses SimplePie_Author::get_name
|
470 |
+
* @uses SimplePie_Author::get_link
|
471 |
+
* @uses SimplePie_Author::get_email
|
472 |
+
* @uses MagpieFromSimplePie::increment_element
|
473 |
+
*/
|
474 |
+
function normalize_author_inheritance (&$item, $original) {
|
475 |
+
// "If an atom:entry element does not contain
|
476 |
+
// atom:author elements, then the atom:author elements
|
477 |
+
// of the contained atom:source element are considered
|
478 |
+
// to apply. In an Atom Feed Document, the atom:author
|
479 |
+
// elements of the containing atom:feed element are
|
480 |
+
// considered to apply to the entry if there are no
|
481 |
+
// atom:author elements in the locations described
|
482 |
+
// above." <http://atompub.org/2005/08/17/draft-ietf-atompub-format-11.html#rfc.section.4.2.1>
|
483 |
+
if (!isset($item["author#"])) :
|
484 |
+
$authors = $original->get_authors();
|
485 |
+
foreach ($authors as $author) :
|
486 |
+
$tag = $this->increment_element($item, 'author', 'atom', array());
|
487 |
+
$item[$tag] = $item["{$tag}_name"] = $author->get_name();
|
488 |
+
if ($author->get_link()) : $item["{$tag}_uri"] = $item["{$tag}_url"] = $author->get_link(); endif;
|
489 |
+
if ($author->get_email()) : $item["{$tag}_email"] = $author->get_email(); endif;
|
490 |
+
endforeach;
|
491 |
+
endif;
|
492 |
+
} /* MagpieFromSimplePie::normalize_author_inheritance() */
|
493 |
+
|
494 |
+
/**
|
495 |
+
* MagpieFromSimplePie::normalize_element
|
496 |
+
* Simplify the logic for normalize(). Makes sure that count of elements
|
497 |
+
* and each of multiple elements is normalized properly. If you need to
|
498 |
+
* mess with things like attributes or change formats or the like, pass
|
499 |
+
* it a callback to handle each element.
|
500 |
+
*
|
501 |
+
* @param array &$source
|
502 |
+
* @param string $from
|
503 |
+
* @param array &$dest
|
504 |
+
* @param string $to
|
505 |
+
* @param mixed $via
|
506 |
+
*/
|
507 |
+
function normalize_element (&$source, $from, &$dest, $to, $via = NULL) {
|
508 |
+
if (isset($source[$from]) or isset($source["{$from}#"])) :
|
509 |
+
if (isset($source["{$from}#"])) :
|
510 |
+
$n = $source["{$from}#"];
|
511 |
+
$dest["{$to}#"] = $source["{$from}#"];
|
512 |
+
else :
|
513 |
+
$n = 1;
|
514 |
+
endif;
|
515 |
+
|
516 |
+
for ($i = 1; $i <= $n; $i++) :
|
517 |
+
if (isset($via) and is_callable(array($this, $via))) : // custom callback for ninja attacks
|
518 |
+
$this->{$via}($source, $from, $dest, $to, $i);
|
519 |
+
else : // just make it the same
|
520 |
+
$from_id = $this->element_id($from, $i);
|
521 |
+
$to_id = $this->element_id($to, $i);
|
522 |
+
|
523 |
+
if (isset($source[$from_id])) : // Avoid PHP notice nastygrams
|
524 |
+
$dest[$to_id] = $source[$from_id];
|
525 |
+
endif;
|
526 |
+
endif;
|
527 |
+
endfor;
|
528 |
+
endif;
|
529 |
+
} /* MagpieFromSimplePie::normalize_element */
|
530 |
+
|
531 |
+
/**
|
532 |
+
* MagpieFromSimplePie::normalize_enclosure
|
533 |
+
*
|
534 |
+
* @param array &$source
|
535 |
+
* @param string $from
|
536 |
+
* @param array &$dest
|
537 |
+
* @param string $to
|
538 |
+
* @param int $i
|
539 |
+
*
|
540 |
+
* @uses MagpieFromSimplePie::element_id
|
541 |
+
*/
|
542 |
+
function normalize_enclosure (&$source, $from, &$dest, $to, $i) {
|
543 |
+
$id_from = $this->element_id($from, $i);
|
544 |
+
$id_to = $this->element_id($to, $i);
|
545 |
+
if (isset($source["{$id_from}@"])) :
|
546 |
+
foreach (explode(',', $source["{$id_from}@"]) as $attr) :
|
547 |
+
if ($from=='link_enclosure' and $attr=='href') : // from Atom
|
548 |
+
$dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"];
|
549 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
550 |
+
elseif ($from=='enclosure' and $attr=='url') : // from RSS
|
551 |
+
$dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"];
|
552 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
553 |
+
else :
|
554 |
+
$dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"];
|
555 |
+
endif;
|
556 |
+
endforeach;
|
557 |
+
endif;
|
558 |
+
} /* MagpieFromSimplePie::normalize_enclosure */
|
559 |
+
|
560 |
+
/**
|
561 |
+
* MagpieFromSimplePie::normalize_atom_person
|
562 |
+
*
|
563 |
+
* @param array &$source
|
564 |
+
* @param string $person
|
565 |
+
* @param array &$dest
|
566 |
+
* @param string $to
|
567 |
+
* @param int $i
|
568 |
+
*
|
569 |
+
*
|
570 |
+
* @uses MagpieFromSimplePie::element_id
|
571 |
+
*/
|
572 |
+
function normalize_atom_person (&$source, $person, &$dest, $to, $i) {
|
573 |
+
$id = $this->element_id($person, $i);
|
574 |
+
$id_to = $this->element_id($to, $i);
|
575 |
+
|
576 |
+
// Atom 0.3 <=> Atom 1.0
|
577 |
+
if ($this->feed_version() >= 1.0) :
|
578 |
+
$used = 'uri'; $norm = 'url';
|
579 |
+
else :
|
580 |
+
$used = 'url'; $norm = 'uri';
|
581 |
+
endif;
|
582 |
+
|
583 |
+
if (isset($source["{$id}_{$used}"])) :
|
584 |
+
$dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"];
|
585 |
+
endif;
|
586 |
+
|
587 |
+
// Atom to RSS 2.0 and Dublin Core
|
588 |
+
// RSS 2.0 person strings should be valid e-mail addresses if possible.
|
589 |
+
if (isset($source["{$id}_email"])) :
|
590 |
+
$rss_author = $source["{$id}_email"];
|
591 |
+
endif;
|
592 |
+
if (isset($source["{$id}_name"])) :
|
593 |
+
$rss_author = $source["{$id}_name"]
|
594 |
+
. (isset($rss_author) ? " <$rss_author>" : '');
|
595 |
+
endif;
|
596 |
+
if (isset($rss_author)) :
|
597 |
+
$source[$id] = $rss_author; // goes to top-level author or contributor
|
598 |
+
$dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor
|
599 |
+
endif;
|
600 |
+
} /* MagpieFromSimplePie::normalize_atom_person */
|
601 |
+
|
602 |
+
/**
|
603 |
+
* MagpieFromSimplePie::normalize_category: Normalize Atom 1.0 and
|
604 |
+
* RSS 2.0 categories to Dublin Core...
|
605 |
+
*
|
606 |
+
* @param array &$source
|
607 |
+
* @param string $from
|
608 |
+
* @param array &$dest
|
609 |
+
* @param string $to
|
610 |
+
* @param int $i
|
611 |
+
*
|
612 |
+
* @uses MagpieFromSimplePie::element_id
|
613 |
+
* @uses MagpieFromSimplePie::is_rss
|
614 |
+
*/
|
615 |
+
function normalize_category (&$source, $from, &$dest, $to, $i) {
|
616 |
+
$cat_id = $this->element_id($from, $i);
|
617 |
+
$dc_id = $this->element_id($to, $i);
|
618 |
+
|
619 |
+
// first normalize category elements: Atom 1.0 <=> RSS 2.0
|
620 |
+
if ( isset($source["{$cat_id}@term"]) ) : // category identifier
|
621 |
+
$source[$cat_id] = $source["{$cat_id}@term"];
|
622 |
+
elseif ( $this->is_rss() ) :
|
623 |
+
$source["{$cat_id}@term"] = $source[$cat_id];
|
624 |
+
endif;
|
625 |
+
|
626 |
+
if ( isset($source["{$cat_id}@scheme"]) ) : // URI to taxonomy
|
627 |
+
$source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"];
|
628 |
+
elseif ( isset($source["{$cat_id}@domain"]) ) :
|
629 |
+
$source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"];
|
630 |
+
endif;
|
631 |
+
|
632 |
+
// Now put the identifier into dc:subject
|
633 |
+
$dest[$dc_id] = $source[$cat_id];
|
634 |
+
} /* MagpieFromSimplePie::normalize_category */
|
635 |
+
|
636 |
+
/**
|
637 |
+
* MagpieFromSimplePie::normalize_dc_subject: Normalize Dublin Core
|
638 |
+
* "subject" elements to Atom 1.0 and RSS 2.0 categories.
|
639 |
+
*
|
640 |
+
* @param array &$source
|
641 |
+
* @param string $from
|
642 |
+
* @param array &$dest
|
643 |
+
* @param string $to
|
644 |
+
* @param int $i
|
645 |
+
*
|
646 |
+
* @uses MagpieFromSimplePie::element_id
|
647 |
+
*/
|
648 |
+
function normalize_dc_subject (&$source, $from, &$dest, $to, $i) {
|
649 |
+
$dc_id = $this->element_id($from, $i);
|
650 |
+
$cat_id = $this->element_id($to, $i);
|
651 |
+
|
652 |
+
$dest[$cat_id] = $source[$dc_id]; // RSS 2.0
|
653 |
+
$dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0
|
654 |
+
}
|
655 |
+
|
656 |
+
/**
|
657 |
+
* MagpieFromSimplePie::element_id
|
658 |
+
* Magic ID function for multiple elemenets.
|
659 |
+
* Can be called as static MagpieRSS::element_id()
|
660 |
+
*
|
661 |
+
* @param string $el
|
662 |
+
* @param int $counter
|
663 |
+
* @return string
|
664 |
+
*/
|
665 |
+
function element_id ($el, $counter) {
|
666 |
+
return $el . (($counter > 1) ? '#'.$counter : '');
|
667 |
+
} /* MagpieFromSimplePie::element_id */
|
668 |
+
|
669 |
+
/**
|
670 |
+
* MagpieFromSimplePie::increment_element
|
671 |
+
*
|
672 |
+
* @param array &$data
|
673 |
+
* @param string $childTag
|
674 |
+
* @param string $ns
|
675 |
+
* @param array $path
|
676 |
+
*/
|
677 |
+
function increment_element (&$data, $childTag, $ns, $path) {
|
678 |
+
$counterIndex = strtolower(implode('_', array_merge($path, array($childTag.'#'))));
|
679 |
+
if ($this->is_namespaced($ns)) :
|
680 |
+
if (!isset($data[$ns])) : $data[$ns] = array(); endif;
|
681 |
+
if (!isset($data[$ns][$counterIndex])) : $data[$ns][$counterIndex] = 0; endif;
|
682 |
+
$data[$ns][$counterIndex] += 1;
|
683 |
+
$N = $data[$ns][$counterIndex];
|
684 |
+
else :
|
685 |
+
if (!isset($data[$counterIndex])) : $data[$counterIndex] = 0; endif;
|
686 |
+
$data[$counterIndex] += 1;
|
687 |
+
$N = $data[$counterIndex];
|
688 |
+
endif;
|
689 |
+
|
690 |
+
if ($N > 1) :
|
691 |
+
$childTag .= '#'.$N;
|
692 |
+
endif;
|
693 |
+
return $childTag;
|
694 |
+
} /* MagpieFromSimplePie::increment_element */
|
695 |
+
|
696 |
+
/**
|
697 |
+
* MagpieFromSimplePie::is_namespaced
|
698 |
+
*
|
699 |
+
* @param string $ns
|
700 |
+
* @return bool
|
701 |
+
*
|
702 |
+
* @uses MagpieFromSimplePie::is_atom
|
703 |
+
* @uses MagpieFromSimplePie::is_rdf
|
704 |
+
*/
|
705 |
+
function is_namespaced ($ns, $attribute = false) {
|
706 |
+
// Atom vs. RSS
|
707 |
+
if ($this->is_atom()) : $root = array('', 'atom');
|
708 |
+
else : $root = array('', 'rss');
|
709 |
+
endif;
|
710 |
+
|
711 |
+
// RDF formats; namespaced in attribs but not in elements
|
712 |
+
if (!$attribute and $this->is_rdf()) :
|
713 |
+
$root[] = 'rdf';
|
714 |
+
endif;
|
715 |
+
|
716 |
+
return !in_array(strtolower($ns), $root);
|
717 |
+
} /* MagpieFromSimplePie::is_namespaced */
|
718 |
+
|
719 |
+
/**
|
720 |
+
* MagpieFromSimplePie::is_atom
|
721 |
+
*
|
722 |
+
* @return bool
|
723 |
+
*/
|
724 |
+
function is_atom () {
|
725 |
+
return $this->pie->get_type() & SIMPLEPIE_TYPE_ATOM_ALL;
|
726 |
+
} /* MagpieFromSimplePie::increment_element */
|
727 |
+
|
728 |
+
/**
|
729 |
+
* MagpieFromSimplePie::is_rss
|
730 |
+
*
|
731 |
+
* @return bool
|
732 |
+
*/
|
733 |
+
function is_rss () {
|
734 |
+
return $this->pie->get_type() & SIMPLEPIE_TYPE_RSS_ALL;
|
735 |
+
} /* MagpieFromSimplePie::is_rss */
|
736 |
+
|
737 |
+
/**
|
738 |
+
* MagpieFromSimplePie::is_rdf
|
739 |
+
*
|
740 |
+
* @return bool
|
741 |
+
*/
|
742 |
+
function is_rdf () {
|
743 |
+
return $this->pie->get_type() & SIMPLEPIE_TYPE_RSS_RDF;
|
744 |
+
} /* MagpieFromSimplePie::is_rdf */
|
745 |
+
|
746 |
+
/**
|
747 |
+
* MagpieFromSimplePie::feed_version
|
748 |
+
*
|
749 |
+
* @return float
|
750 |
+
*/
|
751 |
+
function feed_version () {
|
752 |
+
$map = array (
|
753 |
+
SIMPLEPIE_TYPE_ATOM_10 => 1.0,
|
754 |
+
SIMPLEPIE_TYPE_ATOM_03 => 0.3,
|
755 |
+
SIMPLEPIE_TYPE_RSS_090 => 0.90,
|
756 |
+
SIMPLEPIE_TYPE_RSS_091 => 0.91,
|
757 |
+
SIMPLEPIE_TYPE_RSS_092 => 0.92,
|
758 |
+
SIMPLEPIE_TYPE_RSS_093 => 0.93,
|
759 |
+
SIMPLEPIE_TYPE_RSS_094 => 0.94,
|
760 |
+
SIMPLEPIE_TYPE_RSS_10 => 1.0,
|
761 |
+
SIMPLEPIE_TYPE_RSS_20 => 2.0,
|
762 |
+
);
|
763 |
+
|
764 |
+
$ret = NULL; $type = $this->pie->get_type();
|
765 |
+
foreach ($map as $flag => $version) :
|
766 |
+
if ($type & $flag) :
|
767 |
+
$ret = $version;
|
768 |
+
break;
|
769 |
+
endif;
|
770 |
+
endforeach;
|
771 |
+
return $ret;
|
772 |
+
} /* MagpieFromSimplePie::feed_version */
|
773 |
+
|
774 |
+
} /* class MagpieFromSimplePie */
|
775 |
+
|
magpiemocklink.class.php
CHANGED
@@ -6,7 +6,14 @@ class MagpieMockLink extends SyndicatedLink {
|
|
6 |
|
7 |
function MagpieMockLink ($rss, $url) {
|
8 |
$this->link = $rss;
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
$this->url = $url;
|
11 |
$this->id = -1;
|
12 |
$this->settings = array(
|
@@ -17,7 +24,9 @@ class MagpieMockLink extends SyndicatedLink {
|
|
17 |
|
18 |
function poll ($crash_ts = NULL) {
|
19 |
// Do nothing but update copy of feed
|
20 |
-
$this->
|
|
|
|
|
21 |
$this->link = $this->magpie;
|
22 |
} /* function MagpieMockLink::poll () */
|
23 |
|
@@ -26,8 +35,12 @@ class MagpieMockLink extends SyndicatedLink {
|
|
26 |
} /* function MagpieMockLink::uri() */
|
27 |
|
28 |
function homepage () {
|
29 |
-
return (
|
30 |
} /* function MagpieMockLink::homepage () */
|
|
|
|
|
|
|
|
|
31 |
} /* class MagpieMockLink */
|
32 |
|
33 |
|
6 |
|
7 |
function MagpieMockLink ($rss, $url) {
|
8 |
$this->link = $rss;
|
9 |
+
|
10 |
+
if (is_array($rss) and isset($rss['simplepie']) and isset($rss['magpie'])) :
|
11 |
+
$this->simplepie = $rss['simplepie'];
|
12 |
+
$this->magpie = $rss['magpie'];
|
13 |
+
else :
|
14 |
+
$this->magpie = $rss;
|
15 |
+
endif;
|
16 |
+
|
17 |
$this->url = $url;
|
18 |
$this->id = -1;
|
19 |
$this->settings = array(
|
24 |
|
25 |
function poll ($crash_ts = NULL) {
|
26 |
// Do nothing but update copy of feed
|
27 |
+
$this->simplepie = FeedWordPress::fetch($this->url);
|
28 |
+
$this->magpie = new MagpieFromSimplePie($this->simplepie);
|
29 |
+
|
30 |
$this->link = $this->magpie;
|
31 |
} /* function MagpieMockLink::poll () */
|
32 |
|
35 |
} /* function MagpieMockLink::uri() */
|
36 |
|
37 |
function homepage () {
|
38 |
+
return (!is_wp_error($this->simplepie) ? $this->simplepie->get_link() : null);
|
39 |
} /* function MagpieMockLink::homepage () */
|
40 |
+
|
41 |
+
function save_settings ($reload = false) {
|
42 |
+
// NOOP.
|
43 |
+
}
|
44 |
} /* class MagpieMockLink */
|
45 |
|
46 |
|
posts-page.php
CHANGED
@@ -20,12 +20,12 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
20 |
|
21 |
function accept_POST ($post) {
|
22 |
global $wpdb;
|
23 |
-
|
24 |
-
$link_id = $this->link->id;
|
25 |
|
26 |
// User mashed a Save Changes button
|
27 |
if (isset($post['save']) or isset($post['submit'])) :
|
28 |
// custom post settings
|
|
|
|
|
29 |
foreach ($post['notes'] as $mn) :
|
30 |
$mn['key0'] = trim($mn['key0']);
|
31 |
$mn['key1'] = trim($mn['key1']);
|
@@ -48,7 +48,13 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
48 |
if (isset($post['resolve_relative'])) :
|
49 |
$this->link->settings['resolve relative'] = $post['resolve_relative'];
|
50 |
endif;
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
// Post status, comment status, ping status
|
53 |
foreach (array('post', 'comment', 'ping') as $what) :
|
54 |
$sfield = "feed_{$what}_status";
|
@@ -61,22 +67,14 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
61 |
endif;
|
62 |
endforeach;
|
63 |
|
64 |
-
|
65 |
-
$
|
66 |
-
|
67 |
-
// issue update query
|
68 |
-
$result = $wpdb->query("
|
69 |
-
UPDATE $wpdb->links
|
70 |
-
SET $alter_set
|
71 |
-
WHERE link_id='$link_id'
|
72 |
-
");
|
73 |
$this->updated = true;
|
74 |
-
|
75 |
-
// reload
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
$link =& new SyndicatedLink($link_id);
|
80 |
else :
|
81 |
// update_option ...
|
82 |
if (isset($post['feed_post_status'])) :
|
@@ -92,6 +90,9 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
92 |
if (isset($post['resolve_relative'])) :
|
93 |
update_option('feedwordpress_resolve_relative', $post['resolve_relative']);
|
94 |
endif;
|
|
|
|
|
|
|
95 |
if (isset($_REQUEST['feed_comment_status']) and ($_REQUEST['feed_comment_status'] == 'open')) :
|
96 |
update_option('feedwordpress_syndicated_comment_status', 'open');
|
97 |
else :
|
@@ -125,8 +126,6 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
125 |
* @uses FeedWordPress::syndicated_status()
|
126 |
* @uses SyndicatedLink::syndicated_status()
|
127 |
* @uses SyndicatedPost::use_api()
|
128 |
-
* @uses fwp_option_box_opener()
|
129 |
-
* @uses fwp_option_box_closer()
|
130 |
*/
|
131 |
/*static*/ function publication_box ($page, $box = NULL) {
|
132 |
global $fwp_path;
|
@@ -204,8 +203,6 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
204 |
* a page for one feed's settings or for global defaults
|
205 |
* @param array $box
|
206 |
*
|
207 |
-
* @uses fwp_option_box_opener()
|
208 |
-
* @uses fwp_option_box_closer()
|
209 |
*/
|
210 |
function formatting_box ($page, $box = NULL) {
|
211 |
global $fwp_path;
|
@@ -271,21 +268,36 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
271 |
* a page for one feed's settings or for global defaults
|
272 |
* @param array $box
|
273 |
*
|
274 |
-
* @uses fwp_option_box_opener()
|
275 |
-
* @uses fwp_option_box_closer()
|
276 |
*/
|
277 |
/*static*/ function links_box ($page, $box = NULL) {
|
278 |
-
$
|
279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
?>
|
281 |
<table class="form-table" cellspacing="2" cellpadding="5">
|
282 |
-
<tr><th scope="row">Permalinks:</th>
|
283 |
-
<td><
|
284 |
-
|
285 |
-
<
|
286 |
-
|
|
|
|
|
|
|
287 |
</tr>
|
288 |
|
|
|
289 |
<tr><th scope="row">Posts from aggregator feeds:</th>
|
290 |
<td><ul class="options">
|
291 |
<li><label><input type="radio" name="use_aggregator_source_data" value="no"<?php echo ($use_aggregator_source_data!="yes")?' checked="checked"':''; ?>> Give the aggregator itself as the source of posts from an aggregator feed.</label></li>
|
@@ -295,6 +307,7 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
295 |
This setting controls what FeedWordPress will give as the source of posts from
|
296 |
such an aggregator feed.</p>
|
297 |
</td></tr>
|
|
|
298 |
</table>
|
299 |
|
300 |
<?php
|
@@ -308,10 +321,10 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
308 |
* a page for one feed's settings or for global defaults
|
309 |
* @param array $box
|
310 |
*
|
311 |
-
* @uses fwp_option_box_opener()
|
312 |
-
* @uses fwp_option_box_closer()
|
313 |
*/
|
314 |
/*static*/ function comments_and_pings_box ($page, $box = NULL) {
|
|
|
|
|
315 |
$setting = array();
|
316 |
$selector = array();
|
317 |
|
@@ -321,6 +334,24 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
321 |
);
|
322 |
$onThesePosts = 'on '.$page->these_posts_phrase();
|
323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
foreach ($whatsits as $what => $how) :
|
325 |
$whatsits[$what]['default'] = FeedWordPress::syndicated_status($what, /*default=*/ 'closed');
|
326 |
|
@@ -368,11 +399,44 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
368 |
<?php endforeach; ?>
|
369 |
</ul></td></tr>
|
370 |
<?php endforeach; ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
</table>
|
372 |
|
373 |
<?php
|
374 |
} /* FeedWordPressPostsPage::comments_and_pings_box() */
|
375 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
376 |
/**
|
377 |
* Output "Custom Post Settings" settings box
|
378 |
*
|
@@ -380,33 +444,12 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
380 |
* @param object $page of class FeedWordPressPostsPage tells us whether this is
|
381 |
* a page for one feed's settings or for global defaults
|
382 |
* @param array $box
|
383 |
-
*
|
384 |
-
* @uses fwp_option_box_opener()
|
385 |
-
* @uses fwp_option_box_closer()
|
386 |
*/
|
387 |
/*static*/ function custom_post_settings_box ($page, $box = NULL) {
|
388 |
-
|
389 |
-
$custom_settings = $page->link->settings["postmeta"];
|
390 |
-
if ($custom_settings and !is_array($custom_settings)) :
|
391 |
-
$custom_settings = unserialize($custom_settings);
|
392 |
-
endif;
|
393 |
-
|
394 |
-
if (!is_array($custom_settings)) :
|
395 |
-
$custom_settings = array();
|
396 |
-
endif;
|
397 |
-
else :
|
398 |
-
$custom_settings = get_option('feedwordpress_custom_settings');
|
399 |
-
if ($custom_settings and !is_array($custom_settings)) :
|
400 |
-
$custom_settings = unserialize($custom_settings);
|
401 |
-
endif;
|
402 |
-
|
403 |
-
if (!is_array($custom_settings)) :
|
404 |
-
$custom_settings = array();
|
405 |
-
endif;
|
406 |
-
endif;
|
407 |
-
|
408 |
?>
|
409 |
<div id="postcustomstuff">
|
|
|
410 |
<table id="meta-list" cellpadding="3">
|
411 |
<tr>
|
412 |
<th>Key</th>
|
@@ -419,9 +462,9 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
419 |
foreach ($custom_settings as $key => $value) :
|
420 |
?>
|
421 |
<tr style="vertical-align:top">
|
422 |
-
<th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo
|
423 |
-
<input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo
|
424 |
-
<td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo
|
425 |
<td width="10%"><select name="notes[<?php echo $i; ?>][action]">
|
426 |
<option value="update">save changes</option>
|
427 |
<option value="delete">delete this setting</option>
|
@@ -433,9 +476,15 @@ class FeedWordPressPostsPage extends FeedWordPressAdminPage {
|
|
433 |
endforeach;
|
434 |
?>
|
435 |
|
436 |
-
<tr>
|
437 |
<th scope="row"><input type="text" size="10" name="notes[<?php echo $i; ?>][key1]" value="" /></th>
|
438 |
-
<td><textarea name="notes[<?php echo $i; ?>][value]" rows="2" cols="40"></textarea
|
|
|
|
|
|
|
|
|
|
|
|
|
439 |
<td><em>add new setting...</em><input type="hidden" name="notes[<?php echo $i; ?>][action]" value="update" /></td>
|
440 |
</tr>
|
441 |
</table>
|
@@ -458,7 +507,7 @@ function fwp_posts_page () {
|
|
458 |
FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_posts_settings', /*capability=*/ 'manage_links');
|
459 |
|
460 |
$link = FeedWordPressAdminPage::submitted_link();
|
461 |
-
|
462 |
$postsPage = new FeedWordPressPostsPage($link);
|
463 |
|
464 |
$mesg = null;
|
@@ -476,7 +525,7 @@ function fwp_posts_page () {
|
|
476 |
if ($postsPage->updated) : ?>
|
477 |
<div class="updated"><p>Syndicated posts settings updated.</p></div>
|
478 |
<?php elseif (!is_null($mesg)) : ?>
|
479 |
-
<div class="updated"><p><?php print
|
480 |
<?php endif; ?>
|
481 |
|
482 |
<?php
|
@@ -498,11 +547,6 @@ $boxes_by_methods = array(
|
|
498 |
'custom_post_settings_box' => __('Custom Post Settings (to apply to each syndicated post)'),
|
499 |
);
|
500 |
|
501 |
-
// Feed-level settings don't exist for these.
|
502 |
-
if ($postsPage->for_feed_settings()) :
|
503 |
-
unset($boxes_by_methods['links_box']);
|
504 |
-
endif;
|
505 |
-
|
506 |
foreach ($boxes_by_methods as $method => $title) :
|
507 |
fwp_add_meta_box(
|
508 |
/*id=*/ 'feedwordpress_'.$method,
|
20 |
|
21 |
function accept_POST ($post) {
|
22 |
global $wpdb;
|
|
|
|
|
23 |
|
24 |
// User mashed a Save Changes button
|
25 |
if (isset($post['save']) or isset($post['submit'])) :
|
26 |
// custom post settings
|
27 |
+
$custom_settings = $this->custom_post_settings();
|
28 |
+
|
29 |
foreach ($post['notes'] as $mn) :
|
30 |
$mn['key0'] = trim($mn['key0']);
|
31 |
$mn['key1'] = trim($mn['key1']);
|
48 |
if (isset($post['resolve_relative'])) :
|
49 |
$this->link->settings['resolve relative'] = $post['resolve_relative'];
|
50 |
endif;
|
51 |
+
if (isset($post['munge_permalink'])) :
|
52 |
+
$this->link->settings['munge permalink'] = $post['munge_permalink'];
|
53 |
+
endif;
|
54 |
+
if (isset($post['munge_comments_feed_links'])) :
|
55 |
+
$this->link->settings['munge comments feed links'] = $post['munge_comments_feed_links'];
|
56 |
+
endif;
|
57 |
+
|
58 |
// Post status, comment status, ping status
|
59 |
foreach (array('post', 'comment', 'ping') as $what) :
|
60 |
$sfield = "feed_{$what}_status";
|
67 |
endif;
|
68 |
endforeach;
|
69 |
|
70 |
+
// Save settings
|
71 |
+
$this->link->save_settings(/*reload=*/ true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
$this->updated = true;
|
73 |
+
|
74 |
+
// Reset, reload
|
75 |
+
$link_id = $this->link->id;
|
76 |
+
unset($this->link);
|
77 |
+
$this->link = new SyndicatedLink($link_id);
|
|
|
78 |
else :
|
79 |
// update_option ...
|
80 |
if (isset($post['feed_post_status'])) :
|
90 |
if (isset($post['resolve_relative'])) :
|
91 |
update_option('feedwordpress_resolve_relative', $post['resolve_relative']);
|
92 |
endif;
|
93 |
+
if (isset($post['munge_comments_feed_links'])) :
|
94 |
+
update_option('feedwordpress_munge_comments_feed_links', $post['munge_comments_feed_links']);
|
95 |
+
endif;
|
96 |
if (isset($_REQUEST['feed_comment_status']) and ($_REQUEST['feed_comment_status'] == 'open')) :
|
97 |
update_option('feedwordpress_syndicated_comment_status', 'open');
|
98 |
else :
|
126 |
* @uses FeedWordPress::syndicated_status()
|
127 |
* @uses SyndicatedLink::syndicated_status()
|
128 |
* @uses SyndicatedPost::use_api()
|
|
|
|
|
129 |
*/
|
130 |
/*static*/ function publication_box ($page, $box = NULL) {
|
131 |
global $fwp_path;
|
203 |
* a page for one feed's settings or for global defaults
|
204 |
* @param array $box
|
205 |
*
|
|
|
|
|
206 |
*/
|
207 |
function formatting_box ($page, $box = NULL) {
|
208 |
global $fwp_path;
|
268 |
* a page for one feed's settings or for global defaults
|
269 |
* @param array $box
|
270 |
*
|
|
|
|
|
271 |
*/
|
272 |
/*static*/ function links_box ($page, $box = NULL) {
|
273 |
+
$setting = array(
|
274 |
+
'munge_permalink' => array(
|
275 |
+
'yes' => 'the copy on the original website',
|
276 |
+
'no' => 'the local copy on this website',
|
277 |
+
),
|
278 |
+
);
|
279 |
+
|
280 |
+
$global_munge_permalink = get_option('feedwordpress_munge_permalink');
|
281 |
+
if ($page->for_feed_settings()) :
|
282 |
+
$munge_permalink = $page->link->setting('munge permalink', NULL);
|
283 |
+
else :
|
284 |
+
$munge_permalink = $global_munge_permalink;
|
285 |
+
$use_aggregator_source_data = get_option('feedwordpress_use_aggregator_source_data');
|
286 |
+
endif;
|
287 |
+
|
288 |
?>
|
289 |
<table class="form-table" cellspacing="2" cellpadding="5">
|
290 |
+
<tr><th scope="row">Permalinks point to:</th>
|
291 |
+
<td><ul class="options">
|
292 |
+
<?php if ($page->for_feed_settings()) : ?>
|
293 |
+
<li><label><input type="radio" name="munge_permalink" value="default"<?php echo ($munge_permalink!='yes' and $munge_permalink != 'no')?' checked="checked"':''; ?>/> use site-wide setting (currently <?php print $setting['munge_permalink'][$global_munge_permalink]; ?>)</label></li>
|
294 |
+
<?php endif; ?>
|
295 |
+
<li><label><input type="radio" name="munge_permalink" value="yes"<?php echo ($munge_permalink=='yes')?' checked="checked"':''; ?>><?php print $setting['munge_permalink']['yes']; ?></label></li>
|
296 |
+
<li><label><input type="radio" name="munge_permalink" value="no"<?php echo ($munge_permalink=='no')?' checked="checked"':''; ?>><?php print $setting['munge_permalink']['no']; ?></label></li>
|
297 |
+
</ul></td>
|
298 |
</tr>
|
299 |
|
300 |
+
<?php if (!$page->for_feed_settings()) : ?>
|
301 |
<tr><th scope="row">Posts from aggregator feeds:</th>
|
302 |
<td><ul class="options">
|
303 |
<li><label><input type="radio" name="use_aggregator_source_data" value="no"<?php echo ($use_aggregator_source_data!="yes")?' checked="checked"':''; ?>> Give the aggregator itself as the source of posts from an aggregator feed.</label></li>
|
307 |
This setting controls what FeedWordPress will give as the source of posts from
|
308 |
such an aggregator feed.</p>
|
309 |
</td></tr>
|
310 |
+
<?php endif; ?>
|
311 |
</table>
|
312 |
|
313 |
<?php
|
321 |
* a page for one feed's settings or for global defaults
|
322 |
* @param array $box
|
323 |
*
|
|
|
|
|
324 |
*/
|
325 |
/*static*/ function comments_and_pings_box ($page, $box = NULL) {
|
326 |
+
global $fwp_path;
|
327 |
+
|
328 |
$setting = array();
|
329 |
$selector = array();
|
330 |
|
334 |
);
|
335 |
$onThesePosts = 'on '.$page->these_posts_phrase();
|
336 |
|
337 |
+
$selected = array(
|
338 |
+
'munge_comments_feed_links' => array('yes' => '', 'no' => '')
|
339 |
+
);
|
340 |
+
|
341 |
+
$globalMungeCommentsFeedLinks = get_option('feedwordpress_munge_comments_feed_links', 'yes');
|
342 |
+
if ($page->for_feed_settings()) :
|
343 |
+
$selected['munge_comments_feed_links']['default'] = '';
|
344 |
+
|
345 |
+
$sel = $page->link->setting('munge comments feed links', NULL, 'default');
|
346 |
+
else :
|
347 |
+
$sel = $globalMungeCommentsFeedLinks;
|
348 |
+
endif;
|
349 |
+
$selected['munge_comments_feed_links'][$sel] = ' checked="checked"';
|
350 |
+
|
351 |
+
if ($globalMungeCommentsFeedLinks != 'no') : $siteWide = __('comment feeds from the original website');
|
352 |
+
else : $siteWide = __('local comment feeds on this website');
|
353 |
+
endif;
|
354 |
+
|
355 |
foreach ($whatsits as $what => $how) :
|
356 |
$whatsits[$what]['default'] = FeedWordPress::syndicated_status($what, /*default=*/ 'closed');
|
357 |
|
399 |
<?php endforeach; ?>
|
400 |
</ul></td></tr>
|
401 |
<?php endforeach; ?>
|
402 |
+
<tr><th scope="row"><?php _e('Comment feeds'); ?></th>
|
403 |
+
<td><p>When WordPress feeds and templates link to comments
|
404 |
+
feeds for <?php print $page->these_posts_phrase(); ?>, the
|
405 |
+
URLs for the feeds should...</p>
|
406 |
+
<ul class="options">
|
407 |
+
<?php if ($page->for_feed_settings()) : ?>
|
408 |
+
<li><label><input type="radio" name="munge_comments_feed_links" value="default"<?php print $selected['munge_comments_feed_links']['default']; ?> /> Use <a href="admin.php?page=<?php print $href; ?>">site-wide setting</a> (currently: <strong><?php _e($siteWide); ?></strong>)</label></li>
|
409 |
+
<?php endif; ?>
|
410 |
+
<li><label><input type="radio" name="munge_comments_feed_links" value="yes"<?php print $selected['munge_comments_feed_links']['yes']; ?> /> <?php _e('Point to comment feeds from the original website (when provided by the syndicated feed)'); ?></label></li>
|
411 |
+
<li><label><input type="radio" name="munge_comments_feed_links" value="no"<?php print $selected['munge_comments_feed_links']['no']; ?> /> <?php _e('Point to local comment feeds on this website'); ?></label></li>
|
412 |
+
</ul></td></tr>
|
413 |
</table>
|
414 |
|
415 |
<?php
|
416 |
} /* FeedWordPressPostsPage::comments_and_pings_box() */
|
417 |
|
418 |
+
/*static*/ function custom_post_settings ($page = NULL) {
|
419 |
+
if (is_null($page)) :
|
420 |
+
$page = $this;
|
421 |
+
endif;
|
422 |
+
|
423 |
+
if ($page->for_feed_settings()) :
|
424 |
+
$custom_settings = $page->link->settings["postmeta"];
|
425 |
+
else :
|
426 |
+
$custom_settings = get_option('feedwordpress_custom_settings');
|
427 |
+
endif;
|
428 |
+
|
429 |
+
if ($custom_settings and !is_array($custom_settings)) :
|
430 |
+
$custom_settings = unserialize($custom_settings);
|
431 |
+
endif;
|
432 |
+
|
433 |
+
if (!is_array($custom_settings)) :
|
434 |
+
$custom_settings = array();
|
435 |
+
endif;
|
436 |
+
|
437 |
+
return $custom_settings;
|
438 |
+
} /* FeedWordPressPostsPage::custom_post_settings() */
|
439 |
+
|
440 |
/**
|
441 |
* Output "Custom Post Settings" settings box
|
442 |
*
|
444 |
* @param object $page of class FeedWordPressPostsPage tells us whether this is
|
445 |
* a page for one feed's settings or for global defaults
|
446 |
* @param array $box
|
|
|
|
|
|
|
447 |
*/
|
448 |
/*static*/ function custom_post_settings_box ($page, $box = NULL) {
|
449 |
+
$custom_settings = FeedWordPressPostsPage::custom_post_settings($page);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 |
?>
|
451 |
<div id="postcustomstuff">
|
452 |
+
<p>Custom fields can be used to add extra metadata to a post that you can <a href="http://codex.wordpress.org/Using_Custom_Fields">use in your theme</a>.</p>
|
453 |
<table id="meta-list" cellpadding="3">
|
454 |
<tr>
|
455 |
<th>Key</th>
|
462 |
foreach ($custom_settings as $key => $value) :
|
463 |
?>
|
464 |
<tr style="vertical-align:top">
|
465 |
+
<th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo esc_html($key); ?>" />
|
466 |
+
<input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo esc_html($key); ?>" /></th>
|
467 |
+
<td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo esc_html($value); ?></textarea></td>
|
468 |
<td width="10%"><select name="notes[<?php echo $i; ?>][action]">
|
469 |
<option value="update">save changes</option>
|
470 |
<option value="delete">delete this setting</option>
|
476 |
endforeach;
|
477 |
?>
|
478 |
|
479 |
+
<tr style="vertical-align: top">
|
480 |
<th scope="row"><input type="text" size="10" name="notes[<?php echo $i; ?>][key1]" value="" /></th>
|
481 |
+
<td><textarea name="notes[<?php echo $i; ?>][value]" rows="2" cols="40"></textarea>
|
482 |
+
<p>Enter a text value, or a path to a data element from the syndicated item.<br/>
|
483 |
+
For data elements, you can use an XPath-like syntax wrapped in <code>$( ... )</code>.<br/>
|
484 |
+
<code>hello</code> = the text value <code><span style="background-color: #30FFA0;">hello</span></code><br/>
|
485 |
+
<code>$(author/email)</code> = the contents of <code><author><email><span style="background-color: #30FFA0">...</span></email></author></code><br/>
|
486 |
+
<code>$(media:content/@url)</code> = the contents of <code><media:content url="<span style="background-color: #30FFA0">...</span>">...</media:content></code></p>
|
487 |
+
</td>
|
488 |
<td><em>add new setting...</em><input type="hidden" name="notes[<?php echo $i; ?>][action]" value="update" /></td>
|
489 |
</tr>
|
490 |
</table>
|
507 |
FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_posts_settings', /*capability=*/ 'manage_links');
|
508 |
|
509 |
$link = FeedWordPressAdminPage::submitted_link();
|
510 |
+
|
511 |
$postsPage = new FeedWordPressPostsPage($link);
|
512 |
|
513 |
$mesg = null;
|
525 |
if ($postsPage->updated) : ?>
|
526 |
<div class="updated"><p>Syndicated posts settings updated.</p></div>
|
527 |
<?php elseif (!is_null($mesg)) : ?>
|
528 |
+
<div class="updated"><p><?php print esc_html($mesg); ?></p></div>
|
529 |
<?php endif; ?>
|
530 |
|
531 |
<?php
|
547 |
'custom_post_settings_box' => __('Custom Post Settings (to apply to each syndicated post)'),
|
548 |
);
|
549 |
|
|
|
|
|
|
|
|
|
|
|
550 |
foreach ($boxes_by_methods as $method => $title) :
|
551 |
fwp_add_meta_box(
|
552 |
/*id=*/ 'feedwordpress_'.$method,
|
readme.txt
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
Contributors: Charles Johnson
|
3 |
Donate link: http://feedwordpress.radgeek.com/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
-
Requires at least:
|
6 |
-
Tested up to:
|
7 |
-
Stable tag: 2010.
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
@@ -18,107 +18,69 @@ FeedWordPress is an Atom/RSS aggregator for WordPress. It syndicates content
|
|
18 |
from feeds that you choose into your WordPress weblog; if you syndicate several
|
19 |
feeds then you can use WordPress's posts database and templating engine as the
|
20 |
back-end of an aggregation ("planet") website. It was developed, originally,
|
21 |
-
because I needed a more flexible replacement for [Planet]
|
22 |
-
to use at [Feminist Blogs]
|
|
|
|
|
|
|
23 |
|
24 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
25 |
configuration in mind. You'll need a working installation of WordPress or
|
26 |
-
WordPress MU (
|
27 |
-
|
28 |
-
|
29 |
-
necessary. You *don't* need to tweak any plain-text configuration files and you
|
30 |
*don't* need shell access to your web host to make it work. (Although, I should
|
31 |
point out, web hosts that *don't* offer shell access are *bad web hosts*.)
|
32 |
|
|
|
|
|
33 |
[2.8]: http://codex.wordpress.org/Version_2.8
|
34 |
-
[2.7]: http://codex.wordpress.org/Version_2.7
|
35 |
-
[2.6]: http://codex.wordpress.org/Version_2.6
|
36 |
-
[2.5]: http://codex.wordpress.org/Version_2.5
|
37 |
-
[2.3]: http://codex.wordpress.org/Version_2.3
|
38 |
-
[2.2]: http://codex.wordpress.org/Version_2.2
|
39 |
-
[2.1]: http://codex.wordpress.org/Version_2.1
|
40 |
-
[2.0]: http://codex.wordpress.org/Version_2.0
|
41 |
-
[1.5]: http://codex.wordpress.org/Version_1.5
|
42 |
|
43 |
== Installation ==
|
44 |
|
45 |
To use FeedWordPress, you will need:
|
46 |
|
47 |
-
* an installed and configured copy of WordPress
|
48 |
-
(
|
49 |
-
MU.)
|
50 |
|
51 |
-
* FTP or
|
52 |
|
53 |
= New Installations =
|
54 |
|
55 |
-
1. Download the FeedWordPress
|
|
|
56 |
|
57 |
2. Create a new directory named `feedwordpress` in the `wp-content/plugins`
|
58 |
directory of your WordPress installation. Use an FTP or SFTP client to
|
59 |
upload the contents of your FeedWordPress archive to the new directory
|
60 |
that you just created on your web host.
|
61 |
|
62 |
-
3.
|
63 |
-
new copies of `rss.php` and `rss-functions.php` into the `wp-includes`
|
64 |
-
directory of your FeedWordPress installation. These files are stored in
|
65 |
-
the `MagpieRSS-upgrade` directory of your FeedWordPress archive. Strictly
|
66 |
-
speaking, upgrading MagpieRSS is optional; FeedWordPress will run
|
67 |
-
correctly without the upgrade. But if you hope to take advantage of
|
68 |
-
numerous bug fixes, or support for Atom 1.0, multiple post categories,
|
69 |
-
RSS enclosures, or multiple character encodings, then you need to
|
70 |
-
install the upgrade.
|
71 |
|
72 |
-
4.
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
-
|
75 |
-
and set (1) the link category that FeedWordPress will syndicate links
|
76 |
-
from (by default, "Contributors"), and (2) whether FeedWordPress will
|
77 |
-
use automatic updates or only manual updates.
|
78 |
|
79 |
-
|
80 |
-
|
81 |
|
82 |
-
|
|
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
your existing `wp-content/update-feeds.php` and
|
93 |
-
`wp-content/plugins/feedwordpress.php` files. The file structure for
|
94 |
-
FeedWordPress has changed and the files from your old version will not
|
95 |
-
be overwritten, which could cause conflicts if you leave them in place.
|
96 |
-
|
97 |
-
3. Upload the new PHP files to `wp-content/plugins/feedwordpress`,
|
98 |
-
overwriting any existing FeedWordPress files that are there. Also be
|
99 |
-
sure to upgrade the MagpieRSS module by uploading `rss.php` and
|
100 |
-
`rss-functions.php` from the `MagpieRSS-upgrade` directory in your
|
101 |
-
archive to the `wp-includes` directory of your WordPress installation.
|
102 |
-
|
103 |
-
3. If you are upgrading from version 0.96 or earlier, **immediately** log
|
104 |
-
in to the WordPress Dashboard, and go to **Options --> Syndicated**.
|
105 |
-
Follow the directions to launch the database upgrade procedure. The new
|
106 |
-
versions of FeedWordPress incorporate some long-needed improvements, but
|
107 |
-
old meta-data needs to be updated to prevent duplicate posts and other
|
108 |
-
possible maladies. If you're upgrading an existing installation, updates
|
109 |
-
and FeedWordPress template functions *will not work* until you've done
|
110 |
-
the upgrade. Then take a coffee break while the upgrade runs. It should,
|
111 |
-
hopefully, finish within a few minutes even on relatively large
|
112 |
-
databases.
|
113 |
-
|
114 |
-
4. If you are upgrading from version 0.98 or earlier, note that the old
|
115 |
-
`update-feeds.php` has been eliminated in favor of a (hopefully) more
|
116 |
-
humane method for automatic updating. If you used a cron job for
|
117 |
-
scheduled updates, it will not work anymore, but there is another,
|
118 |
-
simpler method which will. See [Setting Up Feed Updates](http://projects.radgeek.com/feedwordpress/install/#setting-up-feed-updates)
|
119 |
-
to get scheduled updates back on track.
|
120 |
-
|
121 |
-
5. Enjoy your new installation of FeedWordPress.
|
122 |
|
123 |
== Using and Customizing FeedWordPress ==
|
124 |
|
@@ -127,11 +89,11 @@ Dashboard, and a lot of functionality accessible programmatically through
|
|
127 |
WordPress templates or plugins. For further documentation of the ins and
|
128 |
outs, see the documentation at the [FeedWordPress project homepage][].
|
129 |
|
130 |
-
[FeedWordPress project homepage]: http://
|
131 |
|
132 |
== License ==
|
133 |
|
134 |
-
The FeedWordPress plugin is copyright © 2005-
|
135 |
code derived or translated from:
|
136 |
|
137 |
- [wp-rss-aggregate.php][] by [Kellan Elliot-McCrea](kellan@protest.net)
|
@@ -154,6 +116,5 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
154 |
[MagpieRSS]: http://magpierss.sourceforge.net/
|
155 |
[HTTP Navigator 2]: http://www.keyvan.net/2004/11/16/http-navigator/
|
156 |
[Ultra-Liberal Feed Finder]: http://diveintomark.org/projects/feed_finder/
|
157 |
-
|
158 |
[GNU General Public License]: http://www.gnu.org/copyleft/gpl.html
|
159 |
|
2 |
Contributors: Charles Johnson
|
3 |
Donate link: http://feedwordpress.radgeek.com/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
+
Requires at least: 2.8
|
6 |
+
Tested up to: 3.0
|
7 |
+
Stable tag: 2010.0528
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
18 |
from feeds that you choose into your WordPress weblog; if you syndicate several
|
19 |
feeds then you can use WordPress's posts database and templating engine as the
|
20 |
back-end of an aggregation ("planet") website. It was developed, originally,
|
21 |
+
because I needed a more flexible replacement for [Planet][]
|
22 |
+
to use at [Feminist Blogs][].
|
23 |
+
|
24 |
+
[Planet]: http://www.planetplanet.org/
|
25 |
+
[Feminist Blogs]: http://feministblogs.org/
|
26 |
|
27 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
28 |
configuration in mind. You'll need a working installation of WordPress or
|
29 |
+
WordPress MU (version [2.8] or later), and also FTP or SFTP access to your web
|
30 |
+
host. The ability to create cron jobs on your web host is helpful but not
|
31 |
+
required. You *don't* need to tweak any plain-text configuration files and you
|
|
|
32 |
*don't* need shell access to your web host to make it work. (Although, I should
|
33 |
point out, web hosts that *don't* offer shell access are *bad web hosts*.)
|
34 |
|
35 |
+
[WordPress]: http://wordpress.org/
|
36 |
+
[WordPress MU]: http://mu.wordpress.org/
|
37 |
[2.8]: http://codex.wordpress.org/Version_2.8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
== Installation ==
|
40 |
|
41 |
To use FeedWordPress, you will need:
|
42 |
|
43 |
+
* an installed and configured copy of [WordPress][] or [WordPress MU][]
|
44 |
+
(version 2.8 or later).
|
|
|
45 |
|
46 |
+
* FTP, SFTP or shell access to your web host
|
47 |
|
48 |
= New Installations =
|
49 |
|
50 |
+
1. Download the FeedWordPress installation package and extract the files on
|
51 |
+
your computer.
|
52 |
|
53 |
2. Create a new directory named `feedwordpress` in the `wp-content/plugins`
|
54 |
directory of your WordPress installation. Use an FTP or SFTP client to
|
55 |
upload the contents of your FeedWordPress archive to the new directory
|
56 |
that you just created on your web host.
|
57 |
|
58 |
+
3. Log in to the WordPress Dashboard and activate the FeedWordPress plugin.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
+
4. Once the plugin is activated, a new **Syndication** section should
|
61 |
+
appear in your WordPress admin menu. Click here to add new syndicated
|
62 |
+
feeds, set up configuration options, and determine how FeedWordPress
|
63 |
+
will check for updates. For help, see the [FeedWordPress Quick Start][]
|
64 |
+
page.
|
65 |
+
|
66 |
+
[FeedWordPress Quick Start]: http://feedwordpress.radgeek.com/wiki/quick-start
|
67 |
|
68 |
+
= Upgrades =
|
|
|
|
|
|
|
69 |
|
70 |
+
To *upgrade* an existing installation of FeedWordPress to the most recent
|
71 |
+
release:
|
72 |
|
73 |
+
1. Download the FeedWordPress installation package and extract the files on
|
74 |
+
your computer.
|
75 |
|
76 |
+
2. Upload the new PHP files to `wp-content/plugins/feedwordpress`,
|
77 |
+
overwriting any existing FeedWordPress files that are there.
|
78 |
+
|
79 |
+
3. Log in to your WordPress administrative interface immediately in order
|
80 |
+
to see whether there are any further tasks that you need to perform
|
81 |
+
to complete the upgrade.
|
82 |
+
|
83 |
+
4. Enjoy your newer and hotter installation of FeedWordPress
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
== Using and Customizing FeedWordPress ==
|
86 |
|
89 |
WordPress templates or plugins. For further documentation of the ins and
|
90 |
outs, see the documentation at the [FeedWordPress project homepage][].
|
91 |
|
92 |
+
[FeedWordPress project homepage]: http://feedwordpress.radgeek.com/
|
93 |
|
94 |
== License ==
|
95 |
|
96 |
+
The FeedWordPress plugin is copyright © 2005-2010 by Charles Johnson. It uses
|
97 |
code derived or translated from:
|
98 |
|
99 |
- [wp-rss-aggregate.php][] by [Kellan Elliot-McCrea](kellan@protest.net)
|
116 |
[MagpieRSS]: http://magpierss.sourceforge.net/
|
117 |
[HTTP Navigator 2]: http://www.keyvan.net/2004/11/16/http-navigator/
|
118 |
[Ultra-Liberal Feed Finder]: http://diveintomark.org/projects/feed_finder/
|
|
|
119 |
[GNU General Public License]: http://www.gnu.org/copyleft/gpl.html
|
120 |
|
syndicatedlink.class.php
CHANGED
@@ -33,10 +33,13 @@
|
|
33 |
# Values of keys in link_notes are accessible from templates using
|
34 |
# the function `get_feed_meta($key)` if this plugin is activated.
|
35 |
|
|
|
|
|
36 |
class SyndicatedLink {
|
37 |
var $id = null;
|
38 |
var $link = null;
|
39 |
var $settings = array ();
|
|
|
40 |
var $magpie = null;
|
41 |
|
42 |
function SyndicatedLink ($link) {
|
@@ -124,7 +127,7 @@ class SyndicatedLink {
|
|
124 |
} /* SyndicatedLink::SyndicatedLink () */
|
125 |
|
126 |
function found () {
|
127 |
-
return is_object($this->link);
|
128 |
} /* SyndicatedLink::found () */
|
129 |
|
130 |
function stale () {
|
@@ -146,7 +149,19 @@ class SyndicatedLink {
|
|
146 |
function poll ($crash_ts = NULL) {
|
147 |
global $wpdb;
|
148 |
|
149 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
$new_count = NULL;
|
151 |
|
152 |
$resume = FeedWordPress::affirmative($this->settings, 'update/unfinished');
|
@@ -158,7 +173,9 @@ class SyndicatedLink {
|
|
158 |
$processed = array();
|
159 |
endif;
|
160 |
|
161 |
-
if (
|
|
|
|
|
162 |
$new_count = array('new' => 0, 'updated' => 0);
|
163 |
|
164 |
# -- Update Link metadata live from feed
|
@@ -193,12 +210,11 @@ class SyndicatedLink {
|
|
193 |
$this->settings['update/timed'] = 'feed';
|
194 |
else :
|
195 |
// spread out over a time interval for staggered updates
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
if (!is_numeric($updateWindow) or ($updateWindow < 1)) :
|
203 |
$updateWindow = DEFAULT_UPDATE_PERIOD;
|
204 |
endif;
|
@@ -225,13 +241,24 @@ class SyndicatedLink {
|
|
225 |
SET $update_set
|
226 |
WHERE link_id='$this->id'
|
227 |
");
|
|
|
228 |
|
229 |
# -- Add new posts from feed and update any updated posts
|
230 |
$crashed = false;
|
231 |
|
232 |
-
|
233 |
-
|
234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
if (!$resume or !in_array(trim($post->guid()), $processed)) :
|
236 |
$processed[] = $post->guid();
|
237 |
if (!$post->filtered()) :
|
@@ -244,9 +271,13 @@ class SyndicatedLink {
|
|
244 |
break;
|
245 |
endif;
|
246 |
endif;
|
|
|
247 |
endforeach;
|
248 |
endif;
|
249 |
-
|
|
|
|
|
|
|
250 |
// Copy back any changes to feed settings made in the course of updating (e.g. new author rules)
|
251 |
$to_notes = $this->settings;
|
252 |
|
@@ -263,6 +294,8 @@ class SyndicatedLink {
|
|
263 |
SET $update_set
|
264 |
WHERE link_id='$this->id'
|
265 |
");
|
|
|
|
|
266 |
endif;
|
267 |
|
268 |
return $new_count;
|
@@ -365,9 +398,17 @@ class SyndicatedLink {
|
|
365 |
function save_settings ($reload = false) {
|
366 |
global $wpdb;
|
367 |
|
368 |
-
|
369 |
-
|
370 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
$result = $wpdb->query("
|
372 |
UPDATE $wpdb->links
|
373 |
SET $update_set
|
@@ -375,7 +416,7 @@ class SyndicatedLink {
|
|
375 |
");
|
376 |
|
377 |
if ($reload) :
|
378 |
-
// reload link information from DB
|
379 |
if (function_exists('clean_bookmark_cache')) :
|
380 |
clean_bookmark_cache($this->id);
|
381 |
endif;
|
@@ -397,11 +438,21 @@ class SyndicatedLink {
|
|
397 |
$ret = $this->settings[$name];
|
398 |
endif;
|
399 |
|
400 |
-
|
|
|
|
|
|
|
|
|
|
|
401 |
$ret = get_option('feedwordpress_'.$fallback_global, /*default=*/ NULL);
|
402 |
endif;
|
403 |
|
404 |
-
|
|
|
|
|
|
|
|
|
|
|
405 |
$ret = $fallback_value;
|
406 |
endif;
|
407 |
return $ret;
|
33 |
# Values of keys in link_notes are accessible from templates using
|
34 |
# the function `get_feed_meta($key)` if this plugin is activated.
|
35 |
|
36 |
+
require_once(dirname(__FILE__).'/magpiefromsimplepie.class.php');
|
37 |
+
|
38 |
class SyndicatedLink {
|
39 |
var $id = null;
|
40 |
var $link = null;
|
41 |
var $settings = array ();
|
42 |
+
var $simplepie = null;
|
43 |
var $magpie = null;
|
44 |
|
45 |
function SyndicatedLink ($link) {
|
127 |
} /* SyndicatedLink::SyndicatedLink () */
|
128 |
|
129 |
function found () {
|
130 |
+
return is_object($this->link) and !is_wp_error($this->link);
|
131 |
} /* SyndicatedLink::found () */
|
132 |
|
133 |
function stale () {
|
149 |
function poll ($crash_ts = NULL) {
|
150 |
global $wpdb;
|
151 |
|
152 |
+
$this->simplepie = apply_filters(
|
153 |
+
'syndicated_feed',
|
154 |
+
FeedWordPress::fetch($this->link->link_rss),
|
155 |
+
$this
|
156 |
+
);
|
157 |
+
|
158 |
+
// Filter compatibility mode
|
159 |
+
if (is_wp_error($this->simplepie)) :
|
160 |
+
$this->magpie = $this->simplepie;
|
161 |
+
else :
|
162 |
+
$this->magpie = new MagpieFromSimplePie($this->simplepie);
|
163 |
+
endif;
|
164 |
+
|
165 |
$new_count = NULL;
|
166 |
|
167 |
$resume = FeedWordPress::affirmative($this->settings, 'update/unfinished');
|
173 |
$processed = array();
|
174 |
endif;
|
175 |
|
176 |
+
if (is_wp_error($this->simplepie)) :
|
177 |
+
$new_count = $this->simplepie;
|
178 |
+
elseif (is_object($this->simplepie)) :
|
179 |
$new_count = array('new' => 0, 'updated' => 0);
|
180 |
|
181 |
# -- Update Link metadata live from feed
|
210 |
$this->settings['update/timed'] = 'feed';
|
211 |
else :
|
212 |
// spread out over a time interval for staggered updates
|
213 |
+
$updateWindow = $this->setting(
|
214 |
+
'update/window',
|
215 |
+
'update_window',
|
216 |
+
DEFAULT_UPDATE_PERIOD
|
217 |
+
);
|
|
|
218 |
if (!is_numeric($updateWindow) or ($updateWindow < 1)) :
|
219 |
$updateWindow = DEFAULT_UPDATE_PERIOD;
|
220 |
endif;
|
241 |
SET $update_set
|
242 |
WHERE link_id='$this->id'
|
243 |
");
|
244 |
+
do_action('update_syndicated_feed', $this->id, $this);
|
245 |
|
246 |
# -- Add new posts from feed and update any updated posts
|
247 |
$crashed = false;
|
248 |
|
249 |
+
$posts = apply_filters(
|
250 |
+
'syndicated_feed_items',
|
251 |
+
$this->magpie->originals,
|
252 |
+
$this
|
253 |
+
);
|
254 |
+
if (is_array($posts)) :
|
255 |
+
foreach ($posts as $key => $original) :
|
256 |
+
$item = $this->magpie->items[$key];
|
257 |
+
$post = new SyndicatedPost(array(
|
258 |
+
'simplepie' => $original,
|
259 |
+
'magpie' => $item,
|
260 |
+
), $this);
|
261 |
+
|
262 |
if (!$resume or !in_array(trim($post->guid()), $processed)) :
|
263 |
$processed[] = $post->guid();
|
264 |
if (!$post->filtered()) :
|
271 |
break;
|
272 |
endif;
|
273 |
endif;
|
274 |
+
unset($post);
|
275 |
endforeach;
|
276 |
endif;
|
277 |
+
$suffix = ($crashed ? 'crashed' : 'completed');
|
278 |
+
do_action('update_syndicated_feed_items', $this->id, $this);
|
279 |
+
do_action("update_syndicated_feed_items_${suffix}", $this->id, $this);
|
280 |
+
|
281 |
// Copy back any changes to feed settings made in the course of updating (e.g. new author rules)
|
282 |
$to_notes = $this->settings;
|
283 |
|
294 |
SET $update_set
|
295 |
WHERE link_id='$this->id'
|
296 |
");
|
297 |
+
|
298 |
+
do_action("update_syndicated_feed_completed", $this->id, $this);
|
299 |
endif;
|
300 |
|
301 |
return $new_count;
|
398 |
function save_settings ($reload = false) {
|
399 |
global $wpdb;
|
400 |
|
401 |
+
// Save channel-level meta-data
|
402 |
+
foreach (array('link_name', 'link_description', 'link_url') as $what) :
|
403 |
+
$alter[] = "{$what} = '".$wpdb->escape($this->link->{$what})."'";
|
404 |
+
endforeach;
|
405 |
+
|
406 |
+
// Save settings to the notes field
|
407 |
+
$alter[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
|
408 |
+
|
409 |
+
// Update the properties of the link from settings changes, etc.
|
410 |
+
$update_set = implode(", ", $alter);
|
411 |
+
|
412 |
$result = $wpdb->query("
|
413 |
UPDATE $wpdb->links
|
414 |
SET $update_set
|
416 |
");
|
417 |
|
418 |
if ($reload) :
|
419 |
+
// force reload of link information from DB
|
420 |
if (function_exists('clean_bookmark_cache')) :
|
421 |
clean_bookmark_cache($this->id);
|
422 |
endif;
|
438 |
$ret = $this->settings[$name];
|
439 |
endif;
|
440 |
|
441 |
+
$no_value = (
|
442 |
+
is_null($ret)
|
443 |
+
or (is_string($ret) and strtolower($ret)=='default')
|
444 |
+
);
|
445 |
+
|
446 |
+
if ($no_value and !is_null($fallback_global)) :
|
447 |
$ret = get_option('feedwordpress_'.$fallback_global, /*default=*/ NULL);
|
448 |
endif;
|
449 |
|
450 |
+
$no_value = (
|
451 |
+
is_null($ret)
|
452 |
+
or (is_string($ret) and strtolower($ret)=='default')
|
453 |
+
);
|
454 |
+
|
455 |
+
if ($no_value and !is_null($fallback_value)) :
|
456 |
$ret = $fallback_value;
|
457 |
endif;
|
458 |
return $ret;
|
syndicatedpost.class.php
CHANGED
@@ -1,38 +1,95 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
class SyndicatedPost {
|
3 |
-
var $item = null;
|
4 |
-
|
|
|
5 |
var $link = null;
|
6 |
var $feed = null;
|
7 |
var $feedmeta = null;
|
8 |
|
|
|
|
|
9 |
var $post = array ();
|
10 |
|
11 |
var $_freshness = null;
|
12 |
var $_wp_id = null;
|
13 |
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
global $wpdb;
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
-
#
|
22 |
-
#
|
23 |
-
#
|
24 |
-
#
|
25 |
-
# the board here.
|
26 |
#
|
27 |
-
#
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
30 |
|
31 |
-
$
|
32 |
-
$this->
|
33 |
|
34 |
-
|
35 |
$this->item = apply_filters('syndicated_item', $this->item, $this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
# Filters can halt further processing by returning NULL
|
38 |
if (is_null($this->item)) :
|
@@ -43,59 +100,39 @@ class SyndicatedPost {
|
|
43 |
# of insertion, not here, to avoid double-escaping and
|
44 |
# to avoid screwing with syndicated_post filters
|
45 |
|
46 |
-
$this->post['post_title'] = apply_filters(
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
// ID for the author in SyndicatedPost::add()
|
51 |
-
$this->post['named']['author'] = apply_filters('syndicated_item_author', $this->author(), $this);
|
52 |
-
|
53 |
-
# Identify content and sanitize it.
|
54 |
-
# ---------------------------------
|
55 |
-
if (isset($this->item['atom_content'])) :
|
56 |
-
$content = $this->item['atom_content'];
|
57 |
-
elseif (isset($this->item['xhtml']['body'])) :
|
58 |
-
$content = $this->item['xhtml']['body'];
|
59 |
-
elseif (isset($this->item['xhtml']['div'])) :
|
60 |
-
$content = $this->item['xhtml']['div'];
|
61 |
-
elseif (isset($this->item['content']['encoded']) and $this->item['content']['encoded']):
|
62 |
-
$content = $this->item['content']['encoded'];
|
63 |
-
else:
|
64 |
-
$content = $this->item['description'];
|
65 |
-
endif;
|
66 |
-
$this->post['post_content'] = apply_filters('syndicated_item_content', $content, $this);
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
$excerpt = substr($excerpt,0,252).'...';
|
76 |
-
endif;
|
77 |
-
endif;
|
78 |
-
$excerpt = apply_filters('syndicated_item_excerpt', $excerpt, $this);
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
if (!is_null($excerpt)):
|
81 |
$this->post['post_excerpt'] = $excerpt;
|
82 |
endif;
|
83 |
|
84 |
-
// This is unnecessary if we use wp_insert_post
|
85 |
-
if (!$this->use_api('wp_insert_post')) :
|
86 |
-
$this->post['post_name'] = sanitize_title($this->post['post_title']);
|
87 |
-
endif;
|
88 |
-
|
89 |
$this->post['epoch']['issued'] = apply_filters('syndicated_item_published', $this->published(), $this);
|
90 |
$this->post['epoch']['created'] = apply_filters('syndicated_item_created', $this->created(), $this);
|
91 |
$this->post['epoch']['modified'] = apply_filters('syndicated_item_updated', $this->updated(), $this);
|
92 |
|
93 |
// Dealing with timestamps in WordPress is so fucking fucked.
|
94 |
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
95 |
-
$this->post['post_date'] = gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
96 |
-
$this->post['post_modified'] = gmdate('Y-m-d H:i:s', $this->updated() + $offset);
|
97 |
-
$this->post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $this->published());
|
98 |
-
$this->post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $this->updated());
|
99 |
|
100 |
// Use feed-level preferences or the global default.
|
101 |
$this->post['post_status'] = $this->link->syndicated_status('post', 'publish');
|
@@ -121,18 +158,47 @@ class SyndicatedPost {
|
|
121 |
if (!is_array($custom_settings)) :
|
122 |
$custom_settings = array();
|
123 |
endif;
|
124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
// RSS 2.0 / Atom 1.0 enclosure support
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
endfor;
|
135 |
-
endif;
|
136 |
|
137 |
// In case you want to point back to the blog this was syndicated from
|
138 |
if (isset($this->feed->channel['title'])) :
|
@@ -157,27 +223,16 @@ class SyndicatedPost {
|
|
157 |
endif;
|
158 |
|
159 |
// Store information on human-readable and machine-readable comment URIs
|
160 |
-
if (isset($this->item['comments'])) :
|
161 |
-
$this->post['meta']['rss:comments'] = apply_filters('syndicated_item_comments', $this->item['comments']);
|
162 |
-
endif;
|
163 |
|
164 |
-
//
|
165 |
-
|
166 |
-
|
167 |
-
endif;
|
168 |
|
169 |
-
//
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
$currentElement = 'link_replies'.(($i > 1) ? '#'.$i : '');
|
175 |
-
if (isset($this->item[$currentElement.'@type'])
|
176 |
-
and preg_match("\007application/(atom|rss|rdf)\+xml\007i", $this->item[$currentElement.'@type'])) :
|
177 |
-
$this->post['meta']['wfw:commentRSS'] = apply_filters('syndicated_item_commentrss', $this->item[$currentElement]);
|
178 |
-
endif;
|
179 |
-
endfor;
|
180 |
-
endif;
|
181 |
|
182 |
// Store information to identify the feed that this came from
|
183 |
if (isset($this->feedmeta['link/uri'])) :
|
@@ -192,17 +247,7 @@ class SyndicatedPost {
|
|
192 |
endif;
|
193 |
|
194 |
// In case you want to know the external permalink...
|
195 |
-
|
196 |
-
$permalink = $this->item['link'];
|
197 |
-
|
198 |
-
// No <link> element. See if this feed has <guid isPermalink="true"> ....
|
199 |
-
elseif (isset($this->item['guid'])) :
|
200 |
-
if (isset($this->item['guid@ispermalink']) and strtolower(trim($this->item['guid@ispermalink'])) != 'false') :
|
201 |
-
$permalink = $this->item['guid'];
|
202 |
-
endif;
|
203 |
-
endif;
|
204 |
-
|
205 |
-
$this->post['meta']['syndication_permalink'] = apply_filters('syndicated_item_link', $permalink);
|
206 |
|
207 |
// Store a hash of the post content for checking whether something needs to be updated
|
208 |
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
@@ -253,1050 +298,1397 @@ class SyndicatedPost {
|
|
253 |
endif;
|
254 |
$this->post['tags_input'] = apply_filters('syndicated_item_tags', $this->post['tags_input'], $this);
|
255 |
endif;
|
256 |
-
}
|
257 |
|
258 |
-
|
259 |
-
|
260 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
|
262 |
-
|
263 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
|
|
284 |
else :
|
285 |
-
$
|
286 |
endif;
|
287 |
|
288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
$
|
295 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
296 |
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
endif;
|
321 |
endif;
|
322 |
endif;
|
323 |
-
return $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
}
|
325 |
|
326 |
-
function
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
|
|
333 |
endif;
|
334 |
-
return $this->_wp_id;
|
335 |
-
}
|
336 |
|
337 |
-
|
338 |
-
|
|
|
339 |
|
340 |
-
|
341 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
endif;
|
343 |
|
344 |
-
$
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
);
|
350 |
-
|
351 |
-
if (is_null($this->post['post_author'])) :
|
352 |
-
$this->post = NULL;
|
353 |
-
endif;
|
354 |
endif;
|
355 |
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
$
|
360 |
-
FeedWordPress::on_unfamiliar('category', $this->post['named']['unfamiliar']['category']),
|
361 |
-
/*tags_too=*/ true
|
362 |
-
);
|
363 |
-
|
364 |
-
$this->post['post_category'] = $pcats;
|
365 |
-
$this->post['tags_input'] = array_merge($this->post['tags_input'], $ptags);
|
366 |
-
|
367 |
-
if (is_null($this->post['post_category'])) :
|
368 |
-
// filter mode on, no matching categories; drop the post
|
369 |
-
$this->post = NULL;
|
370 |
else :
|
371 |
-
|
372 |
-
$this->post['post_category'] = array_merge (
|
373 |
-
$this->post['post_category'],
|
374 |
-
$this->category_ids (
|
375 |
-
$this->post['named']['preset/category'],
|
376 |
-
'default'
|
377 |
-
)
|
378 |
-
);
|
379 |
-
|
380 |
-
if (count($this->post['post_category']) < 1) :
|
381 |
-
$this->post['post_category'][] = 1; // Default to category 1 ("Uncategorized" / "General") if nothing else
|
382 |
-
endif;
|
383 |
endif;
|
384 |
endif;
|
385 |
|
386 |
-
|
387 |
-
|
388 |
-
$this->post = apply_filters('syndicated_post', $this->post, $this);
|
389 |
-
endif;
|
390 |
-
|
391 |
-
if (!$this->filtered() and $freshness == 2) :
|
392 |
-
// The item has not yet been added. So let's add it.
|
393 |
-
$this->insert_new();
|
394 |
-
$this->add_rss_meta();
|
395 |
-
do_action('post_syndicated_item', $this->wp_id(), $this);
|
396 |
|
397 |
-
|
398 |
-
|
399 |
-
$this->post['ID'] = $this->wp_id();
|
400 |
-
$this->update_existing();
|
401 |
-
$this->add_rss_meta();
|
402 |
-
do_action('update_syndicated_item', $this->wp_id(), $this);
|
403 |
|
404 |
-
|
405 |
-
|
406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
endif;
|
408 |
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
$dbpost = $this->normalize_post(/*new=*/ true);
|
416 |
-
if (!is_null($dbpost)) :
|
417 |
-
if ($this->use_api('wp_insert_post')) :
|
418 |
-
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
419 |
-
|
420 |
-
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
421 |
-
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
422 |
-
|
423 |
-
// Kludge to prevent kses filters from stripping the
|
424 |
-
// content of posts when updating without a logged in
|
425 |
-
// user who has `unfiltered_html` capability.
|
426 |
-
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
427 |
-
|
428 |
-
$this->_wp_id = wp_insert_post($dbpost);
|
429 |
-
|
430 |
-
// Turn off ridiculous fucking kludges #1 and #2
|
431 |
-
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
432 |
-
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
433 |
-
|
434 |
-
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
435 |
-
|
436 |
-
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
437 |
-
// *still* offers no way to use a guid of your choice,
|
438 |
-
// and munges your post modified timestamp, too.
|
439 |
-
$result = $wpdb->query("
|
440 |
-
UPDATE $wpdb->posts
|
441 |
-
SET
|
442 |
-
guid='{$dbpost['guid']}',
|
443 |
-
post_modified='{$dbpost['post_modified']}',
|
444 |
-
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
445 |
-
WHERE ID='{$this->_wp_id}'
|
446 |
-
");
|
447 |
-
else :
|
448 |
-
# The right way to do this is the above. But, alas,
|
449 |
-
# in earlier versions of WordPress, wp_insert_post has
|
450 |
-
# too much behavior (mainly related to pings) that can't
|
451 |
-
# be overridden. In WordPress 1.5, it's enough of a
|
452 |
-
# resource hog to make PHP segfault after inserting
|
453 |
-
# 50-100 posts. This can get pretty annoying, especially
|
454 |
-
# if you are trying to update your feeds for the first
|
455 |
-
# time.
|
456 |
-
|
457 |
-
$result = $wpdb->query("
|
458 |
-
INSERT INTO $wpdb->posts
|
459 |
-
SET
|
460 |
-
guid = '{$dbpost['guid']}',
|
461 |
-
post_author = '{$dbpost['post_author']}',
|
462 |
-
post_date = '{$dbpost['post_date']}',
|
463 |
-
post_date_gmt = '{$dbpost['post_date_gmt']}',
|
464 |
-
post_content = '{$dbpost['post_content']}',"
|
465 |
-
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
466 |
-
post_title = '{$dbpost['post_title']}',
|
467 |
-
post_name = '{$dbpost['post_name']}',
|
468 |
-
post_modified = '{$dbpost['post_modified']}',
|
469 |
-
post_modified_gmt = '{$dbpost['post_modified_gmt']}',
|
470 |
-
comment_status = '{$dbpost['comment_status']}',
|
471 |
-
ping_status = '{$dbpost['ping_status']}',
|
472 |
-
post_status = '{$dbpost['post_status']}'
|
473 |
-
");
|
474 |
-
$this->_wp_id = $wpdb->insert_id;
|
475 |
-
|
476 |
-
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
477 |
-
|
478 |
-
// WordPress 1.5.x - 2.0.x
|
479 |
-
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
480 |
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
do_action('publish_post', $this->_wp_id);
|
488 |
endif;
|
489 |
endif;
|
490 |
-
} /* SyndicatedPost::insert_new() */
|
491 |
|
492 |
-
|
493 |
-
|
494 |
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
if ($this->use_api('wp_insert_post')) :
|
499 |
-
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
500 |
-
|
501 |
-
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
502 |
-
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
503 |
-
|
504 |
-
// Kludge to prevent kses filters from stripping the
|
505 |
-
// content of posts when updating without a logged in
|
506 |
-
// user who has `unfiltered_html` capability.
|
507 |
-
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
508 |
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
516 |
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
$
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
WHERE ID='{$this->_wp_id}'
|
533 |
-
");
|
534 |
else :
|
|
|
|
|
|
|
|
|
|
|
535 |
|
536 |
-
|
537 |
-
|
538 |
-
SET
|
539 |
-
post_author = '{$dbpost['post_author']}',
|
540 |
-
post_content = '{$dbpost['post_content']}',"
|
541 |
-
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
542 |
-
post_title = '{$dbpost['post_title']}',
|
543 |
-
post_name = '{$dbpost['post_name']}',
|
544 |
-
post_modified = '{$dbpost['post_modified']}',
|
545 |
-
post_modified_gmt = '{$dbpost['post_modified_gmt']}'
|
546 |
-
WHERE guid='{$dbpost['guid']}'
|
547 |
-
");
|
548 |
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
556 |
else :
|
557 |
-
|
558 |
endif;
|
559 |
-
|
560 |
-
// Since we are not going through official channels, we need to
|
561 |
-
// manually tell WordPress that we've published a new post.
|
562 |
-
// We need to make sure to do this in order for FeedWordPress
|
563 |
-
// to play well with the staticize-reloaded plugin (something
|
564 |
-
// that a large aggregator website is going to *want* to be
|
565 |
-
// able to use).
|
566 |
-
do_action('edit_post', $this->post['ID']);
|
567 |
endif;
|
|
|
|
|
568 |
endif;
|
569 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
570 |
|
571 |
/**
|
572 |
-
* SyndicatedPost::
|
|
|
|
|
573 |
*
|
574 |
-
* @param
|
575 |
-
*
|
|
|
|
|
|
|
576 |
*/
|
577 |
-
function
|
578 |
-
|
579 |
|
580 |
-
|
|
|
|
|
581 |
|
582 |
-
//
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
590 |
|
591 |
-
if (strlen($out['post_title'].$out['post_content'].$out['post_excerpt']) == 0) :
|
592 |
-
// FIXME: Option for filtering out empty posts
|
593 |
-
endif;
|
594 |
-
if (strlen($out['post_title'])==0) :
|
595 |
-
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
596 |
-
$out['post_title'] =
|
597 |
-
$this->post['meta']['syndication_source']
|
598 |
-
.' '.gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
599 |
-
// FIXME: Option for what to fill a blank title with...
|
600 |
endif;
|
601 |
|
602 |
-
|
603 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
604 |
|
605 |
/**
|
606 |
-
* SyndicatedPost::
|
|
|
607 |
*
|
608 |
-
* @param
|
609 |
-
*
|
|
|
|
|
|
|
610 |
*/
|
611 |
-
function
|
612 |
-
|
613 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
614 |
|
615 |
-
//
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
"\$dbpost" => $dbpost,
|
622 |
-
"\$this" => $this
|
623 |
-
),
|
624 |
-
/*line # =*/ __LINE__
|
625 |
-
);
|
626 |
endif;
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
* syndicated post.
|
633 |
-
*
|
634 |
-
* In their infinite wisdom, the WordPress coders have made it completely
|
635 |
-
* impossible for a plugin that uses wp_insert_post() to set certain
|
636 |
-
* meta-data (such as the author) when you store an old revision of an
|
637 |
-
* updated post. Instead, it uses the WordPress defaults (= currently
|
638 |
-
* active user ID if the process is running with a user logged in, or
|
639 |
-
* = #0 if there is no user logged in). This results in bogus authorship
|
640 |
-
* data for revisions that are syndicated from off the feed, unless we
|
641 |
-
* use a ridiculous kludge like this to end-run the munging of meta-data
|
642 |
-
* by _wp_put_post_revision.
|
643 |
-
*
|
644 |
-
* @param int $revision_id The revision ID to fix up meta-data
|
645 |
-
*/
|
646 |
-
function fix_revision_meta ($revision_id) {
|
647 |
-
global $wpdb;
|
648 |
|
649 |
-
|
|
|
650 |
|
651 |
-
|
652 |
-
$
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
* gets a wp_insert_post() when current_user_can('unfiltered_html') is
|
665 |
-
* false, it will run the content of the post through a kses function
|
666 |
-
* that strips out lots of HTML tags -- notably <object> and some others.
|
667 |
-
* This causes problems for syndicating (for example) feeds that contain
|
668 |
-
* YouTube videos. It also produces an unexpected asymmetry between
|
669 |
-
* automatically-initiated updates and updates initiated manually from
|
670 |
-
* the WordPress Dashboard (which are usually initiated under the
|
671 |
-
* credentials of a logged-in admin, and so don't get run through the
|
672 |
-
* kses function). So, to avoid the whole mess, what we do here is
|
673 |
-
* just forcibly disable the kses munging for a single syndicated post,
|
674 |
-
* by restoring the contents of the `post_content` field.
|
675 |
-
*
|
676 |
-
* @param string $content The content of the post, after other filters have gotten to it
|
677 |
-
* @return string The original content of the post, before other filters had a chance to munge it.
|
678 |
-
*/
|
679 |
-
function avoid_kses_munge ($content) {
|
680 |
-
global $wpdb;
|
681 |
-
return $wpdb->escape($this->post['post_content']);
|
682 |
-
}
|
683 |
-
|
684 |
-
// SyndicatedPost::add_rss_meta: adds interesting meta-data to each entry
|
685 |
-
// using the space for custom keys. The set of keys and values to add is
|
686 |
-
// specified by the keys and values of $post['meta']. This is used to
|
687 |
-
// store anything that the WordPress user might want to access from a
|
688 |
-
// template concerning the post's original source that isn't provided
|
689 |
-
// for by standard WP meta-data (i.e., any interesting data about the
|
690 |
-
// syndicated post other than author, title, timestamp, categories, and
|
691 |
-
// guid). It's also used to hook into WordPress's support for
|
692 |
-
// enclosures.
|
693 |
-
function add_rss_meta () {
|
694 |
-
global $wpdb;
|
695 |
-
if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
|
696 |
-
$postId = $this->wp_id();
|
697 |
-
|
698 |
-
// Aggregated posts should NOT send out pingbacks.
|
699 |
-
// WordPress 2.1-2.2 claim you can tell them not to
|
700 |
-
// using $post_pingback, but they don't listen, so we
|
701 |
-
// make sure here.
|
702 |
-
$result = $wpdb->query("
|
703 |
-
DELETE FROM $wpdb->postmeta
|
704 |
-
WHERE post_id='$postId' AND meta_key='_pingme'
|
705 |
-
");
|
706 |
-
|
707 |
-
foreach ( $this->post['meta'] as $key => $values ) :
|
708 |
|
709 |
-
|
|
|
710 |
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
717 |
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
endforeach;
|
737 |
endif;
|
738 |
-
|
|
|
739 |
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
global $wpdb;
|
744 |
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
749 |
|
750 |
-
|
751 |
-
if ($match_author_by_email and !FeedWordPress::is_null_email($email)) :
|
752 |
-
$test_email = $email;
|
753 |
-
else :
|
754 |
-
$test_email = NULL;
|
755 |
-
endif;
|
756 |
|
757 |
-
|
758 |
-
$
|
759 |
-
$
|
|
|
|
|
760 |
|
761 |
-
|
762 |
-
$
|
|
|
|
|
|
|
|
|
763 |
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
|
|
769 |
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
|
|
|
|
|
|
|
|
775 |
endif;
|
776 |
-
|
777 |
-
// User name is mapped to a particular author. If that author ID exists, use it.
|
778 |
-
if (is_numeric($author_rule) and get_userdata((int) $author_rule)) :
|
779 |
-
$id = (int) $author_rule;
|
780 |
-
|
781 |
-
// User name is filtered out
|
782 |
-
elseif ('filter' == $author_rule) :
|
783 |
-
$id = NULL;
|
784 |
|
785 |
-
|
786 |
-
|
787 |
|
788 |
-
|
789 |
-
|
|
|
|
|
|
|
790 |
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
TRIM(LCASE(user_login)) = TRIM(LCASE('$login'))
|
796 |
-
OR (
|
797 |
-
LENGTH(TRIM(LCASE(user_email))) > 0
|
798 |
-
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
799 |
-
)
|
800 |
-
OR TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author'))
|
801 |
-
");
|
802 |
-
|
803 |
-
// If that fails, look for aliases in the user meta data table
|
804 |
-
if (is_null($id)) :
|
805 |
-
$id = $wpdb->get_var(
|
806 |
-
"SELECT user_id FROM $wpdb->usermeta
|
807 |
-
WHERE
|
808 |
-
(meta_key = 'description' AND TRIM(LCASE(meta_value)) = TRIM(LCASE('$author')))
|
809 |
-
OR (
|
810 |
-
meta_key = 'description'
|
811 |
-
AND TRIM(LCASE(meta_value))
|
812 |
-
RLIKE CONCAT(
|
813 |
-
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
814 |
-
TRIM(LCASE('$reg_author')),
|
815 |
-
'( |\\t|\\r)*(\\n|\$)'
|
816 |
-
)
|
817 |
-
)
|
818 |
-
");
|
819 |
-
endif;
|
820 |
-
|
821 |
-
#-- WordPress 1.5.x
|
822 |
-
else :
|
823 |
-
$id = $wpdb->get_var(
|
824 |
-
"SELECT ID from $wpdb->users
|
825 |
-
WHERE
|
826 |
-
TRIM(LCASE(user_login)) = TRIM(LCASE('$login')) OR
|
827 |
-
(
|
828 |
-
LENGTH(TRIM(LCASE(user_email))) > 0
|
829 |
-
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
830 |
-
) OR
|
831 |
-
TRIM(LCASE(user_firstname)) = TRIM(LCASE('$author')) OR
|
832 |
-
TRIM(LCASE(user_nickname)) = TRIM(LCASE('$author')) OR
|
833 |
-
TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author')) OR
|
834 |
-
TRIM(LCASE(user_description)) = TRIM(LCASE('$author')) OR
|
835 |
-
(
|
836 |
-
LOWER(user_description)
|
837 |
-
RLIKE CONCAT(
|
838 |
-
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
839 |
-
LCASE('$reg_author'),
|
840 |
-
'( |\\t|\\r)*(\\n|\$)'
|
841 |
-
)
|
842 |
-
)
|
843 |
-
");
|
844 |
|
845 |
-
|
|
|
|
|
|
|
|
|
|
|
846 |
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
|
|
|
|
|
|
|
|
851 |
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
$userdata['user_nicename'] = $nice_author;
|
856 |
-
$userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up
|
857 |
-
$userdata['user_email'] = $email;
|
858 |
-
$userdata['user_url'] = $url;
|
859 |
-
$userdata['display_name'] = $author;
|
860 |
-
|
861 |
-
$id = wp_insert_user($userdata);
|
862 |
-
elseif (is_numeric($unfamiliar_author) and get_userdata((int) $unfamiliar_author)) :
|
863 |
-
$id = (int) $unfamiliar_author;
|
864 |
-
elseif ($unfamiliar_author === 'default') :
|
865 |
-
$id = 1;
|
866 |
-
endif;
|
867 |
-
endif;
|
868 |
-
endif;
|
869 |
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
|
|
|
|
|
|
|
|
875 |
|
876 |
-
|
877 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
878 |
global $wpdb;
|
879 |
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
$cats = array_map('trim', $cats);
|
887 |
|
888 |
-
|
|
|
|
|
|
|
889 |
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
$
|
894 |
-
if (
|
895 |
-
$
|
896 |
-
|
897 |
-
|
|
|
898 |
endif;
|
899 |
-
|
900 |
-
|
901 |
-
|
|
|
|
|
902 |
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
WHERE
|
913 |
-
LOWER(description) RLIKE
|
914 |
-
CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)')"
|
915 |
-
)) :
|
916 |
-
foreach ($results AS $term) :
|
917 |
-
$cat_ids[] = (int) $term->term_id;
|
918 |
-
endforeach;
|
919 |
-
elseif ('tag'==$unfamiliar_category) :
|
920 |
-
$tags[] = $cat_name;
|
921 |
-
elseif ('create'===$unfamiliar_category) :
|
922 |
-
$term = wp_insert_term($cat_name, 'category');
|
923 |
-
if (is_wp_error($term)) :
|
924 |
-
FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__);
|
925 |
-
else :
|
926 |
-
$cat_ids[] = $term['term_id'];
|
927 |
-
endif;
|
928 |
-
endif;
|
929 |
|
930 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
931 |
else :
|
932 |
-
$
|
933 |
-
|
934 |
-
FROM $wpdb->categories
|
935 |
-
WHERE
|
936 |
-
(LOWER(cat_name) = LOWER('$esc'))
|
937 |
-
OR (LOWER(category_description)
|
938 |
-
RLIKE CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)'))
|
939 |
-
");
|
940 |
-
if ($results) :
|
941 |
-
foreach ($results as $term) :
|
942 |
-
$cat_ids[] = (int) $term->cat_ID;
|
943 |
-
endforeach;
|
944 |
-
elseif ('create'===$unfamiliar_category) :
|
945 |
-
if (function_exists('wp_insert_category')) :
|
946 |
-
$cat_id = wp_insert_category(array('cat_name' => $esc));
|
947 |
-
// And into the database we go.
|
948 |
-
else :
|
949 |
-
$nice_kitty = sanitize_title($cat_name);
|
950 |
-
$wpdb->query(sprintf("
|
951 |
-
INSERT INTO $wpdb->categories
|
952 |
-
SET
|
953 |
-
cat_name='%s',
|
954 |
-
category_nicename='%s'
|
955 |
-
", $esc, $nice_kitty
|
956 |
-
));
|
957 |
-
$cat_id = $wpdb->insert_id;
|
958 |
-
endif;
|
959 |
-
$cat_ids[] = $cat_id;
|
960 |
-
endif;
|
961 |
endif;
|
962 |
endif;
|
963 |
-
endforeach;
|
964 |
-
|
965 |
-
if ((count($cat_ids) == 0) and ($unfamiliar_category === 'filter')) :
|
966 |
-
$cat_ids = NULL; // Drop the post
|
967 |
-
else :
|
968 |
-
$cat_ids = array_unique($cat_ids);
|
969 |
-
endif;
|
970 |
-
|
971 |
-
if ($tags_too) : $ret = array($cat_ids, $tags);
|
972 |
-
else : $ret = $cat_ids;
|
973 |
endif;
|
|
|
|
|
974 |
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
function use_api ($tag) {
|
979 |
-
global $wp_db_version;
|
980 |
-
switch ($tag) :
|
981 |
-
case 'wp_insert_post':
|
982 |
-
// Before 2.2, wp_insert_post does too much of the wrong stuff to use it
|
983 |
-
// In 1.5 it was such a resource hog it would make PHP segfault on big updates
|
984 |
-
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_21);
|
985 |
-
break;
|
986 |
-
case 'post_status_pending':
|
987 |
-
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_23);
|
988 |
-
break;
|
989 |
-
endswitch;
|
990 |
-
return $ret;
|
991 |
-
} // function SyndicatedPost::use_api ()
|
992 |
-
|
993 |
-
#### EXTRACT DATA FROM FEED ITEM ####
|
994 |
|
995 |
-
function
|
996 |
-
$
|
997 |
-
|
998 |
-
$epoch = @parse_w3cdtf($this->item['dc']['created']);
|
999 |
-
elseif (isset($this->item['dcterms']['created'])) :
|
1000 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['created']);
|
1001 |
-
elseif (isset($this->item['created'])): // Atom 0.3
|
1002 |
-
$epoch = @parse_w3cdtf($this->item['created']);
|
1003 |
endif;
|
1004 |
-
|
|
|
|
|
|
|
|
|
1005 |
}
|
1006 |
-
function published ($fallback = true) {
|
1007 |
-
$epoch = null;
|
1008 |
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
$epoch = @parse_w3cdtf($this->item['dc']['date']);
|
1015 |
-
elseif (isset($this->item['dcterms']['issued'])) : // Dublin Core extensions
|
1016 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['issued']);
|
1017 |
-
elseif (isset($this->item['published'])) : // Atom 1.0
|
1018 |
-
$epoch = @parse_w3cdtf($this->item['published']);
|
1019 |
-
elseif (isset($this->item['issued'])): // Atom 0.3
|
1020 |
-
$epoch = @parse_w3cdtf($this->item['issued']);
|
1021 |
-
elseif (isset($this->item['pubdate'])): // RSS 2.0
|
1022 |
-
$epoch = strtotime($this->item['pubdate']);
|
1023 |
-
elseif ($fallback) : // Fall back to <updated> / <modified> if present
|
1024 |
-
$epoch = $this->updated(/*fallback=*/ false);
|
1025 |
endif;
|
1026 |
|
1027 |
-
|
1028 |
-
if (
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
endif;
|
1034 |
-
endif;
|
1035 |
-
|
1036 |
-
return $epoch;
|
1037 |
-
}
|
1038 |
-
function updated ($fallback = true, $default = -1) {
|
1039 |
-
$epoch = null;
|
1040 |
|
1041 |
-
|
1042 |
-
|
1043 |
-
# available, then we'll try to get the time of publication.
|
1044 |
-
if (isset($this->item['dc']['modified'])) : // Not really correct
|
1045 |
-
$epoch = @parse_w3cdtf($this->item['dc']['modified']);
|
1046 |
-
elseif (isset($this->item['dcterms']['modified'])) : // Dublin Core extensions
|
1047 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['modified']);
|
1048 |
-
elseif (isset($this->item['modified'])): // Atom 0.3
|
1049 |
-
$epoch = @parse_w3cdtf($this->item['modified']);
|
1050 |
-
elseif (isset($this->item['updated'])): // Atom 1.0
|
1051 |
-
$epoch = @parse_w3cdtf($this->item['updated']);
|
1052 |
-
elseif ($fallback) : // Fall back to issued / dc:date
|
1053 |
-
$epoch = $this->published(/*fallback=*/ false, /*default=*/ $default);
|
1054 |
-
endif;
|
1055 |
-
|
1056 |
-
# If everything failed, then default to the current time.
|
1057 |
-
if (is_null($epoch)) :
|
1058 |
-
if (-1 == $default) :
|
1059 |
-
$epoch = time();
|
1060 |
-
else :
|
1061 |
-
$epoch = $default;
|
1062 |
endif;
|
1063 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1064 |
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
function update_hash () {
|
1069 |
-
return md5(serialize($this->item));
|
1070 |
-
}
|
1071 |
-
|
1072 |
-
function guid () {
|
1073 |
-
$guid = null;
|
1074 |
-
if (isset($this->item['id'])): // Atom 0.3 / 1.0
|
1075 |
-
$guid = $this->item['id'];
|
1076 |
-
elseif (isset($this->item['atom']['id'])) : // Namespaced Atom
|
1077 |
-
$guid = $this->item['atom']['id'];
|
1078 |
-
elseif (isset($this->item['guid'])) : // RSS 2.0
|
1079 |
-
$guid = $this->item['guid'];
|
1080 |
-
elseif (isset($this->item['dc']['identifier'])) :// yeah, right
|
1081 |
-
$guid = $this->item['dc']['identifier'];
|
1082 |
-
else :
|
1083 |
-
// The feed does not seem to have provided us with a
|
1084 |
-
// unique identifier, so we'll have to cobble together
|
1085 |
-
// a tag: URI that might work for us. The base of the
|
1086 |
-
// URI will be the host name of the feed source ...
|
1087 |
-
$bits = parse_url($this->feedmeta['link/uri']);
|
1088 |
-
$guid = 'tag:'.$bits['host'];
|
1089 |
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
// generate dates of creation, she probably also was
|
1094 |
-
// conscientious enough to generate unique identifiers.)
|
1095 |
-
if (!is_null($this->created())) :
|
1096 |
-
$guid .= '://post.'.date('YmdHis', $this->created());
|
1097 |
-
|
1098 |
-
// Otherwise, use both the URI of the item, *and* the
|
1099 |
-
// item's title. We have to use both because titles are
|
1100 |
-
// often not unique, and sometimes links aren't unique
|
1101 |
-
// either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
|
1102 |
-
// some podcasts). But it's rare to have *both* the same
|
1103 |
-
// title *and* the same link for two different items. So
|
1104 |
-
// this is about the best we can do.
|
1105 |
else :
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
elseif (isset($this->item['dc']['creator'])):
|
1118 |
-
$author['name'] = $this->item['dc']['creator'];
|
1119 |
-
elseif (isset($this->item['dc']['contributor'])):
|
1120 |
-
$author['name'] = $this->item['dc']['contributor'];
|
1121 |
-
elseif (isset($this->feed->channel['dc']['creator'])) :
|
1122 |
-
$author['name'] = $this->feed->channel['dc']['creator'];
|
1123 |
-
elseif (isset($this->feed->channel['dc']['contributor'])) :
|
1124 |
-
$author['name'] = $this->feed->channel['dc']['contributor'];
|
1125 |
-
elseif (isset($this->feed->channel['author_name'])) :
|
1126 |
-
$author['name'] = $this->feed->channel['author_name'];
|
1127 |
-
elseif ($this->feed->is_rss() and isset($this->item['author'])) :
|
1128 |
-
// The author element in RSS is allegedly an
|
1129 |
-
// e-mail address, but lots of people don't use
|
1130 |
-
// it that way. So let's make of it what we can.
|
1131 |
-
$author = parse_email_with_realname($this->item['author']);
|
1132 |
-
|
1133 |
-
if (!isset($author['name'])) :
|
1134 |
-
if (isset($author['email'])) :
|
1135 |
-
$author['name'] = $author['email'];
|
1136 |
-
else :
|
1137 |
-
$author['name'] = $this->feed->channel['title'];
|
1138 |
endif;
|
1139 |
endif;
|
1140 |
-
else :
|
1141 |
-
$author['name'] = $this->feed->channel['title'];
|
1142 |
endif;
|
1143 |
|
1144 |
-
if (
|
1145 |
-
$
|
1146 |
-
|
1147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1148 |
endif;
|
1149 |
|
1150 |
-
if
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
return $author;
|
1159 |
-
} // SyndicatedPost::author()
|
1160 |
-
|
1161 |
-
/**
|
1162 |
-
* SyndicatedPost::isTaggedAs: Test whether a feed item is
|
1163 |
-
* tagged / categorized with a given string. Case and leading and
|
1164 |
-
* trailing whitespace are ignored.
|
1165 |
-
*
|
1166 |
-
* @param string $tag Tag to check for
|
1167 |
-
*
|
1168 |
-
* @return bool Whether or not at least one of the categories / tags on
|
1169 |
-
* $this->item is set to $tag (modulo case and leading and trailing
|
1170 |
-
* whitespace)
|
1171 |
-
*/
|
1172 |
-
function isTaggedAs ($tag) {
|
1173 |
-
$desiredTag = strtolower(trim($tag)); // Normalize case and whitespace
|
1174 |
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
|
|
1178 |
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
$
|
1183 |
-
|
1184 |
-
// We REALLY shouldn't have the old and busted MagpieRSS, but in
|
1185 |
-
// case we do, it doesn't support multiple categories, but there
|
1186 |
-
// might still be a single value under the "category" index.
|
1187 |
-
elseif (isset($this->item['category'])) :
|
1188 |
-
$numberOfCategories = 1;
|
1189 |
|
1190 |
-
|
1191 |
else :
|
1192 |
-
$
|
1193 |
-
|
1194 |
endif;
|
1195 |
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
while ($currentCategoryNumber <= $numberOfCategories) :
|
1202 |
-
if ($desiredTag == strtolower(trim($this->item[$currentCategory]))) :
|
1203 |
-
$isSoTagged = true; // Got it!
|
1204 |
-
break;
|
1205 |
-
endif;
|
1206 |
-
|
1207 |
-
$currentCategoryNumber += 1;
|
1208 |
-
$currentCategory = 'category#'.$currentCategoryNumber;
|
1209 |
-
endwhile;
|
1210 |
-
|
1211 |
-
return $isSoTagged;
|
1212 |
-
} /* SyndicatedPost::isTaggedAs() */
|
1213 |
-
|
1214 |
-
var $uri_attrs = array (
|
1215 |
-
array('a', 'href'),
|
1216 |
-
array('applet', 'codebase'),
|
1217 |
-
array('area', 'href'),
|
1218 |
-
array('blockquote', 'cite'),
|
1219 |
-
array('body', 'background'),
|
1220 |
-
array('del', 'cite'),
|
1221 |
-
array('form', 'action'),
|
1222 |
-
array('frame', 'longdesc'),
|
1223 |
-
array('frame', 'src'),
|
1224 |
-
array('iframe', 'longdesc'),
|
1225 |
-
array('iframe', 'src'),
|
1226 |
-
array('head', 'profile'),
|
1227 |
-
array('img', 'longdesc'),
|
1228 |
-
array('img', 'src'),
|
1229 |
-
array('img', 'usemap'),
|
1230 |
-
array('input', 'src'),
|
1231 |
-
array('input', 'usemap'),
|
1232 |
-
array('ins', 'cite'),
|
1233 |
-
array('link', 'href'),
|
1234 |
-
array('object', 'classid'),
|
1235 |
-
array('object', 'codebase'),
|
1236 |
-
array('object', 'data'),
|
1237 |
-
array('object', 'usemap'),
|
1238 |
-
array('q', 'cite'),
|
1239 |
-
array('script', 'src')
|
1240 |
-
); /* var SyndicatedPost::$uri_attrs */
|
1241 |
-
|
1242 |
-
var $_base = null;
|
1243 |
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
# However, sometimes people do silly things, like putting
|
1255 |
-
# relative URIs out on a production RSS 2.0 feed or other feeds
|
1256 |
-
# with no good support for `xml:base`. So we'll do our best to
|
1257 |
-
# try to catch any remaining relative URIs and resolve them as
|
1258 |
-
# best we can.
|
1259 |
-
$obj->_base = $obj->item['link']; // Reset the base for resolving relative URIs
|
1260 |
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1269 |
endforeach;
|
1270 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1271 |
|
1272 |
-
|
1273 |
-
|
1274 |
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1280 |
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
|
|
1292 |
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1298 |
endforeach;
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1302 |
|
1 |
<?php
|
2 |
+
require_once(dirname(__FILE__).'/feedtime.class.php');
|
3 |
+
|
4 |
+
/**
|
5 |
+
* class SyndicatedPost: FeedWordPress uses to manage the conversion of
|
6 |
+
* incoming items from the feed parser into posts for the WordPress
|
7 |
+
* database. It contains several internal management methods primarily
|
8 |
+
* of interest to someone working on the FeedWordPress source, as well
|
9 |
+
* as some utility methods for extracting useful data from many
|
10 |
+
* different feed formats, which may be useful to FeedWordPress users
|
11 |
+
* who make use of feed data in PHP add-ons and filters.
|
12 |
+
*
|
13 |
+
* @version 2010.0528
|
14 |
+
*/
|
15 |
class SyndicatedPost {
|
16 |
+
var $item = null; // MagpieRSS representation
|
17 |
+
var $entry = null; // SimplePie_Item representation
|
18 |
+
|
19 |
var $link = null;
|
20 |
var $feed = null;
|
21 |
var $feedmeta = null;
|
22 |
|
23 |
+
var $xmlns = array ();
|
24 |
+
|
25 |
var $post = array ();
|
26 |
|
27 |
var $_freshness = null;
|
28 |
var $_wp_id = null;
|
29 |
|
30 |
+
/**
|
31 |
+
* SyndicatedPost constructor: Given a feed item and the source from
|
32 |
+
* which it was taken, prepare a post that can be inserted into the
|
33 |
+
* WordPress database on request, or updated in place if it has already
|
34 |
+
* been syndicated.
|
35 |
+
*
|
36 |
+
* @param array $item The item syndicated from the feed.
|
37 |
+
* @param SyndicatedLink $source The feed it was syndicated from.
|
38 |
+
*/
|
39 |
+
function SyndicatedPost ($item, $source) {
|
40 |
global $wpdb;
|
41 |
|
42 |
+
if (is_array($item)
|
43 |
+
and isset($item['simplepie'])
|
44 |
+
and isset($item['magpie'])) :
|
45 |
+
$this->entry = $item['simplepie'];
|
46 |
+
$this->item = $item['magpie'];
|
47 |
+
$item = $item['magpie'];
|
48 |
+
else :
|
49 |
+
$this->item = $item;
|
50 |
+
endif;
|
51 |
+
|
52 |
+
$this->link = $source;
|
53 |
+
$this->feed = $source->magpie;
|
54 |
+
$this->feedmeta = $source->settings;
|
55 |
+
|
56 |
+
# Dealing with namespaces can get so fucking fucked.
|
57 |
+
$this->xmlns['forward'] = $source->magpie->_XMLNS_FAMILIAR;
|
58 |
+
$this->xmlns['reverse'] = array();
|
59 |
+
foreach ($this->xmlns['forward'] as $url => $ns) :
|
60 |
+
if (!isset($this->xmlns['reverse'][$ns])) :
|
61 |
+
$this->xmlns['reverse'][$ns] = array();
|
62 |
+
endif;
|
63 |
+
$this->xmlns['reverse'][$ns][] = $url;
|
64 |
+
endforeach;
|
65 |
+
|
66 |
+
// Fucking SimplePie.
|
67 |
+
$this->xmlns['reverse']['rss'][] = '';
|
68 |
|
69 |
+
# These globals were originally an ugly kludge around a bug in
|
70 |
+
# apply_filters from WordPress 1.5. The bug was fixed in 1.5.1,
|
71 |
+
# and I sure hope at this point that nobody writing filters for
|
72 |
+
# FeedWordPress is still relying on them.
|
|
|
73 |
#
|
74 |
+
# Anyway, I hereby declare them DEPRECATED as of 8 February
|
75 |
+
# 2010. I'll probably remove the globals within 1-2 releases in
|
76 |
+
# the interests of code hygiene and memory usage. If you
|
77 |
+
# currently use them in your filters, I advise you switch off to
|
78 |
+
# accessing the public members SyndicatedPost::feed and
|
79 |
+
# SyndicatedPost::feedmeta.
|
80 |
|
81 |
+
global $fwp_channel, $fwp_feedmeta;
|
82 |
+
$fwp_channel = $this->feed; $fwp_feedmeta = $this->feedmeta;
|
83 |
|
84 |
+
// Trigger global syndicated_item filter.
|
85 |
$this->item = apply_filters('syndicated_item', $this->item, $this);
|
86 |
+
|
87 |
+
// Allow for feed-specific syndicated_item filters.
|
88 |
+
$this->item = apply_filters(
|
89 |
+
"syndicated_item_".$source->uri(),
|
90 |
+
$this->item,
|
91 |
+
$this
|
92 |
+
);
|
93 |
|
94 |
# Filters can halt further processing by returning NULL
|
95 |
if (is_null($this->item)) :
|
100 |
# of insertion, not here, to avoid double-escaping and
|
101 |
# to avoid screwing with syndicated_post filters
|
102 |
|
103 |
+
$this->post['post_title'] = apply_filters(
|
104 |
+
'syndicated_item_title',
|
105 |
+
$this->entry->get_title(), $this
|
106 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
+
$this->post['named']['author'] = apply_filters(
|
109 |
+
'syndicated_item_author',
|
110 |
+
$this->author(), $this
|
111 |
+
);
|
112 |
+
// This just gives us an alphanumeric name for the author.
|
113 |
+
// We look up (or create) the numeric ID for the author
|
114 |
+
// in SyndicatedPost::add().
|
|
|
|
|
|
|
|
|
115 |
|
116 |
+
$this->post['post_content'] = apply_filters(
|
117 |
+
'syndicated_item_content',
|
118 |
+
$this->content(), $this
|
119 |
+
);
|
120 |
+
|
121 |
+
$excerpt = apply_filters('syndicated_item_excerpt', $this->excerpt(), $this);
|
122 |
if (!is_null($excerpt)):
|
123 |
$this->post['post_excerpt'] = $excerpt;
|
124 |
endif;
|
125 |
|
|
|
|
|
|
|
|
|
|
|
126 |
$this->post['epoch']['issued'] = apply_filters('syndicated_item_published', $this->published(), $this);
|
127 |
$this->post['epoch']['created'] = apply_filters('syndicated_item_created', $this->created(), $this);
|
128 |
$this->post['epoch']['modified'] = apply_filters('syndicated_item_updated', $this->updated(), $this);
|
129 |
|
130 |
// Dealing with timestamps in WordPress is so fucking fucked.
|
131 |
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
132 |
+
$this->post['post_date'] = gmdate('Y-m-d H:i:s', $this->published(/*fallback=*/ true, /*default=*/ -1) + $offset);
|
133 |
+
$this->post['post_modified'] = gmdate('Y-m-d H:i:s', $this->updated(/*fallback=*/ true, /*default=*/ -1) + $offset);
|
134 |
+
$this->post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $this->published(/*fallback=*/ true, /*default=*/ -1));
|
135 |
+
$this->post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $this->updated(/*fallback=*/ true, /*default=*/ -1));
|
136 |
|
137 |
// Use feed-level preferences or the global default.
|
138 |
$this->post['post_status'] = $this->link->syndicated_status('post', 'publish');
|
158 |
if (!is_array($custom_settings)) :
|
159 |
$custom_settings = array();
|
160 |
endif;
|
161 |
+
|
162 |
+
$postMetaIn = array_merge($default_custom_settings, $custom_settings);
|
163 |
+
$postMetaOut = array();
|
164 |
+
|
165 |
+
// Big ugly fuckin loop to do any element substitutions
|
166 |
+
// that we may need.
|
167 |
+
foreach ($postMetaIn as $key => $values) :
|
168 |
+
if (is_string($values)) : $values = array($values); endif;
|
169 |
+
|
170 |
+
$postMetaOut[$key] = array();
|
171 |
+
foreach ($values as $value) :
|
172 |
+
if (preg_match('/\$\( ([^)]+) \)/x', $value, $ref)) :
|
173 |
+
$elements = $this->query($ref[1]);
|
174 |
+
foreach ($elements as $element) :
|
175 |
+
$postMetaOut[$key][] = str_replace(
|
176 |
+
$ref[0],
|
177 |
+
$element,
|
178 |
+
$value
|
179 |
+
);
|
180 |
+
endforeach;
|
181 |
+
else :
|
182 |
+
$postMetaOut[$key][] = $value;
|
183 |
+
endif;
|
184 |
+
endforeach;
|
185 |
+
endforeach;
|
186 |
|
187 |
+
foreach ($postMetaOut as $key => $values) :
|
188 |
+
$this->post['meta'][$key] = array();
|
189 |
+
foreach ($values as $value) :
|
190 |
+
$this->post['meta'][$key][] = apply_filters("syndicated_post_meta_{$key}", $value, $this);
|
191 |
+
endforeach;
|
192 |
+
endforeach;
|
193 |
+
|
194 |
// RSS 2.0 / Atom 1.0 enclosure support
|
195 |
+
$enclosures = $this->entry->get_enclosures();
|
196 |
+
if (is_array($enclosures)) : foreach ($enclosures as $enclosure) :
|
197 |
+
$this->post['meta']['enclosure'][] =
|
198 |
+
apply_filters('syndicated_item_enclosure_url', $enclosure->get_link(), $this)."\n".
|
199 |
+
apply_filters('syndicated_item_enclosure_length', $enclosure->get_length(), $this)."\n".
|
200 |
+
apply_filters('syndicated_item_enclosure_type', $enclosure->get_type(), $this);
|
201 |
+
endforeach; endif;
|
|
|
|
|
202 |
|
203 |
// In case you want to point back to the blog this was syndicated from
|
204 |
if (isset($this->feed->channel['title'])) :
|
223 |
endif;
|
224 |
|
225 |
// Store information on human-readable and machine-readable comment URIs
|
|
|
|
|
|
|
226 |
|
227 |
+
// Human-readable comment URI
|
228 |
+
$commentLink = apply_filters('syndicated_item_comments', $this->comment_link(), $this);
|
229 |
+
if (!is_null($commentLink)) : $this->post['meta']['rss:comments'] = $commentLink; endif;
|
|
|
230 |
|
231 |
+
// Machine-readable content feed URI
|
232 |
+
$commentFeed = apply_filters('syndicated_item_commentrss', $this->comment_feed(), $this);
|
233 |
+
if (!is_null($commentFeed)) : $this->post['meta']['wfw:commentRSS'] = $commentFeed; endif;
|
234 |
+
// Yeah, yeah, now I know that it's supposed to be
|
235 |
+
// wfw:commentRss. Oh well. Path dependence, sucka.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
|
237 |
// Store information to identify the feed that this came from
|
238 |
if (isset($this->feedmeta['link/uri'])) :
|
247 |
endif;
|
248 |
|
249 |
// In case you want to know the external permalink...
|
250 |
+
$this->post['meta']['syndication_permalink'] = apply_filters('syndicated_item_link', $this->permalink());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
// Store a hash of the post content for checking whether something needs to be updated
|
253 |
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
298 |
endif;
|
299 |
$this->post['tags_input'] = apply_filters('syndicated_item_tags', $this->post['tags_input'], $this);
|
300 |
endif;
|
301 |
+
} /* SyndicatedPost::SyndicatedPost() */
|
302 |
|
303 |
+
#####################################
|
304 |
+
#### EXTRACT DATA FROM FEED ITEM ####
|
305 |
+
#####################################
|
306 |
+
|
307 |
+
/**
|
308 |
+
* SyndicatedPost::query uses an XPath-like syntax to query arbitrary
|
309 |
+
* elements within the syndicated item.
|
310 |
+
*
|
311 |
+
* @param string $path
|
312 |
+
* @returns array of string values representing contents of matching
|
313 |
+
* elements or attributes
|
314 |
+
*/
|
315 |
+
function query ($path) {
|
316 |
+
$urlHash = array();
|
317 |
|
318 |
+
// Allow {url} notation for namespaces. URLs will contain : and /, so...
|
319 |
+
preg_match_all('/{([^}]+)}/', $path, $match, PREG_SET_ORDER);
|
320 |
+
foreach ($match as $ref) :
|
321 |
+
$urlHash[md5($ref[1])] = $ref[1];
|
322 |
+
endforeach;
|
323 |
+
|
324 |
+
foreach ($urlHash as $hash => $url) :
|
325 |
+
$path = str_replace('{'.$url.'}', '{#'.$hash.'}', $path);
|
326 |
+
endforeach;
|
327 |
|
328 |
+
$path = explode('/', $path);
|
329 |
+
foreach ($path as $index => $node) :
|
330 |
+
if (preg_match('/{#([^}]+)}/', $node, $ref)) :
|
331 |
+
if (isset($urlHash[$ref[1]])) :
|
332 |
+
$path[$index] = str_replace(
|
333 |
+
'{#'.$ref[1].'}',
|
334 |
+
'{'.$urlHash[$ref[1]].'}',
|
335 |
+
$node
|
336 |
+
);
|
337 |
+
endif;
|
338 |
+
endif;
|
339 |
+
endforeach;
|
340 |
|
341 |
+
// Start out with a get_item_tags query.
|
342 |
+
$node = '';
|
343 |
+
while (strlen($node)==0 and !is_null($node)) :
|
344 |
+
$node = array_shift($path);
|
345 |
+
endwhile;
|
346 |
+
|
347 |
+
switch ($node) :
|
348 |
+
case 'feed' :
|
349 |
+
case 'channel' :
|
350 |
+
$method = "get_${node}_tags";
|
351 |
+
$node = array_shift($path);
|
352 |
+
break;
|
353 |
+
case 'item' :
|
354 |
+
$node = array_shift($path);
|
355 |
+
default :
|
356 |
+
$method = NULL;
|
357 |
+
endswitch;
|
358 |
|
359 |
+
$data = array();
|
360 |
+
if (!is_null($node)) :
|
361 |
+
list($namespaces, $element) = $this->xpath_extended_name($node);
|
362 |
+
|
363 |
+
$matches = array();
|
364 |
+
foreach ($namespaces as $ns) :
|
365 |
+
if (!is_null($method)) :
|
366 |
+
$el = $this->link->simplepie->{$method}($ns, $element);
|
367 |
else :
|
368 |
+
$el = $this->entry->get_item_tags($ns, $element);
|
369 |
endif;
|
370 |
|
371 |
+
if (!is_null($el)) :
|
372 |
+
$matches = array_merge($matches, $el);
|
373 |
+
endif;
|
374 |
+
endforeach;
|
375 |
+
$data = $matches;
|
376 |
+
|
377 |
+
$node = array_shift($path);
|
378 |
+
endif;
|
379 |
|
380 |
+
while (!is_null($node)) :
|
381 |
+
if (strlen($node) > 0) :
|
382 |
+
$matches = array();
|
383 |
+
|
384 |
+
list($ns, $element) = $this->xpath_extended_name($node);
|
385 |
+
|
386 |
+
if (preg_match('/^@(.*)$/', $element, $ref)) :
|
387 |
+
$element = $ref[1];
|
388 |
+
$axis = 'attribs';
|
389 |
+
else :
|
390 |
+
$axis = 'child';
|
391 |
+
endif;
|
392 |
|
393 |
+
foreach ($data as $datum) :
|
394 |
+
foreach ($namespaces as $ns) :
|
395 |
+
if (!is_string($datum)
|
396 |
+
and isset($datum[$axis][$ns][$element])) :
|
397 |
+
if (is_string($datum[$axis][$ns][$element])) :
|
398 |
+
$matches[] = $datum[$axis][$ns][$element];
|
399 |
+
else :
|
400 |
+
$matches = array_merge($matches, $datum[$axis][$ns][$element]);
|
401 |
+
endif;
|
402 |
+
endif;
|
403 |
+
endforeach;
|
404 |
+
endforeach;
|
405 |
+
|
406 |
+
$data = $matches;
|
407 |
+
endif;
|
408 |
+
$node = array_shift($path);
|
409 |
+
endwhile;
|
410 |
+
|
411 |
+
$matches = array();
|
412 |
+
foreach ($data as $datum) :
|
413 |
+
if (is_string($datum)) :
|
414 |
+
$matches[] = $datum;
|
415 |
+
elseif (isset($datum['data'])) :
|
416 |
+
$matches[] = $datum['data'];
|
417 |
+
endif;
|
418 |
+
endforeach;
|
419 |
+
return $matches;
|
420 |
+
} /* SyndicatedPost::query() */
|
421 |
+
|
422 |
+
function xpath_default_namespace () {
|
423 |
+
// Get the default namespace.
|
424 |
+
$type = $this->link->simplepie->get_type();
|
425 |
+
if ($type & SIMPLEPIE_TYPE_ATOM_10) :
|
426 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_10;
|
427 |
+
elseif ($type & SIMPLEPIE_TYPE_ATOM_03) :
|
428 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_ATOM_03;
|
429 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_090) :
|
430 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_090;
|
431 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_10) :
|
432 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_10;
|
433 |
+
elseif ($type & SIMPLEPIE_TYPE_RSS_20) :
|
434 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
435 |
+
else :
|
436 |
+
$defaultNS = SIMPLEPIE_NAMESPACE_RSS_20;
|
437 |
+
endif;
|
438 |
+
return $defaultNS;
|
439 |
+
} /* SyndicatedPost::xpath_default_namespace() */
|
440 |
+
|
441 |
+
function xpath_extended_name ($node) {
|
442 |
+
$ns = NULL; $element = NULL;
|
443 |
+
|
444 |
+
if (substr($node, 0, 1)=='@') :
|
445 |
+
$attr = '@'; $node = substr($node, 1);
|
446 |
+
else :
|
447 |
+
$attr = '';
|
448 |
+
endif;
|
449 |
|
450 |
+
if (preg_match('/^{([^}]*)}(.*)$/', $node, $ref)) :
|
451 |
+
$ns = array($ref[1]); $element = $ref[2];
|
452 |
+
elseif (strpos($node, ':') !== FALSE) :
|
453 |
+
list($xmlns, $element) = explode(':', $node, 2);
|
454 |
+
if (isset($this->xmlns['reverse'][$xmlns])) :
|
455 |
+
$ns = $this->xmlns['reverse'][$xmlns];
|
456 |
+
else :
|
457 |
+
$ns = array($xmlns);
|
458 |
+
endif;
|
459 |
|
460 |
+
// Fucking SimplePie. For attributes in default xmlns.
|
461 |
+
if ($xmlns==$this->xmlns['forward'][$defaultNS[0]]) :
|
462 |
+
$ns[] = '';
|
463 |
+
endif;
|
464 |
+
else :
|
465 |
+
// Often in SimplePie, the default namespace gets stored
|
466 |
+
// as an empty string rather than a URL.
|
467 |
+
$ns = array($this->xpath_default_namespace(), '');
|
468 |
+
$element = $node;
|
469 |
+
endif;
|
470 |
+
return array(array_unique($ns), $attr.$element);
|
471 |
+
} /* SyndicatedPost::xpath_extended_name () */
|
472 |
+
|
473 |
+
function content () {
|
474 |
+
$content = NULL;
|
475 |
+
if (isset($this->item['atom_content'])) :
|
476 |
+
$content = $this->item['atom_content'];
|
477 |
+
elseif (isset($this->item['xhtml']['body'])) :
|
478 |
+
$content = $this->item['xhtml']['body'];
|
479 |
+
elseif (isset($this->item['xhtml']['div'])) :
|
480 |
+
$content = $this->item['xhtml']['div'];
|
481 |
+
elseif (isset($this->item['content']['encoded']) and $this->item['content']['encoded']):
|
482 |
+
$content = $this->item['content']['encoded'];
|
483 |
+
else:
|
484 |
+
$content = $this->item['description'];
|
485 |
+
endif;
|
486 |
+
return $content;
|
487 |
+
} /* SyndicatedPost::content() */
|
488 |
+
|
489 |
+
function excerpt () {
|
490 |
+
# Identify and sanitize excerpt: atom:summary, or rss:description
|
491 |
+
$excerpt = $this->entry->get_description();
|
492 |
+
|
493 |
+
# Many RSS feeds use rss:description, inadvisably, to
|
494 |
+
# carry the entire post (typically with escaped HTML).
|
495 |
+
# If that's what happened, we don't want the full
|
496 |
+
# content for the excerpt.
|
497 |
+
$content = $this->content();
|
498 |
+
if ( is_null($excerpt) or $excerpt == $content ) :
|
499 |
+
# If content is available, generate an excerpt.
|
500 |
+
if ( strlen(trim($content)) > 0 ) :
|
501 |
+
$excerpt = strip_tags($content);
|
502 |
+
if (strlen($excerpt) > 255) :
|
503 |
+
$excerpt = substr($excerpt,0,252).'...';
|
504 |
endif;
|
505 |
endif;
|
506 |
endif;
|
507 |
+
return $excerpt;
|
508 |
+
} /* SyndicatedPost::excerpt() */
|
509 |
+
|
510 |
+
function permalink () {
|
511 |
+
// Handles explicit <link> elements and also RSS 2.0 cases with
|
512 |
+
// <guid isPermaLink="true">, etc. Hooray!
|
513 |
+
$permalink = $this->entry->get_link();
|
514 |
+
return $permalink;
|
515 |
}
|
516 |
|
517 |
+
function created () {
|
518 |
+
$date = '';
|
519 |
+
if (isset($this->item['dc']['created'])) :
|
520 |
+
$date = $this->item['dc']['created'];
|
521 |
+
elseif (isset($this->item['dcterms']['created'])) :
|
522 |
+
$date = $this->item['dcterms']['created'];
|
523 |
+
elseif (isset($this->item['created'])): // Atom 0.3
|
524 |
+
$date = $this->item['created'];
|
525 |
endif;
|
|
|
|
|
526 |
|
527 |
+
$epoch = new FeedTime($date);
|
528 |
+
return $epoch->timestamp();
|
529 |
+
} /* SyndicatedPost::created() */
|
530 |
|
531 |
+
function published ($fallback = true, $default = NULL) {
|
532 |
+
$date = '';
|
533 |
+
|
534 |
+
# RSS is a fucking mess. Figure out whether we have a date in
|
535 |
+
# <dc:date>, <issued>, <pubDate>, etc., and get it into Unix
|
536 |
+
# epoch format for reformatting. If we can't find anything,
|
537 |
+
# we'll use the last-updated time.
|
538 |
+
if (isset($this->item['dc']['date'])): // Dublin Core
|
539 |
+
$date = $this->item['dc']['date'];
|
540 |
+
elseif (isset($this->item['dcterms']['issued'])) : // Dublin Core extensions
|
541 |
+
$date = $this->item['dcterms']['issued'];
|
542 |
+
elseif (isset($this->item['published'])) : // Atom 1.0
|
543 |
+
$date = $this->item['published'];
|
544 |
+
elseif (isset($this->item['issued'])): // Atom 0.3
|
545 |
+
$date = $this->item['issued'];
|
546 |
+
elseif (isset($this->item['pubdate'])): // RSS 2.0
|
547 |
+
$date = $this->item['pubdate'];
|
548 |
endif;
|
549 |
|
550 |
+
if (strlen($date) > 0) :
|
551 |
+
$time = new FeedTime($date);
|
552 |
+
$epoch = $time->timestamp();
|
553 |
+
elseif ($fallback) : // Fall back to <updated> / <modified> if present
|
554 |
+
$epoch = $this->updated(/*fallback=*/ false, /*default=*/ $default);
|
|
|
|
|
|
|
|
|
|
|
555 |
endif;
|
556 |
|
557 |
+
# If everything failed, then default to the current time.
|
558 |
+
if (is_null($epoch)) :
|
559 |
+
if (-1 == $default) :
|
560 |
+
$epoch = time();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
else :
|
562 |
+
$epoch = $default;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
563 |
endif;
|
564 |
endif;
|
565 |
|
566 |
+
return $epoch;
|
567 |
+
} /* SyndicatedPost::published() */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
568 |
|
569 |
+
function updated ($fallback = true, $default = -1) {
|
570 |
+
$date = '';
|
|
|
|
|
|
|
|
|
571 |
|
572 |
+
# As far as I know, only dcterms and Atom have reliable ways to
|
573 |
+
# specify when something was *modified* last. If neither is
|
574 |
+
# available, then we'll try to get the time of publication.
|
575 |
+
if (isset($this->item['dc']['modified'])) : // Not really correct
|
576 |
+
$date = $this->item['dc']['modified'];
|
577 |
+
elseif (isset($this->item['dcterms']['modified'])) : // Dublin Core extensions
|
578 |
+
$date = $this->item['dcterms']['modified'];
|
579 |
+
elseif (isset($this->item['modified'])): // Atom 0.3
|
580 |
+
$date = $this->item['modified'];
|
581 |
+
elseif (isset($this->item['updated'])): // Atom 1.0
|
582 |
+
$date = $this->item['updated'];
|
583 |
endif;
|
584 |
|
585 |
+
if (strlen($date) > 0) :
|
586 |
+
$time = new FeedTime($date);
|
587 |
+
$epoch = $time->timestamp();
|
588 |
+
elseif ($fallback) : // Fall back to issued / dc:date
|
589 |
+
$epoch = $this->published(/*fallback=*/ false, /*default=*/ $default);
|
590 |
+
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
591 |
|
592 |
+
# If everything failed, then default to the current time.
|
593 |
+
if (is_null($epoch)) :
|
594 |
+
if (-1 == $default) :
|
595 |
+
$epoch = time();
|
596 |
+
else :
|
597 |
+
$epoch = $default;
|
|
|
598 |
endif;
|
599 |
endif;
|
|
|
600 |
|
601 |
+
return $epoch;
|
602 |
+
} /* SyndicatedPost::updated() */
|
603 |
|
604 |
+
function update_hash () {
|
605 |
+
return md5(serialize($this->item));
|
606 |
+
} /* SyndicatedPost::update_hash() */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
607 |
|
608 |
+
function guid () {
|
609 |
+
$guid = null;
|
610 |
+
if (isset($this->item['id'])): // Atom 0.3 / 1.0
|
611 |
+
$guid = $this->item['id'];
|
612 |
+
elseif (isset($this->item['atom']['id'])) : // Namespaced Atom
|
613 |
+
$guid = $this->item['atom']['id'];
|
614 |
+
elseif (isset($this->item['guid'])) : // RSS 2.0
|
615 |
+
$guid = $this->item['guid'];
|
616 |
+
elseif (isset($this->item['dc']['identifier'])) :// yeah, right
|
617 |
+
$guid = $this->item['dc']['identifier'];
|
618 |
+
else :
|
619 |
+
// The feed does not seem to have provided us with a
|
620 |
+
// unique identifier, so we'll have to cobble together
|
621 |
+
// a tag: URI that might work for us. The base of the
|
622 |
+
// URI will be the host name of the feed source ...
|
623 |
+
$bits = parse_url($this->feedmeta['link/uri']);
|
624 |
+
$guid = 'tag:'.$bits['host'];
|
625 |
|
626 |
+
// If we have a date of creation, then we can use that
|
627 |
+
// to uniquely identify the item. (On the other hand, if
|
628 |
+
// the feed producer was consicentious enough to
|
629 |
+
// generate dates of creation, she probably also was
|
630 |
+
// conscientious enough to generate unique identifiers.)
|
631 |
+
if (!is_null($this->created())) :
|
632 |
+
$guid .= '://post.'.date('YmdHis', $this->created());
|
633 |
+
|
634 |
+
// Otherwise, use both the URI of the item, *and* the
|
635 |
+
// item's title. We have to use both because titles are
|
636 |
+
// often not unique, and sometimes links aren't unique
|
637 |
+
// either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
|
638 |
+
// some podcasts). But it's rare to have *both* the same
|
639 |
+
// title *and* the same link for two different items. So
|
640 |
+
// this is about the best we can do.
|
|
|
|
|
641 |
else :
|
642 |
+
$guid .= '://'.md5($this->item['link'].'/'.$this->item['title']);
|
643 |
+
endif;
|
644 |
+
endif;
|
645 |
+
return $guid;
|
646 |
+
} /* SyndicatedPost::guid() */
|
647 |
|
648 |
+
function author () {
|
649 |
+
$author = array ();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
|
651 |
+
if (isset($this->item['author_name'])):
|
652 |
+
$author['name'] = $this->item['author_name'];
|
653 |
+
elseif (isset($this->item['dc']['creator'])):
|
654 |
+
$author['name'] = $this->item['dc']['creator'];
|
655 |
+
elseif (isset($this->item['dc']['contributor'])):
|
656 |
+
$author['name'] = $this->item['dc']['contributor'];
|
657 |
+
elseif (isset($this->feed->channel['dc']['creator'])) :
|
658 |
+
$author['name'] = $this->feed->channel['dc']['creator'];
|
659 |
+
elseif (isset($this->feed->channel['dc']['contributor'])) :
|
660 |
+
$author['name'] = $this->feed->channel['dc']['contributor'];
|
661 |
+
elseif (isset($this->feed->channel['author_name'])) :
|
662 |
+
$author['name'] = $this->feed->channel['author_name'];
|
663 |
+
elseif ($this->feed->is_rss() and isset($this->item['author'])) :
|
664 |
+
// The author element in RSS is allegedly an
|
665 |
+
// e-mail address, but lots of people don't use
|
666 |
+
// it that way. So let's make of it what we can.
|
667 |
+
$author = parse_email_with_realname($this->item['author']);
|
668 |
+
|
669 |
+
if (!isset($author['name'])) :
|
670 |
+
if (isset($author['email'])) :
|
671 |
+
$author['name'] = $author['email'];
|
672 |
else :
|
673 |
+
$author['name'] = $this->feed->channel['title'];
|
674 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
675 |
endif;
|
676 |
+
else :
|
677 |
+
$author['name'] = $this->feed->channel['title'];
|
678 |
endif;
|
679 |
+
|
680 |
+
if (isset($this->item['author_email'])):
|
681 |
+
$author['email'] = $this->item['author_email'];
|
682 |
+
elseif (isset($this->feed->channel['author_email'])) :
|
683 |
+
$author['email'] = $this->feed->channel['author_email'];
|
684 |
+
endif;
|
685 |
+
|
686 |
+
if (isset($this->item['author_url'])):
|
687 |
+
$author['uri'] = $this->item['author_url'];
|
688 |
+
elseif (isset($this->feed->channel['author_url'])) :
|
689 |
+
$author['uri'] = $this->item['author_url'];
|
690 |
+
else:
|
691 |
+
$author['uri'] = $this->feed->channel['link'];
|
692 |
+
endif;
|
693 |
+
|
694 |
+
return $author;
|
695 |
+
} /* SyndicatedPost::author() */
|
696 |
|
697 |
/**
|
698 |
+
* SyndicatedPost::isTaggedAs: Test whether a feed item is
|
699 |
+
* tagged / categorized with a given string. Case and leading and
|
700 |
+
* trailing whitespace are ignored.
|
701 |
*
|
702 |
+
* @param string $tag Tag to check for
|
703 |
+
*
|
704 |
+
* @return bool Whether or not at least one of the categories / tags on
|
705 |
+
* $this->item is set to $tag (modulo case and leading and trailing
|
706 |
+
* whitespace)
|
707 |
*/
|
708 |
+
function isTaggedAs ($tag) {
|
709 |
+
$desiredTag = strtolower(trim($tag)); // Normalize case and whitespace
|
710 |
|
711 |
+
// Check to see if this is tagged with $tag
|
712 |
+
$currentCategory = 'category';
|
713 |
+
$currentCategoryNumber = 1;
|
714 |
|
715 |
+
// If we have the new MagpieRSS, the number of category elements
|
716 |
+
// on this item is stored under index "category#".
|
717 |
+
if (isset($this->item['category#'])) :
|
718 |
+
$numberOfCategories = (int) $this->item['category#'];
|
719 |
+
|
720 |
+
// We REALLY shouldn't have the old and busted MagpieRSS, but in
|
721 |
+
// case we do, it doesn't support multiple categories, but there
|
722 |
+
// might still be a single value under the "category" index.
|
723 |
+
elseif (isset($this->item['category'])) :
|
724 |
+
$numberOfCategories = 1;
|
725 |
+
|
726 |
+
// No standard category or tag elements on this feed item.
|
727 |
+
else :
|
728 |
+
$numberOfCategories = 0;
|
729 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
730 |
endif;
|
731 |
|
732 |
+
$isSoTagged = false; // Innocent until proven guilty
|
733 |
+
|
734 |
+
// Loop through category elements; if there are multiple
|
735 |
+
// elements, they are indexed as category, category#2,
|
736 |
+
// category#3, ... category#N
|
737 |
+
while ($currentCategoryNumber <= $numberOfCategories) :
|
738 |
+
if ($desiredTag == strtolower(trim($this->item[$currentCategory]))) :
|
739 |
+
$isSoTagged = true; // Got it!
|
740 |
+
break;
|
741 |
+
endif;
|
742 |
+
|
743 |
+
$currentCategoryNumber += 1;
|
744 |
+
$currentCategory = 'category#'.$currentCategoryNumber;
|
745 |
+
endwhile;
|
746 |
+
|
747 |
+
return $isSoTagged;
|
748 |
+
} /* SyndicatedPost::isTaggedAs() */
|
749 |
|
750 |
/**
|
751 |
+
* SyndicatedPost::enclosures: returns an array with any enclosures
|
752 |
+
* that may be attached to this syndicated item.
|
753 |
*
|
754 |
+
* @param string $type If you only want enclosures that match a certain
|
755 |
+
* MIME type or group of MIME types, you can limit the enclosures
|
756 |
+
* that will be returned to only those with a MIME type which
|
757 |
+
* matches this regular expression.
|
758 |
+
* @return array
|
759 |
*/
|
760 |
+
function enclosures ($type = '/.*/') {
|
761 |
+
$enclosures = array();
|
762 |
+
|
763 |
+
if (isset($this->item['enclosure#'])) :
|
764 |
+
// Loop through enclosure, enclosure#2, enclosure#3, ....
|
765 |
+
for ($i = 1; $i <= $this->item['enclosure#']; $i++) :
|
766 |
+
$eid = (($i > 1) ? "#{$id}" : "");
|
767 |
+
|
768 |
+
// Does it match the type we want?
|
769 |
+
if (preg_match($type, $this->item["enclosure{$eid}@type"])) :
|
770 |
+
$enclosures[] = array(
|
771 |
+
"url" => $this->item["enclosure{$eid}@url"],
|
772 |
+
"type" => $this->item["enclosure{$eid}@type"],
|
773 |
+
"length" => $this->item["enclosure{$eid}@length"],
|
774 |
+
);
|
775 |
+
endif;
|
776 |
+
endfor;
|
777 |
+
endif;
|
778 |
+
return $enclosures;
|
779 |
+
} /* SyndicatedPost::enclosures() */
|
780 |
+
|
781 |
+
function comment_link () {
|
782 |
+
$url = null;
|
783 |
|
784 |
+
// RSS 2.0 has a standard <comments> element:
|
785 |
+
// "<comments> is an optional sub-element of <item>. If present,
|
786 |
+
// it is the url of the comments page for the item."
|
787 |
+
// <http://cyber.law.harvard.edu/rss/rss.html#ltcommentsgtSubelementOfLtitemgt>
|
788 |
+
if (isset($this->item['comments'])) :
|
789 |
+
$url = $this->item['comments'];
|
|
|
|
|
|
|
|
|
|
|
790 |
endif;
|
791 |
+
|
792 |
+
// The convention in Atom feeds is to use a standard <link>
|
793 |
+
// element with @rel="replies" and @type="text/html".
|
794 |
+
// Unfortunately, SimplePie_Item::get_links() allows us to filter
|
795 |
+
// by the value of @rel, but not by the value of @type. *sigh*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
796 |
|
797 |
+
// Try Atom 1.0 first
|
798 |
+
$linkElements = $this->entry->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link');
|
799 |
|
800 |
+
// Fall back and try Atom 0.3
|
801 |
+
if (is_null($linkElements)) : $linkElements = $this->entry->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'); endif;
|
802 |
+
|
803 |
+
// Now loop through the elements, screening by @rel and @type
|
804 |
+
if (is_array($linkElements)) : foreach ($linkElements as $link) :
|
805 |
+
$rel = (isset($link['attribs']['']['rel']) ? $link['attribs']['']['rel'] : 'alternate');
|
806 |
+
$type = (isset($link['attribs']['']['type']) ? $link['attribs']['']['type'] : NULL);
|
807 |
+
$href = (isset($link['attribs']['']['href']) ? $link['attribs']['']['href'] : NULL);
|
808 |
+
|
809 |
+
if (strtolower($rel)=='replies' and $type=='text/html' and !is_null($href)) :
|
810 |
+
$url = $href;
|
811 |
+
endif;
|
812 |
+
endforeach; endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
813 |
|
814 |
+
return $url;
|
815 |
+
}
|
816 |
|
817 |
+
function comment_feed () {
|
818 |
+
$feed = null;
|
819 |
+
|
820 |
+
// Well Formed Web comment feeds extension for RSS 2.0
|
821 |
+
// <http://www.sellsbrothers.com/spout/default.aspx?content=archive.htm#exposingRssComments>
|
822 |
+
//
|
823 |
+
// N.B.: Correct capitalization is wfw:commentRss, but
|
824 |
+
// wfw:commentRSS is common in the wild (partly due to a typo in
|
825 |
+
// the original spec). In any case, our item array is normalized
|
826 |
+
// to all lowercase anyways.
|
827 |
+
if (isset($this->item['wfw']['commentrss'])) :
|
828 |
+
$feed = $this->item['wfw']['commentrss'];
|
829 |
+
endif;
|
830 |
|
831 |
+
// In Atom 1.0, the convention is to use a standard link element
|
832 |
+
// with @rel="replies". Sometimes this is also used to pass a
|
833 |
+
// link to the human-readable comments page, so we also need to
|
834 |
+
// check link/@type for a feed MIME type.
|
835 |
+
//
|
836 |
+
// Which is why I'm not using the SimplePie_Item::get_links()
|
837 |
+
// method here, incidentally: it doesn't allow you to filter by
|
838 |
+
// @type. *sigh*
|
839 |
+
if (isset($this->item['link_replies'])) :
|
840 |
+
// There may be multiple <link rel="replies"> elements; feeds have a feed MIME type
|
841 |
+
$N = isset($this->item['link_replies#']) ? $this->item['link_replies#'] : 1;
|
842 |
+
for ($i = 1; $i <= $N; $i++) :
|
843 |
+
$currentElement = 'link_replies'.(($i > 1) ? '#'.$i : '');
|
844 |
+
if (isset($this->item[$currentElement.'@type'])
|
845 |
+
and preg_match("\007application/(atom|rss|rdf)\+xml\007i", $this->item[$currentElement.'@type'])) :
|
846 |
+
$feed = $this->item[$currentElement];
|
847 |
+
endif;
|
848 |
+
endfor;
|
|
|
849 |
endif;
|
850 |
+
return $feed;
|
851 |
+
} /* SyndicatedPost::comment_feed() */
|
852 |
|
853 |
+
##################################
|
854 |
+
#### BUILT-IN CONTENT FILTERS ####
|
855 |
+
##################################
|
|
|
856 |
|
857 |
+
var $uri_attrs = array (
|
858 |
+
array('a', 'href'),
|
859 |
+
array('applet', 'codebase'),
|
860 |
+
array('area', 'href'),
|
861 |
+
array('blockquote', 'cite'),
|
862 |
+
array('body', 'background'),
|
863 |
+
array('del', 'cite'),
|
864 |
+
array('form', 'action'),
|
865 |
+
array('frame', 'longdesc'),
|
866 |
+
array('frame', 'src'),
|
867 |
+
array('iframe', 'longdesc'),
|
868 |
+
array('iframe', 'src'),
|
869 |
+
array('head', 'profile'),
|
870 |
+
array('img', 'longdesc'),
|
871 |
+
array('img', 'src'),
|
872 |
+
array('img', 'usemap'),
|
873 |
+
array('input', 'src'),
|
874 |
+
array('input', 'usemap'),
|
875 |
+
array('ins', 'cite'),
|
876 |
+
array('link', 'href'),
|
877 |
+
array('object', 'classid'),
|
878 |
+
array('object', 'codebase'),
|
879 |
+
array('object', 'data'),
|
880 |
+
array('object', 'usemap'),
|
881 |
+
array('q', 'cite'),
|
882 |
+
array('script', 'src')
|
883 |
+
); /* var SyndicatedPost::$uri_attrs */
|
884 |
|
885 |
+
var $_base = null;
|
|
|
|
|
|
|
|
|
|
|
886 |
|
887 |
+
function resolve_single_relative_uri ($refs) {
|
888 |
+
$tag = FeedWordPressHTML::attributeMatch($refs);
|
889 |
+
$url = Relative_URI::resolve($tag['value'], $this->_base);
|
890 |
+
return $tag['prefix'] . $url . $tag['suffix'];
|
891 |
+
} /* function SyndicatedPost::resolve_single_relative_uri() */
|
892 |
|
893 |
+
function resolve_relative_uris ($content, $obj) {
|
894 |
+
$set = $obj->link->setting('resolve relative', 'resolve_relative', 'yes');
|
895 |
+
if ($set and $set != 'no') :
|
896 |
+
// Fallback: if we don't have anything better, use the
|
897 |
+
// item link from the feed
|
898 |
+
$obj->_base = $obj->item['link']; // Reset the base for resolving relative URIs
|
899 |
|
900 |
+
// What we should do here, properly, is to use
|
901 |
+
// SimplePie_Item::get_base() -- but that method is
|
902 |
+
// currently broken. Or getting down and dirty in the
|
903 |
+
// SimplePie representation of the content tags and
|
904 |
+
// grabbing the xml_base member for the content element.
|
905 |
+
// Maybe someday...
|
906 |
|
907 |
+
foreach ($obj->uri_attrs as $pair) :
|
908 |
+
list($tag, $attr) = $pair;
|
909 |
+
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
910 |
+
$content = preg_replace_callback (
|
911 |
+
$pattern,
|
912 |
+
array(&$obj, 'resolve_single_relative_uri'),
|
913 |
+
$content
|
914 |
+
);
|
915 |
+
endforeach;
|
916 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
917 |
|
918 |
+
return $content;
|
919 |
+
} /* function SyndicatedPost::resolve_relative_uris () */
|
920 |
|
921 |
+
var $strip_attrs = array (
|
922 |
+
array('[a-z]+', 'target'),
|
923 |
+
// array('[a-z]+', 'style'),
|
924 |
+
// array('[a-z]+', 'on[a-z]+'),
|
925 |
+
);
|
926 |
|
927 |
+
function strip_attribute_from_tag ($refs) {
|
928 |
+
$tag = FeedWordPressHTML::attributeMatch($refs);
|
929 |
+
return $tag['before_attribute'].$tag['after_attribute'];
|
930 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
931 |
|
932 |
+
function sanitize_content ($content, $obj) {
|
933 |
+
# This kind of sucks. I intend to replace it with
|
934 |
+
# lib_filter sometime soon.
|
935 |
+
foreach ($obj->strip_attrs as $pair):
|
936 |
+
list($tag,$attr) = $pair;
|
937 |
+
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
938 |
|
939 |
+
$content = preg_replace_callback (
|
940 |
+
$pattern,
|
941 |
+
array(&$obj, 'strip_attribute_from_tag'),
|
942 |
+
$content
|
943 |
+
);
|
944 |
+
endforeach;
|
945 |
+
return $content;
|
946 |
+
} /* SyndicatedPost::sanitize() */
|
947 |
|
948 |
+
#####################
|
949 |
+
#### POST STATUS ####
|
950 |
+
#####################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
951 |
|
952 |
+
/**
|
953 |
+
* SyndicatedPost::filtered: check whether or not this post has been
|
954 |
+
* screened out by a registered filter.
|
955 |
+
*
|
956 |
+
* @return bool TRUE iff post has been filtered out by a previous filter
|
957 |
+
*/
|
958 |
+
function filtered () {
|
959 |
+
return is_null($this->post);
|
960 |
+
} /* SyndicatedPost::filtered() */
|
961 |
|
962 |
+
/**
|
963 |
+
* SyndicatedPost::freshness: check whether post is a new post to be
|
964 |
+
* inserted, a previously syndicated post that needs to be updated to
|
965 |
+
* match the latest revision, or a previously syndicated post that is
|
966 |
+
* still up-to-date.
|
967 |
+
*
|
968 |
+
* @return int A status code representing the freshness of the post
|
969 |
+
* 0 = post already syndicated; no update needed
|
970 |
+
* 1 = post already syndicated, but needs to be updated to latest
|
971 |
+
* 2 = post has not yet been syndicated; needs to be created
|
972 |
+
*/
|
973 |
+
function freshness () {
|
974 |
global $wpdb;
|
975 |
|
976 |
+
if ($this->filtered()) : // This should never happen.
|
977 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
978 |
+
endif;
|
979 |
+
|
980 |
+
if (is_null($this->_freshness)) :
|
981 |
+
$guid = $wpdb->escape($this->guid());
|
|
|
982 |
|
983 |
+
$result = $wpdb->get_row("
|
984 |
+
SELECT id, guid, post_modified_gmt
|
985 |
+
FROM $wpdb->posts WHERE guid='$guid'
|
986 |
+
");
|
987 |
|
988 |
+
if (!$result) :
|
989 |
+
$this->_freshness = 2; // New content
|
990 |
+
else:
|
991 |
+
$stored_update_hashes = get_post_custom_values('syndication_item_hash', $result->id);
|
992 |
+
if (count($stored_update_hashes) > 0) :
|
993 |
+
$stored_update_hash = $stored_update_hashes[0];
|
994 |
+
$update_hash_changed = ($stored_update_hash != $this->update_hash());
|
995 |
+
else :
|
996 |
+
$update_hash_changed = false;
|
997 |
endif;
|
998 |
+
|
999 |
+
preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $result->post_modified_gmt, $backref);
|
1000 |
+
|
1001 |
+
$last_rev_ts = gmmktime($backref[4], $backref[5], $backref[6], $backref[2], $backref[3], $backref[1]);
|
1002 |
+
$updated_ts = $this->updated(/*fallback=*/ true, /*default=*/ NULL);
|
1003 |
|
1004 |
+
$frozen_values = get_post_custom_values('_syndication_freeze_updates', $result->id);
|
1005 |
+
$frozen_post = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]);
|
1006 |
+
$frozen_feed = ('yes' == $this->link->setting('freeze updates', 'freeze_updates', NULL));
|
1007 |
+
|
1008 |
+
// Check timestamps...
|
1009 |
+
$updated = (
|
1010 |
+
!is_null($updated_ts)
|
1011 |
+
and ($updated_ts > $last_rev_ts)
|
1012 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1013 |
|
1014 |
+
|
1015 |
+
// Or the hash...
|
1016 |
+
$updated = ($updated or $update_hash_changed);
|
1017 |
+
|
1018 |
+
// But only if the post is not frozen.
|
1019 |
+
$updated = (
|
1020 |
+
$updated
|
1021 |
+
and !$frozen_post
|
1022 |
+
and !$frozen_feed
|
1023 |
+
);
|
1024 |
+
|
1025 |
+
if ($updated) :
|
1026 |
+
$this->_freshness = 1; // Updated content
|
1027 |
+
$this->_wp_id = $result->id;
|
1028 |
else :
|
1029 |
+
$this->_freshness = 0; // Same old, same old
|
1030 |
+
$this->_wp_id = $result->id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1031 |
endif;
|
1032 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1033 |
endif;
|
1034 |
+
return $this->_freshness;
|
1035 |
+
}
|
1036 |
|
1037 |
+
#################################################
|
1038 |
+
#### INTERNAL STORAGE AND MANAGEMENT METHODS ####
|
1039 |
+
#################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1040 |
|
1041 |
+
function wp_id () {
|
1042 |
+
if ($this->filtered()) : // This should never happen.
|
1043 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
1044 |
endif;
|
1045 |
+
|
1046 |
+
if (is_null($this->_wp_id) and is_null($this->_freshness)) :
|
1047 |
+
$fresh = $this->freshness(); // sets WP DB id in the process
|
1048 |
+
endif;
|
1049 |
+
return $this->_wp_id;
|
1050 |
}
|
|
|
|
|
1051 |
|
1052 |
+
function store () {
|
1053 |
+
global $wpdb;
|
1054 |
+
|
1055 |
+
if ($this->filtered()) : // This should never happen.
|
1056 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1057 |
endif;
|
1058 |
|
1059 |
+
$freshness = $this->freshness();
|
1060 |
+
if ($freshness > 0) :
|
1061 |
+
# -- Look up, or create, numeric ID for author
|
1062 |
+
$this->post['post_author'] = $this->author_id (
|
1063 |
+
FeedWordPress::on_unfamiliar('author', $this->post['named']['unfamiliar']['author'])
|
1064 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1065 |
|
1066 |
+
if (is_null($this->post['post_author'])) :
|
1067 |
+
$this->post = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1068 |
endif;
|
1069 |
endif;
|
1070 |
+
|
1071 |
+
if (!$this->filtered() and $freshness > 0) :
|
1072 |
+
# -- Look up, or create, numeric ID for categories
|
1073 |
+
list($pcats, $ptags) = $this->category_ids (
|
1074 |
+
$this->post['named']['category'],
|
1075 |
+
FeedWordPress::on_unfamiliar('category', $this->post['named']['unfamiliar']['category']),
|
1076 |
+
/*tags_too=*/ true
|
1077 |
+
);
|
1078 |
|
1079 |
+
$this->post['post_category'] = $pcats;
|
1080 |
+
$this->post['tags_input'] = array_merge($this->post['tags_input'], $ptags);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1081 |
|
1082 |
+
if (is_null($this->post['post_category'])) :
|
1083 |
+
// filter mode on, no matching categories; drop the post
|
1084 |
+
$this->post = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1085 |
else :
|
1086 |
+
// filter mode off or at least one match; now add on the feed and global presets
|
1087 |
+
$this->post['post_category'] = array_merge (
|
1088 |
+
$this->post['post_category'],
|
1089 |
+
$this->category_ids (
|
1090 |
+
$this->post['named']['preset/category'],
|
1091 |
+
'default'
|
1092 |
+
)
|
1093 |
+
);
|
1094 |
+
|
1095 |
+
if (count($this->post['post_category']) < 1) :
|
1096 |
+
$this->post['post_category'][] = 1; // Default to category 1 ("Uncategorized" / "General") if nothing else
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1097 |
endif;
|
1098 |
endif;
|
|
|
|
|
1099 |
endif;
|
1100 |
|
1101 |
+
if (!$this->filtered() and $freshness > 0) :
|
1102 |
+
unset($this->post['named']);
|
1103 |
+
$this->post = apply_filters('syndicated_post', $this->post, $this);
|
1104 |
+
|
1105 |
+
// Allow for feed-specific syndicated_post filters.
|
1106 |
+
$this->post = apply_filters(
|
1107 |
+
"syndicated_post_".$this->link->uri(),
|
1108 |
+
$this->post,
|
1109 |
+
$this
|
1110 |
+
);
|
1111 |
endif;
|
1112 |
|
1113 |
+
// Hook in early to make sure these get inserted if at all possible
|
1114 |
+
add_action(
|
1115 |
+
/*hook=*/ 'transition_post_status',
|
1116 |
+
/*callback=*/ array($this, 'add_rss_meta'),
|
1117 |
+
/*priority=*/ -10000, /* very early */
|
1118 |
+
/*arguments=*/ 3
|
1119 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1120 |
|
1121 |
+
if (!$this->filtered() and $freshness == 2) :
|
1122 |
+
// The item has not yet been added. So let's add it.
|
1123 |
+
$this->insert_new();
|
1124 |
+
do_action('post_syndicated_item', $this->wp_id(), $this);
|
1125 |
|
1126 |
+
$ret = 'new';
|
1127 |
+
elseif (!$this->filtered() and $freshness == 1) :
|
1128 |
+
$this->post['ID'] = $this->wp_id();
|
1129 |
+
$this->update_existing();
|
1130 |
+
do_action('update_syndicated_item', $this->wp_id(), $this);
|
|
|
|
|
|
|
|
|
|
|
1131 |
|
1132 |
+
$ret = 'updated';
|
1133 |
else :
|
1134 |
+
$ret = false;
|
|
|
1135 |
endif;
|
1136 |
|
1137 |
+
// Remove add_rss_meta hook
|
1138 |
+
remove_action(
|
1139 |
+
/*hook=*/ 'transition_post_status',
|
1140 |
+
/*callback=*/ array($this, 'add_rss_meta')
|
1141 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1142 |
|
1143 |
+
return $ret;
|
1144 |
+
} /* function SyndicatedPost::store () */
|
1145 |
+
|
1146 |
+
function insert_new () {
|
1147 |
+
global $wpdb, $wp_db_version;
|
1148 |
|
1149 |
+
$dbpost = $this->normalize_post(/*new=*/ true);
|
1150 |
+
if (!is_null($dbpost)) :
|
1151 |
+
if ($this->use_api('wp_insert_post')) :
|
1152 |
+
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
|
|
|
|
|
|
|
|
|
|
|
|
1153 |
|
1154 |
+
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
1155 |
+
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1156 |
+
|
1157 |
+
// Kludge to prevent kses filters from stripping the
|
1158 |
+
// content of posts when updating without a logged in
|
1159 |
+
// user who has `unfiltered_html` capability.
|
1160 |
+
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1161 |
+
|
1162 |
+
$this->_wp_id = wp_insert_post($dbpost);
|
1163 |
+
|
1164 |
+
// Turn off ridiculous fucking kludges #1 and #2
|
1165 |
+
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1166 |
+
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1167 |
+
|
1168 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1169 |
+
|
1170 |
+
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
1171 |
+
// *still* offers no way to use a guid of your choice,
|
1172 |
+
// and munges your post modified timestamp, too.
|
1173 |
+
$result = $wpdb->query("
|
1174 |
+
UPDATE $wpdb->posts
|
1175 |
+
SET
|
1176 |
+
guid='{$dbpost['guid']}',
|
1177 |
+
post_modified='{$dbpost['post_modified']}',
|
1178 |
+
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
1179 |
+
WHERE ID='{$this->_wp_id}'
|
1180 |
+
");
|
1181 |
+
else :
|
1182 |
+
# The right way to do this is the above. But, alas,
|
1183 |
+
# in earlier versions of WordPress, wp_insert_post has
|
1184 |
+
# too much behavior (mainly related to pings) that can't
|
1185 |
+
# be overridden. In WordPress 1.5, it's enough of a
|
1186 |
+
# resource hog to make PHP segfault after inserting
|
1187 |
+
# 50-100 posts. This can get pretty annoying, especially
|
1188 |
+
# if you are trying to update your feeds for the first
|
1189 |
+
# time.
|
1190 |
+
|
1191 |
+
$result = $wpdb->query("
|
1192 |
+
INSERT INTO $wpdb->posts
|
1193 |
+
SET
|
1194 |
+
guid = '{$dbpost['guid']}',
|
1195 |
+
post_author = '{$dbpost['post_author']}',
|
1196 |
+
post_date = '{$dbpost['post_date']}',
|
1197 |
+
post_date_gmt = '{$dbpost['post_date_gmt']}',
|
1198 |
+
post_content = '{$dbpost['post_content']}',"
|
1199 |
+
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
1200 |
+
post_title = '{$dbpost['post_title']}',
|
1201 |
+
post_name = '{$dbpost['post_name']}',
|
1202 |
+
post_modified = '{$dbpost['post_modified']}',
|
1203 |
+
post_modified_gmt = '{$dbpost['post_modified_gmt']}',
|
1204 |
+
comment_status = '{$dbpost['comment_status']}',
|
1205 |
+
ping_status = '{$dbpost['ping_status']}',
|
1206 |
+
post_status = '{$dbpost['post_status']}'
|
1207 |
+
");
|
1208 |
+
$this->_wp_id = $wpdb->insert_id;
|
1209 |
+
|
1210 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1211 |
+
|
1212 |
+
// WordPress 1.5.x - 2.0.x
|
1213 |
+
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
1214 |
+
|
1215 |
+
// Since we are not going through official channels, we need to
|
1216 |
+
// manually tell WordPress that we've published a new post.
|
1217 |
+
// We need to make sure to do this in order for FeedWordPress
|
1218 |
+
// to play well with the staticize-reloaded plugin (something
|
1219 |
+
// that a large aggregator website is going to *want* to be
|
1220 |
+
// able to use).
|
1221 |
+
do_action('publish_post', $this->_wp_id);
|
1222 |
+
endif;
|
1223 |
+
endif;
|
1224 |
+
} /* SyndicatedPost::insert_new() */
|
1225 |
+
|
1226 |
+
function update_existing () {
|
1227 |
+
global $wpdb;
|
1228 |
+
|
1229 |
+
// Why the fuck doesn't wp_insert_post already do this?
|
1230 |
+
$dbpost = $this->normalize_post(/*new=*/ false);
|
1231 |
+
if (!is_null($dbpost)) :
|
1232 |
+
if ($this->use_api('wp_insert_post')) :
|
1233 |
+
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
1234 |
+
|
1235 |
+
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
1236 |
+
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1237 |
+
|
1238 |
+
// Kludge to prevent kses filters from stripping the
|
1239 |
+
// content of posts when updating without a logged in
|
1240 |
+
// user who has `unfiltered_html` capability.
|
1241 |
+
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1242 |
+
|
1243 |
+
// Don't munge status fields that the user may have reset manually
|
1244 |
+
if (function_exists('get_post_field')) :
|
1245 |
+
$doNotMunge = array('post_status', 'comment_status', 'ping_status');
|
1246 |
+
foreach ($doNotMunge as $field) :
|
1247 |
+
$dbpost[$field] = get_post_field($field, $this->wp_id());
|
1248 |
+
endforeach;
|
1249 |
+
endif;
|
1250 |
+
|
1251 |
+
$this->_wp_id = wp_insert_post($dbpost);
|
1252 |
+
|
1253 |
+
// Turn off ridiculous fucking kludges #1 and #2
|
1254 |
+
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1255 |
+
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1256 |
+
|
1257 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1258 |
+
|
1259 |
+
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
1260 |
+
// munges your post modified timestamp.
|
1261 |
+
$result = $wpdb->query("
|
1262 |
+
UPDATE $wpdb->posts
|
1263 |
+
SET
|
1264 |
+
post_modified='{$dbpost['post_modified']}',
|
1265 |
+
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
1266 |
+
WHERE ID='{$this->_wp_id}'
|
1267 |
+
");
|
1268 |
+
else :
|
1269 |
+
|
1270 |
+
$result = $wpdb->query("
|
1271 |
+
UPDATE $wpdb->posts
|
1272 |
+
SET
|
1273 |
+
post_author = '{$dbpost['post_author']}',
|
1274 |
+
post_content = '{$dbpost['post_content']}',"
|
1275 |
+
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
1276 |
+
post_title = '{$dbpost['post_title']}',
|
1277 |
+
post_name = '{$dbpost['post_name']}',
|
1278 |
+
post_modified = '{$dbpost['post_modified']}',
|
1279 |
+
post_modified_gmt = '{$dbpost['post_modified_gmt']}'
|
1280 |
+
WHERE guid='{$dbpost['guid']}'
|
1281 |
+
");
|
1282 |
+
|
1283 |
+
// WordPress 2.1.x and up
|
1284 |
+
if (function_exists('wp_set_post_categories')) :
|
1285 |
+
wp_set_post_categories($this->wp_id(), $this->post['post_category']);
|
1286 |
+
// WordPress 1.5.x - 2.0.x
|
1287 |
+
elseif (function_exists('wp_set_post_cats')) :
|
1288 |
+
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
1289 |
+
// This should never happen.
|
1290 |
+
else :
|
1291 |
+
FeedWordPress::critical_bug(__CLASS__.'::'.__FUNCTION.'(): no post categorizing function', array("dbpost" => $dbpost, "this" => $this), __LINE__);
|
1292 |
+
endif;
|
1293 |
+
|
1294 |
+
// Since we are not going through official channels, we need to
|
1295 |
+
// manually tell WordPress that we've published a new post.
|
1296 |
+
// We need to make sure to do this in order for FeedWordPress
|
1297 |
+
// to play well with the staticize-reloaded plugin (something
|
1298 |
+
// that a large aggregator website is going to *want* to be
|
1299 |
+
// able to use).
|
1300 |
+
do_action('edit_post', $this->post['ID']);
|
1301 |
+
endif;
|
1302 |
+
endif;
|
1303 |
+
} /* SyndicatedPost::update_existing() */
|
1304 |
+
|
1305 |
+
/**
|
1306 |
+
* SyndicatedPost::normalize_post()
|
1307 |
+
*
|
1308 |
+
* @param bool $new If true, this post is to be inserted anew. If false, it is an update of an existing post.
|
1309 |
+
* @return array A normalized representation of the post ready to be inserted into the database or sent to the WordPress API functions
|
1310 |
+
*/
|
1311 |
+
function normalize_post ($new = true) {
|
1312 |
+
global $wpdb;
|
1313 |
+
|
1314 |
+
$out = array();
|
1315 |
+
|
1316 |
+
// Why the fuck doesn't wp_insert_post already do this?
|
1317 |
+
foreach ($this->post as $key => $value) :
|
1318 |
+
if (is_string($value)) :
|
1319 |
+
$out[$key] = $wpdb->escape($value);
|
1320 |
+
else :
|
1321 |
+
$out[$key] = $value;
|
1322 |
+
endif;
|
1323 |
+
endforeach;
|
1324 |
+
|
1325 |
+
if (strlen($out['post_title'].$out['post_content'].$out['post_excerpt']) == 0) :
|
1326 |
+
// FIXME: Option for filtering out empty posts
|
1327 |
+
endif;
|
1328 |
+
if (strlen($out['post_title'])==0) :
|
1329 |
+
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
1330 |
+
$out['post_title'] =
|
1331 |
+
$this->post['meta']['syndication_source']
|
1332 |
+
.' '.gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
1333 |
+
// FIXME: Option for what to fill a blank title with...
|
1334 |
+
endif;
|
1335 |
+
|
1336 |
+
return $out;
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
/**
|
1340 |
+
* SyndicatedPost::validate_post_id()
|
1341 |
+
*
|
1342 |
+
* @param array $dbpost An array representing the post we attempted to insert or update
|
1343 |
+
* @param mixed $ns A string or array representing the namespace (class, method) whence this method was called.
|
1344 |
+
*/
|
1345 |
+
function validate_post_id ($dbpost, $ns) {
|
1346 |
+
if (is_array($ns)) : $ns = implode('::', $ns);
|
1347 |
+
else : $ns = (string) $ns; endif;
|
1348 |
+
|
1349 |
+
// This should never happen.
|
1350 |
+
if (!is_numeric($this->_wp_id) or ($this->_wp_id == 0)) :
|
1351 |
+
FeedWordPress::critical_bug(
|
1352 |
+
/*name=*/ $ns.'::_wp_id',
|
1353 |
+
/*var =*/ array(
|
1354 |
+
"\$this->_wp_id" => $this->_wp_id,
|
1355 |
+
"\$dbpost" => $dbpost,
|
1356 |
+
"\$this" => $this
|
1357 |
+
),
|
1358 |
+
/*line # =*/ __LINE__
|
1359 |
+
);
|
1360 |
+
endif;
|
1361 |
+
} /* SyndicatedPost::validate_post_id() */
|
1362 |
+
|
1363 |
+
/**
|
1364 |
+
* SyndicatedPost::fix_revision_meta() - Fixes the way WP 2.6+ fucks up
|
1365 |
+
* meta-data (authorship, etc.) when storing revisions of an updated
|
1366 |
+
* syndicated post.
|
1367 |
+
*
|
1368 |
+
* In their infinite wisdom, the WordPress coders have made it completely
|
1369 |
+
* impossible for a plugin that uses wp_insert_post() to set certain
|
1370 |
+
* meta-data (such as the author) when you store an old revision of an
|
1371 |
+
* updated post. Instead, it uses the WordPress defaults (= currently
|
1372 |
+
* active user ID if the process is running with a user logged in, or
|
1373 |
+
* = #0 if there is no user logged in). This results in bogus authorship
|
1374 |
+
* data for revisions that are syndicated from off the feed, unless we
|
1375 |
+
* use a ridiculous kludge like this to end-run the munging of meta-data
|
1376 |
+
* by _wp_put_post_revision.
|
1377 |
+
*
|
1378 |
+
* @param int $revision_id The revision ID to fix up meta-data
|
1379 |
+
*/
|
1380 |
+
function fix_revision_meta ($revision_id) {
|
1381 |
+
global $wpdb;
|
1382 |
+
|
1383 |
+
$post_author = (int) $this->post['post_author'];
|
1384 |
+
|
1385 |
+
$revision_id = (int) $revision_id;
|
1386 |
+
$wpdb->query("
|
1387 |
+
UPDATE $wpdb->posts
|
1388 |
+
SET post_author={$this->post['post_author']}
|
1389 |
+
WHERE post_type = 'revision' AND ID='$revision_id'
|
1390 |
+
");
|
1391 |
+
} /* SyndicatedPost::fix_revision_meta () */
|
1392 |
+
|
1393 |
+
/**
|
1394 |
+
* SyndicatedPost::avoid_kses_munge() -- If FeedWordPress is processing
|
1395 |
+
* an automatic update, that generally means that wp_insert_post() is
|
1396 |
+
* being called under the user credentials of whoever is viewing the
|
1397 |
+
* blog at the time -- usually meaning no user at all. But if WordPress
|
1398 |
+
* gets a wp_insert_post() when current_user_can('unfiltered_html') is
|
1399 |
+
* false, it will run the content of the post through a kses function
|
1400 |
+
* that strips out lots of HTML tags -- notably <object> and some others.
|
1401 |
+
* This causes problems for syndicating (for example) feeds that contain
|
1402 |
+
* YouTube videos. It also produces an unexpected asymmetry between
|
1403 |
+
* automatically-initiated updates and updates initiated manually from
|
1404 |
+
* the WordPress Dashboard (which are usually initiated under the
|
1405 |
+
* credentials of a logged-in admin, and so don't get run through the
|
1406 |
+
* kses function). So, to avoid the whole mess, what we do here is
|
1407 |
+
* just forcibly disable the kses munging for a single syndicated post,
|
1408 |
+
* by restoring the contents of the `post_content` field.
|
1409 |
+
*
|
1410 |
+
* @param string $content The content of the post, after other filters have gotten to it
|
1411 |
+
* @return string The original content of the post, before other filters had a chance to munge it.
|
1412 |
+
*/
|
1413 |
+
function avoid_kses_munge ($content) {
|
1414 |
+
global $wpdb;
|
1415 |
+
return $wpdb->escape($this->post['post_content']);
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
// SyndicatedPost::add_rss_meta: adds interesting meta-data to each entry
|
1419 |
+
// using the space for custom keys. The set of keys and values to add is
|
1420 |
+
// specified by the keys and values of $post['meta']. This is used to
|
1421 |
+
// store anything that the WordPress user might want to access from a
|
1422 |
+
// template concerning the post's original source that isn't provided
|
1423 |
+
// for by standard WP meta-data (i.e., any interesting data about the
|
1424 |
+
// syndicated post other than author, title, timestamp, categories, and
|
1425 |
+
// guid). It's also used to hook into WordPress's support for
|
1426 |
+
// enclosures.
|
1427 |
+
function add_rss_meta ($new_status, $old_status, $post) {
|
1428 |
+
global $wpdb;
|
1429 |
+
if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
|
1430 |
+
$postId = $this->wp_id();
|
1431 |
+
|
1432 |
+
// Aggregated posts should NOT send out pingbacks.
|
1433 |
+
// WordPress 2.1-2.2 claim you can tell them not to
|
1434 |
+
// using $post_pingback, but they don't listen, so we
|
1435 |
+
// make sure here.
|
1436 |
+
$result = $wpdb->query("
|
1437 |
+
DELETE FROM $wpdb->postmeta
|
1438 |
+
WHERE post_id='$postId' AND meta_key='_pingme'
|
1439 |
+
");
|
1440 |
+
|
1441 |
+
foreach ( $this->post['meta'] as $key => $values ) :
|
1442 |
+
|
1443 |
+
$eKey = $wpdb->escape($key);
|
1444 |
+
|
1445 |
+
// If this is an update, clear out the old
|
1446 |
+
// values to avoid duplication.
|
1447 |
+
$result = $wpdb->query("
|
1448 |
+
DELETE FROM $wpdb->postmeta
|
1449 |
+
WHERE post_id='$postId' AND meta_key='$eKey'
|
1450 |
+
");
|
1451 |
+
|
1452 |
+
// Allow for either a single value or an array
|
1453 |
+
if (!is_array($values)) $values = array($values);
|
1454 |
+
foreach ( $values as $value ) :
|
1455 |
+
add_post_meta($postId, $key, $value, /*unique=*/ false);
|
1456 |
+
endforeach;
|
1457 |
endforeach;
|
1458 |
endif;
|
1459 |
+
} /* SyndicatedPost::add_rss_meta () */
|
1460 |
+
|
1461 |
+
// SyndicatedPost::author_id (): get the ID for an author name from
|
1462 |
+
// the feed. Create the author if necessary.
|
1463 |
+
function author_id ($unfamiliar_author = 'create') {
|
1464 |
+
global $wpdb;
|
1465 |
+
|
1466 |
+
$a = $this->author();
|
1467 |
+
$author = $a['name'];
|
1468 |
+
$email = (isset($a['email']) ? $a['email'] : NULL);
|
1469 |
+
$url = (isset($a['uri']) ? $a['uri'] : NULL);
|
1470 |
+
|
1471 |
+
$match_author_by_email = !('yes' == get_option("feedwordpress_do_not_match_author_by_email"));
|
1472 |
+
if ($match_author_by_email and !FeedWordPress::is_null_email($email)) :
|
1473 |
+
$test_email = $email;
|
1474 |
+
else :
|
1475 |
+
$test_email = NULL;
|
1476 |
+
endif;
|
1477 |
+
|
1478 |
+
// Never can be too careful...
|
1479 |
+
$login = sanitize_user($author, /*strict=*/ true);
|
1480 |
+
$login = apply_filters('pre_user_login', $login);
|
1481 |
+
|
1482 |
+
$nice_author = sanitize_title($author);
|
1483 |
+
$nice_author = apply_filters('pre_user_nicename', $nice_author);
|
1484 |
+
|
1485 |
+
$reg_author = $wpdb->escape(preg_quote($author));
|
1486 |
+
$author = $wpdb->escape($author);
|
1487 |
+
$email = $wpdb->escape($email);
|
1488 |
+
$test_email = $wpdb->escape($test_email);
|
1489 |
+
$url = $wpdb->escape($url);
|
1490 |
+
|
1491 |
+
// Check for an existing author rule....
|
1492 |
+
if (isset($this->link->settings['map authors']['name'][strtolower(trim($author))])) :
|
1493 |
+
$author_rule = $this->link->settings['map authors']['name'][strtolower(trim($author))];
|
1494 |
+
else :
|
1495 |
+
$author_rule = NULL;
|
1496 |
+
endif;
|
1497 |
+
|
1498 |
+
// User name is mapped to a particular author. If that author ID exists, use it.
|
1499 |
+
if (is_numeric($author_rule) and get_userdata((int) $author_rule)) :
|
1500 |
+
$id = (int) $author_rule;
|
1501 |
+
|
1502 |
+
// User name is filtered out
|
1503 |
+
elseif ('filter' == $author_rule) :
|
1504 |
+
$id = NULL;
|
1505 |
|
1506 |
+
else :
|
1507 |
+
// Check the database for an existing author record that might fit
|
1508 |
|
1509 |
+
// First try the user core data table.
|
1510 |
+
$id = $wpdb->get_var(
|
1511 |
+
"SELECT ID FROM $wpdb->users
|
1512 |
+
WHERE
|
1513 |
+
TRIM(LCASE(user_login)) = TRIM(LCASE('$login'))
|
1514 |
+
OR (
|
1515 |
+
LENGTH(TRIM(LCASE(user_email))) > 0
|
1516 |
+
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
1517 |
+
)
|
1518 |
+
OR TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author'))
|
1519 |
+
");
|
1520 |
+
|
1521 |
+
// If that fails, look for aliases in the user meta data table
|
1522 |
+
if (is_null($id)) :
|
1523 |
+
$id = $wpdb->get_var(
|
1524 |
+
"SELECT user_id FROM $wpdb->usermeta
|
1525 |
+
WHERE
|
1526 |
+
(meta_key = 'description' AND TRIM(LCASE(meta_value)) = TRIM(LCASE('$author')))
|
1527 |
+
OR (
|
1528 |
+
meta_key = 'description'
|
1529 |
+
AND TRIM(LCASE(meta_value))
|
1530 |
+
RLIKE CONCAT(
|
1531 |
+
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
1532 |
+
TRIM(LCASE('$reg_author')),
|
1533 |
+
'( |\\t|\\r)*(\\n|\$)'
|
1534 |
+
)
|
1535 |
+
)
|
1536 |
+
");
|
1537 |
+
endif;
|
1538 |
|
1539 |
+
// ... if you don't find one, then do what you need to do
|
1540 |
+
if (is_null($id)) :
|
1541 |
+
if ($unfamiliar_author === 'create') :
|
1542 |
+
$userdata = array();
|
1543 |
|
1544 |
+
// WordPress 3 is going to pitch a fit if we attempt to register
|
1545 |
+
// more than one user account with an empty e-mail address, so we
|
1546 |
+
// need *something* here. Ugh.
|
1547 |
+
if (strlen($email) == 0 or FeedWordPress::is_null_email($email)) :
|
1548 |
+
$url = parse_url($this->feed->channel['link']);
|
1549 |
+
$email = $nice_author.'@'.$url['host'];
|
1550 |
+
endif;
|
1551 |
|
1552 |
+
#-- user table data
|
1553 |
+
$userdata['ID'] = NULL; // new user
|
1554 |
+
$userdata['user_login'] = $login;
|
1555 |
+
$userdata['user_nicename'] = $nice_author;
|
1556 |
+
$userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up
|
1557 |
+
$userdata['user_email'] = $email;
|
1558 |
+
$userdata['user_url'] = $url;
|
1559 |
+
$userdata['display_name'] = $author;
|
1560 |
+
|
1561 |
+
$id = wp_insert_user($userdata);
|
1562 |
+
elseif (is_numeric($unfamiliar_author) and get_userdata((int) $unfamiliar_author)) :
|
1563 |
+
$id = (int) $unfamiliar_author;
|
1564 |
+
elseif ($unfamiliar_author === 'default') :
|
1565 |
+
$id = 1;
|
1566 |
+
endif;
|
1567 |
+
endif;
|
1568 |
+
endif;
|
1569 |
+
|
1570 |
+
if ($id) :
|
1571 |
+
$this->link->settings['map authors']['name'][strtolower(trim($author))] = $id;
|
1572 |
+
endif;
|
1573 |
+
return $id;
|
1574 |
+
} // function SyndicatedPost::author_id ()
|
1575 |
+
|
1576 |
+
// look up (and create) category ids from a list of categories
|
1577 |
+
function category_ids ($cats, $unfamiliar_category = 'create', $tags_too = false) {
|
1578 |
+
global $wpdb;
|
1579 |
+
|
1580 |
+
// We need to normalize whitespace because (1) trailing
|
1581 |
+
// whitespace can cause PHP and MySQL not to see eye to eye on
|
1582 |
+
// VARCHAR comparisons for some versions of MySQL (cf.
|
1583 |
+
// <http://dev.mysql.com/doc/mysql/en/char.html>), and (2)
|
1584 |
+
// because I doubt most people want to make a semantic
|
1585 |
+
// distinction between 'Computers' and 'Computers '
|
1586 |
+
$cats = array_map('trim', $cats);
|
1587 |
+
|
1588 |
+
$tags = array();
|
1589 |
+
|
1590 |
+
$cat_ids = array ();
|
1591 |
+
foreach ($cats as $cat_name) :
|
1592 |
+
if (preg_match('/^{#([0-9]+)}$/', $cat_name, $backref)) :
|
1593 |
+
$cat_id = (int) $backref[1];
|
1594 |
+
if (function_exists('is_term') and is_term($cat_id, 'category')) :
|
1595 |
+
$cat_ids[] = $cat_id;
|
1596 |
+
elseif (get_category($cat_id)) :
|
1597 |
+
$cat_ids[] = $cat_id;
|
1598 |
+
endif;
|
1599 |
+
elseif (strlen($cat_name) > 0) :
|
1600 |
+
$esc = $wpdb->escape($cat_name);
|
1601 |
+
$resc = $wpdb->escape(preg_quote($cat_name));
|
1602 |
+
|
1603 |
+
// WordPress 2.3+
|
1604 |
+
if (function_exists('is_term')) :
|
1605 |
+
$cat_id = is_term($cat_name, 'category');
|
1606 |
+
if ($cat_id) :
|
1607 |
+
$cat_ids[] = $cat_id['term_id'];
|
1608 |
+
// There must be a better way to do this...
|
1609 |
+
elseif ($results = $wpdb->get_results(
|
1610 |
+
"SELECT term_id
|
1611 |
+
FROM $wpdb->term_taxonomy
|
1612 |
+
WHERE
|
1613 |
+
LOWER(description) RLIKE
|
1614 |
+
CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)')"
|
1615 |
+
)) :
|
1616 |
+
foreach ($results AS $term) :
|
1617 |
+
$cat_ids[] = (int) $term->term_id;
|
1618 |
+
endforeach;
|
1619 |
+
elseif ('tag'==$unfamiliar_category) :
|
1620 |
+
$tags[] = $cat_name;
|
1621 |
+
elseif ('create'===$unfamiliar_category) :
|
1622 |
+
$term = wp_insert_term($cat_name, 'category');
|
1623 |
+
if (is_wp_error($term)) :
|
1624 |
+
FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__);
|
1625 |
+
else :
|
1626 |
+
$cat_ids[] = $term['term_id'];
|
1627 |
+
endif;
|
1628 |
+
endif;
|
1629 |
+
|
1630 |
+
// WordPress 1.5.x - 2.2.x
|
1631 |
+
else :
|
1632 |
+
$results = $wpdb->get_results(
|
1633 |
+
"SELECT cat_ID
|
1634 |
+
FROM $wpdb->categories
|
1635 |
+
WHERE
|
1636 |
+
(LOWER(cat_name) = LOWER('$esc'))
|
1637 |
+
OR (LOWER(category_description)
|
1638 |
+
RLIKE CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)'))
|
1639 |
+
");
|
1640 |
+
if ($results) :
|
1641 |
+
foreach ($results as $term) :
|
1642 |
+
$cat_ids[] = (int) $term->cat_ID;
|
1643 |
+
endforeach;
|
1644 |
+
elseif ('create'===$unfamiliar_category) :
|
1645 |
+
if (function_exists('wp_insert_category')) :
|
1646 |
+
$cat_id = wp_insert_category(array('cat_name' => $esc));
|
1647 |
+
// And into the database we go.
|
1648 |
+
else :
|
1649 |
+
$nice_kitty = sanitize_title($cat_name);
|
1650 |
+
$wpdb->query(sprintf("
|
1651 |
+
INSERT INTO $wpdb->categories
|
1652 |
+
SET
|
1653 |
+
cat_name='%s',
|
1654 |
+
category_nicename='%s'
|
1655 |
+
", $esc, $nice_kitty
|
1656 |
+
));
|
1657 |
+
$cat_id = $wpdb->insert_id;
|
1658 |
+
endif;
|
1659 |
+
$cat_ids[] = $cat_id;
|
1660 |
+
endif;
|
1661 |
+
endif;
|
1662 |
+
endif;
|
1663 |
endforeach;
|
1664 |
+
|
1665 |
+
if ((count($cat_ids) == 0) and ($unfamiliar_category === 'filter')) :
|
1666 |
+
$cat_ids = NULL; // Drop the post
|
1667 |
+
else :
|
1668 |
+
$cat_ids = array_unique($cat_ids);
|
1669 |
+
endif;
|
1670 |
+
|
1671 |
+
if ($tags_too) : $ret = array($cat_ids, $tags);
|
1672 |
+
else : $ret = $cat_ids;
|
1673 |
+
endif;
|
1674 |
+
|
1675 |
+
return $ret;
|
1676 |
+
} // function SyndicatedPost::category_ids ()
|
1677 |
+
|
1678 |
+
function use_api ($tag) {
|
1679 |
+
global $wp_db_version;
|
1680 |
+
switch ($tag) :
|
1681 |
+
case 'wp_insert_post':
|
1682 |
+
// Before 2.2, wp_insert_post does too much of the wrong stuff to use it
|
1683 |
+
// In 1.5 it was such a resource hog it would make PHP segfault on big updates
|
1684 |
+
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_21);
|
1685 |
+
break;
|
1686 |
+
case 'post_status_pending':
|
1687 |
+
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_23);
|
1688 |
+
break;
|
1689 |
+
endswitch;
|
1690 |
+
return $ret;
|
1691 |
+
} // function SyndicatedPost::use_api ()
|
1692 |
+
|
1693 |
+
} /* class SyndicatedPost */
|
1694 |
|
syndication.php
CHANGED
@@ -229,7 +229,7 @@ function fwp_dashboard_update_if_requested () {
|
|
229 |
|
230 |
shuffle($update_set); // randomize order for load balancing purposes...
|
231 |
if ($fwp_update_invoke != 'get' and count($update_set) > 0) : // Only do things with side-effects for HTTP POST or command line
|
232 |
-
$feedwordpress
|
233 |
add_action('feedwordpress_check_feed', 'update_feeds_mention');
|
234 |
add_action('feedwordpress_check_feed_complete', 'update_feeds_finish', 10, 3);
|
235 |
|
@@ -409,7 +409,7 @@ function fwp_syndication_manage_page_links_box ($object = NULL, $box = NULL) {
|
|
409 |
endif;
|
410 |
?>
|
411 |
<td>
|
412 |
-
<strong><a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php echo $link->link_id; ?>"><?php echo
|
413 |
<div class="row-actions"><div><strong>Settings ></strong>
|
414 |
<a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php echo $link->link_id; ?>"><?php _e('Feed'); ?></a>
|
415 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/posts-page.php&link_id=<?php echo $link->link_id; ?>"><?php _e('Posts'); ?></a>
|
@@ -418,29 +418,18 @@ function fwp_syndication_manage_page_links_box ($object = NULL, $box = NULL) {
|
|
418 |
<div><strong>Actions ></strong>
|
419 |
<a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=feedfinder"><?php echo $caption; ?></a>
|
420 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=Unsubscribe"><?php _e('Unsubscribe'); ?></a>
|
421 |
-
| <a href="<?php echo
|
422 |
</div>
|
423 |
</td>
|
424 |
-
<?php
|
425 |
-
|
426 |
-
$uri_bits = parse_url($link->link_rss);
|
427 |
-
$uri_bits['host'] = preg_replace('/^www\./i', '', $uri_bits['host']);
|
428 |
-
$display_uri =
|
429 |
-
(isset($uri_bits['user'])?$uri_bits['user'].'@':'')
|
430 |
-
.(isset($uri_bits['host'])?$uri_bits['host']:'')
|
431 |
-
.(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
|
432 |
-
.(isset($uri_bits['path'])?$uri_bits['path']:'')
|
433 |
-
.(isset($uri_bits['query'])?'?'.$uri_bits['query']:'');
|
434 |
-
if (strlen($display_uri) > 32) : $display_uri = substr($display_uri, 0, 32).'…'; endif;
|
435 |
-
?>
|
436 |
-
<td><a href="<?php echo wp_specialchars($link->link_rss, 'both'); ?>"><?php echo wp_specialchars($display_uri, 'both'); ?></a></td>
|
437 |
<?php else: ?>
|
438 |
<td style="background-color:#FFFFD0"><p><strong>no
|
439 |
feed assigned</strong></p></td>
|
440 |
<?php endif; ?>
|
441 |
|
442 |
<td><?php
|
443 |
-
$sLink
|
444 |
if (isset($sLink->settings['update/last'])) :
|
445 |
print fwp_time_elapsed($sLink->settings['update/last']);
|
446 |
else :
|
@@ -459,6 +448,7 @@ function fwp_syndication_manage_page_links_box ($object = NULL, $box = NULL) {
|
|
459 |
else:
|
460 |
echo "as soon as possible";
|
461 |
endif;
|
|
|
462 |
print "</div>";
|
463 |
?>
|
464 |
</td>
|
@@ -506,13 +496,15 @@ function fwp_switchfeed_page () {
|
|
506 |
if (isset($fwp_post['save_link_id']) and ($fwp_post['save_link_id']=='*')) :
|
507 |
$changed = true;
|
508 |
$link_id = FeedWordPress::syndicate_link($fwp_post['feed_title'], $fwp_post['feed_link'], $fwp_post['feed']);
|
509 |
-
if ($link_id):
|
510 |
-
|
|
|
|
|
511 |
has been added as a contributing site, using the feed at
|
512 |
-
<<a href="<?php print $fwp_post['feed']; ?>"><?php print
|
513 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php print $link_id; ?>">Configure settings</a>.</p></div>
|
514 |
<?php else: ?>
|
515 |
-
<div class="updated"><p>There was a problem adding the feed. [SQL: <?php echo
|
516 |
<?php endif;
|
517 |
elseif (isset($fwp_post['save_link_id'])):
|
518 |
$existingLink = new SyndicatedLink($fwp_post['save_link_id']);
|
@@ -522,13 +514,17 @@ has been added as a contributing site, using the feed at
|
|
522 |
$home = $existingLink->homepage(/*from feed=*/ false);
|
523 |
$name = $existingLink->name(/*from feed=*/ false);
|
524 |
?>
|
525 |
-
<div class="updated"><p>Feed for <a href="<?php echo
|
526 |
-
updated to <<a href="<?php echo
|
527 |
<?php
|
528 |
endif;
|
529 |
endif;
|
530 |
endif;
|
531 |
|
|
|
|
|
|
|
|
|
532 |
if (!$changed) :
|
533 |
?>
|
534 |
<div class="updated"><p>Nothing was changed.</p></div>
|
@@ -641,10 +637,10 @@ function fwp_multidelete_page () {
|
|
641 |
|
642 |
<h2>Unsubscribe from Syndicated Links:</h2>
|
643 |
<?php foreach ($targets as $link) :
|
644 |
-
$link_url =
|
645 |
-
$link_name =
|
646 |
-
$link_description =
|
647 |
-
$link_rss =
|
648 |
?>
|
649 |
<fieldset>
|
650 |
<legend><?php echo $link_name; ?></legend>
|
229 |
|
230 |
shuffle($update_set); // randomize order for load balancing purposes...
|
231 |
if ($fwp_update_invoke != 'get' and count($update_set) > 0) : // Only do things with side-effects for HTTP POST or command line
|
232 |
+
$feedwordpress = new FeedWordPress;
|
233 |
add_action('feedwordpress_check_feed', 'update_feeds_mention');
|
234 |
add_action('feedwordpress_check_feed_complete', 'update_feeds_finish', 10, 3);
|
235 |
|
409 |
endif;
|
410 |
?>
|
411 |
<td>
|
412 |
+
<strong><a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php echo $link->link_id; ?>"><?php echo esc_html($link->link_name); ?></a></strong>
|
413 |
<div class="row-actions"><div><strong>Settings ></strong>
|
414 |
<a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php echo $link->link_id; ?>"><?php _e('Feed'); ?></a>
|
415 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/posts-page.php&link_id=<?php echo $link->link_id; ?>"><?php _e('Posts'); ?></a>
|
418 |
<div><strong>Actions ></strong>
|
419 |
<a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=feedfinder"><?php echo $caption; ?></a>
|
420 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/<?php echo basename(__FILE__); ?>&link_id=<?php echo $link->link_id; ?>&action=Unsubscribe"><?php _e('Unsubscribe'); ?></a>
|
421 |
+
| <a href="<?php echo esc_html($link->link_url); ?>"><?php _e('View')?></a></div>
|
422 |
</div>
|
423 |
</td>
|
424 |
+
<?php if (strlen($link->link_rss) > 0): ?>
|
425 |
+
<td><a href="<?php echo esc_html($link->link_rss); ?>"><?php echo esc_html(feedwordpress_display_url($link->link_rss, 32)); ?></a></td>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
<?php else: ?>
|
427 |
<td style="background-color:#FFFFD0"><p><strong>no
|
428 |
feed assigned</strong></p></td>
|
429 |
<?php endif; ?>
|
430 |
|
431 |
<td><?php
|
432 |
+
$sLink = new SyndicatedLink($link->link_id);
|
433 |
if (isset($sLink->settings['update/last'])) :
|
434 |
print fwp_time_elapsed($sLink->settings['update/last']);
|
435 |
else :
|
448 |
else:
|
449 |
echo "as soon as possible";
|
450 |
endif;
|
451 |
+
unset($sLink);
|
452 |
print "</div>";
|
453 |
?>
|
454 |
</td>
|
496 |
if (isset($fwp_post['save_link_id']) and ($fwp_post['save_link_id']=='*')) :
|
497 |
$changed = true;
|
498 |
$link_id = FeedWordPress::syndicate_link($fwp_post['feed_title'], $fwp_post['feed_link'], $fwp_post['feed']);
|
499 |
+
if ($link_id):
|
500 |
+
$existingLink = new SyndicatedLink($link_id);
|
501 |
+
?>
|
502 |
+
<div class="updated"><p><a href="<?php print $fwp_post['feed_link']; ?>"><?php print esc_html($fwp_post['feed_title']); ?></a>
|
503 |
has been added as a contributing site, using the feed at
|
504 |
+
<<a href="<?php print $fwp_post['feed']; ?>"><?php print esc_html($fwp_post['feed']); ?></a>>.
|
505 |
| <a href="admin.php?page=<?php print $GLOBALS['fwp_path'] ?>/feeds-page.php&link_id=<?php print $link_id; ?>">Configure settings</a>.</p></div>
|
506 |
<?php else: ?>
|
507 |
+
<div class="updated"><p>There was a problem adding the feed. [SQL: <?php echo esc_html(mysql_error()); ?>]</p></div>
|
508 |
<?php endif;
|
509 |
elseif (isset($fwp_post['save_link_id'])):
|
510 |
$existingLink = new SyndicatedLink($fwp_post['save_link_id']);
|
514 |
$home = $existingLink->homepage(/*from feed=*/ false);
|
515 |
$name = $existingLink->name(/*from feed=*/ false);
|
516 |
?>
|
517 |
+
<div class="updated"><p>Feed for <a href="<?php echo esc_html($home); ?>"><?php echo esc_html($name); ?></a>
|
518 |
+
updated to <<a href="<?php echo esc_html($fwp_post['feed']); ?>"><?php echo esc_html($fwp_post['feed']); ?></a>>.</p></div>
|
519 |
<?php
|
520 |
endif;
|
521 |
endif;
|
522 |
endif;
|
523 |
|
524 |
+
if (isset($existingLink)) :
|
525 |
+
do_action('feedwordpress_admin_switchfeed', $fwp_post['feed'], $existingLink);
|
526 |
+
endif;
|
527 |
+
|
528 |
if (!$changed) :
|
529 |
?>
|
530 |
<div class="updated"><p>Nothing was changed.</p></div>
|
637 |
|
638 |
<h2>Unsubscribe from Syndicated Links:</h2>
|
639 |
<?php foreach ($targets as $link) :
|
640 |
+
$link_url = esc_html($link->link_url);
|
641 |
+
$link_name = esc_html($link->link_name);
|
642 |
+
$link_description = esc_html($link->link_description);
|
643 |
+
$link_rss = esc_html($link->link_rss);
|
644 |
?>
|
645 |
<fieldset>
|
646 |
<legend><?php echo $link_name; ?></legend>
|
updatedpostscontrol.class.php
CHANGED
@@ -18,7 +18,7 @@ class UpdatedPostsControl {
|
|
18 |
else :
|
19 |
$aFeed = 'a syndicated feed';
|
20 |
$freeze_updates = $global_freeze_updates;
|
21 |
-
endif;
|
22 |
?>
|
23 |
<tr>
|
24 |
<th scope="row"><?php _e('Updated posts:') ?></th>
|
18 |
else :
|
19 |
$aFeed = 'a syndicated feed';
|
20 |
$freeze_updates = $global_freeze_updates;
|
21 |
+
endif;
|
22 |
?>
|
23 |
<tr>
|
24 |
<th scope="row"><?php _e('Updated posts:') ?></th>
|