Version Description
Download this release
Release Info
Developer | radgeek |
Plugin | FeedWordPress |
Version | 0.97 |
Comparing to | |
See all releases |
Code changes from version 0.96 to 0.97
- ChangeLog.text +170 -2
- OPTIONAL/wp-includes/rss-functions.php +663 -276
- README.text +374 -560
- wp-content/plugins/feedwordpress.php +1357 -227
- wp-content/update-feeds.php +147 -49
ChangeLog.text
CHANGED
@@ -1,5 +1,173 @@
|
|
1 |
-
Change Log
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
Changes from 0.95 to 0.96
|
5 |
-------------------------
|
1 |
+
FeedWordPress Change Log
|
2 |
+
========================
|
3 |
+
|
4 |
+
Changes from 0.96 to 0.97
|
5 |
+
-------------------------
|
6 |
+
|
7 |
+
* INSTALLATION PROCEDURE: Some of the changes between 0.96 and 0.97
|
8 |
+
require upgrades to the meta-data stored by FeedWordPress to work
|
9 |
+
properly. Thus, if you are upgrading from 0.96 or earlier to 0.97, most
|
10 |
+
FeedWordPress operations (including updates and template functions)
|
11 |
+
WILL BE DISABLED until you run the upgrade procedure. Fortunately,
|
12 |
+
running the upgrade procedure is easy: just go to either Options -->
|
13 |
+
Syndication or Links --> Syndicated in the WordPress Dashboard and press
|
14 |
+
the button.
|
15 |
+
|
16 |
+
* FEED FORMAT SUPPORT: Support has been added for the Atom 1.0 IETF
|
17 |
+
standard. Several other elements are also newly supported
|
18 |
+
(dcterms:created, dcterms:issued, dcterms:modified, dc:identifier,
|
19 |
+
proper support for the RSS 2.0 guid element, the RSS 2.0 author element,
|
20 |
+
the use of Atom author or Dublin Core dc:creator constructs at the feed
|
21 |
+
level to identify the author of individual items, etc.)
|
22 |
+
|
23 |
+
N.B.: full support of several Atom 1.0 features, such as categories
|
24 |
+
and enclosures, requires you to install the optional rss-functions.php
|
25 |
+
upgrade in your wp-includes directory.
|
26 |
+
|
27 |
+
* BUG FIX: Running `update-feeds.php` from command line or crontab
|
28 |
+
returned "I don't syndicate..." errors. It turns out that WordPress
|
29 |
+
sometimes tramples on the internal PHP superglobals that I depended on
|
30 |
+
to determine whether or not the script was being invoked from the
|
31 |
+
command line. This has been fixed (the variables are now checked
|
32 |
+
*before* WordPress can trample them). Note that `update-feeds.php` has
|
33 |
+
been thoroughly overhauled anyway; see below for details.
|
34 |
+
|
35 |
+
* BUG FIX: Duplicate categories or author names. Fixed two bugs that could
|
36 |
+
create duplicate author and/or category names when the name contained
|
37 |
+
either (a) certain international characters (causing a mismatch between
|
38 |
+
MySQL and PHP's handling of lowercasing text), or (b) characters that
|
39 |
+
have a special meaning in regular expressions (causing MySQL errors when
|
40 |
+
looking for the author or category due to regexp syntax errors). These
|
41 |
+
should now be fixed thanks to careful escaping of names that go into
|
42 |
+
regular expressions and careful matching of lowercasing functions
|
43 |
+
(comparing results from PHP only to other results from PHP, and results
|
44 |
+
from MySQL only to other results from MySQL).
|
45 |
+
|
46 |
+
* BUG FIX: Items dated Decembr 31, 1969 should appear less often. The
|
47 |
+
function for parsing W3C date-time format dates that ships with
|
48 |
+
MagpieRSS can only correctly parse fully-specified dates with a
|
49 |
+
fully-specified time, but valid W3C date-time format dates may omit the
|
50 |
+
time, the day of the month, or even the month. Some feeds in the wild
|
51 |
+
date their items with coarse-grained dates, so the optional
|
52 |
+
`rss-functions.php` upgrade now includes a more flexible parse_w3cdtf()
|
53 |
+
function that will work with both coarse-grained and fully-specified
|
54 |
+
dates. (If parts of the date or the time are omitted, they are filled in
|
55 |
+
with values based on the current time, so '2005-09-10' will be dated to
|
56 |
+
the current time on that day; '2004' will be dated to this day and time
|
57 |
+
one year ago.
|
58 |
+
|
59 |
+
N.B.: This fix is only available in the optional `rss-functions.php`
|
60 |
+
upgrade.
|
61 |
+
|
62 |
+
* BUG FIX: Evil use of HTTP GET has been undone. The WordPress interface
|
63 |
+
is riddled with inappropriate (non-idempotent) uses of HTTP GET queries
|
64 |
+
(ordinary links that make the server do something with significant
|
65 |
+
side-effects, such as deleting a post or a link from the database).
|
66 |
+
FeedWordPress did some of this too, especially in places where it aped
|
67 |
+
the WordPress interface (e.g. the "Delete" links in Links -->
|
68 |
+
Syndicated). That's bad business, though. I've changed the interface so
|
69 |
+
that all the examples of improper side-effects that I can find now
|
70 |
+
require an HTTP POST to take effect. I think I got pretty much
|
71 |
+
everything; if there's anything that I missed, let me know.
|
72 |
+
|
73 |
+
Further reading: [Sam Ruby 2005-05-06: This Stuff Matters] (http://www.intertwingly.net/blog/2005/05/06/This-Stuff-Matters)
|
74 |
+
|
75 |
+
* BUG FIX: Categories applied by `cats` setting should no longer prevent
|
76 |
+
category-based filtering from working. In FeedWordPress, you can (1)
|
77 |
+
apply certain categories to all syndicated posts, or all posts from
|
78 |
+
a particular feed; and (2) filter out all posts that don't match one
|
79 |
+
of the categories that are already in the WordPress database (allowing
|
80 |
+
for simple category-based filtering; just load up WordPress with the
|
81 |
+
categories you want to accept, and then tell FeedWordPress not to create
|
82 |
+
new ones). However, the way that (1) and (2) were implemented meant that
|
83 |
+
you couldn't effectively use them together; once you applied a known
|
84 |
+
category to all syndicated posts from a particular feed, it meant that
|
85 |
+
they'd have at least one familiar category (the category or categories
|
86 |
+
you were applying), and that would get all posts past the filter no
|
87 |
+
matter what categories they were originally from.
|
88 |
+
|
89 |
+
Well, no longer. You can still apply categories to all syndicated posts
|
90 |
+
(using either Syndication --> Options, or the feed-level settings under
|
91 |
+
Links --> Syndicated). But these categories are not applied to the post
|
92 |
+
until *after* it has already passed by the "familiar categories" filter.
|
93 |
+
So now, if you want, you can do category filtering and *then* apply as
|
94 |
+
many categories as you please to all and only posts that pass the filter.
|
95 |
+
|
96 |
+
* BUG FIX: Other minor typos and HTML gaffes were fixed along the way.
|
97 |
+
|
98 |
+
* PERFORMANCE: get_feed_meta() no longer hits the database for information
|
99 |
+
on every call; it now caches link data in memory, so FeedWordPress only
|
100 |
+
goes to the database once for each syndicated link. This may
|
101 |
+
substantially improve performance if your database server resources
|
102 |
+
are tight and your templates make a lot of use of custom settings from
|
103 |
+
get_feed_meta().
|
104 |
+
|
105 |
+
* API CHANGE: Link ID numbers, rather than RSS URIs, are now used to
|
106 |
+
identify the feed from which a post is syndicated when you use template
|
107 |
+
functions such as get_feed_meta(). The practical upshot of this is you
|
108 |
+
can switch feeds, or change the feed address for a particular syndicated
|
109 |
+
site, without breaking your templates for all the posts that were
|
110 |
+
syndicated from the earlier URI.
|
111 |
+
|
112 |
+
* API CHANGE: if you have plugins or templates that make use of the
|
113 |
+
get_feed_meta() function or the $fwp_feedmeta global, note that the
|
114 |
+
data formerly located under the `uri` and `name` fields is now located
|
115 |
+
under the `link/uri` field and the `link/name` field, respectively. Note
|
116 |
+
also that you can access the link ID number for any given feed under the
|
117 |
+
global $fwp_feedmeta['link/id'] (in plugins) or
|
118 |
+
get_feed_meta('link/id') (in a template in post contexts).
|
119 |
+
|
120 |
+
* FEATURE: the settings for individual feeds can now be edited using a
|
121 |
+
humane interface (where formerly you had to tweak key-value pairs in the
|
122 |
+
Link Notes section). To edit settings for a feed, pick the feed that you
|
123 |
+
want under Links --> Syndicated and click the Edit link.
|
124 |
+
|
125 |
+
* FEATURE: The "Unsubscribe" button (formerly "Delete") in Links -->
|
126 |
+
Syndicated now offers three options for unsubscribing from a feed: (1)
|
127 |
+
turning off the subscription without deleting the feed data or affecting
|
128 |
+
posts that were syndicated from the feed (this works by setting the Link
|
129 |
+
for the feed as "invisible"); (2) deleting the feed data and all of the
|
130 |
+
posts that were syndicated from the feed; or (3) deleting the feed data
|
131 |
+
and *keeping* the posts that were syndicated from the feed
|
132 |
+
setting the Link to "Invisible" (meaning that it will not be displayed
|
133 |
+
in lists of the site links on the front page, and it won't be checked
|
134 |
+
for updates; (2) deleting the Link and all of the posts that were
|
135 |
+
syndicated from its feed; or (3) deleting the feed data but keeping the
|
136 |
+
posts that were syndicated (which will henceforward be treated as if
|
137 |
+
they were local rather than syndicated posts). (Note that (1) is usually
|
138 |
+
the best option for aggregator sites, unless you want to clean up the
|
139 |
+
results of an error or a test.)
|
140 |
+
|
141 |
+
* FEATURE / BUG FIX: If you have been receiving mysterious "I don't
|
142 |
+
syndicate...", or "(local) HTTP status code was not 200", or "(local)
|
143 |
+
transport error - could not open socket", or "parse error - not well
|
144 |
+
formed" errors, then this update may solve your problems, and if it does
|
145 |
+
*not* solve them, it will at least make the reasons for the problems
|
146 |
+
easier to understand. That's because I've overhauled the way that
|
147 |
+
FeedWordPress goes about updating feeds.
|
148 |
+
|
149 |
+
If you use the command-line PHP scripting method to run scheduled
|
150 |
+
updates, then not much should change for you, except for fewer
|
151 |
+
mysterious errors. If you have done updates by sending periodic HTTP
|
152 |
+
requests to <http://your-blog.com/path/wp-content/update-feeds.php>,
|
153 |
+
then the details have changed somewhat; mostly in such a way as to make
|
154 |
+
things easier on you. See the README file or online documentation on
|
155 |
+
Staying Current for the details.
|
156 |
+
|
157 |
+
* FEATURE: FeedWordPress now features a more sophisticated system for
|
158 |
+
timed updates. Instead of polling *every* subscribed feed for updates
|
159 |
+
*each* time `update-feeds.php` is run, FeedWordPress now keeps track of
|
160 |
+
the last time it polled each feed, and only polls them again after a
|
161 |
+
certain period of time has passed. The amount of time is normally set
|
162 |
+
randomly for each feed, in a period between 30 minutes and 2 hours (so
|
163 |
+
as to stagger updates over time rather than polling all of the feeds at once. However, the length of time between updates can also be set
|
164 |
+
directly by the feed, which brings us to ...
|
165 |
+
|
166 |
+
* FEATURE: FeedWordPress now respects the settings in the `ttl` and
|
167 |
+
Syndication Module RSS elements. Feeds with these elements set will not
|
168 |
+
be polled any more frequently than they indicate with these feeds unless
|
169 |
+
the user manually forces FeedWordPress to poll the feed (see Links -->
|
170 |
+
Syndicated --> Edit settings).
|
171 |
|
172 |
Changes from 0.95 to 0.96
|
173 |
-------------------------
|
OPTIONAL/wp-includes/rss-functions.php
CHANGED
@@ -4,20 +4,21 @@
|
|
4 |
* Author: Kellan Elliot-McCrea <kellan@protest.net>
|
5 |
* WordPress development team <http://www.wordpress.org/>
|
6 |
* Charles Johnson <technophilia@radgeek.com>
|
7 |
-
* Version: 0.
|
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
|
15 |
-
*
|
16 |
-
*
|
17 |
-
*
|
18 |
-
* (2) the
|
19 |
-
*
|
20 |
-
*
|
|
|
21 |
*
|
22 |
* Differences from the main branch of MagpieRSS:
|
23 |
*
|
@@ -33,37 +34,74 @@
|
|
33 |
*
|
34 |
* 4. There are two WordPress-specific functions, get_rss() and wp_rss()
|
35 |
*
|
36 |
-
*
|
37 |
-
* MagpieRSS::feed_end_element(), and MagpieRSS::normalize() to handle:
|
38 |
*
|
39 |
-
*
|
40 |
-
*
|
|
|
|
|
|
|
41 |
*
|
42 |
-
*
|
43 |
-
* $item['dc']['subject'], and $item['dc']['subjects'] (the singular keys
|
44 |
-
* point to string values for the first category used; the plural keys
|
45 |
-
* point to an array of all the categories the item is in)
|
46 |
*
|
47 |
-
*
|
48 |
-
*
|
49 |
-
*
|
50 |
-
*
|
51 |
-
*
|
|
|
|
|
|
|
|
|
52 |
*
|
53 |
-
*
|
54 |
-
*
|
55 |
-
*
|
56 |
-
*
|
57 |
-
*
|
58 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
*/
|
60 |
|
61 |
define('RSS', 'RSS');
|
62 |
define('ATOM', 'Atom');
|
63 |
-
define('MAGPIE_USER_AGENT', 'WordPress/' . $wp_version);
|
64 |
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
/**
|
68 |
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
|
69 |
*
|
@@ -89,21 +127,26 @@ class MagpieRSS {
|
|
89 |
|
90 |
// define some constants
|
91 |
|
92 |
-
var $
|
|
|
|
|
|
|
|
|
|
|
93 |
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
|
94 |
|
95 |
// parser variables, useless if you're not a parser, treat as private
|
96 |
var $stack = array(); // parser stack
|
97 |
var $inchannel = false;
|
98 |
var $initem = false;
|
99 |
-
|
|
|
|
|
|
|
100 |
var $intextinput = false;
|
101 |
var $inimage = false;
|
102 |
var $current_namespace = false;
|
103 |
|
104 |
-
var $incategory = false;
|
105 |
-
var $current_category = 0;
|
106 |
-
|
107 |
/**
|
108 |
* Set up XML parser, parse source, and return populated RSS object..
|
109 |
*
|
@@ -164,7 +207,7 @@ class MagpieRSS {
|
|
164 |
'feed_start_element', 'feed_end_element' );
|
165 |
|
166 |
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
|
167 |
-
|
168 |
$status = xml_parse( $this->parser, $source );
|
169 |
|
170 |
if (! $status ) {
|
@@ -189,14 +232,16 @@ class MagpieRSS {
|
|
189 |
$attrs = array_change_key_case($attrs, CASE_LOWER);
|
190 |
|
191 |
// check for a namespace, and split if found
|
192 |
-
$
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
|
|
|
|
200 |
# if feed type isn't set, then this is first element of feed
|
201 |
# identify feed from root element
|
202 |
#
|
@@ -211,16 +256,38 @@ class MagpieRSS {
|
|
211 |
}
|
212 |
elseif ( $el == 'feed' ) {
|
213 |
$this->feed_type = ATOM;
|
214 |
-
|
|
|
|
|
|
|
|
|
|
|
215 |
$this->inchannel = true;
|
216 |
}
|
217 |
return;
|
218 |
}
|
219 |
|
220 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
{
|
222 |
$this->inchannel = true;
|
223 |
}
|
|
|
224 |
elseif ($el == 'item' or $el == 'entry' )
|
225 |
{
|
226 |
$this->initem = true;
|
@@ -228,12 +295,7 @@ class MagpieRSS {
|
|
228 |
$this->current_item['about'] = $attrs['rdf:about'];
|
229 |
}
|
230 |
}
|
231 |
-
|
232 |
-
elseif ($this->initem and ($el == 'category' or ($this->current_namespace == 'dc' and $el == 'subject'))) {
|
233 |
-
$this->incategory = true;
|
234 |
-
array_unshift( $this->stack, $el );
|
235 |
-
}
|
236 |
-
|
237 |
// if we're in the default namespace of an RSS feed,
|
238 |
// record textinput or image fields
|
239 |
elseif (
|
@@ -252,82 +314,87 @@ class MagpieRSS {
|
|
252 |
$this->inimage = true;
|
253 |
}
|
254 |
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
$this->current_item[$el][] = $attrs;
|
261 |
-
$this->incontent = $el;
|
262 |
-
}
|
263 |
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
|
|
|
|
276 |
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
array_map('map_attrs',
|
283 |
-
array_keys($attrs),
|
284 |
-
array_values($attrs) ) );
|
285 |
-
|
286 |
-
$this->append_content( "<$element $attrs_str>" );
|
287 |
-
|
288 |
-
array_unshift( $this->stack, $el );
|
289 |
-
}
|
290 |
-
|
291 |
-
// Atom support many links per containging element.
|
292 |
-
// Magpie treats link elements of type rel='alternate'
|
293 |
-
// as being equivalent to RSS's simple link element.
|
294 |
-
//
|
295 |
-
elseif ($this->feed_type == ATOM and $el == 'link' )
|
296 |
-
{
|
297 |
-
# -- CWJ: Treat <link> elements without explicit rel as rel="alternate"
|
298 |
-
if ( !isset($attrs['rel']) or isset($attrs['rel']) and $attrs['rel'] == 'alternate' )
|
299 |
-
{
|
300 |
-
$link_el = 'link';
|
301 |
-
}
|
302 |
-
# -- CWJ: support Atom 0.6+ enclosures
|
303 |
-
elseif ( isset($attrs['rel']) and $attrs['rel'] == 'enclosure' )
|
304 |
-
{
|
305 |
-
$link_el = 'link_' . $attrs['rel'];
|
306 |
-
|
307 |
-
# -- CWJ: Normalize to RSS 2.0 enclosure handling
|
308 |
-
$n = count($this->current_item[$attrs['rel']]);
|
309 |
-
$this->current_item[$attrs['rel']][$n] = $attrs;
|
310 |
-
$this->current_item[$attrs['rel']][$n]['url'] =
|
311 |
-
$this->current_item[$attrs['rel']][$n]['href'];
|
312 |
-
}
|
313 |
-
else {
|
314 |
-
$link_el = 'link_' . $attrs['rel'];
|
315 |
-
}
|
316 |
-
|
317 |
-
$this->append($link_el, $attrs['href']);
|
318 |
-
}
|
319 |
|
320 |
-
|
321 |
-
|
322 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
}
|
324 |
}
|
325 |
|
326 |
|
327 |
|
328 |
function feed_cdata ($p, $text) {
|
329 |
-
|
330 |
-
{
|
331 |
$this->append_content( $text );
|
332 |
}
|
333 |
else {
|
@@ -339,7 +406,32 @@ class MagpieRSS {
|
|
339 |
function feed_end_element ($p, $el) {
|
340 |
$el = strtolower($el);
|
341 |
|
342 |
-
if ( $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
{
|
344 |
$this->items[] = $this->current_item;
|
345 |
$this->current_item = array();
|
@@ -347,12 +439,7 @@ class MagpieRSS {
|
|
347 |
|
348 |
$this->current_category = 0;
|
349 |
}
|
350 |
-
|
351 |
-
$this->incategory = false;
|
352 |
-
$this->current_category = $this->current_category + 1;
|
353 |
-
array_shift( $this->stack );
|
354 |
-
}
|
355 |
-
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
|
356 |
{
|
357 |
$this->intextinput = false;
|
358 |
}
|
@@ -360,32 +447,17 @@ class MagpieRSS {
|
|
360 |
{
|
361 |
$this->inimage = false;
|
362 |
}
|
363 |
-
elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
|
364 |
-
{
|
365 |
-
$this->incontent = false;
|
366 |
-
}
|
367 |
elseif ($el == 'channel' or $el == 'feed' )
|
368 |
{
|
369 |
$this->inchannel = false;
|
370 |
}
|
371 |
-
elseif ($this->feed_type == ATOM and $this->incontent ) {
|
372 |
-
// balance tags properly
|
373 |
-
// note: i don't think this is actually neccessary
|
374 |
-
if ( $this->stack[0] == $el )
|
375 |
-
{
|
376 |
-
$this->append_content("</$el>");
|
377 |
-
}
|
378 |
-
else {
|
379 |
-
$this->append_content("<$el />");
|
380 |
-
}
|
381 |
-
|
382 |
-
array_shift( $this->stack );
|
383 |
-
}
|
384 |
else {
|
385 |
-
|
386 |
}
|
387 |
|
388 |
-
|
|
|
|
|
389 |
}
|
390 |
|
391 |
function concat (&$str1, $str2="") {
|
@@ -395,15 +467,21 @@ class MagpieRSS {
|
|
395 |
$str1 .= $str2;
|
396 |
}
|
397 |
|
398 |
-
|
399 |
-
|
400 |
function append_content($text) {
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
}
|
408 |
|
409 |
// smart append - field and namespace aware
|
@@ -413,17 +491,14 @@ class MagpieRSS {
|
|
413 |
}
|
414 |
if ( $this->current_namespace )
|
415 |
{
|
416 |
-
if ( $this->
|
417 |
-
|
418 |
-
|
419 |
-
elseif ( $this->initem ) {
|
420 |
-
$this->concat(
|
421 |
-
$this->current_item[ $this->current_namespace ][ $el ], $text );
|
422 |
}
|
423 |
elseif ($this->inchannel) {
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
elseif ($this->intextinput) {
|
428 |
$this->concat(
|
429 |
$this->textinput[ $this->current_namespace][ $el ], $text );
|
@@ -434,12 +509,9 @@ class MagpieRSS {
|
|
434 |
}
|
435 |
}
|
436 |
else {
|
437 |
-
if ( $this->
|
438 |
-
|
439 |
-
|
440 |
-
elseif ( $this->initem ) {
|
441 |
-
$this->concat(
|
442 |
-
$this->current_item[ $el ], $text);
|
443 |
}
|
444 |
elseif ($this->intextinput) {
|
445 |
$this->concat(
|
@@ -450,50 +522,267 @@ class MagpieRSS {
|
|
450 |
$this->image[ $el ], $text );
|
451 |
}
|
452 |
elseif ($this->inchannel) {
|
453 |
-
|
454 |
-
|
455 |
}
|
456 |
|
457 |
}
|
458 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
function normalize () {
|
461 |
-
// if atom populate rss fields
|
462 |
if ( $this->is_atom() ) {
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
$item['date_timestamp'] = $epoch;
|
476 |
-
}
|
477 |
-
}
|
478 |
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
}
|
488 |
elseif ( $this->is_rss() ) {
|
489 |
-
|
|
|
|
|
|
|
|
|
490 |
for ( $i = 0; $i < count($this->items); $i++) {
|
491 |
$item = $this->items[$i];
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
|
498 |
$epoch = @parse_w3cdtf($item['dc']['date']);
|
499 |
if ($epoch and $epoch > 0) {
|
@@ -506,12 +795,6 @@ class MagpieRSS {
|
|
506 |
$item['date_timestamp'] = $epoch;
|
507 |
}
|
508 |
}
|
509 |
-
|
510 |
-
if ( is_array($item['categories']) ) {
|
511 |
-
$item['category'] = $item['categories'][0];
|
512 |
-
$item['dc']['subjects'] = $item['categories'];
|
513 |
-
$item['dc']['subject'] = $item['category'];
|
514 |
-
}
|
515 |
|
516 |
$this->items[$i] = $item;
|
517 |
}
|
@@ -651,7 +934,7 @@ class MagpieRSS {
|
|
651 |
|
652 |
function error ($errormsg, $lvl=E_USER_WARNING) {
|
653 |
// append PHP's error message if track_errors enabled
|
654 |
-
if ( $php_errormsg ) {
|
655 |
$errormsg .= " ($php_errormsg)";
|
656 |
}
|
657 |
if ( MAGPIE_DEBUG ) {
|
@@ -668,17 +951,71 @@ class MagpieRSS {
|
|
668 |
$this->ERROR = $errormsg;
|
669 |
}
|
670 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
671 |
} // end class RSS
|
672 |
|
673 |
function map_attrs($k, $v) {
|
674 |
return "$k=\"$v\"";
|
675 |
}
|
676 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
677 |
|
678 |
require_once( dirname(__FILE__) . '/class-snoopy.php');
|
679 |
|
680 |
-
|
681 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
682 |
function fetch_rss ($url) {
|
683 |
// initialize constants
|
684 |
init();
|
@@ -733,7 +1070,7 @@ function fetch_rss ($url) {
|
|
733 |
if ( $cache_status == 'HIT' ) {
|
734 |
$rss = $cache->get( $cache_key );
|
735 |
if ( isset($rss) and $rss ) {
|
736 |
-
|
737 |
$rss->from_cache = 1;
|
738 |
if ( MAGPIE_DEBUG > 1) {
|
739 |
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
|
@@ -850,10 +1187,7 @@ function magpie_error ($errormsg="") {
|
|
850 |
|
851 |
return $MAGPIE_ERROR;
|
852 |
}
|
853 |
-
# --- cut here ---
|
854 |
|
855 |
-
# UPDATED FROM: rss_fetch.inc: _fetch_remote_file, _response_to_rss, init
|
856 |
-
# --- cut here ---
|
857 |
/*=======================================================================*\
|
858 |
Function: _fetch_remote_file
|
859 |
Purpose: retrieve an arbitrary remote file
|
@@ -952,11 +1286,7 @@ function init () {
|
|
952 |
}
|
953 |
|
954 |
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
|
955 |
-
|
956 |
-
# --- cut here ---
|
957 |
-
$wp_encoding = get_settings('blog_charset');
|
958 |
-
define('MAGPIE_OUTPUT_ENCODING', ($wp_encoding?$wp_encoding:'ISO-8859-1'));
|
959 |
-
# --- cut here ---
|
960 |
}
|
961 |
|
962 |
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
|
@@ -972,11 +1302,8 @@ function init () {
|
|
972 |
}
|
973 |
|
974 |
if ( !defined('MAGPIE_USER_AGENT') ) {
|
975 |
-
|
976 |
-
|
977 |
-
$ua = 'WordPress/'. $wp_version . ' (+http://www.wordpress.org';
|
978 |
-
# --- cut here ---
|
979 |
-
|
980 |
if ( MAGPIE_CACHE_ON ) {
|
981 |
$ua = $ua . ')';
|
982 |
}
|
@@ -996,34 +1323,73 @@ function init () {
|
|
996 |
define('MAGPIE_USE_GZIP', true);
|
997 |
}
|
998 |
}
|
999 |
-
# --- cut here ---
|
1000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1001 |
function is_info ($sc) {
|
1002 |
-
|
1003 |
}
|
1004 |
|
|
|
|
|
|
|
|
|
1005 |
function is_success ($sc) {
|
1006 |
-
|
1007 |
}
|
1008 |
|
|
|
|
|
|
|
|
|
1009 |
function is_redirect ($sc) {
|
1010 |
-
|
1011 |
}
|
1012 |
|
|
|
|
|
|
|
|
|
1013 |
function is_error ($sc) {
|
1014 |
-
|
1015 |
}
|
1016 |
|
|
|
|
|
|
|
|
|
1017 |
function is_client_error ($sc) {
|
1018 |
-
|
1019 |
}
|
1020 |
|
|
|
|
|
|
|
|
|
1021 |
function is_server_error ($sc) {
|
1022 |
-
|
1023 |
}
|
1024 |
|
1025 |
-
|
1026 |
-
|
|
|
|
|
1027 |
class RSSCache {
|
1028 |
var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
|
1029 |
var $MAX_AGE = 43200; // when are files stale, default twelve hours
|
@@ -1161,52 +1527,74 @@ class RSSCache {
|
|
1161 |
}
|
1162 |
}
|
1163 |
}
|
1164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1165 |
|
1166 |
function parse_w3cdtf ( $date_str ) {
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1206 |
}
|
1207 |
|
1208 |
-
|
1209 |
-
|
|
|
|
|
1210 |
function wp_rss ($url, $num) {
|
1211 |
//ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
|
1212 |
$num_items = $num;
|
@@ -1244,5 +1632,4 @@ function get_rss ($uri, $num = 5) { // Like get posts, but for RSS
|
|
1244 |
return false;
|
1245 |
}
|
1246 |
}
|
1247 |
-
# --- cut here ---
|
1248 |
?>
|
4 |
* Author: Kellan Elliot-McCrea <kellan@protest.net>
|
5 |
* WordPress development team <http://www.wordpress.org/>
|
6 |
* Charles Johnson <technophilia@radgeek.com>
|
7 |
+
* Version: 0.8wp (2005.10.14)
|
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 |
*
|
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_settings('blog_charset');
|
99 |
+
define('MAGPIE_OUTPUT_ENCODING', ($wp_encoding?$wp_encoding:'ISO-8859-1'));
|
100 |
+
|
101 |
+
################################################################################
|
102 |
+
## rss_parse.inc: from MagpieRSS 0.8a ##########################################
|
103 |
+
################################################################################
|
104 |
+
|
105 |
/**
|
106 |
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
|
107 |
*
|
127 |
|
128 |
// define some constants
|
129 |
|
130 |
+
var $_ATOM_CONTENT_CONSTRUCTS = array(
|
131 |
+
'content', 'summary', 'title', /* common */
|
132 |
+
'info', 'tagline', 'copyright', /* Atom 0.3 */
|
133 |
+
'rights', 'subtitle', /* Atom 1.0 */
|
134 |
+
);
|
135 |
+
var $_XHTML_CONTENT_CONSTRUCTS = array('body', 'div');
|
136 |
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1');
|
137 |
|
138 |
// parser variables, useless if you're not a parser, treat as private
|
139 |
var $stack = array(); // parser stack
|
140 |
var $inchannel = false;
|
141 |
var $initem = false;
|
142 |
+
|
143 |
+
var $incontent = array(); // non-empty if in namespaced XML content field
|
144 |
+
var $exclude_top = false; // true when Atom 1.0 type="xhtml"
|
145 |
+
|
146 |
var $intextinput = false;
|
147 |
var $inimage = false;
|
148 |
var $current_namespace = false;
|
149 |
|
|
|
|
|
|
|
150 |
/**
|
151 |
* Set up XML parser, parse source, and return populated RSS object..
|
152 |
*
|
207 |
'feed_start_element', 'feed_end_element' );
|
208 |
|
209 |
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
|
210 |
+
|
211 |
$status = xml_parse( $this->parser, $source );
|
212 |
|
213 |
if (! $status ) {
|
232 |
$attrs = array_change_key_case($attrs, CASE_LOWER);
|
233 |
|
234 |
// check for a namespace, and split if found
|
235 |
+
if ( empty($this->incontent) ) { // Don't munge content tags
|
236 |
+
$ns = false;
|
237 |
+
if ( strpos( $element, ':' ) ) {
|
238 |
+
list($ns, $el) = split( ':', $element, 2);
|
239 |
+
}
|
240 |
+
if ( $ns and $ns != 'rdf' ) {
|
241 |
+
$this->current_namespace = $ns;
|
242 |
+
}
|
243 |
+
}
|
244 |
+
|
245 |
# if feed type isn't set, then this is first element of feed
|
246 |
# identify feed from root element
|
247 |
#
|
256 |
}
|
257 |
elseif ( $el == 'feed' ) {
|
258 |
$this->feed_type = ATOM;
|
259 |
+
if ($attrs['xmlns'] == 'http://www.w3.org/2005/Atom') { // Atom 1.0
|
260 |
+
$this->feed_version = '1.0';
|
261 |
+
}
|
262 |
+
else { // Atom 0.3, probably.
|
263 |
+
$this->feed_version = $attrs['version'];
|
264 |
+
}
|
265 |
$this->inchannel = true;
|
266 |
}
|
267 |
return;
|
268 |
}
|
269 |
|
270 |
+
// if we're inside a namespaced content construct, treat tags as text
|
271 |
+
if ( !empty($this->incontent) )
|
272 |
+
{
|
273 |
+
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
274 |
+
// if tags are inlined, then flatten
|
275 |
+
$attrs_str = join(' ',
|
276 |
+
array_map('map_attrs',
|
277 |
+
array_keys($attrs),
|
278 |
+
array_values($attrs) ) );
|
279 |
+
if (strlen($attrs_str) > 0) $attrs_str = ' '.$attrs_str;
|
280 |
+
|
281 |
+
$this->append_content( "<{$element}{$attrs_str}>" );
|
282 |
+
}
|
283 |
+
array_push($this->incontent, $el); // stack for parsing content XML
|
284 |
+
}
|
285 |
+
|
286 |
+
elseif ( $el == 'channel' )
|
287 |
{
|
288 |
$this->inchannel = true;
|
289 |
}
|
290 |
+
|
291 |
elseif ($el == 'item' or $el == 'entry' )
|
292 |
{
|
293 |
$this->initem = true;
|
295 |
$this->current_item['about'] = $attrs['rdf:about'];
|
296 |
}
|
297 |
}
|
298 |
+
|
|
|
|
|
|
|
|
|
|
|
299 |
// if we're in the default namespace of an RSS feed,
|
300 |
// record textinput or image fields
|
301 |
elseif (
|
314 |
$this->inimage = true;
|
315 |
}
|
316 |
|
317 |
+
// set stack[0] to current element
|
318 |
+
else {
|
319 |
+
// Atom support many links per containing element.
|
320 |
+
// Magpie treats link elements of type rel='alternate'
|
321 |
+
// as being equivalent to RSS's simple link element.
|
|
|
|
|
|
|
322 |
|
323 |
+
$atom_link = false;
|
324 |
+
if ($this->feed_type == ATOM and $el == 'link') {
|
325 |
+
$atom_link = true;
|
326 |
+
if (isset($attrs['rel']) and $attrs['rel'] != 'alternate') {
|
327 |
+
$el = $el . "_" . $attrs['rel']; // pseudo-element names for Atom link elements
|
328 |
+
}
|
329 |
+
}
|
330 |
+
# handle atom content constructs
|
331 |
+
elseif ( $this->feed_type == ATOM and in_array($el, $this->_ATOM_CONTENT_CONSTRUCTS) )
|
332 |
+
{
|
333 |
+
// avoid clashing w/ RSS mod_content
|
334 |
+
if ($el == 'content' ) {
|
335 |
+
$el = 'atom_content';
|
336 |
+
}
|
337 |
|
338 |
+
// assume that everything accepts namespaced XML
|
339 |
+
// (that will pass through some non-validating feeds;
|
340 |
+
// but so what? this isn't a validating parser)
|
341 |
+
$this->incontent = array();
|
342 |
+
array_push($this->incontent, $el); // start a stack
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
|
344 |
+
if (
|
345 |
+
isset($attrs['type'])
|
346 |
+
and trim(strtolower($attrs['type']))=='xhtml'
|
347 |
+
) {
|
348 |
+
$this->exclude_top = true;
|
349 |
+
} else {
|
350 |
+
$this->exclude_top = false;
|
351 |
+
}
|
352 |
+
}
|
353 |
+
# Handle inline XHTML body elements --CWJ
|
354 |
+
elseif (
|
355 |
+
($this->current_namespace=='xhtml' or (isset($attrs['xmlns']) and $attrs['xmlns'] == 'http://www.w3.org/1999/xhtml'))
|
356 |
+
and in_array($el, $this->_XHTML_CONTENT_CONSTRUCTS) )
|
357 |
+
{
|
358 |
+
$this->current_namespace = 'xhtml';
|
359 |
+
$this->incontent = array();
|
360 |
+
array_push($this->incontent, $el); // start a stack
|
361 |
+
$this->exclude_top = false;
|
362 |
+
}
|
363 |
+
|
364 |
+
array_unshift($this->stack, $el);
|
365 |
+
$elpath = join('_', array_reverse($this->stack));
|
366 |
+
|
367 |
+
$n = $this->element_count($elpath);
|
368 |
+
$this->element_count($elpath, $n+1);
|
369 |
+
|
370 |
+
if ($n > 0) {
|
371 |
+
array_shift($this->stack);
|
372 |
+
array_unshift($this->stack, $el.'#'.($n+1));
|
373 |
+
$elpath = join('_', array_reverse($this->stack));
|
374 |
+
}
|
375 |
+
|
376 |
+
// this makes the baby Jesus cry, but we can't do it in normalize()
|
377 |
+
// because we've made the element name for Atom links unpredictable
|
378 |
+
// by tacking on the relation to the end. -CWJ
|
379 |
+
if ($atom_link and isset($attrs['href'])) {
|
380 |
+
$this->append($elpath, $attrs['href']);
|
381 |
+
}
|
382 |
+
|
383 |
+
// add attributes
|
384 |
+
if (count($attrs) > 0) {
|
385 |
+
$this->append($elpath.'@', join(',', array_keys($attrs)));
|
386 |
+
foreach ($attrs as $attr => $value) {
|
387 |
+
$this->append($elpath.'@'.$attr, $value);
|
388 |
+
}
|
389 |
+
}
|
390 |
}
|
391 |
}
|
392 |
|
393 |
|
394 |
|
395 |
function feed_cdata ($p, $text) {
|
396 |
+
|
397 |
+
if ($this->incontent) {
|
398 |
$this->append_content( $text );
|
399 |
}
|
400 |
else {
|
406 |
function feed_end_element ($p, $el) {
|
407 |
$el = strtolower($el);
|
408 |
|
409 |
+
if ( $this->incontent ) {
|
410 |
+
$opener = array_pop($this->incontent);
|
411 |
+
|
412 |
+
// Don't get bamboozled by namespace voodoo
|
413 |
+
if (strpos($el, ':')) { list($ns, $closer) = split(':', $el); }
|
414 |
+
else { $ns = false; $closer = $el; }
|
415 |
+
|
416 |
+
// Don't get bamboozled by our munging of <atom:content>, either
|
417 |
+
if ($this->feed_type == ATOM and $closer == 'content') {
|
418 |
+
$closer = 'atom_content';
|
419 |
+
}
|
420 |
+
|
421 |
+
// balance tags properly
|
422 |
+
// note: i don't think this is actually neccessary
|
423 |
+
if ($opener != $closer) {
|
424 |
+
array_push($this->incontent, $opener);
|
425 |
+
$this->append_content("<$el />");
|
426 |
+
} elseif ($this->incontent) { // are we in the content construct still?
|
427 |
+
if ((count($this->incontent) > 1) or !$this->exclude_top) {
|
428 |
+
$this->append_content("</$el>");
|
429 |
+
}
|
430 |
+
} else { // shift the opening of the content construct off the normal stack
|
431 |
+
array_shift( $this->stack );
|
432 |
+
}
|
433 |
+
}
|
434 |
+
elseif ( $el == 'item' or $el == 'entry' )
|
435 |
{
|
436 |
$this->items[] = $this->current_item;
|
437 |
$this->current_item = array();
|
439 |
|
440 |
$this->current_category = 0;
|
441 |
}
|
442 |
+
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
|
|
|
|
|
|
|
|
|
|
|
443 |
{
|
444 |
$this->intextinput = false;
|
445 |
}
|
447 |
{
|
448 |
$this->inimage = false;
|
449 |
}
|
|
|
|
|
|
|
|
|
450 |
elseif ($el == 'channel' or $el == 'feed' )
|
451 |
{
|
452 |
$this->inchannel = false;
|
453 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
else {
|
455 |
+
array_shift( $this->stack );
|
456 |
}
|
457 |
|
458 |
+
if ( !$this->incontent ) { // Don't munge the namespace after finishing with elements in namespaced content constructs -CWJ
|
459 |
+
$this->current_namespace = false;
|
460 |
+
}
|
461 |
}
|
462 |
|
463 |
function concat (&$str1, $str2="") {
|
467 |
$str1 .= $str2;
|
468 |
}
|
469 |
|
|
|
|
|
470 |
function append_content($text) {
|
471 |
+
if ( $this->initem ) {
|
472 |
+
if ($this->current_namespace) {
|
473 |
+
$this->concat( $this->current_item[$this->current_namespace][ reset($this->incontent) ], $text );
|
474 |
+
} else {
|
475 |
+
$this->concat( $this->current_item[ reset($this->incontent) ], $text );
|
476 |
+
}
|
477 |
+
}
|
478 |
+
elseif ( $this->inchannel ) {
|
479 |
+
if ($this->current_namespace) {
|
480 |
+
$this->concat( $this->channel[$this->current_namespace][ reset($this->incontent) ], $text );
|
481 |
+
} else {
|
482 |
+
$this->concat( $this->channel[ reset($this->incontent) ], $text );
|
483 |
+
}
|
484 |
+
}
|
485 |
}
|
486 |
|
487 |
// smart append - field and namespace aware
|
491 |
}
|
492 |
if ( $this->current_namespace )
|
493 |
{
|
494 |
+
if ( $this->initem ) {
|
495 |
+
$this->concat(
|
496 |
+
$this->current_item[ $this->current_namespace ][ $el ], $text);
|
|
|
|
|
|
|
497 |
}
|
498 |
elseif ($this->inchannel) {
|
499 |
+
$this->concat(
|
500 |
+
$this->channel[ $this->current_namespace][ $el ], $text );
|
501 |
+
}
|
502 |
elseif ($this->intextinput) {
|
503 |
$this->concat(
|
504 |
$this->textinput[ $this->current_namespace][ $el ], $text );
|
509 |
}
|
510 |
}
|
511 |
else {
|
512 |
+
if ( $this->initem ) {
|
513 |
+
$this->concat(
|
514 |
+
$this->current_item[ $el ], $text);
|
|
|
|
|
|
|
515 |
}
|
516 |
elseif ($this->intextinput) {
|
517 |
$this->concat(
|
522 |
$this->image[ $el ], $text );
|
523 |
}
|
524 |
elseif ($this->inchannel) {
|
525 |
+
$this->concat(
|
526 |
+
$this->channel[ $el ], $text );
|
527 |
}
|
528 |
|
529 |
}
|
530 |
}
|
531 |
+
|
532 |
+
// smart count - field and namespace aware
|
533 |
+
function element_count ($el, $set = NULL) {
|
534 |
+
if (!$el) {
|
535 |
+
return;
|
536 |
+
}
|
537 |
+
if ( $this->current_namespace )
|
538 |
+
{
|
539 |
+
if ( $this->initem ) {
|
540 |
+
if (!is_null($set)) { $this->current_item[ $this->current_namespace ][ $el.'#' ] = $set; }
|
541 |
+
$ret = (isset($this->current_item[ $this->current_namespace ][ $el.'#' ]) ?
|
542 |
+
$this->current_item[ $this->current_namespace ][ $el.'#' ] : 0);
|
543 |
+
}
|
544 |
+
elseif ($this->inchannel) {
|
545 |
+
if (!is_null($set)) { $this->channel[ $this->current_namespace ][ $el.'#' ] = $set; }
|
546 |
+
$ret = (isset($this->channel[ $this->current_namespace][ $el.'#' ]) ?
|
547 |
+
$this->channel[ $this->current_namespace][ $el.'#' ] : 0);
|
548 |
+
}
|
549 |
+
}
|
550 |
+
else {
|
551 |
+
if ( $this->initem ) {
|
552 |
+
if (!is_null($set)) { $this->current_item[ $el.'#' ] = $set; }
|
553 |
+
$ret = (isset($this->current_item[ $el.'#' ]) ?
|
554 |
+
$this->current_item[ $el.'#' ] : 0);
|
555 |
+
}
|
556 |
+
elseif ($this->inchannel) {
|
557 |
+
if (!is_null($set)) {$this->channel[ $el.'#' ] = $set; }
|
558 |
+
$ret = (isset($this->channel[ $el.'#' ]) ?
|
559 |
+
$this->channel[ $el.'#' ] : 0);
|
560 |
+
}
|
561 |
+
}
|
562 |
+
return $ret;
|
563 |
+
}
|
564 |
+
|
565 |
+
function normalize_enclosure (&$source, $from, &$dest, $to, $i) {
|
566 |
+
$id_from = $this->element_id($from, $i);
|
567 |
+
$id_to = $this->element_id($to, $i);
|
568 |
+
if (isset($source["{$id_from}@"])) {
|
569 |
+
foreach (explode(',', $source["{$id_from}@"]) as $attr) {
|
570 |
+
if ($from=='link_enclosure' and $attr=='href') { // from Atom
|
571 |
+
$dest["{$id_to}@url"] = $source["{$id_from}@{$attr}"];
|
572 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
573 |
+
}
|
574 |
+
elseif ($from=='enclosure' and $attr=='url') { // from RSS
|
575 |
+
$dest["{$id_to}@href"] = $source["{$id_from}@{$attr}"];
|
576 |
+
$dest["{$id_to}"] = $source["{$id_from}@{$attr}"];
|
577 |
+
}
|
578 |
+
else {
|
579 |
+
$dest["{$id_to}@{$attr}"] = $source["{$id_from}@{$attr}"];
|
580 |
+
}
|
581 |
+
}
|
582 |
+
}
|
583 |
+
}
|
584 |
+
|
585 |
+
function normalize_atom_person (&$source, $person, &$dest, $to, $i) {
|
586 |
+
$id = $this->element_id($person, $i);
|
587 |
+
$id_to = $this->element_id($to, $i);
|
588 |
+
|
589 |
+
// Atom 0.3 <=> Atom 1.0
|
590 |
+
if ($this->feed_version >= 1.0) { $used = 'uri'; $norm = 'url'; }
|
591 |
+
else { $used = 'url'; $norm = 'uri'; }
|
592 |
+
|
593 |
+
if (isset($source["{$id}_{$used}"])) {
|
594 |
+
$dest["{$id_to}_{$norm}"] = $source["{$id}_{$used}"];
|
595 |
+
}
|
596 |
+
|
597 |
+
// Atom to RSS 2.0 and Dublin Core
|
598 |
+
// RSS 2.0 person strings should be valid e-mail addresses if possible.
|
599 |
+
if (isset($source["{$id}_email"])) {
|
600 |
+
$rss_author = $source["{$id}_email"];
|
601 |
+
}
|
602 |
+
if (isset($source["{$id}_name"])) {
|
603 |
+
$rss_author = $source["{$id}_name"]
|
604 |
+
. (isset($rss_author) ? " <$rss_author>" : '');
|
605 |
+
}
|
606 |
+
if (isset($rss_author)) {
|
607 |
+
$source[$id] = $rss_author; // goes to top-level author or contributor
|
608 |
+
$dest[$id_to] = $rss_author; // goes to dc:creator or dc:contributor
|
609 |
+
}
|
610 |
+
}
|
611 |
+
|
612 |
+
// Normalize Atom 1.0 and RSS 2.0 categories to Dublin Core...
|
613 |
+
function normalize_category (&$source, $from, &$dest, $to, $i) {
|
614 |
+
$cat_id = $this->element_id($from, $i);
|
615 |
+
$dc_id = $this->element_id($to, $i);
|
616 |
+
|
617 |
+
// first normalize category elements: Atom 1.0 <=> RSS 2.0
|
618 |
+
if ( isset($source["{$cat_id}@term"]) ) { // category identifier
|
619 |
+
$source[$cat_id] = $source["{$cat_id}@term"];
|
620 |
+
} elseif ( $this->feed_type == RSS ) {
|
621 |
+
$source["{$cat_id}@term"] = $source[$cat_id];
|
622 |
+
}
|
623 |
+
|
624 |
+
if ( isset($source["{$cat_id}@scheme"]) ) { // URI to taxonomy
|
625 |
+
$source["{$cat_id}@domain"] = $source["{$cat_id}@scheme"];
|
626 |
+
} elseif ( isset($source["{$cat_id}@domain"]) ) {
|
627 |
+
$source["{$cat_id}@scheme"] = $source["{$cat_id}@domain"];
|
628 |
+
}
|
629 |
+
|
630 |
+
// Now put the identifier into dc:subject
|
631 |
+
$dest[$dc_id] = $source[$cat_id];
|
632 |
+
}
|
633 |
|
634 |
+
// ... or vice versa
|
635 |
+
function normalize_dc_subject (&$source, $from, &$dest, $to, $i) {
|
636 |
+
$dc_id = $this->element_id($from, $i);
|
637 |
+
$cat_id = $this->element_id($to, $i);
|
638 |
+
|
639 |
+
$dest[$cat_id] = $source[$dc_id]; // RSS 2.0
|
640 |
+
$dest["{$cat_id}@term"] = $source[$dc_id]; // Atom 1.0
|
641 |
+
}
|
642 |
+
|
643 |
+
// simplify the logic for normalize(). Makes sure that count of elements and
|
644 |
+
// each of multiple elements is normalized properly. If you need to mess
|
645 |
+
// with things like attributes or change formats or the like, pass it a
|
646 |
+
// callback to handle each element.
|
647 |
+
function normalize_element (&$source, $from, &$dest, $to, $via = NULL) {
|
648 |
+
if (isset($source[$from]) or isset($source["{$from}#"])) {
|
649 |
+
if (isset($source["{$from}#"])) {
|
650 |
+
$n = $source["{$from}#"];
|
651 |
+
$dest["{$to}#"] = $source["{$from}#"];
|
652 |
+
}
|
653 |
+
else { $n = 1; }
|
654 |
+
|
655 |
+
for ($i = 1; $i <= $n; $i++) {
|
656 |
+
if (isset($via)) { // custom callback for ninja attacks
|
657 |
+
$this->{$via}($source, $from, $dest, $to, $i);
|
658 |
+
}
|
659 |
+
else { // just make it the same
|
660 |
+
$from_id = $this->element_id($from, $i);
|
661 |
+
$to_id = $this->element_id($to, $i);
|
662 |
+
$dest[$to_id] = $source[$from_id];
|
663 |
+
}
|
664 |
+
}
|
665 |
+
}
|
666 |
+
}
|
667 |
+
|
668 |
function normalize () {
|
669 |
+
// if atom populate rss fields and normalize 0.3 and 1.0 feeds
|
670 |
if ( $this->is_atom() ) {
|
671 |
+
// Atom 1.0 elements <=> Atom 0.3 elements (Thanks, o brilliant wordsmiths of the Atom 1.0 standard!)
|
672 |
+
if ($this->feed_version < 1.0) {
|
673 |
+
$this->normalize_element($this->channel, 'tagline', $this->channel, 'subtitle');
|
674 |
+
$this->normalize_element($this->channel, 'copyright', $this->channel, 'rights');
|
675 |
+
$this->normalize_element($this->channel, 'modified', $this->channel, 'updated');
|
676 |
+
} else {
|
677 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'tagline');
|
678 |
+
$this->normalize_element($this->channel, 'rights', $this->channel, 'copyright');
|
679 |
+
$this->normalize_element($this->channel, 'updated', $this->channel, 'modified');
|
680 |
+
}
|
681 |
+
$this->normalize_element($this->channel, 'author', $this->channel['dc'], 'creator', 'normalize_atom_person');
|
682 |
+
$this->normalize_element($this->channel, 'contributor', $this->channel['dc'], 'contributor', 'normalize_atom_person');
|
|
|
|
|
|
|
683 |
|
684 |
+
// Atom elements to RSS elements
|
685 |
+
$this->normalize_element($this->channel, 'subtitle', $this->channel, 'description');
|
686 |
+
|
687 |
+
if ( isset($this->channel['logo']) ) {
|
688 |
+
$this->normalize_element($this->channel, 'logo', $this->image, 'url');
|
689 |
+
$this->normalize_element($this->channel, 'link', $this->image, 'link');
|
690 |
+
$this->normalize_element($this->channel, 'title', $this->image, 'title');
|
691 |
+
}
|
692 |
+
|
693 |
+
for ( $i = 0; $i < count($this->items); $i++) {
|
694 |
+
$item = $this->items[$i];
|
695 |
+
|
696 |
+
// Atom 1.0 elements <=> Atom 0.3 elements
|
697 |
+
if ($this->feed_version < 1.0) {
|
698 |
+
$this->normalize_element($item, 'modified', $item, 'updated');
|
699 |
+
$this->normalize_element($item, 'issued', $item, 'published');
|
700 |
+
} else {
|
701 |
+
$this->normalize_element($item, 'updated', $item, 'modified');
|
702 |
+
$this->normalize_element($item, 'published', $item, 'issued');
|
703 |
+
}
|
704 |
+
|
705 |
+
// "If an atom:entry element does not contain
|
706 |
+
// atom:author elements, then the atom:author elements
|
707 |
+
// of the contained atom:source element are considered
|
708 |
+
// to apply. In an Atom Feed Document, the atom:author
|
709 |
+
// elements of the containing atom:feed element are
|
710 |
+
// considered to apply to the entry if there are no
|
711 |
+
// atom:author elements in the locations described
|
712 |
+
// above." <http://atompub.org/2005/08/17/draft-ietf-atompub-format-11.html#rfc.section.4.2.1>
|
713 |
+
if (!isset($item["author#"])) {
|
714 |
+
if (isset($item["source_author#"])) { // from aggregation source
|
715 |
+
$source = $item;
|
716 |
+
$author = "source_author";
|
717 |
+
} elseif (isset($this->channel["author#"])) { // from containing feed
|
718 |
+
$source = $this->channel;
|
719 |
+
$author = "author";
|
720 |
+
}
|
721 |
+
|
722 |
+
$item["author#"] = $source["{$author}#"];
|
723 |
+
for ($au = 1; $au <= $item["author#"]; $au++) {
|
724 |
+
$id_to = $this->element_id('author', $au);
|
725 |
+
$id_from = $this->element_id($author, $au);
|
726 |
+
|
727 |
+
$item[$id_to] = $source[$id_from];
|
728 |
+
foreach (array('name', 'email', 'uri', 'url') as $what) {
|
729 |
+
if (isset($source["{$id_from}_{$what}"])) {
|
730 |
+
$item["{$id_to}_{$what}"] = $source["{$id_from}_{$what}"];
|
731 |
+
}
|
732 |
+
}
|
733 |
+
}
|
734 |
+
}
|
735 |
+
|
736 |
+
// Atom elements to RSS elements
|
737 |
+
$this->normalize_element($item, 'author', $item['dc'], 'creator', 'normalize_atom_person');
|
738 |
+
$this->normalize_element($item, 'contributor', $item['dc'], 'contributor', 'normalize_atom_person');
|
739 |
+
$this->normalize_element($item, 'summary', $item, 'description');
|
740 |
+
$this->normalize_element($item, 'atom_content', $item['content'], 'encoded');
|
741 |
+
$this->normalize_element($item, 'link_enclosure', $item, 'enclosure', 'normalize_enclosure');
|
742 |
+
|
743 |
+
// Categories
|
744 |
+
if ( isset($item['category#']) ) { // Atom 1.0 categories to dc:subject and RSS 2.0 categories
|
745 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
746 |
+
}
|
747 |
+
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
748 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
749 |
+
}
|
750 |
+
|
751 |
+
// Normalized item timestamp
|
752 |
+
$atom_date = (isset($item['published']) ) ? $item['published'] : $item['updated'];
|
753 |
+
if ( $atom_date ) {
|
754 |
+
$epoch = @parse_w3cdtf($atom_date);
|
755 |
+
if ($epoch and $epoch > 0) {
|
756 |
+
$item['date_timestamp'] = $epoch;
|
757 |
+
}
|
758 |
+
}
|
759 |
+
|
760 |
+
$this->items[$i] = $item;
|
761 |
+
}
|
762 |
}
|
763 |
elseif ( $this->is_rss() ) {
|
764 |
+
// RSS elements to Atom elements
|
765 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'tagline'); // Atom 0.3
|
766 |
+
$this->normalize_element($this->channel, 'description', $this->channel, 'subtitle'); // Atom 1.0 (yay wordsmithing!)
|
767 |
+
$this->normalize_element($this->image, 'url', $this->channel, 'logo');
|
768 |
+
|
769 |
for ( $i = 0; $i < count($this->items); $i++) {
|
770 |
$item = $this->items[$i];
|
771 |
+
|
772 |
+
// RSS elements to Atom elements
|
773 |
+
$this->normalize_element($item, 'description', $item, 'summary');
|
774 |
+
$this->normalize_element($item['content'], 'encoded', $item, 'atom_content');
|
775 |
+
$this->normalize_element($item, 'enclosure', $item, 'link_enclosure', 'normalize_enclosure');
|
776 |
+
|
777 |
+
// Categories
|
778 |
+
if ( isset($item['category#']) ) { // RSS 2.0 categories to dc:subject and Atom 1.0 categories
|
779 |
+
$this->normalize_element($item, 'category', $item['dc'], 'subject', 'normalize_category');
|
780 |
+
}
|
781 |
+
elseif ( isset($item['dc']['subject#']) ) { // dc:subject to Atom 1.0 and RSS 2.0 categories
|
782 |
+
$this->normalize_element($item['dc'], 'subject', $item, 'category', 'normalize_dc_subject');
|
783 |
+
}
|
784 |
+
|
785 |
+
// Normalized item timestamp
|
786 |
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
|
787 |
$epoch = @parse_w3cdtf($item['dc']['date']);
|
788 |
if ($epoch and $epoch > 0) {
|
795 |
$item['date_timestamp'] = $epoch;
|
796 |
}
|
797 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
798 |
|
799 |
$this->items[$i] = $item;
|
800 |
}
|
934 |
|
935 |
function error ($errormsg, $lvl=E_USER_WARNING) {
|
936 |
// append PHP's error message if track_errors enabled
|
937 |
+
if ( isset($php_errormsg) ) {
|
938 |
$errormsg .= " ($php_errormsg)";
|
939 |
}
|
940 |
if ( MAGPIE_DEBUG ) {
|
951 |
$this->ERROR = $errormsg;
|
952 |
}
|
953 |
}
|
954 |
+
|
955 |
+
// magic ID function for multiple elemenets.
|
956 |
+
// can be called as static MagpieRSS::element_id()
|
957 |
+
function element_id ($el, $counter) {
|
958 |
+
return $el . (($counter > 1) ? '#'.$counter : '');
|
959 |
+
}
|
960 |
} // end class RSS
|
961 |
|
962 |
function map_attrs($k, $v) {
|
963 |
return "$k=\"$v\"";
|
964 |
}
|
965 |
+
|
966 |
+
// patch to support medieval versions of PHP4.1.x,
|
967 |
+
// courtesy, Ryan Currie, ryan@digibliss.com
|
968 |
+
|
969 |
+
if (!function_exists('array_change_key_case')) {
|
970 |
+
define("CASE_UPPER",1);
|
971 |
+
define("CASE_LOWER",0);
|
972 |
+
|
973 |
+
|
974 |
+
function array_change_key_case($array,$case=CASE_LOWER) {
|
975 |
+
if ($case==CASE_LOWER) $cmd='strtolower';
|
976 |
+
elseif ($case==CASE_UPPER) $cmd='strtoupper';
|
977 |
+
foreach($array as $key=>$value) {
|
978 |
+
$output[$cmd($key)]=$value;
|
979 |
+
}
|
980 |
+
return $output;
|
981 |
+
}
|
982 |
+
|
983 |
+
}
|
984 |
+
|
985 |
+
################################################################################
|
986 |
+
## WordPress: Load in Snoopy from wp-includes ##################################
|
987 |
+
################################################################################
|
988 |
|
989 |
require_once( dirname(__FILE__) . '/class-snoopy.php');
|
990 |
|
991 |
+
################################################################################
|
992 |
+
## rss_fetch.inc: from MagpieRSS 0.8a ##########################################
|
993 |
+
################################################################################
|
994 |
+
|
995 |
+
/*=======================================================================*\
|
996 |
+
Function: fetch_rss:
|
997 |
+
Purpose: return RSS object for the give url
|
998 |
+
maintain the cache
|
999 |
+
Input: url of RSS file
|
1000 |
+
Output: parsed RSS object (see rss_parse.inc)
|
1001 |
+
|
1002 |
+
NOTES ON CACHEING:
|
1003 |
+
If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache.
|
1004 |
+
|
1005 |
+
NOTES ON RETRIEVING REMOTE FILES:
|
1006 |
+
If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will
|
1007 |
+
return a cached object, and touch the cache object upon recieving a
|
1008 |
+
304.
|
1009 |
+
|
1010 |
+
NOTES ON FAILED REQUESTS:
|
1011 |
+
If there is an HTTP error while fetching an RSS object, the cached
|
1012 |
+
version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off)
|
1013 |
+
\*=======================================================================*/
|
1014 |
+
|
1015 |
+
define('MAGPIE_VERSION', '0.7');
|
1016 |
+
|
1017 |
+
$MAGPIE_ERROR = "";
|
1018 |
+
|
1019 |
function fetch_rss ($url) {
|
1020 |
// initialize constants
|
1021 |
init();
|
1070 |
if ( $cache_status == 'HIT' ) {
|
1071 |
$rss = $cache->get( $cache_key );
|
1072 |
if ( isset($rss) and $rss ) {
|
1073 |
+
// should be cache age
|
1074 |
$rss->from_cache = 1;
|
1075 |
if ( MAGPIE_DEBUG > 1) {
|
1076 |
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
|
1187 |
|
1188 |
return $MAGPIE_ERROR;
|
1189 |
}
|
|
|
1190 |
|
|
|
|
|
1191 |
/*=======================================================================*\
|
1192 |
Function: _fetch_remote_file
|
1193 |
Purpose: retrieve an arbitrary remote file
|
1286 |
}
|
1287 |
|
1288 |
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
|
1289 |
+
define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1');
|
|
|
|
|
|
|
|
|
1290 |
}
|
1291 |
|
1292 |
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
|
1302 |
}
|
1303 |
|
1304 |
if ( !defined('MAGPIE_USER_AGENT') ) {
|
1305 |
+
$ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net';
|
1306 |
+
|
|
|
|
|
|
|
1307 |
if ( MAGPIE_CACHE_ON ) {
|
1308 |
$ua = $ua . ')';
|
1309 |
}
|
1323 |
define('MAGPIE_USE_GZIP', true);
|
1324 |
}
|
1325 |
}
|
|
|
1326 |
|
1327 |
+
// NOTE: the following code should really be in Snoopy, or at least
|
1328 |
+
// somewhere other then rss_fetch!
|
1329 |
+
|
1330 |
+
/*=======================================================================*\
|
1331 |
+
HTTP STATUS CODE PREDICATES
|
1332 |
+
These functions attempt to classify an HTTP status code
|
1333 |
+
based on RFC 2616 and RFC 2518.
|
1334 |
+
|
1335 |
+
All of them take an HTTP status code as input, and return true or false
|
1336 |
+
|
1337 |
+
All this code is adapted from LWP's HTTP::Status.
|
1338 |
+
\*=======================================================================*/
|
1339 |
+
|
1340 |
+
|
1341 |
+
/*=======================================================================*\
|
1342 |
+
Function: is_info
|
1343 |
+
Purpose: return true if Informational status code
|
1344 |
+
\*=======================================================================*/
|
1345 |
function is_info ($sc) {
|
1346 |
+
return $sc >= 100 && $sc < 200;
|
1347 |
}
|
1348 |
|
1349 |
+
/*=======================================================================*\
|
1350 |
+
Function: is_success
|
1351 |
+
Purpose: return true if Successful status code
|
1352 |
+
\*=======================================================================*/
|
1353 |
function is_success ($sc) {
|
1354 |
+
return $sc >= 200 && $sc < 300;
|
1355 |
}
|
1356 |
|
1357 |
+
/*=======================================================================*\
|
1358 |
+
Function: is_redirect
|
1359 |
+
Purpose: return true if Redirection status code
|
1360 |
+
\*=======================================================================*/
|
1361 |
function is_redirect ($sc) {
|
1362 |
+
return $sc >= 300 && $sc < 400;
|
1363 |
}
|
1364 |
|
1365 |
+
/*=======================================================================*\
|
1366 |
+
Function: is_error
|
1367 |
+
Purpose: return true if Error status code
|
1368 |
+
\*=======================================================================*/
|
1369 |
function is_error ($sc) {
|
1370 |
+
return $sc >= 400 && $sc < 600;
|
1371 |
}
|
1372 |
|
1373 |
+
/*=======================================================================*\
|
1374 |
+
Function: is_client_error
|
1375 |
+
Purpose: return true if Error status code, and its a client error
|
1376 |
+
\*=======================================================================*/
|
1377 |
function is_client_error ($sc) {
|
1378 |
+
return $sc >= 400 && $sc < 500;
|
1379 |
}
|
1380 |
|
1381 |
+
/*=======================================================================*\
|
1382 |
+
Function: is_client_error
|
1383 |
+
Purpose: return true if Error status code, and its a server error
|
1384 |
+
\*=======================================================================*/
|
1385 |
function is_server_error ($sc) {
|
1386 |
+
return $sc >= 500 && $sc < 600;
|
1387 |
}
|
1388 |
|
1389 |
+
################################################################################
|
1390 |
+
## rss_cache.inc: from WordPress 1.5 ###########################################
|
1391 |
+
################################################################################
|
1392 |
+
|
1393 |
class RSSCache {
|
1394 |
var $BASE_CACHE = 'wp-content/cache'; // where the cache files are stored
|
1395 |
var $MAX_AGE = 43200; // when are files stale, default twelve hours
|
1527 |
}
|
1528 |
}
|
1529 |
}
|
1530 |
+
|
1531 |
+
################################################################################
|
1532 |
+
## rss_utils.inc: from MagpieRSS 0.8a ##########################################
|
1533 |
+
################################################################################
|
1534 |
+
|
1535 |
+
/*======================================================================*\
|
1536 |
+
Function: parse_w3cdtf
|
1537 |
+
Purpose: parse a W3CDTF date into unix epoch
|
1538 |
+
|
1539 |
+
NOTE: http://www.w3.org/TR/NOTE-datetime
|
1540 |
+
\*======================================================================*/
|
1541 |
|
1542 |
function parse_w3cdtf ( $date_str ) {
|
1543 |
+
|
1544 |
+
# regex to match wc3dtf
|
1545 |
+
$pat = "/^\s*(\d{4})(-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(\.\d+)?)?(?:([-+])(\d{2}):?(\d{2})|(Z))?)?)?)?\s*\$/";
|
1546 |
+
|
1547 |
+
if ( preg_match( $pat, $date_str, $match ) ) {
|
1548 |
+
list( $year, $month, $day, $hours, $minutes, $seconds) =
|
1549 |
+
array( $match[1], $match[3], $match[5], $match[7], $match[8], $match[9]);
|
1550 |
+
|
1551 |
+
# W3C dates can omit the time, the day of the month, or even the month.
|
1552 |
+
# Fill in any blanks using information from the present moment. --CWJ
|
1553 |
+
$default['hr'] = (int) gmdate('H');
|
1554 |
+
$default['day'] = (int) gmdate('d');
|
1555 |
+
$default['month'] = (int) gmdate('m');
|
1556 |
+
|
1557 |
+
if (is_null($hours)) : $hours = $default['hr']; $minutes = 0; $seconds = 0; endif;
|
1558 |
+
if (is_null($day)) : $day = $default['day']; endif;
|
1559 |
+
if (is_null($month)) : $month = $default['month']; endif;
|
1560 |
+
|
1561 |
+
# calc epoch for current date assuming GMT
|
1562 |
+
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
|
1563 |
+
|
1564 |
+
$offset = 0;
|
1565 |
+
if ( $match[14] == 'Z' ) {
|
1566 |
+
# zulu time, aka GMT
|
1567 |
+
}
|
1568 |
+
else {
|
1569 |
+
list( $tz_mod, $tz_hour, $tz_min ) =
|
1570 |
+
array( $match[12], $match[13], $match[14]);
|
1571 |
+
|
1572 |
+
# zero out the variables
|
1573 |
+
if ( ! $tz_hour ) { $tz_hour = 0; }
|
1574 |
+
if ( ! $tz_min ) { $tz_min = 0; }
|
1575 |
+
|
1576 |
+
$offset_secs = (($tz_hour*60)+$tz_min)*60;
|
1577 |
+
|
1578 |
+
# is timezone ahead of GMT? then subtract offset
|
1579 |
+
#
|
1580 |
+
if ( $tz_mod == '+' ) {
|
1581 |
+
$offset_secs = $offset_secs * -1;
|
1582 |
+
}
|
1583 |
+
|
1584 |
+
$offset = $offset_secs;
|
1585 |
+
}
|
1586 |
+
$epoch = $epoch + $offset;
|
1587 |
+
return $epoch;
|
1588 |
+
}
|
1589 |
+
else {
|
1590 |
+
return -1;
|
1591 |
+
}
|
1592 |
}
|
1593 |
|
1594 |
+
################################################################################
|
1595 |
+
## WordPress: wp_rss(), get_rss() ##############################################
|
1596 |
+
################################################################################
|
1597 |
+
|
1598 |
function wp_rss ($url, $num) {
|
1599 |
//ini_set("display_errors", false); uncomment to suppress php errors thrown if the feed is not returned.
|
1600 |
$num_items = $num;
|
1632 |
return false;
|
1633 |
}
|
1634 |
}
|
|
|
1635 |
?>
|
README.text
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
FeedWordPress
|
2 |
=============
|
3 |
|
4 |
-
* Author: [Charles Johnson](http://
|
5 |
-
* Version: 0.
|
6 |
* Project URI: <http://projects.radgeek.com/feedwordpress>
|
7 |
-
* License: GPL. See License below for copyright jots and tittles.
|
8 |
|
9 |
Introduction
|
10 |
------------
|
11 |
-
FeedWordPress is an Atom/RSS aggregator for WordPress. It syndicates content
|
12 |
-
from newsfeeds that you
|
13 |
-
several newsfeeds then you can WordPress's posts database and templating
|
14 |
engine as the back-end of an aggregation ("planet") website. I originally
|
15 |
developed it because I needed a more flexible replacement for [Planet][] to
|
16 |
use at [Feminist Blogs][].
|
@@ -29,22 +29,68 @@ hosts*.)
|
|
29 |
|
30 |
[WordPress 1.5]: http://wordpress.org/development/2005/02/strayhorn/
|
31 |
|
32 |
-
Installation
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
1. Install `feedwordpress.php` in your WordPress `plugins` directory
|
40 |
-
and `update.php` in your WordPress `wp-content` directory.
|
41 |
|
42 |
2. (Optional) Upgrade the copy of MagpieRSS packaged with WordPress by
|
43 |
installing the new `rss-functions.php` (archived in
|
44 |
`OPTIONAL/wp-includes`) into your WordPress `wp-includes` directory.
|
45 |
Upgrading MagpieRSS is necessary if you want to take advantage of
|
46 |
-
support for multiple post categories, RSS enclosures, and
|
47 |
-
character encodings. (Note, however, that support for
|
48 |
transliterating between character encodings is a very complex and
|
49 |
iffy prospect in some PHP environments, so if you intend to use
|
50 |
a lot of feeds with alternate encodings you should make sure that
|
@@ -52,170 +98,190 @@ own that has always-on Internet access.
|
|
52 |
the old MagpieRSS around to compare results.)
|
53 |
|
54 |
3. Log in to the WordPress Dashboard and activate the FeedWordPress
|
55 |
-
plugin.
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
-
|
80 |
-
|
|
|
|
|
|
|
81 |
|
82 |
Basic Concepts
|
83 |
--------------
|
84 |
-
FeedWordPress is written as a plugin for [WordPress 1.5][]. It is designed
|
85 |
-
|
86 |
-
|
87 |
|
88 |
### Contributors / Newsfeeds ###
|
89 |
|
90 |
-
FeedWordPress uses the WordPress Links database to keep a list of the feeds
|
91 |
-
|
92 |
-
categories; FeedWordPress will
|
93 |
-
(by default, this is a category named "Contributors"; you can change
|
94 |
-
category that FeedWordPress will use using Options --> Syndication).
|
95 |
|
96 |
From WordPress's perspective, the list of Contributors are normal links, and
|
97 |
-
they can be manipulated like other links through the WordPress Dashboard.
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
- The Short Description is used to store the tagline of the syndicated
|
137 |
-
website. By default, FeedWordPress automatically updates the
|
138 |
-
description whenever it checks for new posts, using the tagline or
|
139 |
-
description that the newsfeed reports (so that if a Contributor
|
140 |
-
changes the tagline of her website, this is reflected automatically
|
141 |
-
on your Contributors links list). his behavior can be turned off for
|
142 |
-
all feeds through the settings in Options --> Syndication. The
|
143 |
-
default behavior can be overridden for specific feeds using the feed
|
144 |
-
setting `hardcode description`.
|
145 |
-
|
146 |
-
- The Link Notes are used to store a collection of manually-encoded
|
147 |
-
and automatically-generated settings that apply to this feed. The
|
148 |
-
format of settings in Link Notes is:
|
149 |
-
|
150 |
-
key1: value1
|
151 |
-
key2: value2
|
152 |
-
feed/key1: value1
|
153 |
-
feed/key2: value2
|
154 |
-
|
155 |
-
And so on. Values that are prefixed by 'feed/' are automatically
|
156 |
-
generated from feed data every time the feed syndicated by this link
|
157 |
-
is checked for updates. Values without the prefix are set manually
|
158 |
-
by the user.
|
159 |
-
|
160 |
-
The Link Notes section can be used to add, remove, and change custom feed
|
161 |
-
settings. For example, if you want to *add* the feed setting for `unfamiliar
|
162 |
-
author` with the value `filter`, you can do so by going to Links -->
|
163 |
-
Syndicated, clicking the "Edit" link for the feed that you wish to add this
|
164 |
-
setting for, and then adding the following, on a line by itself, to the Link
|
165 |
-
Notes section:
|
166 |
-
|
167 |
-
unfamiliar author: filter
|
168 |
-
|
169 |
-
To remove the setting, follow the same procedure, but find the line for the
|
170 |
-
feed setting that you want to remove and remove it. To change the value,
|
171 |
-
simply change the text that follows after the colon.
|
172 |
-
|
173 |
-
Most settings in the Link Notes have no effect on FeedWordPress, but you can
|
174 |
-
use them to store information for templates to retrieve using the
|
175 |
-
`get_feed_meta()` template function in a post context (see Template API
|
176 |
-
below). For example, many aggregator sites use a "face" image for each feed
|
177 |
-
to visually distinguish posts from different feeds. To implement a face
|
178 |
-
feature, you could add something like this to each feed's Link Notes, on a
|
179 |
-
line by itself:
|
180 |
-
|
181 |
-
face: http://www.zyx.com/mugs/ugly
|
182 |
-
|
183 |
-
The URI should be changed out for each feed to point to the appropriate
|
184 |
-
image, of course. Then, to use the setting from within a template:
|
185 |
|
186 |
// In a post context
|
187 |
<?php $img = get_feed_meta('face'); if (strlen($img) > 0): ?>
|
188 |
<img src="<?=$img?>" alt="" />
|
189 |
<?php endif; ?>
|
190 |
|
191 |
-
... which will display the image, if any, whose URI is set in the "face"
|
192 |
-
|
193 |
-
|
194 |
-
image will be displayed.
|
195 |
|
196 |
-
|
197 |
-
processes posts from that feed. Currently, the settings with special effects
|
198 |
-
on FeedWordPress are `cats`, `hardcode name`, `hardcode description`,
|
199 |
-
`hardcode categories`, `post status`, `comment status`, `ping status`,
|
200 |
-
`unfamiliar author`, and `unfamiliar categories`. For descriptions of their
|
201 |
-
effects, see Special Feed Settings below.
|
202 |
|
203 |
### Syndicated Posts ###
|
204 |
|
205 |
Whenever FeedWordPress updates, it scans one or more of the feeds in its
|
206 |
Contributors list and adds any new posts that it finds to the WordPress
|
207 |
-
database. Syndicated posts are displayed on your WordPress pages like any
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
`the_syndication_source_link()
|
216 |
-
|
217 |
-
|
218 |
-
[Feminist Blogs][]:
|
219 |
|
220 |
<cite class="feed">from <?php the_author_posts_link()?><?php
|
221 |
if (is_syndicated() and (get_the_author() !== get_syndication_source())):
|
@@ -224,472 +290,220 @@ author's name and the original source of the post in the templates for
|
|
224 |
echo '</a>';
|
225 |
endif; ?></cite>
|
226 |
|
227 |
-
For more information on template functions, see Template API
|
228 |
|
229 |
### Categories ###
|
230 |
|
231 |
-
WordPress allows for posts to be placed in *categories*. Each syndicated
|
232 |
-
|
233 |
-
|
234 |
sources:
|
235 |
|
236 |
-
1. Categories (or "tags") that the original author placed the post in
|
237 |
-
|
238 |
|
239 |
-
2. Categories that you set explicitly for each feed using the
|
240 |
-
|
241 |
-
|
242 |
-
"
|
243 |
-
|
244 |
-
|
245 |
-
the
|
246 |
-
|
247 |
-
cats: Pacific Northwest:Cartoonists
|
248 |
-
|
249 |
-
(The colon separates one category name from the next.)
|
250 |
|
251 |
Given the list of category names, FeedWordPress looks for categories in the
|
252 |
WordPress database with the same name as either (1) the category name, or
|
253 |
(2) one of the "aliases" listed in the category description.
|
254 |
|
255 |
-
__Aliases:__ Different often authors use slightly different names for
|
256 |
-
|
257 |
-
|
258 |
-
Issues", "Gender
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
|
266 |
a.k.a.: feministy stuff
|
267 |
|
268 |
-
You can add as many aliases as you like. You can also add any other text
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
__Unfamiliar categories:__
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
to your blog to syndicate only the posts in one
|
286 |
-
feed that has several categories, you could do so by
|
287 |
-
that name, adding the new feed(s), and then
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
Since only posts in categories that are in your database will be included,
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
the `['categories']` array of a syndicated item.
|
304 |
|
305 |
### Authors ###
|
306 |
|
307 |
Most newsfeeds include information about the author of the items on them.
|
308 |
(If a feed doesn't, then FeedWordPress will create an author's name based on
|
309 |
-
the title of the feed from which the item was taken.) This information is
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
|
316 |
__Aliases:__ If there is an author who posts under more than one name (for
|
317 |
example, one of our contributors at [Feminist Blogs][] posts on several
|
318 |
different blogs, sometimes using her full name and sometimes using only her
|
319 |
-
first name), then you can ensure that FeedWordPress will attribute those
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
|
326 |
-
|
327 |
|
328 |
-
You can add as many aliases as you like. You can also add any other text
|
329 |
-
|
330 |
-
|
331 |
|
332 |
__Unfamiliar authors:__ By default, if the author named by the newsfeed is
|
333 |
unfamiliar -- that is, if there is no-one with that name registered in the
|
334 |
-
WordPress author's database -- then by default FeedWordPress will
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
(Similarly, you could set up FeedWordPress so that *all* the feeds are
|
355 |
-
filtered by author by creating the set of users named after the authors you
|
356 |
-
want to syndicate, and then setting the default behavior for *all* feeds at
|
357 |
-
Options --> Syndication).
|
358 |
-
|
359 |
-
If you need an author filter with more complex logic than this allows, you
|
360 |
-
can always create a `syndicated_item` filter in PHP (see Plugin API below)
|
361 |
-
that manipulates the `['author_name']` or `['dc']['creator']` elements of a
|
362 |
-
syndicated item.
|
363 |
-
|
364 |
-
Special Feed Settings
|
365 |
-
---------------------
|
366 |
-
Most feed settings (see Feed Settings above) have no effect on FeedWordPress
|
367 |
-
itself, but can be useful because they can be accessed from templates using
|
368 |
-
the `get_feed_meta()` template function in a post context (see Feed Settings
|
369 |
-
above for an example). However, you can use some feed settings to affect how
|
370 |
-
FeedWordPress will process posts from that particular feed. Currently, these
|
371 |
-
special settings are:
|
372 |
-
|
373 |
-
- `cats:` a colon-separated list of default categories for any post
|
374 |
-
coming from this feed. So, for example, a this line in its Notes
|
375 |
-
section:
|
376 |
-
|
377 |
-
cats: computers:web
|
378 |
-
|
379 |
-
... will make FeedWordPress place any posts syndicated from that
|
380 |
-
feed in the "computers" and "web" categories. Note that by default,
|
381 |
-
FeedWordPress will place them in those categories *in addition to*
|
382 |
-
any categories that the author of the post put them in on her own
|
383 |
-
website. If you want to place posts from a feed *only* in the
|
384 |
-
categories you explicitly set, then you should use the `cats`
|
385 |
-
setting together with the `unfamiliar categories` setting. (See
|
386 |
-
Categories above and `unfamiliar categories` below for the
|
387 |
-
nitty-gritty.)
|
388 |
-
|
389 |
-
- `hardcode name: (yes|no)`
|
390 |
-
|
391 |
-
By default, FeedWordPress updates the value of the Link Name field
|
392 |
-
automatically to reflect the title that is reported by a syndicated
|
393 |
-
feed--so that if one of your contributors changes the title of her
|
394 |
-
website, the change will be reflected on your Contributors list
|
395 |
-
after the next update. If you want to stop this behavior (so that
|
396 |
-
you can set the title of a Contributor link manually -- e.g. so that
|
397 |
-
you can use an abbreviated form for reasons of space), you can
|
398 |
-
change the default behavior for *all* feeds using the settings in
|
399 |
-
Options --> Syndication. If you want to override the default
|
400 |
-
behavior for only *one* feed, you can use the `hardcode name` feed
|
401 |
-
setting. If FeedWordPress updates the title of all feeds by default,
|
402 |
-
but you wish to use a manually-set title for one particular feed,
|
403 |
-
you can add a line like this to the Link Notes section of the feed
|
404 |
-
that you want to manually set the title for:
|
405 |
-
|
406 |
-
hardcode name: yes
|
407 |
-
|
408 |
-
Similarly, if FeedWordPress uses your manually-entered titles for
|
409 |
-
all feeds by default, but you wish to use an automatically updated
|
410 |
-
title for one particular feed, you can add a line like this to the
|
411 |
-
Link Notes section of the feed that you want to manually set the
|
412 |
-
title for:
|
413 |
-
|
414 |
-
hardcode name: no
|
415 |
-
|
416 |
-
If `hardcode name` is absent, or set to a value other than `yes` or
|
417 |
-
`no`, FeedWordPress will follow the default behavior set under
|
418 |
-
Options --> Syndication.
|
419 |
-
|
420 |
-
- `hardcode description: (yes|no)`
|
421 |
-
|
422 |
-
By default, FeedWordPress updates the value of the Link Description
|
423 |
-
field automatically to reflect the tagline or description that is
|
424 |
-
reported by a syndicated feed--so that if one of your contributors
|
425 |
-
changes the tagline for her website, the change will be reflected on
|
426 |
-
your Contributors list after the next update. If you want to stop
|
427 |
-
this behavior (so that you can set the tagline of a Contributor link
|
428 |
-
manually -- e.g. so that you can use it to provide information of
|
429 |
-
another sort or use an abbreviated form for reasons of space), you
|
430 |
-
can change the default behavior for *all* feeds using the settings
|
431 |
-
in Options --> Syndication. If you want to override the default
|
432 |
-
behavior for only *one* feed, you can use the `hardcode description`
|
433 |
-
feed setting. If FeedWordPress updates the description of all feeds
|
434 |
-
by default, but you wish to use a manually-set description for one
|
435 |
-
particular feed, you can add a line like this to the Link Notes
|
436 |
-
section of that particular feed:
|
437 |
-
|
438 |
-
hardcode description: yes
|
439 |
-
|
440 |
-
Similarly, if FeedWordPress uses your manually-entered descriptions
|
441 |
-
for all feeds by default, but you wish to use an automatically
|
442 |
-
updated description for one particular feed, you can add a line like
|
443 |
-
this to the Link Notes section of that particular feed:
|
444 |
-
|
445 |
-
hardcode description: no
|
446 |
-
|
447 |
-
If `hardcode description` is absent, or set to a value other than
|
448 |
-
`yes` or `no`, FeedWordPress will follow the default behavior set
|
449 |
-
under Options --> Syndication.
|
450 |
-
|
451 |
-
- `hardcode url: (yes|no)`
|
452 |
-
|
453 |
-
By default, FeedWordPress updates the value of the Link URI field
|
454 |
-
automatically to reflect the link to the front page of the website
|
455 |
-
you are syndicating, as reported by the syndicated feed--so that if
|
456 |
-
one of your contributors changes the front page of her website (from
|
457 |
-
<http://www.zyx.com/blog/> to <http://www.zyx.com/>, say), the
|
458 |
-
change will be reflected on your Contributors list after the next
|
459 |
-
update. If you want to stop this behavior (so that you can set the
|
460 |
-
human-readable URI that a Contributor link points to manually), you
|
461 |
-
can change the default behavior for *all* feeds using the settings
|
462 |
-
in Options --> Syndication. If you want to override the default
|
463 |
-
behavior for only *one* feed, you can use the `hardcode url` feed
|
464 |
-
setting. If FeedWordPress updates the human-readable URI of all
|
465 |
-
feeds by default, but you wish to use a manually-set URI for one
|
466 |
-
particular feed, you can add a line like this to the Link Notes
|
467 |
-
section of that particular feed:
|
468 |
-
|
469 |
-
hardcode url: yes
|
470 |
-
|
471 |
-
Similarly, if FeedWordPress uses your manually-entered URIs for all
|
472 |
-
feeds by default, but you wish to use an automatically updated URI
|
473 |
-
for one particular feed, you can add a line like this to the Link
|
474 |
-
Notes section of that particular feed:
|
475 |
-
|
476 |
-
hardcode url: no
|
477 |
-
|
478 |
-
If `hardcode url` is absent, or set to a value other than `yes` or
|
479 |
-
`no`, FeedWordPress will follow the default behavior set under
|
480 |
-
Options --> Syndication.
|
481 |
-
|
482 |
-
- `hardcode categories: (yes|no)`
|
483 |
-
|
484 |
-
**This setting has been deprecated.** If set to `yes` it is now
|
485 |
-
treated as equivalent to `unfamiliar categories: default`. (See
|
486 |
-
below.)
|
487 |
-
|
488 |
-
- `post status: (publish|draft|private)`
|
489 |
-
|
490 |
-
By default, FeedWordPress sets all new syndicated posts to be
|
491 |
-
published immediately. If you want syndicated posts to have some
|
492 |
-
other status (for example, to hold them as drafts for moderation, or
|
493 |
-
to hold them as private posts), you can change the default behavior
|
494 |
-
using Options --> Syndication. If you want to override the default
|
495 |
-
post status for syndicated posts from *one particular feed*, you
|
496 |
-
can do so using the `post status` feed setting. So, for example, if
|
497 |
-
you have FeedWordPress set to publish new syndicated posts
|
498 |
-
immediately, but you want posts from one particular feed to be put
|
499 |
-
into the drafts pile for moderation, you can do so by placing the
|
500 |
-
following line in the Link Notes section of that feed's Contributor
|
501 |
-
link:
|
502 |
-
|
503 |
-
post status: draft
|
504 |
-
|
505 |
-
- `comment status: (open|closed)`
|
506 |
-
|
507 |
-
By default, FeedWordPress sets all new syndicated posts to be
|
508 |
-
closed for comments--if users want to comment on posts then it's
|
509 |
-
often best for them to comment on the *original* website rather than
|
510 |
-
your syndication site. But if you want syndicated posts to be open
|
511 |
-
for comments, you can change the default behavior for all syndicated
|
512 |
-
posts using the settings in Options --> Syndication. If you want to
|
513 |
-
override the default comment status for *one particular feed*, you
|
514 |
-
can do so using the `comment status` feed setting. So, for example,
|
515 |
-
if you have FeedWordPress set not to open up new syndicated posts
|
516 |
-
for comments, but you want posts from *one particular feed* to be
|
517 |
-
opened for comments, then you can do so by placing the following
|
518 |
-
line in the Link Notes section of that feed's Contributor link:
|
519 |
-
|
520 |
-
comment status: open
|
521 |
-
|
522 |
-
- `ping status: (open|closed)`
|
523 |
-
|
524 |
-
By default, FeedWordPress sets all new syndicated posts *not* to
|
525 |
-
accept PingBack or TrackBack link notifications ("pings"). If you
|
526 |
-
want syndicated posts on your syndication site to accept pings, you
|
527 |
-
can change the default behavior for all syndicated posts using the
|
528 |
-
settings in Options --> Syndication. If you want to override the
|
529 |
-
default ping status for *one particular feed*, you can do so using
|
530 |
-
the `ping status` feed setting. So, for example, if you have
|
531 |
-
FeedWordPress set not to accept pings for new syndicated posts, but
|
532 |
-
you want posts from *one particular feed* to accept pings, then you
|
533 |
-
can do so by placing the following line in the Link Notes section of
|
534 |
-
that feed's Contributor link:
|
535 |
-
|
536 |
-
ping status: open
|
537 |
-
|
538 |
-
- `unfamiliar authors: (create|default|filter)`
|
539 |
-
|
540 |
-
By default, FeedWordPress creates new author accounts whenever it
|
541 |
-
finds a new post that is by an author whose name is not already in
|
542 |
-
the WordPress database, and uses that account for this post and any
|
543 |
-
future posts by an author of that name. FeedWordPress also allows
|
544 |
-
you to attribute posts by unfamiliar authors to a *default* user
|
545 |
-
account (currently, this means the System Administrator account),
|
546 |
-
*instead of* creating a new author, or simply not to syndicate posts
|
547 |
-
by unfamiliar authors (thus only syndicating posts by authors who
|
548 |
-
are already in the database).
|
549 |
-
|
550 |
-
Which of these FeedWordPress does by default can be set using the
|
551 |
-
settings in Options --> Syndication. You can also override the
|
552 |
-
default behavior for specific feeds by adding the `unfamiliar
|
553 |
-
author` feed setting to the Link Notes section of a feed. For
|
554 |
-
example, to ensure that FeedWordPress filters out posts by
|
555 |
-
unfamiliar authors for one particular feed, add the setting:
|
556 |
-
|
557 |
-
unfamiliar author: filter
|
558 |
-
|
559 |
-
To ensure that FeedWordPress assigns posts by unfamiliar authors to
|
560 |
-
the default user account instead of creating a new user account, add
|
561 |
-
the setting:
|
562 |
-
|
563 |
-
unfamiliar author: default
|
564 |
-
|
565 |
-
If you changed the default behavior under Options --> Syndication
|
566 |
-
but want to ensure that FeedWordPress creates new author accounts
|
567 |
-
for unfamiliar authors on one specific feed, add the setting:
|
568 |
-
|
569 |
-
unfamiliar author: create
|
570 |
-
|
571 |
-
If the setting is anything other than `create`, `default`, or
|
572 |
-
`filter`, FeedWordPress will ignore the setting and follow the
|
573 |
-
default behavior that you specified under Options --> Syndication.
|
574 |
-
|
575 |
-
- `unfamiliar categories: (create|default|filter)`
|
576 |
-
|
577 |
-
By default, FeedWordPress creates categories whenever it finds a new
|
578 |
-
post that is placed in categories whose names are not already in the
|
579 |
-
WordPress database. FeedWordPress allows you to change this
|
580 |
-
behavior, so that it will *not* create new category names. It also
|
581 |
-
allows you to choose whether or not posts must match *at least one*
|
582 |
-
familiar category to be syndicated at all.
|
583 |
-
|
584 |
-
Which of these FeedWordPress does by default can be set using the
|
585 |
-
settings in Options --> Syndication. You can also override the
|
586 |
-
default behavior for specific feeds by adding the `unfamiliar
|
587 |
-
categories` feed setting to the Link Notes section of a feed. For
|
588 |
-
example, to ensure that, when adding new posts from *one particular
|
589 |
-
feed*, FeedWordPress does *not* create new categories, and filters
|
590 |
-
out any posts that don't match *at least one* of the categories that
|
591 |
-
you have already defined, add the setting:
|
592 |
-
|
593 |
-
unfamiliar categories: filter
|
594 |
-
|
595 |
-
To ensure that FeedWordPress does *not* create new categories, but
|
596 |
-
*will* still syndicate categories even if they don't match any of
|
597 |
-
the pre-defined categories, add the following to the feed settings:
|
598 |
-
|
599 |
-
unfamiliar categories: default
|
600 |
-
|
601 |
-
If you changed the default behavior under Options --> Syndication
|
602 |
-
but want to ensure that FeedWordPress creates new categories for
|
603 |
-
posts from one particular feed, add the setting:
|
604 |
-
|
605 |
-
unfamiliar categories: create
|
606 |
|
607 |
-
|
608 |
-
|
609 |
-
|
|
|
610 |
|
611 |
Template API
|
612 |
------------
|
613 |
-
When activated, FeedWordPress makes the following functions available for
|
614 |
-
|
615 |
|
616 |
-
* ``is_syndicated()``: in a post context, returns ``TRUE`` if the post
|
617 |
-
|
618 |
-
|
619 |
|
620 |
-
* ``get_syndication_permalink()``: in a post context, returns the URI
|
621 |
-
|
622 |
|
623 |
-
* ``the_syndication_permalink()``: in a post context, outputs the
|
624 |
-
|
625 |
|
626 |
-
* ``get_syndication_source_link()``: in a post context, returns the
|
627 |
-
|
628 |
-
|
629 |
|
630 |
-
* ``the_syndication_source_link()``: in a post context, outputs the
|
631 |
-
|
|
|
632 |
|
633 |
* ``get_syndication_source()``: in a post context, returns the
|
634 |
human-readable title of the website that a syndicated post was
|
635 |
syndicated from
|
636 |
|
637 |
* ``the_syndication_source()``: in a post context, outputs the value
|
638 |
-
returned by ``get_syndication_source()``
|
639 |
|
640 |
-
* ``get_syndication_feed():`` in a post context, returns the URI of
|
641 |
-
|
642 |
|
643 |
* ``the_syndication_feed()``: in a post context, outputs the value
|
644 |
-
returned by ``get_syndication_feed()``
|
645 |
|
646 |
-
* ``get_feed_meta($key)``: in a post context, returns the value, if
|
647 |
-
|
648 |
-
|
649 |
|
650 |
By default, FeedWordPress also places a filter on the standard functions
|
651 |
-
``get_permalink()`` and ``the_permalink()`` that substitutes the URI
|
652 |
-
|
653 |
-
WordPress. This means that by default the permalinks listed on your
|
654 |
-
and in your newsfeed will link to the location of the posts on the
|
655 |
-
website, *not* to their location on your website. You can switch this
|
656 |
-
behavior on or off at Options --> Syndication in the WordPress Dashboard.
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
FeedWordPress creates five hooks through the WordPress plugin architecture
|
661 |
-
|
662 |
-
FeedWordPress behavior, or to filter posts according to criteria that you
|
663 |
-
|
664 |
-
``feedwordpress_check_feed``, the action ``feedwordpress_update_complete``,
|
665 |
-
|
666 |
``post_syndicated_item``, and the action ``update_syndicated_item``.
|
667 |
|
668 |
For more information, see <http://projects.radgeek.com/feedwordpress/api>.
|
669 |
|
670 |
License
|
671 |
-------
|
672 |
-
The FeedWordPress plugin is copyright (c) 2005 by Charles Johnson. It uses
|
673 |
-
|
674 |
|
675 |
-
- [wp-rss-aggregate.php][] by [Kellan Elliot-McCrea](
|
676 |
-
-
|
677 |
-
- [
|
|
|
678 |
|
679 |
according to the terms of the [GNU General Public License][].
|
680 |
|
681 |
-
This program is free software; you can redistribute it and/or modify it
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
|
686 |
-
This program is distributed in the hope that it will be useful, but WITHOUT
|
687 |
-
|
688 |
-
|
689 |
-
more details.
|
690 |
|
691 |
[wp-rss-aggregate.php]: http://laughingmeme.org/archives/002203.html
|
|
|
692 |
[HTTP Navigator 2]: http://www.keyvan.net/2004/11/16/http-navigator/
|
693 |
[Ultra-Liberal Feed Finder]: http://diveintomark.org/projects/feed_finder/
|
|
|
694 |
[GNU General Public License]: http://www.gnu.org/copyleft/gpl.html
|
695 |
|
1 |
FeedWordPress
|
2 |
=============
|
3 |
|
4 |
+
* Author: [Charles Johnson](http://radgeek.com/contact)
|
5 |
+
* Version: 0.97
|
6 |
* Project URI: <http://projects.radgeek.com/feedwordpress>
|
7 |
+
* License: GPL 2. See License below for copyright jots and tittles.
|
8 |
|
9 |
Introduction
|
10 |
------------
|
11 |
+
FeedWordPress is an Atom/RSS aggregator for WordPress 1.5. It syndicates content
|
12 |
+
from newsfeeds that you choose into your WordPress blog; if you syndicate
|
13 |
+
several newsfeeds then you can use WordPress's posts database and templating
|
14 |
engine as the back-end of an aggregation ("planet") website. I originally
|
15 |
developed it because I needed a more flexible replacement for [Planet][] to
|
16 |
use at [Feminist Blogs][].
|
29 |
|
30 |
[WordPress 1.5]: http://wordpress.org/development/2005/02/strayhorn/
|
31 |
|
32 |
+
Installation
|
33 |
+
------------
|
34 |
+
### Requirements ###
|
35 |
+
|
36 |
+
To use version 0.97 of FeedWordPress, you will need:
|
37 |
+
|
38 |
+
1. an installed configured copy of WordPress 1.5.x. (It *won't work* with
|
39 |
+
WP 1.2 or WP 1.6 development builds.)
|
40 |
+
|
41 |
+
2. FTP or SFTP access to your web host
|
42 |
+
|
43 |
+
And you'll probably also want to have either:
|
44 |
+
|
45 |
+
1. the ability to create cron jobs on your web host, or at least
|
46 |
+
|
47 |
+
2. a computer of your own and always-on Internet access
|
48 |
+
|
49 |
+
### Installation ###
|
50 |
+
|
51 |
+
#### Upgrades ####
|
52 |
+
|
53 |
+
To *upgrade* an existing installation of FeedWordPress to version 0.97:
|
54 |
+
|
55 |
+
1. Download the FeedWordPress archive in zip or gzipped tar format and
|
56 |
+
extract the files on your computer. Replace your existing FeedWordPress
|
57 |
+
files with the new files. Be sure to upgrade `rss-functions.php` if you
|
58 |
+
use the optional MagpieRSS upgrade, or don't use it yet but do want to
|
59 |
+
syndicate Atom 1.0 feeds.
|
60 |
+
|
61 |
+
2. **Immediately** log in to the WordPress Dashboard, and go to Options -->
|
62 |
+
Syndicated. Follow the directions to launch the database upgrade
|
63 |
+
procedure. The new version of FeedWordPress incorporates some
|
64 |
+
long-needed improvements, but old meta-data needs to be updated to
|
65 |
+
prevent duplicate posts and other possible maladies. If you're upgrading
|
66 |
+
an existing installation, updates and FeedWordPress template functions
|
67 |
+
*will not work* until you've done the upgrade.
|
68 |
+
|
69 |
+
3. Take a coffee break while the upgrade runs. It should, hopefully, finish
|
70 |
+
within a few minutes even on relatively large databases.
|
71 |
+
|
72 |
+
4. `update-feeds.php` has been overhauled to improve performance and ease
|
73 |
+
of use, and also to make errors easier to detect and eliminate. The
|
74 |
+
overhaul doesn't require any changes to your set up *if* you used
|
75 |
+
XML-RPC pings, or command-line PHP, to do scheduled updates. It *does*
|
76 |
+
affect you if you used curl or some other tool to send HTTP requests to
|
77 |
+
`update-feeds.php`: your old cron job will probably not work anymore.
|
78 |
+
See [Setting Up Feed Updates][] below to get scheduled updates back on
|
79 |
+
track.
|
80 |
+
|
81 |
+
5. Enjoy your new installation of FeedWordPress.
|
82 |
+
|
83 |
+
#### New Installations ####
|
84 |
|
85 |
1. Install `feedwordpress.php` in your WordPress `plugins` directory
|
86 |
+
and `update-feeds.php` in your WordPress `wp-content` directory.
|
87 |
|
88 |
2. (Optional) Upgrade the copy of MagpieRSS packaged with WordPress by
|
89 |
installing the new `rss-functions.php` (archived in
|
90 |
`OPTIONAL/wp-includes`) into your WordPress `wp-includes` directory.
|
91 |
Upgrading MagpieRSS is necessary if you want to take advantage of
|
92 |
+
support for Atom 1.0, multiple post categories, RSS enclosures, and
|
93 |
+
multiple character encodings. (Note, however, that support for
|
94 |
transliterating between character encodings is a very complex and
|
95 |
iffy prospect in some PHP environments, so if you intend to use
|
96 |
a lot of feeds with alternate encodings you should make sure that
|
98 |
the old MagpieRSS around to compare results.)
|
99 |
|
100 |
3. Log in to the WordPress Dashboard and activate the FeedWordPress
|
101 |
+
plugin.
|
102 |
+
|
103 |
+
4. While you're at the Dashboard, once the plugin is activated, you can
|
104 |
+
go to Options --> Syndication and set (1) the link category that
|
105 |
+
FeedWordPress will syndicate links from (by default, "Contributors"),
|
106 |
+
and (2) a "secret word" for your RPC-XML updating interface. This
|
107 |
+
provides some light security by keeping passing ruffians from saying
|
108 |
+
"Update all the feeds" at will to your FeedWordPress installation.
|
109 |
+
|
110 |
+
5. Go to Links --> Syndicated to set up the list of sites that you want
|
111 |
+
FeedWordPress to syndicate onto your blog. (If you have the feeds you
|
112 |
+
want to aggregate in a service such as Bloglines, you may prefer to
|
113 |
+
export them to an OPML file and use WordPress's Links --> Import to
|
114 |
+
import them into the contributors category.)
|
115 |
+
|
116 |
+
#### Setting Up Feed Updates ####
|
117 |
+
|
118 |
+
FeedWordPress is now ready to accept posts from its syndication sources.
|
119 |
+
Unfortunately, it doesn't yet know *when* to go get them. (**This may be true
|
120 |
+
even if you are upgrading an existing installation of FeedWordPress:** your old
|
121 |
+
cron job will still work if you used command-line PHP or blogging software pings
|
122 |
+
to do updates, but it will need to be fixed if you used curl or another tool to
|
123 |
+
send HTTP requests to `update-feeds.php`.)
|
124 |
+
|
125 |
+
You can load in syndicated posts for the first time by pointing your web browser
|
126 |
+
to `update-feeds.php`. If you have WordPress installed at, say,
|
127 |
+
<http://www.zyx.com/blog> then you should point your browser to
|
128 |
+
<http://www.zyx.com/blog/wp-content/update-feeds.php> and log in as any user in
|
129 |
+
the user database. (You may want to create a new "dummy" user for doing
|
130 |
+
scheduled updates, using **Users --> Authors & Users --> Add New User**. Tell
|
131 |
+
FeedWordPress to update all feeds, and you'll get the first wave of posts
|
132 |
+
imported into the database.
|
133 |
+
|
134 |
+
Congratulations! You should now have an aggregator site full of delicious
|
135 |
+
syndicated content hot off of the newswires. Now you just need a way to *keep*
|
136 |
+
the content freshly updated. Unless you enjoy manually browsing to
|
137 |
+
`update-feeds.php` every hour on the hour, you'll probably want to do this by
|
138 |
+
setting up your site for automated updates.
|
139 |
+
|
140 |
+
You can pull that off in one of two ways, or by a mixture of both:
|
141 |
+
|
142 |
+
1. **The Blogging Software Ping Method:** You can get all of your
|
143 |
+
contributors to add you to the list of URIs that they notify of updates:
|
144 |
+
while FeedWordPress is activated, it will accept XML-RPC "recently
|
145 |
+
updated" pings in the standard format accepted by Weblogs.com,
|
146 |
+
Ping-O-Matic, Technorati, and other services. Most blogging software
|
147 |
+
allows users to add a URI to the list of URIs that get pinged on each
|
148 |
+
update. (See, for example, Options --> Writing --> Update Services in
|
149 |
+
WordPress, or Configuration --> Preferences --> Publicity / Remote
|
150 |
+
Interfaces / TrackBack in Movable Type.)
|
151 |
+
|
152 |
+
If you can get a contributor to add your XML-RPC URI to her
|
153 |
+
services-to-ping list (if you have WordPress installed at
|
154 |
+
<http://www.zyx.com/blog>, say, the URI to add should be
|
155 |
+
<http://www.zyx.com/blog/xmlrpc.php>), then whenever she updates her
|
156 |
+
blog, her blogging software will ping your FeedWordPress installation,
|
157 |
+
and FeedWordPress will look up her feed to grab the new posts off of
|
158 |
+
it.
|
159 |
+
|
160 |
+
2. **The Scheduled Update Job Method:** You may very well not be able to
|
161 |
+
get all your contributors to add your site to their blogging software's
|
162 |
+
ping list, and even if you do you may want to have a back-up option to
|
163 |
+
catch updates later even if the ping fails to go through on one
|
164 |
+
particular occasion. You'll need to create a scheduled job to
|
165 |
+
periodically check for updates on *all* the feeds. You'll need either
|
166 |
+
(a) the ability to create cron jobs on your web host or (b) access to
|
167 |
+
another computer with a reliable, always-on Internet connection.
|
168 |
+
|
169 |
+
If you *can* create a crontab on your web host, then the best thing to
|
170 |
+
do is to create a cron job that will run update-feeds.php through the
|
171 |
+
PHP command-line interface. For example, if you have WordPress installed
|
172 |
+
in `~/www/wp` (where ~ is your home directory), you might insert the
|
173 |
+
following line into your crontab:
|
174 |
|
175 |
+
25 * * * * cd $HOME/www/wp/wp-content ; php -q update-feeds.php
|
176 |
+
|
177 |
+
If you *don't* have access to (a), you can still save the day using
|
178 |
+
another computer with always-on Internet access that sends a POST
|
179 |
+
request to the `update-feeds.php` URI on a regular schedule. So, for
|
180 |
+
example, if you have WordPress installed at <http://www.zyx.com/blog>,
|
181 |
+
and you have a dummy user in your WordPress database with the login name
|
182 |
+
'login' and the password 'pass', then you could add the following line
|
183 |
+
to the crontab on a home Linux box:
|
184 |
+
|
185 |
+
25 * * * * curl --user login:pass http://www.zyx.com/blog/wp-content/update-feeds.php -d update=quiet
|
186 |
+
|
187 |
+
The `-d update=quiet` switch ensures that (1) `update-feeds.php` will
|
188 |
+
receive an HTTP POST request rather than an HTTP GET request (which
|
189 |
+
is important, since it won't take any actions with side-effects -- such
|
190 |
+
as checking for new posts -- unless it receives an HTTP POST); it also
|
191 |
+
tells it to suppress the HTML output that it would generate for normal
|
192 |
+
web browsers, and only to output text if it encounters errors (this will
|
193 |
+
keep the number of e-mails you receive from the Cron Daemon to a
|
194 |
+
minimum).
|
195 |
|
196 |
+
If you are using Windows XP and have a version of curl (such as the
|
197 |
+
version included in [Cygwin][]), you can create a Scheduled Task to
|
198 |
+
similar effect.
|
199 |
+
|
200 |
+
[Cygwin]: http://www.cygwin.com/
|
201 |
|
202 |
Basic Concepts
|
203 |
--------------
|
204 |
+
FeedWordPress is written as a plugin for [WordPress 1.5][]. It is designed to
|
205 |
+
store all the data it needs within the WordPress database and to make that data
|
206 |
+
easy to manage from within the WordPress Dashboard.
|
207 |
|
208 |
### Contributors / Newsfeeds ###
|
209 |
|
210 |
+
FeedWordPress uses the WordPress Links database to keep a list of the feeds from
|
211 |
+
which it will syndicate content. WordPress allows you to place links in
|
212 |
+
categories; FeedWordPress will make use of all and only the links in one
|
213 |
+
category (by default, this is a category named "Contributors"; you can change
|
214 |
+
the category that FeedWordPress will use using **Options --> Syndication**).
|
215 |
|
216 |
From WordPress's perspective, the list of Contributors are normal links, and
|
217 |
+
they can be manipulated like other links through the WordPress Dashboard.
|
218 |
+
However, FeedWordPress provides a nicer interface for adding, removing, or
|
219 |
+
changing information for the Contributor Links from the WordPress Dashboard,
|
220 |
+
under **Links --> Syndicated**.
|
221 |
+
|
222 |
+
If you want to distribute the labor of adding, updating, and managing feeds
|
223 |
+
between several people, you can use the WordPress login andaccess privileges
|
224 |
+
system. Any users with an access level of 5 or greater can add, delete, and
|
225 |
+
modify Contributors; users with an access level of 6 or greater can change
|
226 |
+
syndication options.
|
227 |
+
|
228 |
+
When FeedWordPress looks for new posts, it retrieves one or all of the links
|
229 |
+
from the Contributors category (depending on whether it has been told to scan
|
230 |
+
for new posts on one or all of the feeds), determines which of them should be
|
231 |
+
polled for updates (based on how long it has been since the last time each feed
|
232 |
+
was polled for updates), and then uses an HTTP conditional GET to check for
|
233 |
+
updates at the "RSS URI" for each Link that it selects. Any new posts are added
|
234 |
+
to the database, and old posts that have been updated since the last poll are
|
235 |
+
updated to reflect the new version.
|
236 |
+
|
237 |
+
__Feed settings:__ All of the information for a syndicated feed is stored in the
|
238 |
+
WordPress Links database, and can be easily edited using an interface that
|
239 |
+
FeedWordPress provides under **Links --> Syndicated**. (If you're curious about
|
240 |
+
the technical details of how the information is stored, you can find out more
|
241 |
+
under [API: How feed information is stored][].)
|
242 |
+
|
243 |
+
You can use a feed's **Edit** link under **Links --> Syndicated** to affect how
|
244 |
+
FeedWordPress prcesses posts from that feed. (Most of these options can either
|
245 |
+
be set for *one particular feed* using **Links --> Syndicated --> Edit**, or set
|
246 |
+
as the default for *all feeds* using **Options --> Syndication**.) The **Edit**
|
247 |
+
link also allows you to set **Custom Feed Settings** for use in templates,
|
248 |
+
through the use of the [`get_feed_meta()`][get_feed_meta] template function in a
|
249 |
+
post context (see [Template API][]). For example, many aggregator sites use a
|
250 |
+
"face" image for each feed to visually distinguish posts from different feeds.
|
251 |
+
To implement a face feature, you could add a custom setting for each Contributor
|
252 |
+
Link, with the key of "face" and a URI such as "http://www.zyx.com/mugs/ugly"
|
253 |
+
for the value. (The URI should be changed out for each feed to point to the
|
254 |
+
appropriate image, of course.) Then, to use the setting from within a template,
|
255 |
+
add something like:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
256 |
|
257 |
// In a post context
|
258 |
<?php $img = get_feed_meta('face'); if (strlen($img) > 0): ?>
|
259 |
<img src="<?=$img?>" alt="" />
|
260 |
<?php endif; ?>
|
261 |
|
262 |
+
... which will display the image, if any, whose URI is set in the "face" setting
|
263 |
+
for the feed that post comes from. If there is no "face" setting for a
|
264 |
+
particular feed, [`get_feed_meta()`][get_feed_meta] will return an empty string
|
265 |
+
and no image will be displayed.
|
266 |
|
267 |
+
[API: How feed information is stored]: http://projects.radgeek.com/feedwordpress/api#how-feed-information-is-stored
|
|
|
|
|
|
|
|
|
|
|
268 |
|
269 |
### Syndicated Posts ###
|
270 |
|
271 |
Whenever FeedWordPress updates, it scans one or more of the feeds in its
|
272 |
Contributors list and adds any new posts that it finds to the WordPress
|
273 |
+
database. Syndicated posts are displayed on your WordPress pages like any other
|
274 |
+
posts: they can be listed in archives by category, author, or date; they can be
|
275 |
+
found with the search box; and they are included in the newsfeed of your blog.
|
276 |
+
|
277 |
+
In your WordPress templates (**Presentation --> Theme Editor**) you can access
|
278 |
+
special information about syndicated posts using [functions provided by
|
279 |
+
FeedWordPress][Template API], such as [`is_syndicated()`][is_syndicated],
|
280 |
+
[`the_syndication_source()`][the_syndication_source],
|
281 |
+
[`the_syndication_source_link()`][the_syndication_source_link], and
|
282 |
+
[`get_feed_meta()`][get_feed_meta]. For example, here is the template code that
|
283 |
+
I use (in a post context) to display both the author's name and the original
|
284 |
+
source of the post in the templates for [Feminist Blogs][]:
|
285 |
|
286 |
<cite class="feed">from <?php the_author_posts_link()?><?php
|
287 |
if (is_syndicated() and (get_the_author() !== get_syndication_source())):
|
290 |
echo '</a>';
|
291 |
endif; ?></cite>
|
292 |
|
293 |
+
For more information on template functions, see [Template API][].
|
294 |
|
295 |
### Categories ###
|
296 |
|
297 |
+
WordPress allows for posts to be placed in *categories*. Each syndicated post
|
298 |
+
that FeedWordPress adds to the WordPress database is placed into a set of
|
299 |
+
categories. FeedWordPress gets the list of category names to use from two
|
300 |
sources:
|
301 |
|
302 |
+
1. Categories (or "tags") that the original author placed the post in on
|
303 |
+
her blog
|
304 |
|
305 |
+
2. Categories that you set explicitly for each feed using the
|
306 |
+
**Categories** checkbox under **Links --> Syndicated --> Edit**. For
|
307 |
+
example, if you wanted all the posts from Alas, A Blog to be placed in
|
308 |
+
the "Pacific Northwest" category and the "Cartoonists" category (*in
|
309 |
+
addition to* any other categories that they were placed in on Alas, A
|
310 |
+
Blog), you could do this by creating the categories, going to **Links
|
311 |
+
--> Syndicated**, clicking the "Edit" link for Alas, A Blog, and
|
312 |
+
checking those two categories under the checkbox captioned "Categories."
|
|
|
|
|
|
|
313 |
|
314 |
Given the list of category names, FeedWordPress looks for categories in the
|
315 |
WordPress database with the same name as either (1) the category name, or
|
316 |
(2) one of the "aliases" listed in the category description.
|
317 |
|
318 |
+
__Aliases:__ Different often authors use slightly different names for categories
|
319 |
+
that mean the same thing (contributors to Feminist Blogs, for example, used
|
320 |
+
categories including "Feminism", "feministy stuff", "Women's Issues", "Gender
|
321 |
+
Issues", "Gender Equality", and so on). If you want FeedWordPress to treat one
|
322 |
+
category name as a synonym for another, you can do so by creating an "alias" for
|
323 |
+
the category. For example, to make FeedWordPress treat posts that are placed in
|
324 |
+
the category "feministy stuff" as if they had been placed in the category
|
325 |
+
"Feminism", go to **Manage --> Categories**, find the category "Feminism" and
|
326 |
+
click the "Edit" link for it, and then add the following to the Description
|
327 |
+
field, on a line by itself:
|
328 |
|
329 |
a.k.a.: feministy stuff
|
330 |
|
331 |
+
You can add as many aliases as you like. You can also add any other text that
|
332 |
+
you like to the Description without interfering with FeedWordPress's ability to
|
333 |
+
use the aliases. Each alias must be on a line by itself.
|
334 |
+
|
335 |
+
__Unfamiliar categories:__ If one of the category names that a newsfeed provides
|
336 |
+
is *unfamiliar* -- that is, if there is not yet any category in your WordPress
|
337 |
+
database that either has that name, or uses that name as an alias -- then by
|
338 |
+
default FeedWordPress will *automatically create* a new category with that name
|
339 |
+
and place the current post in it. The default behavior can be changed so that
|
340 |
+
unfamiliar categories will *not* be added to the database, using the
|
341 |
+
**Unfamiliar categories** setting, either for *all* feeds (under **Options -->
|
342 |
+
Syndication**) or for *one particular feed* (under **Links --> Syndicated**).
|
343 |
+
|
344 |
+
If you choose to disable the creation of new categories, either for all feeds or
|
345 |
+
for one particular feed, then you can also choose whether or not FeedWordPress
|
346 |
+
should syndicate posts that do not match *any* of the categories that are
|
347 |
+
currently in the database. This allows you to do some simple filtering of posts
|
348 |
+
by category: if you want to your blog to syndicate only the posts in one
|
349 |
+
particular category from a feed that has several categories, you could do so by
|
350 |
+
creating a category by that name, adding the new feed(s), and then setting
|
351 |
+
**Unfamiliar categories** under **Links --> Syndicated --> Edit** to "don't
|
352 |
+
create new categories and don't syndicate posts unless they match at least one
|
353 |
+
familiar category".
|
354 |
+
|
355 |
+
Since only posts in categories that are in your database will be included, and
|
356 |
+
only the category or categories that you wanted posts from has been added to
|
357 |
+
your database, this will filter out all the posts that aren't in the category or
|
358 |
+
categories that you defined ahead of time. (Similarly, you could set up
|
359 |
+
FeedWordPress so that *all* the feeds are filtered by author by creating the set
|
360 |
+
of users named after the authors you want to syndicate, and then setting the
|
361 |
+
default behavior for *all* feeds at **Options --> Syndication**).
|
362 |
+
|
363 |
+
If you need a category filter with more complex logic, you can always create a
|
364 |
+
`syndicated_item` filter in PHP (see [Plugin API][]) that manipulates the
|
365 |
+
`['categories']` array of a syndicated item.
|
|
|
366 |
|
367 |
### Authors ###
|
368 |
|
369 |
Most newsfeeds include information about the author of the items on them.
|
370 |
(If a feed doesn't, then FeedWordPress will create an author's name based on
|
371 |
+
the title of the feed from which the item was taken.) This information is used
|
372 |
+
to determine the WordPress user that the post will be attributed to. Given the
|
373 |
+
name of the author, FeedWordPress looks for authors in the WordPress database
|
374 |
+
with the same name as either (1) their login, (2) their first name, (3) their
|
375 |
+
nickname, (4) their full name, or (5) one of the "aliases" listed in the
|
376 |
+
user's profile.
|
377 |
|
378 |
__Aliases:__ If there is an author who posts under more than one name (for
|
379 |
example, one of our contributors at [Feminist Blogs][] posts on several
|
380 |
different blogs, sometimes using her full name and sometimes using only her
|
381 |
+
first name), then you can ensure that FeedWordPress will attribute those posts
|
382 |
+
to the same author by creating "aliases" for the author. For example, to make
|
383 |
+
FeedWordPress treat posts by "Joseph Cardinal Ratzinger" and posts by "Pope
|
384 |
+
Benedict XVI" as having the same author, go to **Users --> Authors & Users**,
|
385 |
+
click on the "Edit" link for Pope Benedict XVI, and add a line like this to the
|
386 |
+
Profile text:
|
387 |
|
388 |
+
a.k.a.: Joseph Cardinal Ratzinger
|
389 |
|
390 |
+
You can add as many aliases as you like. You can also add any other text that
|
391 |
+
you like to the Profile without interfering with FeedWordPress's ability to use
|
392 |
+
the aliases. Each alias must be on a line by itself.
|
393 |
|
394 |
__Unfamiliar authors:__ By default, if the author named by the newsfeed is
|
395 |
unfamiliar -- that is, if there is no-one with that name registered in the
|
396 |
+
WordPress author's database -- then by default FeedWordPress will automatically
|
397 |
+
create a new user account with the given name and attribute the post to the new
|
398 |
+
user. The default behavior can be changed, using either the global settings in
|
399 |
+
**Options --> Syndication** or the [feed settings][] under **Links -->
|
400 |
+
Syndicated --> Edit**, so that posts by unfamiliar authors will either be
|
401 |
+
attributed to a default author (instead of creating a new user account to
|
402 |
+
attribute them to), or filtered out and not syndicated at all.
|
403 |
+
|
404 |
+
One of the uses of this feature is to filtering posts by author: if you want to
|
405 |
+
your blog to syndicate only the posts by one particular author from a feed that
|
406 |
+
has several authors, you could do so by creating a user account with that
|
407 |
+
author's name, adding the new feed(s), and then setting **Unfamiliar authors**
|
408 |
+
under **Links --> Syndicated --> Edit** to "don't syndicate the post". Since
|
409 |
+
only posts by authors that are in your database will be included, and only the
|
410 |
+
author that you wanted posts from has been added to your database, this will
|
411 |
+
filter out posts by anyone else on the feeds with that setting. (Similarly, you
|
412 |
+
could set up FeedWordPress so that *all* the feeds are filtered by author by
|
413 |
+
creating the set of users named after the authors you want to syndicate, and
|
414 |
+
then setting the default behavior for *all* feeds at **Options -->
|
415 |
+
Syndication**).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
|
417 |
+
If you need an author filter with more complex logic than this allows, you can
|
418 |
+
always create a `syndicated_item` filter in PHP (see [Plugin API][]) that
|
419 |
+
manipulates the `['author_name']` or `['dc']['creator']` elements of a
|
420 |
+
syndicated item.
|
421 |
|
422 |
Template API
|
423 |
------------
|
424 |
+
When activated, FeedWordPress makes the following functions available for use by
|
425 |
+
themes/templates:
|
426 |
|
427 |
+
* ``is_syndicated()``: in a post context, returns ``TRUE`` if the post was
|
428 |
+
syndicated from another website, or ``FALSE`` if it was originally
|
429 |
+
posted here
|
430 |
|
431 |
+
* ``get_syndication_permalink()``: in a post context, returns the URI of
|
432 |
+
the permalink for this post *on the website it was syndicated from*
|
433 |
|
434 |
+
* ``the_syndication_permalink()``: in a post context, outputs the value
|
435 |
+
returned by [``get_syndication_permalink()``][get_syndication_permalink]
|
436 |
|
437 |
+
* ``get_syndication_source_link()``: in a post context, returns the URI of
|
438 |
+
the front page (*not* the feed) of the website this post was syndicated
|
439 |
+
from
|
440 |
|
441 |
+
* ``the_syndication_source_link()``: in a post context, outputs the URI
|
442 |
+
returned by
|
443 |
+
[``get_syndication_source_link()``][get_syndication_source_link]
|
444 |
|
445 |
* ``get_syndication_source()``: in a post context, returns the
|
446 |
human-readable title of the website that a syndicated post was
|
447 |
syndicated from
|
448 |
|
449 |
* ``the_syndication_source()``: in a post context, outputs the value
|
450 |
+
returned by [``get_syndication_source()``][get_syndication_source]
|
451 |
|
452 |
+
* ``get_syndication_feed():`` in a post context, returns the URI of the
|
453 |
+
feed (*not* the front page) that this post was syndicated from
|
454 |
|
455 |
* ``the_syndication_feed()``: in a post context, outputs the value
|
456 |
+
returned by [``get_syndication_feed()``][get_syndication_feed]
|
457 |
|
458 |
+
* ``get_feed_meta($key)``: in a post context, returns the value, if any,
|
459 |
+
of the feed setting ``$key`` for the feed that this post was syndicated
|
460 |
+
from
|
461 |
|
462 |
By default, FeedWordPress also places a filter on the standard functions
|
463 |
+
``get_permalink()`` and ``the_permalink()`` that substitutes the URI returned by
|
464 |
+
[``get_syndication_permalink()``][get_syndication_permalink] for the URI
|
465 |
+
generated by WordPress. This means that by default the permalinks listed on your
|
466 |
+
website and in your newsfeed will link to the location of the posts on the
|
467 |
+
source website, *not* to their location on your website. You can switch this
|
468 |
+
behavior on or off at **Options --> Syndication** in the WordPress Dashboard.
|
469 |
+
|
470 |
+
Plugin API
|
471 |
+
----------
|
472 |
+
FeedWordPress creates five hooks through the WordPress plugin architecture that
|
473 |
+
you can plug in to using PHP WordPress plugins, to supplement ordinary
|
474 |
+
FeedWordPress behavior, or to filter posts according to criteria that you set.
|
475 |
+
The hooks are the action ``feedwordpress_update``, the action
|
476 |
+
``feedwordpress_check_feed``, the action ``feedwordpress_update_complete``, the
|
477 |
+
filter ``syndicated_item``, the filter ``syndicated_post``, the action
|
478 |
``post_syndicated_item``, and the action ``update_syndicated_item``.
|
479 |
|
480 |
For more information, see <http://projects.radgeek.com/feedwordpress/api>.
|
481 |
|
482 |
License
|
483 |
-------
|
484 |
+
The FeedWordPress plugin is copyright (c) 2005 by Charles Johnson. It uses code
|
485 |
+
derived or translated from:
|
486 |
|
487 |
+
- [wp-rss-aggregate.php][] by [Kellan Elliot-McCrea](kellan@protest.net)
|
488 |
+
- [MagpieRSS][] by [Kellan Elliot-McCrea](kellan@protest.net)
|
489 |
+
- [HTTP Navigator 2][] by [Keyvan Minoukadeh](keyvan@k1m.com)
|
490 |
+
- [Ultra-Liberal Feed Finder][] by [Mark Pilgrim](mark@diveintomark.org)
|
491 |
|
492 |
according to the terms of the [GNU General Public License][].
|
493 |
|
494 |
+
This program is free software; you can redistribute it and/or modify it under
|
495 |
+
the terms of the [GNU General Public License][] as published by the Free
|
496 |
+
Software Foundation; either version 2 of the License, or (at your option) any
|
497 |
+
later version.
|
498 |
|
499 |
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
500 |
+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
501 |
+
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
502 |
|
503 |
[wp-rss-aggregate.php]: http://laughingmeme.org/archives/002203.html
|
504 |
+
[MagpieRSS]: http://magpierss.sourceforge.net/
|
505 |
[HTTP Navigator 2]: http://www.keyvan.net/2004/11/16/http-navigator/
|
506 |
[Ultra-Liberal Feed Finder]: http://diveintomark.org/projects/feed_finder/
|
507 |
+
|
508 |
[GNU General Public License]: http://www.gnu.org/copyleft/gpl.html
|
509 |
|
wp-content/plugins/feedwordpress.php
CHANGED
@@ -3,11 +3,11 @@
|
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
-
Version: 0.
|
7 |
Author: Charles Johnson
|
8 |
-
Author URI: http://
|
9 |
License: GPL
|
10 |
-
Last modified: 2005-
|
11 |
*/
|
12 |
|
13 |
# This uses code derived from:
|
@@ -27,9 +27,14 @@ Last modified: 2005-05-08 1:54pm EDT
|
|
27 |
|
28 |
# -- Don't change these unless you know what you're doing...
|
29 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/');
|
30 |
-
define ('FEEDWORDPRESS_VERSION', '0.
|
31 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
32 |
|
|
|
|
|
|
|
|
|
|
|
33 |
// Note that the rss-functions.php that comes prepackaged with WordPress is
|
34 |
// old & busted. For the new hotness, drop a copy of rss-functions.php from
|
35 |
// this archive into wp-includes/rss-functions.php
|
@@ -38,82 +43,113 @@ require_once (ABSPATH . WPINC . '/rss-functions.php');
|
|
38 |
// Is this being loaded from within WordPress 1.5 or later?
|
39 |
if (isset($wp_version) and $wp_version >= 1.5):
|
40 |
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
55 |
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
-
|
60 |
-
|
|
|
61 |
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
68 |
|
69 |
-
|
|
|
|
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
|
76 |
-
add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
|
77 |
-
add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
|
78 |
-
|
79 |
-
function log_feedwordpress_post ($id) {
|
80 |
-
$post = wp_get_single_post($id);
|
81 |
-
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
|
82 |
-
."'{$post->post_title}' ({$post->post_date})");
|
83 |
-
}
|
84 |
-
|
85 |
-
function log_feedwordpress_update_post ($id) {
|
86 |
-
$post = wp_get_single_post($id);
|
87 |
-
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
|
88 |
-
."'{$post->post_title}' ({$post->post_date})"
|
89 |
-
." (as of {$post->post_modified})");
|
90 |
-
}
|
91 |
-
|
92 |
-
function log_feedwordpress_update_feeds ($uri) {
|
93 |
-
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
|
94 |
-
}
|
95 |
-
|
96 |
-
function log_feedwordpress_check_feed ($feed) {
|
97 |
-
$uri = $feed['uri']; $name = $feed['name'];
|
98 |
-
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
|
99 |
-
}
|
100 |
-
|
101 |
-
function log_feedwordpress_update_complete ($delta) {
|
102 |
-
$mesg = array();
|
103 |
-
if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
|
104 |
-
if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
|
105 |
-
if (empty($mesg)) $mesg[] = 'nothing changed';
|
106 |
-
|
107 |
-
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
|
108 |
-
.(is_null($delta) ? "I don't syndicate <$uri>"
|
109 |
-
: implode(' and ', $mesg)));
|
110 |
-
}
|
111 |
-
endif;
|
112 |
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
-
|
116 |
-
function is_syndicated () { return (strlen(get_syndication_feed()) > 0); }
|
117 |
|
118 |
function the_syndication_source_link () { echo get_syndication_source_link(); }
|
119 |
function get_syndication_source_link () { list($n) = get_post_custom_values('syndication_source_uri'); return $n; }
|
@@ -124,18 +160,28 @@ function the_syndication_source () { echo get_syndication_source(); }
|
|
124 |
function get_syndication_feed () { list($u) = get_post_custom_values('syndication_feed'); return $u; }
|
125 |
function the_syndication_feed () { echo get_syndication_feed (); }
|
126 |
|
|
|
|
|
|
|
|
|
|
|
127 |
function get_feed_meta ($key) {
|
128 |
-
global $wpdb;
|
129 |
-
$
|
130 |
-
|
131 |
$ret = NULL;
|
132 |
-
if (strlen($
|
133 |
-
$
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
-
$meta = FeedWordPress::notes_to_settings($result);
|
139 |
$ret = $meta[$key];
|
140 |
endif; /* if */
|
141 |
return $ret;
|
@@ -148,7 +194,10 @@ function the_syndication_permalink () {
|
|
148 |
echo get_syndication_permalink();
|
149 |
}
|
150 |
|
151 |
-
|
|
|
|
|
|
|
152 |
$feedwordpress_the_syndicated_content = NULL;
|
153 |
|
154 |
function feedwordpress_preserve_syndicated_content ($text) {
|
@@ -181,7 +230,59 @@ function syndication_permalink ($permalink = '') {
|
|
181 |
endif;
|
182 |
} // function syndication_permalink ()
|
183 |
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
function fwp_add_pages () {
|
186 |
add_submenu_page('link-manager.php', 'Syndicated Sites', 'Syndicated', 5, basename(__FILE__), 'fwp_syndication_manage_page');
|
187 |
add_options_page('Syndication Options', 'Syndication', 6, basename(__FILE__), 'fwp_syndication_options_page');
|
@@ -190,8 +291,13 @@ function fwp_add_pages () {
|
|
190 |
function fwp_syndication_options_page () {
|
191 |
global $wpdb, $user_level;
|
192 |
|
|
|
|
|
|
|
|
|
|
|
193 |
$caption = 'Save Changes';
|
194 |
-
if (isset($
|
195 |
check_admin_referer();
|
196 |
|
197 |
if ($user_level < 6):
|
@@ -205,6 +311,23 @@ function fwp_syndication_options_page () {
|
|
205 |
update_option('feedwordpress_unfamiliar_category', $_REQUEST['unfamiliar_category']);
|
206 |
update_option('feedwordpress_syndicated_post_status', $_REQUEST['post_status']);
|
207 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
if (isset($_REQUEST['comment_status']) and ($_REQUEST['comment_status'] == 'open')) :
|
209 |
update_option('feedwordpress_syndicated_comment_status', 'open');
|
210 |
else :
|
@@ -266,6 +389,20 @@ function fwp_syndication_options_page () {
|
|
266 |
$unfamiliar_category[$uc] = ' checked="checked"';
|
267 |
endif;
|
268 |
$results = $wpdb->get_results("SELECT cat_id, cat_name, auto_toggle FROM $wpdb->linkcategories ORDER BY cat_id");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
?>
|
270 |
<div class="wrap">
|
271 |
<h2>Syndication Options</h2>
|
@@ -300,44 +437,52 @@ function fwp_syndication_options_page () {
|
|
300 |
</fieldset>
|
301 |
|
302 |
<fieldset class="options">
|
303 |
-
<legend>Syndicated Posts</
|
304 |
-
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
305 |
-
<tr><th width="33%" scope="row">Permalinks point to:</th>
|
306 |
-
<td width="67%"><select name="munge_permalink" size="1">
|
307 |
-
<option value="yes"<?=($munge_permalink=='yes')?' selected="selected"':''?>>original website</option>
|
308 |
-
<option value="no"<?=($munge_permalink=='no')?' selected="selected"':''?>>this website</option>
|
309 |
-
</select></td></tr>
|
310 |
|
311 |
-
<
|
312 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
<li><label><input type="radio" name="post_status" value="publish"<?=($post_status=='publish')?' checked="checked"':''?> /> Publish syndicated posts immediately</label></li>
|
314 |
<li><label><input type="radio" name="post_status" value="draft"<?=($post_status=='draft')?' checked="checked"':''?> /> Hold syndicated posts as drafts</label></li>
|
315 |
<li><label><input type="radio" name="post_status" value="private"<?=($post_status=='private')?' checked="checked"':''?> /> Hold syndicated posts as private posts</label></li>
|
316 |
</ul></td></tr>
|
317 |
|
318 |
-
<tr><th width="33%" scope="row">Comments:</th>
|
319 |
-
<td width="67%"><ul style="list-style:none">
|
320 |
-
<li><input type="
|
|
|
321 |
</ul></td></tr>
|
322 |
|
323 |
-
<tr><th width="33%" scope="row">Trackback and Pingback:</th>
|
324 |
-
<td width="67%"><ul style="list-style:none">
|
325 |
-
<li><input type="
|
|
|
326 |
</ul></td></tr>
|
327 |
|
328 |
-
<tr><th width="33%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
329 |
-
<td width="67%"><ul style="margin: 0;list-style:none">
|
330 |
<li><label><input type="radio" name="unfamiliar_author" value="create"<?=$unfamiliar_author['create']?>/> create a new author account</label></li>
|
331 |
<li><label><input type="radio" name="unfamiliar_author" value="default"<?=$unfamiliar_author['default']?> /> attribute the post to the default author</label></li>
|
332 |
<li><label><input type="radio" name="unfamiliar_author" value="filter"<?=$unfamiliar_author['filter']?> /> don't syndicate the post</label></li>
|
333 |
</ul></td></tr>
|
334 |
-
<tr><th width="33%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
335 |
-
<td width="67%"><ul style="margin: 0;list-style:none">
|
336 |
<li><label><input type="radio" name="unfamiliar_category" value="create"<?=$unfamiliar_category['create']?>/> create any categories the post is in</label></li>
|
337 |
<li><label><input type="radio" name="unfamiliar_category" value="default"<?=$unfamiliar_category['default']?>/> don't create new categories</li>
|
338 |
<li><label><input type="radio" name="unfamiliar_category" value="filter"<?=$unfamiliar_category['filter']?>/> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
|
339 |
</ul></td></tr>
|
340 |
|
|
|
|
|
|
|
|
|
341 |
</select></td></tr>
|
342 |
</table>
|
343 |
<div class="submit"><input type="submit" name="action" value="<?=$caption?>" /></div>
|
@@ -368,13 +513,19 @@ function fwp_syndication_options_page () {
|
|
368 |
|
369 |
function fwp_syndication_manage_page () {
|
370 |
global $user_level, $wpdb;
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
?>
|
372 |
<?php $cont = true;
|
373 |
if (isset($_REQUEST['action'])):
|
374 |
-
//die("ACTION: '".$_REQUEST['action']."'");
|
375 |
if ($_REQUEST['action'] == 'feedfinder') : $cont = fwp_feedfinder_page();
|
376 |
elseif ($_REQUEST['action'] == 'switchfeed') : $cont = fwp_switchfeed_page();
|
377 |
-
elseif ($_REQUEST['action'] == '
|
|
|
378 |
endif;
|
379 |
endif;
|
380 |
|
@@ -404,7 +555,7 @@ if ($cont):
|
|
404 |
<table width="100%" cellpadding="3" cellspacing="3">
|
405 |
<tr>
|
406 |
<th width="20%"><?php _e('Name'); ?></th>
|
407 |
-
<th width="
|
408 |
<th colspan="4"><?php _e('Action'); ?></th>
|
409 |
</tr>
|
410 |
|
@@ -412,31 +563,44 @@ if ($cont):
|
|
412 |
$alt_row = !$alt_row; ?>
|
413 |
<tr<?=($alt_row?' class="alternate"':'')?>>
|
414 |
<td><a href="<?=wp_specialchars($link->link_url)?>"><?=wp_specialchars($link->link_name)?></a></td>
|
415 |
-
<?php
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
|
|
|
|
|
|
|
|
|
|
435 |
?>
|
436 |
-
|
|
|
|
|
|
|
437 |
<?php
|
|
|
|
|
|
|
|
|
438 |
endforeach;
|
439 |
-
else:
|
|
|
440 |
|
441 |
<p>There are no websites currently listed for syndication.</p>
|
442 |
|
@@ -447,7 +611,7 @@ feed assigned</strong></p></td>
|
|
447 |
<div class="wrap">
|
448 |
<h2>Manage Multiple Links</h2>
|
449 |
<div class="submit">
|
450 |
-
<input type="submit" class="delete" name="action" value="
|
451 |
</div>
|
452 |
</div>
|
453 |
</form>
|
@@ -573,7 +737,7 @@ function fwp_switchfeed_page () {
|
|
573 |
|
574 |
if ($result): ?>
|
575 |
<div class="updated"><p><a href="<?=$_REQUEST['feed_link']?>"><?=wp_specialchars($_REQUEST['feed_title'])?></a>
|
576 |
-
has been added as a contributing site, using the
|
577 |
<?php else: ?>
|
578 |
<div class="updated"><p>There was a problem adding the newsfeed. [SQL: <?=wp_specialchars(mysql_error())?>]</p></div>
|
579 |
<?php endif;
|
@@ -602,30 +766,616 @@ updated to <<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['fe
|
|
602 |
return true; // Continue
|
603 |
}
|
604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
605 |
function fwp_multidelete_page () {
|
606 |
global $wpdb, $user_level;
|
607 |
-
|
|
|
|
|
|
|
|
|
|
|
608 |
if ($user_level < 5):
|
609 |
die (__("Cheatin' uh ?"));
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
WHERE link_id IN (".implode(',',$_REQUEST['linkcheck']).")
|
615 |
-
");
|
616 |
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
$
|
|
|
|
|
|
|
|
|
621 |
endif;
|
622 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
623 |
endif;
|
624 |
-
return true;
|
625 |
}
|
626 |
|
627 |
-
|
628 |
-
|
|
|
|
|
|
|
629 |
$fwp_held_ping = NULL; // NULL: not holding pings yet
|
630 |
|
631 |
function fwp_hold_pings () {
|
@@ -652,8 +1402,11 @@ function fwp_catch_ping ($post_id = 0) {
|
|
652 |
endif;
|
653 |
}
|
654 |
|
655 |
-
|
656 |
-
|
|
|
|
|
|
|
657 |
class FeedWordPress {
|
658 |
var $strip_attrs = array (
|
659 |
array('[a-z]+', 'style'),
|
@@ -703,13 +1456,16 @@ class FeedWordPress {
|
|
703 |
# like so:
|
704 |
#
|
705 |
# key: value
|
706 |
-
# cats: computers
|
707 |
# feed/key: value
|
708 |
#
|
709 |
# Keys that start with "feed/" are gleaned from the data supplied
|
710 |
# by the feed itself, and will be overwritten with each update.
|
711 |
#
|
712 |
-
#
|
|
|
|
|
|
|
713 |
# default categories for any post coming from a particular feed.
|
714 |
# (In the example above, any posts from this feed will be placed
|
715 |
# in the "computers" and "web" categories--*in addition to* any
|
@@ -725,8 +1481,9 @@ class FeedWordPress {
|
|
725 |
if ($result): foreach ($result as $link):
|
726 |
if (strlen($link->link_rss) > 0):
|
727 |
$sec = FeedWordPress::notes_to_settings($link->link_notes);
|
728 |
-
$sec['uri'] = $link->link_rss;
|
729 |
-
$sec['name'] = $link->link_name;
|
|
|
730 |
|
731 |
// `hardcode categories` is deprecated in favor
|
732 |
// of `unfamiliar categories`
|
@@ -738,9 +1495,8 @@ class FeedWordPress {
|
|
738 |
endif;
|
739 |
|
740 |
if (isset($sec['cats'])):
|
741 |
-
$sec['cats'] =
|
742 |
endif;
|
743 |
-
$sec['link_id'] = $link->link_id;
|
744 |
|
745 |
$feeds[] = $sec;
|
746 |
endif;
|
@@ -749,6 +1505,23 @@ class FeedWordPress {
|
|
749 |
$this->feeds = $feeds;
|
750 |
} // FeedWordPress::FeedWordPress ()
|
751 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
752 |
function notes_to_settings ($link_notes) {
|
753 |
$notes = explode("\n", $link_notes);
|
754 |
|
@@ -766,45 +1539,121 @@ class FeedWordPress {
|
|
766 |
return $sec;
|
767 |
} // FeedWordPress::notes_to_settings ()
|
768 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
769 |
function update ($uri) {
|
770 |
global $wpdb;
|
771 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
772 |
do_action('feedwordpress_update', $uri);
|
773 |
|
774 |
// Secret voodoo tag: URI for updating *everything*.
|
775 |
$secret = RPC_MAGIC.FeedWordPress::rpc_secret();
|
776 |
|
777 |
-
fwp_hold_pings();
|
778 |
|
779 |
// Loop through and check for new posts
|
780 |
$delta = NULL;
|
781 |
-
foreach ($this->feeds as $feed)
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
786 |
do_action('feedwordpress_check_feed', array($feed));
|
787 |
$added = $this->feed2wp($wpdb, $feed);
|
788 |
-
if (isset($added['new'])) $delta['new'] += $added['new'];
|
789 |
-
if (isset($added['updated'])) $delta['updated'] += $added['updated'];
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
do_action('feedwordpress_update_complete', array($delta));
|
794 |
-
fwp_release_pings();
|
795 |
|
796 |
return $delta;
|
797 |
}
|
798 |
|
799 |
function feed2wp ($wpdb, $f) {
|
800 |
-
$feed = fetch_rss($f['uri']);
|
801 |
$new_count = array('new' => 0, 'updated' => 0);
|
802 |
|
803 |
$this->update_feed($wpdb, $feed->channel, $f);
|
804 |
|
805 |
if (is_array($feed->items)) :
|
806 |
foreach ($feed->items as $item) :
|
807 |
-
$post = $this->item_to_post($wpdb, $item, $feed
|
808 |
if (!is_null($post)) :
|
809 |
$new = $this->add_post($wpdb, $post);
|
810 |
if ( $new !== false ) $new_count[$new]++;
|
@@ -879,11 +1728,51 @@ class FeedWordPress {
|
|
879 |
return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $affirmo));
|
880 |
}
|
881 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
882 |
function update_feed ($wpdb, $channel, $f) {
|
883 |
-
$link_id = $f['
|
884 |
|
885 |
if (!isset($channel['id'])) :
|
886 |
-
$channel['id'] = $f['uri'];
|
887 |
endif;
|
888 |
|
889 |
$update = array();
|
@@ -904,13 +1793,28 @@ class FeedWordPress {
|
|
904 |
endif;
|
905 |
|
906 |
if (is_array($f['cats'])) :
|
907 |
-
$f['cats'] = implode(
|
908 |
endif;
|
909 |
|
910 |
$f = array_merge($f, $this->flatten_array($channel));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
911 |
|
912 |
# -- A few things we don't want to save in the notes
|
913 |
-
unset($f['
|
|
|
914 |
unset($f['hardcode categories']); // Deprecated
|
915 |
|
916 |
$notes = '';
|
@@ -928,7 +1832,57 @@ class FeedWordPress {
|
|
928 |
WHERE link_id='$link_id'
|
929 |
");
|
930 |
} // function FeedWordPress::update_feed ()
|
931 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
932 |
// item_to_post(): convert information from a single item from an
|
933 |
// Atom/RSS feed to a post for WordPress's database.
|
934 |
//
|
@@ -943,8 +1897,9 @@ class FeedWordPress {
|
|
943 |
// add_post()). If you want plugins that have side effects on the posts
|
944 |
// database, you should probably hook into the action
|
945 |
// post_syndicated_item
|
946 |
-
|
947 |
-
|
|
|
948 |
$post = array();
|
949 |
|
950 |
// This is ugly as all hell. I'd like to use apply_filters()'s
|
@@ -966,22 +1921,46 @@ class FeedWordPress {
|
|
966 |
$post['post_title'] = $wpdb->escape($item['title']);
|
967 |
|
968 |
$post['named']['author'] = array ();
|
969 |
-
|
970 |
-
|
|
|
971 |
elseif (isset($item['dc']['creator'])):
|
|
|
|
|
972 |
$post['named']['author']['name'] = $item['dc']['contributor'];
|
973 |
-
elseif (isset($
|
974 |
-
$post['named']['author']['name'] = $
|
975 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
976 |
$post['named']['author']['name'] = $channel['title'];
|
977 |
endif;
|
978 |
|
979 |
if (isset($item['author_email'])):
|
980 |
$post['named']['author']['email'] = $item['author_email'];
|
|
|
|
|
981 |
endif;
|
982 |
|
983 |
if (isset($item['author_url'])):
|
984 |
$post['named']['author']['uri'] = $item['author_url'];
|
|
|
|
|
985 |
else:
|
986 |
$post['named']['author']['uri'] = $channel['link'];
|
987 |
endif;
|
@@ -993,7 +1972,11 @@ class FeedWordPress {
|
|
993 |
|
994 |
# Identify content and sanitize it.
|
995 |
# ---------------------------------
|
996 |
-
if (isset($item['
|
|
|
|
|
|
|
|
|
997 |
$content = $item['content']['encoded'];
|
998 |
else:
|
999 |
$content = $item['description'];
|
@@ -1055,19 +2038,32 @@ class FeedWordPress {
|
|
1055 |
# current time.
|
1056 |
if (isset($item['dc']['date'])):
|
1057 |
$post['epoch']['issued'] = parse_w3cdtf($item['dc']['date']);
|
1058 |
-
elseif (isset($item['issued'])):
|
|
|
|
|
|
|
|
|
1059 |
$post['epoch']['issued'] = parse_w3cdtf($item['issued']);
|
1060 |
-
elseif (isset($item['pubdate'])):
|
1061 |
$post['epoch']['issued'] = strtotime($item['pubdate']);
|
1062 |
else:
|
1063 |
$post['epoch']['issued'] = time();
|
1064 |
endif;
|
1065 |
|
|
|
|
|
|
|
1066 |
# As far as I know, only atom currently has a reliable way to
|
1067 |
# specify when something was *modified* last
|
1068 |
-
if (isset($item['modified'])):
|
1069 |
-
$post['epoch']['modified'] = parse_w3cdtf($item['modified']);
|
1070 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1071 |
$post['epoch']['modified'] = $post['epoch']['issued'];
|
1072 |
endif;
|
1073 |
|
@@ -1082,26 +2078,30 @@ class FeedWordPress {
|
|
1082 |
$post['ping_status'] = FeedWordPress::syndicated_status('ping', $f, 'closed');
|
1083 |
|
1084 |
// Unique ID (hopefully a unique tag: URI); failing that, the permalink
|
1085 |
-
|
1086 |
-
$post['guid'] = $wpdb->escape($item['id']);
|
1087 |
-
else:
|
1088 |
-
$post['guid'] = $wpdb->escape($item['link']);
|
1089 |
-
endif;
|
1090 |
|
1091 |
-
// RSS 2.0 / Atom 0
|
1092 |
-
if ( isset($item['enclosure'])
|
1093 |
-
|
|
|
1094 |
$post['meta']['enclosure'][] =
|
1095 |
-
$enclosure
|
1096 |
-
$enclosure
|
1097 |
-
$enclosure
|
1098 |
-
|
1099 |
endif;
|
1100 |
|
1101 |
// In case you want to point back to the blog this was syndicated from
|
1102 |
if (isset($channel['title'])) $post['meta']['syndication_source'] = $channel['title'];
|
1103 |
if (isset($channel['link'])) $post['meta']['syndication_source_uri'] = $channel['link'];
|
1104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1105 |
|
1106 |
// In case you want to know the external permalink...
|
1107 |
$post['meta']['syndication_permalink'] = $item['link'];
|
@@ -1111,17 +2111,25 @@ class FeedWordPress {
|
|
1111 |
$post['named']['unfamiliar']['category'] = $f['unfamiliar categories'];
|
1112 |
|
1113 |
// Categories: start with default categories
|
1114 |
-
$
|
|
|
|
|
|
|
|
|
1115 |
|
1116 |
// Now add categories from the post, if we have 'em
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
|
|
|
|
|
|
|
|
1120 |
$post['named']['category'] = array_merge($post['named']['category'], explode(' ', $cat));
|
1121 |
else:
|
1122 |
$post['named']['category'][] = $cat;
|
1123 |
endif;
|
1124 |
-
|
1125 |
endif;
|
1126 |
endif;
|
1127 |
return $post;
|
@@ -1161,8 +2169,18 @@ class FeedWordPress {
|
|
1161 |
$post['named']['category'],
|
1162 |
FeedWordPress::on_unfamiliar('category', $post['named']['unfamiliar']['category'])
|
1163 |
);
|
1164 |
-
|
|
|
1165 |
$freshness = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1166 |
endif;
|
1167 |
endif;
|
1168 |
|
@@ -1254,7 +2272,7 @@ class FeedWordPress {
|
|
1254 |
do_action('edit_post', $postId);
|
1255 |
|
1256 |
$this->add_rss_meta($wpdb, $postId, $post);
|
1257 |
-
|
1258 |
do_action('update_syndicated_item', $postId);
|
1259 |
|
1260 |
$ret = 'updated';
|
@@ -1334,22 +2352,29 @@ class FeedWordPress {
|
|
1334 |
function author_to_id ($wpdb, $author, $email, $url, $unfamiliar_author = 'create') {
|
1335 |
// Never can be too careful...
|
1336 |
$nice_author = sanitize_title($author);
|
|
|
1337 |
$author = $wpdb->escape($author);
|
1338 |
$email = $wpdb->escape($email);
|
1339 |
$url = $wpdb->escape($url);
|
1340 |
-
|
1341 |
$id = $wpdb->get_var(
|
1342 |
"SELECT ID from $wpdb->users
|
1343 |
WHERE
|
1344 |
-
user_login = '$author' OR
|
1345 |
-
user_firstname = '$author' OR
|
1346 |
-
user_nickname = '$author' OR
|
1347 |
-
user_nicename = '$nice_author' OR
|
1348 |
-
user_description = '$author' OR
|
1349 |
-
(
|
1350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1351 |
");
|
1352 |
-
|
1353 |
if (is_null($id)) :
|
1354 |
if ($unfamiliar_author === 'create') :
|
1355 |
$wpdb->query (
|
@@ -1390,24 +2415,22 @@ class FeedWordPress {
|
|
1390 |
$cat_str = array ();
|
1391 |
$cat_aka = array ();
|
1392 |
foreach ( $cats as $c ) :
|
|
|
1393 |
$esc = $wpdb->escape($c);
|
1394 |
$cat_str[] = "'$esc'";
|
1395 |
-
|
|
|
|
|
1396 |
endforeach;
|
1397 |
|
1398 |
$match_cat_name = 'cat_name IN ('.join(',', $cat_str).')';
|
1399 |
$match_cat_alias = join(' OR ', $cat_aka);
|
1400 |
|
1401 |
-
// Normalizing case with LOWER() avoids conflicts in
|
1402 |
-
// VARCHAR comparison between PHP (which has
|
1403 |
-
// case-sensitive comparisons) and MySQL (which has
|
1404 |
-
// case-insensitive comparisons for the field types used
|
1405 |
-
// by WordPress)
|
1406 |
$results = $wpdb->get_results(
|
1407 |
"SELECT
|
1408 |
cat_ID,
|
1409 |
-
|
1410 |
-
|
1411 |
FROM $wpdb->categories
|
1412 |
WHERE ($match_cat_name) OR ($match_cat_alias)"
|
1413 |
);
|
@@ -1422,15 +2445,27 @@ class FeedWordPress {
|
|
1422 |
$cat_ids[] = $row->cat_ID;
|
1423 |
|
1424 |
// Add name to list of categories not to
|
1425 |
-
// create afresh.
|
1426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1427 |
|
1428 |
// Add name of any aliases to list of
|
1429 |
// categories not to create afresh.
|
1430 |
if (preg_match_all('/^a.k.a. \s* :? \s* (.*\S) \s*$/mx',
|
1431 |
$row->category_description, $aka,
|
1432 |
PREG_PATTERN_ORDER)) :
|
1433 |
-
$found = array_merge (
|
|
|
|
|
|
|
|
|
|
|
|
|
1434 |
endif;
|
1435 |
endforeach;
|
1436 |
endif;
|
@@ -1521,9 +2556,73 @@ class FeedWordPress {
|
|
1521 |
");
|
1522 |
return $cat_name;
|
1523 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1524 |
} // class FeedWordPress
|
1525 |
|
1526 |
-
|
|
|
|
|
|
|
1527 |
function feedwordpress_xmlrpc_hook ($args = array ()) {
|
1528 |
$args['weblogUpdates.ping'] = 'feedwordpress_pong';
|
1529 |
return $args;
|
@@ -1543,6 +2642,10 @@ function feedwordpress_pong ($args) {
|
|
1543 |
endif;
|
1544 |
}
|
1545 |
|
|
|
|
|
|
|
|
|
1546 |
class FeedFinder {
|
1547 |
var $uri = NULL;
|
1548 |
var $_cache_uri = NULL;
|
@@ -1873,4 +2976,31 @@ class Relative_URI
|
|
1873 |
return preg_replace('/[^\x21-\x7e]/', '', $encoded);
|
1874 |
}
|
1875 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1876 |
?>
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
+
Version: 0.97
|
7 |
Author: Charles Johnson
|
8 |
+
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
10 |
+
Last modified: 2005-09-28 4:40pm EDT
|
11 |
*/
|
12 |
|
13 |
# This uses code derived from:
|
27 |
|
28 |
# -- Don't change these unless you know what you're doing...
|
29 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/');
|
30 |
+
define ('FEEDWORDPRESS_VERSION', '0.97');
|
31 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
32 |
|
33 |
+
define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
|
34 |
+
define ('FEEDWORDPRESS_CAT_SEPARATOR', "\n");
|
35 |
+
|
36 |
+
define ('FEEDVALIDATOR_URI', 'http://feedvalidator.org/check.cgi');
|
37 |
+
|
38 |
// Note that the rss-functions.php that comes prepackaged with WordPress is
|
39 |
// old & busted. For the new hotness, drop a copy of rss-functions.php from
|
40 |
// this archive into wp-includes/rss-functions.php
|
43 |
// Is this being loaded from within WordPress 1.5 or later?
|
44 |
if (isset($wp_version) and $wp_version >= 1.5):
|
45 |
|
46 |
+
$fwp_db_version = get_settings('feedwordpress_version');
|
47 |
+
$feedwordpress_needs_upgrade = false; // innocent until proven guilty
|
48 |
+
if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
|
49 |
+
// check to see whether this is a fresh install or an upgrade
|
50 |
+
$syn = $wpdb->get_col("
|
51 |
+
SELECT post_id
|
52 |
+
FROM $wpdb->postmeta
|
53 |
+
WHERE meta_key = 'syndication_feed'
|
54 |
+
");
|
55 |
+
if (count($syn) > 0) : // contains at least one syndicated post
|
56 |
+
$feedwordpress_needs_upgrade = true;
|
57 |
+
else : // fresh install; brand it as ours
|
58 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
59 |
+
if (!get_settings('feedwordpress_rpc_secret')) :
|
60 |
+
update_option('feedwordpress_rpc_secret', substr(md5(uniqid(microtime())), 0, 6));
|
61 |
+
endif;
|
62 |
+
endif;
|
63 |
+
endif;
|
64 |
|
65 |
+
if (!$feedwordpress_needs_upgrade) : // only work if the conditions are safe!
|
66 |
+
|
67 |
+
# Syndicated items are generally received in output-ready (X)HTML and
|
68 |
+
# should not be folded, crumpled, mutilated, or spindled by WordPress
|
69 |
+
# formatting filters. But we don't want to interfere with filters for
|
70 |
+
# any locally-authored posts, either.
|
71 |
+
#
|
72 |
+
# What WordPress should really have is a way for upstream filters to
|
73 |
+
# stop downstream filters from running at all. Since it doesn't, and
|
74 |
+
# since a downstream filter can't access the original copy of the text
|
75 |
+
# that is being filtered, what we will do here is (1) save a copy of the
|
76 |
+
# original text upstream, before any other filters run, and then (2)
|
77 |
+
# retrieve that copy downstream, after all the other filters run, *if*
|
78 |
+
# this is a syndicated post
|
79 |
+
|
80 |
+
add_filter('the_content', 'feedwordpress_preserve_syndicated_content', -10000);
|
81 |
+
add_filter('the_content', 'feedwordpress_restore_syndicated_content', 10000);
|
82 |
+
|
83 |
+
# Filter in original permalinks if the user wants that
|
84 |
+
add_filter('post_link', 'syndication_permalink', 1);
|
85 |
+
|
86 |
+
# Admin menu
|
87 |
+
add_action('admin_menu', 'fwp_add_pages');
|
88 |
+
|
89 |
+
# Inbound XML-RPC update methods
|
90 |
+
add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
|
91 |
+
|
92 |
+
# Outbound XML-RPC ping reform
|
93 |
+
remove_action('publish_post', 'generic_ping');
|
94 |
+
add_action('publish_post', 'fwp_catch_ping');
|
95 |
+
|
96 |
+
# Hook in logging functions only if the logging option is ON
|
97 |
+
$update_logging = get_settings('feedwordpress_update_logging');
|
98 |
+
if ($update_logging == 'yes') :
|
99 |
+
add_action('post_syndicated_item', 'log_feedwordpress_post', 100);
|
100 |
+
add_action('update_syndicated_item', 'log_feedwordpress_update_post', 100);
|
101 |
+
add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
|
102 |
+
add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
|
103 |
+
add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
|
104 |
+
endif;
|
105 |
+
else :
|
106 |
+
# Hook in the menus, which will just point to the upgrade interface
|
107 |
+
add_action('admin_menu', 'fwp_add_pages');
|
108 |
+
endif; // if (!$feedwordpress_needs_upgrade)
|
109 |
+
endif;
|
110 |
|
111 |
+
################################################################################
|
112 |
+
## LOGGING FUNCTIONS: log status updates to error_log if you want it ###########
|
113 |
+
################################################################################
|
114 |
|
115 |
+
function log_feedwordpress_post ($id) {
|
116 |
+
$post = wp_get_single_post($id);
|
117 |
+
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
|
118 |
+
."'{$post->post_title}' ({$post->post_date})");
|
119 |
+
}
|
120 |
|
121 |
+
function log_feedwordpress_update_post ($id) {
|
122 |
+
$post = wp_get_single_post($id);
|
123 |
+
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
|
124 |
+
."'{$post->post_title}' ({$post->post_date})"
|
125 |
+
." (as of {$post->post_modified})");
|
126 |
+
}
|
127 |
|
128 |
+
function log_feedwordpress_update_feeds ($uri) {
|
129 |
+
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
|
130 |
+
}
|
131 |
|
132 |
+
function log_feedwordpress_check_feed ($feed) {
|
133 |
+
$uri = $feed['link/uri']; $name = $feed['link/name'];
|
134 |
+
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
|
135 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
|
137 |
+
function log_feedwordpress_update_complete ($delta) {
|
138 |
+
$mesg = array();
|
139 |
+
if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
|
140 |
+
if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
|
141 |
+
if (empty($mesg)) $mesg[] = 'nothing changed';
|
142 |
+
|
143 |
+
error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
|
144 |
+
.(is_null($delta) ? "Error: I don't syndicate that URI"
|
145 |
+
: implode(' and ', $mesg)));
|
146 |
+
}
|
147 |
+
|
148 |
+
################################################################################
|
149 |
+
## TEMPLATE API: functions to make your templates syndication-aware ############
|
150 |
+
################################################################################
|
151 |
|
152 |
+
function is_syndicated () { return (strlen(get_syndication_feed_id()) > 0); }
|
|
|
153 |
|
154 |
function the_syndication_source_link () { echo get_syndication_source_link(); }
|
155 |
function get_syndication_source_link () { list($n) = get_post_custom_values('syndication_source_uri'); return $n; }
|
160 |
function get_syndication_feed () { list($u) = get_post_custom_values('syndication_feed'); return $u; }
|
161 |
function the_syndication_feed () { echo get_syndication_feed (); }
|
162 |
|
163 |
+
function get_syndication_feed_id () { list($u) = get_post_custom_values('syndication_feed_id'); return $u; }
|
164 |
+
function the_syndication_feed_id () { echo get_syndication_feed_id(); }
|
165 |
+
|
166 |
+
$feedwordpress_linkcache = array (); // only load links from database once
|
167 |
+
|
168 |
function get_feed_meta ($key) {
|
169 |
+
global $wpdb, $feedwordpress_linkcache;
|
170 |
+
$feed_id = get_syndication_feed_id();
|
171 |
+
|
172 |
$ret = NULL;
|
173 |
+
if (strlen($feed_id) > 0):
|
174 |
+
if (isset($feedwordpress_linkcache[$feed_id])) :
|
175 |
+
$result = $feedwordpress_linkcache[$feed_id];
|
176 |
+
else :
|
177 |
+
$result = $wpdb->get_row("
|
178 |
+
SELECT * FROM $wpdb->links
|
179 |
+
WHERE (link_id = '".$wpdb->escape($feed_id)."')"
|
180 |
+
);
|
181 |
+
$feedwordpress_linkcache[$feed_id] = $result;
|
182 |
+
endif;
|
183 |
|
184 |
+
$meta = FeedWordPress::notes_to_settings($result->link_notes);
|
185 |
$ret = $meta[$key];
|
186 |
endif; /* if */
|
187 |
return $ret;
|
194 |
echo get_syndication_permalink();
|
195 |
}
|
196 |
|
197 |
+
################################################################################
|
198 |
+
## FILTERS: syndication-aware handling of post data for templates and feeds ####
|
199 |
+
################################################################################
|
200 |
+
|
201 |
$feedwordpress_the_syndicated_content = NULL;
|
202 |
|
203 |
function feedwordpress_preserve_syndicated_content ($text) {
|
230 |
endif;
|
231 |
} // function syndication_permalink ()
|
232 |
|
233 |
+
################################################################################
|
234 |
+
## UPGRADE INTERFACE: Have users upgrade DB from older versions of FWP #########
|
235 |
+
################################################################################
|
236 |
+
|
237 |
+
function fwp_upgrade_page () {
|
238 |
+
if (isset($_POST['action']) and $_POST['action']=='Upgrade') :
|
239 |
+
$ver = get_settings('feedwordpress_version');
|
240 |
+
if (get_settings('feedwordpress_version') != FEEDWORDPRESS_VERSION) :
|
241 |
+
echo "<div class=\"wrap\">\n";
|
242 |
+
echo "<h2>Upgrading FeedWordPress...</h2>";
|
243 |
+
|
244 |
+
$feedwordpress =& new FeedWordPress;
|
245 |
+
$feedwordpress->upgrade_database();
|
246 |
+
echo "<p><strong>Done!</strong> Upgraded database to version ".FEEDWORDPRESS_VERSION.".</p>\n";
|
247 |
+
echo "<form action=\"\" method=\"get\">\n";
|
248 |
+
echo "<div class=\"submit\"><input type=\"hidden\" name=\"page\" value=\"".basename(__FILE__)."\" />";
|
249 |
+
echo "<input type=\"submit\" value=\"Continue »\" /></form></div>\n";
|
250 |
+
echo "</div>\n";
|
251 |
+
return;
|
252 |
+
else :
|
253 |
+
echo "<div class=\"updated\"><p>Already at version ".FEEDWORDPRESS_VERSION."!</p></div>";
|
254 |
+
endif;
|
255 |
+
endif;
|
256 |
+
?>
|
257 |
+
<div class="wrap">
|
258 |
+
<h2>Upgrade FeedWordPress</h2>
|
259 |
+
|
260 |
+
<p>It appears that you have installed FeedWordPress
|
261 |
+
<?=FEEDWORDPRESS_VERSION?> as an upgrade to an existing installation of
|
262 |
+
FeedWordPress. That's no problem, but you will need to take a minute out first
|
263 |
+
to upgrade your database: some necessarily changes in how the software keeps
|
264 |
+
track of posts and feeds will cause problems such as duplicate posts and broken
|
265 |
+
templates if we were to continue without the upgrade.</p>
|
266 |
+
|
267 |
+
<p>Note that most of FeedWordPress's functionality is temporarily disabled
|
268 |
+
until we have successfully completed the upgrade. Everything should begin
|
269 |
+
working as normal again once the upgrade is complete. There's extraordinarily
|
270 |
+
little chance of any damage as the result of the upgrade, but if you're paranoid
|
271 |
+
like me you may want to back up your database before you proceed.</p>
|
272 |
+
|
273 |
+
<p>This may take several minutes for a large installation.</p>
|
274 |
+
|
275 |
+
<form action="" method="post">
|
276 |
+
<div class="submit"><input type="submit" name="action" value="Upgrade" /></div>
|
277 |
+
</form>
|
278 |
+
</div>
|
279 |
+
<?php
|
280 |
+
} // function fwp_upgrade_page ()
|
281 |
+
|
282 |
+
################################################################################
|
283 |
+
## ADMIN MENU ADD-ONS: implement Dashboard management pages ####################
|
284 |
+
################################################################################
|
285 |
+
|
286 |
function fwp_add_pages () {
|
287 |
add_submenu_page('link-manager.php', 'Syndicated Sites', 'Syndicated', 5, basename(__FILE__), 'fwp_syndication_manage_page');
|
288 |
add_options_page('Syndication Options', 'Syndication', 6, basename(__FILE__), 'fwp_syndication_options_page');
|
291 |
function fwp_syndication_options_page () {
|
292 |
global $wpdb, $user_level;
|
293 |
|
294 |
+
if ($GLOBALS['feedwordpress_needs_upgrade']) :
|
295 |
+
fwp_upgrade_page();
|
296 |
+
return;
|
297 |
+
endif;
|
298 |
+
|
299 |
$caption = 'Save Changes';
|
300 |
+
if (isset($_POST['action']) and $_POST['action']==$caption):
|
301 |
check_admin_referer();
|
302 |
|
303 |
if ($user_level < 6):
|
311 |
update_option('feedwordpress_unfamiliar_category', $_REQUEST['unfamiliar_category']);
|
312 |
update_option('feedwordpress_syndicated_post_status', $_REQUEST['post_status']);
|
313 |
|
314 |
+
// Categories
|
315 |
+
$cats = array();
|
316 |
+
if (isset($_POST['post_category'])) :
|
317 |
+
$cat_set = "(".implode(",", $_POST['post_category']).")";
|
318 |
+
$cats = $wpdb->get_col(
|
319 |
+
"SELECT cat_name
|
320 |
+
FROM $wpdb->categories
|
321 |
+
WHERE cat_ID IN {$cat_set}
|
322 |
+
");
|
323 |
+
endif;
|
324 |
+
|
325 |
+
if (!empty($cats)) :
|
326 |
+
update_option('feedwordpress_syndication_cats', implode("\n", $cats));
|
327 |
+
else :
|
328 |
+
delete_option('feedwordpress_syndication_cats');
|
329 |
+
endif;
|
330 |
+
|
331 |
if (isset($_REQUEST['comment_status']) and ($_REQUEST['comment_status'] == 'open')) :
|
332 |
update_option('feedwordpress_syndicated_comment_status', 'open');
|
333 |
else :
|
389 |
$unfamiliar_category[$uc] = ' checked="checked"';
|
390 |
endif;
|
391 |
$results = $wpdb->get_results("SELECT cat_id, cat_name, auto_toggle FROM $wpdb->linkcategories ORDER BY cat_id");
|
392 |
+
|
393 |
+
$cats = get_settings('feedwordpress_syndication_cats');
|
394 |
+
$dogs = get_nested_categories(-1, 0);
|
395 |
+
$cats = array_map('strtolower',
|
396 |
+
array_map('trim',
|
397 |
+
preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $cats)
|
398 |
+
));
|
399 |
+
|
400 |
+
foreach ($dogs as $tag => $dog) :
|
401 |
+
if (in_array(strtolower(trim($dog['cat_name'])), $cats)) :
|
402 |
+
$dogs[$tag]['checked'] = true;
|
403 |
+
endif;
|
404 |
+
endforeach;
|
405 |
+
|
406 |
?>
|
407 |
<div class="wrap">
|
408 |
<h2>Syndication Options</h2>
|
437 |
</fieldset>
|
438 |
|
439 |
<fieldset class="options">
|
440 |
+
<legend>Syndicated Posts</legend>
|
|
|
|
|
|
|
|
|
|
|
|
|
441 |
|
442 |
+
<fieldset id="categorydiv" style="width: 20%; margin-right: 2em">
|
443 |
+
<legend>Categories</legend>
|
444 |
+
<p style="font-size:smaller;font-style:bold;margin:0">Place <em>all syndicated
|
445 |
+
posts</em> under...</p>
|
446 |
+
<div style="height: 20em"><?php write_nested_categories($dogs); ?></div>
|
447 |
+
</fieldset>
|
448 |
+
|
449 |
+
<table class="editform" width="75%" cellspacing="2" cellpadding="5">
|
450 |
+
<tr style="vertical-align: top"><th width="33%" scope="row">Publication:</th>
|
451 |
+
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
452 |
<li><label><input type="radio" name="post_status" value="publish"<?=($post_status=='publish')?' checked="checked"':''?> /> Publish syndicated posts immediately</label></li>
|
453 |
<li><label><input type="radio" name="post_status" value="draft"<?=($post_status=='draft')?' checked="checked"':''?> /> Hold syndicated posts as drafts</label></li>
|
454 |
<li><label><input type="radio" name="post_status" value="private"<?=($post_status=='private')?' checked="checked"':''?> /> Hold syndicated posts as private posts</label></li>
|
455 |
</ul></td></tr>
|
456 |
|
457 |
+
<tr style="vertical-align: top"><th width="33%" scope="row">Comments:</th>
|
458 |
+
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
459 |
+
<li><label><input type="radio" name="comment_status" value="open"<?=($comment_status=='open')?' checked="checked"':''?> /> Allow comments on syndicated posts</label></li>
|
460 |
+
<li><label><input type="radio" name="comment_status" value="closed"<?=($comment_status!='open')?' checked="checked"':''?> /> Don't allow comments on syndicated posts</label></li>
|
461 |
</ul></td></tr>
|
462 |
|
463 |
+
<tr style="vertical-align: top"><th width="33%" scope="row">Trackback and Pingback:</th>
|
464 |
+
<td width="67%"><ul style="margin:0; padding: 0; list-style:none">
|
465 |
+
<li><label><input type="radio" name="ping_status" value="open"<?=($ping_status=='open')?' checked="checked"':''?> /> Accept pings on syndicated posts</label></li>
|
466 |
+
<li><label><input type="radio" name="ping_status" value="closed"<?=($ping_status!='open')?' checked="checked"':''?> /> Don't accept pings on syndicated posts</label></li>
|
467 |
</ul></td></tr>
|
468 |
|
469 |
+
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
470 |
+
<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
|
471 |
<li><label><input type="radio" name="unfamiliar_author" value="create"<?=$unfamiliar_author['create']?>/> create a new author account</label></li>
|
472 |
<li><label><input type="radio" name="unfamiliar_author" value="default"<?=$unfamiliar_author['default']?> /> attribute the post to the default author</label></li>
|
473 |
<li><label><input type="radio" name="unfamiliar_author" value="filter"<?=$unfamiliar_author['filter']?> /> don't syndicate the post</label></li>
|
474 |
</ul></td></tr>
|
475 |
+
<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
476 |
+
<td width="67%"><ul style="margin: 0; padding:0; list-style:none">
|
477 |
<li><label><input type="radio" name="unfamiliar_category" value="create"<?=$unfamiliar_category['create']?>/> create any categories the post is in</label></li>
|
478 |
<li><label><input type="radio" name="unfamiliar_category" value="default"<?=$unfamiliar_category['default']?>/> don't create new categories</li>
|
479 |
<li><label><input type="radio" name="unfamiliar_category" value="filter"<?=$unfamiliar_category['filter']?>/> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
|
480 |
</ul></td></tr>
|
481 |
|
482 |
+
<tr style="vertical-align: top"><th width="33%" scope="row">Permalinks point to:</th>
|
483 |
+
<td width="67%"><select name="munge_permalink" size="1">
|
484 |
+
<option value="yes"<?=($munge_permalink=='yes')?' selected="selected"':''?>>original website</option>
|
485 |
+
<option value="no"<?=($munge_permalink=='no')?' selected="selected"':''?>>this website</option>
|
486 |
</select></td></tr>
|
487 |
</table>
|
488 |
<div class="submit"><input type="submit" name="action" value="<?=$caption?>" /></div>
|
513 |
|
514 |
function fwp_syndication_manage_page () {
|
515 |
global $user_level, $wpdb;
|
516 |
+
|
517 |
+
if ($GLOBALS['feedwordpress_needs_upgrade']) :
|
518 |
+
fwp_upgrade_page();
|
519 |
+
return;
|
520 |
+
endif;
|
521 |
+
|
522 |
?>
|
523 |
<?php $cont = true;
|
524 |
if (isset($_REQUEST['action'])):
|
|
|
525 |
if ($_REQUEST['action'] == 'feedfinder') : $cont = fwp_feedfinder_page();
|
526 |
elseif ($_REQUEST['action'] == 'switchfeed') : $cont = fwp_switchfeed_page();
|
527 |
+
elseif ($_REQUEST['action'] == 'linkedit') : $cont = fwp_linkedit_page();
|
528 |
+
elseif ($_REQUEST['action'] == 'Unsubscribe from Checked' or $_REQUEST['action'] == 'Unsubscribe') : $cont = fwp_multidelete_page();
|
529 |
endif;
|
530 |
endif;
|
531 |
|
555 |
<table width="100%" cellpadding="3" cellspacing="3">
|
556 |
<tr>
|
557 |
<th width="20%"><?php _e('Name'); ?></th>
|
558 |
+
<th width="40%"><?php _e('Feed'); ?></th>
|
559 |
<th colspan="4"><?php _e('Action'); ?></th>
|
560 |
</tr>
|
561 |
|
563 |
$alt_row = !$alt_row; ?>
|
564 |
<tr<?=($alt_row?' class="alternate"':'')?>>
|
565 |
<td><a href="<?=wp_specialchars($link->link_url)?>"><?=wp_specialchars($link->link_name)?></a></td>
|
566 |
+
<?php
|
567 |
+
if (strlen($link->link_rss) > 0):
|
568 |
+
$caption='Switch Feed';
|
569 |
+
$uri_bits = parse_url($link->link_rss);
|
570 |
+
$uri_bits['host'] = preg_replace('/^www\./i', '', $uri_bits['host']);
|
571 |
+
$display_uri =
|
572 |
+
(isset($uri_bits['user'])?$uri_bits['user'].'@':'')
|
573 |
+
.(isset($uri_bits['host'])?$uri_bits['host']:'')
|
574 |
+
.(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
|
575 |
+
.(isset($uri_bits['path'])?$uri_bits['path']:'')
|
576 |
+
.(isset($uri_bits['query'])?'?'.$uri_bits['query']:'');
|
577 |
+
if (strlen($display_uri) > 32) : $display_uri = substr($display_uri, 0, 32).'…'; endif;
|
578 |
+
?>
|
579 |
+
<td>
|
580 |
+
<strong><a href="<?=$link->link_rss?>"><?=wp_specialchars($display_uri)?></a></strong></td>
|
581 |
+
<?php
|
582 |
+
else:
|
583 |
+
$caption='Find Feed';
|
584 |
+
?>
|
585 |
+
<td style="background-color:#FFFFD0"><p><strong>no
|
586 |
+
feed assigned</strong></p></td>
|
587 |
+
<?php
|
588 |
+
endif;
|
589 |
+
|
590 |
+
if (($link->user_level <= $user_level)):
|
591 |
?>
|
592 |
+
<td><a href="link-manager.php?page=<?=basename(__FILE__)?>&link_id=<?=$link->link_id?>&action=linkedit" class="edit"><?php _e('Edit')?></a></td>
|
593 |
+
<td><a href="link-manager.php?page=<?=basename(__FILE__)?>&link_id=<?=$link->link_id?>&action=feedfinder" class="edit"><?=$caption?></a></td>
|
594 |
+
<td><a href="link-manager.php?page=<?=basename(__FILE__)?>&link_id=<?=$link->link_id?>&action=Unsubscribe" class="delete"><?php _e('Unsubscribe'); ?></a></td>
|
595 |
+
<td><input type="checkbox" name="link_ids[]" value="<?=$link->link_id?>" /></td>
|
596 |
<?php
|
597 |
+
else:
|
598 |
+
echo "<td> </td><td> </td><td> </td><td> </td>\n";
|
599 |
+
endif;
|
600 |
+
echo "\n\t</tr>";
|
601 |
endforeach;
|
602 |
+
else:
|
603 |
+
?>
|
604 |
|
605 |
<p>There are no websites currently listed for syndication.</p>
|
606 |
|
611 |
<div class="wrap">
|
612 |
<h2>Manage Multiple Links</h2>
|
613 |
<div class="submit">
|
614 |
+
<input type="submit" class="delete" name="action" value="Unsubscribe from Checked" />
|
615 |
</div>
|
616 |
</div>
|
617 |
</form>
|
737 |
|
738 |
if ($result): ?>
|
739 |
<div class="updated"><p><a href="<?=$_REQUEST['feed_link']?>"><?=wp_specialchars($_REQUEST['feed_title'])?></a>
|
740 |
+
has been added as a contributing site, using the newsfeed at <<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['feed'])?></a>>.</p></div>
|
741 |
<?php else: ?>
|
742 |
<div class="updated"><p>There was a problem adding the newsfeed. [SQL: <?=wp_specialchars(mysql_error())?>]</p></div>
|
743 |
<?php endif;
|
766 |
return true; // Continue
|
767 |
}
|
768 |
|
769 |
+
function fwp_linkedit_page () {
|
770 |
+
global $wpdb, $user_level;
|
771 |
+
|
772 |
+
check_admin_referer(); // Make sure we arrived here from the Dashboard
|
773 |
+
|
774 |
+
$special_settings = array ( /* Regular expression syntax is OK here */
|
775 |
+
'cats',
|
776 |
+
'hardcode name',
|
777 |
+
'hardcode url',
|
778 |
+
'hardcode description',
|
779 |
+
'hardcode categories', /* Deprecated */
|
780 |
+
'post status',
|
781 |
+
'comment status',
|
782 |
+
'ping status',
|
783 |
+
'unfamiliar author',
|
784 |
+
'unfamliar categories',
|
785 |
+
'update/.*',
|
786 |
+
'feed/.*',
|
787 |
+
'link/.*',
|
788 |
+
);
|
789 |
+
|
790 |
+
if ($user_level < 5) :
|
791 |
+
die (__("Cheatin' uh ?"));
|
792 |
+
elseif (isset($_REQUEST['feedfinder'])) :
|
793 |
+
return fwp_feedfinder_page(); // re-route to Feed Finder page
|
794 |
+
else :
|
795 |
+
$link_id = (int) $_REQUEST['link_id'];
|
796 |
+
$row = $wpdb->get_row("
|
797 |
+
SELECT * FROM $wpdb->links WHERE link_id = $link_id
|
798 |
+
");
|
799 |
+
|
800 |
+
if ($row) :
|
801 |
+
if (isset($_POST['save'])) :
|
802 |
+
$alter = array ();
|
803 |
+
|
804 |
+
$meta = FeedWordPress::notes_to_settings($row->link_notes);
|
805 |
+
if (isset($meta['cats'])):
|
806 |
+
$meta['cats'] = preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $meta['cats']);
|
807 |
+
endif;
|
808 |
+
|
809 |
+
// custom feed settings first
|
810 |
+
foreach ($_POST['notes'] as $mn) :
|
811 |
+
$mn['key0'] = trim($mn['key0']);
|
812 |
+
$mn['key1'] = trim($mn['key1']);
|
813 |
+
if (preg_match("\007^(("
|
814 |
+
.implode(')|(',$special_settings)
|
815 |
+
."))$\007i",
|
816 |
+
$mn['key1'])) :
|
817 |
+
$mn['key1'] = 'user/'.$mn['key1'];
|
818 |
+
endif;
|
819 |
+
|
820 |
+
if (strlen($mn['key0']) > 0) :
|
821 |
+
unset($meta[$mn['key0']]); // out with the old
|
822 |
+
endif;
|
823 |
+
|
824 |
+
if (($mn['action']=='update') and (strlen($mn['key1']) > 0)) :
|
825 |
+
$meta[$mn['key1']] = $mn['value']; // in with the new
|
826 |
+
endif;
|
827 |
+
endforeach;
|
828 |
+
|
829 |
+
// now stuff through the web form
|
830 |
+
// hardcoded feed info
|
831 |
+
if (isset($_POST['hardcode_name'])) :
|
832 |
+
$meta['hardcode name'] = $_POST['hardcode_name'];
|
833 |
+
if (FeedWordPress::affirmative($meta, 'hardcode name')) :
|
834 |
+
$alter[] = "link_name = '".$wpdb->escape($_POST['name'])."'";
|
835 |
+
endif;
|
836 |
+
endif;
|
837 |
+
if (isset($_POST['hardcode_description'])) :
|
838 |
+
$meta['hardcode description'] = $_POST['hardcode_description'];
|
839 |
+
if (FeedWordPress::affirmative($meta, 'hardcode description')) :
|
840 |
+
$alter[] = "link_description = '".$wpdb->escape($_POST['description'])."'";
|
841 |
+
endif;
|
842 |
+
endif;
|
843 |
+
if (isset($_POST['hardcode_url'])) :
|
844 |
+
$meta['hardcode url'] = $_POST['hardcode_url'];
|
845 |
+
if (FeedWordPress::affirmative($meta, 'hardcode url')) :
|
846 |
+
$alter[] = "link_url = '".$wpdb->escape($_POST['linkurl'])."'";
|
847 |
+
endif;
|
848 |
+
endif;
|
849 |
+
|
850 |
+
// Update scheduling
|
851 |
+
if (isset($_POST['update_schedule'])) :
|
852 |
+
$meta['update/hold'] = $_POST['update_schedule'];
|
853 |
+
endif;
|
854 |
+
|
855 |
+
// Categories
|
856 |
+
if (isset($_POST['post_category'])) :
|
857 |
+
$cat_set = "(".implode(",", $_POST['post_category']).")";
|
858 |
+
$meta['cats'] = $wpdb->get_col(
|
859 |
+
"SELECT cat_name
|
860 |
+
FROM $wpdb->categories
|
861 |
+
WHERE cat_ID IN {$cat_set}
|
862 |
+
");
|
863 |
+
if (count($meta['cats']) == 0) :
|
864 |
+
unset($meta['cats']);
|
865 |
+
endif;
|
866 |
+
else :
|
867 |
+
unset($meta['cats']);
|
868 |
+
endif;
|
869 |
+
|
870 |
+
// Post status, comment status, ping status
|
871 |
+
foreach (array('post', 'comment', 'ping') as $what) :
|
872 |
+
$sfield = "feed_{$what}_status";
|
873 |
+
if (isset($_POST[$sfield])) :
|
874 |
+
if ($_POST[$sfield]=='site-default') :
|
875 |
+
unset($meta["{$what} status"]);
|
876 |
+
else :
|
877 |
+
$meta["{$what} status"] = $_POST[$sfield];
|
878 |
+
endif;
|
879 |
+
endif;
|
880 |
+
endforeach;
|
881 |
+
|
882 |
+
// Unfamiliar author, unfamiliar categories
|
883 |
+
foreach (array("author", "category") as $what) :
|
884 |
+
$sfield = "unfamiliar_{$what}";
|
885 |
+
if (isset($_POST[$sfield])) :
|
886 |
+
if ($_POST[$sfield]=='site-default') :
|
887 |
+
unset($meta["unfamiliar {$what}"]);
|
888 |
+
else :
|
889 |
+
$meta["unfamiliar {$what}"] = $_POST[$sfield];
|
890 |
+
endif;
|
891 |
+
endif;
|
892 |
+
endforeach;
|
893 |
+
|
894 |
+
if (is_array($meta['cats'])) :
|
895 |
+
$meta['cats'] = implode(FEEDWORDPRESS_CAT_SEPARATOR, $meta['cats']);
|
896 |
+
endif;
|
897 |
+
|
898 |
+
$notes = '';
|
899 |
+
foreach ($meta as $key => $value) :
|
900 |
+
$notes .= $key . ": ". addcslashes($value, "\0..\37") . "\n";
|
901 |
+
endforeach;
|
902 |
+
$alter[] = "link_notes = '".$wpdb->escape($notes)."'";
|
903 |
+
|
904 |
+
$alter_set = implode(", ", $alter);
|
905 |
+
|
906 |
+
// issue update query
|
907 |
+
$result = $wpdb->query("
|
908 |
+
UPDATE $wpdb->links
|
909 |
+
SET $alter_set
|
910 |
+
WHERE link_id='$link_id'
|
911 |
+
");
|
912 |
+
$updated_link = true;
|
913 |
+
|
914 |
+
// reload link information from DB
|
915 |
+
$row = $wpdb->get_row("
|
916 |
+
SELECT * FROM $wpdb->links WHERE link_id = $link_id
|
917 |
+
");
|
918 |
+
else :
|
919 |
+
$updated_link = false;
|
920 |
+
endif;
|
921 |
+
|
922 |
+
$link_url = wp_specialchars($row->link_url, 1);
|
923 |
+
$link_name = wp_specialchars($row->link_name, 1);
|
924 |
+
$link_image = $row->link_image;
|
925 |
+
$link_target = $row->link_target;
|
926 |
+
$link_category = $row->link_category;
|
927 |
+
$link_description = wp_specialchars($row->link_description);
|
928 |
+
$link_visible = $row->link_visible;
|
929 |
+
$link_rating = $row->link_rating;
|
930 |
+
$link_rel = $row->link_rel;
|
931 |
+
$link_notes = wp_specialchars($row->link_notes);
|
932 |
+
$link_rss_uri = wp_specialchars($row->link_rss);
|
933 |
+
|
934 |
+
$meta = FeedWordPress::notes_to_settings($row->link_notes);
|
935 |
+
|
936 |
+
$status['post'] = array('publish' => '', 'private' => '', 'draft' => '', 'site-default' => '');
|
937 |
+
$status['comment'] = array('open' => '', 'closed' => '', 'site-default' => '');
|
938 |
+
$status['ping'] = array('open' => '', 'closed' => '', 'site-default' => '');
|
939 |
+
|
940 |
+
foreach (array('post', 'comment', 'ping') as $what) :
|
941 |
+
if (isset($meta["{$what} status"])) :
|
942 |
+
$status[$what][$meta["{$what} status"]] = ' checked="checked"';
|
943 |
+
else :
|
944 |
+
$status[$what]['site-default'] = ' checked="checked"';
|
945 |
+
endif;
|
946 |
+
endforeach;
|
947 |
+
|
948 |
+
$unfamiliar['author'] = array ('create' => '','default' => '','filter' => '');
|
949 |
+
$unfamiliar['category'] = array ('create'=>'','default'=>'','filter'=>'');
|
950 |
+
|
951 |
+
foreach (array('author', 'category') as $what) :
|
952 |
+
if (is_string($meta["unfamiliar {$what}"]) and
|
953 |
+
array_key_exists($meta["unfamiliar {$what}"], $unfamiliar[$what])) :
|
954 |
+
$key = $meta["unfamiliar {$what}"];
|
955 |
+
else:
|
956 |
+
$key = 'site-default';
|
957 |
+
endif;
|
958 |
+
$unfamiliar[$what][$key] = ' checked="checked"';
|
959 |
+
endforeach;
|
960 |
+
|
961 |
+
$dogs = get_nested_categories(-1, 0);
|
962 |
+
$cats = array_map('strtolower',
|
963 |
+
array_map('trim',
|
964 |
+
preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $meta['cats'])
|
965 |
+
));
|
966 |
+
|
967 |
+
foreach ($dogs as $tag => $dog) :
|
968 |
+
if (in_array(strtolower(trim($dog['cat_name'])), $cats)) :
|
969 |
+
$dogs[$tag]['checked'] = true;
|
970 |
+
endif;
|
971 |
+
endforeach;
|
972 |
+
else :
|
973 |
+
die( __('Link not found.') );
|
974 |
+
endif;
|
975 |
+
|
976 |
+
?>
|
977 |
+
<script type="text/javascript">
|
978 |
+
function flip_hardcode (item) {
|
979 |
+
ed=document.getElementById('basics-'+item+'-edit');
|
980 |
+
view=document.getElementById('basics-'+item+'-view');
|
981 |
+
|
982 |
+
o = document.getElementById('basics-hardcode-'+item);
|
983 |
+
if (o.value=='yes') { ed.style.display='inline'; view.style.display='none'; }
|
984 |
+
else { ed.style.display='none'; view.style.display='inline'; }
|
985 |
+
}
|
986 |
+
</script>
|
987 |
+
|
988 |
+
<?php if ($updated_link) : ?>
|
989 |
+
<div class="updated"><p>Syndicated feed settings updated.</p></div>
|
990 |
+
<?php endif; ?>
|
991 |
+
|
992 |
+
<form action="link-manager.php?page=<?=basename(__FILE__)?>" method="post">
|
993 |
+
<div class="wrap">
|
994 |
+
<input type="hidden" name="link_id" value="<?=$link_id?>" />
|
995 |
+
<input type="hidden" name="action" value="linkedit" />
|
996 |
+
<input type="hidden" name="save" value="link" />
|
997 |
+
|
998 |
+
<h2>Edit a syndicated feed:</h2>
|
999 |
+
<fieldset><legend>Basics</legend>
|
1000 |
+
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1001 |
+
<tr>
|
1002 |
+
<th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1003 |
+
<td width="60%"><a href="<?=wp_specialchars($link_rss_uri)?>"><?=$link_rss_uri?></a>
|
1004 |
+
<a href="<?=FEEDVALIDATOR_URI?>?url=<?=urlencode($link_rss_uri)?>"
|
1005 |
+
title="Check feed <<?=wp_specialchars($link_rss_uri)?>> for validity"><img src="../wp-images/smilies/icon_arrow.gif" alt="→" /></a>
|
1006 |
+
</td>
|
1007 |
+
<td width="20%"><input type="submit" name="feedfinder" value="switch →" style="font-size:smaller" /></td>
|
1008 |
+
</tr>
|
1009 |
+
<tr>
|
1010 |
+
<th scope="row" width="20%"><?php _e('Link Name:') ?></th>
|
1011 |
+
<td width="60%"><input type="text" id="basics-name-edit" name="name"
|
1012 |
+
value="<?php echo $link_name; ?>" style="width: 95%" />
|
1013 |
+
<span id="basics-name-view"><strong><?=$link_name?></strong></span>
|
1014 |
+
</td>
|
1015 |
+
<td>
|
1016 |
+
<select id="basics-hardcode-name" onchange="flip_hardcode('name')" name="hardcode_name">
|
1017 |
+
<option value="no" <?=FeedWordPress::hardcode('name', $meta)?'':'selected="selected"'?>>update automatically</option>
|
1018 |
+
<option value="yes" <?=FeedWordPress::hardcode('name', $meta)?'selected="selected"':''?>>edit manually</option>
|
1019 |
+
</select>
|
1020 |
+
</td>
|
1021 |
+
</tr>
|
1022 |
+
<tr>
|
1023 |
+
<th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1024 |
+
<td width="60%">
|
1025 |
+
<input id="basics-description-edit" type="text" name="description" value="<?php echo $link_description; ?>" style="width: 95%" />
|
1026 |
+
<span id="basics-description-view"><strong><?=$link_description?></strong></span>
|
1027 |
+
</td>
|
1028 |
+
<td>
|
1029 |
+
<select id="basics-hardcode-description" onchange="flip_hardcode('description')"
|
1030 |
+
name="hardcode_description">
|
1031 |
+
<option value="no" <?=FeedWordPress::hardcode('description', $meta)?'':'selected="selected"'?>>update automatically</option>
|
1032 |
+
<option value="yes" <?=FeedWordPress::hardcode('description', $meta)?'selected="selected"':''?>>edit manually</option>
|
1033 |
+
</select></td>
|
1034 |
+
</tr>
|
1035 |
+
<tr>
|
1036 |
+
<th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1037 |
+
<td width="60%">
|
1038 |
+
<input id="basics-url-edit" type="text" name="linkurl" value="<?php echo $link_url; ?>" style="width: 95%;" />
|
1039 |
+
<a id="basics-url-view" href="<?=$link_url?>"><?=$link_url?></a></td>
|
1040 |
+
<td>
|
1041 |
+
<select id="basics-hardcode-url" onchange="flip_hardcode('url')" name="hardcode_url">
|
1042 |
+
<option value="no"<?=FeedWordPress::hardcode('url', $meta)?'':' selected="selected"'?>>update live from feed</option>
|
1043 |
+
<option value="yes"<?=FeedWordPress::hardcode('url', $meta)?' selected="selected"':''?>>edit manually</option>
|
1044 |
+
</select></td></tr>
|
1045 |
+
|
1046 |
+
<tr>
|
1047 |
+
<th width="20%"><?php _e('Last update') ?>:</th>
|
1048 |
+
<td colspan="2"><?php
|
1049 |
+
if (isset($meta['update/last'])) :
|
1050 |
+
echo strftime('%x %X', $meta['update/last'])." ";
|
1051 |
+
else :
|
1052 |
+
echo " none yet";
|
1053 |
+
endif;
|
1054 |
+
?></td></tr>
|
1055 |
+
<tr><th width="20%">Next update:</th>
|
1056 |
+
<td colspan="2"><?php
|
1057 |
+
$holdem = (isset($meta['update/hold']) ? $meta['update/hold'] : 'scheduled');
|
1058 |
+
?>
|
1059 |
+
<select name="update_schedule">
|
1060 |
+
<option value="scheduled"<?=($holdem=='scheduled')?' selected="selected"':''?>>update on schedule <?php
|
1061 |
+
echo " (";
|
1062 |
+
if (isset($meta['update/ttl']) and is_numeric($meta['update/ttl'])) :
|
1063 |
+
if (isset($meta['update/timed']) and $meta['update/timed']=='automatically') :
|
1064 |
+
echo 'next: ';
|
1065 |
+
$next = $meta['update/last'] + ((int) $meta['update/ttl'] * 60);
|
1066 |
+
if (strftime('%x', time()) != strftime('%x', $next)) :
|
1067 |
+
echo strftime('%x', $next)." ";
|
1068 |
+
endif;
|
1069 |
+
echo strftime('%X', $meta['update/last']+((int) $meta['update/ttl']*60));
|
1070 |
+
else :
|
1071 |
+
echo "every ".$meta['update/ttl']." minute".(($meta['update/ttl']!=1)?"s":"");
|
1072 |
+
endif;
|
1073 |
+
else:
|
1074 |
+
echo "next scheduled update";
|
1075 |
+
endif;
|
1076 |
+
echo ")";
|
1077 |
+
?></option>
|
1078 |
+
<option value="next"<?=($holdem=='next')?' selected="selected"':''?>>update ASAP</option>
|
1079 |
+
<option value="ping"<?=($holdem=='ping')?' selected="selected"':''?>>update only when pinged</option>
|
1080 |
+
</select></tr>
|
1081 |
+
</table>
|
1082 |
+
</fieldset>
|
1083 |
+
|
1084 |
+
<script type="text/javascript">
|
1085 |
+
flip_hardcode('name');
|
1086 |
+
flip_hardcode('description');
|
1087 |
+
flip_hardcode('url');
|
1088 |
+
</script>
|
1089 |
+
|
1090 |
+
<p class="submit">
|
1091 |
+
<input type="submit" name="submit" value="<?php _e('Save Changes »') ?>" />
|
1092 |
+
</p>
|
1093 |
+
|
1094 |
+
<fieldset>
|
1095 |
+
<legend>Syndicated Posts</legend>
|
1096 |
+
|
1097 |
+
<fieldset id="categorydiv" style="width: 20%; margin-right: 2em">
|
1098 |
+
<legend>Categories</legend>
|
1099 |
+
<p style="font-size:smaller;font-style:bold;margin:0">Place all syndicated posts from this feed
|
1100 |
+
under...</p>
|
1101 |
+
<div style="height: 16em"><?php write_nested_categories($dogs); ?></div>
|
1102 |
+
</fieldset>
|
1103 |
+
|
1104 |
+
<table class="editform" width="80%" cellspacing="2" cellpadding="5">
|
1105 |
+
<tr><th width="20%" scope="row" style="vertical-align:top">Publication:</th>
|
1106 |
+
<td width="80%" style="vertical-align:top"><ul style="margin:0; list-style:none">
|
1107 |
+
<li><label><input type="radio" name="feed_post_status" value="site-default"
|
1108 |
+
<?=$status['post']['site-default']?> /> Use site-wide setting from <a href="options-general.php?page=<?=basename(__FILE__)?>">Syndication Options</a>
|
1109 |
+
(currently: <strong><?=FeedWordPress::syndicated_status('post', array(), 'publish')?></strong>)</label></li>
|
1110 |
+
<li><label><input type="radio" name="feed_post_status" value="publish"
|
1111 |
+
<?=$status['post']['publish']?> /> Publish posts from this feed immediately</label></li>
|
1112 |
+
<li><label><input type="radio" name="feed_post_status" value="private"
|
1113 |
+
<?=$status['post']['private']?> /> Hold posts from this feed as private posts</label></li>
|
1114 |
+
<li><label><input type="radio" name="feed_post_status" value="draft"
|
1115 |
+
<?=$status['post']['draft']?> /> Hold posts from this feed as drafts</label></li>
|
1116 |
+
</ul></td>
|
1117 |
+
</tr>
|
1118 |
+
|
1119 |
+
<tr><th width="20%" scope="row" style="vertical-align:top">Comments:</th>
|
1120 |
+
<td width="80%"><ul style="margin:0; list-style:none">
|
1121 |
+
<li><label><input type="radio" name="feed_comment_status" value="site-default"
|
1122 |
+
<?=$status['comment']['site-default']?> /> Use site-wide setting from <a href="options-general.php?page=<?=basename(__FILE__)?>">Syndication Options</a>
|
1123 |
+
(currently: <strong><?=FeedWordPress::syndicated_status('comment', array(), 'closed')?>)</strong></label></li>
|
1124 |
+
<li><label><input type="radio" name="feed_comment_status" value="open"
|
1125 |
+
<?=$status['comment']['open']?> /> Allow comments on syndicated posts from this feed</label></li>
|
1126 |
+
<li><label><input type="radio" name="feed_comment_status" value="closed"
|
1127 |
+
<?=$status['comment']['closed']?> /> Don't allow comments on syndicated posts from this feed</label></li>
|
1128 |
+
</ul></td>
|
1129 |
+
</tr>
|
1130 |
+
|
1131 |
+
<tr><th width="20%" scope="row" style="vertical-align:top">Trackback and Pingback:</th>
|
1132 |
+
<td width="80%"><ul style="margin:0; list-style:none">
|
1133 |
+
<li><label><input type="radio" name="feed_ping_status" value="site-default"
|
1134 |
+
<?=$status['ping']['site-default']?> /> Use site-wide setting from <a href="options-general.php?page=<?=basename(__FILE__)?>">Syndication Options</a>
|
1135 |
+
(currently: <strong><?=FeedWordPress::syndicated_status('ping', array(), 'closed')?>)</strong></label></li>
|
1136 |
+
<li><label><input type="radio" name="feed_ping_status" value="open"
|
1137 |
+
<?=$status['ping']['open']?> /> Accept pings on syndicated posts from this feed</label></li>
|
1138 |
+
<li><label><input type="radio" name="feed_ping_status" value="closed"
|
1139 |
+
<?=$status['ping']['closed']?> /> Don't accept pings on syndicated posts from this feed</label></li>
|
1140 |
+
</ul></td>
|
1141 |
+
</tr>
|
1142 |
+
</table>
|
1143 |
+
</fieldset>
|
1144 |
+
|
1145 |
+
<p class="submit">
|
1146 |
+
<input type="submit" name="submit" value="<?php _e('Save Changes »') ?>" />
|
1147 |
+
</p>
|
1148 |
+
|
1149 |
+
<fieldset>
|
1150 |
+
<legend>Advanced Feed Options</legend>
|
1151 |
+
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1152 |
+
<tr>
|
1153 |
+
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
|
1154 |
+
<td width="80%"><ul style="margin: 0; list-style:none">
|
1155 |
+
<li><label><input type="radio" name="unfamiliar_author" value="site-default"<?=$unfamiliar['author']['site-default']?> /> use site-wide setting from <a href="options-general.php?page=<?=basename(__FILE__)?>">Syndication Options</a>
|
1156 |
+
(currently <strong><?=FeedWordPress::on_unfamiliar('author');?></strong>)</label></li>
|
1157 |
+
<li><label><input type="radio" name="unfamiliar_author" value="create"<?=$unfamiliar['author']['create']?>/> create a new author account</label></li>
|
1158 |
+
<li><label><input type="radio" name="unfamiliar_author" value="default"<?=$unfamiliar['author']['default']?> /> attribute the post to the default author</label></li>
|
1159 |
+
<li><label><input type="radio" name="unfamiliar_author" value="filter"<?=$unfamiliar['author']['filter']?> /> don't syndicate the post</label></li>
|
1160 |
+
</ul></td>
|
1161 |
+
</tr>
|
1162 |
+
|
1163 |
+
<tr>
|
1164 |
+
<th width="20%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
|
1165 |
+
<td width="80%"><ul style="margin: 0; list-style:none">
|
1166 |
+
<li><label><input type="radio" name="unfamiliar_category" value="site-default"<?=$unfamiliar['category']['site-default']?> /> use site-wide setting from <a href="options-general.php?page=<?=basename(__FILE__)?>">Syndication Options</a>
|
1167 |
+
(currently <strong><?=FeedWordPress::on_unfamiliar('category');?></strong>)</label></li>
|
1168 |
+
<li><label><input type="radio" name="unfamiliar_category" value="create"<?=$unfamiliar['category']['create']?> /> create any categories the post is in</label></li>
|
1169 |
+
<li><label><input type="radio" name="unfamiliar_category" value="default"<?=$unfamiliar['category']['default']?> /> don't create new categories</label></li>
|
1170 |
+
<li><label><input type="radio" name="unfamiliar_category" value="filter"<?=$unfamiliar['category']['filter']?> /> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
|
1171 |
+
</ul></td>
|
1172 |
+
</tr></table>
|
1173 |
+
</fieldset>
|
1174 |
+
|
1175 |
+
<p class="submit">
|
1176 |
+
<input type="submit" name="submit" value="<?php _e('Save Changes »') ?>" />
|
1177 |
+
</p>
|
1178 |
+
|
1179 |
+
<fieldset id="postcustom">
|
1180 |
+
<legend>Custom Settings (for use in templates)</legend>
|
1181 |
+
<div id="postcustomstuff">
|
1182 |
+
<table id="meta-list" cellpadding="3">
|
1183 |
+
<tr>
|
1184 |
+
<th>Key</th>
|
1185 |
+
<th>Value</th>
|
1186 |
+
<th>Action</th>
|
1187 |
+
</tr>
|
1188 |
+
|
1189 |
+
<?php
|
1190 |
+
$i = 0;
|
1191 |
+
foreach ($meta as $key => $value) :
|
1192 |
+
if (!preg_match("\007^((".implode(')|(', $special_settings)."))$\007i", $key)) :
|
1193 |
+
?>
|
1194 |
+
<tr style="vertical-align:top">
|
1195 |
+
<th width="30%" scope="row"><input type="hidden" name="notes[<?=$i?>][key0]" value="<?=wp_specialchars($key)?>" />
|
1196 |
+
<input id="notes-<?=$i?>-key" name="notes[<?=$i?>][key1]" value="<?=wp_specialchars($key)?>" /></th>
|
1197 |
+
<td width="60%"><textarea rows="2" cols="40" id="notes-<?=$i?>-value" name="notes[<?=$i?>][value]"><?=wp_specialchars($value)?></textarea></td>
|
1198 |
+
<td width="10%"><select name="notes[<?=$i?>][action]">
|
1199 |
+
<option value="update">save changes</option>
|
1200 |
+
<option value="delete">delete this setting</option>
|
1201 |
+
</select></td>
|
1202 |
+
</tr>
|
1203 |
+
<?php
|
1204 |
+
$i++;
|
1205 |
+
endif;
|
1206 |
+
endforeach;
|
1207 |
+
?>
|
1208 |
+
<tr>
|
1209 |
+
<th scope="row"><input type="text" size="10" name="notes[<?=$i?>][key1]" value="" /></th>
|
1210 |
+
<td><textarea name="notes[<?=$i?>][value]" rows="2" cols="40"></textarea></td>
|
1211 |
+
<td><em>add new setting...</em><input type="hidden" name="notes[<?=$i?>][action]" value="update" /></td>
|
1212 |
+
</tr>
|
1213 |
+
</table>
|
1214 |
+
</fieldset>
|
1215 |
+
|
1216 |
+
<p class="submit">
|
1217 |
+
<input type="submit" name="submit" value="<?php _e('Save Changes »') ?>" />
|
1218 |
+
</p>
|
1219 |
+
|
1220 |
+
</div>
|
1221 |
+
<?php
|
1222 |
+
endif;
|
1223 |
+
return false; // Don't continue
|
1224 |
+
}
|
1225 |
+
|
1226 |
function fwp_multidelete_page () {
|
1227 |
global $wpdb, $user_level;
|
1228 |
+
|
1229 |
+
check_admin_referer(); // Make sure the referers are kosher
|
1230 |
+
|
1231 |
+
$link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array());
|
1232 |
+
if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif;
|
1233 |
+
|
1234 |
if ($user_level < 5):
|
1235 |
die (__("Cheatin' uh ?"));
|
1236 |
+
elseif (isset($_POST['confirm']) and $_POST['confirm']=='Delete'):
|
1237 |
+
foreach ($_POST['link_action'] as $link_id => $what) :
|
1238 |
+
$do_it[$what][] = $link_id;
|
1239 |
+
endforeach;
|
|
|
|
|
1240 |
|
1241 |
+
$alter = array();
|
1242 |
+
if (count($do_it['hide']) > 0) :
|
1243 |
+
$hidem = "(".implode(', ', $do_it['hide']).")";
|
1244 |
+
$alter[] = "
|
1245 |
+
UPDATE $wpdb->links
|
1246 |
+
SET link_visible = 'N'
|
1247 |
+
WHERE link_id IN {$hidem}
|
1248 |
+
";
|
1249 |
endif;
|
1250 |
+
|
1251 |
+
if (count($do_it['nuke']) > 0) :
|
1252 |
+
$nukem = "(".implode(', ', $do_it['nuke']).")";
|
1253 |
+
|
1254 |
+
// Make a list of the items syndicated from this feed...
|
1255 |
+
$post_ids = $wpdb->get_col("
|
1256 |
+
SELECT post_id FROM $wpdb->postmeta
|
1257 |
+
WHERE meta_key = 'syndication_feed_id'
|
1258 |
+
AND meta_value IN {$nukem}
|
1259 |
+
");
|
1260 |
+
|
1261 |
+
// ... and kill them all
|
1262 |
+
if (count($post_ids) > 0) :
|
1263 |
+
foreach ($post_ids as $post_id) :
|
1264 |
+
wp_delete_post($post_id);
|
1265 |
+
endforeach;
|
1266 |
+
endif;
|
1267 |
+
|
1268 |
+
$alter[] = "
|
1269 |
+
DELETE FROM $wpdb->links
|
1270 |
+
WHERE link_id IN {$nukem}
|
1271 |
+
";
|
1272 |
+
endif;
|
1273 |
+
|
1274 |
+
if (count($do_it['delete']) > 0) :
|
1275 |
+
$deletem = "(".implode(', ', $do_it['delete']).")";
|
1276 |
+
|
1277 |
+
// Make the items syndicated from this feed appear to be locally-authored
|
1278 |
+
$alter[] = "
|
1279 |
+
DELETE FROM $wpdb->postmeta
|
1280 |
+
WHERE meta_key = 'syndication_feed_id'
|
1281 |
+
AND meta_value IN {$deletem}
|
1282 |
+
";
|
1283 |
+
|
1284 |
+
// ... and delete the links themselves.
|
1285 |
+
$alter[] = "
|
1286 |
+
DELETE FROM $wpdb->links
|
1287 |
+
WHERE link_id IN {$deletem}
|
1288 |
+
";
|
1289 |
+
endif;
|
1290 |
+
|
1291 |
+
$errs = array(); $success = array ();
|
1292 |
+
foreach ($alter as $sql) :
|
1293 |
+
$result = $wpdb->query($sql);
|
1294 |
+
if (!$result):
|
1295 |
+
$errs[] = mysql_error();
|
1296 |
+
endif;
|
1297 |
+
endforeach;
|
1298 |
+
|
1299 |
+
if (count($alter) > 0) :
|
1300 |
+
echo "<div class=\"updated\">\n";
|
1301 |
+
if (count($errs) > 0) :
|
1302 |
+
echo "There were some problems processing your ";
|
1303 |
+
echo "unsubscribe request. [SQL: ".implode('; ', $errs)."]";
|
1304 |
+
else :
|
1305 |
+
echo "Your unsubscribe request(s) have been processed.";
|
1306 |
+
endif;
|
1307 |
+
echo "</div>\n";
|
1308 |
+
endif;
|
1309 |
+
|
1310 |
+
return true; // Continue on to Syndicated Sites listing
|
1311 |
+
else :
|
1312 |
+
$targets = $wpdb->get_results("
|
1313 |
+
SELECT * FROM $wpdb->links
|
1314 |
+
WHERE link_id IN (".implode(",",$link_ids).")
|
1315 |
+
");
|
1316 |
+
?>
|
1317 |
+
<form action="link-manager.php?page=<?=basename(__FILE__)?>" method="post">
|
1318 |
+
<div class="wrap">
|
1319 |
+
<input type="hidden" name="action" value="Unsubscribe" />
|
1320 |
+
<input type="hidden" name="confirm" value="Delete" />
|
1321 |
+
|
1322 |
+
<h2>Unsubscribe from Syndicated Links:</h2>
|
1323 |
+
<?php foreach ($targets as $link) :
|
1324 |
+
$link_url = wp_specialchars($link->link_url, 1);
|
1325 |
+
$link_name = wp_specialchars($link->link_name, 1);
|
1326 |
+
$link_description = wp_specialchars($link->link_description);
|
1327 |
+
$link_rss = wp_specialchars($link->link_rss);
|
1328 |
+
$meta = FeedWordPress::notes_to_settings($link->link_notes);
|
1329 |
+
?>
|
1330 |
+
<fieldset>
|
1331 |
+
<legend><?=$link_name?></legend>
|
1332 |
+
<table class="editform" width="100%" cellspacing="2" cellpadding="5">
|
1333 |
+
<tr><th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
|
1334 |
+
<td width="80%"><a href="<?=$link_rss?>"><?=$link_rss?></a></td></tr>
|
1335 |
+
<tr><th scope="row" width="20%"><?php _e('Short description:') ?></th>
|
1336 |
+
<td width="80%"><?=$link_description?></span></td></tr>
|
1337 |
+
<tr><th width="20%" scope="row"><?php _e('Homepage:') ?></th>
|
1338 |
+
<td width="80%"><a href="<?=$link_url?>"><?=$link_url?></a></td></tr>
|
1339 |
+
<tr style="vertical-align:top"><th width="20%" scope="row">Subscription <?php _e('Options') ?>:</th>
|
1340 |
+
<td width="80%"><ul style="margin:0; padding: 0; list-style: none">
|
1341 |
+
<li><input type="radio" id="hide-<?=$link->link_id?>"
|
1342 |
+
name="link_action[<?=$link->link_id?>]" value="hide" />
|
1343 |
+
<label for="hide-<?=$link->link_id?>">Turn off the subscription for this
|
1344 |
+
syndicated link<br/><span style="font-size:smaller">(Keep the feed information
|
1345 |
+
and all the posts from this feed in the database, but don't syndicate any
|
1346 |
+
new posts from the feed.)</span></label></li>
|
1347 |
+
<li><input type="radio" id="nuke-<?=$link->link_id?>"
|
1348 |
+
name="link_action[<?=$link->link_id?>]" value="nuke" />
|
1349 |
+
<label for="nuke-<?=$link->link_id?>">Delete this syndicated link and all the
|
1350 |
+
posts that were syndicated from it</label></li>
|
1351 |
+
<li><input type="radio" id="delete-<?=$link->link_id?>"
|
1352 |
+
name="link_action[<?=$link->link_id?>]" value="delete" />
|
1353 |
+
<label for="delete-<?=$link->link_id?>">Delete this syndicated link, but
|
1354 |
+
<em>keep</em> posts that were syndicated from it (as if they were authored
|
1355 |
+
locally).</label></li>
|
1356 |
+
<li><input type="radio" id="nothing-<?=$link->link_id?>"
|
1357 |
+
name="link_action[<?=$link->link_id?>]" value="nothing" />
|
1358 |
+
<label for="nothing-<?=$link->link_id?>">Keep this feed as it is. I changed
|
1359 |
+
my mind.</label></li>
|
1360 |
+
</ul>
|
1361 |
+
</table>
|
1362 |
+
</fieldset>
|
1363 |
+
<?php endforeach; ?>
|
1364 |
+
|
1365 |
+
<div class="submit">
|
1366 |
+
<input class="delete" type="submit" name="submit" value="<?php _e('Unsubscribe from selected feeds »') ?>" />
|
1367 |
+
</div>
|
1368 |
+
</div>
|
1369 |
+
<?php
|
1370 |
+
return false; // Don't continue on to Syndicated Sites listing
|
1371 |
endif;
|
|
|
1372 |
}
|
1373 |
|
1374 |
+
################################################################################
|
1375 |
+
## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
|
1376 |
+
## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
|
1377 |
+
################################################################################
|
1378 |
+
|
1379 |
$fwp_held_ping = NULL; // NULL: not holding pings yet
|
1380 |
|
1381 |
function fwp_hold_pings () {
|
1402 |
endif;
|
1403 |
}
|
1404 |
|
1405 |
+
################################################################################
|
1406 |
+
## class FeedWordPress #########################################################
|
1407 |
+
################################################################################
|
1408 |
+
|
1409 |
+
// class FeedWordPress: handles feed updates and plugs in to the XML-RPC interface
|
1410 |
class FeedWordPress {
|
1411 |
var $strip_attrs = array (
|
1412 |
array('[a-z]+', 'style'),
|
1456 |
# like so:
|
1457 |
#
|
1458 |
# key: value
|
1459 |
+
# cats: computers\nweb
|
1460 |
# feed/key: value
|
1461 |
#
|
1462 |
# Keys that start with "feed/" are gleaned from the data supplied
|
1463 |
# by the feed itself, and will be overwritten with each update.
|
1464 |
#
|
1465 |
+
# Values have linebreak characters escaped with C-style
|
1466 |
+
# backslashes (so, for example, a newline becomes "\n").
|
1467 |
+
#
|
1468 |
+
# The value of `cats` is used as a newline-separated list of
|
1469 |
# default categories for any post coming from a particular feed.
|
1470 |
# (In the example above, any posts from this feed will be placed
|
1471 |
# in the "computers" and "web" categories--*in addition to* any
|
1481 |
if ($result): foreach ($result as $link):
|
1482 |
if (strlen($link->link_rss) > 0):
|
1483 |
$sec = FeedWordPress::notes_to_settings($link->link_notes);
|
1484 |
+
$sec['link/uri'] = $link->link_rss;
|
1485 |
+
$sec['link/name'] = $link->link_name;
|
1486 |
+
$sec['link/id'] = $link->link_id;
|
1487 |
|
1488 |
// `hardcode categories` is deprecated in favor
|
1489 |
// of `unfamiliar categories`
|
1495 |
endif;
|
1496 |
|
1497 |
if (isset($sec['cats'])):
|
1498 |
+
$sec['cats'] = preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $sec['cats']);
|
1499 |
endif;
|
|
|
1500 |
|
1501 |
$feeds[] = $sec;
|
1502 |
endif;
|
1505 |
$this->feeds = $feeds;
|
1506 |
} // FeedWordPress::FeedWordPress ()
|
1507 |
|
1508 |
+
# function notes_to_settings (): Convert WordPress Link Notes to array
|
1509 |
+
# of feed-level settings
|
1510 |
+
#
|
1511 |
+
# Arguments:
|
1512 |
+
# ----------
|
1513 |
+
# * $link_notes (string): the text from the Link Notes section of a link
|
1514 |
+
#
|
1515 |
+
# Returns:
|
1516 |
+
# --------
|
1517 |
+
# An associative array of settings stored in the Link Notes field. (For
|
1518 |
+
# the `unfamiliar authors` setting, for example, simply look up the
|
1519 |
+
# value of $meta['unfamiliar authors'], if $meta contains the value
|
1520 |
+
# returned by `notes_to_settings()`.
|
1521 |
+
#
|
1522 |
+
# Values in FeedWordPress feed settings are escaped using C-style
|
1523 |
+
# slashes. The escaped characters will already have been processed and
|
1524 |
+
# converted in the returned array.
|
1525 |
function notes_to_settings ($link_notes) {
|
1526 |
$notes = explode("\n", $link_notes);
|
1527 |
|
1539 |
return $sec;
|
1540 |
} // FeedWordPress::notes_to_settings ()
|
1541 |
|
1542 |
+
# function update (): polls for updates on one or more Contributor feeds
|
1543 |
+
#
|
1544 |
+
# Arguments:
|
1545 |
+
# ----------
|
1546 |
+
# * $uri (string): either the URI of the feed to poll, the URI of the
|
1547 |
+
# website (human-readable link) whose feed you want to poll, or a
|
1548 |
+
# "magic" tag: URI composed of the URI in the constant `RPC_MAGIC`
|
1549 |
+
# and a "secret word" set in the FeedWordPress Options.
|
1550 |
+
#
|
1551 |
+
# If the "magic" URI is used, then FeedWordPress will poll any
|
1552 |
+
# feeds that are ready for polling. It will not poll feeds that are
|
1553 |
+
# marked as "Invisible" Links (signifying that the subscription has
|
1554 |
+
# been de-activated), or feeds that are not yet stale according to
|
1555 |
+
# their TTL setting (which is either set in the feed, or else
|
1556 |
+
# set randomly within a window of 30 minutes - 2 hours).
|
1557 |
+
#
|
1558 |
+
# Returns:
|
1559 |
+
# --------
|
1560 |
+
# * Normally returns an associative array, with 'new' => the number
|
1561 |
+
# of new posts added during the update, and 'updated' => the number
|
1562 |
+
# of old posts that were updated during the update. If both numbers
|
1563 |
+
# are zero, there was no change since the last poll on that URI.
|
1564 |
+
#
|
1565 |
+
# * Returns NULL if URI it was passed was not a URI that this
|
1566 |
+
# installation of FeedWordPress syndicates (the most common cause
|
1567 |
+
# of this error is attempts to poll all feeds, lacking, or using
|
1568 |
+
# an incorrect, "secret word."
|
1569 |
+
#
|
1570 |
+
# Effects:
|
1571 |
+
# --------
|
1572 |
+
# * One or more feeds are polled for updates
|
1573 |
+
#
|
1574 |
+
# * If the feed Link does not have a hardcoded name set, its Link
|
1575 |
+
# Name is synchronized with the feed's title element
|
1576 |
+
#
|
1577 |
+
# * If the feed Link does not have a hardcoded URI set, its Link URI
|
1578 |
+
# is synchronized with the feed's human-readable link element
|
1579 |
+
#
|
1580 |
+
# * If the feed Link does not have a hardcoded description set, its
|
1581 |
+
# Link Description is synchronized with the feed's description,
|
1582 |
+
# tagline, or subtitle element.
|
1583 |
+
#
|
1584 |
+
# * The time of polling is recorded in the feed's settings, and the
|
1585 |
+
# TTL (time until the feed is next available for polling) is set
|
1586 |
+
# either from the feed (if it is supplied in the ttl or syndication
|
1587 |
+
# module elements) or else from a randomly-generated time window
|
1588 |
+
# (between 30 minutes and 2 hours).
|
1589 |
+
#
|
1590 |
+
# * New posts from the polled feed are added to the WordPress store.
|
1591 |
+
#
|
1592 |
+
# * Updates to existing posts since the last poll are mirrored in the
|
1593 |
+
# WordPress store.
|
1594 |
+
#
|
1595 |
function update ($uri) {
|
1596 |
global $wpdb;
|
1597 |
+
|
1598 |
+
$uri = trim($uri);
|
1599 |
+
|
1600 |
+
if ($GLOBALS['feedwordpress_needs_upgrade']) : // Will make duplicate posts if we don't hold off
|
1601 |
+
return NULL;
|
1602 |
+
endif;
|
1603 |
+
|
1604 |
do_action('feedwordpress_update', $uri);
|
1605 |
|
1606 |
// Secret voodoo tag: URI for updating *everything*.
|
1607 |
$secret = RPC_MAGIC.FeedWordPress::rpc_secret();
|
1608 |
|
1609 |
+
fwp_hold_pings(); // Only send out one ping for the whole to-do
|
1610 |
|
1611 |
// Loop through and check for new posts
|
1612 |
$delta = NULL;
|
1613 |
+
foreach ($this->feeds as $feed) :
|
1614 |
+
$pinged_that = in_array($uri, array($secret, $feed['link/uri'], $feed['feed/link']));
|
1615 |
+
|
1616 |
+
if ($uri != $secret) : // A site-specific ping always updates
|
1617 |
+
$timely = true;
|
1618 |
+
elseif (isset($feed['update/hold']) and ($feed['update/hold']=='ping')) :
|
1619 |
+
$timely = false;
|
1620 |
+
elseif (isset($feed['update/hold']) and ($feed['update/hold']=='next')) :
|
1621 |
+
$timely = true;
|
1622 |
+
elseif (!isset($feed['update/ttl']) or !isset($feed['update/last'])) :
|
1623 |
+
$timely = true;
|
1624 |
+
else :
|
1625 |
+
$after = ((int) $feed['update/last'])
|
1626 |
+
+((int) $feed['update/ttl'] * 60);
|
1627 |
+
$timely = (time() >= $after);
|
1628 |
+
endif;
|
1629 |
+
|
1630 |
+
if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
|
1631 |
+
$delta = array('new' => 0, 'updated' => 0); // ... don't return error condition
|
1632 |
+
endif;
|
1633 |
+
|
1634 |
+
if ($pinged_that and $timely) :
|
1635 |
do_action('feedwordpress_check_feed', array($feed));
|
1636 |
$added = $this->feed2wp($wpdb, $feed);
|
1637 |
+
if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
|
1638 |
+
if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
|
1639 |
+
endif;
|
1640 |
+
endforeach;
|
1641 |
+
|
1642 |
do_action('feedwordpress_update_complete', array($delta));
|
1643 |
+
fwp_release_pings(); // Now that we're done, send the one ping
|
1644 |
|
1645 |
return $delta;
|
1646 |
}
|
1647 |
|
1648 |
function feed2wp ($wpdb, $f) {
|
1649 |
+
$feed = fetch_rss($f['link/uri']);
|
1650 |
$new_count = array('new' => 0, 'updated' => 0);
|
1651 |
|
1652 |
$this->update_feed($wpdb, $feed->channel, $f);
|
1653 |
|
1654 |
if (is_array($feed->items)) :
|
1655 |
foreach ($feed->items as $item) :
|
1656 |
+
$post = $this->item_to_post($wpdb, $item, $feed, $f);
|
1657 |
if (!is_null($post)) :
|
1658 |
$new = $this->add_post($wpdb, $post);
|
1659 |
if ( $new !== false ) $new_count[$new]++;
|
1728 |
return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $affirmo));
|
1729 |
}
|
1730 |
|
1731 |
+
function feed_ttl ($channel) {
|
1732 |
+
if (isset($channel['ttl'])) :
|
1733 |
+
// "ttl stands for time to live. It's a number of
|
1734 |
+
// minutes that indicates how long a channel can be
|
1735 |
+
// cached before refreshing from the source."
|
1736 |
+
// <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>
|
1737 |
+
$ret = $channel['ttl'];
|
1738 |
+
elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
|
1739 |
+
$period_minutes = array (
|
1740 |
+
'hourly' => 60, /* minutes in an hour */
|
1741 |
+
'daily' => 1440, /* minutes in a day */
|
1742 |
+
'weekly' => 10080, /* minutes in a week */
|
1743 |
+
'monthly' => 43200, /* minutes in a month */
|
1744 |
+
'yearly' => 525600, /* minutes in a year */
|
1745 |
+
);
|
1746 |
+
|
1747 |
+
// "sy:updatePeriod: Describes the period over which the
|
1748 |
+
// channel format is updated. Acceptable values are:
|
1749 |
+
// hourly, daily, weekly, monthly, yearly. If omitted,
|
1750 |
+
// daily is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
|
1751 |
+
if (isset($channel['sy']['updateperiod'])) : $period = $channel['sy']['updateperiod'];
|
1752 |
+
else : $period = 'daily';
|
1753 |
+
endif;
|
1754 |
+
|
1755 |
+
// "sy:updateFrequency: Used to describe the frequency
|
1756 |
+
// of updates in relation to the update period. A
|
1757 |
+
// positive integer indicates how many times in that
|
1758 |
+
// period the channel is updated. ... If omitted a value
|
1759 |
+
// of 1 is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
|
1760 |
+
if (isset($channel['sy']['updatefrequency'])) : $freq = (int) $channel['sy']['updatefrequency'];
|
1761 |
+
else : $freq = 1;
|
1762 |
+
endif;
|
1763 |
+
|
1764 |
+
$ret = (int) ($period_minutes[$period] / $freq);
|
1765 |
+
else :
|
1766 |
+
$ret = NULL;
|
1767 |
+
endif;
|
1768 |
+
return $ret;
|
1769 |
+
}
|
1770 |
+
|
1771 |
function update_feed ($wpdb, $channel, $f) {
|
1772 |
+
$link_id = $f['link/id'];
|
1773 |
|
1774 |
if (!isset($channel['id'])) :
|
1775 |
+
$channel['id'] = $f['link/uri'];
|
1776 |
endif;
|
1777 |
|
1778 |
$update = array();
|
1793 |
endif;
|
1794 |
|
1795 |
if (is_array($f['cats'])) :
|
1796 |
+
$f['cats'] = implode(FEEDWORDPRESS_CAT_SEPARATOR, $f['cats']);
|
1797 |
endif;
|
1798 |
|
1799 |
$f = array_merge($f, $this->flatten_array($channel));
|
1800 |
+
|
1801 |
+
$f['update/last'] = time();
|
1802 |
+
$ttl = $this->feed_ttl($channel);
|
1803 |
+
if (!is_null($ttl)) :
|
1804 |
+
$f['update/ttl'] = $ttl;
|
1805 |
+
$f['update/timed'] = 'feed';
|
1806 |
+
else :
|
1807 |
+
$f['update/ttl'] = rand(30, 120); // spread over time interval for staggered updates
|
1808 |
+
$f['update/timed'] = 'automatically';
|
1809 |
+
endif;
|
1810 |
+
|
1811 |
+
if (!isset($f['update/hold']) or $f['update/hold']!='ping') :
|
1812 |
+
$f['update/hold'] = 'scheduled';
|
1813 |
+
endif;
|
1814 |
|
1815 |
# -- A few things we don't want to save in the notes
|
1816 |
+
unset($f['link/id']); unset($f['link/uri']);
|
1817 |
+
unset($f['link/name']);
|
1818 |
unset($f['hardcode categories']); // Deprecated
|
1819 |
|
1820 |
$notes = '';
|
1832 |
WHERE link_id='$link_id'
|
1833 |
");
|
1834 |
} // function FeedWordPress::update_feed ()
|
1835 |
+
|
1836 |
+
function date_created ($item) {
|
1837 |
+
if (isset($item['dc']['created'])) :
|
1838 |
+
$epoch = @parse_w3cdtf($item['dc']['created']);
|
1839 |
+
elseif (isset($item['dcterms']['created'])) :
|
1840 |
+
$epoch = @parse_w3cdtf($item['dcterms']['created']);
|
1841 |
+
elseif (isset($item['created'])): // Atom 0.3
|
1842 |
+
$epoch = @parse_w3cdtf($item['created']);
|
1843 |
+
endif;
|
1844 |
+
return $epoch;
|
1845 |
+
}
|
1846 |
+
|
1847 |
+
function guid ($item, $feed) {
|
1848 |
+
if (isset($item['id'])): // Atom 0.3 / 1.0
|
1849 |
+
$guid = $item['id'];
|
1850 |
+
elseif (isset($item['atom']['id'])) : // Namespaced Atom
|
1851 |
+
$guid = $item['atom']['id'];
|
1852 |
+
elseif (isset($item['guid'])) : // RSS 2.0
|
1853 |
+
$guid = $item['guid'];
|
1854 |
+
elseif (isset($item['dc']['identifier'])) : // yeah, right
|
1855 |
+
$guid = $item['dc']['identifier'];
|
1856 |
+
else :
|
1857 |
+
// The feed does not seem to have provided us with a
|
1858 |
+
// unique identifier, so we'll have to cobble together
|
1859 |
+
// a tag: URI that might work for us. The base of the
|
1860 |
+
// URI will be the host name of the feed source ...
|
1861 |
+
$bits = parse_url($feed['link/uri']);
|
1862 |
+
$guid = 'tag:'.$bits['host'];
|
1863 |
+
|
1864 |
+
// If we have a date of creation, then we can use that
|
1865 |
+
// to uniquely identify the item. (On the other hand, if
|
1866 |
+
// the feed producer was consicentious enough to
|
1867 |
+
// generate dates of creation, she probably also was
|
1868 |
+
// conscientious enough to generate unique identifiers.)
|
1869 |
+
if (!is_null(FeedWordPress::date_created($item))) :
|
1870 |
+
$guid .= '://post.'.date('YmdHis', FeedWordPress::date_created($item));
|
1871 |
+
|
1872 |
+
// Otherwise, use both the URI of the item, *and* the
|
1873 |
+
// item's title. We have to use both because titles are
|
1874 |
+
// often not unique, and sometimes links aren't unique
|
1875 |
+
// either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
|
1876 |
+
// some podcasts). But it's rare to have *both* the same
|
1877 |
+
// title *and* the same link for two different items. So
|
1878 |
+
// this is about the best we can do.
|
1879 |
+
else :
|
1880 |
+
$guid .= '://'.md5($item['link'].'/'.$item['title']);
|
1881 |
+
endif;
|
1882 |
+
endif;
|
1883 |
+
return $guid;
|
1884 |
+
}
|
1885 |
+
|
1886 |
// item_to_post(): convert information from a single item from an
|
1887 |
// Atom/RSS feed to a post for WordPress's database.
|
1888 |
//
|
1897 |
// add_post()). If you want plugins that have side effects on the posts
|
1898 |
// database, you should probably hook into the action
|
1899 |
// post_syndicated_item
|
1900 |
+
function item_to_post($wpdb, $item, $rss, $f) {
|
1901 |
+
$channel = $rss->channel;
|
1902 |
+
|
1903 |
$post = array();
|
1904 |
|
1905 |
// This is ugly as all hell. I'd like to use apply_filters()'s
|
1921 |
$post['post_title'] = $wpdb->escape($item['title']);
|
1922 |
|
1923 |
$post['named']['author'] = array ();
|
1924 |
+
|
1925 |
+
if (isset($item['author_name'])):
|
1926 |
+
$post['named']['author']['name'] = $item['author_name'];
|
1927 |
elseif (isset($item['dc']['creator'])):
|
1928 |
+
$post['named']['author']['name'] = $item['dc']['creator'];
|
1929 |
+
elseif (isset($item['dc']['contributor'])):
|
1930 |
$post['named']['author']['name'] = $item['dc']['contributor'];
|
1931 |
+
elseif (isset($channel['dc']['creator'])) :
|
1932 |
+
$post['named']['author']['name'] = $channel['dc']['creator'];
|
1933 |
+
elseif (isset($channel['dc']['contributor'])) :
|
1934 |
+
$post['named']['author']['name'] = $channel['dc']['contributor'];
|
1935 |
+
elseif (isset($channel['author_name'])) :
|
1936 |
+
$post['named']['author']['name'] = $channel['author_name'];
|
1937 |
+
elseif ($rss->is_rss() and isset($item['author'])) :
|
1938 |
+
// The author element in RSS is allegedly an
|
1939 |
+
// e-mail address, but lots of people don't use
|
1940 |
+
// it that way. So let's make of it what we can.
|
1941 |
+
$post['named']['author'] = parse_email_with_realname($item['author']);
|
1942 |
+
|
1943 |
+
if (!isset($post['named']['author']['name'])) :
|
1944 |
+
if (isset($post['named']['author']['email'])) :
|
1945 |
+
$post['named']['author']['name'] = $post['named']['author']['email'];
|
1946 |
+
else :
|
1947 |
+
$post['named']['author']['name'] = $channel['title'];
|
1948 |
+
endif;
|
1949 |
+
endif;
|
1950 |
+
else :
|
1951 |
$post['named']['author']['name'] = $channel['title'];
|
1952 |
endif;
|
1953 |
|
1954 |
if (isset($item['author_email'])):
|
1955 |
$post['named']['author']['email'] = $item['author_email'];
|
1956 |
+
elseif (isset($channel['author_email'])) :
|
1957 |
+
$post['named']['author']['email'] = $channel['author_email'];
|
1958 |
endif;
|
1959 |
|
1960 |
if (isset($item['author_url'])):
|
1961 |
$post['named']['author']['uri'] = $item['author_url'];
|
1962 |
+
elseif (isset($channel['author_url'])) :
|
1963 |
+
$post['named']['author']['uri'] = $item['author_url'];
|
1964 |
else:
|
1965 |
$post['named']['author']['uri'] = $channel['link'];
|
1966 |
endif;
|
1972 |
|
1973 |
# Identify content and sanitize it.
|
1974 |
# ---------------------------------
|
1975 |
+
if (isset($item['xhtml']['body'])) :
|
1976 |
+
$content = $item['xhtml']['body'];
|
1977 |
+
elseif (isset($item['xhtml']['div'])) :
|
1978 |
+
$content = $item['xhtml']['div'];
|
1979 |
+
elseif (isset($item['content']['encoded']) and $item['content']['encoded']):
|
1980 |
$content = $item['content']['encoded'];
|
1981 |
else:
|
1982 |
$content = $item['description'];
|
2038 |
# current time.
|
2039 |
if (isset($item['dc']['date'])):
|
2040 |
$post['epoch']['issued'] = parse_w3cdtf($item['dc']['date']);
|
2041 |
+
elseif (isset($item['dcterms']['issued'])) :
|
2042 |
+
$post['epoch']['issued'] = parse_w3cdtf($item['dcterms']['issued']);
|
2043 |
+
elseif (isset($item['published'])) : // Atom 1.0
|
2044 |
+
$post['epoch']['issued'] = parse_w3cdtf($item['published']);
|
2045 |
+
elseif (isset($item['issued'])): // Atom 0.3
|
2046 |
$post['epoch']['issued'] = parse_w3cdtf($item['issued']);
|
2047 |
+
elseif (isset($item['pubdate'])): // RSS 2.0
|
2048 |
$post['epoch']['issued'] = strtotime($item['pubdate']);
|
2049 |
else:
|
2050 |
$post['epoch']['issued'] = time();
|
2051 |
endif;
|
2052 |
|
2053 |
+
# And again, for the created date
|
2054 |
+
$post['epoch']['created'] = FeedWordPress::date_created($item);
|
2055 |
+
|
2056 |
# As far as I know, only atom currently has a reliable way to
|
2057 |
# specify when something was *modified* last
|
2058 |
+
if (isset($item['dc']['modified'])) : // Not really correct
|
2059 |
+
$post['epoch']['modified'] = @parse_w3cdtf($item['dc']['modified']);
|
2060 |
+
elseif (isset($item['dcterms']['modified'])) : // Dublin Core extensions
|
2061 |
+
$post['epoch']['modified'] = @parse_w3cdtf($item['dcterms']['modified']);
|
2062 |
+
elseif (isset($item['modified'])): // Atom 0.3
|
2063 |
+
$post['epoch']['modified'] = @parse_w3cdtf($item['modified']);
|
2064 |
+
elseif (isset($item['updated'])): // Atom 1.0
|
2065 |
+
$post['epoch']['modified'] = @parse_w3cdtf($item['updated']);
|
2066 |
+
else : // Fall back to issued / dc:date
|
2067 |
$post['epoch']['modified'] = $post['epoch']['issued'];
|
2068 |
endif;
|
2069 |
|
2078 |
$post['ping_status'] = FeedWordPress::syndicated_status('ping', $f, 'closed');
|
2079 |
|
2080 |
// Unique ID (hopefully a unique tag: URI); failing that, the permalink
|
2081 |
+
$post['guid'] = $wpdb->escape(FeedWordPress::guid($item, $f));
|
|
|
|
|
|
|
|
|
2082 |
|
2083 |
+
// RSS 2.0 / Atom 1.0 enclosure support
|
2084 |
+
if ( isset($item['enclosure#']) ) :
|
2085 |
+
for ($i = 1; $i <= $item['enclosure#']; $i++) :
|
2086 |
+
$eid = (($i > 1) ? "#{$id}" : "");
|
2087 |
$post['meta']['enclosure'][] =
|
2088 |
+
$item["enclosure{$eid}@url"]."\n".
|
2089 |
+
$item["enclosure{$eid}@length"]."\n".
|
2090 |
+
$item["enclosure{$eid}@type"];
|
2091 |
+
endfor;
|
2092 |
endif;
|
2093 |
|
2094 |
// In case you want to point back to the blog this was syndicated from
|
2095 |
if (isset($channel['title'])) $post['meta']['syndication_source'] = $channel['title'];
|
2096 |
if (isset($channel['link'])) $post['meta']['syndication_source_uri'] = $channel['link'];
|
2097 |
+
|
2098 |
+
// Store information on human-readable and machine-readable comment URIs
|
2099 |
+
if (isset($item['comments'])) : $post['meta']['rss:comments'] = $item['comments']; endif;
|
2100 |
+
if (isset($item['wfw']['commentrss'])) : $post['meta']['wfw:commentRSS'] = $item['wfw']['commentrss']; endif;
|
2101 |
+
|
2102 |
+
// Store information to identify the feed that this came from
|
2103 |
+
$post['meta']['syndication_feed'] = $f['link/uri'];
|
2104 |
+
$post['meta']['syndication_feed_id'] = $f['link/id'];
|
2105 |
|
2106 |
// In case you want to know the external permalink...
|
2107 |
$post['meta']['syndication_permalink'] = $item['link'];
|
2111 |
$post['named']['unfamiliar']['category'] = $f['unfamiliar categories'];
|
2112 |
|
2113 |
// Categories: start with default categories
|
2114 |
+
$fc = get_settings("feedwordpress_syndication_cats");
|
2115 |
+
if ($fc) : $post['named']['preset/category'] = explode("\n", $fc);
|
2116 |
+
else : $post['named']['preset/category'] = array();
|
2117 |
+
endif;
|
2118 |
+
$post['named']['preset/category'] = array_merge($post['named']['preset/category'], $f['cats']);
|
2119 |
|
2120 |
// Now add categories from the post, if we have 'em
|
2121 |
+
$post['named']['category'] = array();
|
2122 |
+
if ( isset($item['category#']) ) :
|
2123 |
+
for ($i = 1; $i <= $item['category#']; $i++) :
|
2124 |
+
$cat_idx = (($i > 1) ? "#{$i}" : "");
|
2125 |
+
$cat = $item["category{$cat_idx}"];
|
2126 |
+
|
2127 |
+
if ( strpos($f['link/uri'], 'del.icio.us') !== false ):
|
2128 |
$post['named']['category'] = array_merge($post['named']['category'], explode(' ', $cat));
|
2129 |
else:
|
2130 |
$post['named']['category'][] = $cat;
|
2131 |
endif;
|
2132 |
+
endfor;
|
2133 |
endif;
|
2134 |
endif;
|
2135 |
return $post;
|
2169 |
$post['named']['category'],
|
2170 |
FeedWordPress::on_unfamiliar('category', $post['named']['unfamiliar']['category'])
|
2171 |
);
|
2172 |
+
|
2173 |
+
if (is_null($post['post_category'])) : // filter mode on, no matching categories; drop the post
|
2174 |
$freshness = 0;
|
2175 |
+
else : // filter mode off or at least one match; now add on the feed and global presets
|
2176 |
+
$post['post_category'] = array_merge (
|
2177 |
+
$post['post_category'],
|
2178 |
+
$this->lookup_categories (
|
2179 |
+
$wpdb,
|
2180 |
+
$post['named']['preset/category'],
|
2181 |
+
'default'
|
2182 |
+
)
|
2183 |
+
);
|
2184 |
endif;
|
2185 |
endif;
|
2186 |
|
2272 |
do_action('edit_post', $postId);
|
2273 |
|
2274 |
$this->add_rss_meta($wpdb, $postId, $post);
|
2275 |
+
|
2276 |
do_action('update_syndicated_item', $postId);
|
2277 |
|
2278 |
$ret = 'updated';
|
2352 |
function author_to_id ($wpdb, $author, $email, $url, $unfamiliar_author = 'create') {
|
2353 |
// Never can be too careful...
|
2354 |
$nice_author = sanitize_title($author);
|
2355 |
+
$reg_author = $wpdb->escape(preg_quote($author));
|
2356 |
$author = $wpdb->escape($author);
|
2357 |
$email = $wpdb->escape($email);
|
2358 |
$url = $wpdb->escape($url);
|
2359 |
+
|
2360 |
$id = $wpdb->get_var(
|
2361 |
"SELECT ID from $wpdb->users
|
2362 |
WHERE
|
2363 |
+
TRIM(LCASE(user_login)) = TRIM(LCASE('$author')) OR
|
2364 |
+
TRIM(LCASE(user_firstname)) = TRIM(LCASE('$author')) OR
|
2365 |
+
TRIM(LCASE(user_nickname)) = TRIM(LCASE('$author')) OR
|
2366 |
+
TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author')) OR
|
2367 |
+
TRIM(LCASE(user_description)) = TRIM(LCASE('$author')) OR
|
2368 |
+
(
|
2369 |
+
LOWER(user_description)
|
2370 |
+
RLIKE CONCAT(
|
2371 |
+
'(^|\\n)a.k.a.( |\\t)*:?( |\\t)*',
|
2372 |
+
LCASE('$reg_author'),
|
2373 |
+
'( |\\t|\\r)*(\\n|\$)'
|
2374 |
+
)
|
2375 |
+
)
|
2376 |
");
|
2377 |
+
|
2378 |
if (is_null($id)) :
|
2379 |
if ($unfamiliar_author === 'create') :
|
2380 |
$wpdb->query (
|
2415 |
$cat_str = array ();
|
2416 |
$cat_aka = array ();
|
2417 |
foreach ( $cats as $c ) :
|
2418 |
+
$resc = $wpdb->escape(preg_quote($c));
|
2419 |
$esc = $wpdb->escape($c);
|
2420 |
$cat_str[] = "'$esc'";
|
2421 |
+
|
2422 |
+
$cat_aka[] = "(LOWER(category_description)
|
2423 |
+
RLIKE CONCAT('(^|\n)a.k.a.( |\t)*:?( |\t)*', LOWER('{$resc}'), '( |\t|\r)*(\n|\$)'))";
|
2424 |
endforeach;
|
2425 |
|
2426 |
$match_cat_name = 'cat_name IN ('.join(',', $cat_str).')';
|
2427 |
$match_cat_alias = join(' OR ', $cat_aka);
|
2428 |
|
|
|
|
|
|
|
|
|
|
|
2429 |
$results = $wpdb->get_results(
|
2430 |
"SELECT
|
2431 |
cat_ID,
|
2432 |
+
cat_name,
|
2433 |
+
category_description
|
2434 |
FROM $wpdb->categories
|
2435 |
WHERE ($match_cat_name) OR ($match_cat_alias)"
|
2436 |
);
|
2445 |
$cat_ids[] = $row->cat_ID;
|
2446 |
|
2447 |
// Add name to list of categories not to
|
2448 |
+
// create afresh. Normalizing case with
|
2449 |
+
// strtolower() avoids mismatches in
|
2450 |
+
// VARCHAR comparison between PHP (which
|
2451 |
+
// has case-sensitive comparisons) and
|
2452 |
+
// MySQL (which has case-insensitive
|
2453 |
+
// comparisons for the field types used
|
2454 |
+
// by WordPress)
|
2455 |
+
$found[] = strtolower(trim($row->cat_name));
|
2456 |
|
2457 |
// Add name of any aliases to list of
|
2458 |
// categories not to create afresh.
|
2459 |
if (preg_match_all('/^a.k.a. \s* :? \s* (.*\S) \s*$/mx',
|
2460 |
$row->category_description, $aka,
|
2461 |
PREG_PATTERN_ORDER)) :
|
2462 |
+
$found = array_merge (
|
2463 |
+
$found,
|
2464 |
+
array_map('strtolower',
|
2465 |
+
array_map('trim',
|
2466 |
+
$aka[1]
|
2467 |
+
))
|
2468 |
+
);
|
2469 |
endif;
|
2470 |
endforeach;
|
2471 |
endif;
|
2556 |
");
|
2557 |
return $cat_name;
|
2558 |
}
|
2559 |
+
|
2560 |
+
function upgrade_database ($from = NULL) {
|
2561 |
+
global $wpdb;
|
2562 |
+
|
2563 |
+
if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
|
2564 |
+
|
2565 |
+
switch ($from) :
|
2566 |
+
case 0.96: // account for changes to syndication custom values and guid
|
2567 |
+
echo "<p>Upgrading database from {$from} to 0.97...</p>\n";
|
2568 |
+
|
2569 |
+
$cat_id = FeedWordPress::link_category_id();
|
2570 |
+
|
2571 |
+
// Avoid duplicates
|
2572 |
+
$wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key = 'syndication_feed_id'");
|
2573 |
+
|
2574 |
+
// Look up all the link IDs
|
2575 |
+
$wpdb->query("
|
2576 |
+
CREATE TEMPORARY TABLE tmp_custom_values
|
2577 |
+
SELECT
|
2578 |
+
NULL AS meta_id,
|
2579 |
+
post_id,
|
2580 |
+
'syndication_feed_id' AS meta_key,
|
2581 |
+
link_id AS meta_value
|
2582 |
+
FROM `{$wpdb->postmeta}`, `{$wpdb->links}`
|
2583 |
+
WHERE
|
2584 |
+
meta_key='syndication_feed'
|
2585 |
+
AND meta_value=link_rss
|
2586 |
+
AND link_category = {$cat_id}
|
2587 |
+
");
|
2588 |
+
|
2589 |
+
// Now attach them to their posts
|
2590 |
+
$wpdb->query("INSERT INTO `{$wpdb->postmeta}` SELECT * FROM tmp_custom_values");
|
2591 |
+
|
2592 |
+
// And clean up after ourselves.
|
2593 |
+
$wpdb->query("DROP TABLE tmp_custom_values");
|
2594 |
+
|
2595 |
+
// Now fix the guids to avoid duplicate posts
|
2596 |
+
echo "<ul>";
|
2597 |
+
foreach ($this->feeds as $feed) :
|
2598 |
+
echo "<li>Fixing post meta-data for <cite>".$feed['link/name']."</cite> … "; flush();
|
2599 |
+
$rss = @fetch_rss($feed['link/uri']);
|
2600 |
+
if (is_array($rss->items)) :
|
2601 |
+
foreach ($rss->items as $item) :
|
2602 |
+
$guid = $wpdb->escape(FeedWordPress::guid($item, $feed)); // new GUID algorithm
|
2603 |
+
$link = $wpdb->escape($item['link']);
|
2604 |
+
|
2605 |
+
$wpdb->query("
|
2606 |
+
UPDATE `{$wpdb->posts}` SET guid='{$guid}' WHERE guid='{$link}'
|
2607 |
+
");
|
2608 |
+
endforeach;
|
2609 |
+
endif;
|
2610 |
+
echo "<strong>complete.</strong></li>\n";
|
2611 |
+
endforeach;
|
2612 |
+
echo "</ul>\n";
|
2613 |
+
|
2614 |
+
// Mark the upgrade as successful.
|
2615 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
2616 |
+
endswitch;
|
2617 |
+
echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
|
2618 |
+
} /* FeedWordPress::upgrade_database() */
|
2619 |
+
|
2620 |
} // class FeedWordPress
|
2621 |
|
2622 |
+
################################################################################
|
2623 |
+
## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
|
2624 |
+
################################################################################
|
2625 |
+
|
2626 |
function feedwordpress_xmlrpc_hook ($args = array ()) {
|
2627 |
$args['weblogUpdates.ping'] = 'feedwordpress_pong';
|
2628 |
return $args;
|
2642 |
endif;
|
2643 |
}
|
2644 |
|
2645 |
+
################################################################################
|
2646 |
+
## class FeedFinder: find likely feeds using autodetection and/or guesswork ####
|
2647 |
+
################################################################################
|
2648 |
+
|
2649 |
class FeedFinder {
|
2650 |
var $uri = NULL;
|
2651 |
var $_cache_uri = NULL;
|
2976 |
return preg_replace('/[^\x21-\x7e]/', '', $encoded);
|
2977 |
}
|
2978 |
}
|
2979 |
+
|
2980 |
+
// take your best guess at the realname and e-mail, given a string
|
2981 |
+
define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
|
2982 |
+
define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');
|
2983 |
+
define('FWP_REGEX_EMAIL_POSTFIX_NAME', "/^\s*".FWP_REGEX_EMAIL_ADDY."\s+\(".FWP_REGEX_EMAIL_NAME."\)\s*$/");
|
2984 |
+
define('FWP_REGEX_EMAIL_PREFIX_NAME', "/^\s*".FWP_REGEX_EMAIL_NAME."\s*<".FWP_REGEX_EMAIL_ADDY.">\s*$/");
|
2985 |
+
define('FWP_REGEX_EMAIL_JUST_ADDY', "/^\s*".FWP_REGEX_EMAIL_ADDY."\s*$/");
|
2986 |
+
define('FWP_REGEX_EMAIL_JUST_NAME', "/^\s*".FWP_REGEX_EMAIL_NAME."\s*$/");
|
2987 |
+
|
2988 |
+
function parse_email_with_realname ($email) {
|
2989 |
+
if (preg_match(FWP_REGEX_EMAIL_POSTFIX_NAME, $email, $matches)) :
|
2990 |
+
($ret['name'] = $matches[3]) or ($ret['name'] = $matches[2]);
|
2991 |
+
$ret['email'] = $matches[1];
|
2992 |
+
elseif (preg_match(FWP_REGEX_EMAIL_PREFIX_NAME, $email, $matches)) :
|
2993 |
+
($ret['name'] = $matches[2]) or ($ret['name'] = $matches[3]);
|
2994 |
+
$ret['email'] = $matches[4];
|
2995 |
+
elseif (preg_match(FWP_REGEX_EMAIL_JUST_ADDY, $email, $matches)) :
|
2996 |
+
$ret['name'] = NULL; $ret['email'] = $matches[1];
|
2997 |
+
elseif (preg_match(FWP_REGEX_EMAIL_JUST_NAME, $email, $matches)) :
|
2998 |
+
$ret['email'] = NULL;
|
2999 |
+
($ret['name'] = $matches[2]) or ($ret['name'] = $matches[3]);
|
3000 |
+
else :
|
3001 |
+
$ret['name'] = NULL; $ret['email'] = NULL;
|
3002 |
+
endif;
|
3003 |
+
return $ret;
|
3004 |
+
}
|
3005 |
+
|
3006 |
?>
|
wp-content/update-feeds.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
# URI: <http://projects.radgeek.com/feedwordpress>
|
6 |
# Author: Charles Johnson <technophilia@radgeek.com>
|
7 |
# License: GPL
|
8 |
-
# Version: 2005.
|
9 |
#
|
10 |
# USAGE
|
11 |
# -----
|
@@ -18,90 +18,188 @@
|
|
18 |
# <http://projects.radgeek.com/feedwordpress/install> if you need a guide
|
19 |
# for the perplexed.)
|
20 |
#
|
21 |
-
# 2.
|
|
|
|
|
|
|
|
|
22 |
#
|
23 |
-
#
|
|
|
24 |
#
|
25 |
-
#
|
26 |
#
|
27 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
#
|
29 |
# 4. If you want to update *one* of the feeds rather than *all* of them, then
|
30 |
# pass the URI and title as command-line arguments:
|
31 |
#
|
32 |
-
# $ php update-feeds.php http://
|
33 |
#
|
34 |
# or in the POST request:
|
35 |
#
|
36 |
-
# $ curl http://
|
37 |
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
# -- Don't change these unless you know what you're doing...
|
43 |
-
define ('RPC_URI', NULL); // Change this setting to ping a URI of your own devising
|
44 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/'); // update all
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
-
|
55 |
-
if (isset($_SERVER['REQUEST_URI'])) {
|
56 |
-
$rpc_secret = (isset($_REQUEST['shibboleth'])?$_REQUEST['shibboleth']:'');
|
57 |
$uri = (isset($_REQUEST['uri']) ? $_REQUEST['uri'] : RPC_MAGIC.$rpc_secret);
|
58 |
-
$blog = (isset($_REQUEST['title']) ? $_REQUEST['title'] : 'Refresh');
|
59 |
|
60 |
-
|
|
|
|
|
61 |
<html>
|
62 |
<head>
|
63 |
<title>update-feeds :: FeedWordPress</title>
|
64 |
</head>
|
65 |
|
66 |
<body>
|
67 |
-
<h1>update-feeds:
|
68 |
|
69 |
-
<p>Sending ping to <$rpc_uri>...</p>
|
70 |
-
|
71 |
-
<p>
|
72 |
EOHTML;
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
|
|
|
|
77 |
$uri = (isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : RPC_MAGIC.$rpc_secret);
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
-
$
|
82 |
-
$
|
83 |
-
|
84 |
-
if (
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
endif;
|
96 |
endif;
|
97 |
|
98 |
-
if (
|
99 |
echo <<<EOHTML
|
100 |
-
</p>
|
101 |
|
102 |
<p><a href="../wp-admin">← Return to WordPress Dashboard</a></p>
|
103 |
</body>
|
104 |
</html>
|
105 |
EOHTML;
|
106 |
-
|
107 |
?>
|
5 |
# URI: <http://projects.radgeek.com/feedwordpress>
|
6 |
# Author: Charles Johnson <technophilia@radgeek.com>
|
7 |
# License: GPL
|
8 |
+
# Version: 2005.11.06
|
9 |
#
|
10 |
# USAGE
|
11 |
# -----
|
18 |
# <http://projects.radgeek.com/feedwordpress/install> if you need a guide
|
19 |
# for the perplexed.)
|
20 |
#
|
21 |
+
# 2. If you want to manually update one or more of your feeds, you can do
|
22 |
+
# so by pointing your web browser to the URI
|
23 |
+
# <http://xyz.com/wp-content/update-feeds.php>, where `http://xyz.com/` is
|
24 |
+
# replaced by the URI to your installation of WordPress. Log in as any
|
25 |
+
# user in your WordPress database and use the form to update.
|
26 |
#
|
27 |
+
# 3. To keep content up-to-date automatically, set up a cron job to run
|
28 |
+
# update-feeds.php locally:
|
29 |
#
|
30 |
+
# cd /path/to/wordpress/wp-content ; php update-feeds.php
|
31 |
#
|
32 |
+
# where `/path/to/wordpress` is replaced by the filesystem path to your
|
33 |
+
# installation of WordPress; or, if you don't have, or don't want to use,
|
34 |
+
# command-line PHP, you can send an HTTP POST request to the appropriate
|
35 |
+
# URI:
|
36 |
+
#
|
37 |
+
# curl --user user:pass http://xyz.com/wp-content/update-feeds.php -d update=quiet
|
38 |
+
#
|
39 |
+
# `user` and `pass` should be replaced by the username and password of
|
40 |
+
# a user in your WordPress database (you can create a dummy user for
|
41 |
+
# updates if you want; that's what I do). `http://xyz.com/` should be
|
42 |
+
# replaced by the URI to your installation of WordPress.
|
43 |
+
#
|
44 |
+
# Don't be afraid to run this cron job frequently. FeedWordPress staggers
|
45 |
+
# updates over time rather than checking all of the feeds every time the
|
46 |
+
# cron job runs, so even if the cron job runs every 10 minutes, each feed
|
47 |
+
# will, on average only be polled for updates once an hour or so (or less
|
48 |
+
# frequently if the feed author requests less frequent updates using
|
49 |
+
# the RSS <ttl> element or the syndication module elements).
|
50 |
#
|
51 |
# 4. If you want to update *one* of the feeds rather than *all* of them, then
|
52 |
# pass the URI and title as command-line arguments:
|
53 |
#
|
54 |
+
# $ php update-feeds.php http://radgeek.com
|
55 |
#
|
56 |
# or in the POST request:
|
57 |
#
|
58 |
+
# $ curl --user login:password http://xyz.com/wp-content/update-feeds.php -d uri=http://www.radgeek.com\&update=quiet
|
59 |
#
|
60 |
+
// Help us to pick out errors, if any.
|
61 |
+
ini_set('error_reporting', E_ALL & ~E_NOTICE);
|
62 |
+
ini_set('display_errors', true);
|
63 |
+
define('MAGPIE_DEBUG', true);
|
64 |
+
|
65 |
+
// Are we running from a web request or from the command line?
|
66 |
+
if (!isset($_SERVER['REQUEST_URI'])) :
|
67 |
+
$update_feeds_display = 'text/plain';
|
68 |
+
$update_feeds_invoke = 'cmd';
|
69 |
+
elseif (isset($_POST['update'])) :
|
70 |
+
if ($_POST['update'] == 'quiet') :
|
71 |
+
$update_feeds_display = 'text/plain';
|
72 |
+
$update_feeds_invoke = 'post';
|
73 |
+
$update_feeds_verbose = false;
|
74 |
+
elseif ($_POST['update'] == 'verbose') :
|
75 |
+
$update_feeds_display = 'text/plain';
|
76 |
+
$update_feeds_invoke = 'post';
|
77 |
+
$update_feeds_verbose = true;
|
78 |
+
else :
|
79 |
+
$update_feeds_display = 'text/html';
|
80 |
+
$update_feeds_invoke = 'post';
|
81 |
+
endif;
|
82 |
+
else :
|
83 |
+
$update_feeds_display = 'text/html';
|
84 |
+
$update_feeds_invoke = 'get';
|
85 |
+
endif;
|
86 |
+
|
87 |
+
require_once ('../wp-blog-header.php');
|
88 |
|
89 |
+
function update_feeds_mention ($feed) {
|
90 |
+
global $update_feeds_display;
|
91 |
+
|
92 |
+
if ($update_feeds_display=='text/html') :
|
93 |
+
echo "<li>Updating <cite>".$feed['link/name']."</cite> from <<a href=\""
|
94 |
+
.$feed['link/uri']."\">".$feed['link/uri']."</a>> ...</li>\n";
|
95 |
+
else :
|
96 |
+
echo "* Updating ".$feed['link/name']." from <".$feed['link/uri']."> ...\n";
|
97 |
+
endif;
|
98 |
+
flush();
|
99 |
+
}
|
100 |
|
101 |
# -- Don't change these unless you know what you're doing...
|
|
|
102 |
define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/'); // update all
|
103 |
|
104 |
+
// Query secret word from database
|
105 |
+
$rpc_secret = get_settings('feedwordpress_rpc_secret');
|
106 |
+
|
107 |
+
header("Content-Type: {$update_feeds_display}; charset=utf-8");
|
108 |
+
|
109 |
+
# -- Are we running from an HTTP GET, HTTP POST, or from the command line?
|
110 |
+
if ($update_feeds_invoke != 'cmd') : // We're acessing this from HTTP GET or HTTP POST
|
111 |
+
// Authenticate the user, if possible ...
|
112 |
+
if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) : // try HTTP authentication
|
113 |
+
$login = $_SERVER['PHP_AUTH_USER']; $pass = $_SERVER['PHP_AUTH_PW'];
|
114 |
+
elseif (isset($_POST['log']) and isset($_POST['pwd'])) : // try POST data
|
115 |
+
$login = $_REQUEST['log']; $pass = $_REQUEST['pwd'];
|
116 |
+
endif;
|
117 |
+
|
118 |
+
if (empty($login) or empty($pass) or !wp_login($login, $pass)) :
|
119 |
+
if ($update_feeds_display=='text/html') :
|
120 |
+
auth_redirect(); // try authentication cookies; if all else fails, redirect to wp-login.php
|
121 |
+
else :
|
122 |
+
echo "update-feeds (".date('Y-m-d H:i:s')."): ERROR: Could not log in as '$login'/pass='$pass']\n";
|
123 |
+
die;
|
124 |
+
endif;
|
125 |
+
endif;
|
126 |
|
127 |
+
// Henceforward, we can proceed on the assumption that we have an authenticated user
|
|
|
|
|
128 |
$uri = (isset($_REQUEST['uri']) ? $_REQUEST['uri'] : RPC_MAGIC.$rpc_secret);
|
|
|
129 |
|
130 |
+
if ($update_feeds_display=='text/html') :
|
131 |
+
echo <<<EOHTML
|
132 |
+
<?xml version="1.0" encoding="utf-8"?>
|
133 |
<html>
|
134 |
<head>
|
135 |
<title>update-feeds :: FeedWordPress</title>
|
136 |
</head>
|
137 |
|
138 |
<body>
|
139 |
+
<h1>update-feeds: make FeedWordPress check for new syndicated content</h1>
|
140 |
|
|
|
|
|
|
|
141 |
EOHTML;
|
142 |
+
endif;
|
143 |
+
else :
|
144 |
+
// update-feeds has been invoked from the command line; no further
|
145 |
+
// authentication is necessary. (If PAM hasn't already done the
|
146 |
+
// necessary screening for you, you have bigger problems than their
|
147 |
+
// access to FeedWordPress...)
|
148 |
$uri = (isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : RPC_MAGIC.$rpc_secret);
|
149 |
+
endif;
|
150 |
+
|
151 |
+
$feedwordpress =& new FeedWordPress;
|
152 |
+
|
153 |
+
if ($update_feeds_display=='text/html' or $update_feeds_verbose) :
|
154 |
+
add_action('feedwordpress_check_feed', 'update_feeds_mention');
|
155 |
+
endif;
|
156 |
+
|
157 |
+
if ($update_feeds_display=='text/html') : // HTTP GET or HTTP POST: add some web niceties
|
158 |
+
|
159 |
+
echo "<form action=\"\" method=\"POST\">\n";
|
160 |
+
echo "<select name=\"uri\">\n";
|
161 |
+
echo "<option value=\"".RPC_MAGIC.$rpc_secret."\">All feeds</option>\n";
|
162 |
+
foreach ($feedwordpress->feeds as $feed) :
|
163 |
+
echo "<option value=\"{$feed['link/uri']}\"";
|
164 |
+
if ($feed['link/uri']==$_REQUEST['uri']) : echo ' selected="selected"'; endif;
|
165 |
+
echo ">{$feed['link/name']}</option>\n";
|
166 |
+
endforeach;
|
167 |
+
echo "</select> ";
|
168 |
+
echo "<input type=\"submit\" name=\"update\" value=\"Update\" />\n";
|
169 |
+
echo "</form>\n";
|
170 |
+
endif;
|
171 |
|
172 |
+
if ($update_feeds_invoke != 'get') : // Only do things with side-effects for HTTP POST or command line
|
173 |
+
if ($update_feeds_display == 'text/html') : echo "<ul>\n"; endif;
|
174 |
+
$delta = @$feedwordpress->update($uri);
|
175 |
+
if ($update_feeds_display == 'text/html') : echo "</ul>\n"; endif;
|
176 |
+
|
177 |
+
if (is_null($delta)) :
|
178 |
+
if ($update_feeds_invoke == 'cmd') :
|
179 |
+
$stderr = fopen('php://stderr', 'w');
|
180 |
+
fputs($stderr, "update-feeds (".date('Y-m-d H:i:s')."): ERROR: I don't syndicate <$uri>\n");
|
181 |
+
elseif ($update_feeds_display == 'text/plain') :
|
182 |
+
echo "update-feeds (".date('Y-m-d H:i:s')."): ERROR: I don't syndicate <$uri>\n";
|
183 |
+
else :
|
184 |
+
echo "<p><strong>Error:</strong> I don't syndicate <a href=\"$uri\">$uri</a></p>\n";
|
185 |
+
endif;
|
186 |
+
elseif ($update_feeds_display=='text/html' or $update_feeds_verbose) :
|
187 |
+
$mesg = array();
|
188 |
+
if (isset($delta['new'])) : $mesg[] = ' '.$delta['new'].' new posts were syndicated'; endif;
|
189 |
+
if (isset($delta['updated'])) : $mesg[] = ' '.$delta['updated'].' existing posts were updated'; endif;
|
190 |
+
if ($update_feeds_display=='text/html') : echo "<p>"; endif;
|
191 |
+
echo "Update complete.".implode(' and', $mesg);
|
192 |
+
if ($update_feeds_display=='text/html') : echo "</p>"; endif;
|
193 |
+
echo "\n"; flush();
|
194 |
endif;
|
195 |
endif;
|
196 |
|
197 |
+
if ($update_feeds_display=='text/html') : // HTTP GET or HTTP POST: close off web niceties
|
198 |
echo <<<EOHTML
|
|
|
199 |
|
200 |
<p><a href="../wp-admin">← Return to WordPress Dashboard</a></p>
|
201 |
</body>
|
202 |
</html>
|
203 |
EOHTML;
|
204 |
+
endif;
|
205 |
?>
|