PluginProbe
FeedWordPress / 2011.0211.2
FeedWordPress v2011.0211.2
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 | feedwordpress.php +1050 -377 2010.05282011.0211.2 View file →
@@ -2,9 +2,9 @@
2 2 /*
3 3 Plugin Name: FeedWordPress
4 4 Plugin URI: http://feedwordpress.radgeek.com/
5 5 Description: simple and flexible Atom/RSS syndication for WordPress
6 -Version: 2010.0528
6 +Version: 2011.0211.2
7 7 Author: Charles Johnson
8 8 Author URI: http://radgeek.com/
9 9 License: GPL
10 10 */
@@ -10,15 +10,16 @@
10 10 */
11 11
12 12 /**
13 13 * @package FeedWordPress
14 - * @version 2010.0528
14 + * @version 2011.0211.2
15 15 */
16 16
17 17 # This uses code derived from:
18 18 # - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
19 -# - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
19 +# - MagpieRSS by Kellan Elliot-McCrea <kellan@protest.net>
20 20 # - Ultra-Liberal Feed Finder by Mark Pilgrim <mark@diveintomark.org>
21 +# - WordPress Blog Tool and Publishing Platform <http://wordpress.org/>
21 22 # according to the terms of the GNU General Public License.
22 23 #
23 24 # INSTALLATION: see readme.txt or <http://projects.radgeek.com/install>
24 25 #
@@ -32,11 +33,15 @@
32 33 # or use a cron job.
33 34
34 35 # -- Don't change these unless you know what you're doing...
35 36
36 -define ('FEEDWORDPRESS_VERSION', '2010.0528');
37 +define ('FEEDWORDPRESS_VERSION', '2011.0211.2');
37 38 define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
38 39
40 +if (!defined('FEEDWORDPRESS_BLEG')) :
41 + define ('FEEDWORDPRESS_BLEG', true);
42 +endif;
43 +
39 44 // Defaults
40 45 define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
41 46 define ('DEFAULT_UPDATE_PERIOD', 60); // value in minutes
42 47
@@ -57,8 +62,9 @@
57 62
58 63 define ('FEEDWORDPRESS_FRESHNESS_INTERVAL', 10*60); // Every ten minutes
59 64
60 65 define ('FWP_SCHEMA_HAS_USERMETA', 2966);
66 +define ('FWP_SCHEMA_USES_ARGS_TAXONOMY', 12694); // Revision # for using $args['taxonomy'] to get link categories
61 67 define ('FWP_SCHEMA_20', 3308); // Database schema # for WP 2.0
62 68 define ('FWP_SCHEMA_21', 4772); // Database schema # for WP 2.1
63 69 define ('FWP_SCHEMA_23', 5495); // Database schema # for WP 2.3
64 70 define ('FWP_SCHEMA_25', 7558); // Database schema # for WP 2.5
@@ -65,8 +71,9 @@
65 71 define ('FWP_SCHEMA_26', 8201); // Database schema # for WP 2.6
66 72 define ('FWP_SCHEMA_27', 9872); // Database schema # for WP 2.7
67 73 define ('FWP_SCHEMA_28', 11548); // Database schema # for WP 2.8
68 74 define ('FWP_SCHEMA_29', 12329); // Database schema # for WP 2.9
75 +define ('FWP_SCHEMA_30', 12694); // Database schema # for WP 3.0
69 76
70 77 if (FEEDWORDPRESS_DEBUG) :
71 78 // Help us to pick out errors, if any.
72 79 ini_set('error_reporting', E_ALL & ~E_NOTICE);
@@ -78,15 +85,15 @@
78 85 // make sure FEEDWORDPRESS_DEBUG is FALSE for any site that will be
79 86 // used for more than testing purposes!
80 87 define('FEEDWORDPRESS_CACHE_AGE', 1);
81 88 define('FEEDWORDPRESS_CACHE_LIFETIME', 1);
82 - define('FEEDWORDPRESS_FETCH_TIME_OUT', 60);
89 + define('FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT', 60);
83 90 else :
84 91 // Hold onto data all day for conditional GET purposes,
85 92 // but consider it stale after 1 min (requiring a conditional GET)
86 93 define('FEEDWORDPRESS_CACHE_LIFETIME', 24*60*60);
87 94 define('FEEDWORDPRESS_CACHE_AGE', 1*60);
88 - define('FEEDWORDPRESS_FETCH_TIME_OUT', 10);
95 + define('FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT', 20);
89 96 endif;
90 97
91 98 // Use our the cache settings that we want.
92 99 add_filter('wp_feed_cache_transient_lifetime', array('FeedWordPress', 'cache_lifetime'));
@@ -92,33 +99,37 @@
92 99 add_filter('wp_feed_cache_transient_lifetime', array('FeedWordPress', 'cache_lifetime'));
93 100
94 101 // Ensure that we have SimplePie loaded up and ready to go.
95 102 // We no longer need a MagpieRSS upgrade module. Hallelujah!
96 -require_once(ABSPATH . WPINC . '/feed.php');
103 +if (!class_exists('SimplePie')) :
104 + require_once(ABSPATH . WPINC . '/class-simplepie.php');
105 +endif;
106 +require_once(ABSPATH . WPINC . '/class-feed.php');
97 107
98 -if (isset($wp_db_version)) :
99 - if ($wp_db_version >= FWP_SCHEMA_23) :
100 - require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
101 - elseif ($wp_db_version >= FWP_SCHEMA_21) : // WordPress 2.1 and 2.2, but not 2.3
102 - require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
103 - require_once (ABSPATH . 'wp-admin/admin-db.php'); // for wp_insert_category
104 - elseif ($wp_db_version >= FWP_SCHEMA_20) : // WordPress 2.0
105 - require_once (ABSPATH . WPINC . '/registration-functions.php'); // for wp_insert_user
106 - require_once (ABSPATH . 'wp-admin/admin-db.php'); // for wp_insert_category
107 - endif;
108 +if (!function_exists('wp_insert_user')) :
109 + require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
108 110 endif;
109 111
112 +require_once(dirname(__FILE__) . '/admin-ui.php');
113 +require_once(dirname(__FILE__) . '/feedwordpresssyndicationpage.class.php');
110 114 require_once(dirname(__FILE__) . '/compatability.php'); // LEGACY API: Replicate or mock up functions for legacy support purposes
115 +
116 +require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
117 +require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
111 118 require_once(dirname(__FILE__) . '/feedwordpresshtml.class.php');
119 +require_once(dirname(__FILE__) . '/feedwordpress-content-type-sniffer.class.php');
112 120
113 121 // Magic quotes are just about the stupidest thing ever.
114 122 if (is_array($_POST)) :
115 - $fwp_post = stripslashes_deep($_POST);
123 + $fwp_post = $_POST;
124 + if (get_magic_quotes_gpc()) :
125 + $fwp_post = stripslashes_deep($fwp_post);
126 + endif;
116 127 endif;
117 128
118 129 // Get the path relative to the plugins directory in which FWP is stored
119 130 preg_match (
120 - '|/wp-content/plugins/(.+)$|',
131 + '|'.preg_quote(WP_PLUGIN_DIR).'/(.+)$|',
121 132 dirname(__FILE__),
122 133 $ref
123 134 );
124 135
@@ -127,36 +138,23 @@
127 138 else : // Something went wrong. Let's just guess.
128 139 $fwp_path = 'feedwordpress';
129 140 endif;
130 141
131 -function feedwordpress_admin_scripts () {
132 - wp_enqueue_script('post'); // for magic tag and category boxes
133 - wp_enqueue_script('admin-forms'); // for checkbox selection
134 -}
135 -
136 142 // If this is a FeedWordPress admin page, queue up scripts for AJAX functions that FWP uses
137 143 // If it is a display page or a non-FeedWordPress admin page, don't.
138 -if (is_admin() and isset($_REQUEST['page']) and preg_match("|^{$fwp_path}/|", $_REQUEST['page'])) :
139 - if (function_exists('wp_enqueue_script')) :
140 - if (FeedWordPressCompatibility::test_version(FWP_SCHEMA_29)) :
141 - add_action('admin_print_scripts', 'feedwordpress_admin_scripts');
142 - elseif (FeedWordPressCompatibility::test_version(FWP_SCHEMA_25)) :
143 - wp_enqueue_script('post'); // for magic tag and category boxes
144 - wp_enqueue_script('thickbox'); // for fold-up boxes
145 - wp_enqueue_script('admin-forms'); // for checkbox selection
146 - else :
147 - wp_enqueue_script( 'ajaxcat' ); // Provides the handy-dandy new category text box
148 - endif;
149 - endif;
150 - if (function_exists('wp_enqueue_style')) :
151 - if (fwp_test_wp_version(FWP_SCHEMA_25)) :
152 - wp_enqueue_style('dashboard');
153 - endif;
154 - endif;
144 +wp_register_style('feedwordpress-elements', WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-elements.css');
145 +if (FeedWordPressSettingsUI::is_admin()) :
146 + // For JavaScript that needs to be generated dynamically
147 + add_action('admin_print_scripts', array('FeedWordPressSettingsUI', 'admin_scripts'));
148 +
149 + // For CSS that needs to be generated dynamically.
150 + add_action('admin_print_styles', array('FeedWordPressSettingsUI', 'admin_styles'));
151 +
152 + wp_enqueue_style('dashboard');
153 + wp_enqueue_style('feedwordpress-elements');
154 +
155 155 if (function_exists('wp_admin_css')) :
156 - if (fwp_test_wp_version(FWP_SCHEMA_25)) :
157 - wp_admin_css('css/dashboard');
158 - endif;
156 + wp_admin_css('css/dashboard');
159 157 endif;
160 158 endif;
161 159
162 160 if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
@@ -179,9 +177,9 @@
179 177
180 178 add_action('atom_entry', 'feedwordpress_item_feed_data');
181 179
182 180 # Filter in original permalinks if the user wants that
183 - add_filter('post_link', 'syndication_permalink', 1);
181 + add_filter('post_link', 'syndication_permalink', /*priority=*/ 1, /*arguments=*/ 3);
184 182
185 183 # When foreign URLs are used for permalinks in feeds or display
186 184 # contexts, they need to be escaped properly.
187 185 add_filter('the_permalink', 'syndication_permalink_escaped');
@@ -202,11 +200,13 @@
202 200
203 201 add_action('admin_menu', 'feedwordpress_add_post_edit_controls');
204 202 add_action('save_post', 'feedwordpress_save_post_edit_controls');
205 203
204 + add_action('admin_footer', array('FeedWordPress', 'admin_footer'));
205 +
206 206 # Inbound XML-RPC update methods
207 - add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
208 -
207 + $feedwordpressRPC = new FeedWordPressRPC;
208 +
209 209 # Outbound XML-RPC ping reform
210 210 remove_action('publish_post', 'generic_ping'); // WP 1.5.x
211 211 remove_action('do_pings', 'do_all_pings', 10, 1); // WP 2.1, 2.2
212 212 remove_action('publish_post', '_publish_post_hook', 5, 1); // WP 2.3
@@ -215,39 +215,25 @@
215 215 add_action('do_pings', 'fwp_do_pings', 10, 1);
216 216 add_action('feedwordpress_update', 'fwp_hold_pings');
217 217 add_action('feedwordpress_update_complete', 'fwp_release_pings');
218 218
219 - # Hook in logging functions only if the logging option is ON
220 - $update_logging = get_option('feedwordpress_update_logging');
221 - if ($update_logging == 'yes') :
222 - add_action('post_syndicated_item', 'log_feedwordpress_post', 100);
223 - add_action('update_syndicated_item', 'log_feedwordpress_update_post', 100);
224 - add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
225 - add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
226 - add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
227 - endif;
219 + add_action('syndicated_feed_error', array('FeedWordPressDiagnostic', 'feed_error'), 100, 3);
220 +
221 + add_action('wp_footer', 'debug_out_feedwordpress_footer', -100);
222 + add_action('admin_footer', 'debug_out_feedwordpress_footer', -100);
228 223
229 - if (FeedWordPress::update_requested()) :
230 - if (FEEDWORDPRESS_DEBUG) :
231 - add_action('post_syndicated_item', 'debug_out_feedwordpress_post', 100);
232 - add_action('update_syndicated_item', 'debug_out_feedwordpress_update_post', 100);
233 - add_action('feedwordpress_update', 'debug_out_feedwordpress_update_feeds', 100);
234 - add_action('feedwordpress_check_feed', 'debug_out_feedwordpress_check_feed', 100);
235 - add_action('feedwordpress_update_complete', 'debug_out_feedwordpress_update_complete', 100);
236 - endif;
224 + $feedwordpress = new FeedWordPress;
237 225
238 - add_action('feedwordpress_check_feed_complete', 'debug_out_feedwordpress_feed_error', 100, 3);
239 - endif;
240 -
241 226 # Cron-less auto-update. Hooray!
242 227 $autoUpdateHook = get_option('feedwordpress_automatic_updates');
243 228 if ($autoUpdateHook != 'init') :
244 229 $autoUpdateHook = 'shutdown';
245 230 endif;
246 - add_action($autoUpdateHook, 'feedwordpress_auto_update');
231 + add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
232 + add_action('init', array(&$feedwordpress, 'init'));
233 + add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
234 + add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
247 235
248 - add_action('init', 'feedwordpress_update_magic_url');
249 -
250 236 # Default sanitizers
251 237 add_filter('syndicated_item_content', array('SyndicatedPost', 'resolve_relative_uris'), 0, 2);
252 238 add_filter('syndicated_item_content', array('SyndicatedPost', 'sanitize_content'), 0, 2);
253 239
@@ -255,127 +241,78 @@
255 241 # Hook in the menus, which will just point to the upgrade interface
256 242 add_action('admin_menu', 'fwp_add_pages');
257 243 endif; // if (!FeedWordPress::needs_upgrade())
258 244
259 -function feedwordpress_auto_update () {
260 - if (FeedWordPress::stale()) :
261 - $feedwordpress = new FeedWordPress;
262 - $feedwordpress->update();
263 - endif;
264 -} /* feedwordpress_auto_update () */
265 -
266 -function feedwordpress_update_magic_url () {
267 - global $wpdb;
268 -
269 - // Explicit update request in the HTTP request (e.g. from a cron job)
270 - if (FeedWordPress::update_requested()) :
271 - $feedwordpress = new FeedWordPress;
272 - $feedwordpress->update(FeedWordPress::update_requested_url());
273 -
274 - if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
275 - $mysqlTime = 0.0;
276 - $byTime = array();
277 - foreach ($wpdb->queries as $query) :
278 - $time = $query[1] * 1000000.0;
279 - $mysqlTime += $query[1];
280 - if (!isset($byTime[$time])) : $byTime[$time] = array(); endif;
281 - $byTime[$time][] = $query[0]. ' // STACK: ' . $query[2];
282 - endforeach;
283 - krsort($byTime);
284 -
285 - foreach ($byTime as $time => $querySet) :
286 - foreach ($querySet as $query) :
287 - print "[".(sprintf('%4.4f', $time/1000.0)) . "ms] $query\n";
288 - endforeach;
289 - endforeach;
290 - echo "[feedwordpress] $wpdb->num_queries queries. $mysqlTime seconds in MySQL. Total of "; timer_stop(1); print " seconds.";
291 - endif;
292 -
293 -
294 - // Magic URL should return nothing but a 200 OK header packet
295 - // when successful.
296 - exit;
297 - endif;
298 -} /* feedwordpress_magic_update_url () */
299 -
300 245 ################################################################################
301 246 ## LOGGING FUNCTIONS: log status updates to error_log if you want it ###########
302 247 ################################################################################
303 248
304 -function log_feedwordpress_post ($id) {
305 - $post = wp_get_single_post($id);
306 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
307 - ."'{$post->post_title}' ({$post->post_date})");
308 -}
249 +class FeedWordPressDiagnostic {
250 + function feed_error ($error, $old, $link) {
251 + $wpError = $error['object'];
252 + $url = $link->uri();
253 +
254 + $mesgs = $wpError->get_error_messages();
255 + foreach ($mesgs as $mesg) :
256 + $mesg = esc_html($mesg);
257 + FeedWordPress::diagnostic(
258 + 'updated_feeds:errors',
259 + "Feed Error: [${url}] update returned error: $mesg"
260 + );
261 +
262 + $hours = get_option('feedwordpress_diagnostics_persistent_errors_hours', 2);
263 + $span = ($error['ts'] - $error['since']);
309 264
310 -function log_feedwordpress_update_post ($id) {
311 - $post = wp_get_single_post($id);
312 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
313 - ."'{$post->post_title}' ({$post->post_date})"
314 - ." (as of {$post->post_modified})");
315 -}
265 + if ($span >= ($hours * 60 * 60)) :
266 + $since = date('r', $error['since']);
267 + $mostRecent = date('r', $error['ts']);
268 + FeedWordPress::diagnostic(
269 + 'updated_feeds:errors:persistent',
270 + "Feed Update Error: [${url}] returning errors"
271 + ." since ${since}:<br/><code>$mesg</code>",
272 + $url, $error['since'], $error['ts']
273 + );
274 + endif;
275 + endforeach;
276 + }
316 277
317 -function log_feedwordpress_update_feeds ($uri) {
318 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
319 -}
278 + function admin_emails ($id = '') {
279 + $users = get_users_of_blog($id);
280 + $recipients = array();
281 + foreach ($users as $user) :
282 + $user_id = (isset($user->user_id) ? $user->user_id : $user->ID);
283 + $dude = new WP_User($user_id);
284 + if ($dude->has_cap('administrator')) :
285 + if ($dude->user_email) :
286 + $recipients[] = $dude->user_email;
287 + endif;
288 + endif;
289 + endforeach;
290 + return $recipients;
291 + }
292 +} /* class FeedWordPressDiagnostic */
320 293
321 -function log_feedwordpress_check_feed ($feed) {
322 - $uri = $feed['link/uri']; $name = $feed['link/name'];
323 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
294 +function debug_out_human_readable_bytes ($quantity) {
295 + $quantity = (int) $quantity;
296 + $magnitude = 'B';
297 + $orders = array('KB', 'MB', 'GB', 'TB');
298 + while (($quantity > (1024*100)) and (count($orders) > 0)) :
299 + $quantity = floor($quantity / 1024);
300 + $magnitude = array_shift($orders);
301 + endwhile;
302 + return "${quantity} ${magnitude}";
324 303 }
325 304
326 -function log_feedwordpress_update_complete ($delta) {
327 - $mesg = array();
328 - if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
329 - if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
330 - if (empty($mesg)) $mesg[] = 'nothing changed';
331 -
332 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
333 - .(is_null($delta) ? "Error: I don't syndicate that URI"
334 - : implode(' and ', $mesg)));
335 -}
336 -
337 -function debug_out_feedwordpress_post ($id) {
338 - $post = wp_get_single_post($id);
339 - print ("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
340 - ."'{$post->post_title}' ({$post->post_date})\n");
341 -}
342 -
343 -function debug_out_feedwordpress_update_post ($id) {
344 - $post = wp_get_single_post($id);
345 - print ("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
346 - ."'{$post->post_title}' ({$post->post_date})"
347 - ." (as of {$post->post_modified})\n");
348 -}
349 -
350 -function debug_out_feedwordpress_update_feeds ($uri) {
351 - print ("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')\n");
352 -}
353 -
354 -function debug_out_feedwordpress_check_feed ($feed) {
355 - $uri = $feed['link/uri']; $name = $feed['link/name'];
356 - print ("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>\n");
357 -}
358 -
359 -function debug_out_feedwordpress_update_complete ($delta) {
360 - $mesg = array();
361 - if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
362 - if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
363 - if (empty($mesg)) $mesg[] = 'nothing changed';
364 -
365 - print ("[".date('Y-m-d H:i:s')."][feedwordpress] "
366 - .(is_null($delta) ? "Error: I don't syndicate that URI"
367 - : implode(' and ', $mesg))."\n");
368 -}
369 -
370 -function debug_out_feedwordpress_feed_error ($feed, $added, $dt) {
371 - if (is_wp_error($added)) :
372 - $mesgs = $added->get_error_messages();
373 - foreach ($mesgs as $mesg) :
374 - echo "[feedwordpress] Error updating [{$feed['link/uri']}]: $mesg\n";
375 - endforeach;
305 +function debug_out_feedwordpress_footer () {
306 + if (FeedWordPress::diagnostic_on('memory_usage')) :
307 + if (function_exists('memory_get_usage')) :
308 + FeedWordPress::diagnostic ('memory_usage', "Memory: Current usage: ".debug_out_human_readable_bytes(memory_get_usage()));
309 + endif;
310 + if (function_exists('memory_get_peak_usage')) :
311 + FeedWordPress::diagnostic ('memory_usage', "Memory: Peak usage: ".debug_out_human_readable_bytes(memory_get_peak_usage()));
312 + endif;
376 313 endif;
377 -}
314 +} /* debug_out_feedwordpress_footer() */
378 315
379 316 ################################################################################
380 317 ## TEMPLATE API: functions to make your templates syndication-aware ############
381 318 ################################################################################
@@ -392,34 +329,16 @@
392 329 function is_syndicated ($id = NULL) {
393 330 return (strlen(get_syndication_feed_id($id)) > 0);
394 331 } /* function is_syndicated() */
395 332
396 -function get_syndication_source_link ($original = NULL, $id = NULL) {
397 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
398 - endif;
399 -
400 - if ($original) : $vals = get_post_custom_values('syndication_source_uri_original', $id);
401 - else : $vals = array();
402 - endif;
403 -
404 - if (count($vals) == 0) : $vals = get_post_custom_values('syndication_source_uri', $id);
405 - endif;
406 -
407 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
408 -
409 - return $ret;
410 -} /* function get_syndication_source_link() */
411 -
412 -function the_syndication_source_link ($original = NULL, $id = NULL) {
413 - echo get_syndication_source_link($original, $id);
414 -}
415 -
416 333 function feedwordpress_display_url ($url, $before = 60, $after = 0) {
417 334 $bits = parse_url($url);
418 335
419 336 // Strip out crufty subdomains
420 - $bits['host'] = preg_replace('/^www[0-9]*\./i', '', $bits['host']);
421 -
337 + if (isset($bits['host'])) :
338 + $bits['host'] = preg_replace('/^www[0-9]*\./i', '', $bits['host']);
339 + endif;
340 +
422 341 // Reassemble bit-by-bit with minimum of crufty elements
423 342 $url = (isset($bits['user'])?$bits['user'].'@':'')
424 343 .(isset($bits['host'])?$bits['host']:'')
425 344 .(isset($bits['path'])?$bits['path']:'')
@@ -430,77 +349,59 @@
430 349 $url = substr($url, 0, $before).'…'.substr($url, 0 - $after, $after);
431 350 endif;
432 351
433 352 return $url;
434 -}
353 +} /* feedwordpress_display_url () */
435 354
436 -function get_syndication_source ($original = NULL, $id = NULL) {
355 +function get_syndication_source_property ($original, $id, $local, $remote = NULL) {
356 + $ret = NULL;
437 357 if (is_null($original)) :
438 358 $original = FeedWordPress::use_aggregator_source_data();
439 359 endif;
440 -
441 - if ($original) :
442 - $vals = get_post_custom_values('syndication_source_original', $id);
443 - else :
444 - $vals = array();
360 +
361 + if (is_null($remote)) :
362 + $remote = $local . '_original';
445 363 endif;
446 364
447 - if (count($vals) == 0) :
448 - $vals = get_post_custom_values('syndication_source', $id);
365 + $vals = ($original ? get_post_custom_values($remote, $id) : array());
366 + if (count($vals) < 1) :
367 + $vals = get_post_custom_values($local, $id);
449 368 endif;
450 369
451 370 if (count($vals) > 0) :
452 371 $ret = $vals[0];
453 - else :
454 - $ret = NULL;
455 372 endif;
373 + return $ret;
374 +} /* function get_syndication_source_property () */
456 375
457 - if (is_null($ret) or strlen(trim($ret)) == 0) :
458 - // Fall back to URL of blog
376 +function the_syndication_source_link ($original = NULL, $id = NULL) { echo get_syndication_source_link($original, $id); }
377 +function get_syndication_source_link ($original = NULL, $id = NULL) {
378 + return get_syndication_source_property($original, $id, 'syndication_source_uri');
379 +} /* function get_syndication_source_link() */
380 +
381 +function the_syndication_source ($original = NULL, $id = NULL) { echo get_syndication_source($original, $id); }
382 +function get_syndication_source ($original = NULL, $id = NULL) {
383 + $ret = get_syndication_source_property($original, $id, 'syndication_source');
384 + if (is_null($ret) or strlen(trim($ret)) == 0) : // Fall back to URL of blog
459 385 $ret = feedwordpress_display_url(get_syndication_source_link());
460 386 endif;
461 -
462 387 return $ret;
463 388 } /* function get_syndication_source() */
464 389
465 -function the_syndication_source ($original = NULL, $id = NULL) { echo get_syndication_source($original, $id); }
466 -
390 +function the_syndication_feed ($original = NULL, $id = NULL) { echo get_syndication_feed($original, $id); }
467 391 function get_syndication_feed ($original = NULL, $id = NULL) {
468 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
469 - endif;
470 -
471 - if ($original) : $vals = get_post_custom_values('syndication_feed_original', $id);
472 - else : $vals = array();
473 - endif;
474 -
475 - if (count($vals) == 0) : $vals = get_post_custom_values('syndication_feed', $id);
476 - endif;
477 -
478 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
479 -
480 - return $ret;
392 + return get_syndication_source_property($original, $id, 'syndication_feed');
481 393 } /* function get_syndication_feed() */
482 394
483 -function the_syndication_feed ($original = NULL, $id = NULL) { echo get_syndication_feed($original, $id); }
484 -
395 +function the_syndication_feed_guid ($original = NULL, $id = NULL) { echo get_syndication_feed_guid($original, $id); }
485 396 function get_syndication_feed_guid ($original = NULL, $id = NULL) {
486 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
397 + $ret = get_syndication_source_property($original, $id, 'syndication_source_id');
398 + if (is_null($ret) or strlen(trim($ret))==0) : // Fall back to URL of feed
399 + $ret = get_syndication_feed();
487 400 endif;
488 -
489 - if ($original) : $vals = get_post_custom_values('syndication_source_id_original', $id);
490 - else : $vals = array();
491 - endif;
492 -
493 - if (count($vals) == 0) : $vals = array(get_feed_meta('feed/id', $id));
494 - endif;
495 -
496 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
497 -
498 401 return $ret;
499 402 } /* function get_syndication_feed_guid () */
500 403
501 -function the_syndication_feed_guid ($original = NULL, $id = NULL) { echo get_syndication_feed_guid($original, $id); }
502 -
503 404 function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_values('syndication_feed_id', $id); return $u; }
504 405 function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
505 406
506 407 $feedwordpress_linkcache = array (); // only load links from database once
@@ -647,30 +548,43 @@
647 548 * @return string The new permalink. Same as the old if the post is not
648 549 * syndicated, or if FWP is set to use internal permalinks, or if the post
649 550 * was syndicated, but didn't have a proper permalink recorded.
650 551 *
651 - * @uses FeedWordPress::munge_permalinks()
552 + * @uses SyndicatedLink::setting()
652 553 * @uses get_syndication_permalink()
554 + * @uses get_syndication_feed_object()
555 + * @uses url_to_postid()
556 + * @global $id
653 557 * @global $feedwordpress_the_original_permalink
654 - */
655 -function syndication_permalink ($permalink = '') {
558 + */
559 +function syndication_permalink ($permalink = '', $post = null, $leavename = false) {
560 + global $id;
656 561 global $feedwordpress_the_original_permalink;
657 562
658 563 // Save the local permalink in case we need to retrieve it later.
659 564 $feedwordpress_the_original_permalink = $permalink;
660 565
661 - // Map this permalink to a post ID so we can get the correct permalink
662 - // even outside of the Post Loop. Props Björn.
663 - $id = url_to_postid($permalink);
566 + if (is_object($post) and isset($post->ID) and !empty($post->ID)) :
567 + // Use the post ID we've been provided with.
568 + $postId = $post->ID;
569 + elseif (is_string($permalink) and strlen($permalink) > 0) :
570 + // Map this permalink to a post ID so we can get the correct
571 + // permalink even outside of the Post Loop. Props Björn.
572 + $postId = url_to_postid($permalink);
573 + else :
574 + // If the permalink string is empty but Post Loop context
575 + // provides an id.
576 + $postId = $id;
577 + endif;
664 578
665 579 $munge = false;
666 - $link = get_syndication_feed_object($id);
580 + $link = get_syndication_feed_object($postId);
667 581 if (is_object($link)) :
668 582 $munge = ($link->setting('munge permalink', 'munge_permalink', 'yes') != 'no');
669 583 endif;
670 584
671 585 if ($munge):
672 - $uri = get_syndication_permalink($id);
586 + $uri = get_syndication_permalink($postId);
673 587 $permalink = ((strlen($uri) > 0) ? $uri : $permalink);
674 588 endif;
675 589 return $permalink;
676 590 } /* function syndication_permalink () */
@@ -686,8 +600,9 @@
686 600 * @uses FeedWordPress::munge_permalinks()
687 601 *
688 602 */
689 603 function syndication_permalink_escaped ($permalink) {
604 + /* FIXME: This should review link settings not just global settings */
690 605 if (is_syndicated() and FeedWordPress::munge_permalinks()) :
691 606 // This is a foreign link; WordPress can't vouch for its not
692 607 // having any entities that need to be &-escaped. So we'll do
693 608 // it here.
@@ -764,23 +679,55 @@
764 679 ## ADMIN MENU ADD-ONS: register Dashboard management pages #####################
765 680 ################################################################################
766 681
767 682 function fwp_add_pages () {
768 - global $fwp_capability;
769 - global $fwp_path;
683 + $menu_cap = FeedWordPress::menu_cap();
684 + $settings_cap = FeedWordPress::menu_cap(/*sub=*/ true);
685 + $syndicationMenu = FeedWordPress::path('syndication.php');
686 +
687 + add_menu_page(
688 + 'Syndicated Sites', 'Syndication',
689 + $menu_cap,
690 + $syndicationMenu,
691 + NULL,
692 + WP_PLUGIN_URL.'/'.FeedWordPress::path('feedwordpress-tiny.png')
693 + );
770 694
771 - $menu = array('Syndicated Sites', 'Syndication', $fwp_capability['manage_links'], $fwp_path.'/syndication.php', NULL);
772 - if (fwp_test_wp_version(FWP_SCHEMA_27)) :
773 - // add icon parameter
774 - $menu[] = WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-tiny.png';
775 - endif;
695 + do_action('feedwordpress_admin_menu_pre_feeds', $menu_cap, $settings_cap);
696 + add_submenu_page(
697 + $syndicationMenu, 'Syndicated Feeds & Updates', 'Feeds & Updates',
698 + $settings_cap, FeedWordPress::path('feeds-page.php')
699 + );
776 700
777 - call_user_func_array('add_menu_page', $menu);
778 - add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Feeds & Updates', 'Feeds & Updates', $fwp_capability['manage_options'], $fwp_path.'/feeds-page.php');
779 - add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Posts & Links', 'Posts & Links', $fwp_capability['manage_options'], $fwp_path.'/posts-page.php');
780 - add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Authors', 'Authors', $fwp_capability['manage_options'], $fwp_path.'/authors-page.php');
781 - add_submenu_page($fwp_path.'/syndication.php', 'Categories'.FEEDWORDPRESS_AND_TAGS, 'Categories'.FEEDWORDPRESS_AND_TAGS, $fwp_capability['manage_options'], $fwp_path.'/categories-page.php');
782 - add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Back End', 'Back End', $fwp_capability['manage_options'], $fwp_path.'/backend-page.php');
701 + do_action('feedwordpress_admin_menu_pre_posts', $menu_cap, $settings_cap);
702 + add_submenu_page(
703 + $syndicationMenu, 'Syndicated Posts & Links', 'Posts & Links',
704 + $settings_cap, FeedWordPress::path('posts-page.php')
705 + );
706 +
707 + do_action('feedwordpress_admin_menu_pre_authors', $menu_cap, $settings_cap);
708 + add_submenu_page(
709 + $syndicationMenu, 'Syndicated Authors', 'Authors',
710 + $settings_cap, FeedWordPress::path('authors-page.php')
711 + );
712 +
713 + do_action('feedwordpress_admin_menu_pre_categories', $menu_cap, $settings_cap);
714 + add_submenu_page(
715 + $syndicationMenu, 'Categories'.FEEDWORDPRESS_AND_TAGS, 'Categories'.FEEDWORDPRESS_AND_TAGS,
716 + $settings_cap, FeedWordPress::path('categories-page.php')
717 + );
718 +
719 + do_action('feedwordpress_admin_menu_pre_performance', $menu_cap, $settings_cap);
720 + add_submenu_page(
721 + $syndicationMenu, 'FeedWordPress Performance', 'Performance',
722 + $settings_cap, FeedWordPress::path('performance-page.php')
723 + );
724 +
725 + do_action('feedwordpress_admin_menu_pre_diagnostics', $menu_cap, $settings_cap);
726 + add_submenu_page(
727 + $syndicationMenu, 'FeedWordPress Diagnostics', 'Diagnostics',
728 + $settings_cap, FeedWordPress::path('diagnostics-page.php')
729 + );
783 730 } /* function fwp_add_pages () */
784 731
785 732 function fwp_check_debug () {
786 733 // This is a horrible fucking kludge that I have to do because the
@@ -909,14 +856,16 @@
909 856 endif;
910 857
911 858 // OK, we're golden. Now let's save some data.
912 859 if (isset($_POST['freeze_updates'])) :
913 - update_post_meta($post_id, '_syndication_freeze_updates', $_POST['freeze_updates']);
860 + update_post_meta($post_id, '_syndication_freeze_updates', $_POST['freeze_updates']);
861 + $ret = $_POST['freeze_updates'];
914 862 else :
915 863 delete_post_meta($post_id, '_syndication_freeze_updates');
864 + $ret = NULL;
916 865 endif;
917 866
918 - return $_POST['freeze_updates'];
867 + return $ret;
919 868 } // function feedwordpress_save_edit_controls
920 869
921 870 ################################################################################
922 871 ## class FeedWordPress #########################################################
@@ -1022,9 +971,9 @@
1022 971 if (FeedWordPress::needs_upgrade()) : // Will make duplicate posts if we don't hold off
1023 972 return NULL;
1024 973 endif;
1025 974
1026 - if (!is_null($uri)) :
975 + if (!is_null($uri) and $uri != '*') :
1027 976 $uri = trim($uri);
1028 977 else : // Update all
1029 978 update_option('feedwordpress_last_update_all', time());
1030 979 endif;
@@ -1031,20 +980,17 @@
1031 980
1032 981 do_action('feedwordpress_update', $uri);
1033 982
1034 983 if (is_null($crash_ts)) :
1035 - $crash_dt = (int) get_option('feedwordpress_update_time_limit');
1036 - if ($crash_dt > 0) :
1037 - $crash_ts = time() + $crash_dt;
1038 - else :
1039 - $crash_ts = NULL;
1040 - endif;
984 + $crash_ts = $this->crash_ts();
1041 985 endif;
1042 -
986 +
1043 987 // Randomize order for load balancing purposes
1044 988 $feed_set = $this->feeds;
1045 989 shuffle($feed_set);
1046 990
991 + $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri);
992 +
1047 993 // Loop through and check for new posts
1048 994 $delta = NULL;
1049 995 foreach ($feed_set as $feed) :
1050 996 if (!is_null($crash_ts) and (time() > $crash_ts)) : // Check whether we've exceeded the time limit
@@ -1058,9 +1004,9 @@
1058 1004 else :
1059 1005 $timely = $feed->stale();
1060 1006 endif;
1061 1007
1062 - if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
1008 + if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
1063 1009 $delta = array('new' => 0, 'updated' => 0); // ... don't return error condition
1064 1010 endif;
1065 1011
1066 1012 if ($pinged_that and $timely) :
@@ -1080,8 +1026,18 @@
1080 1026
1081 1027 return $delta;
1082 1028 }
1083 1029
1030 + function crash_ts ($default = NULL) {
1031 + $crash_dt = (int) get_option('feedwordpress_update_time_limit', 0);
1032 + if ($crash_dt > 0) :
1033 + $crash_ts = time() + $crash_dt;
1034 + else :
1035 + $crash_ts = $default;
1036 + endif;
1037 + return $crash_ts;
1038 + }
1039 +
1084 1040 function stale () {
1085 1041 if (get_option('feedwordpress_automatic_updates')) :
1086 1042 // Do our best to avoid possible simultaneous
1087 1043 // updates by getting up-to-the-minute settings.
@@ -1110,9 +1066,122 @@
1110 1066 $ret = false;
1111 1067 endif;
1112 1068 return $ret;
1113 1069 } // FeedWordPress::stale()
1070 +
1071 + function init () {
1072 + $this->clear_cache_magic_url();
1073 + $this->update_magic_url();
1074 + } /* FeedWordPress::init() */
1114 1075
1076 + function dashboard_setup () {
1077 + $see_it = FeedWordPress::menu_cap();
1078 +
1079 + if (current_user_can($see_it)) :
1080 + // Get the stylesheet
1081 + wp_enqueue_style('feedwordpress-elements');
1082 +
1083 + $widget_id = 'feedwordpress_dashboard';
1084 + $widget_name = __('Syndicated Sources');
1085 + $column = 'side';
1086 + $priority = 'core';
1087 +
1088 + // I would love to use wp_add_dashboard_widget() here and save
1089 + // myself some trouble. But WP 3 does not yet have any way to
1090 + // push a dashboard widget onto the side, or to give it a default
1091 + // location.
1092 + add_meta_box(
1093 + /*id=*/ $widget_id,
1094 + /*title=*/ $widget_name,
1095 + /*callback=*/ array(&$this, 'dashboard'),
1096 + /*page=*/ 'dashboard',
1097 + /*context=*/ $column,
1098 + /*priority=*/ $priority
1099 + );
1100 + /*control_callback= array(&$this, 'dashboard_control') */
1101 +
1102 + // This is kind of rude, I know, but the dashboard widget isn't
1103 + // worth much if users don't know that it exists, and I don't
1104 + // know of any better way to reorder the boxen.
1105 + //
1106 + // Gleefully ripped off of codex.wordpress.org/Dashboard_Widgets_API
1107 +
1108 + // Globalize the metaboxes array, this holds all the widgets for wp-admin
1109 + global $wp_meta_boxes;
1110 +
1111 + // Get the regular dashboard widgets array
1112 + // (which has our new widget already but at the end)
1113 +
1114 + $normal_dashboard = $wp_meta_boxes['dashboard'][$column][$priority];
1115 +
1116 + // Backup and delete our new dashbaord widget from the end of the array
1117 + if (isset($normal_dashboard[$widget_id])) :
1118 + $backup = array();
1119 + $backup[$widget_id] = $normal_dashboard[$widget_id];
1120 + unset($normal_dashboard[$widget_id]);
1121 +
1122 + // Merge the two arrays together so our widget is at the
1123 + // beginning
1124 + $sorted_dashboard = array_merge($backup, $normal_dashboard);
1125 +
1126 + // Save the sorted array back into the original metaboxes
1127 + $wp_meta_boxes['dashboard'][$column][$priority] = $sorted_dashboard;
1128 + endif;
1129 + endif;
1130 + } /* FeedWordPress::dashboard_setup () */
1131 +
1132 + function dashboard () {
1133 + $syndicationPage = new FeedWordPressSyndicationPage(dirname(__FILE__).'/syndication.php');
1134 + $syndicationPage->dashboard_box($syndicationPage);
1135 + } /* FeedWordPress::dashboard () */
1136 +
1137 + function update_magic_url () {
1138 + global $wpdb;
1139 +
1140 + // Explicit update request in the HTTP request (e.g. from a cron job)
1141 + if ($this->update_requested()) :
1142 + $this->update($this->update_requested_url());
1143 +
1144 + if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
1145 + $mysqlTime = 0.0;
1146 + $byTime = array();
1147 + foreach ($wpdb->queries as $query) :
1148 + $time = $query[1] * 1000000.0;
1149 + $mysqlTime += $query[1];
1150 + if (!isset($byTime[$time])) : $byTime[$time] = array(); endif;
1151 + $byTime[$time][] = $query[0]. ' // STACK: ' . $query[2];
1152 + endforeach;
1153 + krsort($byTime);
1154 +
1155 + foreach ($byTime as $time => $querySet) :
1156 + foreach ($querySet as $query) :
1157 + print "[".(sprintf('%4.4f', $time/1000.0)) . "ms] $query\n";
1158 + endforeach;
1159 + endforeach;
1160 + echo $this->log_prefix()."$wpdb->num_queries queries. $mysqlTime seconds in MySQL. Total of "; timer_stop(1); print " seconds.";
1161 + endif;
1162 +
1163 + debug_out_feedwordpress_footer();
1164 +
1165 + // Magic URL should return nothing but a 200 OK header packet
1166 + // when successful.
1167 + exit;
1168 + endif;
1169 + } /* FeedWordPress::magic_update_url () */
1170 +
1171 + function clear_cache_magic_url () {
1172 + if ($this->clear_cache_requested()) :
1173 + $this->clear_cache();
1174 + endif;
1175 + } /* FeedWordPress::clear_cache_magic_url() */
1176 +
1177 + function clear_cache_requested () {
1178 + return (
1179 + isset($_GET['clear_cache'])
1180 + and $_GET['clear_cache']
1181 + );
1182 + } /* FeedWordPress::clear_cache_requested() */
1183 +
1115 1184 function update_requested () {
1116 1185 return (
1117 1186 isset($_REQUEST['update_feedwordpress'])
1118 1187 and $_REQUEST['update_feedwordpress']
@@ -1119,60 +1188,61 @@
1119 1188 );
1120 1189 } // FeedWordPress::update_requested()
1121 1190
1122 1191 function update_requested_url () {
1123 - $ret = null;
1124 -
1125 - if (($_REQUEST['update_feedwordpress']=='*')
1126 - or (preg_match('|^http://.*|i', $_REQUEST['update_feedwordpress']))) :
1127 - $ret = $_REQUEST['update_feedwordpress'];
1128 - endif;
1192 + $ret = null;
1193 +
1194 + if (($_REQUEST['update_feedwordpress']=='*')
1195 + or (preg_match('|^http://.*|i', $_REQUEST['update_feedwordpress']))) :
1196 + $ret = $_REQUEST['update_feedwordpress'];
1197 + endif;
1129 1198
1130 - return $ret;
1199 + return $ret;
1131 1200 } // FeedWordPress::update_requested_url()
1132 1201
1133 - function syndicate_link ($name, $uri, $rss) {
1202 + function auto_update () {
1203 + if ($this->stale()) :
1204 + $this->update();
1205 + endif;
1206 + } /* FeedWordPress::auto_update () */
1207 +
1208 + function find_link ($uri, $field = 'link_rss') {
1134 1209 global $wpdb;
1135 1210
1211 + $unslashed = untrailingslashit($uri);
1212 + $slashed = trailingslashit($uri);
1213 + $link_id = $wpdb->get_var($wpdb->prepare("
1214 + SELECT link_id FROM $wpdb->links WHERE $field IN ('%s', '%s')
1215 + LIMIT 1", $unslashed, $slashed
1216 + ));
1217 +
1218 + return $link_id;
1219 + } /* FeedWordPress::find_link () */
1220 +
1221 + function syndicate_link ($name, $uri, $rss) {
1136 1222 // Get the category ID#
1137 1223 $cat_id = FeedWordPress::link_category_id();
1138 -
1224 + if (!is_wp_error($cat_id)) :
1225 + $link_category = array($cat_id);
1226 + else :
1227 + $link_category = array();
1228 + endif;
1229 +
1139 1230 // WordPress gets cranky if there's no homepage URI
1140 - if (!isset($uri) or strlen($uri)<1) : $uri = $rss; endif;
1231 + if (!is_string($uri) or strlen($uri)<1) : $uri = $rss; endif;
1141 1232
1142 - if (function_exists('wp_insert_link')) : // WordPress 2.x
1143 - if (FeedWordPressCompatibility::test_version(0, FWP_SCHEMA_21)) :
1144 - // Morons.
1145 - $name = $wpdb->escape($name);
1146 - $uri = $wpdb->escape($uri);
1147 - $rss = $wpdb->escape($rss);
1148 -
1149 - // Comes in as a single category
1150 - $linkCats = $cat_id;
1151 - else :
1152 - // Comes in as an array of categories
1153 - $linkCats = array($cat_id);
1154 - endif;
1233 + // Check if this feed URL is already being syndicated.
1234 + $link_id = wp_insert_link(array(
1235 + "link_id" => FeedWordPress::find_link($rss), // insert if nothing was found; else update
1236 + "link_rss" => $rss,
1237 + "link_name" => $name,
1238 + "link_url" => $uri,
1239 + "link_category" => $link_category,
1240 + "link_visible" => 'Y', // reactivate if inactivated
1241 + ));
1155 1242
1156 - $link_id = wp_insert_link(array(
1157 - "link_name" => $name,
1158 - "link_url" => $uri,
1159 - "link_category" => $linkCats,
1160 - "link_rss" => $rss
1161 - ));
1162 - else : // WordPress 1.5.x
1163 - $result = $wpdb->query("
1164 - INSERT INTO $wpdb->links
1165 - SET
1166 - link_name = '".$wpdb->escape($name)."',
1167 - link_url = '".$wpdb->escape($uri)."',
1168 - link_category = '".$wpdb->escape($cat_id)."',
1169 - link_rss = '".$wpdb->escape($rss)."'
1170 - ");
1171 - $link_id = $wpdb->insert_id;
1172 - endif;
1173 1243 return $link_id;
1174 - } // function FeedWordPress::syndicate_link()
1244 + } /* function FeedWordPress::syndicate_link() */
1175 1245
1176 1246 /*static*/ function syndicated_status ($what, $default) {
1177 1247 $ret = get_option("feedwordpress_syndicated_{$what}_status");
1178 1248 if (!$ret) :
@@ -1180,28 +1250,16 @@
1180 1250 endif;
1181 1251 return $ret;
1182 1252 } /* FeedWordPress::syndicated_status() */
1183 1253
1184 - function on_unfamiliar ($what = 'author', $override = NULL) {
1185 - $set = array(
1186 - 'author' => array('create', 'default', 'filter'),
1187 - 'category' => array('create', 'tag', 'default', 'filter'),
1188 - );
1254 + function on_unfamiliar ($what = 'author') {
1255 + switch ($what) :
1256 + case 'category' : $suffix = ':category'; break;
1257 + case 'post_tag' : $suffix = ':post_tag'; break;
1258 + default: $suffix = '';
1259 + endswitch;
1189 1260
1190 - if (is_string($override)) :
1191 - $ret = strtolower($override);
1192 - else :
1193 - $ret = NULL;
1194 - endif;
1195 -
1196 - if (!is_numeric($override) and !in_array($ret, $set[$what])) :
1197 - $ret = get_option('feedwordpress_unfamiliar_'.$what);
1198 - if (!is_numeric($ret) and !in_array($ret, $set[$what])) :
1199 - $ret = 'create';
1200 - endif;
1201 - endif;
1202 -
1203 - return $ret;
1261 + return get_option('feedwordpress_unfamiliar_'.$what, 'create'.$suffix);
1204 1262 } // function FeedWordPress::on_unfamiliar()
1205 1263
1206 1264 function null_email_set () {
1207 1265 $base = get_option('feedwordpress_null_email_set');
@@ -1238,14 +1296,17 @@
1238 1296 /*static*/ function munge_permalinks () {
1239 1297 return (get_option('feedwordpress_munge_permalink', /*default=*/ 'yes') != 'no');
1240 1298 } /* FeedWordPress::munge_permalinks() */
1241 1299
1242 - function syndicated_links () {
1300 + function syndicated_links ($args = array()) {
1243 1301 $contributors = FeedWordPress::link_category_id();
1244 - if (function_exists('get_bookmarks')) :
1245 - $links = get_bookmarks(array("category" => $contributors));
1246 - else:
1247 - $links = get_linkobjects($contributors); // deprecated as of WP 2.1
1302 + if (!is_wp_error($contributors)) :
1303 + $links = get_bookmarks(array_merge(
1304 + array("category" => $contributors),
1305 + $args
1306 + ));
1307 + else :
1308 + $links = array();
1248 1309 endif;
1249 1310 return $links;
1250 1311 } // function FeedWordPress::syndicated_links()
1251 1312
@@ -1271,11 +1332,12 @@
1271 1332 // If we could not find an appropriate link category,
1272 1333 // make a new one for ourselves.
1273 1334 if (!$cat_id) :
1274 1335 $cat_id = FeedWordPressCompatibility::insert_link_category(DEFAULT_SYNDICATION_CATEGORY);
1275 -
1276 - // Stamp it
1277 - update_option('feedwordpress_cat_id', $cat_id);
1336 + if (!is_wp_error($cat_id)) :
1337 + // Stamp it
1338 + update_option('feedwordpress_cat_id', $cat_id);
1339 + endif;
1278 1340 endif;
1279 1341
1280 1342 return $cat_id;
1281 1343 } // function FeedWordPress::link_category_id()
@@ -1301,15 +1363,47 @@
1301 1363 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1302 1364 endif;
1303 1365 elseif ($fwp_db_version < 2009.0707) :
1304 1366 // We need to clear out any busted AJAX crap
1305 - if (fwp_test_wp_version(FWP_SCHEMA_HAS_USERMETA)) :
1306 - $wpdb->query("
1307 - DELETE FROM $wpdb->usermeta
1308 - WHERE LOCATE('feedwordpress', meta_key)
1309 - AND LOCATE('box', meta_key);
1310 - ");
1367 + $wpdb->query("
1368 + DELETE FROM $wpdb->usermeta
1369 + WHERE LOCATE('feedwordpress', meta_key)
1370 + AND LOCATE('box', meta_key);
1371 + ");
1372 +
1373 + update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1374 + elseif ($fwp_db_version < 2010.0814) :
1375 + // Change in terminology.
1376 + if (get_option('feedwordpress_unfamiliar_category', 'create')=='default') :
1377 + update_option('feedwordpress_unfamiliar_category', 'null');
1311 1378 endif;
1379 + foreach (FeedWordPress::syndicated_links() as $link) :
1380 + $sub = new SyndicatedLink($link);
1381 +
1382 + $remap_uf = array(
1383 + 'default' => 'null',
1384 + 'filter' => 'null',
1385 + 'create' => 'create:category',
1386 + 'tag' => 'create:post_tag'
1387 + );
1388 + if (isset($sub->settings['unfamiliar category'])) :
1389 + if ($sub->settings['unfamiliar category']=='filter') :
1390 + $sub->settings['match/filter'] = array('category');
1391 + endif;
1392 + foreach ($remap_uf as $from => $to) :
1393 + if ($sub->settings['unfamiliar category']==$from) :
1394 + $sub->settings['unfamiliar category'] = $to;
1395 + endif;
1396 + endforeach;
1397 + endif;
1398 +
1399 + if (isset($sub->settings['add global categories'])) :
1400 + $sub->settings['add/category'] = $sub->settings['add global categories'];
1401 + unset($sub->settings['add global categories']);
1402 + endif;
1403 +
1404 + $sub->save_settings(/*reload=*/ true);
1405 + endforeach;
1312 1406 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1313 1407 else :
1314 1408 // No. Just brand it with the new version.
1315 1409 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
@@ -1370,14 +1464,50 @@
1370 1464 DROP INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}
1371 1465 ");
1372 1466 }
1373 1467
1374 - /*static*/ function fetch ($url) {
1375 - require_once (ABSPATH . WPINC . '/class-feed.php');
1376 - $feed = new SimplePie();
1468 + /*static*/ function fetch_timeout () {
1469 + return apply_filters(
1470 + 'feedwordpress_fetch_timeout',
1471 + intval(get_option('feedwordpress_fetch_timeout', FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT))
1472 + );
1473 + }
1474 +
1475 + /*static*/ function fetch ($url, $params = array()) {
1476 + $force_feed = true; // Default
1477 +
1478 + // Allow user to change default feed-fetch timeout with a global setting. Props Erigami Scholey-Fuller <http://www.piepalace.ca/blog/2010/11/feedwordpress-broke-my-heart.html> 'timeout' =>
1479 + $timeout = FeedWordPress::fetch_timeout();
1480 +
1481 + if (!is_array($params)) :
1482 + $force_feed = $params;
1483 + else : // Parameter array
1484 + $args = shortcode_atts(array(
1485 + 'force_feed' => $force_feed,
1486 + 'timeout' => $timeout
1487 + ), $params);
1488 +
1489 + extract($args);
1490 + endif;
1491 + $timeout = intval($timeout);
1492 +
1493 + $pie_class = apply_filters('feedwordpress_simplepie_class', 'SimplePie');
1494 + $cache_class = apply_filters('feedwordpress_cache_class', 'WP_Feed_Cache');
1495 + $file_class = apply_filters('feedwordpress_file_class', 'FeedWordPress_File');
1496 + $parser_class = apply_filters('feedwordpress_parser_class', 'FeedWordPress_Parser');
1497 +
1498 + $sniffer_class = apply_filters('feedwordpress_sniffer_class', 'FeedWordPress_Content_Type_Sniffer');
1499 +
1500 + $feed = new $pie_class;
1377 1501 $feed->set_feed_url($url);
1378 - $feed->set_cache_class('WP_Feed_Cache');
1379 - $feed->set_file_class('WP_SimplePie_File');
1502 + $feed->set_cache_class($cache_class);
1503 + $feed->set_timeout($timeout);
1504 +
1505 + //$feed->set_file_class('WP_SimplePie_File');
1506 + $feed->set_content_type_sniffer_class($sniffer_class);
1507 + $feed->set_file_class($file_class);
1508 + $feed->set_parser_class($parser_class);
1509 + $feed->force_feed($force_feed);
1380 1510 $feed->set_cache_duration(FeedWordPress::cache_duration());
1381 1511 $feed->init();
1382 1512 $feed->handle_content_type();
1383 1513
@@ -1391,8 +1521,14 @@
1391 1521
1392 1522 function clear_cache () {
1393 1523 global $wpdb;
1394 1524
1525 + // Just in case, clear out any old MagpieRSS cache records.
1526 + $magpies = $wpdb->query("
1527 + DELETE FROM {$wpdb->options}
1528 + WHERE option_name LIKE 'rss_%' AND LENGTH(option_name) > 32
1529 + ");
1530 +
1395 1531 // The WordPress SimplePie module stores its cached feeds as
1396 1532 // transient records in the options table. The data itself is
1397 1533 // stored in `_transient_feed_{md5 of url}` and the last-modified
1398 1534 // timestamp in `_transient_feed_mod_{md5 of url}`. Timeouts for
@@ -1398,12 +1534,15 @@
1398 1534 // timestamp in `_transient_feed_mod_{md5 of url}`. Timeouts for
1399 1535 // these records are stored in `_transient_timeout_feed_{md5}`.
1400 1536 // Since the md5 is always 32 characters in length, the
1401 1537 // option_name is always over 32 characters.
1402 - $wpdb->query("
1538 + $simplepies = $wpdb->query("
1403 1539 DELETE FROM {$wpdb->options}
1404 1540 WHERE option_name LIKE '_transient%_feed_%' AND LENGTH(option_name) > 32
1405 1541 ");
1542 + $simplepies = (int) ($simplepies / 4); // Each transient has 4 rows: the data, the modified timestamp; and the timeouts for each
1543 +
1544 + return ($magpies + $simplepies);
1406 1545 } /* FeedWordPress::clear_cache () */
1407 1546
1408 1547 function cache_duration () {
1409 1548 $duration = NULL;
@@ -1436,9 +1575,8 @@
1436 1575 $affirmo = array ('y', 'yes', 't', 'true', 1);
1437 1576 return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $affirmo));
1438 1577 }
1439 1578
1440 -
1441 1579 # Internal debugging functions
1442 1580 function critical_bug ($varname, $var, $line) {
1443 1581 global $wp_version;
1444 1582
@@ -1457,37 +1595,572 @@
1457 1595 if (FEEDWORDPRESS_DEBUG) : // halt only when we are doing debugging
1458 1596 FeedWordPress::critical_bug($varname, $var, $line);
1459 1597 endif;
1460 1598 }
1599 +
1600 + function val ($v, $no_newlines = false) {
1601 + ob_start();
1602 + var_dump($v);
1603 + $out = ob_get_contents(); ob_end_clean();
1604 +
1605 + if ($no_newlines) :
1606 + $out = preg_replace('/\s+/', " ", $out);
1607 + endif;
1608 + return $out;
1609 + } /* FeedWordPress::val () */
1610 +
1611 + function diagnostic_on ($level) {
1612 + $show = get_option('feedwordpress_diagnostics_show', array());
1613 + return (in_array($level, $show));
1614 + } /* FeedWordPress::diagnostic_on () */
1615 +
1616 + function diagnostic ($level, $out, $persist = NULL, $since = NULL, $mostRecent = NULL) {
1617 + global $feedwordpress_admin_footer;
1618 +
1619 + $output = get_option('feedwordpress_diagnostics_output', array());
1620 + $dlog = get_option('feedwordpress_diagnostics_log', array());
1621 +
1622 + $diagnostic_nesting = count(explode(":", $level));
1623 +
1624 + if (FeedWordPress::diagnostic_on($level)) :
1625 + foreach ($output as $method) :
1626 + switch ($method) :
1627 + case 'echo' :
1628 + echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>";
1629 + break;
1630 + case 'echo_in_cronjob' :
1631 + if (FeedWordPress::update_requested()) :
1632 + echo FeedWordPress::log_prefix()." ".$out."\n";
1633 + endif;
1634 + break;
1635 + case 'admin_footer' :
1636 + $feedwordpress_admin_footer[] = $out;
1637 + break;
1638 + case 'error_log' :
1639 + error_log(FeedWordPress::log_prefix().' '.$out);
1640 + break;
1641 + case 'email' :
1642 + if (is_null($persist)) :
1643 + $sect = 'occurrent';
1644 + $hook = (isset($dlog['mesg'][$sect]) ? count($dlog['mesg'][$sect]) : 0);
1645 + $line = array("Time" => time(), "Message" => $out);
1646 + else :
1647 + $sect = 'persistent';
1648 + $hook = md5($level."\n".$persist);
1649 + $line = array("Since" => $since, "Message" => $out, "Most Recent" => $mostRecent);
1650 + endif;
1651 +
1652 + if (!isset($dlog['mesg'])) : $dlog['mesg'] = array(); endif;
1653 + if (!isset($dlog['mesg'][$sect])) : $dlog['mesg'][$sect] = array(); endif;
1654 +
1655 + $dlog['mesg'][$sect][$hook] = $line;
1656 + endswitch;
1657 + endforeach;
1658 + endif;
1659 +
1660 + update_option('feedwordpress_diagnostics_log', $dlog);
1661 + } /* FeedWordPress::diagnostic () */
1662 +
1663 + function email_diagnostic_log () {
1664 + $dlog = get_option('feedwordpress_diagnostics_log', array());
1665 +
1666 + if (isset($dlog['schedule']) and isset($dlog['schedule']['last'])) :
1667 + if (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq'])) :
1668 + // No news is good news; only send if
1669 + // there are some messages to send.
1670 + $body = NULL;
1671 + foreach ($dlog['mesg'] as $sect => $mesgs) :
1672 + if (count($mesgs) > 0) :
1673 + if (is_null($body)) : $body = ''; endif;
1674 +
1675 + $paradigm = reset($mesgs);
1676 + $body .= "<h2>".ucfirst($sect)." issues</h2>\n"
1677 + ."<table>\n"
1678 + ."<thead><tr>\n";
1679 + foreach ($paradigm as $col => $value) :
1680 + $body .= '<th scope="col">'.$col."</th>\n";
1681 + endforeach;
1682 + $body .= "</tr></thead>\n"
1683 + ."<tbody>\n";
1684 +
1685 + foreach ($mesgs as $line) :
1686 + $body .= "<tr>\n";
1687 + foreach ($line as $col => $cell) :
1688 + if (is_numeric($cell)) :
1689 + $cell = date('j-M-y, h:i a', $cell);
1690 + endif;
1691 + $class = strtolower(preg_replace('/\s+/', '-', $col));
1692 + $body .= "<td class=\"$class\">${cell}</td>";
1693 + endforeach;
1694 + $body .= "</tr>\n";
1695 + endforeach;
1696 +
1697 + $body .= "</tbody>\n</table>\n\n";
1698 + endif;
1699 + endforeach;
1700 +
1701 + if (!is_null($body)) :
1702 + $home = feedwordpress_display_url(get_bloginfo('url'));
1703 + $subj = $home . " syndication issues for ".date('j-M-y', time());
1704 + $agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION;
1705 + $body = <<<EOMAIL
1706 +<html>
1707 +<head>
1708 +<title>$subj</title>
1709 +<style type="text/css">
1710 + body { background-color: white; color: black; }
1711 + table { width: 100%; border: 1px solid black; }
1712 + table thead tr th { background-color: #ff7700; color: white; border-bottom: 1px solid black; }
1713 + table thead tr { border-bottom: 1px solid black; }
1714 + table tr { vertical-align: top; }
1715 + table .since { width: 20%; }
1716 + table .time { width: 20%; }
1717 + table .most-recently { width: 20%; }
1718 + table .message { width: auto; }
1719 +</style>
1720 +</head>
1721 +<body>
1722 +<h1>Syndication Issues encountered by $agent on $home</h1>
1723 +$body
1724 +</body>
1725 +</html>
1726 +
1727 +EOMAIL;
1728 +
1729 + $ded = get_option('feedwordpress_diagnostics_email_destination', 'admins');
1730 +
1731 + // e-mail address
1732 + if (preg_match('/^mailto:(.*)$/', $ded, $ref)) :
1733 + $recipients = array($ref[1]);
1734 +
1735 + // userid
1736 + elseif (preg_match('/^user:(.*)$/', $ded, $ref)) :
1737 + $userdata = get_userdata((int) $ref[1]);
1738 + $recipients = array($userdata->user_email);
1739 +
1740 + // admins
1741 + else :
1742 + $recipients = FeedWordPressDiagnostic::admin_emails();
1743 + endif;
1744 +
1745 + foreach ($recipients as $email) :
1746 + add_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1747 + wp_mail($email, $subj, $body);
1748 + remove_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1749 + endforeach;
1750 + endif;
1751 +
1752 + // Clear the logs
1753 + $dlog['mesg']['persistent'] = array();
1754 + $dlog['mesg']['occurrent'] = array();
1755 +
1756 + // Set schedule for next update
1757 + $dlog['schedule']['last'] = time();
1758 + endif;
1759 + else :
1760 + $dlog['schedule'] = array(
1761 + 'freq' => 24 /*hr*/ * 60 /*min*/ * 60 /*s*/,
1762 + 'last' => time(),
1763 + );
1764 + endif;
1765 +
1766 + update_option('feedwordpress_diagnostics_log', $dlog);
1767 + } /* FeedWordPress::email_diagnostic_log () */
1768 +
1769 + function allow_html_mail () {
1770 + return 'text/html';
1771 + } /* FeedWordPress::allow_html_mail () */
1772 +
1773 + function admin_footer () {
1774 + global $feedwordpress_admin_footer;
1775 + foreach ($feedwordpress_admin_footer as $line) :
1776 + echo '<div><pre>'.$line.'</pre></div>';
1777 + endforeach;
1778 + } /* FeedWordPress::admin_footer () */
1779 +
1780 + function log_prefix ($date = false) {
1781 + $home = get_bloginfo('url');
1782 + $prefix = '['.feedwordpress_display_url($home).'] [feedwordpress] ';
1783 + if ($date) :
1784 + $prefix = "[".date('Y-m-d H:i:s')."]".$prefix;
1785 + endif;
1786 + return $prefix;
1787 + } /* FeedWordPress::log_prefix () */
1788 +
1789 + function menu_cap ($sub = false) {
1790 + if ($sub) :
1791 + $cap = apply_filters('feedwordpress_menu_settings_capacity', 'manage_options');
1792 + else :
1793 + $cap = apply_filters('feedwordpress_menu_main_capacity', 'manage_links');
1794 + endif;
1795 + return $cap;
1796 + } /* FeedWordPress::menu_cap () */
1797 +
1798 + function path ($filename = '') {
1799 + global $fwp_path;
1800 +
1801 + $path = $fwp_path;
1802 + if (strlen($filename) > 0) :
1803 + $path .= '/'.$filename;
1804 + endif;
1805 + return $path;
1806 + }
1807 +
1808 + function param ($key, $type = 'REQUEST', $default = NULL) {
1809 + $where = '_'.strtoupper($type);
1810 + $ret = $default;
1811 + if (isset($GLOBALS[$where]) and is_array($GLOBALS[$where])) :
1812 + if (isset($GLOBALS[$where][$key])) :
1813 + $ret = $GLOBALS[$where][$key];
1814 + if (get_magic_quotes_gpc()) :
1815 + $ret = stripslashes_deep($ret);
1816 + endif;
1817 + endif;
1818 + endif;
1819 + return $ret;
1820 + }
1821 + function post ($key, $default = NULL) {
1822 + return FeedWordPress::param($key, 'POST');
1823 + }
1461 1824 } // class FeedWordPress
1462 1825
1463 -require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
1464 -require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
1826 +class FeedWordPress_File extends WP_SimplePie_File {
1827 + function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
1828 + WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
1465 1829
1830 + // SimplePie makes a strongly typed check against integers with
1831 + // this, but WordPress puts a string in. Which causes caching
1832 + // to break and fall on its ass when SimplePie is getting a 304,
1833 + // but doesn't realize it because this member is "304" instead.
1834 + $this->status_code = (int) $this->status_code;
1835 + }
1836 +} /* class FeedWordPress_File () */
1837 +
1838 +class FeedWordPress_Parser extends SimplePie_Parser {
1839 + function parse (&$data, $encoding) {
1840 + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
1841 + if (strtoupper($encoding) === 'US-ASCII')
1842 + {
1843 + $this->encoding = 'UTF-8';
1844 + }
1845 + else
1846 + {
1847 + $this->encoding = $encoding;
1848 + }
1849 +
1850 + // Strip BOM:
1851 + // UTF-32 Big Endian BOM
1852 + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
1853 + {
1854 + $data = substr($data, 4);
1855 + }
1856 + // UTF-32 Little Endian BOM
1857 + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
1858 + {
1859 + $data = substr($data, 4);
1860 + }
1861 + // UTF-16 Big Endian BOM
1862 + elseif (substr($data, 0, 2) === "\xFE\xFF")
1863 + {
1864 + $data = substr($data, 2);
1865 + }
1866 + // UTF-16 Little Endian BOM
1867 + elseif (substr($data, 0, 2) === "\xFF\xFE")
1868 + {
1869 + $data = substr($data, 2);
1870 + }
1871 + // UTF-8 BOM
1872 + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
1873 + {
1874 + $data = substr($data, 3);
1875 + }
1876 +
1877 + if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
1878 + {
1879 + $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
1880 + if ($declaration->parse())
1881 + {
1882 + $data = substr($data, $pos + 2);
1883 + $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
1884 + }
1885 + else
1886 + {
1887 + $this->error_string = 'SimplePie bug! Please report this!';
1888 + return false;
1889 + }
1890 + }
1891 +
1892 + $return = true;
1893 +
1894 + static $xml_is_sane = null;
1895 + if ($xml_is_sane === null)
1896 + {
1897 + $parser_check = xml_parser_create();
1898 + xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1899 + xml_parser_free($parser_check);
1900 + $xml_is_sane = isset($values[0]['value']);
1901 + }
1902 +
1903 + // Create the parser
1904 + if ($xml_is_sane)
1905 + {
1906 + $xml = xml_parser_create_ns($this->encoding, $this->separator);
1907 + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
1908 + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
1909 + xml_set_object($xml, $this);
1910 + xml_set_character_data_handler($xml, 'cdata');
1911 + xml_set_element_handler($xml, 'tag_open', 'tag_close');
1912 + xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
1913 +
1914 + // Parse!
1915 + if (!xml_parse($xml, $data, true))
1916 + {
1917 + $this->error_code = xml_get_error_code($xml);
1918 + $this->error_string = xml_error_string($this->error_code);
1919 + $return = false;
1920 + }
1921 +
1922 + $this->current_line = xml_get_current_line_number($xml);
1923 + $this->current_column = xml_get_current_column_number($xml);
1924 + $this->current_byte = xml_get_current_byte_index($xml);
1925 + xml_parser_free($xml);
1926 +
1927 + return $return;
1928 + }
1929 + else
1930 + {
1931 + libxml_clear_errors();
1932 + $xml =& new XMLReader();
1933 + $xml->xml($data);
1934 + while (@$xml->read())
1935 + {
1936 + switch ($xml->nodeType)
1937 + {
1938 +
1939 + case constant('XMLReader::END_ELEMENT'):
1940 + if ($xml->namespaceURI !== '')
1941 + {
1942 + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1943 + }
1944 + else
1945 + {
1946 + $tagName = $xml->localName;
1947 + }
1948 + $this->tag_close(null, $tagName);
1949 + break;
1950 + case constant('XMLReader::ELEMENT'):
1951 + $empty = $xml->isEmptyElement;
1952 + if ($xml->namespaceURI !== '')
1953 + {
1954 + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1955 + }
1956 + else
1957 + {
1958 + $tagName = $xml->localName;
1959 + }
1960 + $attributes = array();
1961 + while ($xml->moveToNextAttribute())
1962 + {
1963 + if ($xml->namespaceURI !== '')
1964 + {
1965 + $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1966 + }
1967 + else
1968 + {
1969 + $attrName = $xml->localName;
1970 + }
1971 + $attributes[$attrName] = $xml->value;
1972 + }
1973 +
1974 + foreach ($attributes as $attr => $value) :
1975 + list($ns, $local) = $this->split_ns($attr);
1976 + if ($ns=='http://www.w3.org/2000/xmlns/') :
1977 + if ('xmlns' == $local) : $local = false; endif;
1978 + $this->start_xmlns(null, $local, $value);
1979 + endif;
1980 + endforeach;
1981 +
1982 + $this->tag_open(null, $tagName, $attributes);
1983 + if ($empty)
1984 + {
1985 + $this->tag_close(null, $tagName);
1986 + }
1987 + break;
1988 + case constant('XMLReader::TEXT'):
1989 +
1990 + case constant('XMLReader::CDATA'):
1991 + $this->cdata(null, $xml->value);
1992 + break;
1993 + }
1994 + }
1995 + if ($error = libxml_get_last_error())
1996 + {
1997 + $this->error_code = $error->code;
1998 + $this->error_string = $error->message;
1999 + $this->current_line = $error->line;
2000 + $this->current_column = $error->column;
2001 + return false;
2002 + }
2003 + else
2004 + {
2005 + return true;
2006 + }
2007 + }
2008 + } /* FeedWordPress_Parser::parse() */
2009 +
2010 + var $xmlns_stack = array();
2011 + var $xmlns_current = array();
2012 + function tag_open ($parser, $tag, $attributes) {
2013 + $ret = parent::tag_open($parser, $tag, $attributes);
2014 + if ($this->current_xhtml_construct < 0) :
2015 + $this->data['xmlns'] = $this->xmlns_current;
2016 + $this->xmlns_stack[] = $this->xmlns_current;
2017 + endif;
2018 + return $ret;
2019 + }
2020 +
2021 + function tag_close($parser, $tag) {
2022 + if ($this->current_xhtml_construct < 0) :
2023 + $this->xmlns_current = array_pop($this->xmlns_stack);
2024 + endif;
2025 + $ret = parent::tag_close($parser, $tag);
2026 + return $ret;
2027 + }
2028 +
2029 + function start_xmlns ($parser, $prefix, $uri) {
2030 + if (!$prefix) :
2031 + $prefix = '';
2032 + endif;
2033 + if ($this->current_xhtml_construct < 0) :
2034 + $this->xmlns_current[$prefix] = $uri;
2035 + endif;
2036 + return true;
2037 + } /* FeedWordPress_Parser::start_xmlns() */
2038 +}
2039 +
2040 +$feedwordpress_admin_footer = array();
2041 +
1466 2042 ################################################################################
1467 2043 ## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
1468 2044 ################################################################################
1469 2045
1470 -function feedwordpress_xmlrpc_hook ($args = array ()) {
1471 - $args['weblogUpdates.ping'] = 'feedwordpress_pong';
1472 - return $args;
1473 -}
2046 +class FeedWordPressRPC {
2047 + function FeedWordPressRPC () {
2048 + add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
2049 + }
2050 +
2051 + function xmlrpc_methods ($args = array()) {
2052 + $args['weblogUpdates.ping'] = array(&$this, 'ping');
2053 + $args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
2054 + $args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
2055 + $args['feedwordpress.delete'] = array(&$this, 'delete');
2056 + $args['feedwordpress.nuke'] = array(&$this, 'nuke');
2057 + return $args;
2058 + }
2059 +
2060 + function ping ($args) {
2061 + global $feedwordpress;
2062 +
2063 + $delta = @$feedwordpress->update($args[1]);
2064 + if (is_null($delta)):
2065 + return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
2066 + else:
2067 + $mesg = array();
2068 + if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
2069 + if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
2070 +
2071 + return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
2072 + endif;
2073 + }
2074 +
2075 + function validate (&$args) {
2076 + global $wp_xmlrpc_server;
1474 2077
1475 -function feedwordpress_pong ($args) {
1476 - $feedwordpress = new FeedWordPress;
1477 - $delta = @$feedwordpress->update($args[1]);
1478 - if (is_null($delta)):
1479 - return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
1480 - else:
1481 - $mesg = array();
1482 - if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
1483 - if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
2078 + // First two params are username/password
2079 + $username = $wp_xmlrpc_server->escape(array_shift($args));
2080 + $password = $wp_xmlrpc_server->escape(array_shift($args));
1484 2081
1485 - return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
1486 - endif;
1487 -}
2082 + $ret = array();
2083 + if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
2084 + $ret = $wp_xmlrpc_server->error;
2085 + elseif (!current_user_can('manage_links')) :
2086 + $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
2087 + endif;
2088 + return $ret;
2089 + }
1488 2090
1489 -require_once(dirname(__FILE__) . '/relative_uri.class.php');
2091 + function subscribe ($args) {
2092 + $ret = $this->validate($args);
2093 + if (is_array($ret)) : // Success
2094 + // The remaining params are feed URLs
2095 + foreach ($args as $arg) :
2096 + $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
2097 + $feeds = array_values(array_unique($finder->find()));
2098 +
2099 + if (count($feeds) > 0) :
2100 + $link_id = FeedWordPress::syndicate_link(
2101 + /*title=*/ feedwordpress_display_url($feeds[0]),
2102 + /*homepage=*/ $feeds[0],
2103 + /*feed=*/ $feeds[0]
2104 + );
2105 + $ret[] = array(
2106 + 'added',
2107 + $feeds[0],
2108 + $arg,
2109 + );
2110 + else :
2111 + $ret[] = array(
2112 + 'error',
2113 + $arg
2114 + );
2115 + endif;
2116 + endforeach;
2117 + endif;
2118 + return $ret;
2119 + } /* FeedWordPressRPC::subscribe () */
2120 +
2121 + function unsubscribe ($method, $args) {
2122 + $ret = $this->validate($args);
2123 + if (is_array($ret)) : // Success
2124 + // The remaining params are feed URLs
2125 + foreach ($args as $arg) :
2126 + $link_id = FeedWordPress::find_link($arg);
2127 +
2128 + if (!$link_id) :
2129 + $link_id = FeedWordPress::find_link($arg, 'link_url');
2130 + endif;
2131 +
2132 + if ($link_id) :
2133 + $link = new SyndicatedLink($link_id);
2134 +
2135 + $link->{$method}();
2136 + $ret[] = array(
2137 + 'deactivated',
2138 + $arg,
2139 + );
2140 + else :
2141 + $ret[] = array(
2142 + 'error',
2143 + $arg,
2144 + );
2145 + endif;
2146 + endforeach;
2147 + endif;
2148 + return $ret;
2149 + } /* FeedWordPress::unsubscribe () */
2150 +
2151 + function deactivate ($args) {
2152 + return $this->unsubscribe('deactivate', $args);
2153 + } /* FeedWordPressRPC::deactivate () */
2154 +
2155 + function delete ($args) {
2156 + return $this->unsubscribe('delete', $args);
2157 + } /* FeedWordPressRPC::delete () */
2158 +
2159 + function nuke ($args) {
2160 + return $this->unsubscribe('nuke', $args);
2161 + } /* FeedWordPressRPC::nuke () */
2162 +} /* class FeedWordPressRPC */
1490 2163
1491 2164 // take your best guess at the realname and e-mail, given a string
1492 2165 define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
1493 2166 define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');