PluginProbe
FeedWordPress / 2010.0531
FeedWordPress v2010.0531
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 +387 -238 2010.01272010.0531 View file →
@@ -2,14 +2,19 @@
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.0127
6 +Version: 2010.0531
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.0531
15 + */
16 +
12 17 # This uses code derived from:
13 18 # - wp-rss-aggregate.php by Kellan Elliot-McCrea <kellan@protest.net>
14 19 # - HTTP Navigator 2 by Keyvan Minoukadeh <keyvan@k1m.com>
15 20 # - Ultra-Liberal Feed Finder by Mark Pilgrim <mark@diveintomark.org>
@@ -27,9 +32,9 @@
27 32 # or use a cron job.
28 33
29 34 # -- Don't change these unless you know what you're doing...
30 35
31 -define ('FEEDWORDPRESS_VERSION', '2010.0127');
36 +define ('FEEDWORDPRESS_VERSION', '2010.0531');
32 37 define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
33 38
34 39 // Defaults
35 40 define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
@@ -65,9 +70,8 @@
65 70 if (FEEDWORDPRESS_DEBUG) :
66 71 // Help us to pick out errors, if any.
67 72 ini_set('error_reporting', E_ALL & ~E_NOTICE);
68 73 ini_set('display_errors', true);
69 - define('MAGPIE_DEBUG', true);
70 74
71 75 // When testing we don't want cache issues to interfere. But this is
72 76 // a VERY BAD SETTING for a production server. Webmasters will eat your
73 77 // face for breakfast if you use it, and the baby Jesus will cry. So
@@ -72,24 +76,25 @@
72 76 // a VERY BAD SETTING for a production server. Webmasters will eat your
73 77 // face for breakfast if you use it, and the baby Jesus will cry. So
74 78 // make sure FEEDWORDPRESS_DEBUG is FALSE for any site that will be
75 79 // used for more than testing purposes!
76 - define('MAGPIE_CACHE_AGE', 1);
80 + define('FEEDWORDPRESS_CACHE_AGE', 1);
81 + define('FEEDWORDPRESS_CACHE_LIFETIME', 1);
82 + define('FEEDWORDPRESS_FETCH_TIME_OUT', 60);
77 83 else :
78 - define('MAGPIE_DEBUG', false);
79 -
80 - define('MAGPIE_CACHE_AGE', 1*60);
84 + // Hold onto data all day for conditional GET purposes,
85 + // but consider it stale after 1 min (requiring a conditional GET)
86 + define('FEEDWORDPRESS_CACHE_LIFETIME', 24*60*60);
87 + define('FEEDWORDPRESS_CACHE_AGE', 1*60);
88 + define('FEEDWORDPRESS_FETCH_TIME_OUT', 10);
81 89 endif;
82 90
83 -// Note that the rss-functions.php that comes prepackaged with WordPress is
84 -// old & busted. For the new hotness, drop a copy of rss.php from
85 -// this archive into wp-includes/rss.php
91 +// Use our the cache settings that we want.
92 +add_filter('wp_feed_cache_transient_lifetime', array('FeedWordPress', 'cache_lifetime'));
86 93
87 -if (is_readable(ABSPATH . WPINC . '/rss.php')) :
88 - require_once (ABSPATH . WPINC . '/rss.php');
89 -else :
90 - require_once (ABSPATH . WPINC . '/rss-functions.php');
91 -endif;
94 +// Ensure that we have SimplePie loaded up and ready to go.
95 +// We no longer need a MagpieRSS upgrade module. Hallelujah!
96 +require_once(ABSPATH . WPINC . '/feed.php');
92 97
93 98 if (isset($wp_db_version)) :
94 99 if ($wp_db_version >= FWP_SCHEMA_23) :
95 100 require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
@@ -176,8 +181,15 @@
176 181
177 182 # Filter in original permalinks if the user wants that
178 183 add_filter('post_link', 'syndication_permalink', 1);
179 184
185 + # When foreign URLs are used for permalinks in feeds or display
186 + # contexts, they need to be escaped properly.
187 + add_filter('the_permalink', 'syndication_permalink_escaped');
188 + add_filter('the_permalink_rss', 'syndication_permalink_escaped');
189 +
190 + add_filter('post_comments_feed_link', 'syndication_comments_feed_link');
191 +
180 192 # WTF? By default, wp_insert_link runs incoming link_url and link_rss
181 193 # URIs through default filters that include `wp_kses()`. But `wp_kses()`
182 194 # just happens to escape any occurrence of & to &amp; -- which just
183 195 # happens to fuck up any URI with a & to separate GET parameters.
@@ -186,14 +198,14 @@
186 198
187 199 # Admin menu
188 200 add_action('admin_menu', 'fwp_add_pages');
189 201 add_action('admin_notices', 'fwp_check_debug');
190 - add_action('admin_notices', 'fwp_check_magpie');
191 - add_action('init', 'feedwordpress_check_for_magpie_fix');
192 202
193 203 add_action('admin_menu', 'feedwordpress_add_post_edit_controls');
194 204 add_action('save_post', 'feedwordpress_save_post_edit_controls');
195 205
206 + add_action('admin_footer', array('FeedWordPress', 'admin_footer'));
207 +
196 208 # Inbound XML-RPC update methods
197 209 add_filter('xmlrpc_methods', 'feedwordpress_xmlrpc_hook');
198 210
199 211 # Outbound XML-RPC ping reform
@@ -215,14 +227,18 @@
215 227 add_action('feedwordpress_check_feed', 'log_feedwordpress_check_feed', 100);
216 228 add_action('feedwordpress_update_complete', 'log_feedwordpress_update_complete', 100);
217 229 endif;
218 230
219 - if (FeedWordPress::update_requested() and FEEDWORDPRESS_DEBUG) :
220 - add_action('post_syndicated_item', 'debug_out_feedwordpress_post', 100);
221 - add_action('update_syndicated_item', 'debug_out_feedwordpress_update_post', 100);
222 - add_action('feedwordpress_update', 'debug_out_feedwordpress_update_feeds', 100);
223 - add_action('feedwordpress_check_feed', 'debug_out_feedwordpress_check_feed', 100);
224 - add_action('feedwordpress_update_complete', 'debug_out_feedwordpress_update_complete', 100);
231 + if (FeedWordPress::update_requested()) :
232 + if (FEEDWORDPRESS_DEBUG) :
233 + add_action('post_syndicated_item', 'debug_out_feedwordpress_post', 100);
234 + add_action('update_syndicated_item', 'debug_out_feedwordpress_update_post', 100);
235 + add_action('feedwordpress_update', 'debug_out_feedwordpress_update_feeds', 100);
236 + add_action('feedwordpress_check_feed', 'debug_out_feedwordpress_check_feed', 100);
237 + add_action('feedwordpress_update_complete', 'debug_out_feedwordpress_update_complete', 100);
238 + endif;
239 +
240 + add_action('feedwordpress_check_feed_complete', 'debug_out_feedwordpress_feed_error', 100, 3);
225 241 endif;
226 242
227 243 # Cron-less auto-update. Hooray!
228 244 $autoUpdateHook = get_option('feedwordpress_automatic_updates');
@@ -241,44 +257,11 @@
241 257 # Hook in the menus, which will just point to the upgrade interface
242 258 add_action('admin_menu', 'fwp_add_pages');
243 259 endif; // if (!FeedWordPress::needs_upgrade())
244 260
245 -function feedwordpress_check_for_magpie_fix () {
246 - if (isset($_POST['action']) and $_POST['action']=='fix_magpie_version') :
247 - FeedWordPressCompatibility::validate_http_request(/*action=*/ 'feedwordpress_fix_magpie', /*capability=*/ 'edit_files');
248 -
249 - $back_to = $_SERVER['REQUEST_URI'];
250 - if (isset($_POST['ignore'])) :
251 - // kill error message by telling it we ignored the upgrade request for this version
252 - update_option('feedwordpress_magpie_ignored_upgrade_to', EXPECTED_MAGPIE_VERSION);
253 - $ret = 'ignored';
254 - elseif (isset($_POST['upgrade'])) :
255 - $source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
256 - $destination = ABSPATH . WPINC . '/rss.php';
257 - $success = @copy($source, $destination);
258 -
259 - // Copy over rss-functions.php, too, to avoid collisions
260 - // on pre-lapsarian versions of WordPress.
261 - if ($success) :
262 - $source = dirname(__FILE__)."/MagpieRSS-upgrade/rss-functions.php";
263 - $destination = ABSPATH . WPINC . '/rss-functions.php';
264 - $success = @copy($source, $destination);
265 - endif;
266 - $ret = (int) $success;
267 - endif;
268 -
269 - if (strpos($back_to, '?')===false) : $sep = '?';
270 - else : $sep = '&';
271 - endif;
272 -
273 - header("Location: {$back_to}{$sep}feedwordpress_magpie_fix=".$ret);
274 - exit;
275 - endif;
276 -} /* feedwordpress_check_for_magpie_fix() */
277 -
278 261 function feedwordpress_auto_update () {
279 262 if (FeedWordPress::stale()) :
280 - $feedwordpress =& new FeedWordPress;
263 + $feedwordpress = new FeedWordPress;
281 264 $feedwordpress->update();
282 265 endif;
283 266 } /* feedwordpress_auto_update () */
284 267
@@ -286,9 +269,9 @@
286 269 global $wpdb;
287 270
288 271 // Explicit update request in the HTTP request (e.g. from a cron job)
289 272 if (FeedWordPress::update_requested()) :
290 - $feedwordpress =& new FeedWordPress;
273 + $feedwordpress = new FeedWordPress;
291 274 $feedwordpress->update(FeedWordPress::update_requested_url());
292 275
293 276 if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
294 277 $mysqlTime = 0.0;
@@ -385,13 +368,33 @@
385 368 .(is_null($delta) ? "Error: I don't syndicate that URI"
386 369 : implode(' and ', $mesg))."\n");
387 370 }
388 371
372 +function debug_out_feedwordpress_feed_error ($feed, $added, $dt) {
373 + if (is_wp_error($added)) :
374 + $mesgs = $added->get_error_messages();
375 + foreach ($mesgs as $mesg) :
376 + echo "[feedwordpress] Error updating [{$feed['link/uri']}]: $mesg\n";
377 + endforeach;
378 + endif;
379 +}
380 +
389 381 ################################################################################
390 382 ## TEMPLATE API: functions to make your templates syndication-aware ############
391 383 ################################################################################
392 384
393 -function is_syndicated ($id = NULL) { return (strlen(get_syndication_feed_id($id)) > 0); }
385 +/**
386 + * is_syndicated: Tests whether the current post in a Loop context, or a post
387 + * given by ID number, was syndicated by FeedWordPress. Useful for templates
388 + * to determine whether or not to retrieve syndication-related meta-data in
389 + * displaying a post.
390 + *
391 + * @param int $id The post to check for syndicated status. Defaults to the current post in a Loop context.
392 + * @return bool TRUE if the post's meta-data indicates it was syndicated; FALSE otherwise
393 + */
394 +function is_syndicated ($id = NULL) {
395 + return (strlen(get_syndication_feed_id($id)) > 0);
396 +} /* function is_syndicated() */
394 397
395 398 function get_syndication_source_link ($original = NULL, $id = NULL) {
396 399 if (is_null($original)) : $original = FeedWordPress::use_aggregator_source_data();
397 400 endif;
@@ -421,8 +424,9 @@
421 424 // Reassemble bit-by-bit with minimum of crufty elements
422 425 $url = (isset($bits['user'])?$bits['user'].'@':'')
423 426 .(isset($bits['host'])?$bits['host']:'')
424 427 .(isset($bits['path'])?$bits['path']:'')
428 + .(isset($uri_bits['port'])?':'.$uri_bits['port']:'')
425 429 .(isset($bits['query'])?'?'.$bits['query']:'');
426 430
427 431 if (strlen($url) > ($before+$after)) :
428 432 $url = substr($url, 0, $before).'…'.substr($url, 0 - $after, $after);
@@ -501,22 +505,30 @@
501 505 function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_values('syndication_feed_id', $id); return $u; }
502 506 function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
503 507
504 508 $feedwordpress_linkcache = array (); // only load links from database once
509 +function get_syndication_feed_object ($id = NULL) {
510 + global $feedwordpress_linkcache;
505 511
506 -function get_feed_meta ($key, $id = NULL) {
507 - global $wpdb, $feedwordpress_linkcache;
512 + $link = NULL;
513 +
508 514 $feed_id = get_syndication_feed_id($id);
509 -
510 - $ret = NULL;
511 515 if (strlen($feed_id) > 0):
512 516 if (isset($feedwordpress_linkcache[$feed_id])) :
513 517 $link = $feedwordpress_linkcache[$feed_id];
514 518 else :
515 - $link =& new SyndicatedLink($feed_id);
519 + $link = new SyndicatedLink($feed_id);
516 520 $feedwordpress_linkcache[$feed_id] = $link;
517 521 endif;
522 + endif;
523 + return $link;
524 +}
518 525
526 +function get_feed_meta ($key, $id = NULL) {
527 + $ret = NULL;
528 +
529 + $link = get_syndication_feed_object($id);
530 + if (is_object($link) and isset($link->settings[$key])) :
519 531 $ret = $link->settings[$key];
520 532 endif;
521 533 return $ret;
522 534 } /* get_feed_meta() */
@@ -527,13 +539,55 @@
527 539 function the_syndication_permalink ($id = NULL) {
528 540 echo get_syndication_permalink($id);
529 541 }
530 542
543 +/**
544 + * get_local_permalink: returns a string containing the internal permalink
545 + * for a post (whether syndicated or not) on your local WordPress installation.
546 + * This may be useful if you want permalinks to point to the original source of
547 + * an article for most purposes, but want to retrieve a URL for the local
548 + * representation of the post for one or two limited purposes (for example,
549 + * linking to a comments page on your local aggregator site).
550 + *
551 + * @param $id The numerical ID of the post to get the permalink for. If empty,
552 + * defaults to the current post in a Loop context.
553 + * @return string The URL of the local permalink for this post.
554 + *
555 + * @uses get_permalink()
556 + * @global $feedwordpress_the_original_permalink
557 + *
558 + * @since 2010.0217
559 + */
560 +function get_local_permalink ($id = NULL) {
561 + global $feedwordpress_the_original_permalink;
562 +
563 + // get permalink, and thus activate filter and force global to be filled
564 + // with original URL.
565 + $url = get_permalink($id);
566 + return $feedwordpress_the_original_permalink;
567 +} /* get_local_permalink() */
568 +
569 +/**
570 + * the_original_permalink: displays the contents of get_original_permalink()
571 + *
572 + * @param $id The numerical ID of the post to get the permalink for. If empty,
573 + * defaults to the current post in a Loop context.
574 + *
575 + * @uses get_local_permalinks()
576 + * @uses apply_filters
577 + *
578 + * @since 2010.0217
579 + */
580 +function the_local_permalink ($id = NULL) {
581 + print apply_filters('the_permalink', get_local_permalink($id));
582 +} /* function the_local_permalink() */
583 +
531 584 ################################################################################
532 585 ## FILTERS: syndication-aware handling of post data for templates and feeds ####
533 586 ################################################################################
534 587
535 588 $feedwordpress_the_syndicated_content = NULL;
589 +$feedwordpress_the_original_permalink = NULL;
536 590
537 591 function feedwordpress_preserve_syndicated_content ($text) {
538 592 global $feedwordpress_the_syndicated_content;
539 593
@@ -584,17 +638,131 @@
584 638 <?php
585 639 endif;
586 640 }
587 641
642 +/**
643 + * syndication_permalink: Allow WordPress to use the original remote URL of
644 + * syndicated posts as their permalink. Can be turned on or off by by setting in
645 + * Syndication => Posts & Links. Saves the old internal permalink in a global
646 + * variable for later use.
647 + *
648 + * @param string $permalink The internal permalink
649 + * @return string The new permalink. Same as the old if the post is not
650 + * syndicated, or if FWP is set to use internal permalinks, or if the post
651 + * was syndicated, but didn't have a proper permalink recorded.
652 + *
653 + * @uses FeedWordPress::munge_permalinks()
654 + * @uses get_syndication_permalink()
655 + * @global $feedwordpress_the_original_permalink
656 + */
588 657 function syndication_permalink ($permalink = '') {
589 - if (get_option('feedwordpress_munge_permalink') != 'no'):
590 - $uri = get_syndication_permalink();
591 - return ((strlen($uri) > 0) ? $uri : $permalink);
592 - else:
593 - return $permalink;
658 + global $feedwordpress_the_original_permalink;
659 +
660 + // Save the local permalink in case we need to retrieve it later.
661 + $feedwordpress_the_original_permalink = $permalink;
662 +
663 + // Map this permalink to a post ID so we can get the correct permalink
664 + // even outside of the Post Loop. Props Björn.
665 + $id = url_to_postid($permalink);
666 +
667 + $munge = false;
668 + $link = get_syndication_feed_object($id);
669 + if (is_object($link)) :
670 + $munge = ($link->setting('munge permalink', 'munge_permalink', 'yes') != 'no');
594 671 endif;
595 -} // function syndication_permalink ()
596 672
673 + if ($munge):
674 + $uri = get_syndication_permalink($id);
675 + $permalink = ((strlen($uri) > 0) ? $uri : $permalink);
676 + endif;
677 + return $permalink;
678 +} /* function syndication_permalink () */
679 +
680 +/**
681 + * syndication_permalink_escaped: Escape XML special characters in syndicated
682 + * permalinks when used in feed contexts and HTML display contexts.
683 + *
684 + * @param string $permalink
685 + * @return string
686 + *
687 + * @uses is_syndicated()
688 + * @uses FeedWordPress::munge_permalinks()
689 + *
690 + */
691 +function syndication_permalink_escaped ($permalink) {
692 + if (is_syndicated() and FeedWordPress::munge_permalinks()) :
693 + // This is a foreign link; WordPress can't vouch for its not
694 + // having any entities that need to be &-escaped. So we'll do
695 + // it here.
696 + $permalink = esc_html($permalink);
697 + endif;
698 + return $permalink;
699 +} /* function syndication_permalink_escaped() */
700 +
701 +/**
702 + * syndication_comments_feed_link: Escape XML special characters in comments
703 + * feed links
704 + *
705 + * @param string $link
706 + * @return string
707 + *
708 + * @uses is_syndicated()
709 + * @uses FeedWordPress::munge_permalinks()
710 + */
711 +function syndication_comments_feed_link ($link) {
712 + global $feedwordpress_the_original_permalink, $id;
713 +
714 + if (is_syndicated() and FeedWordPress::munge_permalinks()) :
715 + // If the source post provided a comment feed URL using
716 + // wfw:commentRss or atom:link/@rel="replies" we can make use of
717 + // that value here.
718 + $source = get_syndication_feed_object();
719 + $replacement = NULL;
720 + if ($source->setting('munge comments feed links', 'munge_comments_feed_links', 'yes') != 'no') :
721 + $commentFeeds = get_post_custom_values('wfw:commentRSS');
722 + if (
723 + is_array($commentFeeds)
724 + and (count($commentFeeds) > 0)
725 + and (strlen($commentFeeds[0]) > 0)
726 + ) :
727 + $replacement = $commentFeeds[0];
728 +
729 + // This is a foreign link; WordPress can't vouch for its not
730 + // having any entities that need to be &-escaped. So we'll do it
731 + // here.
732 + $replacement = esc_html($replacement);
733 + endif;
734 + endif;
735 +
736 + if (is_null($replacement)) :
737 + // Q: How can we get the proper feed format, since the
738 + // format is, stupidly, not passed to the filter?
739 + // A: Kludge kludge kludge kludge!
740 + $fancy_permalinks = ('' != get_option('permalink_structure'));
741 + if ($fancy_permalinks) :
742 + preg_match('|/feed(/([^/]+))?/?$|', $link, $ref);
743 +
744 + $format = (isset($ref[2]) ? $ref[2] : '');
745 + if (strlen($format) == 0) : $format = get_default_feed(); endif;
746 +
747 + $replacement = trailingslashit($feedwordpress_the_original_permalink) . 'feed';
748 + if ($format != get_default_feed()) :
749 + $replacement .= '/'.$format;
750 + endif;
751 + $replacement = user_trailingslashit($replacement, 'single_feed');
752 + else :
753 + // No fancy permalinks = no problem
754 + // WordPress doesn't call get_permalink() to
755 + // generate the comment feed URL, so the
756 + // comments feed link is never munged by FWP.
757 + endif;
758 + endif;
759 +
760 + if (!is_null($replacement)) : $link = $replacement; endif;
761 + endif;
762 + return $link;
763 +} /* function syndication_comments_feed_link() */
764 +
597 765 ################################################################################
598 766 ## ADMIN MENU ADD-ONS: register Dashboard management pages #####################
599 767 ################################################################################
600 768
@@ -612,9 +780,10 @@
612 780 add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Feeds & Updates', 'Feeds & Updates', $fwp_capability['manage_options'], $fwp_path.'/feeds-page.php');
613 781 add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Posts & Links', 'Posts & Links', $fwp_capability['manage_options'], $fwp_path.'/posts-page.php');
614 782 add_submenu_page($fwp_path.'/syndication.php', 'Syndicated Authors', 'Authors', $fwp_capability['manage_options'], $fwp_path.'/authors-page.php');
615 783 add_submenu_page($fwp_path.'/syndication.php', 'Categories'.FEEDWORDPRESS_AND_TAGS, 'Categories'.FEEDWORDPRESS_AND_TAGS, $fwp_capability['manage_options'], $fwp_path.'/categories-page.php');
616 - add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Back End', 'Back End', $fwp_capability['manage_options'], $fwp_path.'/backend-page.php');
784 + add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Performance', 'Performance', $fwp_capability['manage_options'], $fwp_path.'/performance-page.php');
785 + add_submenu_page($fwp_path.'/syndication.php', 'FeedWordPress Diagnostics', 'Diagnostics', $fwp_capability['manage_options'], $fwp_path.'/diagnostics-page.php');
617 786 } /* function fwp_add_pages () */
618 787
619 788 function fwp_check_debug () {
620 789 // This is a horrible fucking kludge that I have to do because the
@@ -637,97 +806,8 @@
637 806 <?php
638 807 endif;
639 808 } /* function fwp_check_debug () */
640 809
641 -define('EXPECTED_MAGPIE_VERSION', '2010.0122');
642 -function fwp_check_magpie () {
643 - if (isset($_REQUEST['feedwordpress_magpie_fix'])) :
644 - if ($_REQUEST['feedwordpress_magpie_fix']=='ignored') :
645 -?>
646 -<div class="updated fade">
647 -<p>O.K., we'll ignore the problem for now. FeedWordPress will not display any
648 -more error messages.</p>
649 -</div>
650 -<?php
651 - elseif ((bool) $_REQUEST['feedwordpress_magpie_fix']) :
652 -?>
653 -<div class="updated fade">
654 -<p>Congratulations! Your MagpieRSS has been successfully upgraded to the version
655 -shipped with FeedWordPress.</p>
656 -</div>
657 -<?php
658 - else :
659 - $source = dirname(__FILE__)."/MagpieRSS-upgrade/rss.php";
660 - $destination = ABSPATH . WPINC . '/rss.php';
661 - $cmd = "cp '".htmlspecialchars(addslashes($source))."' '".htmlspecialchars(addslashes($destination))."'";
662 - $cmd = wordwrap($cmd, /*width=*/ 75, /*break=*/ " \\\n\t");
663 -
664 -?>
665 -<div class="error">
666 -<p><strong>FeedWordPress was unable to automatically upgrade your copy of MagpieRSS.</strong></p>
667 -<p>It's likely that you need to change the file permissions on <code><?php print htmlspecialchars($source); ?></code>
668 -to allow FeedWordPress to overwrite it.</p>
669 -<p><strong>To perform the upgrade manually,</strong> you can
670 -use a SFTP or FTP client to upload a copy of <code>rss.php</code> from the
671 -<code>MagpieRSS-upgrades/</code> directory of your FeedWordPress archive so that
672 -it overwrites <code><?php print htmlspecialchars($destination); ?></code>. Or,
673 -if your web host provides shell access, you can issue the following command from
674 -a command prompt to perform the upgrade:</p>
675 -<pre>
676 -<samp>$</samp> <kbd><?php print $cmd; ?></kbd>
677 -</pre>
678 -<p><strong>If you've fixed the file permissions,</strong> you can try the
679 -automatic upgrade again.</p>
680 -
681 -<?php feedwordpress_upgrade_old_and_busted_buttons(); ?>
682 -</div>
683 -<?php
684 - endif;
685 - else :
686 - $magpie_version = FeedWordPress::magpie_version();
687 -
688 - $ignored = get_option('feedwordpress_magpie_ignored_upgrade_to');
689 - if (EXPECTED_MAGPIE_VERSION != $magpie_version and EXPECTED_MAGPIE_VERSION != $ignored) :
690 - if (current_user_can('edit_files')) :
691 - $youAre = 'you are';
692 - $itIsRecommendedThatYou = 'It is <strong>strongly recommended</strong> that you';
693 - else :
694 - $youAre = 'this site is';
695 - $itIsRecommendedThatYou = 'You may want to contact the administrator of the site; it is <strong>strongly recommended</strong> that they';
696 - endif;
697 - print '<div class="error">';
698 -?>
699 -<p style="font-style: italic"><strong>FeedWordPress has detected that <?php print $youAre; ?> currently using a version of
700 -MagpieRSS other than the upgraded version that ships with this version of FeedWordPress.</strong></p>
701 -<ul>
702 -<li><strong>Currently running:</strong> MagpieRSS <?php print $magpie_version; ?></li>
703 -<li><strong>Version included with FeedWordPress <?php print FEEDWORDPRESS_VERSION; ?>:</strong> MagpieRSS <?php print EXPECTED_MAGPIE_VERSION; ?></li>
704 -</ul>
705 -<p><?php print $itIsRecommendedThatYou; ?> install the upgraded
706 -version of MagpieRSS supplied with FeedWordPress. The version of
707 -MagpieRSS that ships with WordPress is very old and buggy, and
708 -encounters a number of errors when trying to parse modern Atom
709 -and RSS feeds.</p>
710 -<?php
711 - feedwordpress_upgrade_old_and_busted_buttons();
712 - print '</div>';
713 - endif;
714 - endif;
715 -}
716 -
717 -function feedwordpress_upgrade_old_and_busted_buttons() {
718 - if (current_user_can('edit_files')) :
719 -?>
720 -<form action="" method="post"><div>
721 -<?php FeedWordPressCompatibility::stamp_nonce('feedwordpress_fix_magpie'); ?>
722 -<input type="hidden" name="action" value="fix_magpie_version" />
723 -<input class="button-secondary" type="submit" name="ignore" value="<?php _e('Ignore this problem'); ?>" />
724 -<input class="button-primary" type="submit" name="upgrade" value="<?php _e('Upgrade'); ?>" />
725 -</div></form>
726 -<?php
727 - endif;
728 -}
729 -
730 810 ################################################################################
731 811 ## fwp_hold_pings() and fwp_release_pings(): Outbound XML-RPC ping reform ####
732 812 ## ... 'coz it's rude to send 500 pings the first time your aggregator runs ####
733 813 ################################################################################
@@ -796,10 +876,10 @@
796 876
797 877 if (is_syndicated($post->ID)) :
798 878 ?>
799 879 <p>This is a syndicated post, which originally appeared at
800 - <cite><?php print wp_specialchars(get_syndication_source(NULL, $post->ID)); ?></cite>.
801 - <a href="<?php print wp_specialchars(get_syndication_permalink($post->ID)); ?>">View original post</a>.</p>
880 + <cite><?php print esc_html(get_syndication_source(NULL, $post->ID)); ?></cite>.
881 + <a href="<?php print esc_html(get_syndication_permalink($post->ID)); ?>">View original post</a>.</p>
802 882
803 883 <p><input type="hidden" name="feedwordpress_noncename" id="feedwordpress_noncename" value="<?php print wp_create_nonce(plugin_basename(__FILE__)); ?>" />
804 884 <label><input type="checkbox" name="freeze_updates" value="yes" <?php if ($frozen_post) : ?>checked="checked"<?php endif; ?> /> <strong>Manual editing.</strong>
805 885 If set, FeedWordPress will not overwrite the changes you make manually
@@ -832,14 +912,16 @@
832 912 endif;
833 913
834 914 // OK, we're golden. Now let's save some data.
835 915 if (isset($_POST['freeze_updates'])) :
836 - update_post_meta($post_id, '_syndication_freeze_updates', $_POST['freeze_updates']);
916 + update_post_meta($post_id, '_syndication_freeze_updates', $_POST['freeze_updates']);
917 + $ret = $_POST['freeze_updates'];
837 918 else :
838 919 delete_post_meta($post_id, '_syndication_freeze_updates');
920 + $ret = NULL;
839 921 endif;
840 922
841 - return $_POST['freeze_updates'];
923 + return $ret;
842 924 } // function feedwordpress_save_edit_controls
843 925
844 926 ################################################################################
845 927 ## class FeedWordPress #########################################################
@@ -885,9 +967,9 @@
885 967 function FeedWordPress () {
886 968 $this->feeds = array ();
887 969 $links = FeedWordPress::syndicated_links();
888 970 if ($links): foreach ($links as $link):
889 - $this->feeds[] =& new SyndicatedLink($link);
971 + $this->feeds[] = new SyndicatedLink($link);
890 972 endforeach; endif;
891 973 } // FeedWordPress::FeedWordPress ()
892 974
893 975 # function update (): polls for updates on one or more Contributor feeds
@@ -991,10 +1073,12 @@
991 1073 $start_ts = time();
992 1074 $added = $feed->poll($crash_ts);
993 1075 do_action('feedwordpress_check_feed_complete', $feed->settings, $added, time() - $start_ts);
994 1076
995 - if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
996 - if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
1077 + if (is_array($added)) : // Success
1078 + if (isset($added['new'])) : $delta['new'] += $added['new']; endif;
1079 + if (isset($added['updated'])) : $delta['updated'] += $added['updated']; endif;
1080 + endif;
997 1081 endif;
998 1082 endforeach;
999 1083
1000 1084 do_action('feedwordpress_update_complete', $delta);
@@ -1148,8 +1232,19 @@
1148 1232 $ret = get_option('feedwordpress_use_aggregator_source_data');
1149 1233 return apply_filters('syndicated_post_use_aggregator_source_data', ($ret=='yes'));
1150 1234 }
1151 1235
1236 + /**
1237 + * FeedWordPress::munge_permalinks: check whether or not FeedWordPress
1238 + * should rewrite permalinks for syndicated items to reflect their
1239 + * original location.
1240 + *
1241 + * @return bool TRUE if FeedWordPress SHOULD rewrite permalinks; FALSE otherwise
1242 + */
1243 + /*static*/ function munge_permalinks () {
1244 + return (get_option('feedwordpress_munge_permalink', /*default=*/ 'yes') != 'no');
1245 + } /* FeedWordPress::munge_permalinks() */
1246 +
1152 1247 function syndicated_links () {
1153 1248 $contributors = FeedWordPress::link_category_id();
1154 1249 if (function_exists('get_bookmarks')) :
1155 1250 $links = get_bookmarks(array("category" => $contributors));
@@ -1233,58 +1328,14 @@
1233 1328
1234 1329 if (is_null($from) or $from <= 0.96) : $from = 0.96; endif;
1235 1330
1236 1331 switch ($from) :
1237 - case 0.96: // account for changes to syndication custom values and guid
1238 - echo "<p>Upgrading database from {$from} to ".FEEDWORDPRESS_VERSION."...</p>\n";
1332 + case 0.96:
1333 + // Dropping legacy upgrade code. If anyone is still
1334 + // using 0.96 and just now decided to upgrade, well, I'm
1335 + // sorry about that. You'll just have to cope with a few
1336 + // duplicate posts.
1239 1337
1240 - $cat_id = FeedWordPress::link_category_id();
1241 -
1242 - // Avoid duplicates
1243 - $wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key = 'syndication_feed_id'");
1244 -
1245 - // Look up all the link IDs
1246 - $wpdb->query("
1247 - CREATE TEMPORARY TABLE tmp_custom_values
1248 - SELECT
1249 - NULL AS meta_id,
1250 - post_id,
1251 - 'syndication_feed_id' AS meta_key,
1252 - link_id AS meta_value
1253 - FROM `{$wpdb->postmeta}`, `{$wpdb->links}`
1254 - WHERE
1255 - meta_key='syndication_feed'
1256 - AND meta_value=link_rss
1257 - AND link_category = {$cat_id}
1258 - ");
1259 -
1260 - // Now attach them to their posts
1261 - $wpdb->query("INSERT INTO `{$wpdb->postmeta}` SELECT * FROM tmp_custom_values");
1262 -
1263 - // And clean up after ourselves.
1264 - $wpdb->query("DROP TABLE tmp_custom_values");
1265 -
1266 - // Now fix the guids to avoid duplicate posts
1267 - echo "<ul>";
1268 - foreach ($this->feeds as $syndicatedLink) :
1269 - $feed = $syndicatedLink->settings;
1270 - echo "<li>Fixing post meta-data for <cite>".$feed['link/name']."</cite> &#8230; "; flush();
1271 - $rss = @fetch_rss($feed['link/uri']);
1272 - if (is_array($rss->items)) :
1273 - foreach ($rss->items as $item) :
1274 - $post = new SyndicatedPost($item, $syndicatedLink);
1275 - $guid = $wpdb->escape($post->guid()); // new GUID algorithm
1276 - $link = $wpdb->escape($item['link']);
1277 -
1278 - $wpdb->query("
1279 - UPDATE `{$wpdb->posts}` SET guid='{$guid}' WHERE guid='{$link}'
1280 - ");
1281 - endforeach;
1282 - endif;
1283 - echo "<strong>complete.</strong></li>\n";
1284 - endforeach;
1285 - echo "</ul>\n";
1286 -
1287 1338 // Mark the upgrade as successful.
1288 1339 update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
1289 1340 endswitch;
1290 1341 echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
@@ -1289,8 +1340,27 @@
1289 1340 endswitch;
1290 1341 echo "<p>Upgrade complete. FeedWordPress is now ready to use again.</p>";
1291 1342 } /* FeedWordPress::upgrade_database() */
1292 1343
1344 + function has_guid_index () {
1345 + global $wpdb;
1346 +
1347 + $found = false; // Guilty until proven innocent.
1348 +
1349 + $results = $wpdb->get_results("
1350 + SHOW INDEXES FROM {$wpdb->posts}
1351 + ");
1352 + if ($results) :
1353 + foreach ($results as $index) :
1354 + if (isset($index->Column_name)
1355 + and ('guid' == $index->Column_name)) :
1356 + $found = true;
1357 + endif;
1358 + endforeach;
1359 + endif;
1360 + return $found;
1361 + } /* FeedWordPress::has_guid_index () */
1362 +
1293 1363 function create_guid_index () {
1294 1364 global $wpdb;
1295 1365
1296 1366 $wpdb->query("
@@ -1297,29 +1367,72 @@
1297 1367 CREATE INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}(guid)
1298 1368 ");
1299 1369 } /* FeedWordPress::create_guid_index () */
1300 1370
1371 + function remove_guid_index () {
1372 + global $wpdb;
1373 +
1374 + $wpdb->query("
1375 + DROP INDEX {$wpdb->posts}_guid_idx ON {$wpdb->posts}
1376 + ");
1377 + }
1378 +
1379 + /*static*/ function fetch ($url) {
1380 + require_once (ABSPATH . WPINC . '/class-feed.php');
1381 + $feed = new SimplePie();
1382 + $feed->set_feed_url($url);
1383 + $feed->set_cache_class('WP_Feed_Cache');
1384 + $feed->set_file_class('WP_SimplePie_File');
1385 + $feed->set_cache_duration(FeedWordPress::cache_duration());
1386 + $feed->init();
1387 + $feed->handle_content_type();
1388 +
1389 + if ($feed->error()) :
1390 + $ret = new WP_Error('simplepie-error', $feed->error());
1391 + else :
1392 + $ret = $feed;
1393 + endif;
1394 + return $ret;
1395 + } /* FeedWordPress::fetch () */
1396 +
1301 1397 function clear_cache () {
1302 1398 global $wpdb;
1303 1399
1304 - // MagpieRSS stores its cached feeds in options table rows with
1305 - // name = `rss_{md5 of url}` and timestamps for cached feeds in
1306 - // table rows with name = `rss_{md5 of url}_ts`. The md5 is
1307 - // always 32 characters in length, so the total option_name is
1308 - // always over 32 characters.
1309 - $wpdb->query("
1400 + // The WordPress SimplePie module stores its cached feeds as
1401 + // transient records in the options table. The data itself is
1402 + // stored in `_transient_feed_{md5 of url}` and the last-modified
1403 + // timestamp in `_transient_feed_mod_{md5 of url}`. Timeouts for
1404 + // these records are stored in `_transient_timeout_feed_{md5}`.
1405 + // Since the md5 is always 32 characters in length, the
1406 + // option_name is always over 32 characters.
1407 + $ret = $wpdb->query("
1310 1408 DELETE FROM {$wpdb->options}
1311 - WHERE LOCATE('rss_', option_name) AND LENGTH(option_name) > 32
1409 + WHERE option_name LIKE '_transient%_feed_%' AND LENGTH(option_name) > 32
1312 1410 ");
1411 + return (int) ($ret / 4); // Each transient has 4 rows: the data, the modified timestamp; and the timeouts for each
1313 1412 } /* FeedWordPress::clear_cache () */
1314 1413
1315 - function magpie_version () {
1316 - if (!defined('MAGPIE_VERSION')) : $magpie_version = $GLOBALS['wp_version'].'-default';
1317 - else : $magpie_version = MAGPIE_VERSION;
1414 + function cache_duration () {
1415 + $duration = NULL;
1416 + if (defined('FEEDWORDPRESS_CACHE_AGE')) :
1417 + $duration = FEEDWORDPRESS_CACHE_AGE;
1318 1418 endif;
1319 - return $magpie_version;
1419 + return $duration;
1320 1420 }
1421 + function cache_lifetime ($duration) {
1422 + // Check for explicit setting of a lifetime duration
1423 + if (defined('FEEDWORDPRESS_CACHE_LIFETIME')) :
1424 + $duration = FEEDWORDPRESS_CACHE_LIFETIME;
1321 1425
1426 + // Fall back to the cache freshness duration
1427 + elseif (defined('FEEDWORDPRESS_CACHE_AGE')) :
1428 + $duration = FEEDWORDPRESS_CACHE_AGE;
1429 + endif;
1430 +
1431 + // Fall back to WordPress default
1432 + return $duration;
1433 + } /* FeedWordPress::cache_lifetime () */
1434 +
1322 1435 # Utility functions for handling text settings
1323 1436 function negative ($f, $setting) {
1324 1437 $nego = array ('n', 'no', 'f', 'false');
1325 1438 return (isset($f[$setting]) and in_array(strtolower($f[$setting]), $nego));
@@ -1334,17 +1447,12 @@
1334 1447 # Internal debugging functions
1335 1448 function critical_bug ($varname, $var, $line) {
1336 1449 global $wp_version;
1337 1450
1338 - if (defined('MAGPIE_VERSION')) : $mv = MAGPIE_VERSION;
1339 - else : $mv = 'WordPress '.$wp_version.' default.';
1340 - endif;
1341 -
1342 1451 echo '<p>There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
1343 1452 echo "\n<plaintext>";
1344 1453 echo "Triggered at line # ".$line."\n";
1345 1454 echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n";
1346 - echo "MagpieRSS version: {$mv}\n";
1347 1455 echo "WordPress version: {$wp_version}\n";
1348 1456 echo "PHP version: ".phpversion()."\n";
1349 1457 echo "\n";
1350 1458 echo $varname.": "; var_dump($var); echo "\n";
@@ -1355,10 +1463,55 @@
1355 1463 if (FEEDWORDPRESS_DEBUG) : // halt only when we are doing debugging
1356 1464 FeedWordPress::critical_bug($varname, $var, $line);
1357 1465 endif;
1358 1466 }
1467 +
1468 + function val ($v, $no_newlines = false) {
1469 + ob_start();
1470 + var_dump($v);
1471 + $out = ob_get_contents(); ob_end_clean();
1472 +
1473 + if ($no_newlines) :
1474 + $out = preg_replace('/\s+/', " ", $out);
1475 + endif;
1476 + return $out;
1477 + } /* FeedWordPress:val () */
1478 +
1479 + function diagnostic ($level, $out) {
1480 + global $feedwordpress_admin_footer;
1481 +
1482 + $output = get_option('feedwordpress_diagnostics_output', array());
1483 + $show = get_option('feedwordpress_diagnostics_show', array());
1484 +
1485 + $diagnostic_nesting = count(explode(":", $level));
1486 +
1487 + if (in_array($level, $show)) :
1488 + foreach ($output as $method) :
1489 + switch ($method) :
1490 + case 'echo' :
1491 + echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.esc_html($out)."</pre></div>";
1492 + break;
1493 + case 'admin_footer' :
1494 + $feedwordpress_admin_footer[] = $out;
1495 + break;
1496 + case 'error_log' :
1497 + error_log('[feedwordpress]' . $out);
1498 + break;
1499 + endswitch;
1500 + endforeach;
1501 + endif;
1502 + } /* FeedWordPress::diagnostic () */
1503 +
1504 + function admin_footer () {
1505 + global $feedwordpress_admin_footer;
1506 + foreach ($feedwordpress_admin_footer as $line) :
1507 + echo '<div><pre>'.esc_html($line).'</pre></div>';
1508 + endforeach;
1509 + } /* FeedWordPress::admin_footer () */
1359 1510 } // class FeedWordPress
1360 1511
1512 +$feedwordpress_admin_footer = array();
1513 +
1361 1514 require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
1362 1515 require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
1363 1516
1364 1517 ################################################################################
@@ -1370,9 +1523,9 @@
1370 1523 return $args;
1371 1524 }
1372 1525
1373 1526 function feedwordpress_pong ($args) {
1374 - $feedwordpress =& new FeedWordPress;
1527 + $feedwordpress = new FeedWordPress;
1375 1528 $delta = @$feedwordpress->update($args[1]);
1376 1529 if (is_null($delta)):
1377 1530 return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
1378 1531 else:
@@ -1383,13 +1536,9 @@
1383 1536 return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
1384 1537 endif;
1385 1538 }
1386 1539
1387 -# The upgraded MagpieRSS also uses this class. So if we have it loaded
1388 -# in, don't load it again.
1389 -if (!class_exists('Relative_URI')) {
1390 - require_once(dirname(__FILE__) . '/relative_uri.class.php');
1391 -}
1540 +require_once(dirname(__FILE__) . '/relative_uri.class.php');
1392 1541
1393 1542 // take your best guess at the realname and e-mail, given a string
1394 1543 define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
1395 1544 define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');