Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 5 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jul 20, 2012
Charles Johnson Ver bump. f99fdac
Charles Johnson Add .gitignore. c4ffab2
Charles Johnson .gitignore Dropbox conflict copies. 6de7199
Commits on Jul 24, 2012
Charles Johnson .gitignore / Fiddle with exclusion rule. 69278b5
Commits on Aug 10, 2012
Charles Johnson Framework for processing Atom tombstones and framework for post expir…
…ation. Commissioned by Ellissa Nagle.
09684f0
View
8 .gitignore
@@ -0,0 +1,8 @@
+#####################################################################
+# Subversion Repository for the benefit of the WordPress overlords. #
+#####################################################################
+
+.svn
+*(*conflicted copy*)*
+
+
View
55 feeds-page.php
@@ -111,7 +111,7 @@ function display () {
'global_feeds_box' => __('Update Scheduling'),
'updated_posts_box' => __('Updated Posts'),
'custom_settings_box' => __('Custom Feed Settings (for use in templates)'),
- 'fetch_settings_box' => __('Settings for Fetching Feeds (Advanced)'),
+ 'advanced_settings_box' => __('Advanced Settings'),
);
if ($this->for_default_settings()) :
unset($this->boxes_by_methods['custom_settings_box']);
@@ -363,7 +363,13 @@ function fetch_timeout_setting_value ($setting, $defaulted, $params) {
print number_format(intval($setting)) . " " . (($setting==1) ? "second" : "seconds");
}
- function fetch_settings_box ($page, $box = NULL) {
+ function advanced_settings_box ($page, $box = NULL) {
+ ?>
+ <table class="edit-form">
+ <tr>
+ <th>Fetch Timeout:</th>
+ <td>
+ <?php
$this->setting_radio_control(
'fetch timeout', 'fetch_timeout',
array(&$this, 'fetch_timeout_setting'),
@@ -374,7 +380,42 @@ function fetch_settings_box ($page, $box = NULL) {
'labels' => array(&$this, 'fetch_timeout_setting_value'),
)
);
- } /* FeedWordPressFeedsPage::fetch_settings_box () */
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <th>Feed Update Type:</th>
+ <td><?php
+ $this->setting_radio_control('update_incremental', 'update_incremental',
+ /*options=*/ array(
+ 'incremental' => '<strong>Incremental.</strong> When items no longer appear on the feed, keep them in the WordPress posts table.',
+ 'complete' => '<strong>Complete.</strong> When items no longer appear on the feed, they are obsolete; retire them from the WordPress posts table.',
+ ),
+ /*params=*/ array(
+ 'setting-default' => NULL,
+ 'global-setting-default' => 'incremental',
+ 'default-input-value' => 'default',
+ )
+ ); ?></td>
+ </tr>
+ <tr>
+ <th>Allow Feeds to Delete Posts:</th>
+ <td><?php
+ $this->setting_radio_control('tombstones', 'tombstones',
+ /*options=*/ array(
+ 'yes' => 'Yes. If a feed indicates that one of its posts has been deleted, delete the local copy syndicated to this website.',
+ 'no' => 'No. Even if a feed indicates that one of its posts has been deleted, retain the local copy on this website.',
+ ),
+ /*params=*/ array(
+ 'setting-default' => NULL,
+ 'global-setting-default' => 'yes',
+ 'default-input-value' => 'default',
+ )
+ ); ?></td>
+ </tr>
+ </table>
+ <?php
+ } /* FeedWordPressFeedsPage::advanced_settings_box () */
function display_authentication_credentials_box ($params = array()) {
static $count = 0;
@@ -1175,6 +1216,14 @@ function save_settings ($post) {
endif;
$this->update_setting('fetch timeout', $timeout);
endif;
+
+ if (isset($post['update_incremental'])) :
+ $this->update_setting('update_incremental', $post['update_incremental']);
+ endif;
+
+ if (isset($post['tombstones'])) :
+ $this->update_setting('tombstones', $post['tombstones']);
+ endif;
if (isset($post['update_minimum'])) :
$this->update_setting('update/minimum', $post['update_minimum']);
View
42 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: 2012.0524
+Version: 2012.0810
Author: Charles Johnson
Author URI: http://radgeek.com/
License: GPL
@@ -11,7 +11,7 @@
/**
* @package FeedWordPress
- * @version 2012.0524
+ * @version 2012.0810
*/
# This uses code derived from:
@@ -34,7 +34,7 @@
# -- Don't change these unless you know what you're doing...
-define ('FEEDWORDPRESS_VERSION', '2012.0524');
+define ('FEEDWORDPRESS_VERSION', '2012.0810');
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
if (!defined('FEEDWORDPRESS_BLEG')) :
@@ -54,6 +54,8 @@
endif;
endif;
define ('FEEDWORDPRESS_DEBUG', $feedwordpress_debug);
+$feedwordpress_compatibility = true;
+define ('FEEDWORDPRESS_COMPATIBILITY', $feedwordpress_compatibility);
define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
define ('FEEDWORDPRESS_CAT_SEPARATOR', "\n");
@@ -1213,10 +1215,44 @@ function init () {
endif;*/
endif;
+ // This is a special post status for hiding posts that have expired
+ register_post_status('fwpretired', array(
+ 'label' => _x('Retired', 'post'),
+ 'label_count' => _n_noop('Retired <span class="count">(%s)</span>', 'Retired <span class="count">(%s)</span>'),
+ 'exclude_from_search' => true,
+ 'public' => false,
+ 'publicly_queryable' => false,
+ 'show_in_admin_all_list' => false,
+ 'show_in_admin_status_list' => true,
+ ));
+ add_action(
+ /*hook=*/ 'template_redirect',
+ /*function=*/ array(&$this, 'redirect_retired'),
+ /*priority=*/ -100
+ );
+
$this->clear_cache_magic_url();
$this->update_magic_url();
} /* FeedWordPress::init() */
+ function redirect_retired () {
+ global $wp_query;
+ if (is_singular()) :
+ if ('fwpretired'==$wp_query->post->post_status) :
+ do_action('feedwordpress_redirect_retired', $wp_query->post);
+
+ if (!($template = get_404_template())) :
+ $template = get_index_template();
+ endif;
+ if ($template = apply_filters('template_include', $template)) :
+ header("HTTP/1.1 410 Gone");
+ include($template);
+ endif;
+ exit;
+ endif;
+ endif;
+ }
+
function dashboard_setup () {
$see_it = FeedWordPress::menu_cap();
View
76 syndicatedlink.class.php
@@ -57,6 +57,8 @@ function SyndicatedLink ($link) {
if (strlen($this->link->link_rss) > 0) :
$this->get_settings_from_notes();
endif;
+
+ add_filter('feedwordpress_update_complete', array(&$this, 'process_retirements'), 1000, 1);
} /* SyndicatedLink::SyndicatedLink () */
function found () {
@@ -236,6 +238,21 @@ function poll ($crash_ts = NULL) {
$this->magpie->originals = $posts;
+ // If this is a complete feed, rather than an incremental feed, we
+ // need to prepare to mark everything for presumptive retirement.
+ if ($this->is_incremental()) :
+ $q = new WP_Query(array(
+ 'fields' => '_synfrom',
+ 'post_status__not' => 'fwpretired',
+ 'ignore_sticky_posts' => true,
+ 'meta_key' => 'syndication_feed_id',
+ 'meta_value' => $this->id,
+ ));
+ foreach ($q->posts as $p) :
+ update_post_meta($p->ID, '_feedwordpress_retire_me_'.$this->id, '1');
+ endforeach;
+ endif;
+
if (is_array($posts)) :
foreach ($posts as $key => $item) :
$post = new SyndicatedPost($item, $this);
@@ -255,6 +272,39 @@ function poll ($crash_ts = NULL) {
unset($post);
endforeach;
endif;
+
+ if ('yes'==$this->setting('tombstones', 'tombstones', 'yes')) :
+ // Check for use of Atom tombstones. Spec:
+ // <http://tools.ietf.org/html/draft-snell-atompub-tombstones-18>
+ $tombstones = $this->simplepie->get_feed_tags('http://purl.org/atompub/tombstones/1.0', 'deleted-entry');
+ if (count($tombstones) > 0) :
+ foreach ($tombstones as $tombstone) :
+ $ref = NULL;
+ foreach (array('', 'http://purl.org/atompub/tombstones/1.0') as $ns) :
+ if (isset($tombstone['attribs'][$ns])
+ and isset($tombstone['attribs'][$ns]['ref'])) :
+ $ref = $tombstone['attribs'][$ns]['ref'];
+ endif;
+ endforeach;
+
+ $q = new WP_Query(array(
+ 'ignore_sticky_posts' => true,
+ 'guid' => $ref,
+ 'meta_key' => 'syndication_feed_id',
+ 'meta_value' => $this->id, // Only allow a feed to tombstone its own entries.
+ ));
+
+ foreach ($q->posts as $p) :
+ $old_status = $p->post_status;
+ FeedWordPress::diagnostic('syndicated_posts', 'Retiring existing post # '.$p->ID.' "'.$p->post_title.'" due to Atom tombstone element in feed.');
+ set_post_field('post_status', 'fwpretired', $p->ID);
+ wp_transition_post_status('fwpretired', $old_status, $p);
+ endforeach;
+
+ endforeach;
+ endif;
+ endif;
+
$suffix = ($crashed ? 'crashed' : 'completed');
do_action('update_syndicated_feed_items', $this->id, $this);
do_action("update_syndicated_feed_items_${suffix}", $this->id, $this);
@@ -292,6 +342,28 @@ function poll ($crash_ts = NULL) {
return $new_count;
} /* SyndicatedLink::poll() */
+ function process_retirements ($delta) {
+ global $post;
+
+ $q = new WP_Query(array(
+ 'fields' => '_synfrom',
+ 'post_status__not' => 'fwpretired',
+ 'ignore_sticky_posts' => true,
+ 'meta_key' => '_feedwordpress_retire_me_'.$this->id,
+ 'meta_value' => '1',
+ ));
+ if ($q->have_posts()) :
+ foreach ($q->posts as $p) :
+ $old_status = $p->post_status;
+ FeedWordPress::diagnostic('syndicated_posts', 'Retiring existing post # '.$p->ID.' "'.$p->post_title.'" due to absence from a non-incremental feed.');
+ set_post_field('post_status', 'fwpretired', $p->ID);
+ wp_transition_post_status('fwpretired', $old_status, $p);
+ delete_post_meta($p->ID, '_feedwordpress_retire_me_'.$this->id);
+ endforeach;
+ endif;
+ return $delta;
+ }
+
/**
* Updates the URL for the feed syndicated by this link.
*
@@ -616,6 +688,10 @@ function update_setting ($name, $value, $default = 'default') {
endif;
} /* SyndicatedLink::update_setting () */
+ function is_incremental () {
+ return ('complete'==$this->setting('update_incremental', 'update_incremental', 'incremental'));
+ } /* SyndicatedLink::is_incremental () */
+
function uri ($params = array()) {
$params = wp_parse_args($params, array(
'add_params' => false,
View
121 syndicatedpost.class.php
@@ -850,56 +850,77 @@ function guid () {
function author () {
$author = array ();
- if (isset($this->item['author_name'])):
- $author['name'] = $this->item['author_name'];
- elseif (isset($this->item['dc']['creator'])):
- $author['name'] = $this->item['dc']['creator'];
- elseif (isset($this->item['dc']['contributor'])):
- $author['name'] = $this->item['dc']['contributor'];
- elseif (isset($this->feed->channel['dc']['creator'])) :
- $author['name'] = $this->feed->channel['dc']['creator'];
- elseif (isset($this->feed->channel['dc']['contributor'])) :
- $author['name'] = $this->feed->channel['dc']['contributor'];
- elseif (isset($this->feed->channel['author_name'])) :
- $author['name'] = $this->feed->channel['author_name'];
- elseif ($this->feed->is_rss() and isset($this->item['author'])) :
- // The author element in RSS is allegedly an
- // e-mail address, but lots of people don't use
- // it that way. So let's make of it what we can.
- $author = parse_email_with_realname($this->item['author']);
-
- if (!isset($author['name'])) :
- if (isset($author['email'])) :
- $author['name'] = $author['email'];
- else :
- $author['name'] = $this->feed->channel['title'];
+ $aa = $this->entry->get_authors();
+ if (count($aa) > 0) :
+ $a = reset($aa);
+
+ $author = array(
+ 'name' => $a->get_name(),
+ 'email' => $a->get_email(),
+ 'uri' => $a->get_link(),
+ );
+ endif;
+
+ if (FEEDWORDPRESS_COMPATIBILITY) :
+ // Search through the MagpieRSS elements: Atom, Dublin Core, RSS
+ if (isset($this->item['author_name'])):
+ $author['name'] = $this->item['author_name'];
+ elseif (isset($this->item['dc']['creator'])):
+ $author['name'] = $this->item['dc']['creator'];
+ elseif (isset($this->item['dc']['contributor'])):
+ $author['name'] = $this->item['dc']['contributor'];
+ elseif (isset($this->feed->channel['dc']['creator'])) :
+ $author['name'] = $this->feed->channel['dc']['creator'];
+ elseif (isset($this->feed->channel['dc']['contributor'])) :
+ $author['name'] = $this->feed->channel['dc']['contributor'];
+ elseif (isset($this->feed->channel['author_name'])) :
+ $author['name'] = $this->feed->channel['author_name'];
+ elseif ($this->feed->is_rss() and isset($this->item['author'])) :
+ // The author element in RSS is allegedly an
+ // e-mail address, but lots of people don't use
+ // it that way. So let's make of it what we can.
+ $author = parse_email_with_realname($this->item['author']);
+
+ if (!isset($author['name'])) :
+ if (isset($author['email'])) :
+ $author['name'] = $author['email'];
+ else :
+ $author['name'] = $this->feed->channel['title'];
+ endif;
endif;
endif;
- elseif ($this->link->name()) :
- $author['name'] = $this->link->name();
- else :
- $url = parse_url($this->link->uri());
- $author['name'] = $url['host'];
endif;
- if (isset($this->item['author_email'])):
- $author['email'] = $this->item['author_email'];
- elseif (isset($this->feed->channel['author_email'])) :
- $author['email'] = $this->feed->channel['author_email'];
+ if (!isset($author['name']) or is_null($author['name'])) :
+ // Nothing found. Try some crappy defaults.
+ if ($this->link->name()) :
+ $author['name'] = $this->link->name();
+ else :
+ $url = parse_url($this->link->uri());
+ $author['name'] = $url['host'];
+ endif;
endif;
- 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'])) :
- $author['uri'] = $this->feed->channel['link'];
+ if (FEEDWORDPRESS_COMPATIBILITY) :
+ if (isset($this->item['author_email'])):
+ $author['email'] = $this->item['author_email'];
+ elseif (isset($this->feed->channel['author_email'])) :
+ $author['email'] = $this->feed->channel['author_email'];
+ endif;
+
+ 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'])) :
+ $author['uri'] = $this->feed->channel['link'];
+ endif;
endif;
-
+
return $author;
} /* SyndicatedPost::author() */
@@ -1494,6 +1515,20 @@ function store () {
$ret = $retval[$freshness];
endif;
+ // If this is a legit, non-filtered post, tag it as found on the feed
+ // regardless of fresh or stale status
+ if (!$this->filtered()) :
+ $key = '_feedwordpress_retire_me_' . $this->link->id;
+ delete_post_meta($this->wp_id(), $key);
+
+ $status = get_post_field('post_status', $this->wp_id());
+ if ('fwpretired'==$status and $this->link->is_incremental()) :
+ FeedWordPress::diagnostic('syndicated_posts', "Un-retiring previously retired post # ".$this->wp_id()." due to re-appearance on non-incremental feed.");
+ set_post_field('post_status', $this->post['post_status'], $this->wp_id());
+ wp_transition_post_status($this->post['post_status'], $status, $old_status, $this->post);
+ endif;
+ endif;
+
// Remove add_rss_meta hook
remove_action(
/*hook=*/ 'transition_post_status',
View
17 syndicationdataqueries.class.php
@@ -45,7 +45,8 @@ function parse_query (&$q) {
$q->is_singular = true; // Doesn't?
endif;
- if ($q->get('fields') == '_synfresh') :
+ $ff = $q->get('fields');
+ if ($ff == '_synfresh' or $ff == '_synfrom') :
$q->query_vars['cache_results'] = false; // Not suitable.
endif;
} /* SyndicationDataQueries::parse_query () */
@@ -60,7 +61,7 @@ function posts_request ($sql, &$query) {
endif;
return $sql;
}
-
+
function posts_search ($search, &$query) {
global $wpdb;
if ($guid = $query->get('guid')) :
@@ -92,17 +93,26 @@ function posts_search ($search, &$query) {
// Ugly hack to ensure we ONLY check by guid in syndicated freshness
// checks -- for reasons of both performance and correctness. Pitch:
$search .= " -- '";
+ elseif ($query->get('fields')=='_synfrom') :
+ $search .= " AND ({$wpdb->postmeta}.meta_key = '".$query->get('meta_key')."' AND wp_postmeta.meta_value = '".$query->get('meta_value')."') -- '";
endif;
return $search;
} /* SyndicationDataQueries::posts_search () */
function posts_where ($where, &$q) {
+ global $wpdb;
+
// 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;
+
+ if ($psn = $q->get('post_status__not')) :
+ $where .= " AND ({$wpdb->posts}.post_status <> '".$wpdb->escape($psn)."')";
+ endif;
+
return $where;
} /* SyndicationDataQueries::post_where () */
@@ -113,6 +123,9 @@ function posts_fields ($fields, &$query) {
case '_synfresh' :
$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_modified_gmt";
break;
+ case '_synfrom' :
+ $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_title, {$wpdb->postmeta}.meta_value";
+ break;
default :
// Do nothing.
endswitch;

No commit comments for this range

Something went wrong with that request. Please try again.