diff --git a/wp-content/plugins/feedwordpress/admin-ui.php b/wp-content/plugins/feedwordpress/admin-ui.php index d9ba9c3a62c98bee9c465a6cb5e4d290008a5e40..d9eee616d283643e4ec5e95f9f7e0c611ae01f50 100644 --- a/wp-content/plugins/feedwordpress/admin-ui.php +++ b/wp-content/plugins/feedwordpress/admin-ui.php @@ -746,38 +746,68 @@ function fwp_option_box_closer () { } function fwp_tags_box ($tags, $object, $params = array()) { + $params = wp_parse_args($params, array( // Default values + 'taxonomy' => 'post_tag', + 'textarea_name' => NULL, + 'textarea_id' => NULL, + 'input_id' => NULL, + 'input_name' => NULL, + 'id' => NULL, + 'box_title' => __('Post Tags'), + )); + if (!is_array($tags)) : $tags = array(); endif; - $tax_name = (isset($params['taxonomy']) ? $params['taxonomy'] : 'post_tag'); + + $tax_name = $params['taxonomy']; + $taxonomy = get_taxonomy($params['taxonomy']); + $disabled = (!current_user_can($taxonomy->cap->assign_terms) ? 'disabled="disabled"' : ''); + $desc = "<p style=\"font-size:smaller;font-style:bold;margin:0\">Tag $object as...</p>"; - if (isset($params['textarea_name'])) : - $textAreaName = $params['textarea_name']; - else : - $textAreaName = "tax_input[$tax_name]"; + if (is_null($params['textarea_name'])) : + $params['textarea_name'] = "tax_input[$tax_name]"; + endif; + if (is_null($params['textarea_id'])) : + $params['textarea_id'] = "tax-input-${tax_name}"; endif; + if (is_null($params['input_id'])) : + $params['input_id'] = "new-tag-${tax_name}"; + endif; + if (is_null($params['input_name'])) : + $params['input_name'] = "newtag[$tax_name]"; + endif; + + if (is_null($params['id'])) : + $params['id'] = $tax_name; + endif; + print $desc; $helps = __('Separate tags with commas.'); $box['title'] = __('Tags'); ?> - <div class="tagsdiv" id="<?php echo $tax_name; ?>"> - <div class="jaxtag"> - <div class="nojs-tags hide-if-js"> - <p><?php _e('Add or remove tags'); ?></p> - <textarea name="<?php echo esc_html($textAreaName); ?>" class="the-tags" id="tax-input[<?php echo $tax_name; ?>]"><?php echo esc_attr(implode(",", $tags)); ?></textarea></div> +<div class="tagsdiv" id="<?php echo $params['id']; ?>"> + <div class="jaxtag"> + <div class="nojs-tags hide-if-js"> + <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p> + <textarea name="<?php echo $params['textarea_name']; ?>" class="the-tags" id="<?php echo $params['textarea_id']; ?>"><?php echo esc_attr(implode(",", $tags)); ?></textarea></div> - <div class="ajaxtag hide-if-no-js"> - <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box['title']; ?></label> - <div class="taghint"><?php _e('Add new tag'); ?></div> - <p> - <input type="text" id="new-tag-<?php echo $tax_name; ?>" name="newtag[<?php echo $tax_name; ?>]" class="newtag form-input-tip" size="16" autocomplete="off" value="" /> - <input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" tabindex="3" /> - </p> - </div></div> - <p class="howto"><?php echo $helps; ?></p> - <div class="tagchecklist"></div> - </div> - <p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php printf( __('Choose from the most used tags in %s'), $box['title'] ); ?></a></p> - <?php + <?php if ( current_user_can($taxonomy->cap->assign_terms) ) :?> + <div class="ajaxtag hide-if-no-js"> + <label class="screen-reader-text" for="<?php echo $params['input_id']; ?>"><?php echo $params['box_title']; ?></label> + <div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div> + <p><input type="text" id="<?php print $params['input_id']; ?>" name="<?php print $params['input_name']; ?>" class="newtag form-input-tip" size="16" autocomplete="off" value="" /> + <input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" tabindex="3" /></p> + </div> + <p class="howto"><?php echo esc_attr( $taxonomy->labels->separate_items_with_commas ); ?></p> + <?php endif; ?> + </div> + + <div class="tagchecklist"></div> +</div> +<?php if ( current_user_can($taxonomy->cap->assign_terms) ) : ?> +<p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->choose_from_most_used; ?></a></p> +<?php endif; + } function fwp_category_box ($checked, $object, $tags = array(), $params = array()) { @@ -946,6 +976,12 @@ class FeedWordPressSettingsUI { background-position:0 top; background-repeat:repeat-x; } + + .update-results { + max-width: 100%; + overflow: auto; + } + </style> <?php } /* FeedWordPressSettingsUI::admin_styles () */ @@ -1076,7 +1112,7 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible = // Prep: Get last updated timestamp $sLink = new SyndicatedLink($link->link_id); if (!is_null($sLink->setting('update/last'))) : - $lastUpdated = fwp_time_elapsed($sLink->setting('update/last')); + $lastUpdated = 'Last checked '. fwp_time_elapsed($sLink->setting('update/last')); else : $lastUpdated = __('None yet'); endif; @@ -1101,19 +1137,41 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible = ."</div>\n"; endif; - $nextUpdate = "<div style='font-style:italic;size:0.9em'>Ready for next update "; - if (isset($sLink->settings['update/ttl']) and is_numeric($sLink->settings['update/ttl'])) : - if (isset($sLink->settings['update/timed']) and $sLink->settings['update/timed']=='automatically') : - $next = $sLink->settings['update/last'] + ((int) $sLink->settings['update/ttl'] * 60); + $nextUpdate = "<div style='max-width: 30.0em; font-size: 0.9em;'><div style='font-style:italic;'>"; + + $ttl = $sLink->setting('update/ttl'); + if (is_numeric($ttl)) : + $next = $sLink->setting('update/last') + $sLink->setting('update/fudge') + ((int) $ttl * 60); + if ('automatically'==$sLink->setting('update/timed')) : + if ($next < time()) : + $nextUpdate .= 'Ready and waiting to be updated since '; + else : + $nextUpdate .= 'Scheduled for next update '; + endif; $nextUpdate .= fwp_time_elapsed($next); if (FEEDWORDPRESS_DEBUG) : $nextUpdate .= " [".(($next-time())/60)." minutes]"; endif; else : - $nextUpdate .= "every ".$sLink->settings['update/ttl']." minute".(($sLink->settings['update/ttl']!=1)?"s":""); + $lastUpdated .= " · Next "; + if ($next < time()) : + $lastUpdated .= 'ASAP'; + elseif ($next - time() < 60) : + $lastUpdated .= fwp_time_elapsed($next); + elseif ($next - time() < 60*60*24) : + $lastUpdated .= gmdate('g:ia', $next + (get_option('gmt_offset') * 3600)); + else : + $lastUpdated .= gmdate('F j', $next + (get_option('gmt_offset') * 3600)); + endif; + + $nextUpdate .= "Scheduled to be checked for updates every ".$ttl." minute".(($ttl!=1)?"s":"")."</div><div style='size:0.9em; margin-top: 0.5em'> This update schedule was requested by the feed provider"; + if ($sLink->setting('update/xml')) : + $nextUpdate .= " using a standard <code style=\"font-size: inherit; padding: 0; background: transparent\"><".$sLink->setting('update/xml')."></code> element"; + endif; + $nextUpdate .= "."; endif; else: - $nextUpdate .= "as soon as possible"; + $nextUpdate .= "Scheduled for update as soon as possible"; endif; - $nextUpdate .= "</div>"; + $nextUpdate .= "</div></div>"; unset($sLink); diff --git a/wp-content/plugins/feedwordpress/authors-page.php b/wp-content/plugins/feedwordpress/authors-page.php index 8a36068207b9dcdfbba5d445471424a10641ac8a..d2438e88592c19c605b00b6066be39f3ccd30010 100644 --- a/wp-content/plugins/feedwordpress/authors-page.php +++ b/wp-content/plugins/feedwordpress/authors-page.php @@ -24,6 +24,9 @@ class FeedWordPressAuthorsPage extends FeedWordPressAdminPage { function refresh_author_list () { $this->authorlist = fwp_author_list(); + + // Case-insensitive "natural" alphanumeric sort. Preserves key/value associations. + if (function_exists('natcasesort')) : natcasesort($this->authorlist); endif; } /*static*/ function syndicated_authors_box ($page, $box = NULL) { @@ -45,6 +48,26 @@ class FeedWordPressAuthorsPage extends FeedWordPressAdminPage { ?> <table class="form-table"> <?php +if ($page->for_default_settings()) : +?> +<tr><th>Unmatched authors</th> +<td><span>Authors who haven’t been syndicated before</span> + <select style="max-width: 27.0em" id="unfamiliar-author" name="unfamiliar_author" onchange="contextual_appearance('unfamiliar-author', 'unfamiliar-author-newuser', 'unfamiliar-author-default', 'newuser', 'inline');"> + <option value="create"<?php print $unfamiliar['create']; ?>>will have a new author account created for them</option> + <?php foreach ($page->authorlist as $author_id => $author_name) : ?> + <option value="<?php echo $author_id; ?>"<?php print (isset($unfamiliar[$author_id]) ? $unfamiliar[$author_id] : ''); ?>>will have their posts attributed to <?php echo $author_name; ?></option> + <?php endforeach; ?> + <option value="newuser">will have their posts attributed to a new user...</option> + <option value="filter"<?php print $unfamiliar['filter'] ?>>get filtered out</option> + </select> + + <span id="unfamiliar-author-newuser">named <input type="text" name="unfamiliar_author_newuser" value="" /></span></p> + </td> +</tr> + +<?php +endif; + if ($page->for_feed_settings()) : $map = $this->link->setting('map authors', NULL, array()); ?> @@ -55,8 +78,10 @@ authors?</p> <li><p><input type="radio" name="author_rules_name[all]" value="*" <?php if (isset($map['name']['*'])) : $author_action = $map['name']['*']; ?> checked="checked" -<?php else : $author_action = NULL; ?> -<?php endif; ?> +<?php + else : + $author_action = NULL; + endif; ?> /> All posts syndicated from this feed <select class="author-rules" id="author-rules-all" name="author_rules_action[all]" onchange="contextual_appearance('author-rules-all', 'author-rules-all-newuser', 'author-rules-all-default', 'newuser', 'inline');"> diff --git a/wp-content/plugins/feedwordpress/diagnostics-page.php b/wp-content/plugins/feedwordpress/diagnostics-page.php index ad9fe528316c632e3a6e6409fd604e0464d09f3b..d062b00f3290822cf9eedf988c20ef246ddc1574 100644 --- a/wp-content/plugins/feedwordpress/diagnostics-page.php +++ b/wp-content/plugins/feedwordpress/diagnostics-page.php @@ -70,6 +70,7 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage { if (isset($post['submit']) or isset($post['save'])) : update_option('feedwordpress_debug', $post['feedwordpress_debug']); + update_option('feedwordpress_secret_key', $post['feedwordpress_secret_key']); if (!isset($post['diagnostics_output']) or !is_array($post['diagnostics_output'])) : @@ -106,8 +107,9 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage { } /* FeedWordPressDiagnosticsPage::accept_POST () */ function info_box ($page, $box = NULL) { - $link_category_id = FeedWordPress::link_category_id(); - ?> + global $feedwordpress; + $link_category_id = FeedWordPress::link_category_id(); + ?> <table class="edit-form narrow"> <thead style="display: none"> <th scope="col">Topic</th> @@ -146,6 +148,14 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage { </table> <?php endif; ?></td> </tr> + + <tr> + <th scope="row"><?php _e('Secret Key:'); ?></th> + <td><input type="text" name="feedwordpress_secret_key" value="<?php print esc_attr($feedwordpress->secret_key()); ?>" /> + <p class="setting-description">This is used to control access to some diagnostic testing functions. You can change it to any string you want, + but only tell it to people you trust to help you troubleshoot your + FeedWordPress installation. Keep it secret—keep it safe.</p></td> + </tr> </table> <?php @@ -228,7 +238,8 @@ testing but absolutely inappropriate for a production server.</p> $hours = get_option('feedwordpress_diagnostics_persistent_errors_hours', 2); $fields = apply_filters('feedwordpress_diagnostics', array( 'Update Diagnostics' => array( - 'updated_feeds' => 'as each feed checked for updates', + 'update_schedule:check' => 'whenever a FeedWordPress checks in on the update schedule', + 'updated_feeds' => 'as each feed is checked for updates', 'updated_feeds:errors:persistent' => 'when attempts to update a feed have resulted in errors</label> <label>for at least <input type="number" min="1" max="360" step="1" name="diagnostics_persistent_error_hours" value="'.$hours.'" /> hours', 'updated_feeds:errors' => 'any time FeedWordPress encounters any errors while checking a feed for updates', 'syndicated_posts' => 'as each syndicated post is added to the database', @@ -236,8 +247,14 @@ testing but absolutely inappropriate for a production server.</p> 'memory_usage' => 'indicating how much memory was used', ), 'Syndicated Post Details' => array( + 'feed_items:freshness' => 'as FeedWordPress decides whether to treat an item as a new post, an update, or a duplicate of an existing post', + 'feed_items:rejected' => 'when FeedWordPress rejects a post without syndicating it', 'syndicated_posts:meta_data' => 'as syndication meta-data is added on the post', ), + 'Advanced Diagnostics' => array( + 'feed_items:freshness:sql' => 'when FeedWordPress issues the SQL query it uses to decide whether to treat items as new, updates, or duplicates', + 'syndicated_posts:static_meta_data' => 'providing meta-data about syndicated posts in the Edit Posts interface', + ), ), $page); foreach ($fields as $section => $items) : diff --git a/wp-content/plugins/feedwordpress/feeds-page.php b/wp-content/plugins/feedwordpress/feeds-page.php index c96537c504acc68f180fe3ed991571cd5ff8e2bd..3aa1c3bb73f22caf302e6f3c86f8dc368035cb42 100644 --- a/wp-content/plugins/feedwordpress/feeds-page.php +++ b/wp-content/plugins/feedwordpress/feeds-page.php @@ -175,7 +175,8 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { } /* FeedWordPressFeedsPage::updated_posts_box() */ /*static*/ function global_feeds_box ($page, $box = NULL) { - $automatic_updates = get_option('feedwordpress_automatic_updates'); + global $feedwordpress; + $automatic_updates = $feedwordpress->automatic_update_hook(array('setting only' => true)); $update_time_limit = (int) get_option('feedwordpress_update_time_limit'); // Hey, ho, let's go... @@ -263,6 +264,30 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { ?></td> </tr> + <tr> + <th scope="row"><?php print __('Minimum Interval:'); ?></th> + <td><p style="margin-top:0px">Some feeds include standard elements that + request a specific update schedule. If the interval requested by the + feed provider is <em>longer</em> than FeedWordPress's normal scheduling, + FeedWordPress will always respect their request to slow down. But what + should it do if the update interval is <em>shorter</em> than the schedule set above?</p> + <?php + $this->setting_radio_control( + 'update/minimum', 'update_minimum', + /*options=*/ array( + 'no' => 'Speed up and accept the interval from the feed provider', + 'yes' => 'Keep pace and use the longer scheduling from FeedWordPress', + ), + /*params=*/ array( + 'setting-default' => NULL, + 'global-setting-default' => 'no', + 'default-input-value' => 'default', + ) + ); + ?> + </td> + </tr> + <?php if ($this->for_default_settings()) : ?> <tr> @@ -905,7 +930,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { update_option('feedwordpress_cat_id', $post['syndication_category']); if (!isset($post['automatic_updates']) or !in_array($post['automatic_updates'], array('init', 'shutdown'))) : - $automatic_updates = false; + $automatic_updates = NULL; else : $automatic_updates = $post['automatic_updates']; endif; @@ -939,6 +964,10 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage { endif; $this->update_setting('fetch timeout', $timeout); endif; + + if (isset($post['update_minimum'])) : + $this->update_setting('update/minimum', $post['update_minimum']); + endif; $this->updatedPosts->accept_POST($post); parent::save_settings($post); diff --git a/wp-content/plugins/feedwordpress/feedtime.class.php b/wp-content/plugins/feedwordpress/feedtime.class.php index 7aab3388fa8d6f9a9243b24fdd98b636119c1c46..5cfc3a26a081a69fcde0a68d279242f697cfe64b 100644 --- a/wp-content/plugins/feedwordpress/feedtime.class.php +++ b/wp-content/plugins/feedwordpress/feedtime.class.php @@ -11,7 +11,7 @@ class FeedTime { $this->set($time); } /* FeedTime constructor */ - function set ($time) { + function set ($time, $recurse = false) { $this->rep = $time; $this->ts = NULL; if (is_numeric($time)) : // Presumably a Unix-epoch timestamp @@ -23,7 +23,7 @@ class FeedTime { if ($this->failed()) : // In some versions of PHP, strtotime() does not support // the UT timezone. Since UT is by definition within 1 - // second of UTC, we'll just convert it here to avoid + // second of UTC, we'll just convert it preemptively to avoid // problems. $time = preg_replace( '/(\s)UT$/', @@ -31,6 +31,12 @@ class FeedTime { $time ); $this->ts = strtotime($time); + + if ($this->failed() + and preg_match('/^(.*)([+\-][0-9]+|\s+[A-Za-z]{1,3})$/', $time, $matches)) : + // Try dropping the time zone and recurse + $this->set($matches[1], /*recurse=*/ true); + endif; endif; endif; } /* FeedTime::set() */ diff --git a/wp-content/plugins/feedwordpress/feedwordpress-elements.js b/wp-content/plugins/feedwordpress/feedwordpress-elements.js index 838ba66cfc41b73215e13773d681e02e1099e062..50333aba83eddb218dab711926ee1b46cb8ede26 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress-elements.js +++ b/wp-content/plugins/feedwordpress/feedwordpress-elements.js @@ -62,7 +62,7 @@ fwpList = { if ( !s ) { return false; } - if ( !e.is("[class^=add:" + list.id + ":]") ) { return !fwpList.add.call( list, e, s ); } + if ( !e.is('[class^="add:' + list.id + ':"]') ) { return !fwpList.add.call( list, e, s ); } if ( !s.element ) { return true; } @@ -91,6 +91,7 @@ fwpList = { if ( true === res ) { return true; } jQuery.each( res.responses, function() { + // FIXME: Causes ownerDocument is undefined breakage in WP3.2 fwpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue pos: this.position || 0, id: this.id || 0, @@ -321,11 +322,11 @@ fwpList = { process: function(el) { var list = this; - $("[class^=add:" + list.id + ":]", el || null) + $('[class^="add:' + list.id + ':"]', el || null) .filter('form').submit( function() { return list.fwpList.add(this); } ).end() .not('form').click( function() { return list.fwpList.add(this); } ); - $("[class^=delete:" + list.id + ":]", el || null).click( function() { return list.fwpList.del(this); } ); - $("[class^=dim:" + list.id + ":]", el || null).click( function() { return list.fwpList.dim(this); } ); + $('[class^="delete:' + list.id + ':"]', el || null).click( function() { return list.fwpList.del(this); } ); + $('[class^="dim:' + list.id + ':"]', el || null).click( function() { return list.fwpList.dim(this); } ); }, recolor: function() { diff --git a/wp-content/plugins/feedwordpress/feedwordpress.php b/wp-content/plugins/feedwordpress/feedwordpress.php index 32024cff123501a05fdb7af004c70dda5db7d957..310f9bd8f8e96ed831e21a2f5bb75a7b9063f67c 100644 --- a/wp-content/plugins/feedwordpress/feedwordpress.php +++ b/wp-content/plugins/feedwordpress/feedwordpress.php @@ -3,7 +3,7 @@ Plugin Name: FeedWordPress Plugin URI: http://feedwordpress.radgeek.com/ Description: simple and flexible Atom/RSS syndication for WordPress -Version: 2011.0211.2 +Version: 2011.0721 Author: Charles Johnson Author URI: http://radgeek.com/ License: GPL @@ -11,7 +11,7 @@ License: GPL /** * @package FeedWordPress - * @version 2011.0211.2 + * @version 2011.0721 */ # This uses code derived from: @@ -34,7 +34,7 @@ License: GPL # -- Don't change these unless you know what you're doing... -define ('FEEDWORDPRESS_VERSION', '2011.0211.2'); +define ('FEEDWORDPRESS_VERSION', '2011.0721'); define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact'); if (!defined('FEEDWORDPRESS_BLEG')) : @@ -109,14 +109,19 @@ if (!function_exists('wp_insert_user')) : require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user endif; -require_once(dirname(__FILE__) . '/admin-ui.php'); -require_once(dirname(__FILE__) . '/feedwordpresssyndicationpage.class.php'); -require_once(dirname(__FILE__) . '/compatability.php'); // LEGACY API: Replicate or mock up functions for legacy support purposes - -require_once(dirname(__FILE__) . '/syndicatedpost.class.php'); -require_once(dirname(__FILE__) . '/syndicatedlink.class.php'); -require_once(dirname(__FILE__) . '/feedwordpresshtml.class.php'); -require_once(dirname(__FILE__) . '/feedwordpress-content-type-sniffer.class.php'); +$dir = dirname(__FILE__); +require_once("${dir}/admin-ui.php"); +require_once("${dir}/feedwordpresssyndicationpage.class.php"); +require_once("${dir}/compatability.php"); // Legacy API +require_once("${dir}/syndicatedpost.class.php"); +require_once("${dir}/syndicatedlink.class.php"); +require_once("${dir}/feedwordpresshtml.class.php"); +require_once("${dir}/feedwordpress-content-type-sniffer.class.php"); +require_once("${dir}/inspectpostmeta.class.php"); +require_once("${dir}/syndicationdataqueries.class.php"); +require_once("${dir}/feedwordpress_file.class.php"); +require_once("${dir}/feedwordpress_parser.class.php"); +require_once("${dir}/feedwordpressrpc.class.php"); // Magic quotes are just about the stupidest thing ever. if (is_array($_POST)) : @@ -224,11 +229,11 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe! $feedwordpress = new FeedWordPress; # Cron-less auto-update. Hooray! - $autoUpdateHook = get_option('feedwordpress_automatic_updates'); - if ($autoUpdateHook != 'init') : - $autoUpdateHook = 'shutdown'; + $autoUpdateHook = $feedwordpress->automatic_update_hook(); + if (!is_null($autoUpdateHook)) : + add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update')); endif; - add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update')); + add_action('init', array(&$feedwordpress, 'init')); add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log')); add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup')); @@ -810,6 +815,9 @@ function fwp_publish_post_hook ($post_id) { function feedwordpress_add_post_edit_controls () { add_meta_box('feedwordpress-post-controls', __('Syndication'), 'feedwordpress_post_edit_controls', 'post', 'side', 'high'); + if (FeedWordPress::diagnostic_on('syndicated_posts:static_meta_data')) : + $GLOBALS['inspectPostMeta'] = new InspectPostMeta; + endif; } // function FeedWordPress::postEditControls function feedwordpress_post_edit_controls () { @@ -975,6 +983,13 @@ class FeedWordPress { if (!is_null($uri) and $uri != '*') : $uri = trim($uri); else : // Update all + if ($this->update_hooked) : + $diag = $this->update_hooked; + else : + $diag = 'Initiating a MANUAL check-in on the update schedule at '.date('r', time()); + endif; + $this->diagnostic('update_schedule:check', $diag); + update_option('feedwordpress_last_update_all', time()); endif; @@ -984,6 +999,8 @@ class FeedWordPress { $crash_ts = $this->crash_ts(); endif; + $max_polls = apply_filters('feedwordpress_polls_per_update', get_option('feedwordpress_polls_per_update', 10), $uri); + // Randomize order for load balancing purposes $feed_set = $this->feeds; shuffle($feed_set); @@ -991,12 +1008,20 @@ class FeedWordPress { $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri); // Loop through and check for new posts - $delta = NULL; + $delta = NULL; $remaining = $max_polls; foreach ($feed_set as $feed) : - if (!is_null($crash_ts) and (time() > $crash_ts)) : // Check whether we've exceeded the time limit + + // Has this process overstayed its welcome? + if ( + // Over time limit? + (!is_null($crash_ts) and (time() > $crash_ts)) + + // Over feed count? + or ($remaining == 0) + ) : break; endif; - + $pinged_that = (is_null($uri) or ($uri=='*') or in_array($uri, array($feed->uri(), $feed->homepage()))); if (!is_null($uri)) : // A site-specific ping always updates @@ -1010,6 +1035,8 @@ class FeedWordPress { endif; if ($pinged_that and $timely) : + $remaining = $remaining - 1; + do_action('feedwordpress_check_feed', $feed->settings); $start_ts = time(); $added = $feed->poll($crash_ts); @@ -1037,12 +1064,79 @@ class FeedWordPress { return $crash_ts; } + function secret_key () { + $secret = get_option('feedwordpress_secret_key', false); + if (!$secret) : // Generate random key. + $secret = substr(md5(uniqid(microtime())), 0, 6); + update_option('feedwordpress_secret_key', $secret); + endif; + return $secret; + } + + function has_secret () { + return ($this->by_request('feedwordpress_key', $this->secret_key())); + } + + // Utility function so I don't have to repeat myself w/ 1,000,003 isset()'s + function by_request ($param, $eq = NULL) { + $match = false; + if (isset($_REQUEST[$param])) : + $match = (is_null($eq) ? $_REQUEST[$param] : ($eq==$_REQUEST[$param])); + endif; + return $match; + } + + var $update_hooked = NULL; + function automatic_update_hook ($params = array()) { + $params = wp_parse_args($params, array( // Defaults + 'setting only' => false, + )); + $hook = get_option('feedwordpress_automatic_updates', NULL); + $method = 'FeedWordPress option'; + + // Allow for forced behavior in testing. + if ( + !$params['setting only'] + and $this->has_secret() + and $this->by_request('automatic_update') + ) : + $hook = $_REQUEST['automatic_update']; + $method = 'URL parameter'; + endif; + + $exact = $hook; // Before munging + + if (!!$hook) : + if ($hook != 'init') : // Constrain values. + $hook = 'shutdown'; + endif; + endif; + + if ($hook) : + $this->update_hooked = "Initiating an AUTOMATIC CHECK FOR UPDATES ON PAGE LOAD ".$hook." due to ".$method." = ".trim($this->val($exact)); + endif; + + return $hook; + } + function last_update_all () { + $last = get_option('feedwordpress_last_update_all'); + if ($this->has_secret() and $this->by_request('automatic_update')) : + $last = 1; // A long, long time ago. + elseif ($this->has_secret() and $this->by_request('last_update_all')) : + $last = $_REQUEST['last_update_all']; + endif; + return $last; + } + function force_update_all () { + return ($this->has_secret() and $this->by_request('force_update_feeds')); + } + function stale () { - if (get_option('feedwordpress_automatic_updates')) : + if (!is_null($this->automatic_update_hook())) : // Do our best to avoid possible simultaneous // updates by getting up-to-the-minute settings. - $last = get_option('feedwordpress_last_update_all'); + $last = $this->last_update_all(); // If we haven't updated all yet, give it a time window if (false === $last) : @@ -1055,11 +1149,11 @@ class FeedWordPress { if (false === $freshness) : // Use default $freshness = FEEDWORDPRESS_FRESHNESS_INTERVAL; endif; - $ret = ( (time() - $last) > $freshness); - - // This should never happen. + $ret = ( (time() - $last) > $freshness ); + + // This should never happen. else : - FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__); + FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__, __FILE__); endif; else : @@ -1139,6 +1233,8 @@ class FeedWordPress { // Explicit update request in the HTTP request (e.g. from a cron job) if ($this->update_requested()) : + $this->update_hooked = "Initiating a CRON JOB CHECK-IN ON UPDATE SCHEDULE due to URL parameter = ".trim($this->val($_REQUEST['update_feedwordpress'])); + $this->update($this->update_requested_url()); if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) : @@ -1182,10 +1278,7 @@ class FeedWordPress { } /* FeedWordPress::clear_cache_requested() */ function update_requested () { - return ( - isset($_REQUEST['update_feedwordpress']) - and $_REQUEST['update_feedwordpress'] - ); + return FeedWordPress::by_request('update_feedwordpress'); } // FeedWordPress::update_requested() function update_requested_url () { @@ -1502,7 +1595,6 @@ class FeedWordPress { $feed->set_cache_class($cache_class); $feed->set_timeout($timeout); - //$feed->set_file_class('WP_SimplePie_File'); $feed->set_content_type_sniffer_class($sniffer_class); $feed->set_file_class($file_class); $feed->set_parser_class($parser_class); @@ -1577,23 +1669,29 @@ class FeedWordPress { } # Internal debugging functions - function critical_bug ($varname, $var, $line) { + function critical_bug ($varname, $var, $line, $file = NULL) { global $wp_version; - - 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>'; - echo "\n<plaintext>"; - echo "Triggered at line # ".$line."\n"; - echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n"; - echo "WordPress version: {$wp_version}\n"; - echo "PHP version: ".phpversion()."\n"; - echo "\n"; - echo $varname.": "; var_dump($var); echo "\n"; + + if (!is_null($file)) : + $location = "line # ${line} of ".basename($file); + else : + $location = "line # ${line}"; + endif; + + print '<p><strong>Critical error:</strong> 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>'; + print "\n<plaintext>"; + print "Triggered at ${location}\n"; + print "FeedWordPress: ".FEEDWORDPRESS_VERSION."\n"; + print "WordPress: {$wp_version}\n"; + print "PHP: ".phpversion()."\n"; + print "Error data: "; + print $varname.": "; var_dump($var); echo "\n"; die; } - function noncritical_bug ($varname, $var, $line) { + function noncritical_bug ($varname, $var, $line, $file = NULL) { if (FEEDWORDPRESS_DEBUG) : // halt only when we are doing debugging - FeedWordPress::critical_bug($varname, $var, $line); + FeedWordPress::critical_bug($varname, $var, $line, $file); endif; } @@ -1625,7 +1723,9 @@ class FeedWordPress { foreach ($output as $method) : switch ($method) : case 'echo' : - echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>"; + if (!FeedWordPress::update_requested()) : + echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>"; + endif; break; case 'echo_in_cronjob' : if (FeedWordPress::update_requested()) : @@ -1660,14 +1760,36 @@ class FeedWordPress { update_option('feedwordpress_diagnostics_log', $dlog); } /* FeedWordPress::diagnostic () */ + function email_diagnostics_override () { + return ($this->has_secret() and isset($_REQUEST['feedwordpress_email_diagnostics']) and !!$_REQUEST['feedwordpress_email_diagnostics']); + } + function has_emailed_diagnostics ($dlog) { + $ret = false; + if ($this->email_diagnostics_override() + or (isset($dlog['schedule']) and isset($dlog['schedule']['last']))) : + $ret = true; + endif; + return $ret; + } + function ready_to_email_diagnostics ($dlog) { + $ret = false; + if ($this->email_diagnostics_override() + or (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq']))) : + $ret = true; + endif; + return $ret; + } + function email_diagnostic_log () { $dlog = get_option('feedwordpress_diagnostics_log', array()); - if (isset($dlog['schedule']) and isset($dlog['schedule']['last'])) : - if (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq'])) : + if ($this->has_emailed_diagnostics($dlog)) : + if ($this->ready_to_email_diagnostics($dlog)) : // No news is good news; only send if // there are some messages to send. $body = NULL; + if (!isset($dlog['mesg'])) : $dlog['mesg'] = array(); endif; + foreach ($dlog['mesg'] as $sect => $mesgs) : if (count($mesgs) > 0) : if (is_null($body)) : $body = ''; endif; @@ -1698,9 +1820,10 @@ class FeedWordPress { endif; endforeach; + $body = apply_filters('feedwordpress_diagnostic_email_body', $body, $dlog); if (!is_null($body)) : $home = feedwordpress_display_url(get_bloginfo('url')); - $subj = $home . " syndication issues for ".date('j-M-y', time()); + $subj = apply_filters('feedwordpress_diagnostic_email_subject', $home . " syndication issues", $dlog); $agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION; $body = <<<EOMAIL <html> @@ -1823,344 +1946,8 @@ EOMAIL; } } // class FeedWordPress -class FeedWordPress_File extends WP_SimplePie_File { - function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { - WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - - // SimplePie makes a strongly typed check against integers with - // this, but WordPress puts a string in. Which causes caching - // to break and fall on its ass when SimplePie is getting a 304, - // but doesn't realize it because this member is "304" instead. - $this->status_code = (int) $this->status_code; - } -} /* class FeedWordPress_File () */ - -class FeedWordPress_Parser extends SimplePie_Parser { - function parse (&$data, $encoding) { - // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character - if (strtoupper($encoding) === 'US-ASCII') - { - $this->encoding = 'UTF-8'; - } - else - { - $this->encoding = $encoding; - } - - // Strip BOM: - // UTF-32 Big Endian BOM - if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") - { - $data = substr($data, 4); - } - // UTF-32 Little Endian BOM - elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") - { - $data = substr($data, 4); - } - // UTF-16 Big Endian BOM - elseif (substr($data, 0, 2) === "\xFE\xFF") - { - $data = substr($data, 2); - } - // UTF-16 Little Endian BOM - elseif (substr($data, 0, 2) === "\xFF\xFE") - { - $data = substr($data, 2); - } - // UTF-8 BOM - elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") - { - $data = substr($data, 3); - } - - if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) - { - $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); - if ($declaration->parse()) - { - $data = substr($data, $pos + 2); - $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; - } - else - { - $this->error_string = 'SimplePie bug! Please report this!'; - return false; - } - } - - $return = true; - - static $xml_is_sane = null; - if ($xml_is_sane === null) - { - $parser_check = xml_parser_create(); - xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); - xml_parser_free($parser_check); - $xml_is_sane = isset($values[0]['value']); - } - - // Create the parser - if ($xml_is_sane) - { - $xml = xml_parser_create_ns($this->encoding, $this->separator); - xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($xml, $this); - xml_set_character_data_handler($xml, 'cdata'); - xml_set_element_handler($xml, 'tag_open', 'tag_close'); - xml_set_start_namespace_decl_handler($xml, 'start_xmlns'); - - // Parse! - if (!xml_parse($xml, $data, true)) - { - $this->error_code = xml_get_error_code($xml); - $this->error_string = xml_error_string($this->error_code); - $return = false; - } - - $this->current_line = xml_get_current_line_number($xml); - $this->current_column = xml_get_current_column_number($xml); - $this->current_byte = xml_get_current_byte_index($xml); - xml_parser_free($xml); - - return $return; - } - else - { - libxml_clear_errors(); - $xml =& new XMLReader(); - $xml->xml($data); - while (@$xml->read()) - { - switch ($xml->nodeType) - { - - case constant('XMLReader::END_ELEMENT'): - if ($xml->namespaceURI !== '') - { - $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; - } - else - { - $tagName = $xml->localName; - } - $this->tag_close(null, $tagName); - break; - case constant('XMLReader::ELEMENT'): - $empty = $xml->isEmptyElement; - if ($xml->namespaceURI !== '') - { - $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; - } - else - { - $tagName = $xml->localName; - } - $attributes = array(); - while ($xml->moveToNextAttribute()) - { - if ($xml->namespaceURI !== '') - { - $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; - } - else - { - $attrName = $xml->localName; - } - $attributes[$attrName] = $xml->value; - } - - foreach ($attributes as $attr => $value) : - list($ns, $local) = $this->split_ns($attr); - if ($ns=='http://www.w3.org/2000/xmlns/') : - if ('xmlns' == $local) : $local = false; endif; - $this->start_xmlns(null, $local, $value); - endif; - endforeach; - - $this->tag_open(null, $tagName, $attributes); - if ($empty) - { - $this->tag_close(null, $tagName); - } - break; - case constant('XMLReader::TEXT'): - - case constant('XMLReader::CDATA'): - $this->cdata(null, $xml->value); - break; - } - } - if ($error = libxml_get_last_error()) - { - $this->error_code = $error->code; - $this->error_string = $error->message; - $this->current_line = $error->line; - $this->current_column = $error->column; - return false; - } - else - { - return true; - } - } - } /* FeedWordPress_Parser::parse() */ - - var $xmlns_stack = array(); - var $xmlns_current = array(); - function tag_open ($parser, $tag, $attributes) { - $ret = parent::tag_open($parser, $tag, $attributes); - if ($this->current_xhtml_construct < 0) : - $this->data['xmlns'] = $this->xmlns_current; - $this->xmlns_stack[] = $this->xmlns_current; - endif; - return $ret; - } - - function tag_close($parser, $tag) { - if ($this->current_xhtml_construct < 0) : - $this->xmlns_current = array_pop($this->xmlns_stack); - endif; - $ret = parent::tag_close($parser, $tag); - return $ret; - } - - function start_xmlns ($parser, $prefix, $uri) { - if (!$prefix) : - $prefix = ''; - endif; - if ($this->current_xhtml_construct < 0) : - $this->xmlns_current[$prefix] = $uri; - endif; - return true; - } /* FeedWordPress_Parser::start_xmlns() */ -} - $feedwordpress_admin_footer = array(); -################################################################################ -## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################ -################################################################################ - -class FeedWordPressRPC { - function FeedWordPressRPC () { - add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods')); - } - - function xmlrpc_methods ($args = array()) { - $args['weblogUpdates.ping'] = array(&$this, 'ping'); - $args['feedwordpress.subscribe'] = array(&$this, 'subscribe'); - $args['feedwordpress.deactivate'] = array(&$this, 'deactivate'); - $args['feedwordpress.delete'] = array(&$this, 'delete'); - $args['feedwordpress.nuke'] = array(&$this, 'nuke'); - return $args; - } - - function ping ($args) { - global $feedwordpress; - - $delta = @$feedwordpress->update($args[1]); - if (is_null($delta)): - return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>."); - else: - $mesg = array(); - if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; } - if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; } - - return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg)); - endif; - } - - function validate (&$args) { - global $wp_xmlrpc_server; - - // First two params are username/password - $username = $wp_xmlrpc_server->escape(array_shift($args)); - $password = $wp_xmlrpc_server->escape(array_shift($args)); - - $ret = array(); - if ( !$user = $wp_xmlrpc_server->login($username, $password) ) : - $ret = $wp_xmlrpc_server->error; - elseif (!current_user_can('manage_links')) : - $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.'); - endif; - return $ret; - } - - function subscribe ($args) { - $ret = $this->validate($args); - if (is_array($ret)) : // Success - // The remaining params are feed URLs - foreach ($args as $arg) : - $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1); - $feeds = array_values(array_unique($finder->find())); - - if (count($feeds) > 0) : - $link_id = FeedWordPress::syndicate_link( - /*title=*/ feedwordpress_display_url($feeds[0]), - /*homepage=*/ $feeds[0], - /*feed=*/ $feeds[0] - ); - $ret[] = array( - 'added', - $feeds[0], - $arg, - ); - else : - $ret[] = array( - 'error', - $arg - ); - endif; - endforeach; - endif; - return $ret; - } /* FeedWordPressRPC::subscribe () */ - - function unsubscribe ($method, $args) { - $ret = $this->validate($args); - if (is_array($ret)) : // Success - // The remaining params are feed URLs - foreach ($args as $arg) : - $link_id = FeedWordPress::find_link($arg); - - if (!$link_id) : - $link_id = FeedWordPress::find_link($arg, 'link_url'); - endif; - - if ($link_id) : - $link = new SyndicatedLink($link_id); - - $link->{$method}(); - $ret[] = array( - 'deactivated', - $arg, - ); - else : - $ret[] = array( - 'error', - $arg, - ); - endif; - endforeach; - endif; - return $ret; - } /* FeedWordPress::unsubscribe () */ - - function deactivate ($args) { - return $this->unsubscribe('deactivate', $args); - } /* FeedWordPressRPC::deactivate () */ - - function delete ($args) { - return $this->unsubscribe('delete', $args); - } /* FeedWordPressRPC::delete () */ - - function nuke ($args) { - return $this->unsubscribe('nuke', $args); - } /* FeedWordPressRPC::nuke () */ -} /* class FeedWordPressRPC */ - // take your best guess at the realname and e-mail, given a string define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)'); define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))'); diff --git a/wp-content/plugins/feedwordpress/feedwordpress_file.class.php b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php new file mode 100644 index 0000000000000000000000000000000000000000..70a9edffe2d889546cb4dc0ea643e3d58a01e910 --- /dev/null +++ b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php @@ -0,0 +1,21 @@ +<?php +class FeedWordPress_File extends WP_SimplePie_File { + function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { + self::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + + function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { + if (is_callable(array('WP_SimplePie_File', 'WP_SimplePie_File'))) : // PHP 4 idiom + WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + else : // PHP 5+ + parent::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + endif; + + // SimplePie makes a strongly typed check against integers with + // this, but WordPress puts a string in. Which causes caching + // to break and fall on its ass when SimplePie is getting a 304, + // but doesn't realize it because this member is "304" instead. + $this->status_code = (int) $this->status_code; + } +} /* class FeedWordPress_File () */ + diff --git a/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php b/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php new file mode 100644 index 0000000000000000000000000000000000000000..49c2239bffcdb543c2ff7ee4a571422624f8a418 --- /dev/null +++ b/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php @@ -0,0 +1,203 @@ +<?php +class FeedWordPress_Parser extends SimplePie_Parser { + function parse (&$data, $encoding) { + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character + if (strtoupper($encoding) === 'US-ASCII') + { + $this->encoding = 'UTF-8'; + } + else + { + $this->encoding = $encoding; + } + + // Strip BOM: + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + { + $data = substr($data, 4); + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $data = substr($data, 4); + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $data = substr($data, 2); + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $data = substr($data, 2); + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $data = substr($data, 3); + } + + if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) + { + $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); + if ($declaration->parse()) + { + $data = substr($data, $pos + 2); + $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; + } + else + { + $this->error_string = 'SimplePie bug! Please report this!'; + return false; + } + } + + $return = true; + + static $xml_is_sane = null; + if ($xml_is_sane === null) + { + $parser_check = xml_parser_create(); + xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); + xml_parser_free($parser_check); + $xml_is_sane = isset($values[0]['value']); + } + + // Create the parser + if ($xml_is_sane) + { + $xml = xml_parser_create_ns($this->encoding, $this->separator); + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xml, $this); + xml_set_character_data_handler($xml, 'cdata'); + xml_set_element_handler($xml, 'tag_open', 'tag_close'); + xml_set_start_namespace_decl_handler($xml, 'start_xmlns'); + + // Parse! + if (!xml_parse($xml, $data, true)) + { + $this->error_code = xml_get_error_code($xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + } + + $this->current_line = xml_get_current_line_number($xml); + $this->current_column = xml_get_current_column_number($xml); + $this->current_byte = xml_get_current_byte_index($xml); + xml_parser_free($xml); + + return $return; + } + else + { + libxml_clear_errors(); + $xml =& new XMLReader(); + $xml->xml($data); + while (@$xml->read()) + { + switch ($xml->nodeType) + { + + case constant('XMLReader::END_ELEMENT'): + if ($xml->namespaceURI !== '') + { + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $tagName = $xml->localName; + } + $this->tag_close(null, $tagName); + break; + case constant('XMLReader::ELEMENT'): + $empty = $xml->isEmptyElement; + if ($xml->namespaceURI !== '') + { + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $tagName = $xml->localName; + } + $attributes = array(); + while ($xml->moveToNextAttribute()) + { + if ($xml->namespaceURI !== '') + { + $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $attrName = $xml->localName; + } + $attributes[$attrName] = $xml->value; + } + + foreach ($attributes as $attr => $value) : + list($ns, $local) = $this->split_ns($attr); + if ($ns=='http://www.w3.org/2000/xmlns/') : + if ('xmlns' == $local) : $local = false; endif; + $this->start_xmlns(null, $local, $value); + endif; + endforeach; + + $this->tag_open(null, $tagName, $attributes); + if ($empty) + { + $this->tag_close(null, $tagName); + } + break; + case constant('XMLReader::TEXT'): + + case constant('XMLReader::CDATA'): + $this->cdata(null, $xml->value); + break; + } + } + if ($error = libxml_get_last_error()) + { + $this->error_code = $error->code; + $this->error_string = $error->message; + $this->current_line = $error->line; + $this->current_column = $error->column; + return false; + } + else + { + return true; + } + } + } /* FeedWordPress_Parser::parse() */ + + var $xmlns_stack = array(); + var $xmlns_current = array(); + function tag_open ($parser, $tag, $attributes) { + $ret = parent::tag_open($parser, $tag, $attributes); + if ($this->current_xhtml_construct < 0) : + $this->data['xmlns'] = $this->xmlns_current; + $this->xmlns_stack[] = $this->xmlns_current; + endif; + return $ret; + } + + function tag_close($parser, $tag) { + if ($this->current_xhtml_construct < 0) : + $this->xmlns_current = array_pop($this->xmlns_stack); + endif; + $ret = parent::tag_close($parser, $tag); + return $ret; + } + + function start_xmlns ($parser, $prefix, $uri) { + if (!$prefix) : + $prefix = ''; + endif; + if ($this->current_xhtml_construct < 0) : + $this->xmlns_current[$prefix] = $uri; + endif; + return true; + } /* FeedWordPress_Parser::start_xmlns() */ +} + diff --git a/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php b/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php new file mode 100644 index 0000000000000000000000000000000000000000..ead601c558a73075fe0b31037beb2477fbe0ff56 --- /dev/null +++ b/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php @@ -0,0 +1,123 @@ +<?php +################################################################################ +## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################ +################################################################################ + +class FeedWordPressRPC { + function FeedWordPressRPC () { + add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods')); + } + + function xmlrpc_methods ($args = array()) { + $args['weblogUpdates.ping'] = array(&$this, 'ping'); + $args['feedwordpress.subscribe'] = array(&$this, 'subscribe'); + $args['feedwordpress.deactivate'] = array(&$this, 'deactivate'); + $args['feedwordpress.delete'] = array(&$this, 'delete'); + $args['feedwordpress.nuke'] = array(&$this, 'nuke'); + return $args; + } + + function ping ($args) { + global $feedwordpress; + + $delta = @$feedwordpress->update($args[1]); + if (is_null($delta)): + return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>."); + else: + $mesg = array(); + if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; } + if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; } + + return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg)); + endif; + } + + function validate (&$args) { + global $wp_xmlrpc_server; + + // First two params are username/password + $username = $wp_xmlrpc_server->escape(array_shift($args)); + $password = $wp_xmlrpc_server->escape(array_shift($args)); + + $ret = array(); + if ( !$user = $wp_xmlrpc_server->login($username, $password) ) : + $ret = $wp_xmlrpc_server->error; + elseif (!current_user_can('manage_links')) : + $ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.'); + endif; + return $ret; + } + + function subscribe ($args) { + $ret = $this->validate($args); + if (is_array($ret)) : // Success + // The remaining params are feed URLs + foreach ($args as $arg) : + $finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1); + $feeds = array_values(array_unique($finder->find())); + + if (count($feeds) > 0) : + $link_id = FeedWordPress::syndicate_link( + /*title=*/ feedwordpress_display_url($feeds[0]), + /*homepage=*/ $feeds[0], + /*feed=*/ $feeds[0] + ); + $ret[] = array( + 'added', + $feeds[0], + $arg, + ); + else : + $ret[] = array( + 'error', + $arg + ); + endif; + endforeach; + endif; + return $ret; + } /* FeedWordPressRPC::subscribe () */ + + function unsubscribe ($method, $args) { + $ret = $this->validate($args); + if (is_array($ret)) : // Success + // The remaining params are feed URLs + foreach ($args as $arg) : + $link_id = FeedWordPress::find_link($arg); + + if (!$link_id) : + $link_id = FeedWordPress::find_link($arg, 'link_url'); + endif; + + if ($link_id) : + $link = new SyndicatedLink($link_id); + + $link->{$method}(); + $ret[] = array( + 'deactivated', + $arg, + ); + else : + $ret[] = array( + 'error', + $arg, + ); + endif; + endforeach; + endif; + return $ret; + } /* FeedWordPress::unsubscribe () */ + + function deactivate ($args) { + return $this->unsubscribe('deactivate', $args); + } /* FeedWordPressRPC::deactivate () */ + + function delete ($args) { + return $this->unsubscribe('delete', $args); + } /* FeedWordPressRPC::delete () */ + + function nuke ($args) { + return $this->unsubscribe('nuke', $args); + } /* FeedWordPressRPC::nuke () */ +} /* class FeedWordPressRPC */ + diff --git a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php index 99b24d9dfb4980c7691b5143e0edf79b8e75c58b..71e060ef6f8ba32a5417cb1a9c5be91a9631271e 100644 --- a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php +++ b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php @@ -93,7 +93,7 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage { $update_set[] = $target->link_rss; endforeach; else : // This should never happen - FeedWordPress::critical_bug('fwp_syndication_manage_page::targets', $targets, __LINE__); + FeedWordPress::critical_bug('fwp_syndication_manage_page::targets', $targets, __LINE__, __FILE__); endif; elseif (!is_null(FeedWordPress::post('update_uri'))) : $targets = FeedWordPress::post('update_uri'); diff --git a/wp-content/plugins/feedwordpress/inspectpostmeta.class.php b/wp-content/plugins/feedwordpress/inspectpostmeta.class.php new file mode 100644 index 0000000000000000000000000000000000000000..a53f4e2565d93d8f47d29badff9a3f5eb97f9aca --- /dev/null +++ b/wp-content/plugins/feedwordpress/inspectpostmeta.class.php @@ -0,0 +1,71 @@ +<?php +/* + * Inspect Post Meta + * Creates a post widget to help you inspect some meta fields for posts + * Version: 2010.1104 + * Author: Charles Johnson + * Author URI: http://projects.radgeek.com +*/ + +class InspectPostMeta { + function InspectPostMeta ($in_hook = true) { + if (!$in_hook) : + add_action('admin_menu', array($this, 'add_meta_box')); + else : + $this->add_meta_box(); + endif; + } + + function add_meta_box () { + add_meta_box( + /*id=*/ 'inspect_post_guid_box', + /*title=*/ 'Post GUID and Meta Data', + /*callback=*/ array($this, 'meta_box'), + /*page=*/ 'post', + /*context=*/ 'normal', + /*priority=*/ 'default' + ); + } + + function meta_box () { + global $post; + ?> + <table> + <tbody> + <tr> + <th style="text-align: left" scope="row">ID:</th> + <td><code><?php print esc_html($post->ID); ?></code></td> + </tr> + + <tr> + <th style="text-align: left" scope="row">GUID:</th> + <td><code><?php print esc_html($post->guid); ?></code></td> + </tr> + + <tr> + <th colspan="2" style="text-align: center"><h4>Custom Fields</h4></th> + </tr> + + <?php + $custom = get_post_custom($post->ID); + if (count($custom) > 0) : + foreach ($custom as $key => $values) : + $idx = 1; + foreach ($values as $value) : + print "<tr><th style='text-align: left' scope='row'>".esc_html($key); + if ($idx > 1) : + print "[$idx]"; + endif; + print ":</th> "; + print "<td><pre><code>".esc_html($value)."</code></pre>"; + print "</td></tr>\n"; + $idx++; + endforeach; + endforeach; + else : + print "<tr><td colspan='2'><p><em>No custom fields for this post.</em></p></td></tr>\n"; + endif; + print "</table>\n"; + } /* InspectPostMeta::meta_box() */ +} /* class InspectPostMeta */ + diff --git a/wp-content/plugins/feedwordpress/readme.txt b/wp-content/plugins/feedwordpress/readme.txt index 0219e2fe9a52275b49e7d9d5fdb6423b1ab5f8e6..97e4bbca30350ca02ccbd295a9fd08b0e4eeb3b0 100644 --- a/wp-content/plugins/feedwordpress/readme.txt +++ b/wp-content/plugins/feedwordpress/readme.txt @@ -3,8 +3,8 @@ Contributors: Charles Johnson Donate link: http://feedwordpress.radgeek.com/ Tags: syndication, aggregation, feed, atom, rss Requires at least: 3.0 -Tested up to: 3.0.5 -Stable tag: 2011.0211.2 +Tested up to: 3.2 +Stable tag: 2011.0721 FeedWordPress syndicates content from feeds you choose into your WordPress weblog. @@ -15,11 +15,12 @@ FeedWordPress syndicates content from feeds you choose into your WordPress weblo * License: GPL 2. See License below for copyright jots and tittles. FeedWordPress is an Atom/RSS aggregator for WordPress. It syndicates content -from feeds that you choose into your WordPress weblog; if you syndicate several -feeds then you can use WordPress's posts database and templating engine as the -back-end of an aggregation ("planet") website. It was developed, originally, -because I needed a more flexible replacement for [Planet][] -to use at [Feminist Blogs][]. +from feeds that you choose into your WordPress weblog; the content it syndicates +appears as a series of special posts in your WordPress posts database. If you +syndicate several feeds then you can use WordPress's posts database and +templating engine as the back-end of an aggregation ("planet") website. It was +developed, originally, because I needed a more flexible replacement for +[Planet][] to use at [Feminist Blogs][]. [Planet]: http://www.planetplanet.org/ [Feminist Blogs]: http://feministblogs.org/ @@ -93,6 +94,226 @@ outs, see the documentation at the [FeedWordPress project homepage][]. == Changelog == += 2011.0721 = + +* BUGFIX: SERIOUS BUG CAUSING RARE UNEXPECTED DELETION OF PAGES AND OTHER + CONTENT. A bug in the guid-checking code for some rare kinds of guids could + cause content in the wp_posts table to seemingly disappear at random after + FeedWordPress updates.This most frequently but not exclusively affected + static pages. What actually happened is that in these rare cases the + existing static page was mistaken for an older version of the new incoming + syndicated post, which was then stored as a new revision of the original + page. The bug that caused these mistaken identities has been fixed. + +* BUGFIX: UNWANTED AUTOMATIC PAGE-LOAD-BASED UPDATES NO LONGER A NUISANCE. + Some users encountered a bug in which FeedWordPress would adopt an automatic + page-load-based update method, even if they had requested that it not do + so, and that it use a manual or cron job update method instead. The bug + causing this has been fixed, and page-load-based updates should no longer + trigger unless explicitly turned on. + +* WP 3.2 USER INTERFACE COMPATIBILITY: POST TAGS BOX NOW WORKS AGAIN. The + release of WordPress 3.2 caused a breakage in the tags box which prevented + you from adding or removing tags under Syndication --> Categories & Tags. + (The breakage was the result of an incompatibility introduced by the new + release of jQuery.) This breakage has now been fixed, and the tags box + should work correctly again. + +* FEED UPDATE SCHEDULING IMPROVEMENTS: UI. The Syndicated Sources table now + provides considerably more data to understand update scheduling, when + specific scheduling decisions are made because of, e.g., requests from the + feed producer. + +* FEED UPDATE SCHEDULING IMPROVEMENTS: ENFORCEABLE "MINIMUM INTERVAL" SETTIN + TO SPACE OUT UPDATES. Some feeds request specific update schedules, using + standard elements such as sy:updateFrequency and rss:ttl. Normally, + FeedWordPress respects any scheduling requests that a feed makes -- if it + requests a longer gap between polls than what FWP would normally adopt, then + FWP slows down to meet the request. If it indicates a shorter gap than what + FWP would normally adopt, FWP speeds up and checks that feed for updates + more often than it normally would. Now, there should not be any way for user + settings to override an explicit slow-down request from the feed producer -- + if producers indicate a particular update schedule, then polling the feed + more frequently than they request is considered abusive behavior. But + there's no reason why users should not be able -- if they so desire -- to + override speed-up requests, and poll a feed *less* frequently than the + indicated update schedule, if the FWP user wants to space update checkins + over a longer interval of time. Before, they could not do this: FWP always + sped up to meet the indicated update schedule. Now, they can do this, by + using the new "Minimum Interval" setting in Syndication --> Feeds & + Updates.. + += 2011.0706 = + +* WP 3.2 COMPATIBILITY: ELIMINATES FATAL ERROR "Call to undefined method + WP_SimplePie_File::WP_SimplePie_File() in + [...]/wp-content/plugins/feedwordpress/feedwordpress.php on line 1841." The + latest release of WordPress, version 3.2, has shifted the minimum + requirements up to PHP 5.2, and in line with the shift to PHP5 they have + rewritten a number of code segments that made use of now-obsolete PHP4 + idioms. Unfortunately, this caused a fatal error whenever FeedWordPress + attempted to make use of the cache, since FWP's caching plugin was written + to match the older idiom. FeedWordPress has been updated to follow the new, + PHP5 idiom when possible, thus eliminating the fatal error. + +* PERFORMANCE: The handling of queries to determine whether posts had been + previously syndicated produced some very slow queries (usually, but not + always, involving a scan over the MD5(post_guid) column of the table). The + code that prepares MySQL queries for previously-syndicated checks has been + revised to eliminate the MD5(post_guid) scan entirely, and to significantly + improve performance by eliminating other unnecessary clauses. + +* BUGFIX: NO LONGER DESTROYS STICKY POSTS. Previous versions could destroy + (or, more precisely, replace the content of) sticky posts due to some + queries mashed together in unexpected ways by WordPress. Version 2011.0706 + accounts for and eliminates the problem; your sticky posts should be safe + once again. + +* BUGFIX: GUIDS CONTAINING MYSQL-ESCAPED CHARACTERS NO LONGER CAUSE DUPLICATE + POSTS TO APPEAR. One remaining source of duplicate post issues in 2011.0602 + was guids that contained characters that needed to be escaped for MySQL, + such as single quotes and double quotes. The work-around for handling + filtered URIs has now been corrected to ensure that these do not cause + duplicate posts. + += 2011.0602 = + +* WP 3.1.3 COMPAT / BUGFIX: WHITESPACE IN GUIDS NO LONGER PRODUCES DUPLICATE + POSTS. The work-around for handling filtered URIs in guid elements has now + been extended to handle URIs that were filtered because of leading or + trailing whitespace, in addition to URIs that were filtered because of + unapproved schemes. + +* WP 3.1.3 COMPAT / BUGFIX: RELATIVE URLS IN GUIDS NO LONGER PRODUCE DUPLICATE + POSTS. The work-around for handling filtered URIs in guid elements has now + been extended to handle URIs that were altered without being filtered out + entirely (most commonly because a scheme was added to a relative URL). + +* BUGFIX: UPDATES TO POST NO LONGER CAUSE DUPLICATE DRAFT VERSION TO APPEAR. + Under certain conditions in 2011.0531, an update to an existing post would + not be properly applied to the post itself, but rather would appear as a + duplicate post with Draft status. This bug has been eliminated, and updates + will now be properly inserted as revisions to the existing post. + += 2011.0531 = + +* WORDPRESS 3.1.3 COMPATIBILITY: DUPLICATE POSTS ISSUE FIXED. Due to + internal changes in the way that WordPress handles post guids in the + most recent release (3.1.3), many users experienced problems with many + duplicate posts appearing in rapid succession. (Specifically, this would + happen with any posts using tag: URL guids -- such as all the posts + coming from Blogger feeds or feeds from other Google services.) This + compatibility release of FeedWordPress eliminates the issue by working + around the new restrictions on tag: URLs. + +* NEW AND IMPROVED DIAGNOSTICS: Syndication --> Diagnostics now contains some + new diagnostics settings useful for debugging problems with duplicate posts + (allowing you to easily view the guid of posts in the WordPress posts + database and allowing you to track the SQL used to check for existing + versions of a syndicated post). + += 2011.0512 = + +* DIAGNOSTICS IMPROVEMENTS; "THERE MAY BE A BUG IN FEEDWORDPRESS" CRITICAL + ERROR NOTICES ELIMINATED: This version includes some major improvements + to the Syndication --> Diagnostics section, which should aid in + troubleshooting difficulties with items failing to be imported, posts + failing to be properly inserted into the database, or updates failing to + be recorded. If you have been encountering critical error / bug notices + with a white screen and the message "THERE MAY BE A BUG IN + FEEDWORDPRESS," followed by an extraordinarily long dump of mostly + incomprehensible diagnostic information, you'll be happy to know that + the condition causing these notices has been eliminated. In the few + cases where errors may still crop up with database insertions, + FeedWordPress will now produce a significantly more manageable and more + useful diagnostic message. + +* BUGFIX: NEW POSTS FAILING TO APPEAR IN A CLEANLY-INSTALLED FEEDWORDPRESS + SYSTEM. If you encountered a recurring problem with FeedWordPress + failing to import new posts, after a clean install of FeedWordPress + (i.e., not an upgrade from a previous version), this problem may have + been the result of a bug with author-handling which has now been fixed + in the 2011.0512 release. (If the problem does *not* go away with the + upgrade, this version also includes significant improvements to the + Diagnostics system, which will help track down what *is* causing it + in your particular case.) + +* PERFORMANCE: New handling of update hashes allows FeedWordPress to avoid + a certain kind of infinite loop, caused when two more more different + syndicated feeds each carried a version of the same item (for example, + because it appeared on two different aggregator feeds that you're + syndicating). In previous versions, when this kind of loop cropped up, + syndicated posts could pile up an indefinitely large number of revisions + -- each revision alternating between the version from each of the two + feeds where it appeared -- which would, over time, dramatically inflate + the size of the database, and kill the performance of queries on the + post table. This issue has been resolved: revisions of the post that + have been syndicated once will not be re-syndicated over and over again. + +* AUTHOR LISTS: Lists of authors presented on the Author settings pages + should now be easier to scan through, with author names arranged in + alphabetical order. + +* FEED ITEM DATE PARSING: More tweaks to make date-time handling more + resilient when feeds provide broken or weird values for the timestamps + on syndicated items. FWP will now attempt to work around unparseable + timezone values. + +* AUTHOR MATCHING: Now attempts to match author names against the WP login + name in addition to display_name; when creating user record, also fills + in some best-guess values for nickname, firstname and lastname. Also + properly picks up Atom 1.0 author/uri data from feed. + +* COMPATIBILITY: FeedWordPress has been successfully tested for + compatibility with recent releases of WordPress, up to version 3.1.2. + += 2011.0211 = + +* BUGFIX: DUPLICATE POSTS WHEN GUIDS ARE TOO LONG: When feeds included + exceptionally long GUIDs, FeedWordPress could occasionally get into + a situation where posts with the long GUIDs would be duplicated over + and over again with each update (because FWP failed to store the full + GUID, due to length constraints in the relevant database tables). + Without the full GUID, FWP would not know that the post had already + been syndicated once. This bug has been fixed, and should no longer + produce duplicate posts. + +* HTTP TIMEOUT SETTING: If you are frequently running into timeout + problems with one or more of the feeds you syndicate, FWP now allows you + to adjust the timeout for HTTP requests using a global or feed-by-feed + setting. + +* HTTP GET PARAMETERS: You can now temporarily or permanently add HTTP + GET parameters to a subscription using an interface in Syndication --> + Feeds & Updates. This is especially helpful for making quick, short-term + changes to a subscription (for example, to pull in all the previous + items from a web service, before settling down to pulling in only newly + updated items). + +* DIAGNOSTICS SYSTEM: Added several new diagnostics which are useful in + troubleshooting, and established a framework for add-on modules to hook + in with their own diagnostic messages. + +* UI: Adjusted some internal coding, which should allow for settings + pages and add-ons to properly display multiple category pickers on a + single settings page. + +* PHP4 COMPATIBILITY TWEAKS: This version makes some tweaks to the handling + of object references which should improve compatibility with older + versions of PHP. (Although, I should note, web hosts that still force + you to run under PHP 4 -- in 2011! -- are *bad web hosts*.) + +* IMPROVED PERFORMANCE: This version eliminates a *major* performance drag + that shows up on sites with large numbers of users (due to some poor + decisions about where to place a user query, which caused the user table + to be scanned frequently when it did not need to be). If you experienced + serious problems with CPU load or slow database performance under + 2010.0905, which kicked in immediately when FWP was loaded and tended + to disappear immediately if FWP was de-activated, it is likely that + upgrading away from 2010.0905 to the most recent version will resolve + your problem. + + = 2010.0905 = * BUGFIX: CATEGORIES AND TAGS CORRECTLY ASSIGNED IN AUTOMATIC UPDATES. diff --git a/wp-content/plugins/feedwordpress/syndicatedlink.class.php b/wp-content/plugins/feedwordpress/syndicatedlink.class.php index c1a45732e337ae27f95c277b2f745e9629b765f4..735bd6e09a9cfefe176445c766b44c470eb29d83 100644 --- a/wp-content/plugins/feedwordpress/syndicatedlink.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedlink.class.php @@ -165,16 +165,23 @@ class SyndicatedLink { } /* SyndicatedLink::found () */ function stale () { + global $feedwordpress; + $stale = true; - if (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='ping')) : + if ($this->setting('update/hold')=='ping') : $stale = false; // don't update on any timed updates; pings only - elseif (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='next')) : + elseif ($this->setting('update/hold')=='next') : $stale = true; // update on the next timed update - elseif (!isset($this->settings['update/ttl']) or !isset($this->settings['update/last'])) : + elseif ( !$this->setting('update/last') ) : $stale = true; // initial update + elseif ($feedwordpress->force_update_all()) : + $stale = true; // forced general updating else : - $after = ((int) $this->settings['update/last']) - +((int) $this->settings['update/ttl'] * 60); + $after = ( + (int) $this->setting('update/last') + + (int) $this->setting('update/fudge') + + ((int) $this->setting('update/ttl') * 60) + ); $stale = (time() >= $after); endif; return $stale; @@ -278,17 +285,23 @@ class SyndicatedLink { $this->settings = array_merge($this->settings, $this->flatten_array($channel)); - $this->settings['update/last'] = time(); $ttl = $this->ttl(); + $this->settings['update/last'] = time(); + list($ttl, $xml) = $this->ttl(/*return element=*/ true); + if (!is_null($ttl)) : $this->settings['update/ttl'] = $ttl; + $this->settings['update/xml'] = $xml; $this->settings['update/timed'] = 'feed'; else : - $this->settings['update/ttl'] = $this->automatic_ttl(); + $ttl = $this->automatic_ttl(); + $this->settings['update/ttl'] = $ttl; + $this->settings['update/xml'] = NULL; $this->settings['update/timed'] = 'automatically'; endif; - $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this); + $this->settings['update/fudge'] = rand(0, ($ttl/3))*60; + $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->setting('update/ttl'), $this); - if (!isset($this->settings['update/hold']) or $this->settings['update/hold']!='ping') : + if (!$this->setting('update/hold') != 'ping') : $this->settings['update/hold'] = 'scheduled'; endif; @@ -666,7 +679,7 @@ class SyndicatedLink { return $ret; } - function ttl () { + function ttl ($return_element = false) { if (is_object($this->magpie)) : $channel = $this->magpie->channel; else : @@ -678,6 +691,7 @@ class SyndicatedLink { // minutes that indicates how long a channel can be // cached before refreshing from the source." // <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt> + $xml = 'rss:ttl'; $ret = $channel['ttl']; elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) : $period_minutes = array ( @@ -705,11 +719,21 @@ class SyndicatedLink { else : $freq = 1; endif; + $xml = 'sy:updateFrequency'; $ret = (int) ($period_minutes[$period] / $freq); else : + $xml = NULL; $ret = NULL; endif; - return $ret; + + if ('yes'==$this->setting('update/minimum', 'update_minimum', 'no')) : + $min = (int) $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD); + + if ($min > $ret) : + $ret = NULL; + endif; + endif; + return ($return_element ? array($ret, $xml) : $ret); } /* SyndicatedLink::ttl() */ function automatic_ttl () { @@ -719,7 +743,9 @@ class SyndicatedLink { $updateWindow = DEFAULT_UPDATE_PERIOD; endif; - $fudgedInterval = $updateWindow+rand(0, 2*($updateWindow/3)); + // We get a fudge of 1/3 of window from elsewhere. We'll do some more + // fudging here. + $fudgedInterval = $updateWindow+rand(-($updateWindow/6), 5*($updateWindow/12)); return apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this); } /* SyndicatedLink::automatic_ttl () */ diff --git a/wp-content/plugins/feedwordpress/syndicatedpost.class.php b/wp-content/plugins/feedwordpress/syndicatedpost.class.php index df96b783ca948564f1decb0beaae01fd790313e2..e96869e572e8a5602a6c88a7c47a6e6a36451cb2 100644 --- a/wp-content/plugins/feedwordpress/syndicatedpost.class.php +++ b/wp-content/plugins/feedwordpress/syndicatedpost.class.php @@ -10,7 +10,7 @@ require_once(dirname(__FILE__).'/feedtime.class.php'); * different feed formats, which may be useful to FeedWordPress users * who make use of feed data in PHP add-ons and filters. * - * @version 2010.0905 + * @version 2011.0601 */ class SyndicatedPost { var $item = null; // MagpieRSS representation @@ -618,7 +618,7 @@ class SyndicatedPost { // Ignore whitespace, case, and tag cruft. $theExcerpt = preg_replace('/\s+/', '', strtolower(strip_tags($excerpt))); - $theContent = preg_replace('/\s+/', '', strtolower(strip_Tags($content))); + $theContent = preg_replace('/\s+/', '', strtolower(strip_tags($content))); if ( empty($excerpt) or $theExcerpt == $theContent ) : # If content is available, generate an excerpt. @@ -755,17 +755,49 @@ class SyndicatedPost { return $ts; } /* SyndicatedPost::updated() */ + var $_hashes = array(); + function stored_hashes ($id = NULL) { + if (is_null($id)) : + $id = $this->wp_id(); + endif; + + if (!isset($this->_hashes[$id])) : + $this->_hashes[$id] = get_post_custom_values( + 'syndication_item_hash', $id + ); + if (is_null($this->_hashes[$id])) : + $this->_hashes[$id] = array(); + endif; + endif; + return $this->_hashes[$id]; + } + function update_hash () { return md5(serialize($this->item)); } /* SyndicatedPost::update_hash() */ + /*static*/ function normalize_guid_prefix () { + return trailingslashit(get_bloginfo('url')).'?guid='; + } + + /*static*/ function normalize_guid ($guid) { + $guid = trim($guid); + if (preg_match('/^[0-9a-z]{32}$/i', $guid)) : // MD5 + $guid = SyndicatedPost::normalize_guid_prefix().strtolower($guid); + elseif ((strlen(esc_url($guid)) == 0) or (esc_url($guid) != $guid)) : + $guid = SyndicatedPost::normalize_guid_prefix().md5($guid); + endif; + $guid = trim($guid); + return $guid; + } /* SyndicatedPost::normalize_guid() */ + function guid () { $guid = null; - if (isset($this->item['id'])): // Atom 0.3 / 1.0 + if (isset($this->item['id'])): // Atom 0.3 / 1.0 $guid = $this->item['id']; elseif (isset($this->item['atom']['id'])) : // Namespaced Atom $guid = $this->item['atom']['id']; - elseif (isset($this->item['guid'])) : // RSS 2.0 + elseif (isset($this->item['guid'])) : // RSS 2.0 $guid = $this->item['guid']; elseif (isset($this->item['dc']['identifier'])) : // yeah, right $guid = $this->item['dc']['identifier']; @@ -859,8 +891,12 @@ class SyndicatedPost { $author['email'] = $this->feed->channel['author_email']; endif; - if (isset($this->item['author_url'])): + if (isset($this->item['author_uri'])): + $author['uri'] = $this->item['author_uri']; + elseif (isset($this->item['author_url'])): $author['uri'] = $this->item['author_url']; + elseif (isset($this->feed->channel['author_uri'])) : + $author['uri'] = $this->item['author_uri']; elseif (isset($this->feed->channel['author_url'])) : $author['uri'] = $this->item['author_url']; elseif (isset($this->feed->channel['link'])) : @@ -1199,22 +1235,31 @@ class SyndicatedPost { global $wpdb; if ($this->filtered()) : // This should never happen. - FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__); + FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__); endif; - if (is_null($this->_freshness)) : + if (is_null($this->_freshness)) : // Not yet checked and cached. $guid = $wpdb->escape($this->guid()); - $result = $wpdb->get_row(" - SELECT id, guid, post_modified_gmt - FROM $wpdb->posts WHERE guid='$guid' - "); - - if (!$result) : + $q = new WP_Query(array( + 'fields' => '_synfresh', // id, guid, post_modified_gmt + 'ignore_sticky_posts' => true, + 'guid' => $this->guid(), + )); + + $old_post = NULL; + if ($q->have_posts()) : + while ($q->have_posts()) : $q->the_post(); + $old_post = $q->post; + endwhile; + endif; + + if (is_null($old_post)) : // No post with this guid + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a NEW POST.'); $this->_wp_id = NULL; $this->_freshness = 2; // New content - else: - preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $result->post_modified_gmt, $backref); + else : + preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $old_post->post_modified_gmt, $backref); $last_rev_ts = gmmktime($backref[4], $backref[5], $backref[6], $backref[2], $backref[3], $backref[1]); $updated_ts = $this->updated(/*fallback=*/ true, /*default=*/ NULL); @@ -1225,12 +1270,13 @@ class SyndicatedPost { and ($updated_ts > $last_rev_ts) ); + if (!$updated) : // Or the hash... - $stored_update_hashes = get_post_custom_values('syndication_item_hash', $result->id); - if (count($stored_update_hashes) > 0) : - $stored_update_hash = $stored_update_hashes[0]; - $updated = ($stored_update_hash != $this->update_hash()); + $hash = $this->update_hash(); + $seen = $this->stored_hashes($old_post->ID); + if (count($seen) > 0) : + $updated = !in_array($hash, $seen); // Not seen yet? else : $updated = true; // Can't find syndication meta-data endif; @@ -1240,18 +1286,27 @@ class SyndicatedPost { if ($updated) : // Ignore if the post is frozen $frozen = ('yes' == $this->link->setting('freeze updates', 'freeze_updates', NULL)); if (!$frozen) : - $frozen_values = get_post_custom_values('_syndication_freeze_updates', $result->id); + $frozen_values = get_post_custom_values('_syndication_freeze_updates', $old_post->ID); $frozen = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]); endif; endif; $updated = ($updated and !$frozen); if ($updated) : + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is an update of an existing post.'); $this->_freshness = 1; // Updated content - $this->_wp_id = $result->id; + $this->_wp_id = $old_post->ID; + + // We want this to keep a running list of all the + // processed update hashes. + $this->post['meta']['syndication_item_hash'] = array_merge( + $this->stored_hashes(), + array($this->update_hash()) + ); else : + FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a duplicate of an existing post.'); $this->_freshness = 0; // Same old, same old - $this->_wp_id = $result->id; + $this->_wp_id = $old_post->ID; endif; endif; endif; @@ -1264,7 +1319,7 @@ class SyndicatedPost { function wp_id () { if ($this->filtered()) : // This should never happen. - FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__); + FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__); endif; if (is_null($this->_wp_id) and is_null($this->_freshness)) : @@ -1277,7 +1332,7 @@ class SyndicatedPost { global $wpdb; if ($this->filtered()) : // This should never happen. - FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__); + FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__); endif; $freshness = $this->freshness(); @@ -1288,6 +1343,7 @@ class SyndicatedPost { ); if (is_null($this->post['post_author'])) : + FeedWordPress::diagnostic('feed_items:rejected', 'Filtered out item ['.$this->guid().'] without syndication: no author available'); $this->post = NULL; endif; endif; @@ -1436,7 +1492,14 @@ class SyndicatedPost { // Kludge to prevent kses filters from stripping the // content of posts when updating without a logged in // user who has `unfiltered_html` capability. - add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11); + $mungers = array('wp_filter_kses', 'wp_filter_post_kses'); + $removed = array(); + foreach ($mungers as $munger) : + if (has_filter('content_save_pre', $munger)) : + remove_filter('content_save_pre', $munger); + $removed[] = $munger; + endif; + endforeach; if ($update and function_exists('get_post_field')) : // Don't munge status fields that the user may @@ -1445,7 +1508,7 @@ class SyndicatedPost { foreach ($doNotMunge as $field) : $dbpost[$field] = get_post_field($field, $this->wp_id()); - endforeach; + endforeach; endif; // WP3's wp_insert_post scans current_user_can() for the @@ -1470,7 +1533,8 @@ class SyndicatedPost { $this->post['ID'] = $this->wp_id(); $dbpost['ID'] = $this->post['ID']; endif; - $this->_wp_id = wp_insert_post($dbpost); + + $this->_wp_id = wp_insert_post($dbpost, /*return wp_error=*/ true); remove_action( /*hook=*/ 'transition_post_status', @@ -1488,9 +1552,11 @@ class SyndicatedPost { // Turn off ridiculous fucking kludges #1 and #2 remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta')); - remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11); - - $this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__)); + foreach ($removed as $filter) : + add_filter('content_save_pre', $removed); + endforeach; + + $this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__)); endif; } /* function SyndicatedPost::insert_post () */ @@ -1511,16 +1577,7 @@ class SyndicatedPost { function normalize_post ($new = true) { global $wpdb; - $out = array(); - - // Why the fuck doesn't wp_insert_post already do this? - foreach ($this->post as $key => $value) : - if (is_string($value)) : - $out[$key] = $wpdb->escape($value); - else : - $out[$key] = $value; - endif; - endforeach; + $out = $this->post; $fullPost = $out['post_title'].$out['post_content']; $fullPost .= (isset($out['post_excerpt']) ? $out['post_excerpt'] : ''); @@ -1541,6 +1598,18 @@ class SyndicatedPost { // FIXME: Option for what to fill a blank title with... endif; + // Normalize the guid if necessary. + $out['guid'] = SyndicatedPost::normalize_guid($out['guid']); + + // Why the fuck doesn't wp_insert_post already do this? + foreach ($out as $key => $value) : + if (is_string($value)) : + $out[$key] = $wpdb->escape($value); + else : + $out[$key] = $value; + endif; + endforeach; + return $out; } @@ -1550,20 +1619,41 @@ class SyndicatedPost { * @param array $dbpost An array representing the post we attempted to insert or update * @param mixed $ns A string or array representing the namespace (class, method) whence this method was called. */ - function validate_post_id ($dbpost, $ns) { + function validate_post_id ($dbpost, $is_update, $ns) { if (is_array($ns)) : $ns = implode('::', $ns); else : $ns = (string) $ns; endif; - + // This should never happen. if (!is_numeric($this->_wp_id) or ($this->_wp_id == 0)) : - FeedWordPress::critical_bug( - /*name=*/ $ns.'::_wp_id', + $verb = ($is_update ? 'update existing' : 'insert new'); + $guid = $this->guid(); + $url = $this->permalink(); + $feed = $this->link->uri(array('add_params' => true)); + + // wp_insert_post failed. Diagnostics, or barf up a critical bug + // notice if we are in debug mode. + $mesg = "Failed to $verb item [$guid]. WordPress API returned no valid post ID.\n" + ."\t\tID = ".serialize($this->_wp_id)."\n" + ."\t\tURL = ".FeedWordPress::val($url) + ."\t\tFeed = ".FeedWordPress::val($feed); + FeedWordPress::diagnostic('updated_feeds:errors', "WordPress API error: $mesg"); + FeedWordPress::diagnostic('feed_items:rejected', $mesg); + + $mesg = <<<EOM +The WordPress API returned an invalid post ID + when FeedWordPress tried to $verb item $guid + [URL: $url] + from the feed at $feed + +$ns::_wp_id +EOM; + FeedWordPress::noncritical_bug( + /*message=*/ $mesg, /*var =*/ array( "\$this->_wp_id" => $this->_wp_id, "\$dbpost" => $dbpost, - "\$this" => $this ), - /*line # =*/ __LINE__ + /*line # =*/ __LINE__, /*filename=*/ __FILE__ ); endif; } /* SyndicatedPost::validate_post_id() */ @@ -1597,31 +1687,6 @@ class SyndicatedPost { WHERE post_type = 'revision' AND ID='$revision_id' "); } /* SyndicatedPost::fix_revision_meta () */ - - /** - * SyndicatedPost::avoid_kses_munge() -- If FeedWordPress is processing - * an automatic update, that generally means that wp_insert_post() is - * being called under the user credentials of whoever is viewing the - * blog at the time -- usually meaning no user at all. But if WordPress - * gets a wp_insert_post() when current_user_can('unfiltered_html') is - * false, it will run the content of the post through a kses function - * that strips out lots of HTML tags -- notably <object> and some others. - * This causes problems for syndicating (for example) feeds that contain - * YouTube videos. It also produces an unexpected asymmetry between - * automatically-initiated updates and updates initiated manually from - * the WordPress Dashboard (which are usually initiated under the - * credentials of a logged-in admin, and so don't get run through the - * kses function). So, to avoid the whole mess, what we do here is - * just forcibly disable the kses munging for a single syndicated post, - * by restoring the contents of the `post_content` field. - * - * @param string $content The content of the post, after other filters have gotten to it - * @return string The original content of the post, before other filters had a chance to munge it. - */ - function avoid_kses_munge ($content) { - global $wpdb; - return $wpdb->escape($this->post['post_content']); - } /** * SyndicatedPost::add_terms() -- if FeedWordPress is processing an @@ -1641,14 +1706,15 @@ class SyndicatedPost { * @param object $post The database record for the post just inserted. */ function add_terms ($new_status, $old_status, $post) { - if ( is_array($this->post) and isset($this->post['tax_input']) and is_array($this->post['tax_input']) ) : - foreach ($this->post['tax_input'] as $taxonomy => $terms) : - if (is_array($terms)) : - $terms = array_filter($terms); // strip out empties - endif; - - wp_set_post_terms($post->ID, $terms, $taxonomy); - endforeach; + if ($new_status!='inherit') : // Bail if we are creating a revision. + if ( is_array($this->post) and isset($this->post['tax_input']) and is_array($this->post['tax_input']) ) : + foreach ($this->post['tax_input'] as $taxonomy => $terms) : + if (is_array($terms)) : + $terms = array_filter($terms); // strip out empties + endif; + wp_set_post_terms($post->ID, $terms, $taxonomy); + endforeach; + endif; endif; } /* SyndicatedPost::add_terms () */ @@ -1669,10 +1735,12 @@ class SyndicatedPost { */ function fix_post_modified_ts ($new_status, $old_status, $post) { global $wpdb; - $wpdb->update( $wpdb->posts, /*data=*/ array( - 'post_modified' => $this->post['post_modified'], - 'post_modified_gmt' => $this->post['post_modified_gmt'], - ), /*where=*/ array('ID' => $post->ID) ); + if ($new_status!='inherit') : // Bail if we are creating a revision. + $wpdb->update( $wpdb->posts, /*data=*/ array( + 'post_modified' => $this->post['post_modified'], + 'post_modified_gmt' => $this->post['post_modified_gmt'], + ), /*where=*/ array('ID' => $post->ID) ); + endif; } /* SyndicatedPost::fix_post_modified_ts () */ /** @@ -1691,38 +1759,40 @@ class SyndicatedPost { * @param object $post The database record for the post just inserted. */ function add_rss_meta ($new_status, $old_status, $post) { - FeedWordPress::diagnostic('syndicated_posts:meta_data', 'Adding post meta-data: {'.implode(", ", array_keys($this->post['meta'])).'}'); - global $wpdb; - if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) : - $postId = $post->ID; - - // Aggregated posts should NOT send out pingbacks. - // WordPress 2.1-2.2 claim you can tell them not to - // using $post_pingback, but they don't listen, so we - // make sure here. - $result = $wpdb->query(" - DELETE FROM $wpdb->postmeta - WHERE post_id='$postId' AND meta_key='_pingme' - "); - - foreach ( $this->post['meta'] as $key => $values ) : - $eKey = $wpdb->escape($key); - - // If this is an update, clear out the old - // values to avoid duplication. + if ($new_status!='inherit') : // Bail if we are creating a revision. + FeedWordPress::diagnostic('syndicated_posts:meta_data', 'Adding post meta-data: {'.implode(", ", array_keys($this->post['meta'])).'}'); + + if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) : + $postId = $post->ID; + + // Aggregated posts should NOT send out pingbacks. + // WordPress 2.1-2.2 claim you can tell them not to + // using $post_pingback, but they don't listen, so we + // make sure here. $result = $wpdb->query(" DELETE FROM $wpdb->postmeta - WHERE post_id='$postId' AND meta_key='$eKey' + WHERE post_id='$postId' AND meta_key='_pingme' "); - - // Allow for either a single value or an array - if (!is_array($values)) $values = array($values); - foreach ( $values as $value ) : - FeedWordPress::diagnostic('syndicated_posts:meta_data', "Adding post meta-datum to post [$postId]: [$key] = ".FeedWordPress::val($value, /*no newlines=*/ true)); - add_post_meta($postId, $key, $value, /*unique=*/ false); + + foreach ( $this->post['meta'] as $key => $values ) : + $eKey = $wpdb->escape($key); + + // If this is an update, clear out the old + // values to avoid duplication. + $result = $wpdb->query(" + DELETE FROM $wpdb->postmeta + WHERE post_id='$postId' AND meta_key='$eKey' + "); + + // Allow for either a single value or an array + if (!is_array($values)) $values = array($values); + foreach ( $values as $value ) : + FeedWordPress::diagnostic('syndicated_posts:meta_data', "Adding post meta-datum to post [$postId]: [$key] = ".FeedWordPress::val($value, /*no newlines=*/ true)); + add_post_meta($postId, $key, $value, /*unique=*/ false); + endforeach; endforeach; - endforeach; + endif; endif; } /* SyndicatedPost::add_rss_meta () */ @@ -1739,11 +1809,17 @@ class SyndicatedPost { global $wpdb; $a = $this->named['author']; - + $source = $this->source(); $forbidden = apply_filters('feedwordpress_forbidden_author_names', array('admin', 'administrator', 'www', 'root')); + // Prepare the list of candidates to try for author name: name from + // feed, original source title (if any), immediate source title live + // from feed, subscription title, prettied version of feed homepage URL, + // prettied version of feed URL, or, failing all, use "unknown author" + // as last resort + $candidates = array(); $candidates[] = $a['name']; if (!is_null($source)) : $candidates[] = $source['title']; endif; @@ -1753,6 +1829,9 @@ class SyndicatedPost { $candidates[] = feedwordpress_display_url($this->link->uri()); $candidates[] = 'unknown author'; + // Pick the first one that works from the list, screening against empty + // or forbidden names. + $author = NULL; while (is_null($author) and ($candidate = each($candidates))) : if (!is_null($candidate['value']) @@ -1835,6 +1914,7 @@ class SyndicatedPost { $id = $wpdb->get_var( "SELECT ID FROM $wpdb->users WHERE TRIM(LCASE(display_name)) = TRIM(LCASE('$author')) + OR TRIM(LCASE(user_login)) = TRIM(LCASE('$author')) OR ( LENGTH(TRIM(LCASE(user_email))) > 0 AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email')) @@ -1878,6 +1958,10 @@ class SyndicatedPost { $userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up $userdata['user_email'] = $email; $userdata['user_url'] = $authorUrl; + $userdata['nickname'] = $author; + $parts = preg_split('/\s+/', trim($author), 2); + if (isset($parts[0])) : $userdata['first_name'] = $parts[0]; endif; + if (isset($parts[1])) : $userdata['last_name'] = $parts[1]; endif; $userdata['display_name'] = $author; $userdata['role'] = 'contributor'; @@ -1924,7 +2008,7 @@ class SyndicatedPost { endif; endif; return $id; - } // function SyndicatedPost::author_id () + } /* function SyndicatedPost::author_id () */ /** * category_ids: look up (and create) category ids from a list of categories @@ -2007,7 +2091,7 @@ class SyndicatedPost { endif; $term = wp_insert_term($cat_name, $tax); if (is_wp_error($term)) : - FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__); + FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__, __FILE__); else : if (!isset($terms[$tax])) : $terms[$tax] = array(); diff --git a/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php b/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php new file mode 100644 index 0000000000000000000000000000000000000000..90ff6553179a02db09694324663f555c32946d41 --- /dev/null +++ b/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php @@ -0,0 +1,100 @@ +<?php +class SyndicationDataQueries { + function SyndicationDataQueries () { + add_action('init', array(&$this, 'init')); + add_action('parse_query', array(&$this, 'parse_query'), 10, 1); + add_filter('posts_search', array(&$this, 'posts_search'), 10, 2); + add_filter('posts_where', array(&$this, 'posts_where'), 10, 2); + add_filter('posts_fields', array(&$this, 'posts_fields'), 10, 2); + add_filter('posts_request', array(&$this, 'posts_request'), 10, 2); + } + + function init () { + global $wp; + $wp->add_query_var('guid'); + } + + function parse_query (&$q) { + if ($q->get('guid')) : + $q->is_single = false; // Causes nasty side-effects. + $q->is_singular = true; // Doesn't? + endif; + + if ($q->get('fields') == '_synfresh') : + $q->query_vars['cache_results'] = false; // Not suitable. + endif; + } /* SyndicationDataQueries::parse_query () */ + + function pre_get_posts (&$q) { + // + } + + function posts_request ($sql, &$query) { + if ($query->get('fields') == '_synfresh') : + FeedWordPress::diagnostic('feed_items:freshness:sql', "SQL: ".$sql); + endif; + return $sql; + } + + function posts_search ($search, &$query) { + global $wpdb; + if ($guid = $query->get('guid')) : + if (strlen(trim($guid)) > 0) : + $seek = array($guid); + + // MD5 hashes + if (preg_match('/^[0-9a-f]{32}$/i', $guid)) : + $seek[] = SyndicatedPost::normalize_guid_prefix().$guid; + endif; + + // Invalid URIs, URIs that WordPress just doesn't like, and URIs + // that WordPress decides to munge. + $nGuid = SyndicatedPost::normalize_guid($guid); + if ($guid != $nGuid) : + $seek[] = $nGuid; + endif; + + // Escape to prevent frak-ups, injections, etc. + $seek = array_map('esc_sql', $seek); + + // Assemble + $guidMatch = "(guid = '".implode("') OR (guid = '", $seek)."')"; + $search .= " AND ($guidMatch)"; + endif; + endif; + + if ($query->get('fields')=='_synfresh') : + // Ugly hack to ensure we ONLY check by guid in syndicated freshness + // checks -- for reasons of both performance and correctness. Pitch: + $search .= " -- '"; + endif; + return $search; + } /* SyndicationDataQueries::posts_search () */ + + function posts_where ($where, &$q) { + // Ugly hack to ensure we ONLY check by guid in syndicated freshness + // checks -- for reasons of both performance and correctness. Catch: + if (strpos($where, " -- '") !== false) : + $bits = explode(" -- '", $where, 2); + $where = $bits[0]; + endif; + return $where; + } /* SyndicationDataQueries::post_where () */ + + function posts_fields ($fields, &$query) { + global $wpdb; + if ($f = $query->get('fields')) : + switch ($f) : + case '_synfresh' : + $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_modified_gmt"; + break; + default : + // Do nothing. + endswitch; + endif; + return $fields; + } /* SyndicationDataQueries::posts_fields () */ +} + +$SDQ = new SyndicationDataQueries; +