PluginProbe
FeedWordPress / 2010.0905
FeedWordPress v2010.0905
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 +1340 -502 2009.07072010.0905 View file →
@@ -1,19 +1,25 @@
1 1 <?php
2 2 /*
3 3 Plugin Name: FeedWordPress
4 -Plugin URI: http://projects.radgeek.com/feedwordpress
4 +Plugin URI: http://feedwordpress.radgeek.com/
5 5 Description: simple and flexible Atom/RSS syndication for WordPress
6 -Version: 2009.0707
6 +Version: 2010.0905
7 7 Author: Charles Johnson
8 8 Author URI: http://radgeek.com/
9 9 License: GPL
10 10 */
11 11
12 +/**
13 + * @package FeedWordPress
14 + * @version 2010.0905
15 + */
16 +
12 17 # This uses code derived from:
13 18 # - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
14 -# - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
19 +# - MagpieRSS by Kellan Elliot-McCrea <kellan@protest.net>
15 20 # - Ultra-Liberal Feed Finder by Mark Pilgrim <mark@diveintomark.org>
21 +# - WordPress Blog Tool and Publishing Platform <http://wordpress.org/>
16 22 # according to the terms of the GNU General Public License.
17 23 #
18 24 # INSTALLATION: see readme.txt or <http://projects.radgeek.com/install>
19 25 #
@@ -27,15 +33,26 @@
27 33 # or use a cron job.
28 34
29 35 # -- Don't change these unless you know what you're doing...
30 36
31 -define ('FEEDWORDPRESS_VERSION', '2009.0707');
37 +define ('FEEDWORDPRESS_VERSION', '2010.0905');
32 38 define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
39 +
40 +if (!defined('FEEDWORDPRESS_BLEG')) :
41 + define ('FEEDWORDPRESS_BLEG', true);
42 +endif;
43 +
44 +// Defaults
33 45 define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
46 +define ('DEFAULT_UPDATE_PERIOD', 60); // value in minutes
34 47
35 -$feedwordpress_debug = get_option('feedwordpress_debug');
36 -if (is_string($feedwordpress_debug)) :
37 - $feedwordpress_debug = ($feedwordpress_debug == 'yes');
48 +if (isset($_REQUEST['feedwordpress_debug'])) :
49 + $feedwordpress_debug = $_REQUEST['feedwordpress_debug'];
50 +else :
51 + $feedwordpress_debug = get_option('feedwordpress_debug');
52 + if (is_string($feedwordpress_debug)) :
53 + $feedwordpress_debug = ($feedwordpress_debug == 'yes');
54 + endif;
38 55 endif;
39 56 define ('FEEDWORDPRESS_DEBUG', $feedwordpress_debug);
40 57
41 58 define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
@@ -45,8 +62,9 @@
45 62
46 63 define ('FEEDWORDPRESS_FRESHNESS_INTERVAL', 10*60); // Every ten minutes
47 64
48 65 define ('FWP_SCHEMA_HAS_USERMETA', 2966);
66 +define ('FWP_SCHEMA_USES_ARGS_TAXONOMY', 12694); // Revision # for using $args['taxonomy'] to get link categories
49 67 define ('FWP_SCHEMA_20', 3308); // Database schema # for WP 2.0
50 68 define ('FWP_SCHEMA_21', 4772); // Database schema # for WP 2.1
51 69 define ('FWP_SCHEMA_23', 5495); // Database schema # for WP 2.3
52 70 define ('FWP_SCHEMA_25', 7558); // Database schema # for WP 2.5
@@ -52,14 +70,15 @@
52 70 define ('FWP_SCHEMA_25', 7558); // Database schema # for WP 2.5
53 71 define ('FWP_SCHEMA_26', 8201); // Database schema # for WP 2.6
54 72 define ('FWP_SCHEMA_27', 9872); // Database schema # for WP 2.7
55 73 define ('FWP_SCHEMA_28', 11548); // Database schema # for WP 2.8
74 +define ('FWP_SCHEMA_29', 12329); // Database schema # for WP 2.9
75 +define ('FWP_SCHEMA_30', 12694); // Database schema # for WP 3.0
56 76
57 77 if (FEEDWORDPRESS_DEBUG) :
58 78 // Help us to pick out errors, if any.
59 79 ini_set('error_reporting', E_ALL & ~E_NOTICE);
60 80 ini_set('display_errors', true);
61 - define('MAGPIE_DEBUG', true);
62 81
63 82 // When testing we don't want cache issues to interfere. But this is
64 83 // a VERY BAD SETTING for a production server. Webmasters will eat your
65 84 // face for breakfast if you use it, and the baby Jesus will cry. So
@@ -64,37 +83,39 @@
64 83 // a VERY BAD SETTING for a production server. Webmasters will eat your
65 84 // face for breakfast if you use it, and the baby Jesus will cry. So
66 85 // make sure FEEDWORDPRESS_DEBUG is FALSE for any site that will be
67 86 // used for more than testing purposes!
68 - define('MAGPIE_CACHE_AGE', 1);
87 + define('FEEDWORDPRESS_CACHE_AGE', 1);
88 + define('FEEDWORDPRESS_CACHE_LIFETIME', 1);
89 + define('FEEDWORDPRESS_FETCH_TIME_OUT', 60);
69 90 else :
70 - define('MAGPIE_DEBUG', false);
91 + // Hold onto data all day for conditional GET purposes,
92 + // but consider it stale after 1 min (requiring a conditional GET)
93 + define('FEEDWORDPRESS_CACHE_LIFETIME', 24*60*60);
94 + define('FEEDWORDPRESS_CACHE_AGE', 1*60);
95 + define('FEEDWORDPRESS_FETCH_TIME_OUT', 10);
71 96 endif;
72 97
73 -// Note that the rss-functions.php that comes prepackaged with WordPress is
74 -// old & busted. For the new hotness, drop a copy of rss.php from
75 -// this archive into wp-includes/rss.php
98 +// Use our the cache settings that we want.
99 +add_filter('wp_feed_cache_transient_lifetime', array('FeedWordPress', 'cache_lifetime'));
76 100
77 -if (is_readable(ABSPATH . WPINC . '/rss.php')) :
78 - require_once (ABSPATH . WPINC . '/rss.php');
79 -else :
80 - require_once (ABSPATH . WPINC . '/rss-functions.php');
101 +// Ensure that we have SimplePie loaded up and ready to go.
102 +// We no longer need a MagpieRSS upgrade module. Hallelujah!
103 +if (!class_exists('SimplePie')) :
104 + require_once(ABSPATH . WPINC . '/class-simplepie.php');
81 105 endif;
106 +require_once(ABSPATH . WPINC . '/class-feed.php');
82 107
83 -if (isset($wp_db_version)) :
84 - if ($wp_db_version >= FWP_SCHEMA_23) :
85 - require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
86 - elseif ($wp_db_version >= FWP_SCHEMA_21) : // WordPress 2.1 and 2.2, but not 2.3
87 - require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
88 - require_once (ABSPATH . 'wp-admin/admin-db.php'); // for wp_insert_category
89 - elseif ($wp_db_version >= FWP_SCHEMA_20) : // WordPress 2.0
90 - require_once (ABSPATH . WPINC . '/registration-functions.php'); // for wp_insert_user
91 - require_once (ABSPATH . 'wp-admin/admin-db.php'); // for wp_insert_category
92 - endif;
93 -endif;
108 +require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
94 109
110 +require_once(dirname(__FILE__) . '/admin-ui.php');
111 +require_once(dirname(__FILE__) . '/feedwordpresssyndicationpage.class.php');
95 112 require_once(dirname(__FILE__) . '/compatability.php'); // LEGACY API: Replicate or mock up functions for legacy support purposes
113 +
114 +require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
115 +require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
96 116 require_once(dirname(__FILE__) . '/feedwordpresshtml.class.php');
117 +require_once(dirname(__FILE__) . '/feedwordpress-content-type-sniffer.class.php');
97 118
98 119 // Magic quotes are just about the stupidest thing ever.
99 120 if (is_array($_POST)) :
100 121 $fwp_post = stripslashes_deep($_POST);
@@ -101,9 +122,9 @@
101 122 endif;
102 123
103 124 // Get the path relative to the plugins directory in which FWP is stored
104 125 preg_match (
105 - '|/wp-content/plugins/(.+)$|',
126 + '|'.preg_quote(WP_PLUGIN_DIR).'/(.+)$|',
106 127 dirname(__FILE__),
107 128 $ref
108 129 );
109 130
@@ -114,27 +135,21 @@
114 135 endif;
115 136
116 137 // If this is a FeedWordPress admin page, queue up scripts for AJAX functions that FWP uses
117 138 // If it is a display page or a non-FeedWordPress admin page, don't.
118 -if (is_admin() and isset($_REQUEST['page']) and preg_match("|^{$fwp_path}/|", $_REQUEST['page'])) :
119 - if (function_exists('wp_enqueue_script')) :
120 - if (isset($wp_db_version) and $wp_db_version >= FWP_SCHEMA_25) :
121 - wp_enqueue_script('post'); // for magic tag and category boxes
122 - wp_enqueue_script('thickbox'); // for fold-up boxes
123 - wp_enqueue_script('admin-forms'); // for checkbox selection
124 - else :
125 - wp_enqueue_script( 'ajaxcat' ); // Provides the handy-dandy new category text box
126 - endif;
127 - endif;
128 - if (function_exists('wp_enqueue_style')) :
129 - if (fwp_test_wp_version(FWP_SCHEMA_25)) :
130 - wp_enqueue_style('dashboard');
131 - endif;
132 - endif;
139 +wp_register_style('feedwordpress-elements', WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-elements.css');
140 +if (FeedWordPressSettingsUI::is_admin()) :
141 + // For JavaScript that needs to be generated dynamically
142 + add_action('admin_print_scripts', array('FeedWordPressSettingsUI', 'admin_scripts'));
143 +
144 + // For CSS that needs to be generated dynamically.
145 + add_action('admin_print_styles', array('FeedWordPressSettingsUI', 'admin_styles'));
146 +
147 + wp_enqueue_style('dashboard');
148 + wp_enqueue_style('feedwordpress-elements');
149 +
133 150 if (function_exists('wp_admin_css')) :
134 - if (fwp_test_wp_version(FWP_SCHEMA_25)) :
135 - wp_admin_css('css/dashboard');
136 - endif;
151 + wp_admin_css('css/dashboard');
137 152 endif;
138 153 endif;
139 154
140 155 if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
@@ -157,10 +172,17 @@
157 172
158 173 add_action('atom_entry', 'feedwordpress_item_feed_data');
159 174
160 175 # Filter in original permalinks if the user wants that
161 - add_filter('post_link', 'syndication_permalink', 1);
176 + add_filter('post_link', 'syndication_permalink', /*priority=*/ 1, /*arguments=*/ 3);
162 177
178 + # When foreign URLs are used for permalinks in feeds or display
179 + # contexts, they need to be escaped properly.
180 + add_filter('the_permalink', 'syndication_permalink_escaped');
181 + add_filter('the_permalink_rss', 'syndication_permalink_escaped');
182 +
183 + add_filter('post_comments_feed_link', 'syndication_comments_feed_link');
184 +
163 185 # WTF? By default, wp_insert_link runs incoming link_url and link_rss
164 186 # URIs through default filters that include `wp_kses()`. But `wp_kses()`
165 187 # just happens to escape any occurrence of & to &amp; -- which just
166 188 # happens to fuck up any URI with a & to separate GET parameters.
@@ -169,13 +191,17 @@
169 191
170 192 # Admin menu
171 193 add_action('admin_menu', 'fwp_add_pages');
172 194 add_action('admin_notices', 'fwp_check_debug');
173 - add_action('admin_notices', 'fwp_check_magpie');
174 195
196 + add_action('admin_menu', 'feedwordpress_add_post_edit_controls');
197 + add_action('save_post', 'feedwordpress_save_post_edit_controls');
198 +
199 + add_action('admin_footer', array('FeedWordPress', 'admin_footer'));
200 +
175 201 # Inbound XML-RPC update methods
176 - add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
177 -
202 + $feedwordpressRPC = new FeedWordPressRPC;
203 +
178 204 # Outbound XML-RPC ping reform
179 205 remove_action('publish_post', 'generic_ping'); // WP 1.5.x
180 206 remove_action('do_pings', 'do_all_pings', 10, 1); // WP 2.1, 2.2
181 207 remove_action('publish_post', '_publish_post_hook', 5, 1); // WP 2.3
@@ -184,22 +210,25 @@
184 210 add_action('do_pings', 'fwp_do_pings', 10, 1);
185 211 add_action('feedwordpress_update', 'fwp_hold_pings');
186 212 add_action('feedwordpress_update_complete', 'fwp_release_pings');
187 213
188 - # Hook in logging functions only if the logging option is ON
189 - $update_logging = get_option('feedwordpress_update_logging');
190 - if ($update_logging == 'yes') :
191 - add_action('post_syndicated_item', 'log_feedwordpress_post', 100);
192 - add_action('update_syndicated_item', 'log_feedwordpress_update_post', 100);
193 - add_action('feedwordpress_update', 'log_feedwordpress_update_feeds', 100);
194 - add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
195 - add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
214 + add_action('syndicated_feed_error', array('FeedWordPressDiagnostic', 'feed_error'), 100, 3);
215 +
216 + add_action('wp_footer', 'debug_out_feedwordpress_footer', -100);
217 + add_action('admin_footer', 'debug_out_feedwordpress_footer', -100);
218 +
219 + $feedwordpress = new FeedWordPress;
220 +
221 + # Cron-less auto-update. Hooray!
222 + $autoUpdateHook = get_option('feedwordpress_automatic_updates');
223 + if ($autoUpdateHook != 'init') :
224 + $autoUpdateHook = 'shutdown';
196 225 endif;
197 -
198 - # Cron-less auto-update. Hooray!
199 - add_action('init', 'feedwordpress_auto_update');
200 - add_action('init', 'feedwordpress_check_for_magpie_fix');
201 -
226 + add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
227 + add_action('init', array(&$feedwordpress, 'init'));
228 + add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
229 + add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
230 +
202 231 # Default sanitizers
203 232 add_filter('syndicated_item_content', array('SyndicatedPost', 'resolve_relative_uris'), 0, 2);
204 233 add_filter('syndicated_item_content', array('SyndicatedPost', 'sanitize_content'), 0, 2);
205 234
@@ -207,194 +236,247 @@
207 236 # Hook in the menus, which will just point to the upgrade interface
208 237 add_action('admin_menu', 'fwp_add_pages');
209 238 endif; // if (!FeedWordPress::needs_upgrade())
210 239
211 -function feedwordpress_check_for_magpie_fix () {
212 - if (isset($_POST['action']) and $_POST['action']=='fix_magpie_version') :
213 - FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_fix_magpie', /*capability=*/ 'edit_files');
214 -
215 - $back_to = $_SERVER['REQUEST_URI'];
216 - if (isset($_POST['ignore'])) :
217 - // kill error message by telling it we ignored the upgrade request for this version
218 - update_option('feedwordpress_magpie_ignored_upgrade_to', EXPECTED_MAGPIE_VERSION);
219 - $ret = 'ignored';
220 - elseif (isset($_POST['upgrade'])) :
221 - $source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
222 - $destination = ABSPATH . WPINC . '/rss.php';
223 - $success = @copy($source, $destination);
224 - $ret = (int) $success;
225 - endif;
226 -
227 - if (strpos($back_to, '?')===false) : $sep = '?';
228 - else : $sep = '&';
229 - endif;
230 -
231 - header("Location: {$back_to}{$sep}feedwordpress_magpie_fix=".$ret);
232 - exit;
233 - endif;
234 -} /* feedwordpress_check_for_magpie_fix() */
235 -
236 -function feedwordpress_auto_update () {
237 - if (FeedWordPress::stale()) :
238 - $feedwordpress =& new FeedWordPress;
239 - $feedwordpress->update();
240 - endif;
241 -
242 - if (FeedWordPress::update_requested()) :
243 - exit;
244 - endif;
245 -} /* feedwordpress_auto_update () */
246 -
247 240 ################################################################################
248 241 ## LOGGING FUNCTIONS: log status updates to error_log if you want it ###########
249 242 ################################################################################
250 243
251 -function log_feedwordpress_post ($id) {
252 - $post = wp_get_single_post($id);
253 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] posted "
254 - ."'{$post->post_title}' ({$post->post_date})");
255 -}
244 +class FeedWordPressDiagnostic {
245 + function feed_error ($error, $old, $link) {
246 + $wpError = $error['object'];
247 + $url = $link->uri();
248 +
249 + $mesgs = $wpError->get_error_messages();
250 + foreach ($mesgs as $mesg) :
251 + $mesg = esc_html($mesg);
252 + FeedWordPress::diagnostic(
253 + 'updated_feeds:errors',
254 + "Feed Error: [${url}] update returned error: $mesg"
255 + );
256 + if ($error['ts'] > $error['since']) :
257 + $since = date('r', $error['since']);
258 + $mostRecent = date('r', $error['ts']);
259 + FeedWordPress::diagnostic(
260 + 'updated_feeds:errors:persistent',
261 + "Feed Update Error: [${url}] returning errors"
262 + ." since ${since}:<br/><code>$mesg</code>",
263 + $url, $error['since'], $error['ts']
264 + );
265 + endif;
266 + endforeach;
267 + }
256 268
257 -function log_feedwordpress_update_post ($id) {
258 - $post = wp_get_single_post($id);
259 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] updated "
260 - ."'{$post->post_title}' ({$post->post_date})"
261 - ." (as of {$post->post_modified})");
262 -}
269 + function admin_emails ($id = '') {
270 + $users = get_users_of_blog($id);
271 + $recipients = array();
272 + foreach ($users as $user) :
273 + $dude = new WP_User($user->user_id);
274 + if ($dude->has_cap('administrator')) :
275 + if ($dude->user_email) :
276 + $recipients[] = $dude->user_email;
277 + endif;
278 + endif;
279 + endforeach;
280 + return $recipients;
281 + }
282 +} /* class FeedWordPressDiagnostic */
263 283
264 -function log_feedwordpress_update_feeds ($uri) {
265 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] update('$uri')");
284 +function debug_out_human_readable_bytes ($quantity) {
285 + $quantity = (int) $quantity;
286 + $magnitude = 'B';
287 + $orders = array('KB', 'MB', 'GB', 'TB');
288 + while (($quantity > (1024*100)) and (count($orders) > 0)) :
289 + $quantity = floor($quantity / 1024);
290 + $magnitude = array_shift($orders);
291 + endwhile;
292 + return "${quantity} ${magnitude}";
266 293 }
267 294
268 -function log_feedwordpress_check_feed ($feed) {
269 - $uri = $feed['link/uri']; $name = $feed['link/name'];
270 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] Examining $name <$uri>");
271 -}
295 +function debug_out_feedwordpress_footer () {
296 + if (FeedWordPress::diagnostic_on('memory_usage')) :
297 + if (function_exists('memory_get_usage')) :
298 + FeedWordPress::diagnostic ('memory_usage', "Memory: Current usage: ".debug_out_human_readable_bytes(memory_get_usage()));
299 + endif;
300 + if (function_exists('memory_get_peak_usage')) :
301 + FeedWordPress::diagnostic ('memory_usage', "Memory: Peak usage: ".debug_out_human_readable_bytes(memory_get_peak_usage()));
302 + endif;
303 + endif;
304 +} /* debug_out_feedwordpress_footer() */
272 305
273 -function log_feedwordpress_update_complete ($delta) {
274 - $mesg = array();
275 - if (isset($delta['new'])) $mesg[] = 'added '.$delta['new'].' new posts';
276 - if (isset($delta['updated'])) $mesg[] = 'updated '.$delta['updated'].' existing posts';
277 - if (empty($mesg)) $mesg[] = 'nothing changed';
278 -
279 - error_log("[".date('Y-m-d H:i:s')."][feedwordpress] "
280 - .(is_null($delta) ? "Error: I don't syndicate that URI"
281 - : implode(' and ', $mesg)));
282 -}
283 -
284 306 ################################################################################
285 307 ## TEMPLATE API: functions to make your templates syndication-aware ############
286 308 ################################################################################
287 309
288 -function is_syndicated () { return (strlen(get_syndication_feed_id()) > 0); }
310 +/**
311 + * is_syndicated: Tests whether the current post in a Loop context, or a post
312 + * given by ID number, was syndicated by FeedWordPress. Useful for templates
313 + * to determine whether or not to retrieve syndication-related meta-data in
314 + * displaying a post.
315 + *
316 + * @param int $id The post to check for syndicated status. Defaults to the current post in a Loop context.
317 + * @return bool TRUE if the post's meta-data indicates it was syndicated; FALSE otherwise
318 + */
319 +function is_syndicated ($id = NULL) {
320 + return (strlen(get_syndication_feed_id($id)) > 0);
321 +} /* function is_syndicated() */
289 322
290 -function get_syndication_source_link ($original = NULL) {
291 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
323 +function feedwordpress_display_url ($url, $before = 60, $after = 0) {
324 + $bits = parse_url($url);
325 +
326 + // Strip out crufty subdomains
327 + if (isset($bits['host'])) :
328 + $bits['host'] = preg_replace('/^www[0-9]*\./i', '', $bits['host']);
329 + endif;
330 +
331 + // Reassemble bit-by-bit with minimum of crufty elements
332 + $url = (isset($bits['user'])?$bits['user'].'@':'')
333 + .(isset($bits['host'])?$bits['host']:'')
334 + .(isset($bits['path'])?$bits['path']:'')
335 + .(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
336 + .(isset($bits['query'])?'?'.$bits['query']:'');
337 +
338 + if (strlen($url) > ($before+$after)) :
339 + $url = substr($url, 0, $before).'…'.substr($url, 0 - $after, $after);
292 340 endif;
293 341
294 - if ($original) : $vals = get_post_custom_values('syndication_source_uri_original');
295 - else : $vals = array();
342 + return $url;
343 +} /* feedwordpress_display_url () */
344 +
345 +function get_syndication_source_property ($original, $id, $local, $remote = NULL) {
346 + $ret = NULL;
347 + if (is_null($original)) :
348 + $original = FeedWordPress::use_aggregator_source_data();
296 349 endif;
297 350
298 - if (count($vals) == 0) : $vals = get_post_custom_values('syndication_source_uri');
351 + if (is_null($remote)) :
352 + $remote = $local . '_original';
299 353 endif;
300 354
301 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
302 -
303 - return $ret;
304 -} /* function get_syndication_source_link() */
305 -
306 -function the_syndication_source_link ($original = NULL) { echo get_syndication_source_link($original); }
307 -
308 -function get_syndication_source ($original = NULL) {
309 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
355 + $vals = ($original ? get_post_custom_values($remote, $id) : array());
356 + if (count($vals) < 1) :
357 + $vals = get_post_custom_values($local, $id);
310 358 endif;
311 -
312 - if ($original) : $vals = get_post_custom_values('syndication_source_original');
313 - else : $vals = array();
314 - endif;
315 359
316 - if (count($vals) == 0) : $vals = get_post_custom_values('syndication_source');
360 + if (count($vals) > 0) :
361 + $ret = $vals[0];
317 362 endif;
318 -
319 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
320 -
321 363 return $ret;
322 -} /* function get_syndication_source() */
364 +} /* function get_syndication_source_property () */
323 365
324 -function the_syndication_source ($original = NULL) { echo get_syndication_source($original); }
366 +function the_syndication_source_link ($original = NULL, $id = NULL) { echo get_syndication_source_link($original, $id); }
367 +function get_syndication_source_link ($original = NULL, $id = NULL) {
368 + return get_syndication_source_property($original, $id, 'syndication_source_uri');
369 +} /* function get_syndication_source_link() */
325 370
326 -function get_syndication_feed ($original = NULL) {
327 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
371 +function the_syndication_source ($original = NULL, $id = NULL) { echo get_syndication_source($original, $id); }
372 +function get_syndication_source ($original = NULL, $id = NULL) {
373 + $ret = get_syndication_source_property($original, $id, 'syndication_source');
374 + if (is_null($ret) or strlen(trim($ret)) == 0) : // Fall back to URL of blog
375 + $ret = feedwordpress_display_url(get_syndication_source_link());
328 376 endif;
377 + return $ret;
378 +} /* function get_syndication_source() */
329 379
330 - if ($original) : $vals = get_post_custom_values('syndication_feed_original');
331 - else : $vals = array();
332 - endif;
333 -
334 - if (count($vals) == 0) : $vals = get_post_custom_values('syndication_feed');
335 - endif;
336 -
337 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
338 -
339 - return $ret;
380 +function the_syndication_feed ($original = NULL, $id = NULL) { echo get_syndication_feed($original, $id); }
381 +function get_syndication_feed ($original = NULL, $id = NULL) {
382 + return get_syndication_source_property($original, $id, 'syndication_feed');
340 383 } /* function get_syndication_feed() */
341 384
342 -function the_syndication_feed ($original = NULL) { echo get_syndication_feed ($original); }
343 -
344 -function get_syndication_feed_guid ($original = NULL) {
345 - if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
385 +function the_syndication_feed_guid ($original = NULL, $id = NULL) { echo get_syndication_feed_guid($original, $id); }
386 +function get_syndication_feed_guid ($original = NULL, $id = NULL) {
387 + $ret = get_syndication_source_property($original, $id, 'syndication_source_id');
388 + if (is_null($ret) or strlen(trim($ret))==0) : // Fall back to URL of feed
389 + $ret = get_syndication_feed();
346 390 endif;
347 -
348 - if ($original) : $vals = get_post_custom_values('syndication_source_id_original');
349 - else : $vals = array();
350 - endif;
351 -
352 - if (count($vals) == 0) : $vals = array(get_feed_meta('feed/id'));
353 - endif;
354 -
355 - if (count($vals) > 0) : $ret = $vals[0]; else : $ret = NULL; endif;
356 -
357 391 return $ret;
358 392 } /* function get_syndication_feed_guid () */
359 393
360 -function the_syndication_feed_guid ($original = NULL) { echo get_syndication_feed_guid($original); }
394 +function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_values('syndication_feed_id', $id); return $u; }
395 +function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
361 396
362 -function get_syndication_feed_id () { list($u) = get_post_custom_values('syndication_feed_id'); return $u; }
363 -function the_syndication_feed_id () { echo get_syndication_feed_id(); }
364 -
365 397 $feedwordpress_linkcache = array (); // only load links from database once
398 +function get_syndication_feed_object ($id = NULL) {
399 + global $feedwordpress_linkcache;
366 400
367 -function get_feed_meta ($key) {
368 - global $wpdb, $feedwordpress_linkcache;
369 - $feed_id = get_syndication_feed_id();
401 + $link = NULL;
370 402
371 - $ret = NULL;
403 + $feed_id = get_syndication_feed_id($id);
372 404 if (strlen($feed_id) > 0):
373 405 if (isset($feedwordpress_linkcache[$feed_id])) :
374 406 $link = $feedwordpress_linkcache[$feed_id];
375 407 else :
376 - $link =& new SyndicatedLink($feed_id);
408 + $link = new SyndicatedLink($feed_id);
377 409 $feedwordpress_linkcache[$feed_id] = $link;
378 410 endif;
411 + endif;
412 + return $link;
413 +}
379 414
415 +function get_feed_meta ($key, $id = NULL) {
416 + $ret = NULL;
417 +
418 + $link = get_syndication_feed_object($id);
419 + if (is_object($link) and isset($link->settings[$key])) :
380 420 $ret = $link->settings[$key];
381 421 endif;
382 422 return $ret;
383 423 } /* get_feed_meta() */
384 424
385 -function get_syndication_permalink () {
386 - list($u) = get_post_custom_values('syndication_permalink'); return $u;
425 +function get_syndication_permalink ($id = NULL) {
426 + list($u) = get_post_custom_values('syndication_permalink', $id); return $u;
387 427 }
388 -function the_syndication_permalink () {
389 - echo get_syndication_permalink();
428 +function the_syndication_permalink ($id = NULL) {
429 + echo get_syndication_permalink($id);
390 430 }
391 431
432 +/**
433 + * get_local_permalink: returns a string containing the internal permalink
434 + * for a post (whether syndicated or not) on your local WordPress installation.
435 + * This may be useful if you want permalinks to point to the original source of
436 + * an article for most purposes, but want to retrieve a URL for the local
437 + * representation of the post for one or two limited purposes (for example,
438 + * linking to a comments page on your local aggregator site).
439 + *
440 + * @param $id The numerical ID of the post to get the permalink for. If empty,
441 + * defaults to the current post in a Loop context.
442 + * @return string The URL of the local permalink for this post.
443 + *
444 + * @uses get_permalink()
445 + * @global $feedwordpress_the_original_permalink
446 + *
447 + * @since 2010.0217
448 + */
449 +function get_local_permalink ($id = NULL) {
450 + global $feedwordpress_the_original_permalink;
451 +
452 + // get permalink, and thus activate filter and force global to be filled
453 + // with original URL.
454 + $url = get_permalink($id);
455 + return $feedwordpress_the_original_permalink;
456 +} /* get_local_permalink() */
457 +
458 +/**
459 + * the_original_permalink: displays the contents of get_original_permalink()
460 + *
461 + * @param $id The numerical ID of the post to get the permalink for. If empty,
462 + * defaults to the current post in a Loop context.
463 + *
464 + * @uses get_local_permalinks()
465 + * @uses apply_filters
466 + *
467 + * @since 2010.0217
468 + */
469 +function the_local_permalink ($id = NULL) {
470 + print apply_filters('the_permalink', get_local_permalink($id));
471 +} /* function the_local_permalink() */
472 +
392 473 ################################################################################
393 474 ## FILTERS: syndication-aware handling of post data for templates and feeds ####
394 475 ################################################################################
395 476
396 477 $feedwordpress_the_syndicated_content = NULL;
478 +$feedwordpress_the_original_permalink = NULL;
397 479
398 480 function feedwordpress_preserve_syndicated_content ($text) {
399 481 global $feedwordpress_the_syndicated_content;
400 482
@@ -424,16 +506,16 @@
424 506 // In a post context....
425 507 if (is_syndicated()) :
426 508 ?>
427 509 <source>
428 - <title><?php the_syndication_source(); ?></title>
429 - <link rel="alternate" type="text/html" href="<?php the_syndication_source_link(); ?>" />
430 - <link rel="self" href="<?php the_syndication_feed(); ?>" />
510 + <title><?php print htmlspecialchars(get_syndication_source()); ?></title>
511 + <link rel="alternate" type="text/html" href="<?php print htmlspecialchars(get_syndication_source_link()); ?>" />
512 + <link rel="self" href="<?php print htmlspecialchars(get_syndication_feed()); ?>" />
431 513 <?php
432 514 $id = get_syndication_feed_guid();
433 515 if (strlen($id) > 0) :
434 516 ?>
435 - <id><?php print $id; ?></id>
517 + <id><?php print htmlspecialchars($id); ?></id>
436 518 <?php
437 519 endif;
438 520 $updated = get_feed_meta('feed/updated');
439 521 if (strlen($updated) > 0) : ?>
@@ -445,46 +527,165 @@
445 527 <?php
446 528 endif;
447 529 }
448 530
449 -function syndication_permalink ($permalink = '') {
450 - if (get_option('feedwordpress_munge_permalink') != 'no'):
451 - $uri = get_syndication_permalink();
452 - return ((strlen($uri) > 0) ? $uri : $permalink);
453 - else:
454 - return $permalink;
531 +/**
532 + * syndication_permalink: Allow WordPress to use the original remote URL of
533 + * syndicated posts as their permalink. Can be turned on or off by by setting in
534 + * Syndication => Posts & Links. Saves the old internal permalink in a global
535 + * variable for later use.
536 + *
537 + * @param string $permalink The internal permalink
538 + * @return string The new permalink. Same as the old if the post is not
539 + * syndicated, or if FWP is set to use internal permalinks, or if the post
540 + * was syndicated, but didn't have a proper permalink recorded.
541 + *
542 + * @uses SyndicatedLink::setting()
543 + * @uses get_syndication_permalink()
544 + * @uses get_syndication_feed_object()
545 + * @uses url_to_postid()
546 + * @global $id
547 + * @global $feedwordpress_the_original_permalink
548 + */
549 +function syndication_permalink ($permalink = '', $post = null, $leavename = false) {
550 + global $id;
551 + global $feedwordpress_the_original_permalink;
552 +
553 + // Save the local permalink in case we need to retrieve it later.
554 + $feedwordpress_the_original_permalink = $permalink;
555 +
556 + if (is_object($post) and isset($post->ID) and !empty($post->ID)) :
557 + // Use the post ID we've been provided with.
558 + $postId = $post->ID;
559 + elseif (is_string($permalink) and strlen($permalink) > 0) :
560 + // Map this permalink to a post ID so we can get the correct
561 + // permalink even outside of the Post Loop. Props Björn.
562 + $postId = url_to_postid($permalink);
563 + else :
564 + // If the permalink string is empty but Post Loop context
565 + // provides an id.
566 + $postId = $id;
455 567 endif;
456 -} // function syndication_permalink ()
457 568
569 + $munge = false;
570 + $link = get_syndication_feed_object($postId);
571 + if (is_object($link)) :
572 + $munge = ($link->setting('munge permalink', 'munge_permalink', 'yes') != 'no');
573 + endif;
574 +
575 + if ($munge):
576 + $uri = get_syndication_permalink($postId);
577 + $permalink = ((strlen($uri) > 0) ? $uri : $permalink);
578 + endif;
579 + return $permalink;
580 +} /* function syndication_permalink () */
581 +
582 +/**
583 + * syndication_permalink_escaped: Escape XML special characters in syndicated
584 + * permalinks when used in feed contexts and HTML display contexts.
585 + *
586 + * @param string $permalink
587 + * @return string
588 + *
589 + * @uses is_syndicated()
590 + * @uses FeedWordPress::munge_permalinks()
591 + *
592 + */
593 +function syndication_permalink_escaped ($permalink) {
594 + /* FIXME: This should review link settings not just global settings */
595 + if (is_syndicated() and FeedWordPress::munge_permalinks()) :
596 + // This is a foreign link; WordPress can't vouch for its not
597 + // having any entities that need to be &-escaped. So we'll do
598 + // it here.
599 + $permalink = esc_html($permalink);
600 + endif;
601 + return $permalink;
602 +} /* function syndication_permalink_escaped() */
603 +
604 +/**
605 + * syndication_comments_feed_link: Escape XML special characters in comments
606 + * feed links
607 + *
608 + * @param string $link
609 + * @return string
610 + *
611 + * @uses is_syndicated()
612 + * @uses FeedWordPress::munge_permalinks()
613 + */
614 +function syndication_comments_feed_link ($link) {
615 + global $feedwordpress_the_original_permalink, $id;
616 +
617 + if (is_syndicated() and FeedWordPress::munge_permalinks()) :
618 + // If the source post provided a comment feed URL using
619 + // wfw:commentRss or atom:link/@rel="replies" we can make use of
620 + // that value here.
621 + $source = get_syndication_feed_object();
622 + $replacement = NULL;
623 + if ($source->setting('munge comments feed links', 'munge_comments_feed_links', 'yes') != 'no') :
624 + $commentFeeds = get_post_custom_values('wfw:commentRSS');
625 + if (
626 + is_array($commentFeeds)
627 + and (count($commentFeeds) > 0)
628 + and (strlen($commentFeeds[0]) > 0)
629 + ) :
630 + $replacement = $commentFeeds[0];
631 +
632 + // This is a foreign link; WordPress can't vouch for its not
633 + // having any entities that need to be &-escaped. So we'll do it
634 + // here.
635 + $replacement = esc_html($replacement);
636 + endif;
637 + endif;
638 +
639 + if (is_null($replacement)) :
640 + // Q: How can we get the proper feed format, since the
641 + // format is, stupidly, not passed to the filter?
642 + // A: Kludge kludge kludge kludge!
643 + $fancy_permalinks = ('' != get_option('permalink_structure'));
644 + if ($fancy_permalinks) :
645 + preg_match('|/feed(/([^/]+))?/?$|', $link, $ref);
646 +
647 + $format = (isset($ref[2]) ? $ref[2] : '');
648 + if (strlen($format) == 0) : $format = get_default_feed(); endif;
649 +
650 + $replacement = trailingslashit($feedwordpress_the_original_permalink) . 'feed';
651 + if ($format != get_default_feed()) :
652 + $replacement .= '/'.$format;
653 + endif;
654 + $replacement = user_trailingslashit($replacement, 'single_feed');
655 + else :
656 + // No fancy permalinks = no problem
657 + // WordPress doesn't call get_permalink() to
658 + // generate the comment feed URL, so the
659 + // comments feed link is never munged by FWP.
660 + endif;
661 + endif;
662 +
663 + if (!is_null($replacement)) : $link = $replacement; endif;
664 + endif;
665 + return $link;
666 +} /* function syndication_comments_feed_link() */
667 +
458 668 ################################################################################
459 669 ## ADMIN MENU ADD-ONS: register Dashboard management pages #####################
460 670 ################################################################################
461 671
462 672 function fwp_add_pages () {
463 - global $fwp_capability;
464 673 global $fwp_path;
465 674
466 - $menu = array('Syndicated Sites', 'Syndication', $fwp_capability['manage_links'], $fwp_path.'/syndication.php', NULL);
467 - if (fwp_test_wp_version(FWP_SCHEMA_27)) :
468 - // add icon parameter
469 - $menu[] = WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-tiny.png';
470 - endif;
471 -
472 - if (fwp_test_wp_version(FWP_SCHEMA_26)) :
473 - $options = __('Settings');
474 - $longoptions = __('Syndication Settings');
475 - else :
476 - $options = __('Options');
477 - $longoptions = __('Syndication Options');
478 - endif;
479 -
480 - call_user_func_array('add_menu_page', $menu);
481 - add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Posts', 'Posts', $fwp_capability['manage_options'], $fwp_path.'/posts-page.php');
482 - add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Authors', 'Authors', $fwp_capability['manage_options'], $fwp_path.'/authors-page.php');
483 - add_submenu_page($fwp_path.'/syndication.php', 'Categories & Tags', 'Categories & Tags', $fwp_capability['manage_options'], $fwp_path.'/categories-page.php');
484 - add_submenu_page($fwp_path.'/syndication.php', $longoptions, $options, $fwp_capability['manage_options'], $fwp_path.'/syndication-options.php');
485 -
486 - add_options_page($longoptions, 'Syndication', $fwp_capability['manage_options'], $fwp_path.'/syndication-options.php');
675 + add_menu_page('Syndicated Sites', 'Syndication', 'manage_links', $fwp_path.'/syndication.php', NULL, WP_PLUGIN_URL.'/'.$fwp_path.'/feedwordpress-tiny.png');
676 + do_action('feedwordpress_admin_menu_pre_feeds');
677 + add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Feeds & Updates', 'Feeds & Updates', 'manage_options', $fwp_path.'/feeds-page.php');
678 + do_action('feedwordpress_admin_menu_pre_posts');
679 + add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Posts & Links', 'Posts & Links', 'manage_options', $fwp_path.'/posts-page.php');
680 + do_action('feedwordpress_admin_menu_pre_authors');
681 + add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Authors', 'Authors', 'manage_options', $fwp_path.'/authors-page.php');
682 + do_action('feedwordpress_admin_menu_pre_categories');
683 + add_submenu_page($fwp_path.'/syndication.php', 'Categories'.FEEDWORDPRESS_AND_TAGS, 'Categories'.FEEDWORDPRESS_AND_TAGS, 'manage_options', $fwp_path.'/categories-page.php');
684 + do_action('feedwordpress_admin_menu_pre_performance');
685 + add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Performance', 'Performance', 'manage_options', $fwp_path.'/performance-page.php');
686 + do_action('feedwordpress_admin_menu_pre_diagnostics');
687 + add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Diagnostics', 'Diagnostics', 'manage_options', $fwp_path.'/diagnostics-page.php');
487 688 } /* function fwp_add_pages () */
488 689
489 690 function fwp_check_debug () {
490 691 // This is a horrible fucking kludge that I have to do because the
@@ -507,97 +708,8 @@
507 708 <?php
508 709 endif;
509 710 } /* function fwp_check_debug () */
510 711
511 -define('EXPECTED_MAGPIE_VERSION', '2009.0618');
512 -function fwp_check_magpie () {
513 - if (isset($_REQUEST['feedwordpress_magpie_fix'])) :
514 - if ($_REQUEST['feedwordpress_magpie_fix']=='ignored') :
515 -?>
516 -<div class="updated fade">
517 -<p>O.K., we'll ignore the problem for now. FeedWordPress will not display any
518 -more error messages.</p>
519 -</div>
520 -<?php
521 - elseif ((bool) $_REQUEST['feedwordpress_magpie_fix']) :
522 -?>
523 -<div class="updated fade">
524 -<p>Congratulations! Your MagpieRSS has been successfully upgraded to the version
525 -shipped with FeedWordPress.</p>
526 -</div>
527 -<?php
528 - else :
529 - $source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
530 - $destination = ABSPATH . WPINC . '/rss.php';
531 - $cmd = "cp '".htmlspecialchars(addslashes($source))."' '".htmlspecialchars(addslashes($destination))."'";
532 - $cmd = wordwrap($cmd, /*width=*/ 75, /*break=*/ " \\\n\t");
533 -
534 -?>
535 -<div class="error">
536 -<p><strong>FeedWordPress was unable to automatically upgrade your copy of MagpieRSS.</strong></p>
537 -<p>It's likely that you need to change the file permissions on <code><?php print htmlspecialchars($source); ?></code>
538 -to allow FeedWordPress to overwrite it.</p>
539 -<p><strong>To perform the upgrade manually,</strong> you can
540 -use a SFTP or FTP client to upload a copy of <code>rss.php</code> from the
541 -<code>MagpieRSS-upgrades/</code> directory of your FeedWordPress archive so that
542 -it overwrites <code><?php print htmlspecialchars($destination); ?></code>. Or,
543 -if your web host provides shell access, you can issue the following command from
544 -a command prompt to perform the upgrade:</p>
545 -<pre>
546 -<samp>$</samp> <kbd><?php print $cmd; ?></kbd>
547 -</pre>
548 -<p><strong>If you've fixed the file permissions,</strong> you can try the
549 -automatic upgrade again.</p>
550 -
551 -<?php feedwordpress_upgrade_old_and_busted_buttons(); ?>
552 -</div>
553 -<?php
554 - endif;
555 - else :
556 - $magpie_version = FeedWordPress::magpie_version();
557 -
558 - $ignored = get_option('feedwordpress_magpie_ignored_upgrade_to');
559 - if (EXPECTED_MAGPIE_VERSION != $magpie_version and EXPECTED_MAGPIE_VERSION != $ignored) :
560 - if (current_user_can('edit_files')) :
561 - $youAre = 'you are';
562 - $itIsRecommendedThatYou = 'It is <strong>strongly recommended</strong> that you';
563 - else :
564 - $youAre = 'this site is';
565 - $itIsRecommendedThatYou = 'You may want to contact the administrator of the site; it is <strong>strongly recommended</strong> that they';
566 - endif;
567 - print '<div class="error">';
568 -?>
569 -<p style="font-style: italic"><strong>FeedWordPress has detected that <?php print $youAre; ?> currently using a version of
570 -MagpieRSS other than the upgraded version that ships with this version of FeedWordPress.</strong></p>
571 -<ul>
572 -<li><strong>Currently running:</strong> MagpieRSS <?php print $magpie_version; ?></li>
573 -<li><strong>Version included with FeedWordPress <?php print FEEDWORDPRESS_VERSION; ?>:</strong> MagpieRSS <?php print EXPECTED_MAGPIE_VERSION; ?></li>
574 -</ul>
575 -<p><?php print $itIsRecommendedThatYou; ?> install the upgraded
576 -version of MagpieRSS supplied with FeedWordPress. The version of
577 -MagpieRSS that ships with WordPress is very old and buggy, and
578 -encounters a number of errors when trying to parse modern Atom
579 -and RSS feeds.</p>
580 -<?php
581 - feedwordpress_upgrade_old_and_busted_buttons();
582 - print '</div>';
583 - endif;
584 - endif;
585 -}
586 -
587 -function feedwordpress_upgrade_old_and_busted_buttons() {
588 - if (current_user_can('edit_files')) :
589 -?>
590 -<form action="" method="post"><div>
591 -<?php FeedWordPressCompatibility::stamp_nonce('feedwordpress_fix_magpie'); ?>
592 -<input type="hidden" name="action" value="fix_magpie_version" />
593 -<input class="button-secondary" type="submit" name="ignore" value="<?php _e('Ignore this problem'); ?>" />
594 -<input class="button-primary" type="submit" name="upgrade" value="<?php _e('Upgrade'); ?>" />
595 -</div></form>
596 -<?php
597 - endif;
598 -}
599 -
600 712 ################################################################################
601 713 ## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
602 714 ## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
603 715 ################################################################################
@@ -653,8 +765,67 @@
653 765 endif;
654 766 endif;
655 767 }
656 768
769 + function feedwordpress_add_post_edit_controls () {
770 + add_meta_box('feedwordpress-post-controls', __('Syndication'), 'feedwordpress_post_edit_controls', 'post', 'side', 'high');
771 + } // function FeedWordPress::postEditControls
772 +
773 + function feedwordpress_post_edit_controls () {
774 + global $post;
775 +
776 + $frozen_values = get_post_custom_values('_syndication_freeze_updates', $post->ID);
777 + $frozen_post = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]);
778 +
779 + if (is_syndicated($post->ID)) :
780 + ?>
781 + <p>This is a syndicated post, which originally appeared at
782 + <cite><?php print esc_html(get_syndication_source(NULL, $post->ID)); ?></cite>.
783 + <a href="<?php print esc_html(get_syndication_permalink($post->ID)); ?>">View original post</a>.</p>
784 +
785 + <p><input type="hidden" name="feedwordpress_noncename" id="feedwordpress_noncename" value="<?php print wp_create_nonce(plugin_basename(__FILE__)); ?>" />
786 + <label><input type="checkbox" name="freeze_updates" value="yes" <?php if ($frozen_post) : ?>checked="checked"<?php endif; ?> /> <strong>Manual editing.</strong>
787 + If set, FeedWordPress will not overwrite the changes you make manually
788 + to this post, if the syndicated content is updated on the
789 + feed.</label></p>
790 + <?php
791 + else :
792 + ?>
793 + <p>This post was created locally at this website.</p>
794 + <?php
795 + endif;
796 + } // function feedwordpress_post_edit_controls () */
797 +
798 + function feedwordpress_save_post_edit_controls ( $post_id ) {
799 + global $post;
800 +
801 + if (!isset($_POST['feedwordpress_noncename']) or !wp_verify_nonce($_POST['feedwordpress_noncename'], plugin_basename(__FILE__))) :
802 + return $post_id;
803 + endif;
804 +
805 + // Verify if this is an auto save routine. If it is our form has
806 + // not been submitted, so we don't want to do anything.
807 + if ( defined('DOING_AUTOSAVE') and DOING_AUTOSAVE ) :
808 + return $post_id;
809 + endif;
810 +
811 + // Check permissions
812 + if ( !current_user_can( 'edit_'.$_POST['post_type'], $post_id) ) :
813 + return $post_id;
814 + endif;
815 +
816 + // OK, we're golden. Now let's save some data.
817 + if (isset($_POST['freeze_updates'])) :
818 + update_post_meta($post_id, '_syndication_freeze_updates', $_POST['freeze_updates']);
819 + $ret = $_POST['freeze_updates'];
820 + else :
821 + delete_post_meta($post_id, '_syndication_freeze_updates');
822 + $ret = NULL;
823 + endif;
824 +
825 + return $ret;
826 + } // function feedwordpress_save_edit_controls
827 +
657 828 ################################################################################
658 829 ## class FeedWordPress #########################################################
659 830 ################################################################################
660 831
@@ -698,9 +869,9 @@
698 869 function FeedWordPress () {
699 870 $this->feeds = array ();
700 871 $links = FeedWordPress::syndicated_links();
701 872 if ($links): foreach ($links as $link):
702 - $this->feeds[] =& new SyndicatedLink($link);
873 + $this->feeds[] = new SyndicatedLink($link);
703 874 endforeach; endif;
704 875 } // FeedWordPress::FeedWordPress ()
705 876
706 877 # function update (): polls for updates on one or more Contributor feeds
@@ -758,9 +929,9 @@
758 929 if (FeedWordPress::needs_upgrade()) : // Will make duplicate posts if we don't hold off
759 930 return NULL;
760 931 endif;
761 932
762 - if (!is_null($uri)) :
933 + if (!is_null($uri) and $uri != '*') :
763 934 $uri = trim($uri);
764 935 else : // Update all
765 936 update_option('feedwordpress_last_update_all', time());
766 937 endif;
@@ -774,13 +945,15 @@
774 945 else :
775 946 $crash_ts = NULL;
776 947 endif;
777 948 endif;
778 -
949 +
779 950 // Randomize order for load balancing purposes
780 951 $feed_set = $this->feeds;
781 952 shuffle($feed_set);
782 953
954 + $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri);
955 +
783 956 // Loop through and check for new posts
784 957 $delta = NULL;
785 958 foreach ($feed_set as $feed) :
786 959 if (!is_null($crash_ts) and (time() > $crash_ts)) : // Check whether we've exceeded the time limit
@@ -786,9 +959,9 @@
786 959 if (!is_null($crash_ts) and (time() > $crash_ts)) : // Check whether we've exceeded the time limit
787 960 break;
788 961 endif;
789 962
790 - $pinged_that = (is_null($uri) or in_array($uri, array($feed->uri(), $feed->homepage())));
963 + $pinged_that = (is_null($uri) or ($uri=='*') or in_array($uri, array($feed->uri(), $feed->homepage())));
791 964
792 965 if (!is_null($uri)) : // A site-specific ping always updates
793 966 $timely = true;
794 967 else :
@@ -794,9 +967,9 @@
794 967 else :
795 968 $timely = $feed->stale();
796 969 endif;
797 970
798 - if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
971 + if ($pinged_that and is_null($delta)) : // If at least one feed was hit for updating...
799 972 $delta = array('new' => 0, 'updated' => 0); // ... don't return error condition
800 973 endif;
801 974
802 975 if ($pinged_that and $timely) :
@@ -804,10 +977,12 @@
804 977 $start_ts = time();
805 978 $added = $feed->poll($crash_ts);
806 979 do_action('feedwordpress_check_feed_complete', $feed->settings, $added, time() - $start_ts);
807 980
808 - if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
809 - if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
981 + if (is_array($added)) : // Success
982 + if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
983 + if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
984 + endif;
810 985 endif;
811 986 endforeach;
812 987
813 988 do_action('feedwordpress_update_complete', $delta);
@@ -816,8 +991,11 @@
816 991 }
817 992
818 993 function stale () {
819 994 if (get_option('feedwordpress_automatic_updates')) :
995 + // Do our best to avoid possible simultaneous
996 + // updates by getting up-to-the-minute settings.
997 +
820 998 $last = get_option('feedwordpress_last_update_all');
821 999
822 1000 // If we haven't updated all yet, give it a time window
823 1001 if (false === $last) :
@@ -836,70 +1014,196 @@
836 1014 else :
837 1015 FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__);
838 1016 endif;
839 1017
840 - // Explicit request for an update (e.g. from a cron job).
841 - elseif (FeedWordPress::update_requested()) :
842 - $ret = true;
843 -
844 1018 else :
845 1019 $ret = false;
846 1020 endif;
847 1021 return $ret;
848 1022 } // FeedWordPress::stale()
1023 +
1024 + function init () {
1025 + $this->clear_cache_magic_url();
1026 + $this->update_magic_url();
1027 + } /* FeedWordPress::init() */
849 1028
1029 + function dashboard_setup () {
1030 + // Get the stylesheet
1031 + wp_enqueue_style('feedwordpress-elements');
1032 +
1033 + $widget_id = 'feedwordpress_dashboard';
1034 + $widget_name = __('Syndicated Sources');
1035 + $column = 'side';
1036 + $priority = 'core';
1037 +
1038 + // I would love to use wp_add_dashboard_widget() here and save
1039 + // myself some trouble. But WP 3 does not yet have any way to
1040 + // push a dashboard widget onto the side, or to give it a default
1041 + // location.
1042 + add_meta_box(
1043 + /*id=*/ $widget_id,
1044 + /*title=*/ $widget_name,
1045 + /*callback=*/ array(&$this, 'dashboard'),
1046 + /*page=*/ 'dashboard',
1047 + /*context=*/ $column,
1048 + /*priority=*/ $priority
1049 + );
1050 + /*control_callback= array(&$this, 'dashboard_control') */
1051 +
1052 + // This is kind of rude, I know, but the dashboard widget isn't
1053 + // worth much if users don't know that it exists, and I don't
1054 + // know of any better way to reorder the boxen.
1055 + //
1056 + // Gleefully ripped off of codex.wordpress.org/Dashboard_Widgets_API
1057 +
1058 + // Globalize the metaboxes array, this holds all the widgets for wp-admin
1059 + global $wp_meta_boxes;
1060 +
1061 + // Get the regular dashboard widgets array
1062 + // (which has our new widget already but at the end)
1063 +
1064 + $normal_dashboard = $wp_meta_boxes['dashboard'][$column][$priority];
1065 +
1066 + // Backup and delete our new dashbaord widget from the end of the array
1067 + if (isset($normal_dashboard[$widget_id])) :
1068 + $backup = array();
1069 + $backup[$widget_id] = $normal_dashboard[$widget_id];
1070 + unset($normal_dashboard[$widget_id]);
1071 +
1072 + // Merge the two arrays together so our widget is at the
1073 + // beginning
1074 + $sorted_dashboard = array_merge($backup, $normal_dashboard);
1075 +
1076 + // Save the sorted array back into the original metaboxes
1077 + $wp_meta_boxes['dashboard'][$column][$priority] = $sorted_dashboard;
1078 + endif;
1079 + } /* FeedWordPress::dashboard_setup () */
1080 +
1081 + function dashboard () {
1082 + $syndicationPage = new FeedWordPressSyndicationPage(dirname(__FILE__).'/syndication.php');
1083 + $syndicationPage->dashboard_box($syndicationPage);
1084 + } /* FeedWordPress::dashboard () */
1085 +
1086 + function update_magic_url () {
1087 + global $wpdb;
1088 +
1089 + // Explicit update request in the HTTP request (e.g. from a cron job)
1090 + if ($this->update_requested()) :
1091 + $this->update($this->update_requested_url());
1092 +
1093 + if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
1094 + $mysqlTime = 0.0;
1095 + $byTime = array();
1096 + foreach ($wpdb->queries as $query) :
1097 + $time = $query[1] * 1000000.0;
1098 + $mysqlTime += $query[1];
1099 + if (!isset($byTime[$time])) : $byTime[$time] = array(); endif;
1100 + $byTime[$time][] = $query[0]. ' // STACK: ' . $query[2];
1101 + endforeach;
1102 + krsort($byTime);
1103 +
1104 + foreach ($byTime as $time => $querySet) :
1105 + foreach ($querySet as $query) :
1106 + print "[".(sprintf('%4.4f', $time/1000.0)) . "ms] $query\n";
1107 + endforeach;
1108 + endforeach;
1109 + echo $this->log_prefix()."$wpdb->num_queries queries. $mysqlTime seconds in MySQL. Total of "; timer_stop(1); print " seconds.";
1110 + endif;
1111 +
1112 + debug_out_feedwordpress_footer();
1113 +
1114 + // Magic URL should return nothing but a 200 OK header packet
1115 + // when successful.
1116 + exit;
1117 + endif;
1118 + } /* FeedWordPress::magic_update_url () */
1119 +
1120 + function clear_cache_magic_url () {
1121 + if ($this->clear_cache_requested()) :
1122 + $this->clear_cache();
1123 + endif;
1124 + } /* FeedWordPress::clear_cache_magic_url() */
1125 +
1126 + function clear_cache_requested () {
1127 + return (
1128 + isset($_GET['clear_cache'])
1129 + and $_GET['clear_cache']
1130 + );
1131 + } /* FeedWordPress::clear_cache_requested() */
1132 +
850 1133 function update_requested () {
851 - return (isset($_REQUEST['update_feedwordpress']) and $_REQUEST['update_feedwordpress']);
1134 + return (
1135 + isset($_REQUEST['update_feedwordpress'])
1136 + and $_REQUEST['update_feedwordpress']
1137 + );
852 1138 } // FeedWordPress::update_requested()
853 1139
854 - function syndicate_link ($name, $uri, $rss) {
1140 + function update_requested_url () {
1141 + $ret = null;
1142 +
1143 + if (($_REQUEST['update_feedwordpress']=='*')
1144 + or (preg_match('|^http://.*|i', $_REQUEST['update_feedwordpress']))) :
1145 + $ret = $_REQUEST['update_feedwordpress'];
1146 + endif;
1147 +
1148 + return $ret;
1149 + } // FeedWordPress::update_requested_url()
1150 +
1151 + function auto_update () {
1152 + if ($this->stale()) :
1153 + $this->update();
1154 + endif;
1155 + } /* FeedWordPress::auto_update () */
1156 +
1157 + function find_link ($uri, $field = 'link_rss') {
855 1158 global $wpdb;
856 1159
1160 + $unslashed = untrailingslashit($uri);
1161 + $slashed = trailingslashit($uri);
1162 + $link_id = $wpdb->get_var($wpdb->prepare("
1163 + SELECT link_id FROM $wpdb->links WHERE $field IN ('%s', '%s')
1164 + LIMIT 1", $unslashed, $slashed
1165 + ));
1166 +
1167 + return $link_id;
1168 + } /* FeedWordPress::find_link () */
1169 +
1170 + function syndicate_link ($name, $uri, $rss) {
857 1171 // Get the category ID#
858 1172 $cat_id = FeedWordPress::link_category_id();
859 1173
860 1174 // WordPress gets cranky if there's no homepage URI
861 - if (!isset($uri) or strlen($uri)<1) : $uri = $rss; endif;
1175 + if (!is_string($uri) or strlen($uri)<1) : $uri = $rss; endif;
862 1176
863 - if (function_exists('wp_insert_link')) { // WordPress 2.x
864 - $link_id = wp_insert_link(array(
865 - "link_name" => $name,
866 - "link_url" => $uri,
867 - "link_category" => (fwp_test_wp_version(0, FWP_SCHEMA_21) ? $cat_id : array($cat_id)),
868 - "link_rss" => $rss
869 - ));
870 - } else { // WordPress 1.5.x
871 - $result = $wpdb->query("
872 - INSERT INTO $wpdb->links
873 - SET
874 - link_name = '".$wpdb->escape($name)."',
875 - link_url = '".$wpdb->escape($uri)."',
876 - link_category = '".$wpdb->escape($cat_id)."',
877 - link_rss = '".$wpdb->escape($rss)."'
878 - ");
879 - $link_id = $wpdb->insert_id;
880 - } // if
1177 + // Check if this feed URL is already being syndicated.
1178 + $link_id = wp_insert_link(array(
1179 + "link_id" => FeedWordPress::find_link($rss), // insert if nothing was found; else update
1180 + "link_rss" => $rss,
1181 + "link_name" => $name,
1182 + "link_url" => $uri,
1183 + "link_category" => array($cat_id),
1184 + "link_visible" => 'Y', // reactivate if inactivated
1185 + ));
1186 +
881 1187 return $link_id;
882 - } // function FeedWordPress::syndicate_link()
1188 + } /* function FeedWordPress::syndicate_link() */
883 1189
884 - function on_unfamiliar ($what = 'author', $override = NULL) {
885 - $set = array(
886 - 'author' => array('create', 'default', 'filter'),
887 - 'category' => array('create', 'tag', 'default', 'filter'),
888 - );
889 -
890 - if (is_string($override)) :
891 - $ret = strtolower($override);
1190 + /*static*/ function syndicated_status ($what, $default) {
1191 + $ret = get_option("feedwordpress_syndicated_{$what}_status");
1192 + if (!$ret) :
1193 + $ret = $default;
892 1194 endif;
1195 + return $ret;
1196 + } /* FeedWordPress::syndicated_status() */
893 1197
894 - if (!is_numeric($override) and !in_array($ret, $set[$what])) :
895 - $ret = get_option('feedwordpress_unfamiliar_'.$what);
896 - if (!is_numeric($ret) and !in_array($ret, $set[$what])) :
897 - $ret = 'create';
898 - endif;
899 - endif;
900 -
901 - return $ret;
1198 + function on_unfamiliar ($what = 'author') {
1199 + switch ($what) :
1200 + case 'category' : $suffix = ':category'; break;
1201 + case 'post_tag' : $suffix = ':post_tag'; break;
1202 + default: $suffix = '';
1203 + endswitch;
1204 +
1205 + return get_option('feedwordpress_unfamiliar_'.$what, 'create'.$suffix);
902 1206 } // function FeedWordPress::on_unfamiliar()
903 1207
904 1208 function null_email_set () {
905 1209 $base = get_option('feedwordpress_null_email_set');
@@ -925,15 +1229,25 @@
925 1229 $ret = get_option('feedwordpress_use_aggregator_source_data');
926 1230 return apply_filters('syndicated_post_use_aggregator_source_data', ($ret=='yes'));
927 1231 }
928 1232
929 - function syndicated_links () {
1233 + /**
1234 + * FeedWordPress::munge_permalinks: check whether or not FeedWordPress
1235 + * should rewrite permalinks for syndicated items to reflect their
1236 + * original location.
1237 + *
1238 + * @return bool TRUE if FeedWordPress SHOULD rewrite permalinks; FALSE otherwise
1239 + */
1240 + /*static*/ function munge_permalinks () {
1241 + return (get_option('feedwordpress_munge_permalink', /*default=*/ 'yes') != 'no');
1242 + } /* FeedWordPress::munge_permalinks() */
1243 +
1244 + function syndicated_links ($args = array()) {
930 1245 $contributors = FeedWordPress::link_category_id();
931 - if (function_exists('get_bookmarks')) :
932 - $links = get_bookmarks(array("category" => $contributors));
933 - else:
934 - $links = get_linkobjects($contributors); // deprecated as of WP 2.1
935 - endif;
1246 + $links = get_bookmarks(array_merge(
1247 + array("category" => $contributors),
1248 + $args
1249 + ));
936 1250 return $links;
937 1251 } // function FeedWordPress::syndicated_links()
938 1252
939 1253 function link_category_id () {
@@ -940,61 +1254,31 @@
940 1254 global $wpdb, $wp_db_version;
941 1255
942 1256 $cat_id = get_option('feedwordpress_cat_id');
943 1257
944 - // If we don't yet *have* the category, we'll have to create it
945 - if ($cat_id === false) :
946 - $cat = $wpdb->escape(DEFAULT_SYNDICATION_CATEGORY);
947 -
948 - // Look for something with the right name...
949 - // -----------------------------------------
1258 + // If we don't yet have the category ID stored, search by name
1259 + if (!$cat_id) :
1260 + $cat_id = FeedWordPressCompatibility::link_category_id(DEFAULT_SYNDICATION_CATEGORY);
950 1261
951 - // WordPress 2.3 introduces a new taxonomy/term API
952 - if (function_exists('is_term')) :
953 - $cat_id = is_term($cat, 'link_category');
954 - // WordPress 2.1 and 2.2 use a common table for both link and post categories
955 - elseif (fwp_test_wp_version(FWP_SCHEMA_21, FWP_SCHEMA_23)) :
956 - $cat_id = $wpdb->get_var("SELECT cat_id FROM {$wpdb->categories} WHERE cat_name='$cat'");
957 - // WordPress 1.5 and 2.0.x have a separate table for link categories
958 - elseif (fwp_test_wp_version(0, FWP_SCHEMA_21)):
959 - $cat_id = $wpdb->get_var("SELECT cat_id FROM {$wpdb->linkcategories} WHERE cat_name='$cat'");
960 - // This should never happen.
961 - else :
962 - FeedWordPress::critical_bug('FeedWordPress::link_category_id::wp_db_version', $wp_db_version, __LINE__);
1262 + if ($cat_id) :
1263 + // We found it; let's stamp it.
1264 + update_option('feedwordpress_cat_id', $cat_id);
963 1265 endif;
964 1266
965 - // If you still can't find anything, make it for yourself.
966 - // -------------------------------------------------------
967 - if (!$cat_id) :
968 - // WordPress 2.3+ term/taxonomy API
969 - if (function_exists('wp_insert_term')) :
970 - $term = wp_insert_term($cat, 'link_category');
971 - $cat_id = $term['term_id'];
972 - // WordPress 2.1, 2.2 category API. By the way, why the fuck is this API function only available in a wp-admin module?
973 - elseif (function_exists('wp_insert_category') and !fwp_test_wp_version(FWP_SCHEMA_20, FWP_SCHEMA_21)) :
974 - $cat_id = wp_insert_category(array('cat_name' => $cat));
975 - // WordPress 1.5 and 2.0.x
976 - elseif (fwp_test_wp_version(0, FWP_SCHEMA_21)) :
977 - $result = $wpdb->query("
978 - INSERT INTO $wpdb->linkcategories
979 - SET
980 - cat_id = 0,
981 - cat_name='$cat',
982 - show_images='N',
983 - show_description='N',
984 - show_rating='N',
985 - show_updated='N',
986 - sort_order='name'
987 - ");
988 - $cat_id = $wpdb->insert_id;
989 - // This should never happen.
990 - else :
991 - FeedWordPress::critical_bug('FeedWordPress::link_category_id::wp_db_version', $wp_db_version, __LINE__);
992 - endif;
993 - endif;
1267 + // If we *do* have the category ID stored, verify that it exists
1268 + else :
1269 + $cat_id = FeedWordPressCompatibility::link_category_id((int) $cat_id, 'cat_id');
1270 + endif;
1271 +
1272 + // If we could not find an appropriate link category,
1273 + // make a new one for ourselves.
1274 + if (!$cat_id) :
1275 + $cat_id = FeedWordPressCompatibility::insert_link_category(DEFAULT_SYNDICATION_CATEGORY);
994 1276
1277 + // Stamp it
995 1278 update_option('feedwordpress_cat_id', $cat_id);
996 1279 endif;
1280 +
997 1281 return $cat_id;
998 1282 } // function FeedWordPress::link_category_id()
999 1283
1000 1284 # Upgrades and maintenance...
@@ -1018,15 +1302,47 @@
1018 1302 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1019 1303 endif;
1020 1304 elseif ($fwp_db_version < 2009.0707) :
1021 1305 // We need to clear out any busted AJAX crap
1022 - if (fwp_test_wp_version(FWP_SCHEMA_HAS_USERMETA)) :
1023 - $wpdb->query("
1024 - DELETE FROM $wpdb->usermeta
1025 - WHERE LOCATE('feedwordpress', meta_key)
1026 - AND LOCATE('box', meta_key);
1027 - ");
1306 + $wpdb->query("
1307 + DELETE FROM $wpdb->usermeta
1308 + WHERE LOCATE('feedwordpress', meta_key)
1309 + AND LOCATE('box', meta_key);
1310 + ");
1311 +
1312 + update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1313 + elseif ($fwp_db_version < 2010.0814) :
1314 + // Change in terminology.
1315 + if (get_option('feedwordpress_unfamiliar_category', 'create')=='default') :
1316 + update_option('feedwordpress_unfamiliar_category', 'null');
1028 1317 endif;
1318 + foreach (FeedWordPress::syndicated_links() as $link) :
1319 + $sub = new SyndicatedLink($link);
1320 +
1321 + $remap_uf = array(
1322 + 'default' => 'null',
1323 + 'filter' => 'null',
1324 + 'create' => 'create:category',
1325 + 'tag' => 'create:post_tag'
1326 + );
1327 + if (isset($sub->settings['unfamiliar category'])) :
1328 + if ($sub->settings['unfamiliar category']=='filter') :
1329 + $sub->settings['match/filter'] = array('category');
1330 + endif;
1331 + foreach ($remap_uf as $from => $to) :
1332 + if ($sub->settings['unfamiliar category']==$from) :
1333 + $sub->settings['unfamiliar category'] = $to;
1334 + endif;
1335 + endforeach;
1336 + endif;
1337 +
1338 + if (isset($sub->settings['add global categories'])) :
1339 + $sub->settings['add/category'] = $sub->settings['add global categories'];
1340 + unset($sub->settings['add global categories']);
1341 + endif;
1342 +
1343 + $sub->save_settings(/*reload=*/ true);
1344 + endforeach;
1029 1345 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1030 1346 else :
1031 1347 // No. Just brand it with the new version.
1032 1348 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
@@ -1040,56 +1356,14 @@
1040 1356
1041 1357 if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
1042 1358
1043 1359 switch ($from) :
1044 - case 0.96: // account for changes to syndication custom values and guid
1045 - echo "<p>Upgrading database from {$from} to ".FEEDWORDPRESS_VERSION."...</p>\n";
1360 + case 0.96:
1361 + // Dropping legacy upgrade code. If anyone is still
1362 + // using 0.96 and just now decided to upgrade, well, I'm
1363 + // sorry about that. You'll just have to cope with a few
1364 + // duplicate posts.
1046 1365
1047 - $cat_id = FeedWordPress::link_category_id();
1048 -
1049 - // Avoid duplicates
1050 - $wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key = 'syndication_feed_id'");
1051 -
1052 - // Look up all the link IDs
1053 - $wpdb->query("
1054 - CREATE TEMPORARY TABLE tmp_custom_values
1055 - SELECT
1056 - NULL AS meta_id,
1057 - post_id,
1058 - 'syndication_feed_id' AS meta_key,
1059 - link_id AS meta_value
1060 - FROM `{$wpdb->postmeta}`, `{$wpdb->links}`
1061 - WHERE
1062 - meta_key='syndication_feed'
1063 - AND meta_value=link_rss
1064 - AND link_category = {$cat_id}
1065 - ");
1066 -
1067 - // Now attach them to their posts
1068 - $wpdb->query("INSERT INTO `{$wpdb->postmeta}` SELECT * FROM tmp_custom_values");
1069 -
1070 - // And clean up after ourselves.
1071 - $wpdb->query("DROP TABLE tmp_custom_values");
1072 -
1073 - // Now fix the guids to avoid duplicate posts
1074 - echo "<ul>";
1075 - foreach ($this->feeds as $feed) :
1076 - echo "<li>Fixing post meta-data for <cite>".$feed['link/name']."</cite> &#8230; "; flush();
1077 - $rss = @fetch_rss($feed['link/uri']);
1078 - if (is_array($rss->items)) :
1079 - foreach ($rss->items as $item) :
1080 - $guid = $wpdb->escape(FeedWordPress::guid($item, $feed)); // new GUID algorithm
1081 - $link = $wpdb->escape($item['link']);
1082 -
1083 - $wpdb->query("
1084 - UPDATE `{$wpdb->posts}` SET guid='{$guid}' WHERE guid='{$link}'
1085 - ");
1086 - endforeach;
1087 - endif;
1088 - echo "<strong>complete.</strong></li>\n";
1089 - endforeach;
1090 - echo "</ul>\n";
1091 -
1092 1366 // Mark the upgrade as successful.
1093 1367 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1094 1368 endswitch;
1095 1369 echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
@@ -1094,8 +1368,27 @@
1094 1368 endswitch;
1095 1369 echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
1096 1370 } /* FeedWordPress::upgrade_database() */
1097 1371
1372 + function has_guid_index () {
1373 + global $wpdb;
1374 +
1375 + $found = false; // Guilty until proven innocent.
1376 +
1377 + $results = $wpdb->get_results("
1378 + SHOW INDEXES FROM {$wpdb->posts}
1379 + ");
1380 + if ($results) :
1381 + foreach ($results as $index) :
1382 + if (isset($index->Column_name)
1383 + and ('guid' == $index->Column_name)) :
1384 + $found = true;
1385 + endif;
1386 + endforeach;
1387 + endif;
1388 + return $found;
1389 + } /* FeedWordPress::has_guid_index () */
1390 +
1098 1391 function create_guid_index () {
1099 1392 global $wpdb;
1100 1393
1101 1394 $wpdb->query("
@@ -1102,15 +1395,83 @@
1102 1395 CREATE INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}(guid)
1103 1396 ");
1104 1397 } /* FeedWordPress::create_guid_index () */
1105 1398
1106 - function magpie_version () {
1107 - if (!defined('MAGPIE_VERSION')) : $magpie_version = $GLOBALS['wp_version'].'-default';
1108 - else : $magpie_version = MAGPIE_VERSION;
1399 + function remove_guid_index () {
1400 + global $wpdb;
1401 +
1402 + $wpdb->query("
1403 + DROP INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}
1404 + ");
1405 + }
1406 +
1407 + /*static*/ function fetch ($url, $force_feed = true) {
1408 + $feed = new SimplePie();
1409 + $feed->set_feed_url($url);
1410 + $feed->set_cache_class('WP_Feed_Cache');
1411 + $feed->set_file_class('WP_SimplePie_File');
1412 + $feed->set_content_type_sniffer_class('FeedWordPress_Content_Type_Sniffer');
1413 + $feed->set_file_class('FeedWordPress_File');
1414 + $feed->set_parser_class('FeedWordPress_Parser');
1415 + $feed->force_feed($force_feed);
1416 + $feed->set_cache_duration(FeedWordPress::cache_duration());
1417 + $feed->init();
1418 + $feed->handle_content_type();
1419 +
1420 + if ($feed->error()) :
1421 + $ret = new WP_Error('simplepie-error', $feed->error());
1422 + else :
1423 + $ret = $feed;
1109 1424 endif;
1110 - return $magpie_version;
1425 + return $ret;
1426 + } /* FeedWordPress::fetch () */
1427 +
1428 + function clear_cache () {
1429 + global $wpdb;
1430 +
1431 + // Just in case, clear out any old MagpieRSS cache records.
1432 + $magpies = $wpdb->query("
1433 + DELETE FROM {$wpdb->options}
1434 + WHERE option_name LIKE 'rss_%' AND LENGTH(option_name) > 32
1435 + ");
1436 +
1437 + // The WordPress SimplePie module stores its cached feeds as
1438 + // transient records in the options table. The data itself is
1439 + // stored in `_transient_feed_{md5 of url}` and the last-modified
1440 + // timestamp in `_transient_feed_mod_{md5 of url}`. Timeouts for
1441 + // these records are stored in `_transient_timeout_feed_{md5}`.
1442 + // Since the md5 is always 32 characters in length, the
1443 + // option_name is always over 32 characters.
1444 + $simplepies = $wpdb->query("
1445 + DELETE FROM {$wpdb->options}
1446 + WHERE option_name LIKE '_transient%_feed_%' AND LENGTH(option_name) > 32
1447 + ");
1448 + $simplepies = (int) ($simplepies / 4); // Each transient has 4 rows: the data, the modified timestamp; and the timeouts for each
1449 +
1450 + return ($magpies + $simplepies);
1451 + } /* FeedWordPress::clear_cache () */
1452 +
1453 + function cache_duration () {
1454 + $duration = NULL;
1455 + if (defined('FEEDWORDPRESS_CACHE_AGE')) :
1456 + $duration = FEEDWORDPRESS_CACHE_AGE;
1457 + endif;
1458 + return $duration;
1111 1459 }
1460 + function cache_lifetime ($duration) {
1461 + // Check for explicit setting of a lifetime duration
1462 + if (defined('FEEDWORDPRESS_CACHE_LIFETIME')) :
1463 + $duration = FEEDWORDPRESS_CACHE_LIFETIME;
1112 1464
1465 + // Fall back to the cache freshness duration
1466 + elseif (defined('FEEDWORDPRESS_CACHE_AGE')) :
1467 + $duration = FEEDWORDPRESS_CACHE_AGE;
1468 + endif;
1469 +
1470 + // Fall back to WordPress default
1471 + return $duration;
1472 + } /* FeedWordPress::cache_lifetime () */
1473 +
1113 1474 # Utility functions for handling text settings
1114 1475 function negative ($f, $setting) {
1115 1476 $nego = array ('n', 'no', 'f', 'false');
1116 1477 return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $nego));
@@ -1120,22 +1481,16 @@
1120 1481 $affirmo = array ('y', 'yes', 't', 'true', 1);
1121 1482 return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $affirmo));
1122 1483 }
1123 1484
1124 -
1125 1485 # Internal debugging functions
1126 1486 function critical_bug ($varname, $var, $line) {
1127 1487 global $wp_version;
1128 1488
1129 - if (defined('MAGPIE_VERSION')) : $mv = MAGPIE_VERSION;
1130 - else : $mv = 'WordPress '.$wp_version.' default.';
1131 - endif;
1132 -
1133 1489 echo '<p>There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
1134 1490 echo "\n<plaintext>";
1135 1491 echo "Triggered at line # ".$line."\n";
1136 1492 echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n";
1137 - echo "MagpieRSS version: {$mv}\n";
1138 1493 echo "WordPress version: {$wp_version}\n";
1139 1494 echo "PHP version: ".phpversion()."\n";
1140 1495 echo "\n";
1141 1496 echo $varname.": "; var_dump($var); echo "\n";
@@ -1146,41 +1501,524 @@
1146 1501 if (FEEDWORDPRESS_DEBUG) : // halt only when we are doing debugging
1147 1502 FeedWordPress::critical_bug($varname, $var, $line);
1148 1503 endif;
1149 1504 }
1505 +
1506 + function val ($v, $no_newlines = false) {
1507 + ob_start();
1508 + var_dump($v);
1509 + $out = ob_get_contents(); ob_end_clean();
1510 +
1511 + if ($no_newlines) :
1512 + $out = preg_replace('/\s+/', " ", $out);
1513 + endif;
1514 + return $out;
1515 + } /* FeedWordPress::val () */
1516 +
1517 + function diagnostic_on ($level) {
1518 + $show = get_option('feedwordpress_diagnostics_show', array());
1519 + return (in_array($level, $show));
1520 + } /* FeedWordPress::diagnostic_on () */
1521 +
1522 + function diagnostic ($level, $out, $persist = NULL, $since = NULL, $mostRecent = NULL) {
1523 + global $feedwordpress_admin_footer;
1524 +
1525 + $output = get_option('feedwordpress_diagnostics_output', array());
1526 + $dlog = get_option('feedwordpress_diagnostics_log', array());
1527 +
1528 + $diagnostic_nesting = count(explode(":", $level));
1529 +
1530 + if (FeedWordPress::diagnostic_on($level)) :
1531 + foreach ($output as $method) :
1532 + switch ($method) :
1533 + case 'echo' :
1534 + echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>";
1535 + break;
1536 + case 'echo_in_cronjob' :
1537 + if (FeedWordPress::update_requested()) :
1538 + echo FeedWordPress::log_prefix()." ".$out."\n";
1539 + endif;
1540 + break;
1541 + case 'admin_footer' :
1542 + $feedwordpress_admin_footer[] = $out;
1543 + break;
1544 + case 'error_log' :
1545 + error_log(FeedWordPress::log_prefix().' '.$out);
1546 + break;
1547 + case 'email' :
1548 + if (is_null($persist)) :
1549 + $sect = 'occurrent';
1550 + $hook = (isset($dlog['mesg'][$sect]) ? count($dlog['mesg'][$sect]) : 0);
1551 + $line = array("Time" => time(), "Message" => $out);
1552 + else :
1553 + $sect = 'persistent';
1554 + $hook = md5($level."\n".$persist);
1555 + $line = array("Since" => $since, "Message" => $out, "Most Recent" => $mostRecent);
1556 + endif;
1557 +
1558 + if (!isset($dlog['mesg'])) : $dlog['mesg'] = array(); endif;
1559 + if (!isset($dlog['mesg'][$sect])) : $dlog['mesg'][$sect] = array(); endif;
1560 +
1561 + $dlog['mesg'][$sect][$hook] = $line;
1562 + endswitch;
1563 + endforeach;
1564 + endif;
1565 +
1566 + update_option('feedwordpress_diagnostics_log', $dlog);
1567 + } /* FeedWordPress::diagnostic () */
1568 +
1569 + function email_diagnostic_log () {
1570 + $dlog = get_option('feedwordpress_diagnostics_log', array());
1571 +
1572 + $recipients = get_option('feedwordpress_diagnostics_log_recipients', NULL);
1573 + if (is_null($recipients)) :
1574 + $recipients = FeedWordPressDiagnostic::admin_emails();
1575 + endif;
1576 +
1577 + if (isset($dlog['schedule']) and isset($dlog['schedule']['last'])) :
1578 + if (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq'])) :
1579 + // No news is good news; only send if
1580 + // there are some messages to send.
1581 + $body = NULL;
1582 + foreach ($dlog['mesg'] as $sect => $mesgs) :
1583 + if (count($mesgs) > 0) :
1584 + if (is_null($body)) : $body = ''; endif;
1585 +
1586 + $paradigm = reset($mesgs);
1587 + $body .= "<h2>".ucfirst($sect)." issues</h2>\n"
1588 + ."<table>\n"
1589 + ."<thead><tr>\n";
1590 + foreach ($paradigm as $col => $value) :
1591 + $body .= '<th scope="col">'.$col."</th>\n";
1592 + endforeach;
1593 + $body .= "</tr></thead>\n"
1594 + ."<tbody>\n";
1595 +
1596 + foreach ($mesgs as $line) :
1597 + $body .= "<tr>\n";
1598 + foreach ($line as $col => $cell) :
1599 + if (is_numeric($cell)) :
1600 + $cell = date('j-M-y, h:i a', $cell);
1601 + endif;
1602 + $class = strtolower(preg_replace('/\s+/', '-', $col));
1603 + $body .= "<td class=\"$class\">${cell}</td>";
1604 + endforeach;
1605 + $body .= "</tr>\n";
1606 + endforeach;
1607 +
1608 + $body .= "</tbody>\n</table>\n\n";
1609 + endif;
1610 + endforeach;
1611 +
1612 + if (!is_null($body)) :
1613 + $home = feedwordpress_display_url(get_bloginfo('url'));
1614 + $subj = $home . " syndication issues for ".date('j-M-y', time());
1615 + $agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION;
1616 + $body = <<<EOMAIL
1617 +<html>
1618 +<head>
1619 +<title>$subj</title>
1620 +<style type="text/css">
1621 + body { background-color: white; color: black; }
1622 + table { width: 100%; border: 1px solid black; }
1623 + table thead tr th { background-color: #ff7700; color: white; border-bottom: 1px solid black; }
1624 + table thead tr { border-bottom: 1px solid black; }
1625 + table tr { vertical-align: top; }
1626 + table .since { width: 20%; }
1627 + table .time { width: 20%; }
1628 + table .most-recently { width: 20%; }
1629 + table .message { width: auto; }
1630 +</style>
1631 +</head>
1632 +<body>
1633 +<h1>Syndication Issues encountered by $agent on $home</h1>
1634 +$body
1635 +</body>
1636 +</html>
1637 +
1638 +EOMAIL;
1639 + foreach ($recipients as $email) :
1640 + add_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1641 + wp_mail($email, $subj, $body);
1642 + remove_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1643 + endforeach;
1644 + endif;
1645 +
1646 + // Clear the logs
1647 + $dlog['mesg']['persistent'] = array();
1648 + $dlog['mesg']['occurrent'] = array();
1649 +
1650 + // Set schedule for next update
1651 + $dlog['schedule']['last'] = time();
1652 + endif;
1653 + else :
1654 + $dlog['schedule'] = array(
1655 + 'freq' =>24 /*hr*/ * 60 /*min*/ * 60 /*s*/,
1656 + 'last' => time(),
1657 + );
1658 + endif;
1659 +
1660 + update_option('feedwordpress_diagnostics_log', $dlog);
1661 + } /* FeedWordPress::email_diagnostic_log () */
1662 +
1663 + function allow_html_mail () {
1664 + return 'text/html';
1665 + } /* FeedWordPress::allow_html_mail () */
1666 +
1667 + function admin_footer () {
1668 + global $feedwordpress_admin_footer;
1669 + foreach ($feedwordpress_admin_footer as $line) :
1670 + echo '<div><pre>'.$line.'</pre></div>';
1671 + endforeach;
1672 + } /* FeedWordPress::admin_footer () */
1673 +
1674 + function log_prefix ($date = false) {
1675 + $home = get_bloginfo('url');
1676 + $prefix = '['.feedwordpress_display_url($home).'] [feedwordpress] ';
1677 + if ($date) :
1678 + $prefix = "[".date('Y-m-d H:i:s')."]".$prefix;
1679 + endif;
1680 + return $prefix;
1681 + } /* FeedWordPress::log_prefix () */
1150 1682 } // class FeedWordPress
1151 1683
1152 -require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
1153 -require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
1684 +class FeedWordPress_File extends WP_SimplePie_File {
1685 + function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
1686 + WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
1154 1687
1688 + // SimplePie makes a strongly typed check against integers with
1689 + // this, but WordPress puts a string in. Which causes caching
1690 + // to break and fall on its ass when SimplePie is getting a 304,
1691 + // but doesn't realize it because this member is "304" instead.
1692 + $this->status_code = (int) $this->status_code;
1693 + }
1694 +} /* class FeedWordPress_File () */
1695 +
1696 +class FeedWordPress_Parser extends SimplePie_Parser {
1697 + function parse (&$data, $encoding) {
1698 + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
1699 + if (strtoupper($encoding) === 'US-ASCII')
1700 + {
1701 + $this->encoding = 'UTF-8';
1702 + }
1703 + else
1704 + {
1705 + $this->encoding = $encoding;
1706 + }
1707 +
1708 + // Strip BOM:
1709 + // UTF-32 Big Endian BOM
1710 + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
1711 + {
1712 + $data = substr($data, 4);
1713 + }
1714 + // UTF-32 Little Endian BOM
1715 + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
1716 + {
1717 + $data = substr($data, 4);
1718 + }
1719 + // UTF-16 Big Endian BOM
1720 + elseif (substr($data, 0, 2) === "\xFE\xFF")
1721 + {
1722 + $data = substr($data, 2);
1723 + }
1724 + // UTF-16 Little Endian BOM
1725 + elseif (substr($data, 0, 2) === "\xFF\xFE")
1726 + {
1727 + $data = substr($data, 2);
1728 + }
1729 + // UTF-8 BOM
1730 + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
1731 + {
1732 + $data = substr($data, 3);
1733 + }
1734 +
1735 + if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
1736 + {
1737 + $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
1738 + if ($declaration->parse())
1739 + {
1740 + $data = substr($data, $pos + 2);
1741 + $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
1742 + }
1743 + else
1744 + {
1745 + $this->error_string = 'SimplePie bug! Please report this!';
1746 + return false;
1747 + }
1748 + }
1749 +
1750 + $return = true;
1751 +
1752 + static $xml_is_sane = null;
1753 + if ($xml_is_sane === null)
1754 + {
1755 + $parser_check = xml_parser_create();
1756 + xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1757 + xml_parser_free($parser_check);
1758 + $xml_is_sane = isset($values[0]['value']);
1759 + }
1760 +
1761 + // Create the parser
1762 + if ($xml_is_sane)
1763 + {
1764 + $xml = xml_parser_create_ns($this->encoding, $this->separator);
1765 + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
1766 + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
1767 + xml_set_object($xml, $this);
1768 + xml_set_character_data_handler($xml, 'cdata');
1769 + xml_set_element_handler($xml, 'tag_open', 'tag_close');
1770 + xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
1771 +
1772 + // Parse!
1773 + if (!xml_parse($xml, $data, true))
1774 + {
1775 + $this->error_code = xml_get_error_code($xml);
1776 + $this->error_string = xml_error_string($this->error_code);
1777 + $return = false;
1778 + }
1779 +
1780 + $this->current_line = xml_get_current_line_number($xml);
1781 + $this->current_column = xml_get_current_column_number($xml);
1782 + $this->current_byte = xml_get_current_byte_index($xml);
1783 + xml_parser_free($xml);
1784 +
1785 + return $return;
1786 + }
1787 + else
1788 + {
1789 + libxml_clear_errors();
1790 + $xml =& new XMLReader();
1791 + $xml->xml($data);
1792 + while (@$xml->read())
1793 + {
1794 + switch ($xml->nodeType)
1795 + {
1796 +
1797 + case constant('XMLReader::END_ELEMENT'):
1798 + if ($xml->namespaceURI !== '')
1799 + {
1800 + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1801 + }
1802 + else
1803 + {
1804 + $tagName = $xml->localName;
1805 + }
1806 + $this->tag_close(null, $tagName);
1807 + break;
1808 + case constant('XMLReader::ELEMENT'):
1809 + $empty = $xml->isEmptyElement;
1810 + if ($xml->namespaceURI !== '')
1811 + {
1812 + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1813 + }
1814 + else
1815 + {
1816 + $tagName = $xml->localName;
1817 + }
1818 + $attributes = array();
1819 + while ($xml->moveToNextAttribute())
1820 + {
1821 + if ($xml->namespaceURI !== '')
1822 + {
1823 + $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
1824 + }
1825 + else
1826 + {
1827 + $attrName = $xml->localName;
1828 + }
1829 + $attributes[$attrName] = $xml->value;
1830 + }
1831 +
1832 + foreach ($attributes as $attr => $value) :
1833 + list($ns, $local) = $this->split_ns($attr);
1834 + if ($ns=='http://www.w3.org/2000/xmlns/') :
1835 + if ('xmlns' == $local) : $local = false; endif;
1836 + $this->start_xmlns(null, $local, $value);
1837 + endif;
1838 + endforeach;
1839 +
1840 + $this->tag_open(null, $tagName, $attributes);
1841 + if ($empty)
1842 + {
1843 + $this->tag_close(null, $tagName);
1844 + }
1845 + break;
1846 + case constant('XMLReader::TEXT'):
1847 +
1848 + case constant('XMLReader::CDATA'):
1849 + $this->cdata(null, $xml->value);
1850 + break;
1851 + }
1852 + }
1853 + if ($error = libxml_get_last_error())
1854 + {
1855 + $this->error_code = $error->code;
1856 + $this->error_string = $error->message;
1857 + $this->current_line = $error->line;
1858 + $this->current_column = $error->column;
1859 + return false;
1860 + }
1861 + else
1862 + {
1863 + return true;
1864 + }
1865 + }
1866 + } /* FeedWordPress_Parser::parse() */
1867 +
1868 + var $xmlns_stack = array();
1869 + var $xmlns_current = array();
1870 + function tag_open ($parser, $tag, $attributes) {
1871 + $ret = parent::tag_open($parser, $tag, $attributes);
1872 + if ($this->current_xhtml_construct < 0) :
1873 + $this->data['xmlns'] = $this->xmlns_current;
1874 + $this->xmlns_stack[] = $this->xmlns_current;
1875 + endif;
1876 + return $ret;
1877 + }
1878 +
1879 + function tag_close($parser, $tag) {
1880 + if ($this->current_xhtml_construct < 0) :
1881 + $this->xmlns_current = array_pop($this->xmlns_stack);
1882 + endif;
1883 + $ret = parent::tag_close($parser, $tag);
1884 + return $ret;
1885 + }
1886 +
1887 + function start_xmlns ($parser, $prefix, $uri) {
1888 + if (!$prefix) :
1889 + $prefix = '';
1890 + endif;
1891 + if ($this->current_xhtml_construct < 0) :
1892 + $this->xmlns_current[$prefix] = $uri;
1893 + endif;
1894 + return true;
1895 + } /* FeedWordPress_Parser::start_xmlns() */
1896 +}
1897 +
1898 +$feedwordpress_admin_footer = array();
1899 +
1155 1900 ################################################################################
1156 1901 ## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
1157 1902 ################################################################################
1158 1903
1159 -function feedwordpress_xmlrpc_hook ($args = array ()) {
1160 - $args['weblogUpdates.ping'] = 'feedwordpress_pong';
1161 - return $args;
1162 -}
1904 +class FeedWordPressRPC {
1905 + function FeedWordPressRPC () {
1906 + add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
1907 + }
1908 +
1909 + function xmlrpc_methods ($args = array()) {
1910 + $args['weblogUpdates.ping'] = array(&$this, 'ping');
1911 + $args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
1912 + $args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
1913 + $args['feedwordpress.delete'] = array(&$this, 'delete');
1914 + $args['feedwordpress.nuke'] = array(&$this, 'nuke');
1915 + return $args;
1916 + }
1917 +
1918 + function ping ($args) {
1919 + global $feedwordpress;
1920 +
1921 + $delta = @$feedwordpress->update($args[1]);
1922 + if (is_null($delta)):
1923 + return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
1924 + else:
1925 + $mesg = array();
1926 + if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
1927 + if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
1928 +
1929 + return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
1930 + endif;
1931 + }
1932 +
1933 + function validate (&$args) {
1934 + global $wp_xmlrpc_server;
1163 1935
1164 -function feedwordpress_pong ($args) {
1165 - $feedwordpress =& new FeedWordPress;
1166 - $delta = @$feedwordpress->update($args[1]);
1167 - if (is_null($delta)):
1168 - return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
1169 - else:
1170 - $mesg = array();
1171 - if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
1172 - if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
1936 + // First two params are username/password
1937 + $username = $wp_xmlrpc_server->escape(array_shift($args));
1938 + $password = $wp_xmlrpc_server->escape(array_shift($args));
1173 1939
1174 - return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
1175 - endif;
1176 -}
1940 + $ret = array();
1941 + if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
1942 + $ret = $wp_xmlrpc_server->error;
1943 + elseif (!current_user_can('manage_links')) :
1944 + $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
1945 + endif;
1946 + return $ret;
1947 + }
1177 1948
1178 -# The upgraded MagpieRSS also uses this class. So if we have it loaded
1179 -# in, don't load it again.
1180 -if (!class_exists('Relative_URI')) {
1181 - require_once(dirname(__FILE__) . '/relative_uri.class.php');
1182 -}
1949 + function subscribe ($args) {
1950 + $ret = $this->validate($args);
1951 + if (is_array($ret)) : // Success
1952 + // The remaining params are feed URLs
1953 + foreach ($args as $arg) :
1954 + $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
1955 + $feeds = array_values(array_unique($finder->find()));
1956 +
1957 + if (count($feeds) > 0) :
1958 + $link_id = FeedWordPress::syndicate_link(
1959 + /*title=*/ feedwordpress_display_url($feeds[0]),
1960 + /*homepage=*/ $feeds[0],
1961 + /*feed=*/ $feeds[0]
1962 + );
1963 + $ret[] = array(
1964 + 'added',
1965 + $feeds[0],
1966 + $arg,
1967 + );
1968 + else :
1969 + $ret[] = array(
1970 + 'error',
1971 + $arg
1972 + );
1973 + endif;
1974 + endforeach;
1975 + endif;
1976 + return $ret;
1977 + } /* FeedWordPressRPC::subscribe () */
1978 +
1979 + function unsubscribe ($method, $args) {
1980 + $ret = $this->validate($args);
1981 + if (is_array($ret)) : // Success
1982 + // The remaining params are feed URLs
1983 + foreach ($args as $arg) :
1984 + $link_id = FeedWordPress::find_link($arg);
1985 +
1986 + if (!$link_id) :
1987 + $link_id = FeedWordPress::find_link($arg, 'link_url');
1988 + endif;
1989 +
1990 + if ($link_id) :
1991 + $link = new SyndicatedLink($link_id);
1992 +
1993 + $link->{$method}();
1994 + $ret[] = array(
1995 + 'deactivated',
1996 + $arg,
1997 + );
1998 + else :
1999 + $ret[] = array(
2000 + 'error',
2001 + $arg,
2002 + );
2003 + endif;
2004 + endforeach;
2005 + endif;
2006 + return $ret;
2007 + } /* FeedWordPress::unsubscribe () */
2008 +
2009 + function deactivate ($args) {
2010 + return $this->unsubscribe('deactivate', $args);
2011 + } /* FeedWordPressRPC::deactivate () */
2012 +
2013 + function delete ($args) {
2014 + return $this->unsubscribe('delete', $args);
2015 + } /* FeedWordPressRPC::delete () */
2016 +
2017 + function nuke ($args) {
2018 + return $this->unsubscribe('nuke', $args);
2019 + } /* FeedWordPressRPC::nuke () */
2020 +} /* class FeedWordPressRPC */
1183 2021
1184 2022 // take your best guess at the realname and e-mail, given a string
1185 2023 define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
1186 2024 define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');