PluginProbe
FeedWordPress / 0.981
FeedWordPress v0.981
trunk 0.8 0.9 0.91 0.95 0.96 0.97 0.98 0.981 0.99 0.991 0.992 0.993 2008.1030 2008.1101 2008.1105 2008.1214 2009.0612 2009.0613 2009.0618 2009.0707 2009.1111 2009.1112 2010.0127 2010.0528 All 65 releases
← All changes | wp-content/plugins/feedwordpress.php +2157 -545 0.90.981 View file →
@@ -2,17 +2,15 @@
2 2 /*
3 3 Plugin Name: FeedWordPress
4 4 Plugin URI: http://projects.radgeek.com/feedwordpress
5 5 Description: simple and flexible Atom/RSS syndication for WordPress
6 -Version: 0.9
6 +Version: 0.981
7 7 Author: Charles Johnson
8 -Author URI: http://www.radgeek.com/
8 +Author URI: http://radgeek.com/
9 +License: GPL
10 +Last modified: 2007-02-17 4:23pm EST
9 11 */
10 12
11 -# Author: Charles Johnson <technophilia@radgeek.com>
12 -# License: GPL
13 -# Last modified: 2005-03-25
14 -#
15 13 # This uses code derived from:
16 14 # - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
17 15 # - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
18 16 # - Ultra-Liberal Feed Finder by Mark Pilgrim <mark@diveintomark.org>
@@ -26,104 +24,153 @@
26 24 # contributors to put your XML-RPC URI (if WordPress is installed at
27 25 # <http://www.zyx.com/blog>, XML-RPC requests should be sent to
28 26 # <http://www.zyx.com/blog/xmlrpc.php>), or see `update-feeds.php`
29 27
30 -# -- Change these as you please
31 -define ('FEEDWORDPRESS_LOG_UPDATES', true); // Make false if you hate status updates sent to error_log()
32 -
33 28 # -- Don't change these unless you know what you're doing...
34 29 define ('RPC_MAGIC', 'tag:radgeek.com/projects/feedwordpress/');
35 -define ('FEEDWORDPRESS_VERSION', '0.9');
30 +define ('FEEDWORDPRESS_VERSION', '0.981');
36 31 define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
37 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 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
41 -require_once (ABSPATH . WPINC . '/rss-functions.php');
39 +// old & busted. For the new hotness, drop a copy of rss.php from
40 +// this archive into wp-includes/rss.php
42 41
43 -// Is this being loaded from within WordPress?
44 -if (!isset($wp_version)):
45 - echo "FeedWordPress/".FEEDWORDPRESS_VERSION.": an Atom/RSS aggregator plugin for WordPress 1.5\n";
46 - exit;
42 +if (is_readable(ABSPATH . WPINC . '/rss.php')) :
43 + require_once (ABSPATH . WPINC . '/rss.php');
44 +else :
45 + require_once (ABSPATH . WPINC . '/rss-functions.php');
47 46 endif;
48 47
49 - # Remove default WordPress auto-paragraph filter.
50 - remove_filter('the_content', 'wpautop');
51 - remove_filter('the_excerpt', 'wpautop');
52 - remove_filter('comment_text', 'wpautop');
48 +if (isset($wp_db_version) and $wp_db_version >= 3308) :
49 + require_once (ABSPATH . WPINC . '/registration-functions.php');
50 + require_once (ABSPATH . 'wp-admin/admin-db.php');
51 +endif;
53 52
54 - # What really should happen here is that we create our own ueber-filter,
55 - # to run with the highest possible priority, which would intercept
56 - # and check whether or not the post comes from off the wire, and
57 - # pre-empty any further formatting filters if it does. Then we could
58 - # leave wpautop in peace and not worry about Markdown, Textile, etc.
59 - # Sadly, WordPress 1.5 gives you no way to pre-empt downstream filters
60 - # (and no way for the furthest downstream filter to recover the original
61 - # content, either.)
53 +// Is this being loaded from within WordPress 1.5 or later?
54 +if (isset($wp_version) and $wp_version >= 1.5):
62 55
63 - # add_filter('the_content', 'feedwordpress_preempt', 10);
64 - # add_filter('the_excerpt', 'feedwordpress_preempt', 10);
65 - # add_filter('comment_text', 'feedwordpress_preempt', 30);
56 + if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
66 57
67 - add_filter('post_link', 'syndication_permalink', 1);
58 + # Syndicated items are generally received in output-ready (X)HTML and
59 + # should not be folded, crumpled, mutilated, or spindled by WordPress
60 + # formatting filters. But we don't want to interfere with filters for
61 + # any locally-authored posts, either.
62 + #
63 + # What WordPress should really have is a way for upstream filters to
64 + # stop downstream filters from running at all. Since it doesn't, and
65 + # since a downstream filter can't access the original copy of the text
66 + # that is being filtered, what we will do here is (1) save a copy of the
67 + # original text upstream, before any other filters run, and then (2)
68 + # retrieve that copy downstream, after all the other filters run, *if*
69 + # this is a syndicated post
68 70
69 - # Admin menu
70 - add_action('admin_menu', 'fwp_add_pages');
71 + add_filter('the_content', 'feedwordpress_preserve_syndicated_content', -10000);
72 + add_filter('the_content', 'feedwordpress_restore_syndicated_content', 10000);
73 +
74 + # Filter in original permalinks if the user wants that
75 + add_filter('post_link', 'syndication_permalink', 1);
76 +
77 + # Admin menu
78 + add_action('admin_menu', 'fwp_add_pages');
79 +
80 + # Inbound XML-RPC update methods
81 + add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
82 +
83 + # Outbound XML-RPC ping reform
84 + remove_action('publish_post', 'generic_ping');
85 + add_action('publish_post', 'fwp_catch_ping');
86 +
87 + # Hook in logging functions only if the logging option is ON
88 + $update_logging = get_settings('feedwordpress_update_logging');
89 + if ($update_logging == 'yes') :
90 + add_action('post_syndicated_item', 'log_feedwordpress_post', 100);
91 + add_action('update_syndicated_item', 'log_feedwordpress_update_post', 100);
92 + add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
93 + add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
94 + add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
95 + endif;
96 + else :
97 + # Hook in the menus, which will just point to the upgrade interface
98 + add_action('admin_menu', 'fwp_add_pages');
99 + endif; // if (!FeedWordPress::needs_upgrade())
100 +endif;
71 101
72 - # Inbound XML-RPC update methods
73 - add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
102 +################################################################################
103 +## LOGGING FUNCTIONS: log status updates to error_log if you want it ###########
104 +################################################################################
74 105
75 - # Outbound XML-RPC reform
76 - remove_action('publish_post', 'generic_ping');
77 - add_action('publish_post', 'fwp_catch_ping');
106 +function log_feedwordpress_post ($id) {
107 + $post = wp_get_single_post($id);
108 + error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
109 + ."'{$post->post_title}' ({$post->post_date})");
110 +}
78 111
79 -$update_logging = get_settings('feedwordpress_update_logging');
112 +function log_feedwordpress_update_post ($id) {
113 + $post = wp_get_single_post($id);
114 + error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
115 + ."'{$post->post_title}' ({$post->post_date})"
116 + ." (as of {$post->post_modified})");
117 +}
80 118
81 -# -- Logging status updates to error_log, if you want it
82 -if ($update_logging == 'yes') :
83 - add_action('post_syndicated_item', 'log_feedwordpress_post', 100);
84 - add_action('update_syndicated_item', 'log_feedwordpress_update_post', 100);
85 - add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
86 - add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
87 - add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
119 +function log_feedwordpress_update_feeds ($uri) {
120 + error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
121 +}
88 122
89 - function log_feedwordpress_post ($id) {
90 - $post = wp_get_single_post($id);
91 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
92 - ."'{$post->post_title}' ({$post->post_date})");
93 - }
123 +function log_feedwordpress_check_feed ($feed) {
124 + $uri = $feed['link/uri']; $name = $feed['link/name'];
125 + error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
126 +}
94 127
95 - function log_feedwordpress_update_post ($id) {
96 - $post = wp_get_single_post($id);
97 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
98 - ."'{$post->post_title}' ({$post->post_date})"
99 - ." (as of {$post->post_modified})");
100 - }
101 -
102 - function log_feedwordpress_update_feeds ($uri) {
103 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
104 - }
105 -
106 - function log_feedwordpress_check_feed ($feed) {
107 - $uri = $feed['url']; $name = $feed['name'];
108 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
109 - }
128 +function log_feedwordpress_update_complete ($delta) {
129 + $mesg = array();
130 + if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
131 + if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
132 + if (empty($mesg)) $mesg[] = 'nothing changed';
110 133
111 - function log_feedwordpress_update_complete ($delta) {
112 - $mesg = array();
113 - if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
114 - if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
115 - if (empty($mesg)) $mesg[] = 'nothing changed';
134 + error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
135 + .(is_null($delta) ? "Error: I don't syndicate that URI"
136 + : implode(' and ', $mesg)));
137 +}
116 138
117 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
118 - .(is_null($delta) ? "I don't syndicate <$uri>"
119 - : implode(' and ', $mesg)));
139 +################################################################################
140 +## LEGACY API: Replicate or mock up functions for legacy support purposes ######
141 +################################################################################
142 +
143 +if (!function_exists('current_user_can')) {
144 + $legacy_capability_hack = true;
145 + function current_user_can ($task) {
146 + global $user_level;
147 +
148 + $can = false;
149 +
150 + // This is **not** a full replacement for current_user_can. It
151 + // is only for checking the capabilities we care about via the
152 + // WordPress 1.5 user levels.
153 + switch ($task) {
154 + case 'manage_options':
155 + $can = ($user_level >= 6);
156 + break;
157 + case 'manage_links':
158 + $can = ($user_level >= 5);
159 + break;
160 + } /* switch */
161 + return $can;
120 162 }
121 -endif;
163 +} else {
164 + $legacy_capability_hack = false;
165 +}
122 166
123 -# -- Template functions for syndication sites
124 -function is_syndicated () { return (strlen(get_syndication_feed()) > 0); }
167 +################################################################################
168 +## TEMPLATE API: functions to make your templates syndication-aware ############
169 +################################################################################
125 170
171 +function is_syndicated () { return (strlen(get_syndication_feed_id()) > 0); }
172 +
126 173 function the_syndication_source_link () { echo get_syndication_source_link(); }
127 174 function get_syndication_source_link () { list($n) = get_post_custom_values('syndication_source_uri'); return $n; }
128 175
129 176 function get_syndication_source () { list($n) = get_post_custom_values('syndication_source'); return $n; }
@@ -131,24 +178,30 @@
131 178
132 179 function get_syndication_feed () { list($u) = get_post_custom_values('syndication_feed'); return $u; }
133 180 function the_syndication_feed () { echo get_syndication_feed (); }
134 181
182 +function get_syndication_feed_id () { list($u) = get_post_custom_values('syndication_feed_id'); return $u; }
183 +function the_syndication_feed_id () { echo get_syndication_feed_id(); }
184 +
185 +$feedwordpress_linkcache = array (); // only load links from database once
186 +
135 187 function get_feed_meta ($key) {
136 - global $wpdb;
137 - $feed = get_syndication_feed();
138 -
188 + global $wpdb, $feedwordpress_linkcache;
189 + $feed_id = get_syndication_feed_id();
190 +
139 191 $ret = NULL;
140 - if (strlen($feed) > 0):
141 - $result = $wpdb->get_var("
142 - SELECT link_notes FROM $wpdb->links
143 - WHERE link_rss = '".$wpdb->escape($feed)."'"
144 - );
145 -
146 - $notes = explode("\n", $result);
147 - foreach ($notes as $note):
148 - list($k, $v) = explode(': ', $note, 2);
149 - $meta[$k] = $v;
150 - endforeach;
192 + if (strlen($feed_id) > 0):
193 + if (isset($feedwordpress_linkcache[$feed_id])) :
194 + $result = $feedwordpress_linkcache[$feed_id];
195 + else :
196 + $result = $wpdb->get_row("
197 + SELECT * FROM $wpdb->links
198 + WHERE (link_id = '".$wpdb->escape($feed_id)."')"
199 + );
200 + $feedwordpress_linkcache[$feed_id] = $result;
201 + endif;
202 +
203 + $meta = FeedWordPress::notes_to_settings($result->link_notes);
151 204 $ret = $meta[$key];
152 205 endif; /* if */
153 206 return $ret;
154 207 }
@@ -159,9 +212,35 @@
159 212 function the_syndication_permalink () {
160 213 echo get_syndication_permalink();
161 214 }
162 215
163 -# -- Filters for templates and feeds
216 +################################################################################
217 +## FILTERS: syndication-aware handling of post data for templates and feeds ####
218 +################################################################################
219 +
220 +$feedwordpress_the_syndicated_content = NULL;
221 +
222 +function feedwordpress_preserve_syndicated_content ($text) {
223 + global $feedwordpress_the_syndicated_content;
224 +
225 + if ( is_syndicated() ) :
226 + $feedwordpress_the_syndicated_content = $text;
227 + else :
228 + $feedwordpress_the_syndicated_content = NULL;
229 + endif;
230 + return $text;
231 +}
232 +
233 +function feedwordpress_restore_syndicated_content ($text) {
234 + global $feedwordpress_the_syndicated_content;
235 +
236 + if ( !is_null($feedwordpress_the_syndicated_content) ) :
237 + $text = $feedwordpress_the_syndicated_content;
238 + endif;
239 +
240 + return $text;
241 +}
242 +
164 243 function syndication_permalink ($permalink = '') {
165 244 if (get_settings('feedwordpress_munge_permalink') != 'no'):
166 245 $uri = get_syndication_permalink();
167 246 return ((strlen($uri) > 0) ? $uri : $permalink);
@@ -169,22 +248,91 @@
169 248 return $permalink;
170 249 endif;
171 250 } // function syndication_permalink ()
172 251
173 -# -- Admin menu add-ons
252 +################################################################################
253 +## UPGRADE INTERFACE: Have users upgrade DB from older versions of FWP #########
254 +################################################################################
255 +
256 +function fwp_upgrade_page () {
257 + if (isset($_POST['action']) and $_POST['action']=='Upgrade') :
258 + $ver = get_settings('feedwordpress_version');
259 + if (get_settings('feedwordpress_version') != FEEDWORDPRESS_VERSION) :
260 + echo "<div class=\"wrap\">\n";
261 + echo "<h2>Upgrading FeedWordPress...</h2>";
262 +
263 + $feedwordpress =& new FeedWordPress;
264 + $feedwordpress->upgrade_database();
265 + echo "<p><strong>Done!</strong> Upgraded database to version ".FEEDWORDPRESS_VERSION.".</p>\n";
266 + echo "<form action=\"\" method=\"get\">\n";
267 + echo "<div class=\"submit\"><input type=\"hidden\" name=\"page\" value=\"".basename(__FILE__)."\" />";
268 + echo "<input type=\"submit\" value=\"Continue &raquo;\" /></form></div>\n";
269 + echo "</div>\n";
270 + return;
271 + else :
272 + echo "<div class=\"updated\"><p>Already at version ".FEEDWORDPRESS_VERSION."!</p></div>";
273 + endif;
274 + endif;
275 +?>
276 +<div class="wrap">
277 +<h2>Upgrade FeedWordPress</h2>
278 +
279 +<p>It appears that you have installed FeedWordPress
280 +<?php echo FEEDWORDPRESS_VERSION; ?> as an upgrade to an existing installation of
281 +FeedWordPress. That's no problem, but you will need to take a minute out first
282 +to upgrade your database: some necessary changes in how the software keeps
283 +track of posts and feeds will cause problems such as duplicate posts and broken
284 +templates if we were to continue without the upgrade.</p>
285 +
286 +<p>Note that most of FeedWordPress's functionality is temporarily disabled
287 +until we have successfully completed the upgrade. Everything should begin
288 +working as normal again once the upgrade is complete. There's extraordinarily
289 +little chance of any damage as the result of the upgrade, but if you're paranoid
290 +like me you may want to back up your database before you proceed.</p>
291 +
292 +<p>This may take several minutes for a large installation.</p>
293 +
294 +<form action="" method="post">
295 +<div class="submit"><input type="submit" name="action" value="Upgrade" /></div>
296 +</form>
297 +</div>
298 +<?php
299 +} // function fwp_upgrade_page ()
300 +
301 +################################################################################
302 +## ADMIN MENU ADD-ONS: implement Dashboard management pages ####################
303 +################################################################################
304 +
174 305 function fwp_add_pages () {
175 - add_submenu_page('link-manager.php', 'Syndicated Sites', 'Syndicated', 5, __FILE__, 'fwp_syndication_manage_page');
176 - add_options_page('Syndication', 'Syndication', 6, __FILE__, 'fwp_syndication_options_page');
306 + global $legacy_capability_hack;
307 +
308 + if ($legacy_capability_hack) :
309 + // old & busted: numeric user levels
310 + $manage_links = 5;
311 + $manage_options = 6;
312 + else :
313 + // new hotness: named capabilities
314 + $manage_links = 'manage_links';
315 + $manage_options = 'manage_options';
316 + endif;
317 +
318 + add_submenu_page('link-manager.php', 'Syndicated Sites', 'Syndicated', $manage_links, basename(__FILE__), 'fwp_syndication_manage_page');
319 + add_options_page('Syndication Options', 'Syndication', $manage_options, basename(__FILE__), 'fwp_syndication_options_page');
177 320 } // function fwp_add_pages () */
178 321
179 322 function fwp_syndication_options_page () {
180 - global $wpdb, $user_level;
323 + global $wpdb, $wp_db_version;
181 324
325 + if (FeedWordPress::needs_upgrade()) :
326 + fwp_upgrade_page();
327 + return;
328 + endif;
329 +
182 330 $caption = 'Save Changes';
183 - if (isset($_REQUEST['action']) and $_REQUEST['action']=$caption):
331 + if (isset($_POST['action']) and $_POST['action']==$caption):
184 332 check_admin_referer();
185 333
186 - if ($user_level < 6):
334 + if (!current_user_can('manage_options')):
187 335 die (__("Cheatin' uh ?"));
188 336 else:
189 337 update_option('feedwordpress_rpc_secret', $_REQUEST['rpc_secret']);
190 338 update_option('feedwordpress_cat_id', $_REQUEST['syndication_category']);
@@ -189,8 +337,58 @@
189 337 update_option('feedwordpress_rpc_secret', $_REQUEST['rpc_secret']);
190 338 update_option('feedwordpress_cat_id', $_REQUEST['syndication_category']);
191 339 update_option('feedwordpress_munge_permalink', $_REQUEST['munge_permalink']);
192 340 update_option('feedwordpress_update_logging', $_REQUEST['update_logging']);
341 + update_option('feedwordpress_unfamiliar_author', $_REQUEST['unfamiliar_author']);
342 + update_option('feedwordpress_unfamiliar_category', $_REQUEST['unfamiliar_category']);
343 + update_option('feedwordpress_syndicated_post_status', $_REQUEST['post_status']);
344 +
345 + // Categories
346 + $cats = array();
347 + if (isset($_POST['post_category'])) :
348 + $cat_set = "(".implode(",", $_POST['post_category']).")";
349 + $cats = $wpdb->get_col(
350 + "SELECT cat_name
351 + FROM $wpdb->categories
352 + WHERE cat_ID IN {$cat_set}
353 + ");
354 + endif;
355 +
356 + if (!empty($cats)) :
357 + update_option('feedwordpress_syndication_cats', implode("\n", $cats));
358 + else :
359 + delete_option('feedwordpress_syndication_cats');
360 + endif;
361 +
362 + if (isset($_REQUEST['comment_status']) and ($_REQUEST['comment_status'] == 'open')) :
363 + update_option('feedwordpress_syndicated_comment_status', 'open');
364 + else :
365 + update_option('feedwordpress_syndicated_comment_status', 'closed');
366 + endif;
367 +
368 + if (isset($_REQUEST['ping_status']) and ($_REQUEST['ping_status'] == 'open')) :
369 + update_option('feedwordpress_syndicated_ping_status', 'open');
370 + else :
371 + update_option('feedwordpress_syndicated_ping_status', 'closed');
372 + endif;
373 +
374 + if (isset($_REQUEST['hardcode_name']) and ($_REQUEST['hardcode_name'] == 'no')) :
375 + update_option('feedwordpress_hardcode_name', 'no');
376 + else :
377 + update_option('feedwordpress_hardcode_name', 'yes');
378 + endif;
379 +
380 + if (isset($_REQUEST['hardcode_description']) and ($_REQUEST['hardcode_description'] == 'no')) :
381 + update_option('feedwordpress_hardcode_description', 'no');
382 + else :
383 + update_option('feedwordpress_hardcode_description', 'yes');
384 + endif;
385 +
386 + if (isset($_REQUEST['hardcode_url']) and ($_REQUEST['hardcode_url'] == 'no')) :
387 + update_option('feedwordpress_hardcode_url', 'no');
388 + else :
389 + update_option('feedwordpress_hardcode_url', 'yes');
390 + endif;
193 391 ?>
194 392 <div class="updated">
195 393 <p><?php _e('Options saved.')?></p>
196 394 </div>
@@ -201,35 +399,61 @@
201 399 $cat_id = FeedWordPress::link_category_id();
202 400 $rpc_secret = FeedWordPress::rpc_secret();
203 401 $munge_permalink = get_settings('feedwordpress_munge_permalink');
204 402 $update_logging = get_settings('feedwordpress_update_logging');
205 - $results = $wpdb->get_results("SELECT cat_id, cat_name, auto_toggle FROM $wpdb->linkcategories ORDER BY cat_id");
403 +
404 + $hardcode_name = get_settings('feedwordpress_hardcode_name');
405 + $hardcode_description = get_settings('feedwordpress_hardcode_description');
406 + $hardcode_url = get_settings('feedwordpress_hardcode_url');
407 +
408 + $post_status = FeedWordPress::syndicated_status('post', array(), 'publish');
409 + $comment_status = FeedWordPress::syndicated_status('comment', array(), 'closed');
410 + $ping_status = FeedWordPress::syndicated_status('ping', array(), 'closed');
411 +
412 + $unfamiliar_author = array ('create' => '','default' => '','filter' => '');
413 + $ua = FeedWordPress::on_unfamiliar('author');
414 + if (is_string($ua) and array_key_exists($ua, $unfamiliar_author)) :
415 + $unfamiliar_author[$ua] = ' checked="checked"';
416 + endif;
417 + $unfamiliar_category = array ('create'=>'','default'=>'','filter'=>'');
418 + $uc = FeedWordPress::on_unfamiliar('category');
419 + if (is_string($uc) and array_key_exists($uc, $unfamiliar_category)) :
420 + $unfamiliar_category[$uc] = ' checked="checked"';
421 + endif;
422 +
423 + if (isset($wp_db_version) and $wp_db_version >= 4772) :
424 + $results = get_categories('type=link');
425 + else :
426 + $results = $wpdb->get_results("SELECT cat_id, cat_name, auto_toggle FROM $wpdb->linkcategories ORDER BY cat_id");
427 + endif;
428 +
429 + $cats = get_settings('feedwordpress_syndication_cats');
430 + $dogs = get_nested_categories(-1, 0);
431 + $cats = array_map('strtolower',
432 + array_map('trim',
433 + preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $cats)
434 + ));
435 +
436 + foreach ($dogs as $tag => $dog) :
437 + if (in_array(strtolower(trim($dog['cat_name'])), $cats)) :
438 + $dogs[$tag]['checked'] = true;
439 + endif;
440 + endforeach;
441 +
206 442 ?>
207 443 <div class="wrap">
208 444 <h2>Syndication Options</h2>
209 445 <form action="" method="post">
210 446 <fieldset class="options">
211 -<legend>Template Options</legend>
447 +<legend>Syndicated Feeds</legend>
212 448 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
213 449 <tr>
214 -<th width="33%" scope="row">Permalinks for syndicated posts point to:</th>
215 -<td width="67%"><select name="munge_permalink" size="1">
216 -<option value="yes"<?=($munge_permalink=='yes')?' selected="selected"':''?>>source website</option>
217 -<option value="no"<?=($munge_permalink=='no')?' selected="selected"':''?>>this website</option>
218 -</select></td>
219 -</tr>
220 -</table>
221 -<div class="submit"><input type="submit" name="action" value="<?=$caption?>" /></div>
222 -</fieldset>
223 -
224 -<fieldset class="options">
225 -<legend>Syndication Options</legend>
226 -<table class="editform" width="100%" cellspacing="2" cellpadding="5">
227 -<tr>
228 450 <th width="33%" scope="row">Syndicate links in category:</th>
229 451 <td width="67%"><?php
230 452 echo "\n<select name=\"syndication_category\" size=\"1\">";
231 453 foreach ($results as $row) {
454 + if (!isset($row->cat_id)) { $row->cat_id = $row->cat_ID; }
455 +
232 456 echo "\n\t<option value=\"$row->cat_id\"";
233 457 if ($row->cat_id == $cat_id)
234 458 echo " selected='selected'";
235 459 echo ">$row->cat_id: ".wp_specialchars($row->cat_name);
@@ -239,29 +463,82 @@
239 463 }
240 464 echo "\n</select>\n";
241 465 ?></td>
242 466 </tr>
467 +
468 +<tr><th width="33%" scope="row" style="vertical-align:top">Update live from feed:</th>
469 +<td width="67%"><ul style="margin:0;list-style:none">
470 +<li><input type="checkbox" name="hardcode_name" value="no"<?php echo (($hardcode_name=='yes')?'':' checked="checked"');?>/> Contributor name (feed title)</li>
471 +<li><input type="checkbox" name="hardcode_description" value="no"<?php echo (($hardcode_description=='yes')?'':' checked="checked"');?>/> Contributor description (feed tagline)</li>
472 +<li><input type="checkbox" name="hardcode_url" value="no"<?php echo (($hardcode_url=='yes')?'':' checked="checked"');?>/> Homepage (feed link)</li>
473 +</ul></td></tr>
243 474 </table>
244 -<div class="submit"><input type="submit" name="action" value="<?=$caption?>" /></div>
245 475 </fieldset>
246 476
247 477 <fieldset class="options">
478 +<legend>Syndicated Posts</legend>
479 +
480 +<?php fwp_category_box($dogs, '<em>all syndicated posts</em>'); ?>
481 +
482 +<table class="editform" width="75%" cellspacing="2" cellpadding="5">
483 +<tr style="vertical-align: top"><th width="33%" scope="row">Publication:</th>
484 +<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
485 +<li><label><input type="radio" name="post_status" value="publish"<?php echo ($post_status=='publish')?' checked="checked"':''; ?> /> Publish syndicated posts immediately</label></li>
486 +<li><label><input type="radio" name="post_status" value="draft"<?php echo ($post_status=='draft')?' checked="checked"':''; ?> /> Hold syndicated posts as drafts</label></li>
487 +<li><label><input type="radio" name="post_status" value="private"<?php echo ($post_status=='private')?' checked="checked"':''; ?> /> Hold syndicated posts as private posts</label></li>
488 +</ul></td></tr>
489 +
490 +<tr style="vertical-align: top"><th width="33%" scope="row">Comments:</th>
491 +<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
492 +<li><label><input type="radio" name="comment_status" value="open"<?php echo ($comment_status=='open')?' checked="checked"':''; ?> /> Allow comments on syndicated posts</label></li>
493 +<li><label><input type="radio" name="comment_status" value="closed"<?php echo ($comment_status!='open')?' checked="checked"':''; ?> /> Don't allow comments on syndicated posts</label></li>
494 +</ul></td></tr>
495 +
496 +<tr style="vertical-align: top"><th width="33%" scope="row">Trackback and Pingback:</th>
497 +<td width="67%"><ul style="margin:0; padding: 0; list-style:none">
498 +<li><label><input type="radio" name="ping_status" value="open"<?php echo ($ping_status=='open')?' checked="checked"':''; ?> /> Accept pings on syndicated posts</label></li>
499 +<li><label><input type="radio" name="ping_status" value="closed"<?php echo ($ping_status!='open')?' checked="checked"':''; ?> /> Don't accept pings on syndicated posts</label></li>
500 +</ul></td></tr>
501 +
502 +<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
503 +<td width="67%"><ul style="margin: 0; padding: 0; list-style:none">
504 +<li><label><input type="radio" name="unfamiliar_author" value="create"<?php echo $unfamiliar_author['create']; ?>/> create a new author account</label></li>
505 +<li><label><input type="radio" name="unfamiliar_author" value="default"<?php echo $unfamiliar_author['default']; ?> /> attribute the post to the default author</label></li>
506 +<li><label><input type="radio" name="unfamiliar_author" value="filter"<?php echo $unfamiliar_author['filter']; ?> /> don't syndicate the post</label></li>
507 +</ul></td></tr>
508 +<tr style="vertical-align: top"><th width="33%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
509 +<td width="67%"><ul style="margin: 0; padding:0; list-style:none">
510 +<li><label><input type="radio" name="unfamiliar_category" value="create"<?php echo $unfamiliar_category['create']; ?>/> create any categories the post is in</label></li>
511 +<li><label><input type="radio" name="unfamiliar_category" value="default"<?php echo $unfamiliar_category['default']; ?>/> don't create new categories</li>
512 +<li><label><input type="radio" name="unfamiliar_category" value="filter"<?php echo $unfamiliar_category['filter']; ?>/> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
513 +</ul></td></tr>
514 +
515 +<tr style="vertical-align: top"><th width="33%" scope="row">Permalinks point to:</th>
516 +<td width="67%"><select name="munge_permalink" size="1">
517 +<option value="yes"<?php echo ($munge_permalink=='yes')?' selected="selected"':''; ?>>original website</option>
518 +<option value="no"<?php echo ($munge_permalink=='no')?' selected="selected"':''; ?>>this website</option>
519 +</select></td></tr>
520 +</table>
521 +<div class="submit"><input type="submit" name="action" value="<?php echo $caption; ?>" /></div>
522 +</fieldset>
523 +
524 +<fieldset class="options">
248 525 <legend>Back-end Options</legend>
249 526 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
250 527 <tr>
251 528 <th width="33%" scope="row">XML-RPC update secret word:</th>
252 -<td width="67%"><input id="rpc_secret" name="rpc_secret" value="<?=$rpc_secret?>" />
529 +<td width="67%"><input id="rpc_secret" name="rpc_secret" value="<?php echo $rpc_secret; ?>" />
253 530 </td>
254 531 </tr>
255 532 <tr>
256 533 <th scope="row">Write update notices to PHP logs:</th>
257 534 <td><select name="update_logging" size="1">
258 -<option value="yes"<?=(($update_logging=='yes')?' selected="selected"':'')?>>yes</option>
259 -<option value="no"<?=(($update_logging!='yes')?' selected="selected"':'')?>>no</option>
535 +<option value="yes"<?php echo (($update_logging=='yes')?' selected="selected"':''); ?>>yes</option>
536 +<option value="no"<?php echo (($update_logging!='yes')?' selected="selected"':''); ?>>no</option>
260 537 </select></td>
261 538 </tr>
262 539 </table>
263 -<div class="submit"><input type="submit" name="action" value="<?=$caption?>" /></div>
540 +<div class="submit"><input type="submit" name="action" value="<?php echo $caption; ?>" /></div>
264 541 </fieldset>
265 542 </form>
266 543 </div>
267 544 <?php
@@ -266,17 +543,54 @@
266 543 </div>
267 544 <?php
268 545 }
269 546
547 +function fwp_category_box ($checked, $object) {
548 + global $wp_db_version;
549 +
550 + if (isset($wp_db_version) and $wp_db_version >= 3308) : // WordPress 2.x
551 +?>
552 + <div id="poststuff">
553 +
554 + <div id="moremeta">
555 + <div id="grabit" class="dbx-group">
556 + <fieldset id="categorydiv" class="dbx-box">
557 + <h3 class="dbx-handle"><?php _e('Categories') ?></h3>
558 + <div class="dbx-content">
559 + <p style="font-size:smaller;font-style:bold;margin:0">Place <?php print $object; ?> under...</p>
560 + <p id="jaxcat"></p>
561 + <ul id="categorychecklist"><?php write_nested_categories($checked); ?></ul></div>
562 + </fieldset>
563 + </div>
564 + </div>
565 + </div>
566 +<?php
567 + else : // WordPress 1.5
568 +?>
569 + <fieldset id="categorydiv" style="width: 20%; margin-right: 2em">
570 + <legend><?php _e('Categories') ?></legend>
571 + <p style="font-size:smaller;font-style:bold;margin:0">Place <?php print $object; ?> under...</p>
572 + <div style="height: 20em"><?php write_nested_categories($checked); ?></div>
573 + </fieldset>
574 +<?php
575 + endif;
576 +}
577 +
270 578 function fwp_syndication_manage_page () {
271 - global $user_level, $wpdb;
579 + global $wpdb;
580 +
581 + if (FeedWordPress::needs_upgrade()) :
582 + fwp_upgrade_page();
583 + return;
584 + endif;
585 +
272 586 ?>
273 587 <?php $cont = true;
274 588 if (isset($_REQUEST['action'])):
275 - //die("ACTION: '".$_REQUEST['action']."'");
276 - if ($_REQUEST['action'] == 'feedfinder'): $cont = fwp_feedfinder_page();
277 - elseif ($_REQUEST['action'] == 'switchfeed'): $cont = fwp_switchfeed_page();
278 - elseif ($_REQUEST['action'] == 'Delete Checked'): $cont = fwp_multidelete_page();
589 + if ($_REQUEST['action'] == 'feedfinder') : $cont = fwp_feedfinder_page();
590 + elseif ($_REQUEST['action'] == 'switchfeed') : $cont = fwp_switchfeed_page();
591 + elseif ($_REQUEST['action'] == 'linkedit') : $cont = fwp_linkedit_page();
592 + elseif ($_REQUEST['action'] == 'Unsubscribe from Checked' or $_REQUEST['action'] == 'Unsubscribe') : $cont = fwp_multidelete_page();
279 593 endif;
280 594 endif;
281 595
282 596 if ($cont):
@@ -281,12 +595,12 @@
281 595
282 596 if ($cont):
283 597 ?>
284 598 <?php
285 - $links = get_linkobjects(FeedWordPress::link_category_id());
599 + $links = FeedWordPress::syndicated_links();
286 600 ?>
287 601 <div class="wrap">
288 - <form action="link-manager.php?page=feedwordpress.php" method="post">
602 + <form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
289 603 <h2>Syndicate a new site:</h2>
290 604 <div>
291 605 <label for="add-uri">Website or newsfeed:</label>
292 606 <input type="text" name="lookup" id="add-uri" value="URI" size="64" />
@@ -295,9 +609,9 @@
295 609 <div class="submit"><input type="submit" value="Syndicate &raquo;" /></div>
296 610 </form>
297 611 </div>
298 612
299 - <form action="link-manager.php?page=feedwordpress.php" method="post">
613 + <form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
300 614 <div class="wrap">
301 615 <h2>Syndicated Sites</h2>
302 616 <?php $alt_row = true;
303 617 if ($links): ?>
@@ -304,41 +618,49 @@
304 618
305 619 <table width="100%" cellpadding="3" cellspacing="3">
306 620 <tr>
307 621 <th width="20%"><?php _e('Name'); ?></th>
308 -<th width="50%"><?php _e('Feed'); ?></th>
622 +<th width="40%"><?php _e('Feed'); ?></th>
309 623 <th colspan="4"><?php _e('Action'); ?></th>
310 624 </tr>
311 625
312 626 <?php foreach ($links as $link):
313 627 $alt_row = !$alt_row; ?>
314 -<tr<?=($alt_row?' class="alternate"':'')?>>
315 -<td><a href="<?=wp_specialchars($link->link_url)?>"><?=wp_specialchars($link->link_name)?></a></td>
316 -<?php if (strlen($link->link_rss) > 0): $caption='Switch Feed'; ?>
317 -<td style="font-size:smaller;text-align:center">
318 -<strong><a href="<?=$link->link_rss?>"><?=wp_specialchars($link->link_rss)?></a></strong>
319 -<em>check validity</em> <a style="vertical-align:middle"
320 -title="Check feed &lt;<?=wp_specialchars($link->link_rss)?>&gt; for validity"
321 -href="http://feedvalidator.org/check.cgi?url=<?=urlencode($link->link_rss)?>"><img
322 -src="../wp-images/smilies/icon_arrow.gif" alt="&rarr;" /></a></td>
323 -<?php else: $caption='Find Feed'; ?>
324 -<td style="background-color:#FFFFD0"><p><strong>no
325 -feed assigned</strong></p></td>
326 -<? endif; ?>
327 -<?php if (($link->user_level <= $user_level)): ?>
328 - <td><a href="link-manager.php?page=feedwordpress.php&amp;link_id=<?=$link->link_id?>&amp;action=feedfinder" class="edit"><?=$caption?></a></div></td>
329 - <td><a href="link-manager.php?link_id=<?=$link->link_id?>&amp;action=linkedit" class="edit"><?php _e('Edit')?></a></td>
330 - <td><a href="link-manager.php?link_id=<?=$link->link_id?>&amp;action=Delete" onclick="return confirm('You are about to delete this link.\\n \'Cancel\' to stop, \'OK\' to delete.');" class="delete"><?php _e('Delete'); ?></a></td>
331 - <td><input type="checkbox" name="linkcheck[]" value="<?=$link->link_id?>" /></td>
332 -<?php else:
333 - echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>\n";
334 - endif;
335 - echo "\n\t</tr>";
628 +<tr<?php echo ($alt_row?' class="alternate"':''); ?>>
629 +<td><a href="<?php echo wp_specialchars($link->link_url); ?>"><?php echo wp_specialchars($link->link_name); ?></a></td>
630 +<?php
631 + if (strlen($link->link_rss) > 0):
632 + $caption='Switch Feed';
633 + $uri_bits = parse_url($link->link_rss);
634 + $uri_bits['host'] = preg_replace('/^www\./i', '', $uri_bits['host']);
635 + $display_uri =
636 + (isset($uri_bits['user'])?$uri_bits['user'].'@':'')
637 + .(isset($uri_bits['host'])?$uri_bits['host']:'')
638 + .(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
639 + .(isset($uri_bits['path'])?$uri_bits['path']:'')
640 + .(isset($uri_bits['query'])?'?'.$uri_bits['query']:'');
641 + if (strlen($display_uri) > 32) : $display_uri = substr($display_uri, 0, 32).'&#8230;'; endif;
336 642 ?>
337 - </tr>
643 + <td>
644 + <strong><a href="<?php echo $link->link_rss; ?>"><?php echo wp_specialchars($display_uri); ?></a></strong></td>
338 645 <?php
646 + else:
647 + $caption='Find Feed';
648 +?>
649 + <td style="background-color:#FFFFD0"><p><strong>no
650 + feed assigned</strong></p></td>
651 +<?php
652 + endif;
653 +?>
654 + <td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&amp;link_id=<?php echo $link->link_id; ?>&amp;action=linkedit" class="edit"><?php _e('Edit')?></a></td>
655 + <td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&amp;link_id=<?php echo $link->link_id; ?>&amp;action=feedfinder" class="edit"><?php echo $caption; ?></a></td>
656 + <td><a href="link-manager.php?page=<?php echo basename(__FILE__); ?>&amp;link_id=<?php echo $link->link_id; ?>&amp;action=Unsubscribe" class="delete"><?php _e('Unsubscribe'); ?></a></td>
657 + <td><input type="checkbox" name="link_ids[]" value="<?php echo $link->link_id; ?>" /></td>
658 +<?php
659 + echo "\n\t</tr>";
339 660 endforeach;
340 - else: ?>
661 + else:
662 +?>
341 663
342 664 <p>There are no websites currently listed for syndication.</p>
343 665
344 666 <?php endif; ?>
@@ -347,9 +669,9 @@
347 669
348 670 <div class="wrap">
349 671 <h2>Manage Multiple Links</h2>
350 672 <div class="submit">
351 - <input type="submit" class="delete" name="action" value="Delete Checked" />
673 + <input type="submit" class="delete" name="action" value="Unsubscribe from Checked" />
352 674 </div>
353 675 </div>
354 676 </form>
355 677 <?php
@@ -356,9 +678,9 @@
356 678 endif;
357 679 }
358 680
359 681 function fwp_feedfinder_page () {
360 - global $user_level, $wpdb;
682 + global $wpdb;
361 683
362 684 $lookup = (isset($_REQUEST['lookup'])?$_REQUEST['lookup']:NULL);
363 685
364 686 if (isset($_REQUEST['link_id']) and ($_REQUEST['link_id']!=0)):
@@ -375,10 +697,11 @@
375 697 $link_id = 0;
376 698 endif;
377 699 ?>
378 700 <div class="wrap">
379 - <h2>Feed Finder: <?=$name?></h2>
380 -<?php $f =& new FeedFinder($lookup);
701 + <h2>Feed Finder: <?php echo $name; ?></h2>
702 +<?php
703 + $f =& new FeedFinder($lookup);
381 704 $feeds = $f->find();
382 705 if (count($feeds) > 0):
383 706 foreach ($feeds as $key => $f):
384 707 $rss = fetch_rss($f);
@@ -385,19 +708,19 @@
385 708 if ($rss):
386 709 $feed_title = isset($rss->channel['title'])?$rss->channel['title']:$rss->channel['link'];
387 710 $feed_link = isset($rss->channel['link'])?$rss->channel['link']:'';
388 711 ?>
389 - <form action="link-manager.php?page=feedwordpress.php" method="post">
712 + <form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
390 713 <fieldset style="clear: both">
391 - <legend><?=$rss->feed_type?> <?=$rss->feed_version?> feed</legend>
714 + <legend><?php echo $rss->feed_type; ?> <?php echo $rss->feed_version; ?> feed</legend>
392 715
393 716 <?php if ($link_id===0): ?>
394 - <input type="hidden" name="feed_title" value="<?=wp_specialchars($feed_title)?>" />
395 - <input type="hidden" name="feed_link" value="<?=wp_specialchars($feed_link)?>" />
717 + <input type="hidden" name="feed_title" value="<?php echo wp_specialchars($feed_title); ?>" />
718 + <input type="hidden" name="feed_link" value="<?php echo wp_specialchars($feed_link); ?>" />
396 719 <?php endif; ?>
397 720
398 - <input type="hidden" name="link_id" value="<?=$link_id?>" />
399 - <input type="hidden" name="feed" value="<?=wp_specialchars($f)?>" />
721 + <input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
722 + <input type="hidden" name="feed" value="<?php echo wp_specialchars($f); ?>" />
400 723 <input type="hidden" name="action" value="switchfeed" />
401 724
402 725 <div>
403 726 <div style="float:right; background-color:#D0D0D0; color: black; width:45%; font-size:70%; border-left: 1px dotted #A0A0A0; padding-left: 0.5em; margin-left: 1.0em">
@@ -404,13 +727,13 @@
404 727 <?php if (count($rss->items) > 0): ?>
405 728 <?php $item = $rss->items[0]; ?>
406 729 <h3>Sample Item</h3>
407 730 <ul>
408 - <li><strong>Title:</strong> <a href="<?=$item['link']?>"><?=$item['title']?></a></li>
409 - <li><strong>Date:</strong> <?=isset($item['date_timestamp']) ? date('d-M-y g:i:s a', $item['date_timestamp']) : 'unknown'?></li>
731 + <li><strong>Title:</strong> <a href="<?php echo $item['link']; ?>"><?php echo $item['title']; ?></a></li>
732 + <li><strong>Date:</strong> <?php echo isset($item['date_timestamp']) ? date('d-M-y g:i:s a', $item['date_timestamp']) : 'unknown'; ?></li>
410 733 </ul>
411 734 <div class="entry">
412 - <?=(isset($item['content']['encoded'])?$item['content']['encoded']:$item['description'])?>
735 + <?php echo (isset($item['content']['encoded'])?$item['content']['encoded']:$item['description']); ?>
413 736 </div>
414 737 <?php else: ?>
415 738 <h3>No Items</h3>
416 739 <p>FeedWordPress found no posts on this feed.</p>
@@ -419,12 +742,12 @@
419 742
420 743 <div>
421 744 <h3>Feed Information</h3>
422 745 <ul>
423 - <li><strong>Website:</strong> <a href="<?=$feed_link?>"><?=is_null($feed_title)?'<em>Unknown</em>':$feed_title?></a></li>
424 - <li><strong>Feed URI:</strong> <a href="<?=wp_specialchars($f)?>"><?=wp_specialchars($f)?></a> <a title="Check feed &lt;<?=wp_specialchars($f)?>&gt; for validity" href="http://feedvalidator.org/check.cgi?url=<?=urlencode($f)?>"><img src="../wp-images/smilies/icon_arrow.gif" alt="(&rarr;)" /></a></li>
425 - <li><strong>Encoding:</strong> <?=isset($rss->encoding)?wp_specialchars($rss->encoding):"<em>Unknown</em>"?></li>
426 - <li><strong>Description:</strong> <?=isset($rss->channel['description'])?wp_specialchars($rss->channel['description']):"<em>Unknown</em>"?></li>
746 + <li><strong>Website:</strong> <a href="<?php echo $feed_link; ?>"><?php echo is_null($feed_title)?'<em>Unknown</em>':$feed_title; ?></a></li>
747 + <li><strong>Feed URI:</strong> <a href="<?php echo wp_specialchars($f); ?>"><?php echo wp_specialchars($f); ?></a> <a title="Check feed &lt;<?php echo wp_specialchars($f); ?>&gt; for validity" href="http://feedvalidator.org/check.cgi?url=<?php echo urlencode($f); ?>"><img src="../wp-images/smilies/icon_arrow.gif" alt="(&rarr;)" /></a></li>
748 + <li><strong>Encoding:</strong> <?php echo isset($rss->encoding)?wp_specialchars($rss->encoding):"<em>Unknown</em>"; ?></li>
749 + <li><strong>Description:</strong> <?php echo isset($rss->channel['description'])?wp_specialchars($rss->channel['description']):"<em>Unknown</em>"; ?></li>
427 750 </ul>
428 751 <div class="submit"><input type="submit" name="Use" value="&laquo; Use this feed" /></div>
429 752 <div class="submit"><input type="submit" name="Cancel" value="&laquo; Cancel" /></div>
430 753 </div>
@@ -438,14 +761,14 @@
438 761 endif;
439 762 ?>
440 763 </div>
441 764
442 - <form action="link-manager.php?page=feedwordpress.php" method="post">
765 + <form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
443 766 <div class="wrap">
444 767 <h2>Use another feed</h2>
445 768 <div><label>Feed:</label>
446 769 <input type="text" name="lookup" value="URI" />
447 - <input type="hidden" name="link_id" value="<?=$link_id?>" />
770 + <input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
448 771 <input type="hidden" name="action" value="feedfinder" /></div>
449 772 <div class="submit"><input type="submit" value="Use this feed &raquo;" /></div>
450 773 </div>
451 774 </form>
@@ -453,31 +776,21 @@
453 776 return false; // Don't continue
454 777 }
455 778
456 779 function fwp_switchfeed_page () {
457 - global $wpdb, $user_level;
780 + global $wpdb, $wp_db_version;
458 781
459 782 check_admin_referer();
460 783 if (!isset($_REQUEST['Cancel'])):
461 - if ($user_level < 5):
784 + if (!current_user_can('manage_links')):
462 785 die (__("Cheatin' uh ?"));
463 786 elseif (isset($_REQUEST['link_id']) and ($_REQUEST['link_id']==0)):
464 - // Get the category ID#
465 - $cat_id = FeedWordPress::link_category_id();
466 - $result = $wpdb->query("
467 - INSERT INTO $wpdb->links
468 - SET
469 - link_name = '".$wpdb->escape($_REQUEST['feed_title'])."',
470 - link_url = '".$wpdb->escape($_REQUEST['feed_link'])."',
471 - link_category = '".$wpdb->escape($cat_id)."',
472 - link_rss = '".$wpdb->escape($_REQUEST['feed'])."'
473 - ");
474 -
475 - if ($result): ?>
476 -<div class="updated"><p><a href="<?=$_REQUEST['feed_link']?>"><?=wp_specialchars($_REQUEST['feed_title'])?></a>
477 -has been added as a contributing site, using the newfeed at &lt;<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['feed'])?></a>&gt;.</p></div>
787 + $link_id = FeedWordPress::syndicate_link($_REQUEST['feed_title'], $_REQUEST['feed_link'], $_REQUEST['feed']);
788 + if ($link_id): ?>
789 +<div class="updated"><p><a href="<?php echo $_REQUEST['feed_link']; ?>"><?php echo wp_specialchars($_REQUEST['feed_title']); ?></a>
790 +has been added as a contributing site, using the newsfeed at &lt;<a href="<?php echo $_REQUEST['feed']; ?>"><?php echo wp_specialchars($_REQUEST['feed']); ?></a>&gt;.</p></div>
478 791 <?php else: ?>
479 -<div class="updated"><p>There was a problem adding the newsfeed. [SQL: <?=wp_specialchars(mysql_error())?>]</p></div>
792 +<div class="updated"><p>There was a problem adding the newsfeed. [SQL: <?php echo wp_specialchars(mysql_error()); ?>]</p></div>
480 793 <?php endif;
481 794 elseif (isset($_REQUEST['link_id'])):
482 795 // Update link_rss
483 796 $result = $wpdb->query("
@@ -492,10 +805,10 @@
492 805 SELECT link_name, link_url FROM $wpdb->links
493 806 WHERE link_id = '".$wpdb->escape($_REQUEST['link_id'])."'
494 807 ");
495 808 ?>
496 -<div class="updated"><p>Feed for <a href="<?=$result->link_url?>"><?=wp_specialchars($result->link_name)?></a>
497 -updated to &lt;<a href="<?=$_REQUEST['feed']?>"><?=wp_specialchars($_REQUEST['feed'])?></a>&gt;.</p></div>
809 +<div class="updated"><p>Feed for <a href="<?php echo $result->link_url; ?>"><?php echo wp_specialchars($result->link_name); ?></a>
810 +updated to &lt;<a href="<?php echo $_REQUEST['feed']; ?>"><?php echo wp_specialchars($_REQUEST['feed']); ?></a>&gt;.</p></div>
498 811 <?php else: ?>
499 812 <div class="updated"><p>Nothing was changed.</p></div>
500 813 <?php endif;
501 814 endif;
@@ -502,32 +815,613 @@
502 815 endif;
503 816 return true; // Continue
504 817 }
505 818
819 +function fwp_linkedit_page () {
820 + global $wpdb;
821 +
822 + check_admin_referer(); // Make sure we arrived here from the Dashboard
823 +
824 + $special_settings = array ( /* Regular expression syntax is OK here */
825 + 'cats',
826 + 'hardcode name',
827 + 'hardcode url',
828 + 'hardcode description',
829 + 'hardcode categories', /* Deprecated */
830 + 'post status',
831 + 'comment status',
832 + 'ping status',
833 + 'unfamiliar author',
834 + 'unfamliar categories',
835 + 'update/.*',
836 + 'feed/.*',
837 + 'link/.*',
838 + );
839 +
840 + if (!current_user_can('manage_links')) :
841 + die (__("Cheatin' uh ?"));
842 + elseif (isset($_REQUEST['feedfinder'])) :
843 + return fwp_feedfinder_page(); // re-route to Feed Finder page
844 + else :
845 + $link_id = (int) $_REQUEST['link_id'];
846 + $row = $wpdb->get_row("
847 + SELECT * FROM $wpdb->links WHERE link_id = $link_id
848 + ");
849 +
850 + if ($row) :
851 + if (isset($_POST['save'])) :
852 + $alter = array ();
853 +
854 + $meta = FeedWordPress::notes_to_settings($row->link_notes);
855 + if (isset($meta['cats'])):
856 + $meta['cats'] = preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $meta['cats']);
857 + endif;
858 +
859 + // custom feed settings first
860 + foreach ($_POST['notes'] as $mn) :
861 + $mn['key0'] = trim($mn['key0']);
862 + $mn['key1'] = trim($mn['key1']);
863 + if (preg_match("\007^(("
864 + .implode(')|(',$special_settings)
865 + ."))$\007i",
866 + $mn['key1'])) :
867 + $mn['key1'] = 'user/'.$mn['key1'];
868 + endif;
869 +
870 + if (strlen($mn['key0']) > 0) :
871 + unset($meta[$mn['key0']]); // out with the old
872 + endif;
873 +
874 + if (($mn['action']=='update') and (strlen($mn['key1']) > 0)) :
875 + $meta[$mn['key1']] = $mn['value']; // in with the new
876 + endif;
877 + endforeach;
878 +
879 + // now stuff through the web form
880 + // hardcoded feed info
881 + if (isset($_POST['hardcode_name'])) :
882 + $meta['hardcode name'] = $_POST['hardcode_name'];
883 + if (FeedWordPress::affirmative($meta, 'hardcode name')) :
884 + $alter[] = "link_name = '".$wpdb->escape($_POST['name'])."'";
885 + endif;
886 + endif;
887 + if (isset($_POST['hardcode_description'])) :
888 + $meta['hardcode description'] = $_POST['hardcode_description'];
889 + if (FeedWordPress::affirmative($meta, 'hardcode description')) :
890 + $alter[] = "link_description = '".$wpdb->escape($_POST['description'])."'";
891 + endif;
892 + endif;
893 + if (isset($_POST['hardcode_url'])) :
894 + $meta['hardcode url'] = $_POST['hardcode_url'];
895 + if (FeedWordPress::affirmative($meta, 'hardcode url')) :
896 + $alter[] = "link_url = '".$wpdb->escape($_POST['linkurl'])."'";
897 + endif;
898 + endif;
899 +
900 + // Update scheduling
901 + if (isset($_POST['update_schedule'])) :
902 + $meta['update/hold'] = $_POST['update_schedule'];
903 + endif;
904 +
905 + // Categories
906 + if (isset($_POST['post_category'])) :
907 + $cat_set = "(".implode(",", $_POST['post_category']).")";
908 + $meta['cats'] = $wpdb->get_col(
909 + "SELECT cat_name
910 + FROM $wpdb->categories
911 + WHERE cat_ID IN {$cat_set}
912 + ");
913 + if (count($meta['cats']) == 0) :
914 + unset($meta['cats']);
915 + endif;
916 + else :
917 + unset($meta['cats']);
918 + endif;
919 +
920 + // Post status, comment status, ping status
921 + foreach (array('post', 'comment', 'ping') as $what) :
922 + $sfield = "feed_{$what}_status";
923 + if (isset($_POST[$sfield])) :
924 + if ($_POST[$sfield]=='site-default') :
925 + unset($meta["{$what} status"]);
926 + else :
927 + $meta["{$what} status"] = $_POST[$sfield];
928 + endif;
929 + endif;
930 + endforeach;
931 +
932 + // Unfamiliar author, unfamiliar categories
933 + foreach (array("author", "category") as $what) :
934 + $sfield = "unfamiliar_{$what}";
935 + if (isset($_POST[$sfield])) :
936 + if ($_POST[$sfield]=='site-default') :
937 + unset($meta["unfamiliar {$what}"]);
938 + else :
939 + $meta["unfamiliar {$what}"] = $_POST[$sfield];
940 + endif;
941 + endif;
942 + endforeach;
943 +
944 + if (is_array($meta['cats'])) :
945 + $meta['cats'] = implode(FEEDWORDPRESS_CAT_SEPARATOR, $meta['cats']);
946 + endif;
947 +
948 + $notes = '';
949 + foreach ($meta as $key => $value) :
950 + $notes .= $key . ": ". addcslashes($value, "\0..\37") . "\n";
951 + endforeach;
952 + $alter[] = "link_notes = '".$wpdb->escape($notes)."'";
953 +
954 + $alter_set = implode(", ", $alter);
955 +
956 + // issue update query
957 + $result = $wpdb->query("
958 + UPDATE $wpdb->links
959 + SET $alter_set
960 + WHERE link_id='$link_id'
961 + ");
962 + $updated_link = true;
963 +
964 + // reload link information from DB
965 + $row = $wpdb->get_row("
966 + SELECT * FROM $wpdb->links WHERE link_id = $link_id
967 + ");
968 + else :
969 + $updated_link = false;
970 + endif;
971 +
972 + $link_url = wp_specialchars($row->link_url, 1);
973 + $link_name = wp_specialchars($row->link_name, 1);
974 + $link_image = $row->link_image;
975 + $link_target = $row->link_target;
976 + $link_category = $row->link_category;
977 + $link_description = wp_specialchars($row->link_description);
978 + $link_visible = $row->link_visible;
979 + $link_rating = $row->link_rating;
980 + $link_rel = $row->link_rel;
981 + $link_notes = wp_specialchars($row->link_notes);
982 + $link_rss_uri = wp_specialchars($row->link_rss);
983 +
984 + $meta = FeedWordPress::notes_to_settings($row->link_notes);
985 +
986 + $status['post'] = array('publish' => '', 'private' => '', 'draft' => '', 'site-default' => '');
987 + $status['comment'] = array('open' => '', 'closed' => '', 'site-default' => '');
988 + $status['ping'] = array('open' => '', 'closed' => '', 'site-default' => '');
989 +
990 + foreach (array('post', 'comment', 'ping') as $what) :
991 + if (isset($meta["{$what} status"])) :
992 + $status[$what][$meta["{$what} status"]] = ' checked="checked"';
993 + else :
994 + $status[$what]['site-default'] = ' checked="checked"';
995 + endif;
996 + endforeach;
997 +
998 + $unfamiliar['author'] = array ('create' => '','default' => '','filter' => '');
999 + $unfamiliar['category'] = array ('create'=>'','default'=>'','filter'=>'');
1000 +
1001 + foreach (array('author', 'category') as $what) :
1002 + if (is_string($meta["unfamiliar {$what}"]) and
1003 + array_key_exists($meta["unfamiliar {$what}"], $unfamiliar[$what])) :
1004 + $key = $meta["unfamiliar {$what}"];
1005 + else:
1006 + $key = 'site-default';
1007 + endif;
1008 + $unfamiliar[$what][$key] = ' checked="checked"';
1009 + endforeach;
1010 +
1011 + $dogs = get_nested_categories(-1, 0);
1012 + $cats = array_map('strtolower',
1013 + array_map('trim',
1014 + preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $meta['cats'])
1015 + ));
1016 +
1017 + foreach ($dogs as $tag => $dog) :
1018 + if (in_array(strtolower(trim($dog['cat_name'])), $cats)) :
1019 + $dogs[$tag]['checked'] = true;
1020 + endif;
1021 + endforeach;
1022 + else :
1023 + die( __('Link not found.') );
1024 + endif;
1025 +
1026 + ?>
1027 +<script type="text/javascript">
1028 + function flip_hardcode (item) {
1029 + ed=document.getElementById('basics-'+item+'-edit');
1030 + view=document.getElementById('basics-'+item+'-view');
1031 +
1032 + o = document.getElementById('basics-hardcode-'+item);
1033 + if (o.value=='yes') { ed.style.display='inline'; view.style.display='none'; }
1034 + else { ed.style.display='none'; view.style.display='inline'; }
1035 + }
1036 +</script>
1037 +
1038 +<?php if ($updated_link) : ?>
1039 +<div class="updated"><p>Syndicated feed settings updated.</p></div>
1040 +<?php endif; ?>
1041 +
1042 +<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
1043 +<div class="wrap">
1044 +<input type="hidden" name="link_id" value="<?php echo $link_id; ?>" />
1045 +<input type="hidden" name="action" value="linkedit" />
1046 +<input type="hidden" name="save" value="link" />
1047 +
1048 +<h2>Edit a syndicated feed:</h2>
1049 +<fieldset><legend>Basics</legend>
1050 +<table class="editform" width="100%" cellspacing="2" cellpadding="5">
1051 +<tr>
1052 +<th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
1053 +<td width="60%"><a href="<?php echo wp_specialchars($link_rss_uri); ?>"><?php echo $link_rss_uri; ?></a>
1054 +<a href="<?php echo FEEDVALIDATOR_URI; ?>?url=<?php echo urlencode($link_rss_uri); ?>"
1055 +title="Check feed &lt;<?php echo wp_specialchars($link_rss_uri); ?>&gt; for validity"><img src="../wp-images/smilies/icon_arrow.gif" alt="&rarr;" /></a>
1056 +</td>
1057 +<td width="20%"><input type="submit" name="feedfinder" value="switch &rarr;" style="font-size:smaller" /></td>
1058 +</tr>
1059 +<tr>
1060 +<th scope="row" width="20%"><?php _e('Link Name:') ?></th>
1061 +<td width="60%"><input type="text" id="basics-name-edit" name="name"
1062 +value="<?php echo $link_name; ?>" style="width: 95%" />
1063 +<span id="basics-name-view"><strong><?php echo $link_name; ?></strong></span>
1064 +</td>
1065 +<td>
1066 +<select id="basics-hardcode-name" onchange="flip_hardcode('name')" name="hardcode_name">
1067 +<option value="no" <?php echo FeedWordPress::hardcode('name', $meta)?'':'selected="selected"'; ?>>update automatically</option>
1068 +<option value="yes" <?php echo FeedWordPress::hardcode('name', $meta)?'selected="selected"':''; ?>>edit manually</option>
1069 +</select>
1070 +</td>
1071 +</tr>
1072 +<tr>
1073 +<th scope="row" width="20%"><?php _e('Short description:') ?></th>
1074 +<td width="60%">
1075 +<input id="basics-description-edit" type="text" name="description" value="<?php echo $link_description; ?>" style="width: 95%" />
1076 +<span id="basics-description-view"><strong><?php echo $link_description; ?></strong></span>
1077 +</td>
1078 +<td>
1079 +<select id="basics-hardcode-description" onchange="flip_hardcode('description')"
1080 +name="hardcode_description">
1081 +<option value="no" <?php echo FeedWordPress::hardcode('description', $meta)?'':'selected="selected"'; ?>>update automatically</option>
1082 +<option value="yes" <?php echo FeedWordPress::hardcode('description', $meta)?'selected="selected"':''; ?>>edit manually</option>
1083 +</select></td>
1084 +</tr>
1085 +<tr>
1086 +<th width="20%" scope="row"><?php _e('Homepage:') ?></th>
1087 +<td width="60%">
1088 +<input id="basics-url-edit" type="text" name="linkurl" value="<?php echo $link_url; ?>" style="width: 95%;" />
1089 +<a id="basics-url-view" href="<?php echo $link_url; ?>"><?php echo $link_url; ?></a></td>
1090 +<td>
1091 +<select id="basics-hardcode-url" onchange="flip_hardcode('url')" name="hardcode_url">
1092 +<option value="no"<?php echo FeedWordPress::hardcode('url', $meta)?'':' selected="selected"'; ?>>update live from feed</option>
1093 +<option value="yes"<?php echo FeedWordPress::hardcode('url', $meta)?' selected="selected"':''; ?>>edit manually</option>
1094 +</select></td></tr>
1095 +
1096 +<tr>
1097 +<th width="20%"><?php _e('Last update') ?>:</th>
1098 +<td colspan="2"><?php
1099 + if (isset($meta['update/last'])) :
1100 + echo strftime('%x %X', $meta['update/last'])." ";
1101 + else :
1102 + echo " none yet";
1103 + endif;
1104 +?></td></tr>
1105 +<tr><th width="20%">Next update:</th>
1106 +<td colspan="2"><?php
1107 + $holdem = (isset($meta['update/hold']) ? $meta['update/hold'] : 'scheduled');
1108 +?>
1109 +<select name="update_schedule">
1110 +<option value="scheduled"<?php echo ($holdem=='scheduled')?' selected="selected"':''; ?>>update on schedule <?php
1111 + echo " (";
1112 + if (isset($meta['update/ttl']) and is_numeric($meta['update/ttl'])) :
1113 + if (isset($meta['update/timed']) and $meta['update/timed']=='automatically') :
1114 + echo 'next: ';
1115 + $next = $meta['update/last'] + ((int) $meta['update/ttl'] * 60);
1116 + if (strftime('%x', time()) != strftime('%x', $next)) :
1117 + echo strftime('%x', $next)." ";
1118 + endif;
1119 + echo strftime('%X', $meta['update/last']+((int) $meta['update/ttl']*60));
1120 + else :
1121 + echo "every ".$meta['update/ttl']." minute".(($meta['update/ttl']!=1)?"s":"");
1122 + endif;
1123 + else:
1124 + echo "next scheduled update";
1125 + endif;
1126 + echo ")";
1127 +?></option>
1128 +<option value="next"<?php echo ($holdem=='next')?' selected="selected"':''; ?>>update ASAP</option>
1129 +<option value="ping"<?php echo ($holdem=='ping')?' selected="selected"':''; ?>>update only when pinged</option>
1130 +</select></tr>
1131 +</table>
1132 +</fieldset>
1133 +
1134 +<script type="text/javascript">
1135 +flip_hardcode('name');
1136 +flip_hardcode('description');
1137 +flip_hardcode('url');
1138 +</script>
1139 +
1140 +<p class="submit">
1141 +<input type="submit" name="submit" value="<?php _e('Save Changes &raquo;') ?>" />
1142 +</p>
1143 +
1144 +<fieldset>
1145 +<legend>Syndicated Posts</legend>
1146 +
1147 +<?php fwp_category_box($dogs, 'all syndicated posts from this feed'); ?>
1148 +
1149 +<table class="editform" width="80%" cellspacing="2" cellpadding="5">
1150 +<tr><th width="20%" scope="row" style="vertical-align:top">Publication:</th>
1151 +<td width="80%" style="vertical-align:top"><ul style="margin:0; list-style:none">
1152 +<li><label><input type="radio" name="feed_post_status" value="site-default"
1153 +<?php echo $status['post']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
1154 +(currently: <strong><?php echo FeedWordPress::syndicated_status('post', array(), 'publish'); ?></strong>)</label></li>
1155 +<li><label><input type="radio" name="feed_post_status" value="publish"
1156 +<?php echo $status['post']['publish']; ?> /> Publish posts from this feed immediately</label></li>
1157 +<li><label><input type="radio" name="feed_post_status" value="private"
1158 +<?php echo $status['post']['private']; ?> /> Hold posts from this feed as private posts</label></li>
1159 +<li><label><input type="radio" name="feed_post_status" value="draft"
1160 +<?php echo $status['post']['draft']; ?> /> Hold posts from this feed as drafts</label></li>
1161 +</ul></td>
1162 +</tr>
1163 +
1164 +<tr><th width="20%" scope="row" style="vertical-align:top">Comments:</th>
1165 +<td width="80%"><ul style="margin:0; list-style:none">
1166 +<li><label><input type="radio" name="feed_comment_status" value="site-default"
1167 +<?php echo $status['comment']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
1168 +(currently: <strong><?php echo FeedWordPress::syndicated_status('comment', array(), 'closed'); ?>)</strong></label></li>
1169 +<li><label><input type="radio" name="feed_comment_status" value="open"
1170 +<?php echo $status['comment']['open']; ?> /> Allow comments on syndicated posts from this feed</label></li>
1171 +<li><label><input type="radio" name="feed_comment_status" value="closed"
1172 +<?php echo $status['comment']['closed']; ?> /> Don't allow comments on syndicated posts from this feed</label></li>
1173 +</ul></td>
1174 +</tr>
1175 +
1176 +<tr><th width="20%" scope="row" style="vertical-align:top">Trackback and Pingback:</th>
1177 +<td width="80%"><ul style="margin:0; list-style:none">
1178 +<li><label><input type="radio" name="feed_ping_status" value="site-default"
1179 +<?php echo $status['ping']['site-default']; ?> /> Use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
1180 +(currently: <strong><?php echo FeedWordPress::syndicated_status('ping', array(), 'closed'); ?>)</strong></label></li>
1181 +<li><label><input type="radio" name="feed_ping_status" value="open"
1182 +<?php echo $status['ping']['open']; ?> /> Accept pings on syndicated posts from this feed</label></li>
1183 +<li><label><input type="radio" name="feed_ping_status" value="closed"
1184 +<?php echo $status['ping']['closed']; ?> /> Don't accept pings on syndicated posts from this feed</label></li>
1185 +</ul></td>
1186 +</tr>
1187 +</table>
1188 +</fieldset>
1189 +
1190 +<p class="submit">
1191 +<input type="submit" name="submit" value="<?php _e('Save Changes &raquo;') ?>" />
1192 +</p>
1193 +
1194 +<fieldset>
1195 +<legend>Advanced Feed Options</legend>
1196 +<table class="editform" width="100%" cellspacing="2" cellpadding="5">
1197 +<tr>
1198 +<th width="20%" scope="row" style="vertical-align:top">Unfamiliar authors:</th>
1199 +<td width="80%"><ul style="margin: 0; list-style:none">
1200 +<li><label><input type="radio" name="unfamiliar_author" value="site-default"<?php echo $unfamiliar['author']['site-default']; ?> /> use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
1201 +(currently <strong><?php echo FeedWordPress::on_unfamiliar('author');; ?></strong>)</label></li>
1202 +<li><label><input type="radio" name="unfamiliar_author" value="create"<?php echo $unfamiliar['author']['create']; ?>/> create a new author account</label></li>
1203 +<li><label><input type="radio" name="unfamiliar_author" value="default"<?php echo $unfamiliar['author']['default']; ?> /> attribute the post to the default author</label></li>
1204 +<li><label><input type="radio" name="unfamiliar_author" value="filter"<?php echo $unfamiliar['author']['filter']; ?> /> don't syndicate the post</label></li>
1205 +</ul></td>
1206 +</tr>
1207 +
1208 +<tr>
1209 +<th width="20%" scope="row" style="vertical-align:top">Unfamiliar categories:</th>
1210 +<td width="80%"><ul style="margin: 0; list-style:none">
1211 +<li><label><input type="radio" name="unfamiliar_category" value="site-default"<?php echo $unfamiliar['category']['site-default']; ?> /> use site-wide setting from <a href="options-general.php?page=<?php echo basename(__FILE__); ?>">Syndication Options</a>
1212 +(currently <strong><?php echo FeedWordPress::on_unfamiliar('category');; ?></strong>)</label></li>
1213 +<li><label><input type="radio" name="unfamiliar_category" value="create"<?php echo $unfamiliar['category']['create']; ?> /> create any categories the post is in</label></li>
1214 +<li><label><input type="radio" name="unfamiliar_category" value="default"<?php echo $unfamiliar['category']['default']; ?> /> don't create new categories</label></li>
1215 +<li><label><input type="radio" name="unfamiliar_category" value="filter"<?php echo $unfamiliar['category']['filter']; ?> /> don't create new categories and don't syndicate posts unless they match at least one familiar category</label></li>
1216 +</ul></td>
1217 +</tr></table>
1218 +</fieldset>
1219 +
1220 +<p class="submit">
1221 +<input type="submit" name="submit" value="<?php _e('Save Changes &raquo;') ?>" />
1222 +</p>
1223 +
1224 +<fieldset id="postcustom">
1225 +<legend>Custom Settings (for use in templates)</legend>
1226 +<div id="postcustomstuff">
1227 +<table id="meta-list" cellpadding="3">
1228 + <tr>
1229 + <th>Key</th>
1230 + <th>Value</th>
1231 + <th>Action</th>
1232 + </tr>
1233 +
1234 +<?php
1235 + $i = 0;
1236 + foreach ($meta as $key => $value) :
1237 + if (!preg_match("\007^((".implode(')|(', $special_settings)."))$\007i", $key)) :
1238 +?>
1239 + <tr style="vertical-align:top">
1240 + <th width="30%" scope="row"><input type="hidden" name="notes[<?php echo $i; ?>][key0]" value="<?php echo wp_specialchars($key); ?>" />
1241 + <input id="notes-<?php echo $i; ?>-key" name="notes[<?php echo $i; ?>][key1]" value="<?php echo wp_specialchars($key); ?>" /></th>
1242 + <td width="60%"><textarea rows="2" cols="40" id="notes-<?php echo $i; ?>-value" name="notes[<?php echo $i; ?>][value]"><?php echo wp_specialchars($value); ?></textarea></td>
1243 + <td width="10%"><select name="notes[<?php echo $i; ?>][action]">
1244 + <option value="update">save changes</option>
1245 + <option value="delete">delete this setting</option>
1246 + </select></td>
1247 + </tr>
1248 +<?php
1249 + $i++;
1250 + endif;
1251 + endforeach;
1252 +?>
1253 + <tr>
1254 + <th scope="row"><input type="text" size="10" name="notes[<?php echo $i; ?>][key1]" value="" /></th>
1255 + <td><textarea name="notes[<?php echo $i; ?>][value]" rows="2" cols="40"></textarea></td>
1256 + <td><em>add new setting...</em><input type="hidden" name="notes[<?php echo $i; ?>][action]" value="update" /></td>
1257 + </tr>
1258 +</table>
1259 +</fieldset>
1260 +
1261 +<p class="submit">
1262 +<input type="submit" name="submit" value="<?php _e('Save Changes &raquo;') ?>" />
1263 +</p>
1264 +
1265 +</div>
1266 + <?php
1267 + endif;
1268 + return false; // Don't continue
1269 +}
1270 +
506 1271 function fwp_multidelete_page () {
507 - global $wpdb, $user_level;
508 - check_admin_referer();
509 - if ($user_level < 5):
1272 + global $wpdb;
1273 +
1274 + check_admin_referer(); // Make sure the referers are kosher
1275 +
1276 + $link_ids = (isset($_REQUEST['link_ids']) ? $_REQUEST['link_ids'] : array());
1277 + if (isset($_REQUEST['link_id'])) : array_push($link_ids, $_REQUEST['link_id']); endif;
1278 +
1279 + if (!current_user_can('manage_links')):
510 1280 die (__("Cheatin' uh ?"));
511 - else:
512 - // Update link_rss
513 - $result = $wpdb->query("
514 - DELETE FROM $wpdb->links
515 - WHERE link_id IN (".implode(',',$_REQUEST['linkcheck']).")
516 - ");
1281 + elseif (isset($_POST['confirm']) and $_POST['confirm']=='Delete'):
1282 + foreach ($_POST['link_action'] as $link_id => $what) :
1283 + $do_it[$what][] = $link_id;
1284 + endforeach;
517 1285
518 - if ($result):
519 - $mesg = "Sites deleted from syndication list.";
520 - else:
521 - $mesg = "There was a problem deleting the sites from the syndication list. [SQL: ".mysql_error()."]";
1286 + $alter = array();
1287 + if (count($do_it['hide']) > 0) :
1288 + $hidem = "(".implode(', ', $do_it['hide']).")";
1289 + $alter[] = "
1290 + UPDATE $wpdb->links
1291 + SET link_visible = 'N'
1292 + WHERE link_id IN {$hidem}
1293 + ";
522 1294 endif;
523 - echo "<div class=\"updated\">$mesg</div>\n";
1295 +
1296 + if (count($do_it['nuke']) > 0) :
1297 + $nukem = "(".implode(', ', $do_it['nuke']).")";
1298 +
1299 + // Make a list of the items syndicated from this feed...
1300 + $post_ids = $wpdb->get_col("
1301 + SELECT post_id FROM $wpdb->postmeta
1302 + WHERE meta_key = 'syndication_feed_id'
1303 + AND meta_value IN {$nukem}
1304 + ");
1305 +
1306 + // ... and kill them all
1307 + if (count($post_ids) > 0) :
1308 + foreach ($post_ids as $post_id) :
1309 + wp_delete_post($post_id);
1310 + endforeach;
1311 + endif;
1312 +
1313 + $alter[] = "
1314 + DELETE FROM $wpdb->links
1315 + WHERE link_id IN {$nukem}
1316 + ";
1317 + endif;
1318 +
1319 + if (count($do_it['delete']) > 0) :
1320 + $deletem = "(".implode(', ', $do_it['delete']).")";
1321 +
1322 + // Make the items syndicated from this feed appear to be locally-authored
1323 + $alter[] = "
1324 + DELETE FROM $wpdb->postmeta
1325 + WHERE meta_key = 'syndication_feed_id'
1326 + AND meta_value IN {$deletem}
1327 + ";
1328 +
1329 + // ... and delete the links themselves.
1330 + $alter[] = "
1331 + DELETE FROM $wpdb->links
1332 + WHERE link_id IN {$deletem}
1333 + ";
1334 + endif;
1335 +
1336 + $errs = array(); $success = array ();
1337 + foreach ($alter as $sql) :
1338 + $result = $wpdb->query($sql);
1339 + if (!$result):
1340 + $errs[] = mysql_error();
1341 + endif;
1342 + endforeach;
1343 +
1344 + if (count($alter) > 0) :
1345 + echo "<div class=\"updated\">\n";
1346 + if (count($errs) > 0) :
1347 + echo "There were some problems processing your ";
1348 + echo "unsubscribe request. [SQL: ".implode('; ', $errs)."]";
1349 + else :
1350 + echo "Your unsubscribe request(s) have been processed.";
1351 + endif;
1352 + echo "</div>\n";
1353 + endif;
1354 +
1355 + return true; // Continue on to Syndicated Sites listing
1356 + else :
1357 + $targets = $wpdb->get_results("
1358 + SELECT * FROM $wpdb->links
1359 + WHERE link_id IN (".implode(",",$link_ids).")
1360 + ");
1361 +?>
1362 +<form action="link-manager.php?page=<?php echo basename(__FILE__); ?>" method="post">
1363 +<div class="wrap">
1364 +<input type="hidden" name="action" value="Unsubscribe" />
1365 +<input type="hidden" name="confirm" value="Delete" />
1366 +
1367 +<h2>Unsubscribe from Syndicated Links:</h2>
1368 +<?php foreach ($targets as $link) :
1369 + $link_url = wp_specialchars($link->link_url, 1);
1370 + $link_name = wp_specialchars($link->link_name, 1);
1371 + $link_description = wp_specialchars($link->link_description);
1372 + $link_rss = wp_specialchars($link->link_rss);
1373 + $meta = FeedWordPress::notes_to_settings($link->link_notes);
1374 +?>
1375 +<fieldset>
1376 +<legend><?php echo $link_name; ?></legend>
1377 +<table class="editform" width="100%" cellspacing="2" cellpadding="5">
1378 +<tr><th scope="row" width="20%"><?php _e('Feed URI:') ?></th>
1379 +<td width="80%"><a href="<?php echo $link_rss; ?>"><?php echo $link_rss; ?></a></td></tr>
1380 +<tr><th scope="row" width="20%"><?php _e('Short description:') ?></th>
1381 +<td width="80%"><?php echo $link_description; ?></span></td></tr>
1382 +<tr><th width="20%" scope="row"><?php _e('Homepage:') ?></th>
1383 +<td width="80%"><a href="<?php echo $link_url; ?>"><?php echo $link_url; ?></a></td></tr>
1384 +<tr style="vertical-align:top"><th width="20%" scope="row">Subscription <?php _e('Options') ?>:</th>
1385 +<td width="80%"><ul style="margin:0; padding: 0; list-style: none">
1386 +<li><input type="radio" id="hide-<?php echo $link->link_id; ?>"
1387 +name="link_action[<?php echo $link->link_id; ?>]" value="hide" />
1388 +<label for="hide-<?php echo $link->link_id; ?>">Turn off the subscription for this
1389 +syndicated link<br/><span style="font-size:smaller">(Keep the feed information
1390 +and all the posts from this feed in the database, but don't syndicate any
1391 +new posts from the feed.)</span></label></li>
1392 +<li><input type="radio" id="nuke-<?php echo $link->link_id; ?>"
1393 +name="link_action[<?php echo $link->link_id; ?>]" value="nuke" />
1394 +<label for="nuke-<?php echo $link->link_id; ?>">Delete this syndicated link and all the
1395 +posts that were syndicated from it</label></li>
1396 +<li><input type="radio" id="delete-<?php echo $link->link_id; ?>"
1397 +name="link_action[<?php echo $link->link_id; ?>]" value="delete" />
1398 +<label for="delete-<?php echo $link->link_id; ?>">Delete this syndicated link, but
1399 +<em>keep</em> posts that were syndicated from it (as if they were authored
1400 +locally).</label></li>
1401 +<li><input type="radio" id="nothing-<?php echo $link->link_id; ?>"
1402 +name="link_action[<?php echo $link->link_id; ?>]" value="nothing" />
1403 +<label for="nothing-<?php echo $link->link_id; ?>">Keep this feed as it is. I changed
1404 +my mind.</label></li>
1405 +</ul>
1406 +</table>
1407 +</fieldset>
1408 +<?php endforeach; ?>
1409 +
1410 +<div class="submit">
1411 +<input class="delete" type="submit" name="submit" value="<?php _e('Unsubscribe from selected feeds &raquo;') ?>" />
1412 +</div>
1413 +</div>
1414 +<?php
1415 + return false; // Don't continue on to Syndicated Sites listing
524 1416 endif;
525 - return true;
526 1417 }
527 1418
528 -# -- Outbound XML-RPC ping reform
529 -# 'coz it's rude to send 500 pings the first time your aggregator runs
1419 +################################################################################
1420 +## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
1421 +## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
1422 +################################################################################
1423 +
530 1424 $fwp_held_ping = NULL; // NULL: not holding pings yet
531 1425
532 1426 function fwp_hold_pings () {
533 1427 global $fwp_held_ping;
@@ -552,10 +1446,13 @@
552 1446 generic_ping($fwp_held_ping);
553 1447 endif;
554 1448 }
555 1449
556 -// class FeedWordPress: handle the updating of the feeds and plug in to the
557 -// XML-RPC interface
1450 +################################################################################
1451 +## class FeedWordPress #########################################################
1452 +################################################################################
1453 +
1454 +// class FeedWordPress: handles feed updates and plugs in to the XML-RPC interface
558 1455 class FeedWordPress {
559 1456 var $strip_attrs = array (
560 1457 array('[a-z]+', 'style'),
561 1458 array('[a-z]+', 'target'),
@@ -603,15 +1500,18 @@
603 1500 # * link_notes: user-configurable options, with keys and values
604 1501 # like so:
605 1502 #
606 1503 # key: value
607 - # cats: computers:web
1504 + # cats: computers\nweb
608 1505 # feed/key: value
609 1506 #
610 1507 # Keys that start with "feed/" are gleaned from the data supplied
611 1508 # by the feed itself, and will be overwritten with each update.
612 1509 #
613 - # The value of `cats` is used as a colon-separated (:) list of
1510 + # Values have linebreak characters escaped with C-style
1511 + # backslashes (so, for example, a newline becomes "\n").
1512 + #
1513 + # The value of `cats` is used as a newline-separated list of
614 1514 # default categories for any post coming from a particular feed.
615 1515 # (In the example above, any posts from this feed will be placed
616 1516 # in the "computers" and "web" categories--*in addition to* any
617 1517 # categories that may already be applied to the posts.)
@@ -619,28 +1519,30 @@
619 1519 # Values of keys in link_notes are accessible from templates using
620 1520 # the function `get_feed_meta($key)` if this plugin is activated.
621 1521
622 1522 function FeedWordPress () {
623 - $result = get_linkobjects(FeedWordPress::link_category_id());
1523 + $result = FeedWordPress::syndicated_links();
624 1524
625 1525 $feeds = array ();
626 1526 if ($result): foreach ($result as $link):
627 - $sec = array ();
628 -
629 1527 if (strlen($link->link_rss) > 0):
630 - $notes = explode("\n", $link->link_notes);
631 - foreach ($notes as $note):
632 - list($key, $value) = explode(": ", $note, 2);
633 - if (strlen($key) > 0) $sec[$key] = $value;
634 - endforeach;
1528 + $sec = FeedWordPress::notes_to_settings($link->link_notes);
1529 + $sec['link/uri'] = $link->link_rss;
1530 + $sec['link/name'] = $link->link_name;
1531 + $sec['link/id'] = $link->link_id;
635 1532
636 - $sec['url'] = $link->link_rss;
637 - $sec['name'] = $link->link_name;
1533 + // `hardcode categories` is deprecated in favor
1534 + // of `unfamiliar categories`
1535 + if (
1536 + FeedWordPress::affirmative($sec, 'hardcode categories')
1537 + and !isset($sec['unfamiliar categories'])
1538 + ) :
1539 + $sec['unfamiliar categories'] = 'default';
1540 + endif;
638 1541
639 1542 if (isset($sec['cats'])):
640 - $sec['cats'] = explode(':',$sec['cats']);
1543 + $sec['cats'] = preg_split(FEEDWORDPRESS_CAT_SEPARATOR_PATTERN, $sec['cats']);
641 1544 endif;
642 - $sec['link_id'] = $link->link_id;
643 1545
644 1546 $feeds[] = $sec;
645 1547 endif;
646 1548 endforeach; endif;
@@ -645,42 +1547,152 @@
645 1547 endif;
646 1548 endforeach; endif;
647 1549
648 1550 $this->feeds = $feeds;
649 - } // function acquire_feeds ()
1551 + } // FeedWordPress::FeedWordPress ()
650 1552
1553 + # function notes_to_settings (): Convert WordPress Link Notes to array
1554 + # of feed-level settings
1555 + #
1556 + # Arguments:
1557 + # ----------
1558 + # * $link_notes (string): the text from the Link Notes section of a link
1559 + #
1560 + # Returns:
1561 + # --------
1562 + # An associative array of settings stored in the Link Notes field. (For
1563 + # the `unfamiliar authors` setting, for example, simply look up the
1564 + # value of $meta['unfamiliar authors'], if $meta contains the value
1565 + # returned by `notes_to_settings()`.
1566 + #
1567 + # Values in FeedWordPress feed settings are escaped using C-style
1568 + # slashes. The escaped characters will already have been processed and
1569 + # converted in the returned array.
1570 + function notes_to_settings ($link_notes) {
1571 + $notes = explode("\n", $link_notes);
1572 +
1573 + $sec = array ();
1574 + foreach ($notes as $note):
1575 + list($key, $value) = explode(": ", $note, 2);
1576 +
1577 + if (strlen($key) > 0) :
1578 + // Unescape and trim() off the whitespace.
1579 + // Thanks to Ray Lischner for pointing out the
1580 + // need to trim off whitespace.
1581 + $sec[$key] = stripcslashes (trim($value));
1582 + endif;
1583 + endforeach;
1584 + return $sec;
1585 + } // FeedWordPress::notes_to_settings ()
1586 +
1587 + # function update (): polls for updates on one or more Contributor feeds
1588 + #
1589 + # Arguments:
1590 + # ----------
1591 + # * $uri (string): either the URI of the feed to poll, the URI of the
1592 + # website (human-readable link) whose feed you want to poll, or a
1593 + # "magic" tag: URI composed of the URI in the constant `RPC_MAGIC`
1594 + # and a "secret word" set in the FeedWordPress Options.
1595 + #
1596 + # If the "magic" URI is used, then FeedWordPress will poll any
1597 + # feeds that are ready for polling. It will not poll feeds that are
1598 + # marked as "Invisible" Links (signifying that the subscription has
1599 + # been de-activated), or feeds that are not yet stale according to
1600 + # their TTL setting (which is either set in the feed, or else
1601 + # set randomly within a window of 30 minutes - 2 hours).
1602 + #
1603 + # Returns:
1604 + # --------
1605 + # * Normally returns an associative array, with 'new' => the number
1606 + # of new posts added during the update, and 'updated' => the number
1607 + # of old posts that were updated during the update. If both numbers
1608 + # are zero, there was no change since the last poll on that URI.
1609 + #
1610 + # * Returns NULL if URI it was passed was not a URI that this
1611 + # installation of FeedWordPress syndicates (the most common cause
1612 + # of this error is attempts to poll all feeds, lacking, or using
1613 + # an incorrect, "secret word."
1614 + #
1615 + # Effects:
1616 + # --------
1617 + # * One or more feeds are polled for updates
1618 + #
1619 + # * If the feed Link does not have a hardcoded name set, its Link
1620 + # Name is synchronized with the feed's title element
1621 + #
1622 + # * If the feed Link does not have a hardcoded URI set, its Link URI
1623 + # is synchronized with the feed's human-readable link element
1624 + #
1625 + # * If the feed Link does not have a hardcoded description set, its
1626 + # Link Description is synchronized with the feed's description,
1627 + # tagline, or subtitle element.
1628 + #
1629 + # * The time of polling is recorded in the feed's settings, and the
1630 + # TTL (time until the feed is next available for polling) is set
1631 + # either from the feed (if it is supplied in the ttl or syndication
1632 + # module elements) or else from a randomly-generated time window
1633 + # (between 30 minutes and 2 hours).
1634 + #
1635 + # * New posts from the polled feed are added to the WordPress store.
1636 + #
1637 + # * Updates to existing posts since the last poll are mirrored in the
1638 + # WordPress store.
1639 + #
651 1640 function update ($uri) {
652 1641 global $wpdb;
653 -
1642 +
1643 + $uri = trim($uri);
1644 +
1645 + if (FeedWordPress::needs_upgrade()) : // Will make duplicate posts if we don't hold off
1646 + return NULL;
1647 + endif;
1648 +
654 1649 do_action('feedwordpress_update', $uri);
655 1650
656 1651 // Secret voodoo tag: URI for updating *everything*.
657 1652 $secret = RPC_MAGIC.FeedWordPress::rpc_secret();
658 1653
659 - fwp_hold_pings();
1654 + fwp_hold_pings(); // Only send out one ping for the whole to-do
660 1655
661 1656 // Loop through and check for new posts
662 1657 $delta = NULL;
663 - foreach ($this->feeds as $feed) {
664 - if (($uri === $secret)
665 - or ($uri === $feed['url'])
666 - or ($uri === $feed['feed/link'])) {
667 - if (is_null($delta)) $delta = array('new' => 0, 'updated' => 0);
668 - do_action('feedwordpress_check_feed', array($feed));
1658 + foreach ($this->feeds as $feed) :
1659 + $pinged_that = in_array($uri, array($secret, $feed['link/uri'], $feed['feed/link']));
1660 +
1661 + if ($uri != $secret) : // A site-specific ping always updates
1662 + $timely = true;
1663 + elseif (isset($feed['update/hold']) and ($feed['update/hold']=='ping')) :
1664 + $timely = false;
1665 + elseif (isset($feed['update/hold']) and ($feed['update/hold']=='next')) :
1666 + $timely = true;
1667 + elseif (!isset($feed['update/ttl']) or !isset($feed['update/last'])) :
1668 + $timely = true;
1669 + else :
1670 + $after = ((int) $feed['update/last'])
1671 + +((int) $feed['update/ttl'] * 60);
1672 + $timely = (time() >= $after);
1673 + endif;
1674 +
1675 + if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
1676 + $delta = array('new' => 0, 'updated' => 0); // ... don't return error condition
1677 + endif;
1678 +
1679 + if ($pinged_that and $timely) :
1680 + do_action('feedwordpress_check_feed', $feed);
669 1681 $added = $this->feed2wp($wpdb, $feed);
670 - if (isset($added['new'])) $delta['new'] += $added['new'];
671 - if (isset($added['updated'])) $delta['updated'] += $added['updated'];
672 - } /* if */
673 - } /* foreach */
674 -
675 - do_action('feedwordpress_update_complete', array($delta));
676 - fwp_release_pings();
1682 + if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
1683 + if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
1684 + endif;
1685 + endforeach;
677 1686
1687 + do_action('feedwordpress_update_complete', $delta);
1688 + fwp_release_pings(); // Now that we're done, send the one ping
1689 +
678 1690 return $delta;
679 1691 }
680 1692
681 1693 function feed2wp ($wpdb, $f) {
682 - $feed = fetch_rss($f['url']);
1694 + $feed = fetch_rss($f['link/uri']);
683 1695 $new_count = array('new' => 0, 'updated' => 0);
684 1696
685 1697 $this->update_feed($wpdb, $feed->channel, $f);
686 1698
@@ -685,9 +1697,9 @@
685 1697 $this->update_feed($wpdb, $feed->channel, $f);
686 1698
687 1699 if (is_array($feed->items)) :
688 1700 foreach ($feed->items as $item) :
689 - $post = $this->item_to_post($wpdb, $item, $feed->channel, $f);
1701 + $post = $this->item_to_post($wpdb, $item, $feed, $f);
690 1702 if (!is_null($post)) :
691 1703 $new = $this->add_post($wpdb, $post);
692 1704 if ( $new !== false ) $new_count[$new]++;
693 1705 endif;
@@ -706,16 +1718,16 @@
706 1718 // returned array for FeedWordPress::flatten_array($a) will contain a key
707 1719 // $a['feed/b/c/d'] with value 'e'.
708 1720 function flatten_array ($arr, $prefix = 'feed/', $separator = '/') {
709 1721 $ret = array ();
710 - if (is_array($arr)):
711 - foreach ($arr as $key => $value) {
712 - if (is_scalar($value)) {
1722 + if (is_array($arr)) :
1723 + foreach ($arr as $key => $value) :
1724 + if (is_scalar($value)) :
713 1725 $ret[$prefix.$key] = $value;
714 - } else {
1726 + else :
715 1727 $ret = array_merge($ret, $this->flatten_array($value, $prefix.$key.$separator, $separator));
716 - } /* if */
717 - } /* foreach */
1728 + endif;
1729 + endforeach;
718 1730 endif;
719 1731 return $ret;
720 1732 } // function FeedWordPress::flatten_array ()
721 1733
@@ -722,50 +1734,144 @@
722 1734 function resolve_relative_uri ($matches) {
723 1735 return $matches[1].Relative_URI::resolve($matches[2], $this->_base).$matches[3];
724 1736 } // function FeedWordPress::resolve_relative_uri ()
725 1737
726 - function update_feed ($wpdb, $channel, $f) {
1738 + function hardcode ($what, $f) {
1739 + $default = get_settings("feedwordpress_hardcode_$what");
1740 + if ( $default === 'yes' ) :
1741 + // If the default is to hardcode, then we want the
1742 + // negation of negative(): TRUE by default and FALSE if
1743 + // the setting is explicitly "no"
1744 + $ret = !FeedWordPress::negative($f, "hardcode $what");
1745 + else :
1746 + // If the default is NOT to hardcode, then we want
1747 + // affirmative(): FALSE by default and TRUE if the
1748 + // setting is explicitly "yes"
1749 + $ret = FeedWordPress::affirmative($f, "hardcode $what");
1750 + endif;
1751 + return $ret;
1752 + }
1753 +
1754 + function syndicated_status ($what, $f, $default) {
1755 + global $wpdb;
1756 +
1757 + $ret = get_settings("feedwordpress_syndicated_{$what}_status");
1758 + if ( isset($f["$what status"]) ) :
1759 + $ret = $f["$what status"];
1760 + elseif (!$ret) :
1761 + $ret = $default;
1762 + endif;
1763 + return $wpdb->escape(trim(strtolower($ret)));
1764 + }
1765 +
1766 + function negative ($f, $setting) {
1767 + $nego = array ('n', 'no', 'f', 'false');
1768 + return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $nego));
1769 + }
1770 +
1771 + function affirmative ($f, $setting) {
727 1772 $affirmo = array ('y', 'yes', 't', 'true', 1);
1773 + return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $affirmo));
1774 + }
728 1775
729 - $link_id = $f['link_id'];
1776 + function feed_ttl ($channel) {
1777 + if (isset($channel['ttl'])) :
1778 + // "ttl stands for time to live. It's a number of
1779 + // minutes that indicates how long a channel can be
1780 + // cached before refreshing from the source."
1781 + // <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>
1782 + $ret = $channel['ttl'];
1783 + elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
1784 + $period_minutes = array (
1785 + 'hourly' => 60, /* minutes in an hour */
1786 + 'daily' => 1440, /* minutes in a day */
1787 + 'weekly' => 10080, /* minutes in a week */
1788 + 'monthly' => 43200, /* minutes in a month */
1789 + 'yearly' => 525600, /* minutes in a year */
1790 + );
730 1791
731 - if (!isset($channel['id'])) {
732 - $channel['id'] = $f['url'];
733 - }
1792 + // "sy:updatePeriod: Describes the period over which the
1793 + // channel format is updated. Acceptable values are:
1794 + // hourly, daily, weekly, monthly, yearly. If omitted,
1795 + // daily is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
1796 + if (isset($channel['sy']['updateperiod'])) : $period = $channel['sy']['updateperiod'];
1797 + else : $period = 'daily';
1798 + endif;
1799 +
1800 + // "sy:updateFrequency: Used to describe the frequency
1801 + // of updates in relation to the update period. A
1802 + // positive integer indicates how many times in that
1803 + // period the channel is updated. ... If omitted a value
1804 + // of 1 is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
1805 + if (isset($channel['sy']['updatefrequency'])) : $freq = (int) $channel['sy']['updatefrequency'];
1806 + else : $freq = 1;
1807 + endif;
1808 +
1809 + $ret = (int) ($period_minutes[$period] / $freq);
1810 + else :
1811 + $ret = NULL;
1812 + endif;
1813 + return $ret;
1814 + }
734 1815
1816 + function update_feed ($wpdb, $channel, $f) {
1817 + $link_id = $f['link/id'];
1818 +
1819 + if (!isset($channel['id'])) :
1820 + $channel['id'] = $f['link/uri'];
1821 + endif;
1822 +
735 1823 $update = array();
736 - if (isset($channel['link'])) {
1824 + if (!FeedWordPress::hardcode('url', $f) and isset($channel['link'])) :
737 1825 $update[] = "link_url = '".$wpdb->escape($channel['link'])."'";
738 - }
739 - if (isset($channel['title']) and (!isset($f['hardcode name'])
740 - or in_array(trim(strtolower($f['hardcode name'])), $affirmo))) {
1826 + endif;
1827 +
1828 + if (!FeedWordPress::hardcode('name', $f) and isset($channel['title'])) :
741 1829 $update[] = "link_name = '".$wpdb->escape($channel['title'])."'";
742 - }
1830 + endif;
743 1831
744 - if (isset($channel['tagline'])) {
745 - $update[] = "link_description = '".$wpdb->escape($channel['tagline'])."'";
746 - } elseif (isset($channel['description'])) {
747 - $update[] = "link_description = '".$wpdb->escape($channel['description'])."'";
748 - }
1832 + if (!FeedWordPress::hardcode('description', $f)) :
1833 + if (isset($channel['tagline'])) :
1834 + $update[] = "link_description = '".$wpdb->escape($channel['tagline'])."'";
1835 + elseif (isset($channel['description'])) :
1836 + $update[] = "link_description = '".$wpdb->escape($channel['description'])."'";
1837 + endif;
1838 + endif;
749 1839
750 - if (is_array($f['cats'])) {
751 - $f['cats'] = implode(':',$f['cats']);
752 - } /* if */
1840 + if (is_array($f['cats'])) :
1841 + $f['cats'] = implode(FEEDWORDPRESS_CAT_SEPARATOR, $f['cats']);
1842 + endif;
753 1843
754 1844 $f = array_merge($f, $this->flatten_array($channel));
1845 +
1846 + $f['update/last'] = time();
1847 + $ttl = $this->feed_ttl($channel);
1848 + if (!is_null($ttl)) :
1849 + $f['update/ttl'] = $ttl;
1850 + $f['update/timed'] = 'feed';
1851 + else :
1852 + $f['update/ttl'] = rand(30, 120); // spread over time interval for staggered updates
1853 + $f['update/timed'] = 'automatically';
1854 + endif;
755 1855
1856 + if (!isset($f['update/hold']) or $f['update/hold']!='ping') :
1857 + $f['update/hold'] = 'scheduled';
1858 + endif;
1859 +
756 1860 # -- A few things we don't want to save in the notes
757 - unset($f['link_id']); unset($f['uri']); unset($f['url']);
1861 + unset($f['link/id']); unset($f['link/uri']);
1862 + unset($f['link/name']);
1863 + unset($f['hardcode categories']); // Deprecated
758 1864
759 1865 $notes = '';
760 - foreach ($f as $key => $value) {
761 - $notes .= "${key}: $value\n";
762 - }
1866 + foreach ($f as $key => $value) :
1867 + $notes .= $key . ": ". addcslashes($value, "\0..\37") . "\n";
1868 + endforeach;
763 1869 $update[] = "link_notes = '".$wpdb->escape($notes)."'";
764 1870
765 1871 $update_set = implode(',', $update);
766 1872
767 - // if we've already have this feed, update
1873 + // Update the properties of the link from the feed information
768 1874 $result = $wpdb->query("
769 1875 UPDATE $wpdb->links
770 1876 SET $update_set
771 1877 WHERE link_id='$link_id'
@@ -770,9 +1876,59 @@
770 1876 SET $update_set
771 1877 WHERE link_id='$link_id'
772 1878 ");
773 1879 } // function FeedWordPress::update_feed ()
774 -
1880 +
1881 + function date_created ($item) {
1882 + if (isset($item['dc']['created'])) :
1883 + $epoch = @parse_w3cdtf($item['dc']['created']);
1884 + elseif (isset($item['dcterms']['created'])) :
1885 + $epoch = @parse_w3cdtf($item['dcterms']['created']);
1886 + elseif (isset($item['created'])): // Atom 0.3
1887 + $epoch = @parse_w3cdtf($item['created']);
1888 + endif;
1889 + return $epoch;
1890 + }
1891 +
1892 + function guid ($item, $feed) {
1893 + if (isset($item['id'])): // Atom 0.3 / 1.0
1894 + $guid = $item['id'];
1895 + elseif (isset($item['atom']['id'])) : // Namespaced Atom
1896 + $guid = $item['atom']['id'];
1897 + elseif (isset($item['guid'])) : // RSS 2.0
1898 + $guid = $item['guid'];
1899 + elseif (isset($item['dc']['identifier'])) : // yeah, right
1900 + $guid = $item['dc']['identifier'];
1901 + else :
1902 + // The feed does not seem to have provided us with a
1903 + // unique identifier, so we'll have to cobble together
1904 + // a tag: URI that might work for us. The base of the
1905 + // URI will be the host name of the feed source ...
1906 + $bits = parse_url($feed['link/uri']);
1907 + $guid = 'tag:'.$bits['host'];
1908 +
1909 + // If we have a date of creation, then we can use that
1910 + // to uniquely identify the item. (On the other hand, if
1911 + // the feed producer was consicentious enough to
1912 + // generate dates of creation, she probably also was
1913 + // conscientious enough to generate unique identifiers.)
1914 + if (!is_null(FeedWordPress::date_created($item))) :
1915 + $guid .= '://post.'.date('YmdHis', FeedWordPress::date_created($item));
1916 +
1917 + // Otherwise, use both the URI of the item, *and* the
1918 + // item's title. We have to use both because titles are
1919 + // often not unique, and sometimes links aren't unique
1920 + // either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
1921 + // some podcasts). But it's rare to have *both* the same
1922 + // title *and* the same link for two different items. So
1923 + // this is about the best we can do.
1924 + else :
1925 + $guid .= '://'.md5($item['link'].'/'.$item['title']);
1926 + endif;
1927 + endif;
1928 + return $guid;
1929 + }
1930 +
775 1931 // item_to_post(): convert information from a single item from an
776 1932 // Atom/RSS feed to a post for WordPress's database.
777 1933 //
778 1934 // item_to_post() invokes the syndicated_item filter on each item it
@@ -785,12 +1941,13 @@
785 1941 // we handle lookup/creation of numeric author and category IDs in
786 1942 // add_post()). If you want plugins that have side effects on the posts
787 1943 // database, you should probably hook into the action
788 1944 // post_syndicated_item
789 - //
790 - function item_to_post($wpdb, $item, $channel, $f) {
1945 + function item_to_post($wpdb, $item, $rss, $f) {
1946 + $channel = $rss->channel;
1947 +
791 1948 $post = array();
792 -
1949 +
793 1950 // This is ugly as all hell. I'd like to use apply_filters()'s
794 1951 // alleged support for a variable argument count, but this seems
795 1952 // to have been broken in WordPress 1.5. It'll be fixed somehow
796 1953 // in WP 1.5.1, but I'm aiming at WP 1.5 compatibility across
@@ -798,8 +1955,9 @@
798 1955 //
799 1956 // Cf.: <http://mosquito.wordpress.org/view.php?id=901>
800 1957 global $fwp_channel, $fwp_feedmeta;
801 1958 $fwp_channel = $channel; $fwp_feedmeta = $f;
1959 +
802 1960 $item = apply_filters('syndicated_item', $item);
803 1961
804 1962 // Filters can halt further processing by returning NULL
805 1963 if (is_null($item)) :
@@ -807,26 +1965,50 @@
807 1965 else :
808 1966 $post['post_title'] = $wpdb->escape($item['title']);
809 1967
810 1968 $post['named']['author'] = array ();
811 - if (isset($item['dc']['creator'])):
1969 +
1970 + if (isset($item['author_name'])):
1971 + $post['named']['author']['name'] = $item['author_name'];
1972 + elseif (isset($item['dc']['creator'])):
812 1973 $post['named']['author']['name'] = $item['dc']['creator'];
813 - elseif (isset($item['dc']['creator'])):
1974 + elseif (isset($item['dc']['contributor'])):
814 1975 $post['named']['author']['name'] = $item['dc']['contributor'];
815 - elseif (isset($item['author_name'])):
816 - $post['named']['author']['name'] = $item['author_name'];
817 - else:
1976 + elseif (isset($channel['dc']['creator'])) :
1977 + $post['named']['author']['name'] = $channel['dc']['creator'];
1978 + elseif (isset($channel['dc']['contributor'])) :
1979 + $post['named']['author']['name'] = $channel['dc']['contributor'];
1980 + elseif (isset($channel['author_name'])) :
1981 + $post['named']['author']['name'] = $channel['author_name'];
1982 + elseif ($rss->is_rss() and isset($item['author'])) :
1983 + // The author element in RSS is allegedly an
1984 + // e-mail address, but lots of people don't use
1985 + // it that way. So let's make of it what we can.
1986 + $post['named']['author'] = parse_email_with_realname($item['author']);
1987 +
1988 + if (!isset($post['named']['author']['name'])) :
1989 + if (isset($post['named']['author']['email'])) :
1990 + $post['named']['author']['name'] = $post['named']['author']['email'];
1991 + else :
1992 + $post['named']['author']['name'] = $channel['title'];
1993 + endif;
1994 + endif;
1995 + else :
818 1996 $post['named']['author']['name'] = $channel['title'];
819 1997 endif;
820 1998
821 1999 if (isset($item['author_email'])):
822 2000 $post['named']['author']['email'] = $item['author_email'];
2001 + elseif (isset($channel['author_email'])) :
2002 + $post['named']['author']['email'] = $channel['author_email'];
823 2003 endif;
824 2004
825 2005 if (isset($item['author_url'])):
826 - $post['named']['author']['url'] = $item['author_url'];
2006 + $post['named']['author']['uri'] = $item['author_url'];
2007 + elseif (isset($channel['author_url'])) :
2008 + $post['named']['author']['uri'] = $item['author_url'];
827 2009 else:
828 - $post['named']['author']['url'] = $channel['link'];
2010 + $post['named']['author']['uri'] = $channel['link'];
829 2011 endif;
830 2012
831 2013 // ... So far we just have an alphanumeric
832 2014 // representation of the author. We will look up (or
@@ -834,9 +2016,13 @@
834 2016 // FeedWordPress::add_post()
835 2017
836 2018 # Identify content and sanitize it.
837 2019 # ---------------------------------
838 - if (isset($item['content']['encoded']) and $item['content']['encoded']):
2020 + if (isset($item['xhtml']['body'])) :
2021 + $content = $item['xhtml']['body'];
2022 + elseif (isset($item['xhtml']['div'])) :
2023 + $content = $item['xhtml']['div'];
2024 + elseif (isset($item['content']['encoded']) and $item['content']['encoded']):
839 2025 $content = $item['content']['encoded'];
840 2026 else:
841 2027 $content = $item['description'];
842 2028 endif;
@@ -847,9 +2033,9 @@
847 2033 # any way to get that information out of MagpieRSS if it's
848 2034 # in the feed, and if it's in the content itself we'd have
849 2035 # to do yet more XML parsing to do things right. For now
850 2036 # this will have to do.
851 -
2037 +
852 2038 $this->_base = $item['link']; // Reset the base for resolving relative URIs
853 2039 foreach ($this->uri_attrs as $pair):
854 2040 list($tag,$attr) = $pair;
855 2041 $content = preg_replace_callback (
@@ -857,9 +2043,9 @@
857 2043 array(&$this,'resolve_relative_uri'),
858 2044 $content
859 2045 );
860 2046 endforeach;
861 -
2047 +
862 2048 # Sanitize problematic attributes
863 2049 foreach ($this->strip_attrs as $pair):
864 2050 list($tag,$attr) = $pair;
865 2051 $content = preg_replace (
@@ -867,16 +2053,31 @@
867 2053 "\\1\\4",
868 2054 $content
869 2055 );
870 2056 endforeach;
871 -
2057 +
2058 + # Identify and sanitize excerpt
2059 + $excerpt = NULL;
2060 + if ( isset($item['description']) and $item['description'] ) :
2061 + $excerpt = $item['description'];
2062 + elseif ( isset($content) and $content ) :
2063 + $excerpt = strip_tags($content);
2064 + if (strlen($excerpt) > 255) :
2065 + $excerpt = substr($excerpt,0,252).'...';
2066 + endif;
2067 + endif;
2068 +
872 2069 $post['post_content'] = $wpdb->escape($content);
873 -
2070 +
2071 + if (!is_null($excerpt)):
2072 + $post['post_excerpt'] = $wpdb->escape($excerpt);
2073 + endif;
2074 +
874 2075 # This is unneeded if wp_insert_post can be used.
875 2076 # --- cut here ---
876 2077 $post['post_name'] = sanitize_title($post['post_title']);
877 2078 # --- cut here ---
878 -
2079 +
879 2080 # RSS is a fucking mess. Figure out whether we have a date in
880 2081 # dc:date, <issued>, <pubDate>, etc., and get it into Unix epoch
881 2082 # format for reformatting. If you can't find anything, use the
882 2083 # current time.
@@ -881,60 +2082,104 @@
881 2082 # format for reformatting. If you can't find anything, use the
882 2083 # current time.
883 2084 if (isset($item['dc']['date'])):
884 2085 $post['epoch']['issued'] = parse_w3cdtf($item['dc']['date']);
885 - elseif (isset($item['issued'])):
2086 + elseif (isset($item['dcterms']['issued'])) :
2087 + $post['epoch']['issued'] = parse_w3cdtf($item['dcterms']['issued']);
2088 + elseif (isset($item['published'])) : // Atom 1.0
2089 + $post['epoch']['issued'] = parse_w3cdtf($item['published']);
2090 + elseif (isset($item['issued'])): // Atom 0.3
886 2091 $post['epoch']['issued'] = parse_w3cdtf($item['issued']);
887 - elseif (isset($item['pubdate'])):
2092 + elseif (isset($item['pubdate'])): // RSS 2.0
888 2093 $post['epoch']['issued'] = strtotime($item['pubdate']);
889 2094 else:
890 - $post['epoch']['issued'] = time();
2095 + $post['epoch']['issued'] = null;
891 2096 endif;
892 -
2097 +
2098 + # And again, for the created date
2099 + $post['epoch']['created'] = FeedWordPress::date_created($item);
2100 +
893 2101 # As far as I know, only atom currently has a reliable way to
894 2102 # specify when something was *modified* last
895 - if (isset($item['modified'])):
896 - $post['epoch']['modified'] = parse_w3cdtf($item['modified']);
897 - else:
2103 + if (isset($item['dc']['modified'])) : // Not really correct
2104 + $post['epoch']['modified'] = @parse_w3cdtf($item['dc']['modified']);
2105 + elseif (isset($item['dcterms']['modified'])) : // Dublin Core extensions
2106 + $post['epoch']['modified'] = @parse_w3cdtf($item['dcterms']['modified']);
2107 + elseif (isset($item['modified'])): // Atom 0.3
2108 + $post['epoch']['modified'] = @parse_w3cdtf($item['modified']);
2109 + elseif (isset($item['updated'])): // Atom 1.0
2110 + $post['epoch']['modified'] = @parse_w3cdtf($item['updated']);
2111 + elseif (isset($post['epoch']['issued'])) : // Fall back to issued / dc:date
898 2112 $post['epoch']['modified'] = $post['epoch']['issued'];
2113 + else :
2114 + $post['epoch']['modified'] = time();
899 2115 endif;
900 -
901 - $post['post_date'] = date('Y-m-d H:i:s', $post['epoch']['issued']);
2116 +
2117 + $post['post_date'] = date('Y-m-d H:i:s', (!is_null($post['epoch']['issued']) ? $post['epoch']['issued'] : $post['epoch']['modified']));
902 2118 $post['post_modified'] = date('Y-m-d H:i:s', $post['epoch']['modified']);
903 - $post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $post['epoch']['issued']);
2119 + $post['post_date_gmt'] = gmdate('Y-m-d H:i:s', (!is_null($post['epoch']['issued']) ? $post['epoch']['issued'] : $post['epoch']['modified']));
904 2120 $post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $post['epoch']['modified']);
905 -
906 - # Use feed-level preferences or a sensible default.
907 - $post['post_status'] = (isset($f['post status']) ? $wpdb->escape(trim(strtolower($f['post status']))) : 'publish');
908 - $post['comment_status'] = (isset($f['comment status']) ? $wpdb->escape(trim(strtolower($f['comment status']))) : 'closed');
909 - $post['ping_status'] = (isset($f['ping status']) ? $wpdb->escape(trim(strtolower($f['ping status']))) : 'closed');
910 -
2121 +
2122 + # Use feed-level preferences or the global default.
2123 + $post['post_status'] = FeedWordPress::syndicated_status('post', $f, 'publish');
2124 + $post['comment_status'] = FeedWordPress::syndicated_status('comment', $f, 'closed');
2125 + $post['ping_status'] = FeedWordPress::syndicated_status('ping', $f, 'closed');
2126 +
911 2127 // Unique ID (hopefully a unique tag: URI); failing that, the permalink
912 - if (isset($item['id'])):
913 - $post['guid'] = $wpdb->escape($item['id']);
914 - else:
915 - $post['guid'] = $wpdb->escape($item['link']);
2128 + $post['guid'] = $wpdb->escape(FeedWordPress::guid($item, $f));
2129 +
2130 + // RSS 2.0 / Atom 1.0 enclosure support
2131 + if ( isset($item['enclosure#']) ) :
2132 + for ($i = 1; $i <= $item['enclosure#']; $i++) :
2133 + $eid = (($i > 1) ? "#{$id}" : "");
2134 + $post['meta']['enclosure'][] =
2135 + $item["enclosure{$eid}@url"]."\n".
2136 + $item["enclosure{$eid}@length"]."\n".
2137 + $item["enclosure{$eid}@type"];
2138 + endfor;
916 2139 endif;
917 -
918 - if (isset($channel['title'])) $post['syndication_source'] = $channel['title'];
919 - if (isset($channel['link'])) $post['syndication_source_uri'] = $channel['link'];
920 - $post['syndication_feed'] = $f['url'];
921 -
2140 +
2141 + // In case you want to point back to the blog this was syndicated from
2142 + if (isset($channel['title'])) $post['meta']['syndication_source'] = $channel['title'];
2143 + if (isset($channel['link'])) $post['meta']['syndication_source_uri'] = $channel['link'];
2144 +
2145 + // Store information on human-readable and machine-readable comment URIs
2146 + if (isset($item['comments'])) : $post['meta']['rss:comments'] = $item['comments']; endif;
2147 + if (isset($item['wfw']['commentrss'])) : $post['meta']['wfw:commentRSS'] = $item['wfw']['commentrss']; endif;
2148 +
2149 + // Store information to identify the feed that this came from
2150 + $post['meta']['syndication_feed'] = $f['link/uri'];
2151 + $post['meta']['syndication_feed_id'] = $f['link/id'];
2152 +
922 2153 // In case you want to know the external permalink...
923 - $post['syndication_permalink'] = $item['link'];
2154 + $post['meta']['syndication_permalink'] = $item['link'];
924 2155
2156 + // Feed-by-feed options for author and category creation
2157 + $post['named']['unfamiliar']['author'] = $f['unfamiliar author'];
2158 + $post['named']['unfamiliar']['category'] = $f['unfamiliar categories'];
2159 +
925 2160 // Categories: start with default categories
926 - $post['named']['category'] = $f['cats'];
2161 + $fc = get_settings("feedwordpress_syndication_cats");
2162 + if ($fc) : $post['named']['preset/category'] = explode("\n", $fc);
2163 + else : $post['named']['preset/category'] = array();
2164 + endif;
2165 + if (is_array($f['cats'])) :
2166 + $post['named']['preset/category'] = array_merge($post['named']['preset/category'], $f['cats']);
2167 + endif;
927 2168
928 2169 // Now add categories from the post, if we have 'em
929 - if (is_array($item['categories'])):
930 - foreach ($item['categories'] as $cat):
931 - if ( strpos($f['url'], 'del.icio.us') !== false ):
2170 + $post['named']['category'] = array();
2171 + if ( isset($item['category#']) ) :
2172 + for ($i = 1; $i <= $item['category#']; $i++) :
2173 + $cat_idx = (($i > 1) ? "#{$i}" : "");
2174 + $cat = $item["category{$cat_idx}"];
2175 +
2176 + if ( strpos($f['link/uri'], 'del.icio.us') !== false ):
932 2177 $post['named']['category'] = array_merge($post['named']['category'], explode(' ', $cat));
933 2178 else:
934 2179 $post['named']['category'][] = $cat;
935 2180 endif;
936 - endforeach;
2181 + endfor;
937 2182 endif;
938 2183 endif;
939 2184 return $post;
940 2185 } // function FeedWordPress::item_to_post ()
@@ -945,13 +2190,13 @@
945 2190 SELECT id, guid, UNIX_TIMESTAMP(post_modified) AS modified
946 2191 FROM $wpdb->posts WHERE guid='$guid'
947 2192 ");
948 2193
949 - if (!$result):
2194 + if (!$result) :
950 2195 $freshness = 2; // New content
951 - elseif ($post['epoch']['modified'] > $result->modified):
2196 + elseif ($post['epoch']['modified'] > $result->modified) :
952 2197 $freshness = 1; // Updated content
953 - else:
2198 + else :
954 2199 $freshness = 0;
955 2200 endif;
956 2201
957 2202 if ($freshness > 0) :
@@ -959,113 +2204,148 @@
959 2204 $post['post_author'] = $this->author_to_id (
960 2205 $wpdb,
961 2206 $post['named']['author']['name'],
962 2207 $post['named']['author']['email'],
963 - $post['named']['author']['url']
2208 + $post['named']['author']['uri'],
2209 + FeedWordPress::on_unfamiliar('author', $post['named']['unfamiliar']['author'])
964 2210 );
2211 +
2212 + if (is_null($post['post_author'])) :
2213 + $freshness = 0;
2214 + else :
2215 + # -- Look up, or create, numeric ID for categories
2216 + $post['post_category'] = $this->lookup_categories (
2217 + $wpdb,
2218 + $post['named']['category'],
2219 + FeedWordPress::on_unfamiliar('category', $post['named']['unfamiliar']['category'])
2220 + );
2221 +
2222 + if (is_null($post['post_category'])) : // filter mode on, no matching categories; drop the post
2223 + $freshness = 0;
2224 + else : // filter mode off or at least one match; now add on the feed and global presets
2225 + $post['post_category'] = array_merge (
2226 + $post['post_category'],
2227 + $this->lookup_categories (
2228 + $wpdb,
2229 + $post['named']['preset/category'],
2230 + 'default'
2231 + )
2232 + );
2233 + endif;
2234 + endif;
965 2235
966 - # -- Look up, or create, numeric ID for categories
967 - $post['post_category'] = $this->lookup_categories (
968 - $wpdb,
969 - $post['named']['category']
970 - );
2236 + unset($post['named']);
2237 + endif;
971 2238
972 - unset($post['named']);
2239 + if ($freshness > 0) :
2240 + $post = apply_filters('syndicated_post', $post);
2241 + if (is_null($post)) $freshness = 0;
973 2242 endif;
974 2243
975 - $post = apply_filters('syndicated_post', $post);
976 - if (is_null($post)) $freshness = 0;
977 -
978 2244 if ($freshness == 2) :
979 2245 // The item has not yet been added. So let's add it.
980 -
981 - # The right way to do this would be to use:
982 - #
983 - # $postId = wp_insert_post($post);
984 - # $result = $wpdb->query("
985 - # UPDATE $wpdb->posts
986 - # SET
987 - # guid='$guid'
988 - # WHERE post_id='$postId'
989 - # ");
990 - #
991 - # in place of everything in the cut below. Alas,
992 - # wp_insert_post seems to be a memory hog; using it
993 - # to insert several posts in one session makes php
994 - # segfault after inserting 50-100 posts. This can get
995 - # pretty annoying, especially if you are trying to
996 - # update your feeds for the first time.
997 - #
998 - # --- cut here ---
999 - $result = $wpdb->query("
1000 - INSERT INTO $wpdb->posts
1001 - SET
1002 - guid = '$guid',
1003 - post_author = '".$post['post_author']."',
1004 - post_date = '".$post['post_date']."',
1005 - post_date_gmt = '".$post['post_date_gmt']."',
1006 - post_content = '".$post['post_content']."',
1007 - post_title = '".$post['post_title']."',
1008 - post_name = '".$post['post_name']."',
1009 - post_modified = '".$post['post_modified']."',
1010 - post_modified_gmt = '".$post['post_modified_gmt']."',
1011 - comment_status = '".$post['comment_status']."',
1012 - ping_status = '".$post['ping_status']."',
1013 - post_status = '".$post['post_status']."'
1014 - ");
1015 - $postId = $wpdb->insert_id;
1016 - $this->add_to_category($wpdb, $postId, $post['post_category']);
1017 -
1018 - // Since we are not going through official channels, we need to
1019 - // manually tell WordPress that we've published a new post.
1020 - // We need to make sure to do this in order for FeedWordPress
1021 - // to play well with the staticize-reloaded plugin (something
1022 - // that a large aggregator website is going to *want* to be
1023 - // able to use).
1024 - do_action('publish_post', $postId);
1025 - # --- cut here ---
1026 -
2246 + $postId = $this->insert_new_post($post);
1027 2247 $this->add_rss_meta($wpdb, $postId, $post);
1028 -
1029 2248 do_action('post_syndicated_item', $postId);
1030 2249
1031 2250 $ret = 'new';
1032 2251 elseif ($freshness == 1) :
1033 - $postId = $result->id; $modified = $result->modified;
2252 + $post['ID'] = $result->id; $modified = $result->modified;
2253 + $this->update_existing_post($post);
2254 + $this->add_rss_meta($wpdb, $post['ID'], $post);
2255 + do_action('update_syndicated_item', $post['ID']);
1034 2256
1035 - $result = $wpdb->query("
1036 - UPDATE $wpdb->posts
1037 - SET
1038 - post_author = '".$post['post_author']."',
1039 - post_content = '".$post['post_content']."',
1040 - post_title = '".$post['post_title']."',
1041 - post_name = '".$post['post_name']."',
1042 - post_modified = '".$post['post_modified']."',
1043 - post_modified_gmt = '".$post['post_modified_gmt']."'
1044 - WHERE guid='$guid'
1045 - ");
1046 - $this->add_to_category($wpdb, $postId, $post['post_category']);
1047 -
1048 - // Since we are not going through official channels, we need to
1049 - // manually tell WordPress that we've published a new post.
1050 - // We need to make sure to do this in order for FeedWordPress
1051 - // to play well with the staticize-reloaded plugin (something
1052 - // that a large aggregator website is going to *want* to be
1053 - // able to use).
1054 - do_action('edit_post', $postId);
1055 -
1056 - $this->add_rss_meta($wpdb, $postId, $post);
1057 -
1058 - do_action('update_syndicated_item', $postId);
1059 -
1060 2257 $ret = 'updated';
1061 - else:
2258 + else :
1062 2259 $ret = false;
1063 2260 endif;
1064 2261
1065 2262 return $ret;
1066 2263 } // function FeedWordPress::add_post ()
1067 -
2264 +
2265 + function insert_new_post ($post) {
2266 + global $wpdb;
2267 +
2268 + $guid = $post['guid'];
2269 +
2270 + # The right way to do this would be to use:
2271 + #
2272 + # $postId = wp_insert_post($post);
2273 + # $result = $wpdb->query("
2274 + # UPDATE $wpdb->posts
2275 + # SET
2276 + # guid='$guid'
2277 + # WHERE post_id='$postId'
2278 + # ");
2279 + #
2280 + # in place of everything in the cut below. Alas,
2281 + # wp_insert_post seems to be a memory hog; using it
2282 + # to insert several posts in one session makes php
2283 + # segfault after inserting 50-100 posts. This can get
2284 + # pretty annoying, especially if you are trying to
2285 + # update your feeds for the first time.
2286 + #
2287 + # --- cut here ---
2288 + $result = $wpdb->query("
2289 + INSERT INTO $wpdb->posts
2290 + SET
2291 + guid = '$guid',
2292 + post_author = '".$post['post_author']."',
2293 + post_date = '".$post['post_date']."',
2294 + post_date_gmt = '".$post['post_date_gmt']."',
2295 + post_content = '".$post['post_content']."',"
2296 + .(isset($post['post_excerpt']) ? "post_excerpt = '".$post['post_excerpt']."'," : "")."
2297 + post_title = '".$post['post_title']."',
2298 + post_name = '".$post['post_name']."',
2299 + post_modified = '".$post['post_modified']."',
2300 + post_modified_gmt = '".$post['post_modified_gmt']."',
2301 + comment_status = '".$post['comment_status']."',
2302 + ping_status = '".$post['ping_status']."',
2303 + post_status = '".$post['post_status']."'
2304 + ");
2305 + $postId = $wpdb->insert_id;
2306 + $this->add_to_category($wpdb, $postId, $post['post_category']);
2307 +
2308 + // Since we are not going through official channels, we need to
2309 + // manually tell WordPress that we've published a new post.
2310 + // We need to make sure to do this in order for FeedWordPress
2311 + // to play well with the staticize-reloaded plugin (something
2312 + // that a large aggregator website is going to *want* to be
2313 + // able to use).
2314 + do_action('publish_post', $postId);
2315 + # --- cut here ---
2316 +
2317 + return $postId;
2318 + } /* FeedWordPress::insert_new_post() */
2319 +
2320 + function update_existing_post ($post) {
2321 + global $wpdb;
2322 +
2323 + $guid = $post['guid'];
2324 + $postId = $post['ID'];
2325 +
2326 + $result = $wpdb->query("
2327 + UPDATE $wpdb->posts
2328 + SET
2329 + post_author = '".$post['post_author']."',
2330 + post_content = '".$post['post_content']."',
2331 + post_title = '".$post['post_title']."',
2332 + post_name = '".$post['post_name']."',
2333 + post_modified = '".$post['post_modified']."',
2334 + post_modified_gmt = '".$post['post_modified_gmt']."'
2335 + WHERE guid='$guid'
2336 + ");
2337 + $this->add_to_category($wpdb, $postId, $post['post_category']);
2338 +
2339 + // Since we are not going through official channels, we need to
2340 + // manually tell WordPress that we've published a new post.
2341 + // We need to make sure to do this in order for FeedWordPress
2342 + // to play well with the staticize-reloaded plugin (something
2343 + // that a large aggregator website is going to *want* to be
2344 + // able to use).
2345 + do_action('edit_post', $postId);
2346 + } /* FeedWordPress::update_existing_post() */
2347 +
1068 2348 # function FeedWordPress::add_to_category ()
1069 2349 #
1070 2350 # If there is a way to properly hook in to wp_insert_post, then this
1071 2351 # function will no longer be needed. In the meantime, here it is.
@@ -1070,126 +2350,254 @@
1070 2350 # If there is a way to properly hook in to wp_insert_post, then this
1071 2351 # function will no longer be needed. In the meantime, here it is.
1072 2352 # --- cut here ---
1073 2353 function add_to_category($wpdb, $postId, $post_categories) {
2354 + global $wp_db_version; // test for WordPress 2.0 database schema
2355 +
1074 2356 // Default to category 1 ("Uncategorized"), if nothing else
1075 2357 if (!$post_categories) $post_categories[] = 1;
1076 2358
1077 - // Clean the slate (in case we're updating)
1078 - $results = $wpdb->query("
1079 - DELETE FROM $wpdb->post2cat
1080 - WHERE post_id = $postId
1081 - ");
1082 -
1083 - foreach ($post_categories as $post_category):
1084 - $results = $wpdb->query("
1085 - INSERT INTO $wpdb->post2cat
1086 - SET
1087 - post_id = $postId,
1088 - category_id = $post_category
1089 - ");
1090 - endforeach;
2359 + // Now pass the buck to the WordPress API...
2360 + wp_set_post_cats('', $postId, $post_categories);
1091 2361 } // function FeedWordPress::add_to_category ()
1092 2362 # --- cut here ---
1093 2363
1094 - // FeedWordPress::add_rss_meta: adds feed meta-data to user-defined keys
1095 - // for each entry. Interesting feed meta-data is tagged in the $post
1096 - // array using the prefix 'syndication_'. This should be used for
1097 - // anything that the WordPress user might want to access about a post's
1098 - // original source that isn't provided for by standard WP meta-data
1099 - // (i.e., beyond author, title, timestamp, and categories)
2364 + // FeedWordPress::add_rss_meta: adds interesting meta-data to each entry
2365 + // using the space for custom keys. The set of keys and values to add is
2366 + // specified by the keys and values of $post['meta']. This is used to
2367 + // store anything that the WordPress user might want to access from a
2368 + // template concerning the post's original source that isn't provided
2369 + // for by standard WP meta-data (i.e., any interesting data about the
2370 + // syndicated post other than author, title, timestamp, categories, and
2371 + // guid). It's also used to hook into WordPress's support for
2372 + // enclosures.
1100 2373 function add_rss_meta ($wpdb, $postId, $post) {
1101 - foreach ($post as $key => $value):
1102 - if (strpos($key, "syndication_") === 0):
1103 - $value = $wpdb->escape($value);
2374 + if ( is_array($post) and isset($post['meta']) and is_array($post['meta']) ) :
2375 + foreach ( $post['meta'] as $key => $values ) :
1104 2376
2377 + $key = $wpdb->escape($key);
2378 +
2379 + // If this is an update, clear out the old
2380 + // values to avoid duplication.
1105 2381 $result = $wpdb->query("
1106 2382 DELETE FROM $wpdb->postmeta
1107 2383 WHERE post_id='$postId' AND meta_key='$key'
1108 2384 ");
1109 2385
1110 - $result = $wpdb->query("
1111 - INSERT INTO $wpdb->postmeta
1112 - SET
1113 - post_id='$postId',
1114 - meta_key='$key',
1115 - meta_value='$value'
1116 - ");
1117 - endif;
1118 - endforeach;
2386 + // Allow for either a single value or an array
2387 + if (!is_array($values)) $values = array($values);
2388 + foreach ( $values as $value ) :
2389 + $value = $wpdb->escape($value);
2390 + $result = $wpdb->query("
2391 + INSERT INTO $wpdb->postmeta
2392 + SET
2393 + post_id='$postId',
2394 + meta_key='$key',
2395 + meta_value='$value'
2396 + ");
2397 + endforeach;
2398 + endforeach;
2399 + endif;
1119 2400 } /* FeedWordPress::add_rss_meta () */
1120 2401
1121 2402 // FeedWordPress::author_to_id (): get the ID for an author name from
1122 2403 // the feed. Create the author if necessary.
1123 - function author_to_id ($wpdb, $author, $email, $url) {
2404 + function author_to_id ($wpdb, $author, $email, $url, $unfamiliar_author = 'create') {
2405 + global $wp_db_version; // test for WordPress 2.0 database schema
2406 +
1124 2407 // Never can be too careful...
1125 2408 $nice_author = sanitize_title($author);
2409 + $reg_author = $wpdb->escape(preg_quote($author));
1126 2410 $author = $wpdb->escape($author);
1127 2411 $email = $wpdb->escape($email);
1128 2412 $url = $wpdb->escape($url);
1129 -
1130 - $id = $wpdb->get_var(
1131 - "SELECT ID from $wpdb->users
1132 - WHERE
1133 - user_login = '$author' OR
1134 - user_firstname = '$author' OR
1135 - user_nickname = '$author' OR
1136 - user_description = '$author' OR
1137 - user_nicename = '$nice_author'");
1138 -
1139 - if (is_null($id)):
1140 - $wpdb->query (
1141 - "INSERT INTO $wpdb->users
1142 - SET
1143 - ID='0',
1144 - user_login='$author',
1145 - user_firstname='$author',
1146 - user_nickname='$author',
1147 - user_nicename='$nice_author',
1148 - user_description='$author',
1149 - user_email='$email',
1150 - user_url='$url'");
1151 - $id = $wpdb->insert_id;
2413 +
2414 + // Look for an existing author record that fits...
2415 + if (!isset($wp_db_version)) :
2416 + #-- WordPress 1.5.x
2417 + $id = $wpdb->get_var(
2418 + "SELECT ID from $wpdb->users
2419 + WHERE
2420 + TRIM(LCASE(user_login)) = TRIM(LCASE('$author')) OR
2421 + (
2422 + LENGTH(TRIM(LCASE(user_email))) > 0
2423 + AND TRIM(LCASE(user_email)) = TRIM(LCASE('$email'))
2424 + ) OR
2425 + TRIM(LCASE(user_firstname)) = TRIM(LCASE('$author')) OR
2426 + TRIM(LCASE(user_nickname)) = TRIM(LCASE('$author')) OR
2427 + TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author')) OR
2428 + TRIM(LCASE(user_description)) = TRIM(LCASE('$author')) OR
2429 + (
2430 + LOWER(user_description)
2431 + RLIKE CONCAT(
2432 + '(^|\\n)a.k.a.( |\\t)*:?( |\\t)*',
2433 + LCASE('$reg_author'),
2434 + '( |\\t|\\r)*(\\n|\$)'
2435 + )
2436 + )
2437 + ");
2438 + elseif ($wp_db_version >= 2966) :
2439 + #-- WordPress 2.0+
2440 +
2441 + # First try the user core data table.
2442 + $id = $wpdb->get_var(
2443 + "SELECT ID FROM $wpdb->users
2444 + WHERE
2445 + TRIM(LCASE(user_login)) = TRIM(LCASE('$author'))
2446 + OR (
2447 + LENGTH(TRIM(LCASE(user_email))) > 0
2448 + AND TRIM(LCASE(user_email)) = TRIM(LCASE('$email'))
2449 + )
2450 + OR TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author'))
2451 + ");
2452 +
2453 + if (is_null($id)) : # Then look for aliases in the user meta data table
2454 + $id = $wpdb->get_var(
2455 + "SELECT user_id FROM $wpdb->usermeta
2456 + WHERE
2457 + (meta_key = 'description' AND TRIM(LCASE(meta_value)) = TRIM(LCASE('$author')))
2458 + OR (
2459 + meta_key = 'description'
2460 + AND LCASE(meta_value)
2461 + RLIKE CONCAT(
2462 + '(^|\\n)a.k.a.( |\\t)*:?( |\\t)*',
2463 + LCASE('$reg_author'),
2464 + '( |\\t|\\r)*(\\n|\$)'
2465 + )
2466 + )
2467 + ");
2468 + endif;
1152 2469 endif;
2470 +
2471 + // ... if you don't find one, then do what you need to do
2472 + if (is_null($id)) :
2473 + if ($unfamiliar_author === 'create') :
2474 + if (!isset($wp_db_version)) :
2475 + #-- WordPress 1.5.x
2476 + $wpdb->query (
2477 + "INSERT INTO $wpdb->users
2478 + SET
2479 + ID='0',
2480 + user_login='$author',
2481 + user_firstname='$author',
2482 + user_nickname='$author',
2483 + user_nicename='$nice_author',
2484 + user_description='$author',
2485 + user_email='$email',
2486 + user_url='$url'");
2487 + $id = $wpdb->insert_id;
2488 + elseif ($wp_db_version >= 2966) :
2489 + #-- WordPress 2.0+
2490 + $userdata = array();
2491 +
2492 + #-- user table data
2493 + $userdata['ID'] = NULL; // new user
2494 + $userdata['user_login'] = $author;
2495 + $userdata['user_pass'] = FeedWordPress::rpc_secret();
2496 + $userdata['user_email'] = $email;
2497 + $userdata['user_url'] = $url;
2498 + $userdata['display_name'] = $author;
2499 +
2500 + $id = wp_insert_user($userdata);
2501 + endif;
2502 + elseif ($unfamiliar_author === 'default') :
2503 + $id = 1;
2504 + endif;
2505 + endif;
1153 2506 return $id;
1154 2507 } // function FeedWordPress::author_to_id ()
1155 -
2508 +
1156 2509 // look up (and create) category ids from a list of categories
1157 - function lookup_categories ($wpdb, $cats) {
1158 - if ( !count($cats) ) return array();
1159 -
1160 - # i'd kill for a decent map function in PHP
1161 - # but that would require functiosn to be first class object, or at least
1162 - # coderef support
1163 - $cat_strs = array();
1164 - foreach ( $cats as $c ) {
1165 - $c = $wpdb->escape($c); $c = "'$c'";
1166 - $cat_strs[] = $c;
1167 - }
1168 -
1169 - $cat_sql = join(',', $cat_strs);
1170 - $sql = "SELECT cat_ID,cat_name from $wpdb->categories WHERE cat_name IN ($cat_sql)";
1171 - $results = $wpdb->get_results($sql);
1172 -
1173 - $cat_ids = array();
1174 - $cat_found = array();
1175 -
1176 - if (!is_null($results)):
1177 - foreach ( $results as $row ) {
1178 - $cat_ids[] = $row->cat_ID;
1179 - $cat_found[] = strtolower($row->cat_name); // Normalize to avoid case problems
1180 - }
2510 + function lookup_categories ($wpdb, $cats, $unfamiliar_category = 'create') {
2511 + // Normalize whitespace because (1) trailing whitespace can
2512 + // cause PHP and MySQL not to see eye to eye on VARCHAR
2513 + // comparisons for some versions of MySQL (cf.
2514 + // <http://dev.mysql.com/doc/mysql/en/char.html>), and (2)
2515 + // because I doubt most people want to make a semantic
2516 + // distinction between 'Computers' and 'Computers '
2517 + $cats = array_map('trim', $cats);
2518 +
2519 + $cat_ids = array ();
2520 +
2521 + if ( count($cats) > 0 ) :
2522 + # i'd kill for a decent map function in PHP
2523 + # but that would require functions to be first class object,
2524 + # or at least coderef support
2525 + $cat_str = array ();
2526 + $cat_aka = array ();
2527 + foreach ( $cats as $c ) :
2528 + $resc = $wpdb->escape(preg_quote($c));
2529 + $esc = $wpdb->escape($c);
2530 + $cat_str[] = "'$esc'";
2531 +
2532 + $cat_aka[] = "(LOWER(category_description)
2533 + RLIKE CONCAT('(^|\n)a.k.a.( |\t)*:?( |\t)*', LOWER('{$resc}'), '( |\t|\r)*(\n|\$)'))";
2534 + endforeach;
2535 +
2536 + $match_cat_name = 'cat_name IN ('.join(',', $cat_str).')';
2537 + $match_cat_alias = join(' OR ', $cat_aka);
2538 +
2539 + $results = $wpdb->get_results(
2540 + "SELECT
2541 + cat_ID,
2542 + cat_name,
2543 + category_description
2544 + FROM $wpdb->categories
2545 + WHERE ($match_cat_name) OR ($match_cat_alias)"
2546 + );
2547 +
2548 + $cat_ids = array();
2549 + $found = array();
2550 +
2551 + if (!is_null($results)):
2552 + foreach ( $results as $row ) :
2553 + // Add existing ID to list of numerical
2554 + // IDs to eventually place post in
2555 + $cat_ids[] = $row->cat_ID;
2556 +
2557 + // Add name to list of categories not to
2558 + // create afresh. Normalizing case with
2559 + // strtolower() avoids mismatches in
2560 + // VARCHAR comparison between PHP (which
2561 + // has case-sensitive comparisons) and
2562 + // MySQL (which has case-insensitive
2563 + // comparisons for the field types used
2564 + // by WordPress)
2565 + $found[] = strtolower(trim($row->cat_name));
2566 +
2567 + // Add name of any aliases to list of
2568 + // categories not to create afresh.
2569 + if (preg_match_all('/^a.k.a. \s* :? \s* (.*\S) \s*$/mx',
2570 + $row->category_description, $aka,
2571 + PREG_PATTERN_ORDER)) :
2572 + $found = array_merge (
2573 + $found,
2574 + array_map('strtolower',
2575 + array_map('trim',
2576 + $aka[1]
2577 + ))
2578 + );
2579 + endif;
2580 + endforeach;
2581 + endif;
2582 +
2583 + foreach ($cats as $new_cat) :
2584 + if (($unfamiliar_category==='create') and !in_array(strtolower($new_cat), $found)) :
2585 + $nice_cat = sanitize_title($new_cat);
2586 + $wpdb->query(sprintf("
2587 + INSERT INTO $wpdb->categories
2588 + SET
2589 + cat_name='%s',
2590 + category_nicename='%s'
2591 + ", $wpdb->escape($new_cat), $nice_cat));
2592 + $cat_ids[] = $wpdb->insert_id;
2593 + endif;
2594 + endforeach;
2595 +
2596 + if ((count($cat_ids) == 0) and ($unfamiliar_category === 'filter')) :
2597 + $cat_ids = NULL; // Drop the post
2598 + endif;
1181 2599 endif;
1182 -
1183 - foreach ($cats as $new_cat):
1184 - $sql = "INSERT INTO $wpdb->categories (cat_name, category_nicename)
1185 - VALUES ('%s', '%s')";
1186 - if (!in_array(strtolower($new_cat), $cat_found)):
1187 - $nice_cat = sanitize_title($new_cat);
1188 - $wpdb->query(sprintf($sql, $wpdb->escape($new_cat), $nice_cat));
1189 - $cat_ids[] = $wpdb->insert_id;
1190 - endif;
1191 - endforeach;
1192 2600 return $cat_ids;
1193 2601 } // function FeedWordPress::lookup_categories ()
1194 2602
1195 2603 function rpc_secret () {
@@ -1194,11 +2602,97 @@
1194 2602
1195 2603 function rpc_secret () {
1196 2604 return get_settings('feedwordpress_rpc_secret');
1197 2605 } // function FeedWordPress::rpc_secret ()
1198 -
2606 +
2607 + function on_unfamiliar ($what = 'author', $override = NULL) {
2608 + $set = array('create', 'default', 'filter');
2609 +
2610 + $ret = strtolower($override);
2611 + if (!in_array($ret, $set)) :
2612 + $ret = get_settings('feedwordpress_unfamiliar_'.$what);
2613 + if (!in_array($ret, $set)) :
2614 + $ret = 'create';
2615 + endif;
2616 + endif;
2617 +
2618 + return $ret;
2619 + } // function FeedWordPress::on_unfamiliar()
2620 +
2621 + function syndicated_links () {
2622 + $contributors = FeedWordPress::link_category_id();
2623 + if (function_exists('get_bookmarks')) {
2624 + $links = get_bookmarks(array("category" => $contributors));
2625 + } else {
2626 + $links = get_linkobjects($contributors); // deprecated as of WP 2.1
2627 + } // if
2628 + return $links;
2629 + } // function syndicated_links()
2630 +
2631 + function syndicate_link ($name, $uri, $rss) {
2632 + global $wpdb;
2633 +
2634 + // Get the category ID#
2635 + $cat_id = FeedWordPress::link_category_id();
2636 +
2637 + if (function_exists('wp_insert_link')) { // WordPress 2.x
2638 + $link_id = wp_insert_link(array(
2639 + "link_name" => $name,
2640 + "link_url" => $uri,
2641 + "link_category" => array($cat_id),
2642 + "link_rss" => $rss
2643 + ));
2644 + } else { // WordPress 1.5.x
2645 + $result = $wpdb->query("
2646 + INSERT INTO $wpdb->links
2647 + SET
2648 + link_name = '".$wpdb->escape($name)."',
2649 + link_url = '".$wpdb->escape($uri)."',
2650 + link_category = '".$wpdb->escape($cat_id)."',
2651 + link_rss = '".$wpdb->escape($rss)."'
2652 + ");
2653 + $link_id = $wpdb->insert_id;
2654 + } // if
2655 + return $link_id;
2656 + } // function insert_syndicated_link()
2657 +
2658 + function link_category_named ($name) {
2659 + global $wp_db_version, $wpdb;
2660 +
2661 + if (!isset($wp_db_version) or $wp_db_version < 4772) {
2662 + // WordPress 1.5 and 2.0.x have segregated post and link categories
2663 + $ct = $wpdb->linkcategories;
2664 + } else {
2665 + // WordPress 2.1 has a unified category table for both
2666 + $ct = $wpdb->categories;
2667 + }
2668 + return $wpdb->get_var("SELECT cat_id FROM $ct WHERE cat_name='$name'");
2669 + }
2670 +
2671 + function create_link_category ($name) {
2672 + global $wp_db_version, $wpdb;
2673 +
2674 + if (!isset($wp_db_version) or $wp_db_version < 4772) {
2675 + $result = $wpdb->query("
2676 + INSERT INTO $wpdb->linkcategories
2677 + SET
2678 + cat_id = 0,
2679 + cat_name='$name',
2680 + show_images='N',
2681 + show_description='N',
2682 + show_rating='N',
2683 + show_updated='N',
2684 + sort_order='name'
2685 + ");
2686 + $cat_id = $wpdb->insert_id;
2687 + } else {
2688 + // Why the fuck is this API function only available in a wp-admin module?
2689 + $cat_id = wp_insert_category(array('cat_name' => $name));
2690 + }
2691 + }
2692 +
1199 2693 function link_category_id () {
1200 - global $wpdb;
2694 + global $wpdb, $wp_db_version;
1201 2695
1202 2696 $cat_id = get_settings('feedwordpress_cat_id');
1203 2697
1204 2698 // If we don't yet *have* the category, we'll have to create it
@@ -1203,31 +2697,17 @@
1203 2697
1204 2698 // If we don't yet *have* the category, we'll have to create it
1205 2699 if ($cat_id === false) {
1206 2700 $cat = $wpdb->escape(DEFAULT_SYNDICATION_CATEGORY);
2701 +
2702 + // Look for something with the right name...
2703 + $cat_id = FeedWordPress::link_category_named($cat);
1207 2704
1208 - // Look for something with the right name...
1209 - $cat_id = $wpdb->get_var("
1210 - SELECT cat_id FROM $wpdb->linkcategories
1211 - WHERE cat_name='$cat'
1212 - ");
1213 -
1214 2705 // If you still can't find anything, make it for yourself.
1215 2706 if (!$cat_id) {
1216 - $result = $wpdb->query("
1217 - INSERT INTO $wpdb->linkcategories
1218 - SET
1219 - cat_id = 0,
1220 - cat_name='$cat',
1221 - show_images='N',
1222 - show_description='N',
1223 - show_rating='N',
1224 - show_updated='N',
1225 - sort_order='name'
1226 - ");
1227 - $cat_id = $wpdb->insert_id;
2707 + $cat_id = FeedWordPress::create_link_category($cat);
1228 2708 }
1229 -
2709 +
1230 2710 update_option('feedwordpress_cat_id', $cat_id);
1231 2711 }
1232 2712 return $cat_id;
1233 2713 }
@@ -1232,22 +2712,124 @@
1232 2712 return $cat_id;
1233 2713 }
1234 2714
1235 2715 function link_category () {
1236 - global $wpdb;
2716 + global $wpdb, $wp_db_version;
1237 2717
1238 2718 $cat_id = FeedWordPress::link_category_id();
1239 2719
1240 2720 // Get the ID# for the category name...
1241 - $cat_name = $wpdb->get_var("
1242 - SELECT cat_name FROM $wpdb->linkcategories
1243 - WHERE cat_id='$cat_id'
1244 - ");
2721 + if (!isset($wp_db_version) or $wp_db_version < 4772) {
2722 + // WordPress 1.5 and 2.0.x
2723 + $cat_name = $wpdb->get_var("
2724 + SELECT cat_name FROM $wpdb->linkcategories
2725 + WHERE cat_id='$cat_id'
2726 + ");
2727 + } else {
2728 + // WordPress 2.1
2729 + $category = get_category($cat_id);
2730 + $cat_name = $category->cat_name;
2731 + }
1245 2732 return $cat_name;
1246 2733 }
2734 +
2735 + function needs_upgrade () {
2736 + global $wpdb;
2737 + $fwp_db_version = get_settings('feedwordpress_version');
2738 + $ret = false; // innocent until proven guilty
2739 + if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
2740 + // This is an older version or a fresh install. Does it
2741 + // require a database upgrade or database initialization?
2742 + if ($fwp_db_version > 0.96) :
2743 + // No. Just brand it with the new version.
2744 + update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
2745 + else :
2746 + // Yes. Check to see whether this is a fresh install or an upgrade.
2747 + $syn = $wpdb->get_col("
2748 + SELECT post_id
2749 + FROM $wpdb->postmeta
2750 + WHERE meta_key = 'syndication_feed'
2751 + ");
2752 + if (count($syn) > 0) : // contains at least one syndicated post
2753 + $ret = true;
2754 + else : // fresh install; brand it as ours
2755 + update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
2756 + if (!get_settings('feedwordpress_rpc_secret')) :
2757 + update_option('feedwordpress_rpc_secret', substr(md5(uniqid(microtime())), 0, 6));
2758 + endif;
2759 + endif;
2760 + endif;
2761 + endif;
2762 + return $ret;
2763 + }
2764 +
2765 +
2766 + function upgrade_database ($from = NULL) {
2767 + global $wpdb;
2768 +
2769 + if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
2770 +
2771 + switch ($from) :
2772 + case 0.96: // account for changes to syndication custom values and guid
2773 + echo "<p>Upgrading database from {$from} to ".FEEDWORDPRESS_VERSION."...</p>\n";
2774 +
2775 + $cat_id = FeedWordPress::link_category_id();
2776 +
2777 + // Avoid duplicates
2778 + $wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key = 'syndication_feed_id'");
2779 +
2780 + // Look up all the link IDs
2781 + $wpdb->query("
2782 + CREATE TEMPORARY TABLE tmp_custom_values
2783 + SELECT
2784 + NULL AS meta_id,
2785 + post_id,
2786 + 'syndication_feed_id' AS meta_key,
2787 + link_id AS meta_value
2788 + FROM `{$wpdb->postmeta}`, `{$wpdb->links}`
2789 + WHERE
2790 + meta_key='syndication_feed'
2791 + AND meta_value=link_rss
2792 + AND link_category = {$cat_id}
2793 + ");
2794 +
2795 + // Now attach them to their posts
2796 + $wpdb->query("INSERT INTO `{$wpdb->postmeta}` SELECT * FROM tmp_custom_values");
2797 +
2798 + // And clean up after ourselves.
2799 + $wpdb->query("DROP TABLE tmp_custom_values");
2800 +
2801 + // Now fix the guids to avoid duplicate posts
2802 + echo "<ul>";
2803 + foreach ($this->feeds as $feed) :
2804 + echo "<li>Fixing post meta-data for <cite>".$feed['link/name']."</cite> &#8230; "; flush();
2805 + $rss = @fetch_rss($feed['link/uri']);
2806 + if (is_array($rss->items)) :
2807 + foreach ($rss->items as $item) :
2808 + $guid = $wpdb->escape(FeedWordPress::guid($item, $feed)); // new GUID algorithm
2809 + $link = $wpdb->escape($item['link']);
2810 +
2811 + $wpdb->query("
2812 + UPDATE `{$wpdb->posts}` SET guid='{$guid}' WHERE guid='{$link}'
2813 + ");
2814 + endforeach;
2815 + endif;
2816 + echo "<strong>complete.</strong></li>\n";
2817 + endforeach;
2818 + echo "</ul>\n";
2819 +
2820 + // Mark the upgrade as successful.
2821 + update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
2822 + endswitch;
2823 + echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
2824 + } /* FeedWordPress::upgrade_database() */
2825 +
1247 2826 } // class FeedWordPress
1248 2827
1249 -# -- Inbound XML-RPC plugin interface
2828 +################################################################################
2829 +## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
2830 +################################################################################
2831 +
1250 2832 function feedwordpress_xmlrpc_hook ($args = array ()) {
1251 2833 $args['weblogUpdates.ping'] = 'feedwordpress_pong';
1252 2834 return $args;
1253 2835 }
@@ -1265,8 +2847,12 @@
1265 2847 return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
1266 2848 endif;
1267 2849 }
1268 2850
2851 +################################################################################
2852 +## class FeedFinder: find likely feeds using autodetection and/or guesswork ####
2853 +################################################################################
2854 +
1269 2855 class FeedFinder {
1270 2856 var $uri = NULL;
1271 2857 var $_cache_uri = NULL;
1272 2858
@@ -1347,26 +2933,25 @@
1347 2933 function _get ($uri = NULL) {
1348 2934 if ($uri) $this->uri = $uri;
1349 2935
1350 2936 // Is the result not yet cached?
1351 - if ($this->_cache_uri !== $this->uri) {
1352 - // Retrieve, with headers, using cURL
1353 - $ch = curl_init($this->uri);
1354 - curl_setopt($ch, CURLOPT_HEADER, false);
1355 - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
1356 - curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: close'));
1357 - curl_setopt($ch, CURLOPT_HTTPHEADER, array('User-Agent: feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress'));
1358 - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1359 - curl_setopt($ch, CURLOPT_TIMEOUT, 15);
1360 - $response = curl_exec($ch);
1361 - curl_close($ch);
2937 + if ($this->_cache_uri !== $this->uri) :
2938 + // Snoopy is an HTTP client in PHP
2939 + $client = new Snoopy();
2940 +
2941 + // Prepare headers and internal settings
2942 + $client->rawheaders['Connection'] = 'close';
2943 + $client->accept = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
2944 + $client->agent = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
2945 + $client->read_timeout = 25;
2946 +
2947 + // Fetch the HTML or feed
2948 + @$client->fetch($this->uri);
2949 + $this->_data = $client->results;
1362 2950
1363 - // Split into headers and content
1364 - $this->_data = $response;
1365 -
1366 - // Kilroy was here
1367 - $this->_cache_uri = $this->uri;
1368 - } /* if */
2951 + // Kilroy was here
2952 + $this->_cache_uri = $this->uri;
2953 + endif;
1369 2954 } /* FeedFinder::_get () */
1370 2955
1371 2956 function _link_rel_feeds () {
1372 2957 $links = $this->_tags('link');
@@ -1451,9 +3036,9 @@
1451 3036 $url = Relative_URI::_encode(trim($url));
1452 3037 $parts = Relative_URI::_parse_url($url);
1453 3038
1454 3039 $uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
1455 - $uri_parts['query'] = $parts['query'];
3040 + $uri_parts['query'] = (isset($parts['query']) ? $parts['query'] : null);
1456 3041
1457 3042 // if path is empty, and scheme, host, and query are undefined,
1458 3043 // the URL is referring the base URL
1459 3044
@@ -1596,5 +3181,32 @@
1596 3181 // remove any character outside the hex range: 21 - 7E (see www.asciitable.com)
1597 3182 return preg_replace('/[^\x21-\x7e]/', '', $encoded);
1598 3183 }
1599 3184 }
3185 +
3186 +// take your best guess at the realname and e-mail, given a string
3187 +define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
3188 +define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');
3189 +define('FWP_REGEX_EMAIL_POSTFIX_NAME', "/^\s*".FWP_REGEX_EMAIL_ADDY."\s+\(".FWP_REGEX_EMAIL_NAME."\)\s*$/");
3190 +define('FWP_REGEX_EMAIL_PREFIX_NAME', "/^\s*".FWP_REGEX_EMAIL_NAME."\s*<".FWP_REGEX_EMAIL_ADDY.">\s*$/");
3191 +define('FWP_REGEX_EMAIL_JUST_ADDY', "/^\s*".FWP_REGEX_EMAIL_ADDY."\s*$/");
3192 +define('FWP_REGEX_EMAIL_JUST_NAME', "/^\s*".FWP_REGEX_EMAIL_NAME."\s*$/");
3193 +
3194 +function parse_email_with_realname ($email) {
3195 + if (preg_match(FWP_REGEX_EMAIL_POSTFIX_NAME, $email, $matches)) :
3196 + ($ret['name'] = $matches[3]) or ($ret['name'] = $matches[2]);
3197 + $ret['email'] = $matches[1];
3198 + elseif (preg_match(FWP_REGEX_EMAIL_PREFIX_NAME, $email, $matches)) :
3199 + ($ret['name'] = $matches[2]) or ($ret['name'] = $matches[3]);
3200 + $ret['email'] = $matches[4];
3201 + elseif (preg_match(FWP_REGEX_EMAIL_JUST_ADDY, $email, $matches)) :
3202 + $ret['name'] = NULL; $ret['email'] = $matches[1];
3203 + elseif (preg_match(FWP_REGEX_EMAIL_JUST_NAME, $email, $matches)) :
3204 + $ret['email'] = NULL;
3205 + ($ret['name'] = $matches[2]) or ($ret['name'] = $matches[3]);
3206 + else :
3207 + $ret['name'] = NULL; $ret['email'] = NULL;
3208 + endif;
3209 + return $ret;
3210 +}
3211 +
1600 3212 ?>