/**
* SyndicatedPost constructor: Given a feed item and the source from
* which it was taken, prepare a post that can be inserted into the
* WordPress database on request, or updated in place if it has already
* been syndicated.
*
* @param array $item The item syndicated from the feed.
* @param SyndicatedLink $source The feed it was syndicated from.
*/
function SyndicatedPost($item, &$source)
{
global $wpdb;
if (empty($item) && empty($source)) {
return;
}
if (is_array($item) and isset($item['simplepie']) and isset($item['magpie'])) {
$this->entry = $item['simplepie'];
$this->item = $item['magpie'];
$item = $item['magpie'];
} elseif (is_a($item, 'SimplePie_Item')) {
$this->entry = $item;
// convert to Magpie for compat purposes
$mp = new MagpieFromSimplePie($source->simplepie, $this->entry);
$this->item = $mp->get_item();
// done with conversion object
$mp = NULL;
unset($mp);
} else {
$this->item = $item;
}
$this->link =& $source;
$this->feed = $source->magpie;
$this->feedmeta = $source->settings;
FeedWordPress::diagnostic('feed_items', 'Considering item [' . $this->guid() . '] "' . $this->entry->get_title() . '"');
# Dealing with namespaces can get so f*****g f****d.
$this->xmlns['forward'] = $source->magpie->_XMLNS_FAMILIAR;
$this->xmlns['reverse'] = array();
foreach ($this->xmlns['forward'] as $url => $ns) {
if (!isset($this->xmlns['reverse'][$ns])) {
$this->xmlns['reverse'][$ns] = array();
}
$this->xmlns['reverse'][$ns][] = $url;
}
// F*****g SimplePie.
$this->xmlns['reverse']['rss'][] = '';
# These globals were originally an ugly kludge around a bug in
# apply_filters from WordPress 1.5. The bug was fixed in 1.5.1,
# and I sure hope at this point that nobody writing filters for
# FeedWordPress is still relying on them.
#
# Anyway, I hereby declare them DEPRECATED as of 8 February
# 2010. I'll probably remove the globals within 1-2 releases in
# the interests of code hygiene and memory usage. If you
# currently use them in your filters, I advise you switch off to
# accessing the public members SyndicatedPost::feed and
# SyndicatedPost::feedmeta.
global $fwp_channel, $fwp_feedmeta;
$fwp_channel = $this->feed;
$fwp_feedmeta = $this->feedmeta;
// Trigger global syndicated_item filter.
$changed = apply_filters('syndicated_item', $this->item, $this);
$this->item = $changed;
// Allow for feed-specific syndicated_item filters.
$changed = apply_filters("syndicated_item_" . $source->uri(), $this->item, $this);
$this->item = $changed;
# Filters can halt further processing by returning NULL
if (is_null($this->item)) {
$this->post = NULL;
} else {
# Note that nothing is run through esc_sql() here.
# That's deliberate. The escaping is done at the point
# of insertion, not here, to avoid double-escaping and
# to avoid screwing with syndicated_post filters
$this->post['post_title'] = apply_filters('syndicated_item_title', $this->entry->get_title(), $this);
$this->named['author'] = apply_filters('syndicated_item_author', $this->author(), $this);
// This just gives us an alphanumeric name for the author.
// We look up (or create) the numeric ID for the author
// in SyndicatedPost::add().
$this->post['post_content'] = apply_filters('syndicated_item_content', $this->content(), $this);
$excerpt = apply_filters('syndicated_item_excerpt', $this->excerpt(), $this);
if (!empty($excerpt)) {
$this->post['post_excerpt'] = $excerpt;
}
// Dealing with timestamps in WordPress is so f*****g f****d.
$offset = (int) get_option('gmt_offset') * 60 * 60;
$post_date_gmt = $this->published(array('default' => -1));
$post_modified_gmt = $this->updated(array('default' => -1));
$this->post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $post_date_gmt);
$this->post['post_date'] = gmdate('Y-m-d H:i:s', $post_date_gmt + $offset);
$this->post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $post_modified_gmt);
$this->post['post_modified'] = gmdate('Y-m-d H:i:s', $post_modified_gmt + $offset);
// Use feed-level preferences or the global default.
$this->post['post_status'] = $this->link->syndicated_status('post', 'publish');
$this->post['comment_status'] = $this->link->syndicated_status('comment', 'closed');
$this->post['ping_status'] = $this->link->syndicated_status('ping', 'closed');
// Unique ID (hopefully a unique tag: URI); failing that, the permalink
$this->post['guid'] = apply_filters('syndicated_item_guid', $this->guid(), $this);
// User-supplied custom settings to apply to each post.
// Do first so that FWP-generated custom settings will
// overwrite if necessary; thus preventing any munging.
$postMetaIn = $this->link->postmeta(array("parsed" => true));
$postMetaOut = array();
foreach ($postMetaIn as $key => $meta) {
$postMetaOut[$key] = $meta->do_substitutions($this);
}
foreach ($postMetaOut as $key => $values) {
$this->post['meta'][$key] = array();
foreach ($values as $value) {
$this->post['meta'][$key][] = apply_filters("syndicated_post_meta_{$key}", $value, $this);
}
}
// RSS 2.0 / Atom 1.0 enclosure support
$enclosures = $this->entry->get_enclosures();
if (is_array($enclosures)) {
foreach ($enclosures as $enclosure) {
$this->post['meta']['enclosure'][] = apply_filters('syndicated_item_enclosure_url', $enclosure->get_link(), $this) . "\n" . apply_filters('syndicated_item_enclosure_length', $enclosure->get_length(), $this) . "\n" . apply_filters('syndicated_item_enclosure_type', $enclosure->get_type(), $this);
}
}
// In case you want to point back to the blog this was
// syndicated from.
$sourcemeta['syndication_source'] = apply_filters('syndicated_item_source_title', $this->link->name(), $this);
$sourcemeta['syndication_source_uri'] = apply_filters('syndicated_item_source_link', $this->link->homepage(), $this);
$sourcemeta['syndication_source_id'] = apply_filters('syndicated_item_source_id', $this->link->guid(), $this);
// Make use of atom:source data, if present in an aggregated feed
$entry_source = $this->source();
if (!is_null($entry_source)) {
foreach ($entry_source as $what => $value) {
if (!is_null($value)) {
if ($what == 'title') {
$key = 'syndication_source';
} elseif ($what == 'feed') {
$key = 'syndication_feed';
} else {
$key = "syndication_source_{$what}";
}
$sourcemeta["{$key}_original"] = apply_filters('syndicated_item_original_source_' . $what, $value, $this);
}
}
}
foreach ($sourcemeta as $meta_key => $value) {
if (!is_null($value)) {
$this->post['meta'][$meta_key] = $value;
}
}
// Store information on human-readable and machine-readable comment URIs
// Human-readable comment URI
$commentLink = apply_filters('syndicated_item_comments', $this->comment_link(), $this);
if (!is_null($commentLink)) {
$this->post['meta']['rss:comments'] = $commentLink;
}
// Machine-readable content feed URI
$commentFeed = apply_filters('syndicated_item_commentrss', $this->comment_feed(), $this);
if (!is_null($commentFeed)) {
$this->post['meta']['wfw:commentRSS'] = $commentFeed;
}
// Yeah, yeah, now I know that it's supposed to be
// wfw:commentRss. Oh well. Path dependence, sucka.
// Store information to identify the feed that this came from
if (isset($this->feedmeta['link/uri'])) {
$this->post['meta']['syndication_feed'] = $this->feedmeta['link/uri'];
}
if (isset($this->feedmeta['link/id'])) {
$this->post['meta']['syndication_feed_id'] = $this->feedmeta['link/id'];
}
if (isset($this->item['source_link_self'])) {
$this->post['meta']['syndication_feed_original'] = $this->item['source_link_self'];
}
// In case you want to know the external permalink...
$this->post['meta']['syndication_permalink'] = apply_filters('syndicated_item_link', $this->permalink());
// Store a hash of the post content for checking whether something needs to be updated
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
// Categories: start with default categories, if any.
$cats = array();
if ('no' != $this->link->setting('add/category', NULL, 'yes')) {
$fc = get_option("feedwordpress_syndication_cats");
if ($fc) {
$cats = array_merge($cats, explode("\n", $fc));
}
}
$fc = $this->link->setting('cats', NULL, array());
if (is_array($fc)) {
$cats = array_merge($cats, $fc);
}
$this->preset_terms['category'] = $cats;
// Now add categories from the post, if we have 'em
$cats = array();
$post_cats = $this->entry->get_categories();
if (is_array($post_cats)) {
foreach ($post_cats as $cat) {
$cat_name = $cat->get_term();
if (!$cat_name) {
$cat_name = $cat->get_label();
}
if ($this->link->setting('cat_split', NULL, NULL)) {
$pcre = "" . $this->feedmeta['cat_split'] . "";
$cats = array_merge($cats, preg_split($pcre, $cat_name, -1, PREG_SPLIT_NO_EMPTY));
} else {
$cats[] = $cat_name;
}
}
}
$this->feed_terms['category'] = apply_filters('syndicated_item_categories', $cats, $this);
// Tags: start with default tags, if any
$tags = array();
if ('no' != $this->link->setting('add/post_tag', NULL, 'yes')) {
$ft = get_option("feedwordpress_syndication_tags", NULL);
$tags = is_null($ft) ? array() : explode(FEEDWORDPRESS_CAT_SEPARATOR, $ft);
}
$ft = $this->link->setting('tags', NULL, array());
if (is_array($ft)) {
$tags = array_merge($tags, $ft);
}
$this->preset_terms['post_tag'] = $tags;
// Scan post for /a[@rel='tag'] and use as tags if present
$tags = $this->inline_tags();
$this->feed_terms['post_tag'] = apply_filters('syndicated_item_tags', $tags, $this);
$taxonomies = $this->link->taxonomies();
$feedTerms = $this->link->setting('terms', NULL, array());
$globalTerms = get_option('feedwordpress_syndication_terms', array());
$specials = array('category' => 'cats', 'post_tag' => 'tags');
foreach ($taxonomies as $tax) {
if (!isset($specials[$tax])) {
$terms = array();
// See if we should get the globals
if ('no' != $this->link->setting("add/{$tax}", NULL, 'yes')) {
if (isset($globalTerms[$tax])) {
$terms = $globalTerms[$tax];
}
}
// Now merge in the locals
if (isset($feedTerms[$tax])) {
$terms = array_merge($terms, $feedTerms[$tax]);
}
// That's all, folks.
$this->preset_terms[$tax] = $terms;
}
}
$this->post['post_type'] = apply_filters('syndicated_post_type', $this->link->setting('syndicated post type', 'syndicated_post_type', 'post'), $this);
}
}