Version Description
Download this release
Release Info
Developer | radgeek |
Plugin | FeedWordPress |
Version | 2009.0707 |
Comparing to | |
See all releases |
Code changes from version 2009.0618 to 2009.0707
- ChangeLog.text +24 -0
- MagpieRSS-upgrade/rss.php +2 -1
- admin-ui.php +36 -9
- categories-page.php +23 -18
- feedwordpress.php +19 -1372
- readme.txt +14 -14
- relative_uri.class.php +174 -0
- syndicatedpost.class.php +1194 -0
- syndication.php +39 -16
ChangeLog.text
CHANGED
@@ -1,5 +1,29 @@
|
|
1 |
FeedWordPress Change Log
|
2 |
========================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
Changes from 2009.0613 to 2009.0618
|
4 |
-----------------------------------
|
5 |
* BUGFIX: MYSTERY ERRORS WITH WITH WP_Http_Fsockopen HTTP TRANSPORT
|
1 |
FeedWordPress Change Log
|
2 |
========================
|
3 |
+
Changes from 2009.0618 to 2009.0707
|
4 |
+
-----------------------------------
|
5 |
+
* BUGFIX: WORDPRESS 2.8 AJAX COMPATIBILITY ISSUES RESOLVED (blank or
|
6 |
+
truncated "Syndicated Sites" administration page): Due to changes in the
|
7 |
+
AJAX interface elements between WordPress 2.7 and WordPress 2.8, several
|
8 |
+
FeedWordPress users encountered an issue where the front "Syndication"
|
9 |
+
page in the FeedWordPress administrative interface would come up blank,
|
10 |
+
without the normal "Syndicated Sites" list and "Update" control, or
|
11 |
+
sometimes wth the boxes visible but one or both of them truncated, with
|
12 |
+
only the title bar. This issue should now be resolved: with the new
|
13 |
+
version of FeedWordPress, the compatibility issue that caused the
|
14 |
+
disappearance should be eliminated, and if boxes are shown with only
|
15 |
+
their handle visible, you should once again be able to drop down the
|
16 |
+
rest of the box by clicking once on its title bar.
|
17 |
+
|
18 |
+
* BUGFIX: TAG SETTING WIDGET FIXED. Due to changes in interface elements
|
19 |
+
between WordPress 2.7 and WordPress 2.8, people using FeedWordPress with
|
20 |
+
WordPress 2.8 found that the widget for setting tags to be applied to
|
21 |
+
all syndicated posts, or all syndicated posts from a particular feed,
|
22 |
+
no longer displayed "Add" and "Remove" buttons for individual tags. This
|
23 |
+
issue has now been fixed, and the tagging widget should once again work
|
24 |
+
more or less exactly like the tagging widget for individual posts in the
|
25 |
+
normal WordPress admin interface.
|
26 |
+
|
27 |
Changes from 2009.0613 to 2009.0618
|
28 |
-----------------------------------
|
29 |
* BUGFIX: MYSTERY ERRORS WITH WITH WP_Http_Fsockopen HTTP TRANSPORT
|
MagpieRSS-upgrade/rss.php
CHANGED
@@ -1326,7 +1326,8 @@ function fetch_rss ($url) {
|
|
1326 |
}
|
1327 |
|
1328 |
// else fetch failed
|
1329 |
-
|
|
|
1330 |
// attempt to return cached object
|
1331 |
if ($rss) {
|
1332 |
if ( MAGPIE_DEBUG ) {
|
1326 |
}
|
1327 |
|
1328 |
// else fetch failed
|
1329 |
+
debug("MagpieRSS fetch failed [$errormsg]");
|
1330 |
+
|
1331 |
// attempt to return cached object
|
1332 |
if ($rss) {
|
1333 |
if ( MAGPIE_DEBUG ) {
|
admin-ui.php
CHANGED
@@ -84,18 +84,45 @@ function fwp_option_box_closer () {
|
|
84 |
endif;
|
85 |
}
|
86 |
|
87 |
-
function fwp_tags_box ($tags) {
|
88 |
if (!is_array($tags)) : $tags = array(); endif;
|
|
|
|
|
|
|
|
|
|
|
89 |
?>
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
function fwp_category_box ($checked, $object, $tags = array()) {
|
84 |
endif;
|
85 |
}
|
86 |
|
87 |
+
function fwp_tags_box ($tags, $object) {
|
88 |
if (!is_array($tags)) : $tags = array(); endif;
|
89 |
+
|
90 |
+
$desc = "<p style=\"font-size:smaller;font-style:bold;margin:0\">Tag $object as...</p>";
|
91 |
+
|
92 |
+
if (fwp_test_wp_version(FWP_SCHEMA_28)) : // WordPress 2.8+
|
93 |
+
fwp_option_box_opener(__('Tags'), 'tagsdiv', 'postbox');
|
94 |
?>
|
95 |
+
<?php print $desc; ?>
|
96 |
+
<div class="tagsdiv" id="post_tag">
|
97 |
+
<div class="jaxtag">
|
98 |
+
<div class="nojs-tags hide-if-js">
|
99 |
+
<p><?php _e('Add or remove tags'); ?></p>
|
100 |
+
<textarea name="tax_input[post_tag]" class="the-tags" id="tax-input[post_tag]"><?php echo implode(",", $tags); ?></textarea>
|
101 |
+
</div>
|
102 |
+
|
103 |
+
<span class="ajaxtag hide-if-no-js">
|
104 |
+
<label class="screen-reader-text" for="new-tag-post_tag"><?php _e('Tags'); ?></label>
|
105 |
+
<input type="text" id="new-tag-post_tag" name="newtag[post_tag]" class="newtag form-input-tip" size="16" autocomplete="off" value="<?php esc_attr_e('Add new tag'); ?>" />
|
106 |
+
<input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" />
|
107 |
+
</span>
|
108 |
+
</div>
|
109 |
+
<p class="howto"><?php echo __('Separate tags with commas.'); ?></p>
|
110 |
+
<div class="tagchecklist"></div>
|
111 |
+
</div>
|
112 |
+
<p class="tagcloud-link hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-post_tag"><?php printf( __('Choose from the most used tags in %s'), 'Post Tags'); ?></a></p>
|
113 |
+
</div>
|
114 |
+
</div>
|
115 |
<?php
|
116 |
+
else :
|
117 |
+
fwp_option_box_opener(__('Tags'), 'tagsdiv', 'postbox');
|
118 |
+
?>
|
119 |
+
<?php print $desc; ?>
|
120 |
+
<p id="jaxtag"><input type="text" name="tags_input" class="tags-input" id="tags-input" size="40" tabindex="3" value="<?php echo implode(",", $tags); ?>" /></p>
|
121 |
+
<div id="tagchecklist"></div>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
<?php
|
125 |
+
endif;
|
126 |
}
|
127 |
|
128 |
function fwp_category_box ($checked, $object, $tags = array()) {
|
categories-page.php
CHANGED
@@ -33,6 +33,15 @@ function fwp_categories_page () {
|
|
33 |
endforeach;
|
34 |
endif;
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
if (is_object($link) and $link->found()) :
|
37 |
$alter = array ();
|
38 |
|
@@ -42,12 +51,7 @@ function fwp_categories_page () {
|
|
42 |
endif;
|
43 |
|
44 |
// Tags
|
45 |
-
|
46 |
-
$link->settings['tags'] = array();
|
47 |
-
foreach (explode(',', $GLOBALS['fwp_post']['tags_input']) as $tag) :
|
48 |
-
$link->settings['tags'][] = trim($tag);
|
49 |
-
endforeach;
|
50 |
-
endif;
|
51 |
|
52 |
// Unfamiliar categories
|
53 |
if (isset($GLOBALS['fwp_post']["unfamiliar_category"])) :
|
@@ -93,14 +97,8 @@ function fwp_categories_page () {
|
|
93 |
endif;
|
94 |
|
95 |
// Tags
|
96 |
-
if (
|
97 |
-
|
98 |
-
else :
|
99 |
-
$tags = array();
|
100 |
-
endif;
|
101 |
-
|
102 |
-
if (!empty($tags)) :
|
103 |
-
update_option('feedwordpress_syndication_tags', implode(FEEDWORDPRESS_CAT_SEPARATOR, $tags));
|
104 |
else :
|
105 |
delete_option('feedwordpress_syndication_tags');
|
106 |
endif;
|
@@ -271,8 +269,7 @@ function fwp_categories_page () {
|
|
271 |
<div id="poststuff">
|
272 |
<div id="post-body">
|
273 |
<?php
|
274 |
-
fwp_option_box_opener(
|
275 |
-
fwp_category_box($dogs, 'all syndicated posts'.((is_object($link) and $link->found()) ? ' from this feed':''));
|
276 |
?>
|
277 |
<table class="edit-form">
|
278 |
<tr>
|
@@ -310,12 +307,20 @@ blank.</p></td>
|
|
310 |
</tr>
|
311 |
<?php endif; ?>
|
312 |
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
<?php
|
314 |
fwp_option_box_closer();
|
315 |
fwp_linkedit_periodic_submit();
|
316 |
|
317 |
-
if (
|
318 |
-
fwp_tags_box($tags);
|
319 |
fwp_linkedit_periodic_submit();
|
320 |
endif; ?>
|
321 |
</div>
|
33 |
endforeach;
|
34 |
endif;
|
35 |
|
36 |
+
// Different variable names to cope with different WordPress AJAX UIs
|
37 |
+
$syndicatedTags = array();
|
38 |
+
if (isset($GLOBALS['fwp_post']['tax_input']['post_tag'])) :
|
39 |
+
$syndicatedTags = explode(",", $GLOBALS['fwp_post']['tax_input']['post_tag']);
|
40 |
+
elseif (isset($GLOBALS['fwp_post']['tags_input'])) :
|
41 |
+
$syndicatedTags = explode(",", $GLOBALS['fwp_post']['tags_input']);
|
42 |
+
endif;
|
43 |
+
$syndicatedTags = array_map('trim', $syndicatedTags);
|
44 |
+
|
45 |
if (is_object($link) and $link->found()) :
|
46 |
$alter = array ();
|
47 |
|
51 |
endif;
|
52 |
|
53 |
// Tags
|
54 |
+
$link->settings['tags'] = $syndicatedTags;
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
// Unfamiliar categories
|
57 |
if (isset($GLOBALS['fwp_post']["unfamiliar_category"])) :
|
97 |
endif;
|
98 |
|
99 |
// Tags
|
100 |
+
if (!empty($syndicatedTags)) :
|
101 |
+
update_option('feedwordpress_syndication_tags', implode(FEEDWORDPRESS_CAT_SEPARATOR, $syndicatedTags));
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
else :
|
103 |
delete_option('feedwordpress_syndication_tags');
|
104 |
endif;
|
269 |
<div id="poststuff">
|
270 |
<div id="post-body">
|
271 |
<?php
|
272 |
+
fwp_option_box_opener("Feed Categories & Tags", 'fromfeeddiv', 'postbox');
|
|
|
273 |
?>
|
274 |
<table class="edit-form">
|
275 |
<tr>
|
307 |
</tr>
|
308 |
<?php endif; ?>
|
309 |
</table>
|
310 |
+
<?php
|
311 |
+
fwp_option_box_closer();
|
312 |
+
fwp_linkedit_periodic_submit();
|
313 |
+
?>
|
314 |
+
<?php
|
315 |
+
fwp_option_box_opener(__('Categories'), 'categorydiv', 'postbox');
|
316 |
+
fwp_category_box($dogs, 'all syndicated posts'.((is_object($link) and $link->found()) ? ' from this feed':''));
|
317 |
+
?>
|
318 |
<?php
|
319 |
fwp_option_box_closer();
|
320 |
fwp_linkedit_periodic_submit();
|
321 |
|
322 |
+
if (fwp_test_wp_version(FWP_SCHEMA_25)) :
|
323 |
+
fwp_tags_box($tags, 'all syndicated posts'.((is_object($link) and $link->found()) ? ' from this feed':''));
|
324 |
fwp_linkedit_periodic_submit();
|
325 |
endif; ?>
|
326 |
</div>
|
feedwordpress.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
-
Version: 2009.
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
@@ -28,7 +28,7 @@ License: GPL
|
|
28 |
|
29 |
# -- Don't change these unless you know what you're doing...
|
30 |
|
31 |
-
define ('FEEDWORDPRESS_VERSION', '2009.
|
32 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
33 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
34 |
|
@@ -52,6 +52,7 @@ define ('FWP_SCHEMA_23', 5495); // Database schema # for WP 2.3
|
|
52 |
define ('FWP_SCHEMA_25', 7558); // Database schema # for WP 2.5
|
53 |
define ('FWP_SCHEMA_26', 8201); // Database schema # for WP 2.6
|
54 |
define ('FWP_SCHEMA_27', 9872); // Database schema # for WP 2.7
|
|
|
55 |
|
56 |
if (FEEDWORDPRESS_DEBUG) :
|
57 |
// Help us to pick out errors, if any.
|
@@ -1004,10 +1005,7 @@ class FeedWordPress {
|
|
1004 |
if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
|
1005 |
// This is an older version or a fresh install. Does it
|
1006 |
// require a database upgrade or database initialization?
|
1007 |
-
if ($fwp_db_version
|
1008 |
-
// No. Just brand it with the new version.
|
1009 |
-
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1010 |
-
else :
|
1011 |
// Yes. Check to see whether this is a fresh install or an upgrade.
|
1012 |
$syn = $wpdb->get_col("
|
1013 |
SELECT post_id
|
@@ -1019,6 +1017,19 @@ class FeedWordPress {
|
|
1019 |
else : // fresh install; brand it as ours
|
1020 |
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1021 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1022 |
endif;
|
1023 |
endif;
|
1024 |
return $ret;
|
@@ -1138,1199 +1149,7 @@ class FeedWordPress {
|
|
1138 |
}
|
1139 |
} // class FeedWordPress
|
1140 |
|
1141 |
-
|
1142 |
-
var $item = null;
|
1143 |
-
|
1144 |
-
var $link = null;
|
1145 |
-
var $feed = null;
|
1146 |
-
var $feedmeta = null;
|
1147 |
-
|
1148 |
-
var $post = array ();
|
1149 |
-
|
1150 |
-
var $_freshness = null;
|
1151 |
-
var $_wp_id = null;
|
1152 |
-
|
1153 |
-
function SyndicatedPost ($item, $link) {
|
1154 |
-
global $wpdb;
|
1155 |
-
|
1156 |
-
$this->link = $link;
|
1157 |
-
$feedmeta = $link->settings;
|
1158 |
-
$feed = $link->magpie;
|
1159 |
-
|
1160 |
-
# This is ugly as all hell. I'd like to use apply_filters()'s
|
1161 |
-
# alleged support for a variable argument count, but this seems
|
1162 |
-
# to have been broken in WordPress 1.5. It'll be fixed somehow
|
1163 |
-
# in WP 1.5.1, but I'm aiming at WP 1.5 compatibility across
|
1164 |
-
# the board here.
|
1165 |
-
#
|
1166 |
-
# Cf.: <http://mosquito.wordpress.org/view.php?id=901>
|
1167 |
-
global $fwp_channel, $fwp_feedmeta;
|
1168 |
-
$fwp_channel = $feed; $fwp_feedmeta = $feedmeta;
|
1169 |
-
|
1170 |
-
$this->feed = $feed;
|
1171 |
-
$this->feedmeta = $feedmeta;
|
1172 |
-
|
1173 |
-
$this->item = $item;
|
1174 |
-
$this->item = apply_filters('syndicated_item', $this->item, $this);
|
1175 |
-
|
1176 |
-
# Filters can halt further processing by returning NULL
|
1177 |
-
if (is_null($this->item)) :
|
1178 |
-
$this->post = NULL;
|
1179 |
-
else :
|
1180 |
-
# Note that nothing is run through $wpdb->escape() here.
|
1181 |
-
# That's deliberate. The escaping is done at the point
|
1182 |
-
# of insertion, not here, to avoid double-escaping and
|
1183 |
-
# to avoid screwing with syndicated_post filters
|
1184 |
-
|
1185 |
-
$this->post['post_title'] = apply_filters('syndicated_item_title', $this->item['title'], $this);
|
1186 |
-
|
1187 |
-
// This just gives us an alphanumeric representation of
|
1188 |
-
// the author. We will look up (or create) the numeric
|
1189 |
-
// ID for the author in SyndicatedPost::add()
|
1190 |
-
$this->post['named']['author'] = apply_filters('syndicated_item_author', $this->author(), $this);
|
1191 |
-
|
1192 |
-
# Identify content and sanitize it.
|
1193 |
-
# ---------------------------------
|
1194 |
-
if (isset($this->item['atom_content'])) :
|
1195 |
-
$content = $this->item['atom_content'];
|
1196 |
-
elseif (isset($this->item['xhtml']['body'])) :
|
1197 |
-
$content = $this->item['xhtml']['body'];
|
1198 |
-
elseif (isset($this->item['xhtml']['div'])) :
|
1199 |
-
$content = $this->item['xhtml']['div'];
|
1200 |
-
elseif (isset($this->item['content']['encoded']) and $this->item['content']['encoded']):
|
1201 |
-
$content = $this->item['content']['encoded'];
|
1202 |
-
else:
|
1203 |
-
$content = $this->item['description'];
|
1204 |
-
endif;
|
1205 |
-
$this->post['post_content'] = apply_filters('syndicated_item_content', $content, $this);
|
1206 |
-
|
1207 |
-
# Identify and sanitize excerpt
|
1208 |
-
$excerpt = NULL;
|
1209 |
-
if ( isset($this->item['description']) and $this->item['description'] ) :
|
1210 |
-
$excerpt = $this->item['description'];
|
1211 |
-
elseif ( isset($content) and $content ) :
|
1212 |
-
$excerpt = strip_tags($content);
|
1213 |
-
if (strlen($excerpt) > 255) :
|
1214 |
-
$excerpt = substr($excerpt,0,252).'...';
|
1215 |
-
endif;
|
1216 |
-
endif;
|
1217 |
-
$excerpt = apply_filters('syndicated_item_excerpt', $excerpt, $this);
|
1218 |
-
|
1219 |
-
if (!is_null($excerpt)):
|
1220 |
-
$this->post['post_excerpt'] = $excerpt;
|
1221 |
-
endif;
|
1222 |
-
|
1223 |
-
// This is unnecessary if we use wp_insert_post
|
1224 |
-
if (!$this->use_api('wp_insert_post')) :
|
1225 |
-
$this->post['post_name'] = sanitize_title($this->post['post_title']);
|
1226 |
-
endif;
|
1227 |
-
|
1228 |
-
$this->post['epoch']['issued'] = apply_filters('syndicated_item_published', $this->published(), $this);
|
1229 |
-
$this->post['epoch']['created'] = apply_filters('syndicated_item_created', $this->created(), $this);
|
1230 |
-
$this->post['epoch']['modified'] = apply_filters('syndicated_item_updated', $this->updated(), $this);
|
1231 |
-
|
1232 |
-
// Dealing with timestamps in WordPress is so fucking fucked.
|
1233 |
-
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
1234 |
-
$this->post['post_date'] = gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
1235 |
-
$this->post['post_modified'] = gmdate('Y-m-d H:i:s', $this->updated() + $offset);
|
1236 |
-
$this->post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $this->published());
|
1237 |
-
$this->post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $this->updated());
|
1238 |
-
|
1239 |
-
// Use feed-level preferences or the global default.
|
1240 |
-
$this->post['post_status'] = $this->link->syndicated_status('post', 'publish');
|
1241 |
-
$this->post['comment_status'] = $this->link->syndicated_status('comment', 'closed');
|
1242 |
-
$this->post['ping_status'] = $this->link->syndicated_status('ping', 'closed');
|
1243 |
-
|
1244 |
-
// Unique ID (hopefully a unique tag: URI); failing that, the permalink
|
1245 |
-
$this->post['guid'] = apply_filters('syndicated_item_guid', $this->guid(), $this);
|
1246 |
-
|
1247 |
-
// 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
|
1248 |
-
$default_custom_settings = get_option('feedwordpress_custom_settings');
|
1249 |
-
if ($default_custom_settings) :
|
1250 |
-
$default_custom_settings = unserialize($default_custom_settings);
|
1251 |
-
endif;
|
1252 |
-
if (!is_array($default_custom_settings)) :
|
1253 |
-
$default_custom_settings = array();
|
1254 |
-
endif;
|
1255 |
-
|
1256 |
-
$custom_settings = (isset($this->link->settings['postmeta']) ? $this->link->settings['postmeta'] : null);
|
1257 |
-
if ($custom_settings) :
|
1258 |
-
$custom_settings = unserialize($custom_settings);
|
1259 |
-
endif;
|
1260 |
-
if (!is_array($custom_settings)) :
|
1261 |
-
$custom_settings = array();
|
1262 |
-
endif;
|
1263 |
-
$this->post['meta'] = array_merge($default_custom_settings, $custom_settings);
|
1264 |
-
|
1265 |
-
// RSS 2.0 / Atom 1.0 enclosure support
|
1266 |
-
if ( isset($this->item['enclosure#']) ) :
|
1267 |
-
for ($i = 1; $i <= $this->item['enclosure#']; $i++) :
|
1268 |
-
$eid = (($i > 1) ? "#{$id}" : "");
|
1269 |
-
$this->post['meta']['enclosure'][] =
|
1270 |
-
apply_filters('syndicated_item_enclosure_url', $this->item["enclosure{$eid}@url"], $this)."\n".
|
1271 |
-
apply_filters('syndicated_item_enclosure_length', $this->item["enclosure{$eid}@length"], $this)."\n".
|
1272 |
-
apply_filters('syndicated_item_enclosure_type', $this->item["enclosure{$eid}@type"], $this);
|
1273 |
-
endfor;
|
1274 |
-
endif;
|
1275 |
-
|
1276 |
-
// In case you want to point back to the blog this was syndicated from
|
1277 |
-
if (isset($this->feed->channel['title'])) :
|
1278 |
-
$this->post['meta']['syndication_source'] = apply_filters('syndicated_item_source_title', $this->feed->channel['title'], $this);
|
1279 |
-
endif;
|
1280 |
-
|
1281 |
-
if (isset($this->feed->channel['link'])) :
|
1282 |
-
$this->post['meta']['syndication_source_uri'] = apply_filters('syndicated_item_source_link', $this->feed->channel['link'], $this);
|
1283 |
-
endif;
|
1284 |
-
|
1285 |
-
// Make use of atom:source data, if present in an aggregated feed
|
1286 |
-
if (isset($this->item['source_title'])) :
|
1287 |
-
$this->post['meta']['syndication_source_original'] = $this->item['source_title'];
|
1288 |
-
endif;
|
1289 |
-
|
1290 |
-
if (isset($this->item['source_link'])) :
|
1291 |
-
$this->post['meta']['syndication_source_uri_original'] = $this->item['source_link'];
|
1292 |
-
endif;
|
1293 |
-
|
1294 |
-
if (isset($this->item['source_id'])) :
|
1295 |
-
$this->post['meta']['syndication_source_id_original'] = $this->item['source_id'];
|
1296 |
-
endif;
|
1297 |
-
|
1298 |
-
// Store information on human-readable and machine-readable comment URIs
|
1299 |
-
if (isset($this->item['comments'])) :
|
1300 |
-
$this->post['meta']['rss:comments'] = apply_filters('syndicated_item_comments', $this->item['comments']);
|
1301 |
-
endif;
|
1302 |
-
if (isset($this->item['wfw']['commentrss'])) :
|
1303 |
-
$this->post['meta']['wfw:commentRSS'] = apply_filters('syndicated_item_commentrss', $this->item['wfw']['commentrss']);
|
1304 |
-
endif;
|
1305 |
-
|
1306 |
-
// Store information to identify the feed that this came from
|
1307 |
-
$this->post['meta']['syndication_feed'] = $this->feedmeta['link/uri'];
|
1308 |
-
$this->post['meta']['syndication_feed_id'] = $this->feedmeta['link/id'];
|
1309 |
-
|
1310 |
-
if (isset($this->item['source_link_self'])) :
|
1311 |
-
$this->post['meta']['syndication_feed_original'] = $this->item['source_link_self'];
|
1312 |
-
endif;
|
1313 |
-
|
1314 |
-
// In case you want to know the external permalink...
|
1315 |
-
$this->post['meta']['syndication_permalink'] = apply_filters('syndicated_item_link', $this->item['link']);
|
1316 |
-
|
1317 |
-
// Store a hash of the post content for checking whether something needs to be updated
|
1318 |
-
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
1319 |
-
|
1320 |
-
// Feed-by-feed options for author and category creation
|
1321 |
-
$this->post['named']['unfamiliar']['author'] = (isset($this->feedmeta['unfamiliar author']) ? $this->feedmeta['unfamiliar author'] : null);
|
1322 |
-
$this->post['named']['unfamiliar']['category'] = (isset($this->feedmeta['unfamiliar category']) ? $this->feedmeta['unfamiliar category'] : null);
|
1323 |
-
|
1324 |
-
// Categories: start with default categories, if any
|
1325 |
-
$fc = get_option("feedwordpress_syndication_cats");
|
1326 |
-
if ($fc) :
|
1327 |
-
$this->post['named']['preset/category'] = explode("\n", $fc);
|
1328 |
-
else :
|
1329 |
-
$this->post['named']['preset/category'] = array();
|
1330 |
-
endif;
|
1331 |
-
|
1332 |
-
if (isset($this->feedmeta['cats']) and is_array($this->feedmeta['cats'])) :
|
1333 |
-
$this->post['named']['preset/category'] = array_merge($this->post['named']['preset/category'], $this->feedmeta['cats']);
|
1334 |
-
endif;
|
1335 |
-
|
1336 |
-
// Now add categories from the post, if we have 'em
|
1337 |
-
$this->post['named']['category'] = array();
|
1338 |
-
if ( isset($this->item['category#']) ) :
|
1339 |
-
for ($i = 1; $i <= $this->item['category#']; $i++) :
|
1340 |
-
$cat_idx = (($i > 1) ? "#{$i}" : "");
|
1341 |
-
$cat = $this->item["category{$cat_idx}"];
|
1342 |
-
|
1343 |
-
if ( isset($this->feedmeta['cat_split']) and strlen($this->feedmeta['cat_split']) > 0) :
|
1344 |
-
$pcre = "\007".$this->feedmeta['cat_split']."\007";
|
1345 |
-
$this->post['named']['category'] = array_merge($this->post['named']['category'], preg_split($pcre, $cat, -1 /*=no limit*/, PREG_SPLIT_NO_EMPTY));
|
1346 |
-
else :
|
1347 |
-
$this->post['named']['category'][] = $cat;
|
1348 |
-
endif;
|
1349 |
-
endfor;
|
1350 |
-
endif;
|
1351 |
-
$this->post['named']['category'] = apply_filters('syndicated_item_categories', $this->post['named']['category'], $this);
|
1352 |
-
|
1353 |
-
// Tags: start with default tags, if any
|
1354 |
-
$ft = get_option("feedwordpress_syndication_tags");
|
1355 |
-
if ($ft) :
|
1356 |
-
$this->post['tags_input'] = explode(FEEDWORDPRESS_CAT_SEPARATOR, $ft);
|
1357 |
-
else :
|
1358 |
-
$this->post['tags_input'] = array();
|
1359 |
-
endif;
|
1360 |
-
|
1361 |
-
if (isset($this->feedmeta['tags']) and is_array($this->feedmeta['tags'])) :
|
1362 |
-
$this->post['tags_input'] = array_merge($this->post['tags_input'], $this->feedmeta['tags']);
|
1363 |
-
endif;
|
1364 |
-
|
1365 |
-
endif;
|
1366 |
-
} // SyndicatedPost::SyndicatedPost()
|
1367 |
-
|
1368 |
-
function filtered () {
|
1369 |
-
return is_null($this->post);
|
1370 |
-
}
|
1371 |
-
|
1372 |
-
function freshness () {
|
1373 |
-
global $wpdb;
|
1374 |
-
|
1375 |
-
if ($this->filtered()) : // This should never happen.
|
1376 |
-
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
1377 |
-
endif;
|
1378 |
-
|
1379 |
-
if (is_null($this->_freshness)) :
|
1380 |
-
$guid = $wpdb->escape($this->guid());
|
1381 |
-
|
1382 |
-
$result = $wpdb->get_row("
|
1383 |
-
SELECT id, guid, post_modified_gmt
|
1384 |
-
FROM $wpdb->posts WHERE guid='$guid'
|
1385 |
-
");
|
1386 |
-
|
1387 |
-
if (!$result) :
|
1388 |
-
$this->_freshness = 2; // New content
|
1389 |
-
else:
|
1390 |
-
$stored_update_hashes = get_post_custom_values('syndication_item_hash', $result->id);
|
1391 |
-
if (count($stored_update_hashes) > 0) :
|
1392 |
-
$stored_update_hash = $stored_update_hashes[0];
|
1393 |
-
$update_hash_changed = ($stored_update_hash != $this->update_hash());
|
1394 |
-
else :
|
1395 |
-
$update_hash_changed = false;
|
1396 |
-
endif;
|
1397 |
-
|
1398 |
-
preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $result->post_modified_gmt, $backref);
|
1399 |
-
|
1400 |
-
$last_rev_ts = gmmktime($backref[4], $backref[5], $backref[6], $backref[2], $backref[3], $backref[1]);
|
1401 |
-
$updated_ts = $this->updated(/*fallback=*/ true, /*default=*/ NULL);
|
1402 |
-
$updated = ((
|
1403 |
-
!is_null($updated_ts)
|
1404 |
-
and ($updated_ts > $last_rev_ts)
|
1405 |
-
) or $update_hash_changed);
|
1406 |
-
|
1407 |
-
if ($updated) :
|
1408 |
-
$this->_freshness = 1; // Updated content
|
1409 |
-
$this->_wp_id = $result->id;
|
1410 |
-
else :
|
1411 |
-
$this->_freshness = 0; // Same old, same old
|
1412 |
-
$this->_wp_id = $result->id;
|
1413 |
-
endif;
|
1414 |
-
endif;
|
1415 |
-
endif;
|
1416 |
-
return $this->_freshness;
|
1417 |
-
}
|
1418 |
-
|
1419 |
-
function wp_id () {
|
1420 |
-
if ($this->filtered()) : // This should never happen.
|
1421 |
-
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
1422 |
-
endif;
|
1423 |
-
|
1424 |
-
if (is_null($this->_wp_id) and is_null($this->_freshness)) :
|
1425 |
-
$fresh = $this->freshness(); // sets WP DB id in the process
|
1426 |
-
endif;
|
1427 |
-
return $this->_wp_id;
|
1428 |
-
}
|
1429 |
-
|
1430 |
-
function store () {
|
1431 |
-
global $wpdb;
|
1432 |
-
|
1433 |
-
if ($this->filtered()) : // This should never happen.
|
1434 |
-
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
1435 |
-
endif;
|
1436 |
-
|
1437 |
-
$freshness = $this->freshness();
|
1438 |
-
if ($freshness > 0) :
|
1439 |
-
# -- Look up, or create, numeric ID for author
|
1440 |
-
$this->post['post_author'] = $this->author_id (
|
1441 |
-
FeedWordPress::on_unfamiliar('author', $this->post['named']['unfamiliar']['author'])
|
1442 |
-
);
|
1443 |
-
|
1444 |
-
if (is_null($this->post['post_author'])) :
|
1445 |
-
$this->post = NULL;
|
1446 |
-
endif;
|
1447 |
-
endif;
|
1448 |
-
|
1449 |
-
if (!$this->filtered() and $freshness > 0) :
|
1450 |
-
# -- Look up, or create, numeric ID for categories
|
1451 |
-
list($pcats, $ptags) = $this->category_ids (
|
1452 |
-
$this->post['named']['category'],
|
1453 |
-
FeedWordPress::on_unfamiliar('category', $this->post['named']['unfamiliar']['category']),
|
1454 |
-
/*tags_too=*/ true
|
1455 |
-
);
|
1456 |
-
|
1457 |
-
$this->post['post_category'] = $pcats;
|
1458 |
-
$this->post['tags_input'] = array_merge($this->post['tags_input'], $ptags);
|
1459 |
-
|
1460 |
-
if (is_null($this->post['post_category'])) :
|
1461 |
-
// filter mode on, no matching categories; drop the post
|
1462 |
-
$this->post = NULL;
|
1463 |
-
else :
|
1464 |
-
// filter mode off or at least one match; now add on the feed and global presets
|
1465 |
-
$this->post['post_category'] = array_merge (
|
1466 |
-
$this->post['post_category'],
|
1467 |
-
$this->category_ids (
|
1468 |
-
$this->post['named']['preset/category'],
|
1469 |
-
'default'
|
1470 |
-
)
|
1471 |
-
);
|
1472 |
-
|
1473 |
-
if (count($this->post['post_category']) < 1) :
|
1474 |
-
$this->post['post_category'][] = 1; // Default to category 1 ("Uncategorized" / "General") if nothing else
|
1475 |
-
endif;
|
1476 |
-
endif;
|
1477 |
-
endif;
|
1478 |
-
|
1479 |
-
if (!$this->filtered() and $freshness > 0) :
|
1480 |
-
unset($this->post['named']);
|
1481 |
-
$this->post = apply_filters('syndicated_post', $this->post, $this);
|
1482 |
-
endif;
|
1483 |
-
|
1484 |
-
if (!$this->filtered() and $freshness == 2) :
|
1485 |
-
// The item has not yet been added. So let's add it.
|
1486 |
-
$this->insert_new();
|
1487 |
-
$this->add_rss_meta();
|
1488 |
-
do_action('post_syndicated_item', $this->wp_id());
|
1489 |
-
|
1490 |
-
$ret = 'new';
|
1491 |
-
elseif (!$this->filtered() and $freshness == 1) :
|
1492 |
-
$this->post['ID'] = $this->wp_id();
|
1493 |
-
$this->update_existing();
|
1494 |
-
$this->add_rss_meta();
|
1495 |
-
do_action('update_syndicated_item', $this->wp_id());
|
1496 |
-
|
1497 |
-
$ret = 'updated';
|
1498 |
-
else :
|
1499 |
-
$ret = false;
|
1500 |
-
endif;
|
1501 |
-
|
1502 |
-
return $ret;
|
1503 |
-
} // function SyndicatedPost::store ()
|
1504 |
-
|
1505 |
-
function insert_new () {
|
1506 |
-
global $wpdb, $wp_db_version;
|
1507 |
-
|
1508 |
-
$dbpost = $this->normalize_post(/*new=*/ true);
|
1509 |
-
if (!is_null($dbpost)) :
|
1510 |
-
if ($this->use_api('wp_insert_post')) :
|
1511 |
-
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
1512 |
-
|
1513 |
-
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
1514 |
-
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1515 |
-
|
1516 |
-
// Kludge to prevent kses filters from stripping the
|
1517 |
-
// content of posts when updating without a logged in
|
1518 |
-
// user who has `unfiltered_html` capability.
|
1519 |
-
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1520 |
-
|
1521 |
-
$this->_wp_id = wp_insert_post($dbpost);
|
1522 |
-
|
1523 |
-
// Turn off ridiculous fucking kludges #1 and #2
|
1524 |
-
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1525 |
-
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1526 |
-
|
1527 |
-
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1528 |
-
|
1529 |
-
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
1530 |
-
// *still* offers no way to use a guid of your choice,
|
1531 |
-
// and munges your post modified timestamp, too.
|
1532 |
-
$result = $wpdb->query("
|
1533 |
-
UPDATE $wpdb->posts
|
1534 |
-
SET
|
1535 |
-
guid='{$dbpost['guid']}',
|
1536 |
-
post_modified='{$dbpost['post_modified']}',
|
1537 |
-
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
1538 |
-
WHERE ID='{$this->_wp_id}'
|
1539 |
-
");
|
1540 |
-
else :
|
1541 |
-
# The right way to do this is the above. But, alas,
|
1542 |
-
# in earlier versions of WordPress, wp_insert_post has
|
1543 |
-
# too much behavior (mainly related to pings) that can't
|
1544 |
-
# be overridden. In WordPress 1.5, it's enough of a
|
1545 |
-
# resource hog to make PHP segfault after inserting
|
1546 |
-
# 50-100 posts. This can get pretty annoying, especially
|
1547 |
-
# if you are trying to update your feeds for the first
|
1548 |
-
# time.
|
1549 |
-
|
1550 |
-
$result = $wpdb->query("
|
1551 |
-
INSERT INTO $wpdb->posts
|
1552 |
-
SET
|
1553 |
-
guid = '{$dbpost['guid']}',
|
1554 |
-
post_author = '{$dbpost['post_author']}',
|
1555 |
-
post_date = '{$dbpost['post_date']}',
|
1556 |
-
post_date_gmt = '{$dbpost['post_date_gmt']}',
|
1557 |
-
post_content = '{$dbpost['post_content']}',"
|
1558 |
-
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
1559 |
-
post_title = '{$dbpost['post_title']}',
|
1560 |
-
post_name = '{$dbpost['post_name']}',
|
1561 |
-
post_modified = '{$dbpost['post_modified']}',
|
1562 |
-
post_modified_gmt = '{$dbpost['post_modified_gmt']}',
|
1563 |
-
comment_status = '{$dbpost['comment_status']}',
|
1564 |
-
ping_status = '{$dbpost['ping_status']}',
|
1565 |
-
post_status = '{$dbpost['post_status']}'
|
1566 |
-
");
|
1567 |
-
$this->_wp_id = $wpdb->insert_id;
|
1568 |
-
|
1569 |
-
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1570 |
-
|
1571 |
-
// WordPress 1.5.x - 2.0.x
|
1572 |
-
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
1573 |
-
|
1574 |
-
// Since we are not going through official channels, we need to
|
1575 |
-
// manually tell WordPress that we've published a new post.
|
1576 |
-
// We need to make sure to do this in order for FeedWordPress
|
1577 |
-
// to play well with the staticize-reloaded plugin (something
|
1578 |
-
// that a large aggregator website is going to *want* to be
|
1579 |
-
// able to use).
|
1580 |
-
do_action('publish_post', $this->_wp_id);
|
1581 |
-
endif;
|
1582 |
-
endif;
|
1583 |
-
} /* SyndicatedPost::insert_new() */
|
1584 |
-
|
1585 |
-
function update_existing () {
|
1586 |
-
global $wpdb;
|
1587 |
-
|
1588 |
-
// Why the fuck doesn't wp_insert_post already do this?
|
1589 |
-
$dbpost = $this->normalize_post(/*new=*/ false);
|
1590 |
-
if (!is_null($dbpost)) :
|
1591 |
-
if ($this->use_api('wp_insert_post')) :
|
1592 |
-
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
1593 |
-
|
1594 |
-
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
1595 |
-
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1596 |
-
|
1597 |
-
// Kludge to prevent kses filters from stripping the
|
1598 |
-
// content of posts when updating without a logged in
|
1599 |
-
// user who has `unfiltered_html` capability.
|
1600 |
-
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1601 |
-
|
1602 |
-
// Don't munge status fields that the user may have reset manually
|
1603 |
-
if (function_exists('get_post_field')) :
|
1604 |
-
$doNotMunge = array('post_status', 'comment_status', 'ping_status');
|
1605 |
-
foreach ($doNotMunge as $field) :
|
1606 |
-
$dbpost[$field] = get_post_field($field, $this->wp_id());
|
1607 |
-
endforeach;
|
1608 |
-
endif;
|
1609 |
-
|
1610 |
-
$this->_wp_id = wp_insert_post($dbpost);
|
1611 |
-
|
1612 |
-
// Turn off ridiculous fucking kludges #1 and #2
|
1613 |
-
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
1614 |
-
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
1615 |
-
|
1616 |
-
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
1617 |
-
|
1618 |
-
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
1619 |
-
// munges your post modified timestamp.
|
1620 |
-
$result = $wpdb->query("
|
1621 |
-
UPDATE $wpdb->posts
|
1622 |
-
SET
|
1623 |
-
post_modified='{$dbpost['post_modified']}',
|
1624 |
-
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
1625 |
-
WHERE ID='{$this->_wp_id}'
|
1626 |
-
");
|
1627 |
-
else :
|
1628 |
-
|
1629 |
-
$result = $wpdb->query("
|
1630 |
-
UPDATE $wpdb->posts
|
1631 |
-
SET
|
1632 |
-
post_author = '{$dbpost['post_author']}',
|
1633 |
-
post_content = '{$dbpost['post_content']}',"
|
1634 |
-
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
1635 |
-
post_title = '{$dbpost['post_title']}',
|
1636 |
-
post_name = '{$dbpost['post_name']}',
|
1637 |
-
post_modified = '{$dbpost['post_modified']}',
|
1638 |
-
post_modified_gmt = '{$dbpost['post_modified_gmt']}'
|
1639 |
-
WHERE guid='{$dbpost['guid']}'
|
1640 |
-
");
|
1641 |
-
|
1642 |
-
// WordPress 2.1.x and up
|
1643 |
-
if (function_exists('wp_set_post_categories')) :
|
1644 |
-
wp_set_post_categories($this->wp_id(), $this->post['post_category']);
|
1645 |
-
// WordPress 1.5.x - 2.0.x
|
1646 |
-
elseif (function_exists('wp_set_post_cats')) :
|
1647 |
-
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
1648 |
-
// This should never happen.
|
1649 |
-
else :
|
1650 |
-
FeedWordPress::critical_bug(__CLASS__.'::'.__FUNCTION.'(): no post categorizing function', array("dbpost" => $dbpost, "this" => $this), __LINE__);
|
1651 |
-
endif;
|
1652 |
-
|
1653 |
-
// Since we are not going through official channels, we need to
|
1654 |
-
// manually tell WordPress that we've published a new post.
|
1655 |
-
// We need to make sure to do this in order for FeedWordPress
|
1656 |
-
// to play well with the staticize-reloaded plugin (something
|
1657 |
-
// that a large aggregator website is going to *want* to be
|
1658 |
-
// able to use).
|
1659 |
-
do_action('edit_post', $this->post['ID']);
|
1660 |
-
endif;
|
1661 |
-
endif;
|
1662 |
-
} /* SyndicatedPost::update_existing() */
|
1663 |
-
|
1664 |
-
/**
|
1665 |
-
* SyndicatedPost::normalize_post()
|
1666 |
-
*
|
1667 |
-
* @param bool $new If true, this post is to be inserted anew. If false, it is an update of an existing post.
|
1668 |
-
* @return array A normalized representation of the post ready to be inserted into the database or sent to the WordPress API functions
|
1669 |
-
*/
|
1670 |
-
function normalize_post ($new = true) {
|
1671 |
-
global $wpdb;
|
1672 |
-
|
1673 |
-
$out = array();
|
1674 |
-
|
1675 |
-
// Why the fuck doesn't wp_insert_post already do this?
|
1676 |
-
foreach ($this->post as $key => $value) :
|
1677 |
-
if (is_string($value)) :
|
1678 |
-
$out[$key] = $wpdb->escape($value);
|
1679 |
-
else :
|
1680 |
-
$out[$key] = $value;
|
1681 |
-
endif;
|
1682 |
-
endforeach;
|
1683 |
-
|
1684 |
-
if (strlen($out['post_title'].$out['post_content'].$out['post_excerpt']) == 0) :
|
1685 |
-
// FIXME: Option for filtering out empty posts
|
1686 |
-
endif;
|
1687 |
-
if (strlen($out['post_title'])==0) :
|
1688 |
-
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
1689 |
-
$out['post_title'] =
|
1690 |
-
$this->post['meta']['syndication_source']
|
1691 |
-
.' '.gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
1692 |
-
// FIXME: Option for what to fill a blank title with...
|
1693 |
-
endif;
|
1694 |
-
|
1695 |
-
return $out;
|
1696 |
-
}
|
1697 |
-
|
1698 |
-
/**
|
1699 |
-
* SyndicatedPost::validate_post_id()
|
1700 |
-
*
|
1701 |
-
* @param array $dbpost An array representing the post we attempted to insert or update
|
1702 |
-
* @param mixed $ns A string or array representing the namespace (class, method) whence this method was called.
|
1703 |
-
*/
|
1704 |
-
function validate_post_id ($dbpost, $ns) {
|
1705 |
-
if (is_array($ns)) : $ns = implode('::', $ns);
|
1706 |
-
else : $ns = (string) $ns; endif;
|
1707 |
-
|
1708 |
-
// This should never happen.
|
1709 |
-
if (!is_numeric($this->_wp_id) or ($this->_wp_id == 0)) :
|
1710 |
-
FeedWordPress::critical_bug(
|
1711 |
-
/*name=*/ $ns.'::_wp_id',
|
1712 |
-
/*var =*/ array(
|
1713 |
-
"\$this->_wp_id" => $this->_wp_id,
|
1714 |
-
"\$dbpost" => $dbpost,
|
1715 |
-
"\$this" => $this
|
1716 |
-
),
|
1717 |
-
/*line # =*/ __LINE__
|
1718 |
-
);
|
1719 |
-
endif;
|
1720 |
-
} /* SyndicatedPost::validate_post_id() */
|
1721 |
-
|
1722 |
-
/**
|
1723 |
-
* SyndicatedPost::fix_revision_meta() - Fixes the way WP 2.6+ fucks up
|
1724 |
-
* meta-data (authorship, etc.) when storing revisions of an updated
|
1725 |
-
* syndicated post.
|
1726 |
-
*
|
1727 |
-
* In their infinite wisdom, the WordPress coders have made it completely
|
1728 |
-
* impossible for a plugin that uses wp_insert_post() to set certain
|
1729 |
-
* meta-data (such as the author) when you store an old revision of an
|
1730 |
-
* updated post. Instead, it uses the WordPress defaults (= currently
|
1731 |
-
* active user ID if the process is running with a user logged in, or
|
1732 |
-
* = #0 if there is no user logged in). This results in bogus authorship
|
1733 |
-
* data for revisions that are syndicated from off the feed, unless we
|
1734 |
-
* use a ridiculous kludge like this to end-run the munging of meta-data
|
1735 |
-
* by _wp_put_post_revision.
|
1736 |
-
*
|
1737 |
-
* @param int $revision_id The revision ID to fix up meta-data
|
1738 |
-
*/
|
1739 |
-
function fix_revision_meta ($revision_id) {
|
1740 |
-
global $wpdb;
|
1741 |
-
|
1742 |
-
$post_author = (int) $this->post['post_author'];
|
1743 |
-
|
1744 |
-
$revision_id = (int) $revision_id;
|
1745 |
-
$wpdb->query("
|
1746 |
-
UPDATE $wpdb->posts
|
1747 |
-
SET post_author={$this->post['post_author']}
|
1748 |
-
WHERE post_type = 'revision' AND ID='$revision_id'
|
1749 |
-
");
|
1750 |
-
} /* SyndicatedPost::fix_revision_meta () */
|
1751 |
-
|
1752 |
-
/**
|
1753 |
-
* SyndicatedPost::avoid_kses_munge() -- If FeedWordPress is processing
|
1754 |
-
* an automatic update, that generally means that wp_insert_post() is
|
1755 |
-
* being called under the user credentials of whoever is viewing the
|
1756 |
-
* blog at the time -- usually meaning no user at all. But if WordPress
|
1757 |
-
* gets a wp_insert_post() when current_user_can('unfiltered_html') is
|
1758 |
-
* false, it will run the content of the post through a kses function
|
1759 |
-
* that strips out lots of HTML tags -- notably <object> and some others.
|
1760 |
-
* This causes problems for syndicating (for example) feeds that contain
|
1761 |
-
* YouTube videos. It also produces an unexpected asymmetry between
|
1762 |
-
* automatically-initiated updates and updates initiated manually from
|
1763 |
-
* the WordPress Dashboard (which are usually initiated under the
|
1764 |
-
* credentials of a logged-in admin, and so don't get run through the
|
1765 |
-
* kses function). So, to avoid the whole mess, what we do here is
|
1766 |
-
* just forcibly disable the kses munging for a single syndicated post,
|
1767 |
-
* by restoring the contents of the `post_content` field.
|
1768 |
-
*
|
1769 |
-
* @param string $content The content of the post, after other filters have gotten to it
|
1770 |
-
* @return string The original content of the post, before other filters had a chance to munge it.
|
1771 |
-
*/
|
1772 |
-
function avoid_kses_munge ($content) {
|
1773 |
-
global $wpdb;
|
1774 |
-
return $wpdb->escape($this->post['post_content']);
|
1775 |
-
}
|
1776 |
-
|
1777 |
-
// SyndicatedPost::add_rss_meta: adds interesting meta-data to each entry
|
1778 |
-
// using the space for custom keys. The set of keys and values to add is
|
1779 |
-
// specified by the keys and values of $post['meta']. This is used to
|
1780 |
-
// store anything that the WordPress user might want to access from a
|
1781 |
-
// template concerning the post's original source that isn't provided
|
1782 |
-
// for by standard WP meta-data (i.e., any interesting data about the
|
1783 |
-
// syndicated post other than author, title, timestamp, categories, and
|
1784 |
-
// guid). It's also used to hook into WordPress's support for
|
1785 |
-
// enclosures.
|
1786 |
-
function add_rss_meta () {
|
1787 |
-
global $wpdb;
|
1788 |
-
if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
|
1789 |
-
$postId = $this->wp_id();
|
1790 |
-
|
1791 |
-
// Aggregated posts should NOT send out pingbacks.
|
1792 |
-
// WordPress 2.1-2.2 claim you can tell them not to
|
1793 |
-
// using $post_pingback, but they don't listen, so we
|
1794 |
-
// make sure here.
|
1795 |
-
$result = $wpdb->query("
|
1796 |
-
DELETE FROM $wpdb->postmeta
|
1797 |
-
WHERE post_id='$postId' AND meta_key='_pingme'
|
1798 |
-
");
|
1799 |
-
|
1800 |
-
foreach ( $this->post['meta'] as $key => $values ) :
|
1801 |
-
|
1802 |
-
$key = $wpdb->escape($key);
|
1803 |
-
|
1804 |
-
// If this is an update, clear out the old
|
1805 |
-
// values to avoid duplication.
|
1806 |
-
$result = $wpdb->query("
|
1807 |
-
DELETE FROM $wpdb->postmeta
|
1808 |
-
WHERE post_id='$postId' AND meta_key='$key'
|
1809 |
-
");
|
1810 |
-
|
1811 |
-
// Allow for either a single value or an array
|
1812 |
-
if (!is_array($values)) $values = array($values);
|
1813 |
-
foreach ( $values as $value ) :
|
1814 |
-
$value = $wpdb->escape($value);
|
1815 |
-
$result = $wpdb->query("
|
1816 |
-
INSERT INTO $wpdb->postmeta
|
1817 |
-
SET
|
1818 |
-
post_id='$postId',
|
1819 |
-
meta_key='$key',
|
1820 |
-
meta_value='$value'
|
1821 |
-
");
|
1822 |
-
endforeach;
|
1823 |
-
endforeach;
|
1824 |
-
endif;
|
1825 |
-
} /* SyndicatedPost::add_rss_meta () */
|
1826 |
-
|
1827 |
-
// SyndicatedPost::author_id (): get the ID for an author name from
|
1828 |
-
// the feed. Create the author if necessary.
|
1829 |
-
function author_id ($unfamiliar_author = 'create') {
|
1830 |
-
global $wpdb;
|
1831 |
-
|
1832 |
-
$a = $this->author();
|
1833 |
-
$author = $a['name'];
|
1834 |
-
$email = $a['email'];
|
1835 |
-
$url = $a['uri'];
|
1836 |
-
|
1837 |
-
$match_author_by_email = !('yes' == get_option("feedwordpress_do_not_match_author_by_email"));
|
1838 |
-
if ($match_author_by_email and !FeedWordPress::is_null_email($email)) :
|
1839 |
-
$test_email = $email;
|
1840 |
-
else :
|
1841 |
-
$test_email = NULL;
|
1842 |
-
endif;
|
1843 |
-
|
1844 |
-
// Never can be too careful...
|
1845 |
-
$login = sanitize_user($author, /*strict=*/ true);
|
1846 |
-
$login = apply_filters('pre_user_login', $login);
|
1847 |
-
|
1848 |
-
$nice_author = sanitize_title($author);
|
1849 |
-
$nice_author = apply_filters('pre_user_nicename', $nice_author);
|
1850 |
-
|
1851 |
-
$reg_author = $wpdb->escape(preg_quote($author));
|
1852 |
-
$author = $wpdb->escape($author);
|
1853 |
-
$email = $wpdb->escape($email);
|
1854 |
-
$test_email = $wpdb->escape($test_email);
|
1855 |
-
$url = $wpdb->escape($url);
|
1856 |
-
|
1857 |
-
// Check for an existing author rule....
|
1858 |
-
if (isset($this->link->settings['map authors']['name'][strtolower(trim($author))])) :
|
1859 |
-
$author_rule = $this->link->settings['map authors']['name'][strtolower(trim($author))];
|
1860 |
-
else :
|
1861 |
-
$author_rule = NULL;
|
1862 |
-
endif;
|
1863 |
-
|
1864 |
-
// User name is mapped to a particular author. If that author ID exists, use it.
|
1865 |
-
if (is_numeric($author_rule) and get_userdata((int) $author_rule)) :
|
1866 |
-
$id = (int) $author_rule;
|
1867 |
-
|
1868 |
-
// User name is filtered out
|
1869 |
-
elseif ('filter' == $author_rule) :
|
1870 |
-
$id = NULL;
|
1871 |
-
|
1872 |
-
else :
|
1873 |
-
// Check the database for an existing author record that might fit
|
1874 |
-
|
1875 |
-
#-- WordPress 2.0+
|
1876 |
-
if (fwp_test_wp_version(FWP_SCHEMA_HAS_USERMETA)) :
|
1877 |
-
|
1878 |
-
// First try the user core data table.
|
1879 |
-
$id = $wpdb->get_var(
|
1880 |
-
"SELECT ID FROM $wpdb->users
|
1881 |
-
WHERE
|
1882 |
-
TRIM(LCASE(user_login)) = TRIM(LCASE('$login'))
|
1883 |
-
OR (
|
1884 |
-
LENGTH(TRIM(LCASE(user_email))) > 0
|
1885 |
-
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
1886 |
-
)
|
1887 |
-
OR TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author'))
|
1888 |
-
");
|
1889 |
-
|
1890 |
-
// If that fails, look for aliases in the user meta data table
|
1891 |
-
if (is_null($id)) :
|
1892 |
-
$id = $wpdb->get_var(
|
1893 |
-
"SELECT user_id FROM $wpdb->usermeta
|
1894 |
-
WHERE
|
1895 |
-
(meta_key = 'description' AND TRIM(LCASE(meta_value)) = TRIM(LCASE('$author')))
|
1896 |
-
OR (
|
1897 |
-
meta_key = 'description'
|
1898 |
-
AND TRIM(LCASE(meta_value))
|
1899 |
-
RLIKE CONCAT(
|
1900 |
-
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
1901 |
-
TRIM(LCASE('$reg_author')),
|
1902 |
-
'( |\\t|\\r)*(\\n|\$)'
|
1903 |
-
)
|
1904 |
-
)
|
1905 |
-
");
|
1906 |
-
endif;
|
1907 |
-
|
1908 |
-
#-- WordPress 1.5.x
|
1909 |
-
else :
|
1910 |
-
$id = $wpdb->get_var(
|
1911 |
-
"SELECT ID from $wpdb->users
|
1912 |
-
WHERE
|
1913 |
-
TRIM(LCASE(user_login)) = TRIM(LCASE('$login')) OR
|
1914 |
-
(
|
1915 |
-
LENGTH(TRIM(LCASE(user_email))) > 0
|
1916 |
-
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
1917 |
-
) OR
|
1918 |
-
TRIM(LCASE(user_firstname)) = TRIM(LCASE('$author')) OR
|
1919 |
-
TRIM(LCASE(user_nickname)) = TRIM(LCASE('$author')) OR
|
1920 |
-
TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author')) OR
|
1921 |
-
TRIM(LCASE(user_description)) = TRIM(LCASE('$author')) OR
|
1922 |
-
(
|
1923 |
-
LOWER(user_description)
|
1924 |
-
RLIKE CONCAT(
|
1925 |
-
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
1926 |
-
LCASE('$reg_author'),
|
1927 |
-
'( |\\t|\\r)*(\\n|\$)'
|
1928 |
-
)
|
1929 |
-
)
|
1930 |
-
");
|
1931 |
-
|
1932 |
-
endif;
|
1933 |
-
|
1934 |
-
// ... if you don't find one, then do what you need to do
|
1935 |
-
if (is_null($id)) :
|
1936 |
-
if ($unfamiliar_author === 'create') :
|
1937 |
-
$userdata = array();
|
1938 |
-
|
1939 |
-
#-- user table data
|
1940 |
-
$userdata['ID'] = NULL; // new user
|
1941 |
-
$userdata['user_login'] = $login;
|
1942 |
-
$userdata['user_nicename'] = $nice_author;
|
1943 |
-
$userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up
|
1944 |
-
$userdata['user_email'] = $email;
|
1945 |
-
$userdata['user_url'] = $url;
|
1946 |
-
$userdata['display_name'] = $author;
|
1947 |
-
|
1948 |
-
$id = wp_insert_user($userdata);
|
1949 |
-
elseif (is_numeric($unfamiliar_author) and get_userdata((int) $unfamiliar_author)) :
|
1950 |
-
$id = (int) $unfamiliar_author;
|
1951 |
-
elseif ($unfamiliar_author === 'default') :
|
1952 |
-
$id = 1;
|
1953 |
-
endif;
|
1954 |
-
endif;
|
1955 |
-
endif;
|
1956 |
-
|
1957 |
-
if ($id) :
|
1958 |
-
$this->link->settings['map authors']['name'][strtolower(trim($author))] = $id;
|
1959 |
-
endif;
|
1960 |
-
return $id;
|
1961 |
-
} // function SyndicatedPost::author_id ()
|
1962 |
-
|
1963 |
-
// look up (and create) category ids from a list of categories
|
1964 |
-
function category_ids ($cats, $unfamiliar_category = 'create', $tags_too = false) {
|
1965 |
-
global $wpdb;
|
1966 |
-
|
1967 |
-
// We need to normalize whitespace because (1) trailing
|
1968 |
-
// whitespace can cause PHP and MySQL not to see eye to eye on
|
1969 |
-
// VARCHAR comparisons for some versions of MySQL (cf.
|
1970 |
-
// <http://dev.mysql.com/doc/mysql/en/char.html>), and (2)
|
1971 |
-
// because I doubt most people want to make a semantic
|
1972 |
-
// distinction between 'Computers' and 'Computers '
|
1973 |
-
$cats = array_map('trim', $cats);
|
1974 |
-
|
1975 |
-
$tags = array();
|
1976 |
-
|
1977 |
-
$cat_ids = array ();
|
1978 |
-
foreach ($cats as $cat_name) :
|
1979 |
-
if (preg_match('/^{#([0-9]+)}$/', $cat_name, $backref)) :
|
1980 |
-
$cat_id = (int) $backref[1];
|
1981 |
-
if (function_exists('is_term') and is_term($cat_id, 'category')) :
|
1982 |
-
$cat_ids[] = $cat_id;
|
1983 |
-
elseif (get_category($cat_id)) :
|
1984 |
-
$cat_ids[] = $cat_id;
|
1985 |
-
endif;
|
1986 |
-
elseif (strlen($cat_name) > 0) :
|
1987 |
-
$esc = $wpdb->escape($cat_name);
|
1988 |
-
$resc = $wpdb->escape(preg_quote($cat_name));
|
1989 |
-
|
1990 |
-
// WordPress 2.3+
|
1991 |
-
if (function_exists('is_term')) :
|
1992 |
-
$cat_id = is_term($cat_name, 'category');
|
1993 |
-
if ($cat_id) :
|
1994 |
-
$cat_ids[] = $cat_id['term_id'];
|
1995 |
-
// There must be a better way to do this...
|
1996 |
-
elseif ($results = $wpdb->get_results(
|
1997 |
-
"SELECT term_id
|
1998 |
-
FROM $wpdb->term_taxonomy
|
1999 |
-
WHERE
|
2000 |
-
LOWER(description) RLIKE
|
2001 |
-
CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)')"
|
2002 |
-
)) :
|
2003 |
-
foreach ($results AS $term) :
|
2004 |
-
$cat_ids[] = (int) $term->term_id;
|
2005 |
-
endforeach;
|
2006 |
-
elseif ('tag'==$unfamiliar_category) :
|
2007 |
-
$tags[] = $cat_name;
|
2008 |
-
elseif ('create'===$unfamiliar_category) :
|
2009 |
-
$term = wp_insert_term($cat_name, 'category');
|
2010 |
-
if (is_wp_error($term)) :
|
2011 |
-
FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__);
|
2012 |
-
else :
|
2013 |
-
$cat_ids[] = $term['term_id'];
|
2014 |
-
endif;
|
2015 |
-
endif;
|
2016 |
-
|
2017 |
-
// WordPress 1.5.x - 2.2.x
|
2018 |
-
else :
|
2019 |
-
$results = $wpdb->get_results(
|
2020 |
-
"SELECT cat_ID
|
2021 |
-
FROM $wpdb->categories
|
2022 |
-
WHERE
|
2023 |
-
(LOWER(cat_name) = LOWER('$esc'))
|
2024 |
-
OR (LOWER(category_description)
|
2025 |
-
RLIKE CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)'))
|
2026 |
-
");
|
2027 |
-
if ($results) :
|
2028 |
-
foreach ($results as $term) :
|
2029 |
-
$cat_ids[] = (int) $term->cat_ID;
|
2030 |
-
endforeach;
|
2031 |
-
elseif ('create'===$unfamiliar_category) :
|
2032 |
-
if (function_exists('wp_insert_category')) :
|
2033 |
-
$cat_id = wp_insert_category(array('cat_name' => $cat_name));
|
2034 |
-
// And into the database we go.
|
2035 |
-
else :
|
2036 |
-
$nice_kitty = sanitize_title($cat_name);
|
2037 |
-
$wpdb->query(sprintf("
|
2038 |
-
INSERT INTO $wpdb->categories
|
2039 |
-
SET
|
2040 |
-
cat_name='%s',
|
2041 |
-
category_nicename='%s'
|
2042 |
-
", $wpdb->escape($cat_name), $nice_kitty
|
2043 |
-
));
|
2044 |
-
$cat_id = $wpdb->insert_id;
|
2045 |
-
endif;
|
2046 |
-
$cat_ids[] = $cat_id;
|
2047 |
-
endif;
|
2048 |
-
endif;
|
2049 |
-
endif;
|
2050 |
-
endforeach;
|
2051 |
-
|
2052 |
-
if ((count($cat_ids) == 0) and ($unfamiliar_category === 'filter')) :
|
2053 |
-
$cat_ids = NULL; // Drop the post
|
2054 |
-
else :
|
2055 |
-
$cat_ids = array_unique($cat_ids);
|
2056 |
-
endif;
|
2057 |
-
|
2058 |
-
if ($tags_too) : $ret = array($cat_ids, $tags);
|
2059 |
-
else : $ret = $cat_ids;
|
2060 |
-
endif;
|
2061 |
-
|
2062 |
-
return $ret;
|
2063 |
-
} // function SyndicatedPost::category_ids ()
|
2064 |
-
|
2065 |
-
function use_api ($tag) {
|
2066 |
-
global $wp_db_version;
|
2067 |
-
switch ($tag) :
|
2068 |
-
case 'wp_insert_post':
|
2069 |
-
// Before 2.2, wp_insert_post does too much of the wrong stuff to use it
|
2070 |
-
// In 1.5 it was such a resource hog it would make PHP segfault on big updates
|
2071 |
-
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_21);
|
2072 |
-
break;
|
2073 |
-
case 'post_status_pending':
|
2074 |
-
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_23);
|
2075 |
-
break;
|
2076 |
-
endswitch;
|
2077 |
-
return $ret;
|
2078 |
-
} // function SyndicatedPost::use_api ()
|
2079 |
-
|
2080 |
-
#### EXTRACT DATA FROM FEED ITEM ####
|
2081 |
-
|
2082 |
-
function created () {
|
2083 |
-
$epoch = null;
|
2084 |
-
if (isset($this->item['dc']['created'])) :
|
2085 |
-
$epoch = @parse_w3cdtf($this->item['dc']['created']);
|
2086 |
-
elseif (isset($this->item['dcterms']['created'])) :
|
2087 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['created']);
|
2088 |
-
elseif (isset($this->item['created'])): // Atom 0.3
|
2089 |
-
$epoch = @parse_w3cdtf($this->item['created']);
|
2090 |
-
endif;
|
2091 |
-
return $epoch;
|
2092 |
-
}
|
2093 |
-
function published ($fallback = true) {
|
2094 |
-
$epoch = null;
|
2095 |
-
|
2096 |
-
# RSS is a fucking mess. Figure out whether we have a date in
|
2097 |
-
# <dc:date>, <issued>, <pubDate>, etc., and get it into Unix
|
2098 |
-
# epoch format for reformatting. If we can't find anything,
|
2099 |
-
# we'll use the last-updated time.
|
2100 |
-
if (isset($this->item['dc']['date'])): // Dublin Core
|
2101 |
-
$epoch = @parse_w3cdtf($this->item['dc']['date']);
|
2102 |
-
elseif (isset($this->item['dcterms']['issued'])) : // Dublin Core extensions
|
2103 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['issued']);
|
2104 |
-
elseif (isset($this->item['published'])) : // Atom 1.0
|
2105 |
-
$epoch = @parse_w3cdtf($this->item['published']);
|
2106 |
-
elseif (isset($this->item['issued'])): // Atom 0.3
|
2107 |
-
$epoch = @parse_w3cdtf($this->item['issued']);
|
2108 |
-
elseif (isset($this->item['pubdate'])): // RSS 2.0
|
2109 |
-
$epoch = strtotime($this->item['pubdate']);
|
2110 |
-
elseif ($fallback) : // Fall back to <updated> / <modified> if present
|
2111 |
-
$epoch = $this->updated(/*fallback=*/ false);
|
2112 |
-
endif;
|
2113 |
-
|
2114 |
-
# If everything failed, then default to the current time.
|
2115 |
-
if (is_null($epoch)) :
|
2116 |
-
if (-1 == $default) :
|
2117 |
-
$epoch = time();
|
2118 |
-
else :
|
2119 |
-
$epoch = $default;
|
2120 |
-
endif;
|
2121 |
-
endif;
|
2122 |
-
|
2123 |
-
return $epoch;
|
2124 |
-
}
|
2125 |
-
function updated ($fallback = true, $default = -1) {
|
2126 |
-
$epoch = null;
|
2127 |
-
|
2128 |
-
# As far as I know, only dcterms and Atom have reliable ways to
|
2129 |
-
# specify when something was *modified* last. If neither is
|
2130 |
-
# available, then we'll try to get the time of publication.
|
2131 |
-
if (isset($this->item['dc']['modified'])) : // Not really correct
|
2132 |
-
$epoch = @parse_w3cdtf($this->item['dc']['modified']);
|
2133 |
-
elseif (isset($this->item['dcterms']['modified'])) : // Dublin Core extensions
|
2134 |
-
$epoch = @parse_w3cdtf($this->item['dcterms']['modified']);
|
2135 |
-
elseif (isset($this->item['modified'])): // Atom 0.3
|
2136 |
-
$epoch = @parse_w3cdtf($this->item['modified']);
|
2137 |
-
elseif (isset($this->item['updated'])): // Atom 1.0
|
2138 |
-
$epoch = @parse_w3cdtf($this->item['updated']);
|
2139 |
-
elseif ($fallback) : // Fall back to issued / dc:date
|
2140 |
-
$epoch = $this->published(/*fallback=*/ false, /*default=*/ $default);
|
2141 |
-
endif;
|
2142 |
-
|
2143 |
-
# If everything failed, then default to the current time.
|
2144 |
-
if (is_null($epoch)) :
|
2145 |
-
if (-1 == $default) :
|
2146 |
-
$epoch = time();
|
2147 |
-
else :
|
2148 |
-
$epoch = $default;
|
2149 |
-
endif;
|
2150 |
-
endif;
|
2151 |
-
|
2152 |
-
return $epoch;
|
2153 |
-
}
|
2154 |
-
|
2155 |
-
function update_hash () {
|
2156 |
-
return md5(serialize($this->item));
|
2157 |
-
}
|
2158 |
-
|
2159 |
-
function guid () {
|
2160 |
-
$guid = null;
|
2161 |
-
if (isset($this->item['id'])): // Atom 0.3 / 1.0
|
2162 |
-
$guid = $this->item['id'];
|
2163 |
-
elseif (isset($this->item['atom']['id'])) : // Namespaced Atom
|
2164 |
-
$guid = $this->item['atom']['id'];
|
2165 |
-
elseif (isset($this->item['guid'])) : // RSS 2.0
|
2166 |
-
$guid = $this->item['guid'];
|
2167 |
-
elseif (isset($this->item['dc']['identifier'])) :// yeah, right
|
2168 |
-
$guid = $this->item['dc']['identifier'];
|
2169 |
-
else :
|
2170 |
-
// The feed does not seem to have provided us with a
|
2171 |
-
// unique identifier, so we'll have to cobble together
|
2172 |
-
// a tag: URI that might work for us. The base of the
|
2173 |
-
// URI will be the host name of the feed source ...
|
2174 |
-
$bits = parse_url($this->feedmeta['link/uri']);
|
2175 |
-
$guid = 'tag:'.$bits['host'];
|
2176 |
-
|
2177 |
-
// If we have a date of creation, then we can use that
|
2178 |
-
// to uniquely identify the item. (On the other hand, if
|
2179 |
-
// the feed producer was consicentious enough to
|
2180 |
-
// generate dates of creation, she probably also was
|
2181 |
-
// conscientious enough to generate unique identifiers.)
|
2182 |
-
if (!is_null($this->created())) :
|
2183 |
-
$guid .= '://post.'.date('YmdHis', $this->created());
|
2184 |
-
|
2185 |
-
// Otherwise, use both the URI of the item, *and* the
|
2186 |
-
// item's title. We have to use both because titles are
|
2187 |
-
// often not unique, and sometimes links aren't unique
|
2188 |
-
// either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
|
2189 |
-
// some podcasts). But it's rare to have *both* the same
|
2190 |
-
// title *and* the same link for two different items. So
|
2191 |
-
// this is about the best we can do.
|
2192 |
-
else :
|
2193 |
-
$guid .= '://'.md5($this->item['link'].'/'.$this->item['title']);
|
2194 |
-
endif;
|
2195 |
-
endif;
|
2196 |
-
return $guid;
|
2197 |
-
}
|
2198 |
-
|
2199 |
-
function author () {
|
2200 |
-
$author = array ();
|
2201 |
-
|
2202 |
-
if (isset($this->item['author_name'])):
|
2203 |
-
$author['name'] = $this->item['author_name'];
|
2204 |
-
elseif (isset($this->item['dc']['creator'])):
|
2205 |
-
$author['name'] = $this->item['dc']['creator'];
|
2206 |
-
elseif (isset($this->item['dc']['contributor'])):
|
2207 |
-
$author['name'] = $this->item['dc']['contributor'];
|
2208 |
-
elseif (isset($this->feed->channel['dc']['creator'])) :
|
2209 |
-
$author['name'] = $this->feed->channel['dc']['creator'];
|
2210 |
-
elseif (isset($this->feed->channel['dc']['contributor'])) :
|
2211 |
-
$author['name'] = $this->feed->channel['dc']['contributor'];
|
2212 |
-
elseif (isset($this->feed->channel['author_name'])) :
|
2213 |
-
$author['name'] = $this->feed->channel['author_name'];
|
2214 |
-
elseif ($this->feed->is_rss() and isset($this->item['author'])) :
|
2215 |
-
// The author element in RSS is allegedly an
|
2216 |
-
// e-mail address, but lots of people don't use
|
2217 |
-
// it that way. So let's make of it what we can.
|
2218 |
-
$author = parse_email_with_realname($this->item['author']);
|
2219 |
-
|
2220 |
-
if (!isset($author['name'])) :
|
2221 |
-
if (isset($author['email'])) :
|
2222 |
-
$author['name'] = $author['email'];
|
2223 |
-
else :
|
2224 |
-
$author['name'] = $this->feed->channel['title'];
|
2225 |
-
endif;
|
2226 |
-
endif;
|
2227 |
-
else :
|
2228 |
-
$author['name'] = $this->feed->channel['title'];
|
2229 |
-
endif;
|
2230 |
-
|
2231 |
-
if (isset($this->item['author_email'])):
|
2232 |
-
$author['email'] = $this->item['author_email'];
|
2233 |
-
elseif (isset($this->feed->channel['author_email'])) :
|
2234 |
-
$author['email'] = $this->feed->channel['author_email'];
|
2235 |
-
endif;
|
2236 |
-
|
2237 |
-
if (isset($this->item['author_url'])):
|
2238 |
-
$author['uri'] = $this->item['author_url'];
|
2239 |
-
elseif (isset($this->feed->channel['author_url'])) :
|
2240 |
-
$author['uri'] = $this->item['author_url'];
|
2241 |
-
else:
|
2242 |
-
$author['uri'] = $this->feed->channel['link'];
|
2243 |
-
endif;
|
2244 |
-
|
2245 |
-
return $author;
|
2246 |
-
} // SyndicatedPost::author()
|
2247 |
-
|
2248 |
-
var $uri_attrs = array (
|
2249 |
-
array('a', 'href'),
|
2250 |
-
array('applet', 'codebase'),
|
2251 |
-
array('area', 'href'),
|
2252 |
-
array('blockquote', 'cite'),
|
2253 |
-
array('body', 'background'),
|
2254 |
-
array('del', 'cite'),
|
2255 |
-
array('form', 'action'),
|
2256 |
-
array('frame', 'longdesc'),
|
2257 |
-
array('frame', 'src'),
|
2258 |
-
array('iframe', 'longdesc'),
|
2259 |
-
array('iframe', 'src'),
|
2260 |
-
array('head', 'profile'),
|
2261 |
-
array('img', 'longdesc'),
|
2262 |
-
array('img', 'src'),
|
2263 |
-
array('img', 'usemap'),
|
2264 |
-
array('input', 'src'),
|
2265 |
-
array('input', 'usemap'),
|
2266 |
-
array('ins', 'cite'),
|
2267 |
-
array('link', 'href'),
|
2268 |
-
array('object', 'classid'),
|
2269 |
-
array('object', 'codebase'),
|
2270 |
-
array('object', 'data'),
|
2271 |
-
array('object', 'usemap'),
|
2272 |
-
array('q', 'cite'),
|
2273 |
-
array('script', 'src')
|
2274 |
-
); /* var SyndicatedPost::$uri_attrs */
|
2275 |
-
|
2276 |
-
var $_base = null;
|
2277 |
-
|
2278 |
-
function resolve_single_relative_uri ($refs) {
|
2279 |
-
$tag = FeedWordPressHTML::attributeMatch($refs);
|
2280 |
-
$url = Relative_URI::resolve($tag['value'], $this->_base);
|
2281 |
-
return $tag['prefix'] . $url . $tag['suffix'];
|
2282 |
-
} /* function SyndicatedPost::resolve_single_relative_uri() */
|
2283 |
-
|
2284 |
-
function resolve_relative_uris ($content, $obj) {
|
2285 |
-
# The MagpieRSS upgrade has some `xml:base` support baked in.
|
2286 |
-
# However, sometimes people do silly things, like putting
|
2287 |
-
# relative URIs out on a production RSS 2.0 feed or other feeds
|
2288 |
-
# with no good support for `xml:base`. So we'll do our best to
|
2289 |
-
# try to catch any remaining relative URIs and resolve them as
|
2290 |
-
# best we can.
|
2291 |
-
$obj->_base = $obj->item['link']; // Reset the base for resolving relative URIs
|
2292 |
-
|
2293 |
-
foreach ($obj->uri_attrs as $pair) :
|
2294 |
-
list($tag, $attr) = $pair;
|
2295 |
-
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
2296 |
-
$content = preg_replace_callback (
|
2297 |
-
$pattern,
|
2298 |
-
array(&$obj, 'resolve_single_relative_uri'),
|
2299 |
-
$content
|
2300 |
-
);
|
2301 |
-
endforeach;
|
2302 |
-
|
2303 |
-
return $content;
|
2304 |
-
} /* function SyndicatedPost::resolve_relative_uris () */
|
2305 |
-
|
2306 |
-
var $strip_attrs = array (
|
2307 |
-
array('[a-z]+', 'target'),
|
2308 |
-
// array('[a-z]+', 'style'),
|
2309 |
-
// array('[a-z]+', 'on[a-z]+'),
|
2310 |
-
);
|
2311 |
-
|
2312 |
-
function strip_attribute_from_tag ($refs) {
|
2313 |
-
$tag = FeedWordPressHTML::attributeMatch($refs);
|
2314 |
-
return $tag['before_attribute'].$tag['after_attribute'];
|
2315 |
-
}
|
2316 |
-
|
2317 |
-
function sanitize_content ($content, $obj) {
|
2318 |
-
# This kind of sucks. I intend to replace it with
|
2319 |
-
# lib_filter sometime soon.
|
2320 |
-
foreach ($obj->strip_attrs as $pair):
|
2321 |
-
list($tag,$attr) = $pair;
|
2322 |
-
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
2323 |
-
|
2324 |
-
$content = preg_replace_callback (
|
2325 |
-
$pattern,
|
2326 |
-
array(&$obj, 'strip_attribute_from_tag'),
|
2327 |
-
$content
|
2328 |
-
);
|
2329 |
-
endforeach;
|
2330 |
-
return $content;
|
2331 |
-
}
|
2332 |
-
} // class SyndicatedPost
|
2333 |
-
|
2334 |
require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
|
2335 |
|
2336 |
################################################################################
|
@@ -2356,182 +1175,10 @@ function feedwordpress_pong ($args) {
|
|
2356 |
endif;
|
2357 |
}
|
2358 |
|
2359 |
-
# Relative URI static class: PHP class for resolving relative URLs
|
2360 |
-
#
|
2361 |
-
# This class is derived (under the terms of the GPL) from URL Class 0.3 by
|
2362 |
-
# Keyvan Minoukadeh <keyvan@k1m.com>, which is great but more than we need
|
2363 |
-
# for FeedWordPress's purposes. The class has been stripped down to a single
|
2364 |
-
# public method: Relative_URI::resolve($url, $base), which resolves the URI in
|
2365 |
-
# $url relative to the URI in $base
|
2366 |
-
#
|
2367 |
# The upgraded MagpieRSS also uses this class. So if we have it loaded
|
2368 |
# in, don't load it again.
|
2369 |
if (!class_exists('Relative_URI')) {
|
2370 |
-
|
2371 |
-
class Relative_URI
|
2372 |
-
{
|
2373 |
-
// Resolve relative URI in $url against the base URI in $base. If $base
|
2374 |
-
// is not supplied, then we use the REQUEST_URI of this script.
|
2375 |
-
//
|
2376 |
-
// I'm hoping this method reflects RFC 2396 Section 5.2
|
2377 |
-
function resolve ($url, $base = NULL)
|
2378 |
-
{
|
2379 |
-
if (is_null($base)):
|
2380 |
-
$base = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
|
2381 |
-
endif;
|
2382 |
-
|
2383 |
-
$base = Relative_URI::_encode(trim($base));
|
2384 |
-
$uri_parts = Relative_URI::_parse_url($base);
|
2385 |
-
|
2386 |
-
$url = Relative_URI::_encode(trim($url));
|
2387 |
-
$parts = Relative_URI::_parse_url($url);
|
2388 |
-
|
2389 |
-
$uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
|
2390 |
-
$uri_parts['query'] = (isset($parts['query']) ? $parts['query'] : null);
|
2391 |
-
|
2392 |
-
// if path is empty, and scheme, host, and query are undefined,
|
2393 |
-
// the URL is referring the base URL
|
2394 |
-
|
2395 |
-
if (($parts['path'] == '') && !isset($parts['scheme']) && !isset($parts['host']) && !isset($parts['query'])) {
|
2396 |
-
// If the URI is empty or only a fragment, return the base URI
|
2397 |
-
return $base . (isset($parts['fragment']) ? '#'.$parts['fragment'] : '');
|
2398 |
-
} elseif (isset($parts['scheme'])) {
|
2399 |
-
// If the scheme is set, then the URI is absolute.
|
2400 |
-
return $url;
|
2401 |
-
} elseif (isset($parts['host'])) {
|
2402 |
-
$uri_parts['host'] = $parts['host'];
|
2403 |
-
$uri_parts['path'] = $parts['path'];
|
2404 |
-
} else {
|
2405 |
-
// We have a relative path but not a host.
|
2406 |
-
|
2407 |
-
// start ugly fix:
|
2408 |
-
// prepend slash to path if base host is set, base path is not set, and url path is not absolute
|
2409 |
-
if ($uri_parts['host'] && ($uri_parts['path'] == '')
|
2410 |
-
&& (strlen($parts['path']) > 0)
|
2411 |
-
&& (substr($parts['path'], 0, 1) != '/')) {
|
2412 |
-
$parts['path'] = '/'.$parts['path'];
|
2413 |
-
} // end ugly fix
|
2414 |
-
|
2415 |
-
if (substr($parts['path'], 0, 1) == '/') {
|
2416 |
-
$uri_parts['path'] = $parts['path'];
|
2417 |
-
} else {
|
2418 |
-
// copy base path excluding any characters after the last (right-most) slash character
|
2419 |
-
$buffer = substr($uri_parts['path'], 0, (int)strrpos($uri_parts['path'], '/')+1);
|
2420 |
-
// append relative path
|
2421 |
-
$buffer .= $parts['path'];
|
2422 |
-
// remove "./" where "." is a complete path segment.
|
2423 |
-
$buffer = str_replace('/./', '/', $buffer);
|
2424 |
-
if (substr($buffer, 0, 2) == './') {
|
2425 |
-
$buffer = substr($buffer, 2);
|
2426 |
-
}
|
2427 |
-
// if buffer ends with "." as a complete path segment, remove it
|
2428 |
-
if (substr($buffer, -2) == '/.') {
|
2429 |
-
$buffer = substr($buffer, 0, -1);
|
2430 |
-
}
|
2431 |
-
// remove "<segment>/../" where <segment> is a complete path segment not equal to ".."
|
2432 |
-
$search_finished = false;
|
2433 |
-
$segment = explode('/', $buffer);
|
2434 |
-
while (!$search_finished) {
|
2435 |
-
for ($x=0; $x+1 < count($segment);) {
|
2436 |
-
if (($segment[$x] != '') && ($segment[$x] != '..') && ($segment[$x+1] == '..')) {
|
2437 |
-
if ($x+2 == count($segment)) $segment[] = '';
|
2438 |
-
unset($segment[$x], $segment[$x+1]);
|
2439 |
-
$segment = array_values($segment);
|
2440 |
-
continue 2;
|
2441 |
-
} else {
|
2442 |
-
$x++;
|
2443 |
-
}
|
2444 |
-
}
|
2445 |
-
$search_finished = true;
|
2446 |
-
}
|
2447 |
-
$buffer = (count($segment) == 1) ? '/' : implode('/', $segment);
|
2448 |
-
$uri_parts['path'] = $buffer;
|
2449 |
-
|
2450 |
-
}
|
2451 |
-
}
|
2452 |
-
|
2453 |
-
// If we've gotten to this point, we can try to put the pieces
|
2454 |
-
// back together.
|
2455 |
-
$ret = '';
|
2456 |
-
if (isset($uri_parts['scheme'])) $ret .= $uri_parts['scheme'].':';
|
2457 |
-
if (isset($uri_parts['user'])) {
|
2458 |
-
$ret .= $uri_parts['user'];
|
2459 |
-
if (isset($uri_parts['pass'])) $ret .= ':'.$uri_parts['parts'];
|
2460 |
-
$ret .= '@';
|
2461 |
-
}
|
2462 |
-
if (isset($uri_parts['host'])) {
|
2463 |
-
$ret .= '//'.$uri_parts['host'];
|
2464 |
-
if (isset($uri_parts['port'])) $ret .= ':'.$uri_parts['port'];
|
2465 |
-
}
|
2466 |
-
$ret .= $uri_parts['path'];
|
2467 |
-
if (isset($uri_parts['query'])) $ret .= '?'.$uri_parts['query'];
|
2468 |
-
if (isset($uri_parts['fragment'])) $ret .= '#'.$uri_parts['fragment'];
|
2469 |
-
|
2470 |
-
return $ret;
|
2471 |
-
}
|
2472 |
-
|
2473 |
-
/**
|
2474 |
-
* Parse URL
|
2475 |
-
*
|
2476 |
-
* Regular expression grabbed from RFC 2396 Appendix B.
|
2477 |
-
* This is a replacement for PHPs builtin parse_url().
|
2478 |
-
* @param string $url
|
2479 |
-
* @access private
|
2480 |
-
* @return array
|
2481 |
-
*/
|
2482 |
-
function _parse_url($url)
|
2483 |
-
{
|
2484 |
-
// I'm using this pattern instead of parse_url() as there's a few strings where parse_url()
|
2485 |
-
// generates a warning.
|
2486 |
-
if (preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!', $url, $match)) {
|
2487 |
-
$parts = array();
|
2488 |
-
if ($match[1] != '') $parts['scheme'] = $match[2];
|
2489 |
-
if ($match[3] != '') $parts['auth'] = $match[4];
|
2490 |
-
// parse auth
|
2491 |
-
if (isset($parts['auth'])) {
|
2492 |
-
// store user info
|
2493 |
-
if (($at_pos = strpos($parts['auth'], '@')) !== false) {
|
2494 |
-
$userinfo = explode(':', substr($parts['auth'], 0, $at_pos), 2);
|
2495 |
-
$parts['user'] = $userinfo[0];
|
2496 |
-
if (isset($userinfo[1])) $parts['pass'] = $userinfo[1];
|
2497 |
-
$parts['auth'] = substr($parts['auth'], $at_pos+1);
|
2498 |
-
}
|
2499 |
-
// get port number
|
2500 |
-
if ($port_pos = strrpos($parts['auth'], ':')) {
|
2501 |
-
$parts['host'] = substr($parts['auth'], 0, $port_pos);
|
2502 |
-
$parts['port'] = (int)substr($parts['auth'], $port_pos+1);
|
2503 |
-
if ($parts['port'] < 1) $parts['port'] = null;
|
2504 |
-
} else {
|
2505 |
-
$parts['host'] = $parts['auth'];
|
2506 |
-
}
|
2507 |
-
}
|
2508 |
-
unset($parts['auth']);
|
2509 |
-
$parts['path'] = $match[5];
|
2510 |
-
if (isset($match[6]) && ($match[6] != '')) $parts['query'] = $match[7];
|
2511 |
-
if (isset($match[8]) && ($match[8] != '')) $parts['fragment'] = $match[9];
|
2512 |
-
return $parts;
|
2513 |
-
}
|
2514 |
-
// shouldn't reach here
|
2515 |
-
return array('path'=>'');
|
2516 |
-
}
|
2517 |
-
|
2518 |
-
function _encode($string)
|
2519 |
-
{
|
2520 |
-
static $replace = array();
|
2521 |
-
if (!count($replace)) {
|
2522 |
-
$find = array(32, 34, 60, 62, 123, 124, 125, 91, 92, 93, 94, 96, 127);
|
2523 |
-
$find = array_merge(range(0, 31), $find);
|
2524 |
-
$find = array_map('chr', $find);
|
2525 |
-
foreach ($find as $char) {
|
2526 |
-
$replace[$char] = '%'.bin2hex($char);
|
2527 |
-
}
|
2528 |
-
}
|
2529 |
-
// escape control characters and a few other characters
|
2530 |
-
$encoded = strtr($string, $replace);
|
2531 |
-
// remove any character outside the hex range: 21 - 7E (see www.asciitable.com)
|
2532 |
-
return preg_replace('/[^\x21-\x7e]/', '', $encoded);
|
2533 |
-
}
|
2534 |
-
} // class Relative_URI
|
2535 |
}
|
2536 |
|
2537 |
// take your best guess at the realname and e-mail, given a string
|
3 |
Plugin Name: FeedWordPress
|
4 |
Plugin URI: http://projects.radgeek.com/feedwordpress
|
5 |
Description: simple and flexible Atom/RSS syndication for WordPress
|
6 |
+
Version: 2009.0707
|
7 |
Author: Charles Johnson
|
8 |
Author URI: http://radgeek.com/
|
9 |
License: GPL
|
28 |
|
29 |
# -- Don't change these unless you know what you're doing...
|
30 |
|
31 |
+
define ('FEEDWORDPRESS_VERSION', '2009.0707');
|
32 |
define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
|
33 |
define ('DEFAULT_SYNDICATION_CATEGORY', 'Contributors');
|
34 |
|
52 |
define ('FWP_SCHEMA_25', 7558); // Database schema # for WP 2.5
|
53 |
define ('FWP_SCHEMA_26', 8201); // Database schema # for WP 2.6
|
54 |
define ('FWP_SCHEMA_27', 9872); // Database schema # for WP 2.7
|
55 |
+
define ('FWP_SCHEMA_28', 11548); // Database schema # for WP 2.8
|
56 |
|
57 |
if (FEEDWORDPRESS_DEBUG) :
|
58 |
// Help us to pick out errors, if any.
|
1005 |
if (!$fwp_db_version or $fwp_db_version < FEEDWORDPRESS_VERSION) :
|
1006 |
// This is an older version or a fresh install. Does it
|
1007 |
// require a database upgrade or database initialization?
|
1008 |
+
if ($fwp_db_version <= 0.96) :
|
|
|
|
|
|
|
1009 |
// Yes. Check to see whether this is a fresh install or an upgrade.
|
1010 |
$syn = $wpdb->get_col("
|
1011 |
SELECT post_id
|
1017 |
else : // fresh install; brand it as ours
|
1018 |
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1019 |
endif;
|
1020 |
+
elseif ($fwp_db_version < 2009.0707) :
|
1021 |
+
// We need to clear out any busted AJAX crap
|
1022 |
+
if (fwp_test_wp_version(FWP_SCHEMA_HAS_USERMETA)) :
|
1023 |
+
$wpdb->query("
|
1024 |
+
DELETE FROM $wpdb->usermeta
|
1025 |
+
WHERE LOCATE('feedwordpress', meta_key)
|
1026 |
+
AND LOCATE('box', meta_key);
|
1027 |
+
");
|
1028 |
+
endif;
|
1029 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1030 |
+
else :
|
1031 |
+
// No. Just brand it with the new version.
|
1032 |
+
update_option('feedwordpress_version', FEEDWORDPRESS_VERSION);
|
1033 |
endif;
|
1034 |
endif;
|
1035 |
return $ret;
|
1149 |
}
|
1150 |
} // class FeedWordPress
|
1151 |
|
1152 |
+
require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1153 |
require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
|
1154 |
|
1155 |
################################################################################
|
1175 |
endif;
|
1176 |
}
|
1177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1178 |
# The upgraded MagpieRSS also uses this class. So if we have it loaded
|
1179 |
# in, don't load it again.
|
1180 |
if (!class_exists('Relative_URI')) {
|
1181 |
+
require_once(dirname(__FILE__) . '/relative_uri.class.php');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1182 |
}
|
1183 |
|
1184 |
// take your best guess at the realname and e-mail, given a string
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: Charles Johnson
|
|
3 |
Donate link: http://projects.radgeek.com/feedwordpress/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
Requires at least: 1.5
|
6 |
-
Tested up to: 2.8
|
7 |
-
Stable tag: 2009.
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
@@ -23,13 +23,14 @@ to use at [Feminist Blogs](http://feministblogs.org/).
|
|
23 |
|
24 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
25 |
configuration in mind. You'll need a working installation of WordPress or
|
26 |
-
WordPress MU (versions [2.
|
27 |
-
[1.5][]), and also FTP or SFTP access to your web host. The
|
28 |
-
cron jobs on your web host is helpful but not absolutely
|
29 |
-
need to tweak any plain-text configuration files and you
|
30 |
-
access to your web host to make it work. (Although, I should
|
31 |
-
hosts that *don't* offer shell access are *bad web hosts*.)
|
32 |
-
|
|
|
33 |
[2.7]: http://codex.wordpress.org/Version_2.7
|
34 |
[2.6]: http://codex.wordpress.org/Version_2.6
|
35 |
[2.5]: http://codex.wordpress.org/Version_2.5
|
@@ -43,16 +44,15 @@ hosts that *don't* offer shell access are *bad web hosts*.)
|
|
43 |
|
44 |
To use FeedWordPress, you will need:
|
45 |
|
46 |
-
* an installed and configured copy of WordPress version 2.
|
47 |
-
|
48 |
-
|
49 |
|
50 |
* FTP or SFTP access to your web host
|
51 |
|
52 |
= New Installations =
|
53 |
|
54 |
-
1. Download the FeedWordPress archive
|
55 |
-
extract the files on your computer.
|
56 |
|
57 |
2. Create a new directory named `feedwordpress` in the `wp-content/plugins`
|
58 |
directory of your WordPress installation. Use an FTP or SFTP client to
|
3 |
Donate link: http://projects.radgeek.com/feedwordpress/
|
4 |
Tags: syndication, aggregation, feed, atom, rss
|
5 |
Requires at least: 1.5
|
6 |
+
Tested up to: 2.8.1
|
7 |
+
Stable tag: 2009.0707
|
8 |
|
9 |
FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
|
10 |
|
23 |
|
24 |
FeedWordPress is designed with flexibility, ease of use, and ease of
|
25 |
configuration in mind. You'll need a working installation of WordPress or
|
26 |
+
WordPress MU (versions [2.8][], [2.7][], [2.6][], [2.5][], [2.3][], [2.2][],
|
27 |
+
[2.1][], [2.0][] or [1.5][]), and also FTP or SFTP access to your web host. The
|
28 |
+
ability to create cron jobs on your web host is helpful but not absolutely
|
29 |
+
necessary. You *don't* need to tweak any plain-text configuration files and you
|
30 |
+
*don't* need shell access to your web host to make it work. (Although, I should
|
31 |
+
point out, web hosts that *don't* offer shell access are *bad web hosts*.)
|
32 |
+
|
33 |
+
[2.8]: http://codex.wordpress.org/Version_2.8
|
34 |
[2.7]: http://codex.wordpress.org/Version_2.7
|
35 |
[2.6]: http://codex.wordpress.org/Version_2.6
|
36 |
[2.5]: http://codex.wordpress.org/Version_2.5
|
44 |
|
45 |
To use FeedWordPress, you will need:
|
46 |
|
47 |
+
* an installed and configured copy of WordPress version 2.x, or 1.5.x.
|
48 |
+
(FeedWordPress will also work with the equivalent versions of WordPress
|
49 |
+
MU.)
|
50 |
|
51 |
* FTP or SFTP access to your web host
|
52 |
|
53 |
= New Installations =
|
54 |
|
55 |
+
1. Download the FeedWordPress archive and extract the files on your computer.
|
|
|
56 |
|
57 |
2. Create a new directory named `feedwordpress` in the `wp-content/plugins`
|
58 |
directory of your WordPress installation. Use an FTP or SFTP client to
|
relative_uri.class.php
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
# Relative URI static class: PHP class for resolving relative URLs
|
3 |
+
#
|
4 |
+
# This class is derived (under the terms of the GPL) from URL Class 0.3 by
|
5 |
+
# Keyvan Minoukadeh <keyvan@k1m.com>, which is great but more than we need
|
6 |
+
# for FeedWordPress's purposes. The class has been stripped down to a single
|
7 |
+
# public method: Relative_URI::resolve($url, $base), which resolves the URI in
|
8 |
+
# $url relative to the URI in $base
|
9 |
+
|
10 |
+
class Relative_URI
|
11 |
+
{
|
12 |
+
// Resolve relative URI in $url against the base URI in $base. If $base
|
13 |
+
// is not supplied, then we use the REQUEST_URI of this script.
|
14 |
+
//
|
15 |
+
// I'm hoping this method reflects RFC 2396 Section 5.2
|
16 |
+
function resolve ($url, $base = NULL)
|
17 |
+
{
|
18 |
+
if (is_null($base)):
|
19 |
+
$base = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
|
20 |
+
endif;
|
21 |
+
|
22 |
+
$base = Relative_URI::_encode(trim($base));
|
23 |
+
$uri_parts = Relative_URI::_parse_url($base);
|
24 |
+
|
25 |
+
$url = Relative_URI::_encode(trim($url));
|
26 |
+
$parts = Relative_URI::_parse_url($url);
|
27 |
+
|
28 |
+
$uri_parts['fragment'] = (isset($parts['fragment']) ? $parts['fragment'] : null);
|
29 |
+
$uri_parts['query'] = (isset($parts['query']) ? $parts['query'] : null);
|
30 |
+
|
31 |
+
// if path is empty, and scheme, host, and query are undefined,
|
32 |
+
// the URL is referring the base URL
|
33 |
+
|
34 |
+
if (($parts['path'] == '') && !isset($parts['scheme']) && !isset($parts['host']) && !isset($parts['query'])) {
|
35 |
+
// If the URI is empty or only a fragment, return the base URI
|
36 |
+
return $base . (isset($parts['fragment']) ? '#'.$parts['fragment'] : '');
|
37 |
+
} elseif (isset($parts['scheme'])) {
|
38 |
+
// If the scheme is set, then the URI is absolute.
|
39 |
+
return $url;
|
40 |
+
} elseif (isset($parts['host'])) {
|
41 |
+
$uri_parts['host'] = $parts['host'];
|
42 |
+
$uri_parts['path'] = $parts['path'];
|
43 |
+
} else {
|
44 |
+
// We have a relative path but not a host.
|
45 |
+
|
46 |
+
// start ugly fix:
|
47 |
+
// prepend slash to path if base host is set, base path is not set, and url path is not absolute
|
48 |
+
if ($uri_parts['host'] && ($uri_parts['path'] == '')
|
49 |
+
&& (strlen($parts['path']) > 0)
|
50 |
+
&& (substr($parts['path'], 0, 1) != '/')) {
|
51 |
+
$parts['path'] = '/'.$parts['path'];
|
52 |
+
} // end ugly fix
|
53 |
+
|
54 |
+
if (substr($parts['path'], 0, 1) == '/') {
|
55 |
+
$uri_parts['path'] = $parts['path'];
|
56 |
+
} else {
|
57 |
+
// copy base path excluding any characters after the last (right-most) slash character
|
58 |
+
$buffer = substr($uri_parts['path'], 0, (int)strrpos($uri_parts['path'], '/')+1);
|
59 |
+
// append relative path
|
60 |
+
$buffer .= $parts['path'];
|
61 |
+
// remove "./" where "." is a complete path segment.
|
62 |
+
$buffer = str_replace('/./', '/', $buffer);
|
63 |
+
if (substr($buffer, 0, 2) == './') {
|
64 |
+
$buffer = substr($buffer, 2);
|
65 |
+
}
|
66 |
+
// if buffer ends with "." as a complete path segment, remove it
|
67 |
+
if (substr($buffer, -2) == '/.') {
|
68 |
+
$buffer = substr($buffer, 0, -1);
|
69 |
+
}
|
70 |
+
// remove "<segment>/../" where <segment> is a complete path segment not equal to ".."
|
71 |
+
$search_finished = false;
|
72 |
+
$segment = explode('/', $buffer);
|
73 |
+
while (!$search_finished) {
|
74 |
+
for ($x=0; $x+1 < count($segment);) {
|
75 |
+
if (($segment[$x] != '') && ($segment[$x] != '..') && ($segment[$x+1] == '..')) {
|
76 |
+
if ($x+2 == count($segment)) $segment[] = '';
|
77 |
+
unset($segment[$x], $segment[$x+1]);
|
78 |
+
$segment = array_values($segment);
|
79 |
+
continue 2;
|
80 |
+
} else {
|
81 |
+
$x++;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
$search_finished = true;
|
85 |
+
}
|
86 |
+
$buffer = (count($segment) == 1) ? '/' : implode('/', $segment);
|
87 |
+
$uri_parts['path'] = $buffer;
|
88 |
+
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
// If we've gotten to this point, we can try to put the pieces
|
93 |
+
// back together.
|
94 |
+
$ret = '';
|
95 |
+
if (isset($uri_parts['scheme'])) $ret .= $uri_parts['scheme'].':';
|
96 |
+
if (isset($uri_parts['user'])) {
|
97 |
+
$ret .= $uri_parts['user'];
|
98 |
+
if (isset($uri_parts['pass'])) $ret .= ':'.$uri_parts['parts'];
|
99 |
+
$ret .= '@';
|
100 |
+
}
|
101 |
+
if (isset($uri_parts['host'])) {
|
102 |
+
$ret .= '//'.$uri_parts['host'];
|
103 |
+
if (isset($uri_parts['port'])) $ret .= ':'.$uri_parts['port'];
|
104 |
+
}
|
105 |
+
$ret .= $uri_parts['path'];
|
106 |
+
if (isset($uri_parts['query'])) $ret .= '?'.$uri_parts['query'];
|
107 |
+
if (isset($uri_parts['fragment'])) $ret .= '#'.$uri_parts['fragment'];
|
108 |
+
|
109 |
+
return $ret;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Parse URL
|
114 |
+
*
|
115 |
+
* Regular expression grabbed from RFC 2396 Appendix B.
|
116 |
+
* This is a replacement for PHPs builtin parse_url().
|
117 |
+
* @param string $url
|
118 |
+
* @access private
|
119 |
+
* @return array
|
120 |
+
*/
|
121 |
+
function _parse_url($url)
|
122 |
+
{
|
123 |
+
// I'm using this pattern instead of parse_url() as there's a few strings where parse_url()
|
124 |
+
// generates a warning.
|
125 |
+
if (preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!', $url, $match)) {
|
126 |
+
$parts = array();
|
127 |
+
if ($match[1] != '') $parts['scheme'] = $match[2];
|
128 |
+
if ($match[3] != '') $parts['auth'] = $match[4];
|
129 |
+
// parse auth
|
130 |
+
if (isset($parts['auth'])) {
|
131 |
+
// store user info
|
132 |
+
if (($at_pos = strpos($parts['auth'], '@')) !== false) {
|
133 |
+
$userinfo = explode(':', substr($parts['auth'], 0, $at_pos), 2);
|
134 |
+
$parts['user'] = $userinfo[0];
|
135 |
+
if (isset($userinfo[1])) $parts['pass'] = $userinfo[1];
|
136 |
+
$parts['auth'] = substr($parts['auth'], $at_pos+1);
|
137 |
+
}
|
138 |
+
// get port number
|
139 |
+
if ($port_pos = strrpos($parts['auth'], ':')) {
|
140 |
+
$parts['host'] = substr($parts['auth'], 0, $port_pos);
|
141 |
+
$parts['port'] = (int)substr($parts['auth'], $port_pos+1);
|
142 |
+
if ($parts['port'] < 1) $parts['port'] = null;
|
143 |
+
} else {
|
144 |
+
$parts['host'] = $parts['auth'];
|
145 |
+
}
|
146 |
+
}
|
147 |
+
unset($parts['auth']);
|
148 |
+
$parts['path'] = $match[5];
|
149 |
+
if (isset($match[6]) && ($match[6] != '')) $parts['query'] = $match[7];
|
150 |
+
if (isset($match[8]) && ($match[8] != '')) $parts['fragment'] = $match[9];
|
151 |
+
return $parts;
|
152 |
+
}
|
153 |
+
// shouldn't reach here
|
154 |
+
return array('path'=>'');
|
155 |
+
}
|
156 |
+
|
157 |
+
function _encode($string)
|
158 |
+
{
|
159 |
+
static $replace = array();
|
160 |
+
if (!count($replace)) {
|
161 |
+
$find = array(32, 34, 60, 62, 123, 124, 125, 91, 92, 93, 94, 96, 127);
|
162 |
+
$find = array_merge(range(0, 31), $find);
|
163 |
+
$find = array_map('chr', $find);
|
164 |
+
foreach ($find as $char) {
|
165 |
+
$replace[$char] = '%'.bin2hex($char);
|
166 |
+
}
|
167 |
+
}
|
168 |
+
// escape control characters and a few other characters
|
169 |
+
$encoded = strtr($string, $replace);
|
170 |
+
// remove any character outside the hex range: 21 - 7E (see www.asciitable.com)
|
171 |
+
return preg_replace('/[^\x21-\x7e]/', '', $encoded);
|
172 |
+
}
|
173 |
+
} // class Relative_URI
|
174 |
+
|
syndicatedpost.class.php
ADDED
@@ -0,0 +1,1194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class SyndicatedPost {
|
3 |
+
var $item = null;
|
4 |
+
|
5 |
+
var $link = null;
|
6 |
+
var $feed = null;
|
7 |
+
var $feedmeta = null;
|
8 |
+
|
9 |
+
var $post = array ();
|
10 |
+
|
11 |
+
var $_freshness = null;
|
12 |
+
var $_wp_id = null;
|
13 |
+
|
14 |
+
function SyndicatedPost ($item, $link) {
|
15 |
+
global $wpdb;
|
16 |
+
|
17 |
+
$this->link = $link;
|
18 |
+
$feedmeta = $link->settings;
|
19 |
+
$feed = $link->magpie;
|
20 |
+
|
21 |
+
# This is ugly as all hell. I'd like to use apply_filters()'s
|
22 |
+
# alleged support for a variable argument count, but this seems
|
23 |
+
# to have been broken in WordPress 1.5. It'll be fixed somehow
|
24 |
+
# in WP 1.5.1, but I'm aiming at WP 1.5 compatibility across
|
25 |
+
# the board here.
|
26 |
+
#
|
27 |
+
# Cf.: <http://mosquito.wordpress.org/view.php?id=901>
|
28 |
+
global $fwp_channel, $fwp_feedmeta;
|
29 |
+
$fwp_channel = $feed; $fwp_feedmeta = $feedmeta;
|
30 |
+
|
31 |
+
$this->feed = $feed;
|
32 |
+
$this->feedmeta = $feedmeta;
|
33 |
+
|
34 |
+
$this->item = $item;
|
35 |
+
$this->item = apply_filters('syndicated_item', $this->item, $this);
|
36 |
+
|
37 |
+
# Filters can halt further processing by returning NULL
|
38 |
+
if (is_null($this->item)) :
|
39 |
+
$this->post = NULL;
|
40 |
+
else :
|
41 |
+
# Note that nothing is run through $wpdb->escape() here.
|
42 |
+
# That's deliberate. The escaping is done at the point
|
43 |
+
# of insertion, not here, to avoid double-escaping and
|
44 |
+
# to avoid screwing with syndicated_post filters
|
45 |
+
|
46 |
+
$this->post['post_title'] = apply_filters('syndicated_item_title', $this->item['title'], $this);
|
47 |
+
|
48 |
+
// This just gives us an alphanumeric representation of
|
49 |
+
// the author. We will look up (or create) the numeric
|
50 |
+
// ID for the author in SyndicatedPost::add()
|
51 |
+
$this->post['named']['author'] = apply_filters('syndicated_item_author', $this->author(), $this);
|
52 |
+
|
53 |
+
# Identify content and sanitize it.
|
54 |
+
# ---------------------------------
|
55 |
+
if (isset($this->item['atom_content'])) :
|
56 |
+
$content = $this->item['atom_content'];
|
57 |
+
elseif (isset($this->item['xhtml']['body'])) :
|
58 |
+
$content = $this->item['xhtml']['body'];
|
59 |
+
elseif (isset($this->item['xhtml']['div'])) :
|
60 |
+
$content = $this->item['xhtml']['div'];
|
61 |
+
elseif (isset($this->item['content']['encoded']) and $this->item['content']['encoded']):
|
62 |
+
$content = $this->item['content']['encoded'];
|
63 |
+
else:
|
64 |
+
$content = $this->item['description'];
|
65 |
+
endif;
|
66 |
+
$this->post['post_content'] = apply_filters('syndicated_item_content', $content, $this);
|
67 |
+
|
68 |
+
# Identify and sanitize excerpt
|
69 |
+
$excerpt = NULL;
|
70 |
+
if ( isset($this->item['description']) and $this->item['description'] ) :
|
71 |
+
$excerpt = $this->item['description'];
|
72 |
+
elseif ( isset($content) and $content ) :
|
73 |
+
$excerpt = strip_tags($content);
|
74 |
+
if (strlen($excerpt) > 255) :
|
75 |
+
$excerpt = substr($excerpt,0,252).'...';
|
76 |
+
endif;
|
77 |
+
endif;
|
78 |
+
$excerpt = apply_filters('syndicated_item_excerpt', $excerpt, $this);
|
79 |
+
|
80 |
+
if (!is_null($excerpt)):
|
81 |
+
$this->post['post_excerpt'] = $excerpt;
|
82 |
+
endif;
|
83 |
+
|
84 |
+
// This is unnecessary if we use wp_insert_post
|
85 |
+
if (!$this->use_api('wp_insert_post')) :
|
86 |
+
$this->post['post_name'] = sanitize_title($this->post['post_title']);
|
87 |
+
endif;
|
88 |
+
|
89 |
+
$this->post['epoch']['issued'] = apply_filters('syndicated_item_published', $this->published(), $this);
|
90 |
+
$this->post['epoch']['created'] = apply_filters('syndicated_item_created', $this->created(), $this);
|
91 |
+
$this->post['epoch']['modified'] = apply_filters('syndicated_item_updated', $this->updated(), $this);
|
92 |
+
|
93 |
+
// Dealing with timestamps in WordPress is so fucking fucked.
|
94 |
+
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
95 |
+
$this->post['post_date'] = gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
96 |
+
$this->post['post_modified'] = gmdate('Y-m-d H:i:s', $this->updated() + $offset);
|
97 |
+
$this->post['post_date_gmt'] = gmdate('Y-m-d H:i:s', $this->published());
|
98 |
+
$this->post['post_modified_gmt'] = gmdate('Y-m-d H:i:s', $this->updated());
|
99 |
+
|
100 |
+
// Use feed-level preferences or the global default.
|
101 |
+
$this->post['post_status'] = $this->link->syndicated_status('post', 'publish');
|
102 |
+
$this->post['comment_status'] = $this->link->syndicated_status('comment', 'closed');
|
103 |
+
$this->post['ping_status'] = $this->link->syndicated_status('ping', 'closed');
|
104 |
+
|
105 |
+
// Unique ID (hopefully a unique tag: URI); failing that, the permalink
|
106 |
+
$this->post['guid'] = apply_filters('syndicated_item_guid', $this->guid(), $this);
|
107 |
+
|
108 |
+
// 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
|
109 |
+
$default_custom_settings = get_option('feedwordpress_custom_settings');
|
110 |
+
if ($default_custom_settings) :
|
111 |
+
$default_custom_settings = unserialize($default_custom_settings);
|
112 |
+
endif;
|
113 |
+
if (!is_array($default_custom_settings)) :
|
114 |
+
$default_custom_settings = array();
|
115 |
+
endif;
|
116 |
+
|
117 |
+
$custom_settings = (isset($this->link->settings['postmeta']) ? $this->link->settings['postmeta'] : null);
|
118 |
+
if ($custom_settings) :
|
119 |
+
$custom_settings = unserialize($custom_settings);
|
120 |
+
endif;
|
121 |
+
if (!is_array($custom_settings)) :
|
122 |
+
$custom_settings = array();
|
123 |
+
endif;
|
124 |
+
$this->post['meta'] = array_merge($default_custom_settings, $custom_settings);
|
125 |
+
|
126 |
+
// RSS 2.0 / Atom 1.0 enclosure support
|
127 |
+
if ( isset($this->item['enclosure#']) ) :
|
128 |
+
for ($i = 1; $i <= $this->item['enclosure#']; $i++) :
|
129 |
+
$eid = (($i > 1) ? "#{$id}" : "");
|
130 |
+
$this->post['meta']['enclosure'][] =
|
131 |
+
apply_filters('syndicated_item_enclosure_url', $this->item["enclosure{$eid}@url"], $this)."\n".
|
132 |
+
apply_filters('syndicated_item_enclosure_length', $this->item["enclosure{$eid}@length"], $this)."\n".
|
133 |
+
apply_filters('syndicated_item_enclosure_type', $this->item["enclosure{$eid}@type"], $this);
|
134 |
+
endfor;
|
135 |
+
endif;
|
136 |
+
|
137 |
+
// In case you want to point back to the blog this was syndicated from
|
138 |
+
if (isset($this->feed->channel['title'])) :
|
139 |
+
$this->post['meta']['syndication_source'] = apply_filters('syndicated_item_source_title', $this->feed->channel['title'], $this);
|
140 |
+
endif;
|
141 |
+
|
142 |
+
if (isset($this->feed->channel['link'])) :
|
143 |
+
$this->post['meta']['syndication_source_uri'] = apply_filters('syndicated_item_source_link', $this->feed->channel['link'], $this);
|
144 |
+
endif;
|
145 |
+
|
146 |
+
// Make use of atom:source data, if present in an aggregated feed
|
147 |
+
if (isset($this->item['source_title'])) :
|
148 |
+
$this->post['meta']['syndication_source_original'] = $this->item['source_title'];
|
149 |
+
endif;
|
150 |
+
|
151 |
+
if (isset($this->item['source_link'])) :
|
152 |
+
$this->post['meta']['syndication_source_uri_original'] = $this->item['source_link'];
|
153 |
+
endif;
|
154 |
+
|
155 |
+
if (isset($this->item['source_id'])) :
|
156 |
+
$this->post['meta']['syndication_source_id_original'] = $this->item['source_id'];
|
157 |
+
endif;
|
158 |
+
|
159 |
+
// Store information on human-readable and machine-readable comment URIs
|
160 |
+
if (isset($this->item['comments'])) :
|
161 |
+
$this->post['meta']['rss:comments'] = apply_filters('syndicated_item_comments', $this->item['comments']);
|
162 |
+
endif;
|
163 |
+
if (isset($this->item['wfw']['commentrss'])) :
|
164 |
+
$this->post['meta']['wfw:commentRSS'] = apply_filters('syndicated_item_commentrss', $this->item['wfw']['commentrss']);
|
165 |
+
endif;
|
166 |
+
|
167 |
+
// Store information to identify the feed that this came from
|
168 |
+
$this->post['meta']['syndication_feed'] = $this->feedmeta['link/uri'];
|
169 |
+
$this->post['meta']['syndication_feed_id'] = $this->feedmeta['link/id'];
|
170 |
+
|
171 |
+
if (isset($this->item['source_link_self'])) :
|
172 |
+
$this->post['meta']['syndication_feed_original'] = $this->item['source_link_self'];
|
173 |
+
endif;
|
174 |
+
|
175 |
+
// In case you want to know the external permalink...
|
176 |
+
$this->post['meta']['syndication_permalink'] = apply_filters('syndicated_item_link', $this->item['link']);
|
177 |
+
|
178 |
+
// Store a hash of the post content for checking whether something needs to be updated
|
179 |
+
$this->post['meta']['syndication_item_hash'] = $this->update_hash();
|
180 |
+
|
181 |
+
// Feed-by-feed options for author and category creation
|
182 |
+
$this->post['named']['unfamiliar']['author'] = (isset($this->feedmeta['unfamiliar author']) ? $this->feedmeta['unfamiliar author'] : null);
|
183 |
+
$this->post['named']['unfamiliar']['category'] = (isset($this->feedmeta['unfamiliar category']) ? $this->feedmeta['unfamiliar category'] : null);
|
184 |
+
|
185 |
+
// Categories: start with default categories, if any
|
186 |
+
$fc = get_option("feedwordpress_syndication_cats");
|
187 |
+
if ($fc) :
|
188 |
+
$this->post['named']['preset/category'] = explode("\n", $fc);
|
189 |
+
else :
|
190 |
+
$this->post['named']['preset/category'] = array();
|
191 |
+
endif;
|
192 |
+
|
193 |
+
if (isset($this->feedmeta['cats']) and is_array($this->feedmeta['cats'])) :
|
194 |
+
$this->post['named']['preset/category'] = array_merge($this->post['named']['preset/category'], $this->feedmeta['cats']);
|
195 |
+
endif;
|
196 |
+
|
197 |
+
// Now add categories from the post, if we have 'em
|
198 |
+
$this->post['named']['category'] = array();
|
199 |
+
if ( isset($this->item['category#']) ) :
|
200 |
+
for ($i = 1; $i <= $this->item['category#']; $i++) :
|
201 |
+
$cat_idx = (($i > 1) ? "#{$i}" : "");
|
202 |
+
$cat = $this->item["category{$cat_idx}"];
|
203 |
+
|
204 |
+
if ( isset($this->feedmeta['cat_split']) and strlen($this->feedmeta['cat_split']) > 0) :
|
205 |
+
$pcre = "\007".$this->feedmeta['cat_split']."\007";
|
206 |
+
$this->post['named']['category'] = array_merge($this->post['named']['category'], preg_split($pcre, $cat, -1 /*=no limit*/, PREG_SPLIT_NO_EMPTY));
|
207 |
+
else :
|
208 |
+
$this->post['named']['category'][] = $cat;
|
209 |
+
endif;
|
210 |
+
endfor;
|
211 |
+
endif;
|
212 |
+
$this->post['named']['category'] = apply_filters('syndicated_item_categories', $this->post['named']['category'], $this);
|
213 |
+
|
214 |
+
// Tags: start with default tags, if any
|
215 |
+
$ft = get_option("feedwordpress_syndication_tags");
|
216 |
+
if ($ft) :
|
217 |
+
$this->post['tags_input'] = explode(FEEDWORDPRESS_CAT_SEPARATOR, $ft);
|
218 |
+
else :
|
219 |
+
$this->post['tags_input'] = array();
|
220 |
+
endif;
|
221 |
+
|
222 |
+
if (isset($this->feedmeta['tags']) and is_array($this->feedmeta['tags'])) :
|
223 |
+
$this->post['tags_input'] = array_merge($this->post['tags_input'], $this->feedmeta['tags']);
|
224 |
+
endif;
|
225 |
+
|
226 |
+
endif;
|
227 |
+
} // SyndicatedPost::SyndicatedPost()
|
228 |
+
|
229 |
+
function filtered () {
|
230 |
+
return is_null($this->post);
|
231 |
+
}
|
232 |
+
|
233 |
+
function freshness () {
|
234 |
+
global $wpdb;
|
235 |
+
|
236 |
+
if ($this->filtered()) : // This should never happen.
|
237 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
238 |
+
endif;
|
239 |
+
|
240 |
+
if (is_null($this->_freshness)) :
|
241 |
+
$guid = $wpdb->escape($this->guid());
|
242 |
+
|
243 |
+
$result = $wpdb->get_row("
|
244 |
+
SELECT id, guid, post_modified_gmt
|
245 |
+
FROM $wpdb->posts WHERE guid='$guid'
|
246 |
+
");
|
247 |
+
|
248 |
+
if (!$result) :
|
249 |
+
$this->_freshness = 2; // New content
|
250 |
+
else:
|
251 |
+
$stored_update_hashes = get_post_custom_values('syndication_item_hash', $result->id);
|
252 |
+
if (count($stored_update_hashes) > 0) :
|
253 |
+
$stored_update_hash = $stored_update_hashes[0];
|
254 |
+
$update_hash_changed = ($stored_update_hash != $this->update_hash());
|
255 |
+
else :
|
256 |
+
$update_hash_changed = false;
|
257 |
+
endif;
|
258 |
+
|
259 |
+
preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $result->post_modified_gmt, $backref);
|
260 |
+
|
261 |
+
$last_rev_ts = gmmktime($backref[4], $backref[5], $backref[6], $backref[2], $backref[3], $backref[1]);
|
262 |
+
$updated_ts = $this->updated(/*fallback=*/ true, /*default=*/ NULL);
|
263 |
+
$updated = ((
|
264 |
+
!is_null($updated_ts)
|
265 |
+
and ($updated_ts > $last_rev_ts)
|
266 |
+
) or $update_hash_changed);
|
267 |
+
|
268 |
+
if ($updated) :
|
269 |
+
$this->_freshness = 1; // Updated content
|
270 |
+
$this->_wp_id = $result->id;
|
271 |
+
else :
|
272 |
+
$this->_freshness = 0; // Same old, same old
|
273 |
+
$this->_wp_id = $result->id;
|
274 |
+
endif;
|
275 |
+
endif;
|
276 |
+
endif;
|
277 |
+
return $this->_freshness;
|
278 |
+
}
|
279 |
+
|
280 |
+
function wp_id () {
|
281 |
+
if ($this->filtered()) : // This should never happen.
|
282 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
283 |
+
endif;
|
284 |
+
|
285 |
+
if (is_null($this->_wp_id) and is_null($this->_freshness)) :
|
286 |
+
$fresh = $this->freshness(); // sets WP DB id in the process
|
287 |
+
endif;
|
288 |
+
return $this->_wp_id;
|
289 |
+
}
|
290 |
+
|
291 |
+
function store () {
|
292 |
+
global $wpdb;
|
293 |
+
|
294 |
+
if ($this->filtered()) : // This should never happen.
|
295 |
+
FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
|
296 |
+
endif;
|
297 |
+
|
298 |
+
$freshness = $this->freshness();
|
299 |
+
if ($freshness > 0) :
|
300 |
+
# -- Look up, or create, numeric ID for author
|
301 |
+
$this->post['post_author'] = $this->author_id (
|
302 |
+
FeedWordPress::on_unfamiliar('author', $this->post['named']['unfamiliar']['author'])
|
303 |
+
);
|
304 |
+
|
305 |
+
if (is_null($this->post['post_author'])) :
|
306 |
+
$this->post = NULL;
|
307 |
+
endif;
|
308 |
+
endif;
|
309 |
+
|
310 |
+
if (!$this->filtered() and $freshness > 0) :
|
311 |
+
# -- Look up, or create, numeric ID for categories
|
312 |
+
list($pcats, $ptags) = $this->category_ids (
|
313 |
+
$this->post['named']['category'],
|
314 |
+
FeedWordPress::on_unfamiliar('category', $this->post['named']['unfamiliar']['category']),
|
315 |
+
/*tags_too=*/ true
|
316 |
+
);
|
317 |
+
|
318 |
+
$this->post['post_category'] = $pcats;
|
319 |
+
$this->post['tags_input'] = array_merge($this->post['tags_input'], $ptags);
|
320 |
+
|
321 |
+
if (is_null($this->post['post_category'])) :
|
322 |
+
// filter mode on, no matching categories; drop the post
|
323 |
+
$this->post = NULL;
|
324 |
+
else :
|
325 |
+
// filter mode off or at least one match; now add on the feed and global presets
|
326 |
+
$this->post['post_category'] = array_merge (
|
327 |
+
$this->post['post_category'],
|
328 |
+
$this->category_ids (
|
329 |
+
$this->post['named']['preset/category'],
|
330 |
+
'default'
|
331 |
+
)
|
332 |
+
);
|
333 |
+
|
334 |
+
if (count($this->post['post_category']) < 1) :
|
335 |
+
$this->post['post_category'][] = 1; // Default to category 1 ("Uncategorized" / "General") if nothing else
|
336 |
+
endif;
|
337 |
+
endif;
|
338 |
+
endif;
|
339 |
+
|
340 |
+
if (!$this->filtered() and $freshness > 0) :
|
341 |
+
unset($this->post['named']);
|
342 |
+
$this->post = apply_filters('syndicated_post', $this->post, $this);
|
343 |
+
endif;
|
344 |
+
|
345 |
+
if (!$this->filtered() and $freshness == 2) :
|
346 |
+
// The item has not yet been added. So let's add it.
|
347 |
+
$this->insert_new();
|
348 |
+
$this->add_rss_meta();
|
349 |
+
do_action('post_syndicated_item', $this->wp_id());
|
350 |
+
|
351 |
+
$ret = 'new';
|
352 |
+
elseif (!$this->filtered() and $freshness == 1) :
|
353 |
+
$this->post['ID'] = $this->wp_id();
|
354 |
+
$this->update_existing();
|
355 |
+
$this->add_rss_meta();
|
356 |
+
do_action('update_syndicated_item', $this->wp_id());
|
357 |
+
|
358 |
+
$ret = 'updated';
|
359 |
+
else :
|
360 |
+
$ret = false;
|
361 |
+
endif;
|
362 |
+
|
363 |
+
return $ret;
|
364 |
+
} // function SyndicatedPost::store ()
|
365 |
+
|
366 |
+
function insert_new () {
|
367 |
+
global $wpdb, $wp_db_version;
|
368 |
+
|
369 |
+
$dbpost = $this->normalize_post(/*new=*/ true);
|
370 |
+
if (!is_null($dbpost)) :
|
371 |
+
if ($this->use_api('wp_insert_post')) :
|
372 |
+
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
373 |
+
|
374 |
+
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
375 |
+
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
376 |
+
|
377 |
+
// Kludge to prevent kses filters from stripping the
|
378 |
+
// content of posts when updating without a logged in
|
379 |
+
// user who has `unfiltered_html` capability.
|
380 |
+
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
381 |
+
|
382 |
+
$this->_wp_id = wp_insert_post($dbpost);
|
383 |
+
|
384 |
+
// Turn off ridiculous fucking kludges #1 and #2
|
385 |
+
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
386 |
+
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
387 |
+
|
388 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
389 |
+
|
390 |
+
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
391 |
+
// *still* offers no way to use a guid of your choice,
|
392 |
+
// and munges your post modified timestamp, too.
|
393 |
+
$result = $wpdb->query("
|
394 |
+
UPDATE $wpdb->posts
|
395 |
+
SET
|
396 |
+
guid='{$dbpost['guid']}',
|
397 |
+
post_modified='{$dbpost['post_modified']}',
|
398 |
+
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
399 |
+
WHERE ID='{$this->_wp_id}'
|
400 |
+
");
|
401 |
+
else :
|
402 |
+
# The right way to do this is the above. But, alas,
|
403 |
+
# in earlier versions of WordPress, wp_insert_post has
|
404 |
+
# too much behavior (mainly related to pings) that can't
|
405 |
+
# be overridden. In WordPress 1.5, it's enough of a
|
406 |
+
# resource hog to make PHP segfault after inserting
|
407 |
+
# 50-100 posts. This can get pretty annoying, especially
|
408 |
+
# if you are trying to update your feeds for the first
|
409 |
+
# time.
|
410 |
+
|
411 |
+
$result = $wpdb->query("
|
412 |
+
INSERT INTO $wpdb->posts
|
413 |
+
SET
|
414 |
+
guid = '{$dbpost['guid']}',
|
415 |
+
post_author = '{$dbpost['post_author']}',
|
416 |
+
post_date = '{$dbpost['post_date']}',
|
417 |
+
post_date_gmt = '{$dbpost['post_date_gmt']}',
|
418 |
+
post_content = '{$dbpost['post_content']}',"
|
419 |
+
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
420 |
+
post_title = '{$dbpost['post_title']}',
|
421 |
+
post_name = '{$dbpost['post_name']}',
|
422 |
+
post_modified = '{$dbpost['post_modified']}',
|
423 |
+
post_modified_gmt = '{$dbpost['post_modified_gmt']}',
|
424 |
+
comment_status = '{$dbpost['comment_status']}',
|
425 |
+
ping_status = '{$dbpost['ping_status']}',
|
426 |
+
post_status = '{$dbpost['post_status']}'
|
427 |
+
");
|
428 |
+
$this->_wp_id = $wpdb->insert_id;
|
429 |
+
|
430 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
431 |
+
|
432 |
+
// WordPress 1.5.x - 2.0.x
|
433 |
+
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
434 |
+
|
435 |
+
// Since we are not going through official channels, we need to
|
436 |
+
// manually tell WordPress that we've published a new post.
|
437 |
+
// We need to make sure to do this in order for FeedWordPress
|
438 |
+
// to play well with the staticize-reloaded plugin (something
|
439 |
+
// that a large aggregator website is going to *want* to be
|
440 |
+
// able to use).
|
441 |
+
do_action('publish_post', $this->_wp_id);
|
442 |
+
endif;
|
443 |
+
endif;
|
444 |
+
} /* SyndicatedPost::insert_new() */
|
445 |
+
|
446 |
+
function update_existing () {
|
447 |
+
global $wpdb;
|
448 |
+
|
449 |
+
// Why the fuck doesn't wp_insert_post already do this?
|
450 |
+
$dbpost = $this->normalize_post(/*new=*/ false);
|
451 |
+
if (!is_null($dbpost)) :
|
452 |
+
if ($this->use_api('wp_insert_post')) :
|
453 |
+
$dbpost['post_pingback'] = false; // Tell WP 2.1 and 2.2 not to process for pingbacks
|
454 |
+
|
455 |
+
// This is a ridiculous fucking kludge necessitated by WordPress 2.6 munging authorship meta-data
|
456 |
+
add_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
457 |
+
|
458 |
+
// Kludge to prevent kses filters from stripping the
|
459 |
+
// content of posts when updating without a logged in
|
460 |
+
// user who has `unfiltered_html` capability.
|
461 |
+
add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
462 |
+
|
463 |
+
// Don't munge status fields that the user may have reset manually
|
464 |
+
if (function_exists('get_post_field')) :
|
465 |
+
$doNotMunge = array('post_status', 'comment_status', 'ping_status');
|
466 |
+
foreach ($doNotMunge as $field) :
|
467 |
+
$dbpost[$field] = get_post_field($field, $this->wp_id());
|
468 |
+
endforeach;
|
469 |
+
endif;
|
470 |
+
|
471 |
+
$this->_wp_id = wp_insert_post($dbpost);
|
472 |
+
|
473 |
+
// Turn off ridiculous fucking kludges #1 and #2
|
474 |
+
remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
|
475 |
+
remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
|
476 |
+
|
477 |
+
$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
|
478 |
+
|
479 |
+
// Unfortunately, as of WordPress 2.3, wp_insert_post()
|
480 |
+
// munges your post modified timestamp.
|
481 |
+
$result = $wpdb->query("
|
482 |
+
UPDATE $wpdb->posts
|
483 |
+
SET
|
484 |
+
post_modified='{$dbpost['post_modified']}',
|
485 |
+
post_modified_gmt='{$dbpost['post_modified_gmt']}'
|
486 |
+
WHERE ID='{$this->_wp_id}'
|
487 |
+
");
|
488 |
+
else :
|
489 |
+
|
490 |
+
$result = $wpdb->query("
|
491 |
+
UPDATE $wpdb->posts
|
492 |
+
SET
|
493 |
+
post_author = '{$dbpost['post_author']}',
|
494 |
+
post_content = '{$dbpost['post_content']}',"
|
495 |
+
.(isset($dbpost['post_excerpt']) ? "post_excerpt = '{$dbpost['post_excerpt']}'," : "")."
|
496 |
+
post_title = '{$dbpost['post_title']}',
|
497 |
+
post_name = '{$dbpost['post_name']}',
|
498 |
+
post_modified = '{$dbpost['post_modified']}',
|
499 |
+
post_modified_gmt = '{$dbpost['post_modified_gmt']}'
|
500 |
+
WHERE guid='{$dbpost['guid']}'
|
501 |
+
");
|
502 |
+
|
503 |
+
// WordPress 2.1.x and up
|
504 |
+
if (function_exists('wp_set_post_categories')) :
|
505 |
+
wp_set_post_categories($this->wp_id(), $this->post['post_category']);
|
506 |
+
// WordPress 1.5.x - 2.0.x
|
507 |
+
elseif (function_exists('wp_set_post_cats')) :
|
508 |
+
wp_set_post_cats('1', $this->wp_id(), $this->post['post_category']);
|
509 |
+
// This should never happen.
|
510 |
+
else :
|
511 |
+
FeedWordPress::critical_bug(__CLASS__.'::'.__FUNCTION.'(): no post categorizing function', array("dbpost" => $dbpost, "this" => $this), __LINE__);
|
512 |
+
endif;
|
513 |
+
|
514 |
+
// Since we are not going through official channels, we need to
|
515 |
+
// manually tell WordPress that we've published a new post.
|
516 |
+
// We need to make sure to do this in order for FeedWordPress
|
517 |
+
// to play well with the staticize-reloaded plugin (something
|
518 |
+
// that a large aggregator website is going to *want* to be
|
519 |
+
// able to use).
|
520 |
+
do_action('edit_post', $this->post['ID']);
|
521 |
+
endif;
|
522 |
+
endif;
|
523 |
+
} /* SyndicatedPost::update_existing() */
|
524 |
+
|
525 |
+
/**
|
526 |
+
* SyndicatedPost::normalize_post()
|
527 |
+
*
|
528 |
+
* @param bool $new If true, this post is to be inserted anew. If false, it is an update of an existing post.
|
529 |
+
* @return array A normalized representation of the post ready to be inserted into the database or sent to the WordPress API functions
|
530 |
+
*/
|
531 |
+
function normalize_post ($new = true) {
|
532 |
+
global $wpdb;
|
533 |
+
|
534 |
+
$out = array();
|
535 |
+
|
536 |
+
// Why the fuck doesn't wp_insert_post already do this?
|
537 |
+
foreach ($this->post as $key => $value) :
|
538 |
+
if (is_string($value)) :
|
539 |
+
$out[$key] = $wpdb->escape($value);
|
540 |
+
else :
|
541 |
+
$out[$key] = $value;
|
542 |
+
endif;
|
543 |
+
endforeach;
|
544 |
+
|
545 |
+
if (strlen($out['post_title'].$out['post_content'].$out['post_excerpt']) == 0) :
|
546 |
+
// FIXME: Option for filtering out empty posts
|
547 |
+
endif;
|
548 |
+
if (strlen($out['post_title'])==0) :
|
549 |
+
$offset = (int) get_option('gmt_offset') * 60 * 60;
|
550 |
+
$out['post_title'] =
|
551 |
+
$this->post['meta']['syndication_source']
|
552 |
+
.' '.gmdate('Y-m-d H:i:s', $this->published() + $offset);
|
553 |
+
// FIXME: Option for what to fill a blank title with...
|
554 |
+
endif;
|
555 |
+
|
556 |
+
return $out;
|
557 |
+
}
|
558 |
+
|
559 |
+
/**
|
560 |
+
* SyndicatedPost::validate_post_id()
|
561 |
+
*
|
562 |
+
* @param array $dbpost An array representing the post we attempted to insert or update
|
563 |
+
* @param mixed $ns A string or array representing the namespace (class, method) whence this method was called.
|
564 |
+
*/
|
565 |
+
function validate_post_id ($dbpost, $ns) {
|
566 |
+
if (is_array($ns)) : $ns = implode('::', $ns);
|
567 |
+
else : $ns = (string) $ns; endif;
|
568 |
+
|
569 |
+
// This should never happen.
|
570 |
+
if (!is_numeric($this->_wp_id) or ($this->_wp_id == 0)) :
|
571 |
+
FeedWordPress::critical_bug(
|
572 |
+
/*name=*/ $ns.'::_wp_id',
|
573 |
+
/*var =*/ array(
|
574 |
+
"\$this->_wp_id" => $this->_wp_id,
|
575 |
+
"\$dbpost" => $dbpost,
|
576 |
+
"\$this" => $this
|
577 |
+
),
|
578 |
+
/*line # =*/ __LINE__
|
579 |
+
);
|
580 |
+
endif;
|
581 |
+
} /* SyndicatedPost::validate_post_id() */
|
582 |
+
|
583 |
+
/**
|
584 |
+
* SyndicatedPost::fix_revision_meta() - Fixes the way WP 2.6+ fucks up
|
585 |
+
* meta-data (authorship, etc.) when storing revisions of an updated
|
586 |
+
* syndicated post.
|
587 |
+
*
|
588 |
+
* In their infinite wisdom, the WordPress coders have made it completely
|
589 |
+
* impossible for a plugin that uses wp_insert_post() to set certain
|
590 |
+
* meta-data (such as the author) when you store an old revision of an
|
591 |
+
* updated post. Instead, it uses the WordPress defaults (= currently
|
592 |
+
* active user ID if the process is running with a user logged in, or
|
593 |
+
* = #0 if there is no user logged in). This results in bogus authorship
|
594 |
+
* data for revisions that are syndicated from off the feed, unless we
|
595 |
+
* use a ridiculous kludge like this to end-run the munging of meta-data
|
596 |
+
* by _wp_put_post_revision.
|
597 |
+
*
|
598 |
+
* @param int $revision_id The revision ID to fix up meta-data
|
599 |
+
*/
|
600 |
+
function fix_revision_meta ($revision_id) {
|
601 |
+
global $wpdb;
|
602 |
+
|
603 |
+
$post_author = (int) $this->post['post_author'];
|
604 |
+
|
605 |
+
$revision_id = (int) $revision_id;
|
606 |
+
$wpdb->query("
|
607 |
+
UPDATE $wpdb->posts
|
608 |
+
SET post_author={$this->post['post_author']}
|
609 |
+
WHERE post_type = 'revision' AND ID='$revision_id'
|
610 |
+
");
|
611 |
+
} /* SyndicatedPost::fix_revision_meta () */
|
612 |
+
|
613 |
+
/**
|
614 |
+
* SyndicatedPost::avoid_kses_munge() -- If FeedWordPress is processing
|
615 |
+
* an automatic update, that generally means that wp_insert_post() is
|
616 |
+
* being called under the user credentials of whoever is viewing the
|
617 |
+
* blog at the time -- usually meaning no user at all. But if WordPress
|
618 |
+
* gets a wp_insert_post() when current_user_can('unfiltered_html') is
|
619 |
+
* false, it will run the content of the post through a kses function
|
620 |
+
* that strips out lots of HTML tags -- notably <object> and some others.
|
621 |
+
* This causes problems for syndicating (for example) feeds that contain
|
622 |
+
* YouTube videos. It also produces an unexpected asymmetry between
|
623 |
+
* automatically-initiated updates and updates initiated manually from
|
624 |
+
* the WordPress Dashboard (which are usually initiated under the
|
625 |
+
* credentials of a logged-in admin, and so don't get run through the
|
626 |
+
* kses function). So, to avoid the whole mess, what we do here is
|
627 |
+
* just forcibly disable the kses munging for a single syndicated post,
|
628 |
+
* by restoring the contents of the `post_content` field.
|
629 |
+
*
|
630 |
+
* @param string $content The content of the post, after other filters have gotten to it
|
631 |
+
* @return string The original content of the post, before other filters had a chance to munge it.
|
632 |
+
*/
|
633 |
+
function avoid_kses_munge ($content) {
|
634 |
+
global $wpdb;
|
635 |
+
return $wpdb->escape($this->post['post_content']);
|
636 |
+
}
|
637 |
+
|
638 |
+
// SyndicatedPost::add_rss_meta: adds interesting meta-data to each entry
|
639 |
+
// using the space for custom keys. The set of keys and values to add is
|
640 |
+
// specified by the keys and values of $post['meta']. This is used to
|
641 |
+
// store anything that the WordPress user might want to access from a
|
642 |
+
// template concerning the post's original source that isn't provided
|
643 |
+
// for by standard WP meta-data (i.e., any interesting data about the
|
644 |
+
// syndicated post other than author, title, timestamp, categories, and
|
645 |
+
// guid). It's also used to hook into WordPress's support for
|
646 |
+
// enclosures.
|
647 |
+
function add_rss_meta () {
|
648 |
+
global $wpdb;
|
649 |
+
if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
|
650 |
+
$postId = $this->wp_id();
|
651 |
+
|
652 |
+
// Aggregated posts should NOT send out pingbacks.
|
653 |
+
// WordPress 2.1-2.2 claim you can tell them not to
|
654 |
+
// using $post_pingback, but they don't listen, so we
|
655 |
+
// make sure here.
|
656 |
+
$result = $wpdb->query("
|
657 |
+
DELETE FROM $wpdb->postmeta
|
658 |
+
WHERE post_id='$postId' AND meta_key='_pingme'
|
659 |
+
");
|
660 |
+
|
661 |
+
foreach ( $this->post['meta'] as $key => $values ) :
|
662 |
+
|
663 |
+
$key = $wpdb->escape($key);
|
664 |
+
|
665 |
+
// If this is an update, clear out the old
|
666 |
+
// values to avoid duplication.
|
667 |
+
$result = $wpdb->query("
|
668 |
+
DELETE FROM $wpdb->postmeta
|
669 |
+
WHERE post_id='$postId' AND meta_key='$key'
|
670 |
+
");
|
671 |
+
|
672 |
+
// Allow for either a single value or an array
|
673 |
+
if (!is_array($values)) $values = array($values);
|
674 |
+
foreach ( $values as $value ) :
|
675 |
+
$value = $wpdb->escape($value);
|
676 |
+
$result = $wpdb->query("
|
677 |
+
INSERT INTO $wpdb->postmeta
|
678 |
+
SET
|
679 |
+
post_id='$postId',
|
680 |
+
meta_key='$key',
|
681 |
+
meta_value='$value'
|
682 |
+
");
|
683 |
+
endforeach;
|
684 |
+
endforeach;
|
685 |
+
endif;
|
686 |
+
} /* SyndicatedPost::add_rss_meta () */
|
687 |
+
|
688 |
+
// SyndicatedPost::author_id (): get the ID for an author name from
|
689 |
+
// the feed. Create the author if necessary.
|
690 |
+
function author_id ($unfamiliar_author = 'create') {
|
691 |
+
global $wpdb;
|
692 |
+
|
693 |
+
$a = $this->author();
|
694 |
+
$author = $a['name'];
|
695 |
+
$email = $a['email'];
|
696 |
+
$url = $a['uri'];
|
697 |
+
|
698 |
+
$match_author_by_email = !('yes' == get_option("feedwordpress_do_not_match_author_by_email"));
|
699 |
+
if ($match_author_by_email and !FeedWordPress::is_null_email($email)) :
|
700 |
+
$test_email = $email;
|
701 |
+
else :
|
702 |
+
$test_email = NULL;
|
703 |
+
endif;
|
704 |
+
|
705 |
+
// Never can be too careful...
|
706 |
+
$login = sanitize_user($author, /*strict=*/ true);
|
707 |
+
$login = apply_filters('pre_user_login', $login);
|
708 |
+
|
709 |
+
$nice_author = sanitize_title($author);
|
710 |
+
$nice_author = apply_filters('pre_user_nicename', $nice_author);
|
711 |
+
|
712 |
+
$reg_author = $wpdb->escape(preg_quote($author));
|
713 |
+
$author = $wpdb->escape($author);
|
714 |
+
$email = $wpdb->escape($email);
|
715 |
+
$test_email = $wpdb->escape($test_email);
|
716 |
+
$url = $wpdb->escape($url);
|
717 |
+
|
718 |
+
// Check for an existing author rule....
|
719 |
+
if (isset($this->link->settings['map authors']['name'][strtolower(trim($author))])) :
|
720 |
+
$author_rule = $this->link->settings['map authors']['name'][strtolower(trim($author))];
|
721 |
+
else :
|
722 |
+
$author_rule = NULL;
|
723 |
+
endif;
|
724 |
+
|
725 |
+
// User name is mapped to a particular author. If that author ID exists, use it.
|
726 |
+
if (is_numeric($author_rule) and get_userdata((int) $author_rule)) :
|
727 |
+
$id = (int) $author_rule;
|
728 |
+
|
729 |
+
// User name is filtered out
|
730 |
+
elseif ('filter' == $author_rule) :
|
731 |
+
$id = NULL;
|
732 |
+
|
733 |
+
else :
|
734 |
+
// Check the database for an existing author record that might fit
|
735 |
+
|
736 |
+
#-- WordPress 2.0+
|
737 |
+
if (fwp_test_wp_version(FWP_SCHEMA_HAS_USERMETA)) :
|
738 |
+
|
739 |
+
// First try the user core data table.
|
740 |
+
$id = $wpdb->get_var(
|
741 |
+
"SELECT ID FROM $wpdb->users
|
742 |
+
WHERE
|
743 |
+
TRIM(LCASE(user_login)) = TRIM(LCASE('$login'))
|
744 |
+
OR (
|
745 |
+
LENGTH(TRIM(LCASE(user_email))) > 0
|
746 |
+
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
747 |
+
)
|
748 |
+
OR TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author'))
|
749 |
+
");
|
750 |
+
|
751 |
+
// If that fails, look for aliases in the user meta data table
|
752 |
+
if (is_null($id)) :
|
753 |
+
$id = $wpdb->get_var(
|
754 |
+
"SELECT user_id FROM $wpdb->usermeta
|
755 |
+
WHERE
|
756 |
+
(meta_key = 'description' AND TRIM(LCASE(meta_value)) = TRIM(LCASE('$author')))
|
757 |
+
OR (
|
758 |
+
meta_key = 'description'
|
759 |
+
AND TRIM(LCASE(meta_value))
|
760 |
+
RLIKE CONCAT(
|
761 |
+
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
762 |
+
TRIM(LCASE('$reg_author')),
|
763 |
+
'( |\\t|\\r)*(\\n|\$)'
|
764 |
+
)
|
765 |
+
)
|
766 |
+
");
|
767 |
+
endif;
|
768 |
+
|
769 |
+
#-- WordPress 1.5.x
|
770 |
+
else :
|
771 |
+
$id = $wpdb->get_var(
|
772 |
+
"SELECT ID from $wpdb->users
|
773 |
+
WHERE
|
774 |
+
TRIM(LCASE(user_login)) = TRIM(LCASE('$login')) OR
|
775 |
+
(
|
776 |
+
LENGTH(TRIM(LCASE(user_email))) > 0
|
777 |
+
AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
|
778 |
+
) OR
|
779 |
+
TRIM(LCASE(user_firstname)) = TRIM(LCASE('$author')) OR
|
780 |
+
TRIM(LCASE(user_nickname)) = TRIM(LCASE('$author')) OR
|
781 |
+
TRIM(LCASE(user_nicename)) = TRIM(LCASE('$nice_author')) OR
|
782 |
+
TRIM(LCASE(user_description)) = TRIM(LCASE('$author')) OR
|
783 |
+
(
|
784 |
+
LOWER(user_description)
|
785 |
+
RLIKE CONCAT(
|
786 |
+
'(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*',
|
787 |
+
LCASE('$reg_author'),
|
788 |
+
'( |\\t|\\r)*(\\n|\$)'
|
789 |
+
)
|
790 |
+
)
|
791 |
+
");
|
792 |
+
|
793 |
+
endif;
|
794 |
+
|
795 |
+
// ... if you don't find one, then do what you need to do
|
796 |
+
if (is_null($id)) :
|
797 |
+
if ($unfamiliar_author === 'create') :
|
798 |
+
$userdata = array();
|
799 |
+
|
800 |
+
#-- user table data
|
801 |
+
$userdata['ID'] = NULL; // new user
|
802 |
+
$userdata['user_login'] = $login;
|
803 |
+
$userdata['user_nicename'] = $nice_author;
|
804 |
+
$userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up
|
805 |
+
$userdata['user_email'] = $email;
|
806 |
+
$userdata['user_url'] = $url;
|
807 |
+
$userdata['display_name'] = $author;
|
808 |
+
|
809 |
+
$id = wp_insert_user($userdata);
|
810 |
+
elseif (is_numeric($unfamiliar_author) and get_userdata((int) $unfamiliar_author)) :
|
811 |
+
$id = (int) $unfamiliar_author;
|
812 |
+
elseif ($unfamiliar_author === 'default') :
|
813 |
+
$id = 1;
|
814 |
+
endif;
|
815 |
+
endif;
|
816 |
+
endif;
|
817 |
+
|
818 |
+
if ($id) :
|
819 |
+
$this->link->settings['map authors']['name'][strtolower(trim($author))] = $id;
|
820 |
+
endif;
|
821 |
+
return $id;
|
822 |
+
} // function SyndicatedPost::author_id ()
|
823 |
+
|
824 |
+
// look up (and create) category ids from a list of categories
|
825 |
+
function category_ids ($cats, $unfamiliar_category = 'create', $tags_too = false) {
|
826 |
+
global $wpdb;
|
827 |
+
|
828 |
+
// We need to normalize whitespace because (1) trailing
|
829 |
+
// whitespace can cause PHP and MySQL not to see eye to eye on
|
830 |
+
// VARCHAR comparisons for some versions of MySQL (cf.
|
831 |
+
// <http://dev.mysql.com/doc/mysql/en/char.html>), and (2)
|
832 |
+
// because I doubt most people want to make a semantic
|
833 |
+
// distinction between 'Computers' and 'Computers '
|
834 |
+
$cats = array_map('trim', $cats);
|
835 |
+
|
836 |
+
$tags = array();
|
837 |
+
|
838 |
+
$cat_ids = array ();
|
839 |
+
foreach ($cats as $cat_name) :
|
840 |
+
if (preg_match('/^{#([0-9]+)}$/', $cat_name, $backref)) :
|
841 |
+
$cat_id = (int) $backref[1];
|
842 |
+
if (function_exists('is_term') and is_term($cat_id, 'category')) :
|
843 |
+
$cat_ids[] = $cat_id;
|
844 |
+
elseif (get_category($cat_id)) :
|
845 |
+
$cat_ids[] = $cat_id;
|
846 |
+
endif;
|
847 |
+
elseif (strlen($cat_name) > 0) :
|
848 |
+
$esc = $wpdb->escape($cat_name);
|
849 |
+
$resc = $wpdb->escape(preg_quote($cat_name));
|
850 |
+
|
851 |
+
// WordPress 2.3+
|
852 |
+
if (function_exists('is_term')) :
|
853 |
+
$cat_id = is_term($cat_name, 'category');
|
854 |
+
if ($cat_id) :
|
855 |
+
$cat_ids[] = $cat_id['term_id'];
|
856 |
+
// There must be a better way to do this...
|
857 |
+
elseif ($results = $wpdb->get_results(
|
858 |
+
"SELECT term_id
|
859 |
+
FROM $wpdb->term_taxonomy
|
860 |
+
WHERE
|
861 |
+
LOWER(description) RLIKE
|
862 |
+
CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)')"
|
863 |
+
)) :
|
864 |
+
foreach ($results AS $term) :
|
865 |
+
$cat_ids[] = (int) $term->term_id;
|
866 |
+
endforeach;
|
867 |
+
elseif ('tag'==$unfamiliar_category) :
|
868 |
+
$tags[] = $cat_name;
|
869 |
+
elseif ('create'===$unfamiliar_category) :
|
870 |
+
$term = wp_insert_term($cat_name, 'category');
|
871 |
+
if (is_wp_error($term)) :
|
872 |
+
FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__);
|
873 |
+
else :
|
874 |
+
$cat_ids[] = $term['term_id'];
|
875 |
+
endif;
|
876 |
+
endif;
|
877 |
+
|
878 |
+
// WordPress 1.5.x - 2.2.x
|
879 |
+
else :
|
880 |
+
$results = $wpdb->get_results(
|
881 |
+
"SELECT cat_ID
|
882 |
+
FROM $wpdb->categories
|
883 |
+
WHERE
|
884 |
+
(LOWER(cat_name) = LOWER('$esc'))
|
885 |
+
OR (LOWER(category_description)
|
886 |
+
RLIKE CONCAT('(^|\\n)a\\.?k\\.?a\\.?( |\\t)*:?( |\\t)*', LOWER('{$resc}'), '( |\\t|\\r)*(\\n|\$)'))
|
887 |
+
");
|
888 |
+
if ($results) :
|
889 |
+
foreach ($results as $term) :
|
890 |
+
$cat_ids[] = (int) $term->cat_ID;
|
891 |
+
endforeach;
|
892 |
+
elseif ('create'===$unfamiliar_category) :
|
893 |
+
if (function_exists('wp_insert_category')) :
|
894 |
+
$cat_id = wp_insert_category(array('cat_name' => $cat_name));
|
895 |
+
// And into the database we go.
|
896 |
+
else :
|
897 |
+
$nice_kitty = sanitize_title($cat_name);
|
898 |
+
$wpdb->query(sprintf("
|
899 |
+
INSERT INTO $wpdb->categories
|
900 |
+
SET
|
901 |
+
cat_name='%s',
|
902 |
+
category_nicename='%s'
|
903 |
+
", $wpdb->escape($cat_name), $nice_kitty
|
904 |
+
));
|
905 |
+
$cat_id = $wpdb->insert_id;
|
906 |
+
endif;
|
907 |
+
$cat_ids[] = $cat_id;
|
908 |
+
endif;
|
909 |
+
endif;
|
910 |
+
endif;
|
911 |
+
endforeach;
|
912 |
+
|
913 |
+
if ((count($cat_ids) == 0) and ($unfamiliar_category === 'filter')) :
|
914 |
+
$cat_ids = NULL; // Drop the post
|
915 |
+
else :
|
916 |
+
$cat_ids = array_unique($cat_ids);
|
917 |
+
endif;
|
918 |
+
|
919 |
+
if ($tags_too) : $ret = array($cat_ids, $tags);
|
920 |
+
else : $ret = $cat_ids;
|
921 |
+
endif;
|
922 |
+
|
923 |
+
return $ret;
|
924 |
+
} // function SyndicatedPost::category_ids ()
|
925 |
+
|
926 |
+
function use_api ($tag) {
|
927 |
+
global $wp_db_version;
|
928 |
+
switch ($tag) :
|
929 |
+
case 'wp_insert_post':
|
930 |
+
// Before 2.2, wp_insert_post does too much of the wrong stuff to use it
|
931 |
+
// In 1.5 it was such a resource hog it would make PHP segfault on big updates
|
932 |
+
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_21);
|
933 |
+
break;
|
934 |
+
case 'post_status_pending':
|
935 |
+
$ret = (isset($wp_db_version) and $wp_db_version > FWP_SCHEMA_23);
|
936 |
+
break;
|
937 |
+
endswitch;
|
938 |
+
return $ret;
|
939 |
+
} // function SyndicatedPost::use_api ()
|
940 |
+
|
941 |
+
#### EXTRACT DATA FROM FEED ITEM ####
|
942 |
+
|
943 |
+
function created () {
|
944 |
+
$epoch = null;
|
945 |
+
if (isset($this->item['dc']['created'])) :
|
946 |
+
$epoch = @parse_w3cdtf($this->item['dc']['created']);
|
947 |
+
elseif (isset($this->item['dcterms']['created'])) :
|
948 |
+
$epoch = @parse_w3cdtf($this->item['dcterms']['created']);
|
949 |
+
elseif (isset($this->item['created'])): // Atom 0.3
|
950 |
+
$epoch = @parse_w3cdtf($this->item['created']);
|
951 |
+
endif;
|
952 |
+
return $epoch;
|
953 |
+
}
|
954 |
+
function published ($fallback = true) {
|
955 |
+
$epoch = null;
|
956 |
+
|
957 |
+
# RSS is a fucking mess. Figure out whether we have a date in
|
958 |
+
# <dc:date>, <issued>, <pubDate>, etc., and get it into Unix
|
959 |
+
# epoch format for reformatting. If we can't find anything,
|
960 |
+
# we'll use the last-updated time.
|
961 |
+
if (isset($this->item['dc']['date'])): // Dublin Core
|
962 |
+
$epoch = @parse_w3cdtf($this->item['dc']['date']);
|
963 |
+
elseif (isset($this->item['dcterms']['issued'])) : // Dublin Core extensions
|
964 |
+
$epoch = @parse_w3cdtf($this->item['dcterms']['issued']);
|
965 |
+
elseif (isset($this->item['published'])) : // Atom 1.0
|
966 |
+
$epoch = @parse_w3cdtf($this->item['published']);
|
967 |
+
elseif (isset($this->item['issued'])): // Atom 0.3
|
968 |
+
$epoch = @parse_w3cdtf($this->item['issued']);
|
969 |
+
elseif (isset($this->item['pubdate'])): // RSS 2.0
|
970 |
+
$epoch = strtotime($this->item['pubdate']);
|
971 |
+
elseif ($fallback) : // Fall back to <updated> / <modified> if present
|
972 |
+
$epoch = $this->updated(/*fallback=*/ false);
|
973 |
+
endif;
|
974 |
+
|
975 |
+
# If everything failed, then default to the current time.
|
976 |
+
if (is_null($epoch)) :
|
977 |
+
if (-1 == $default) :
|
978 |
+
$epoch = time();
|
979 |
+
else :
|
980 |
+
$epoch = $default;
|
981 |
+
endif;
|
982 |
+
endif;
|
983 |
+
|
984 |
+
return $epoch;
|
985 |
+
}
|
986 |
+
function updated ($fallback = true, $default = -1) {
|
987 |
+
$epoch = null;
|
988 |
+
|
989 |
+
# As far as I know, only dcterms and Atom have reliable ways to
|
990 |
+
# specify when something was *modified* last. If neither is
|
991 |
+
# available, then we'll try to get the time of publication.
|
992 |
+
if (isset($this->item['dc']['modified'])) : // Not really correct
|
993 |
+
$epoch = @parse_w3cdtf($this->item['dc']['modified']);
|
994 |
+
elseif (isset($this->item['dcterms']['modified'])) : // Dublin Core extensions
|
995 |
+
$epoch = @parse_w3cdtf($this->item['dcterms']['modified']);
|
996 |
+
elseif (isset($this->item['modified'])): // Atom 0.3
|
997 |
+
$epoch = @parse_w3cdtf($this->item['modified']);
|
998 |
+
elseif (isset($this->item['updated'])): // Atom 1.0
|
999 |
+
$epoch = @parse_w3cdtf($this->item['updated']);
|
1000 |
+
elseif ($fallback) : // Fall back to issued / dc:date
|
1001 |
+
$epoch = $this->published(/*fallback=*/ false, /*default=*/ $default);
|
1002 |
+
endif;
|
1003 |
+
|
1004 |
+
# If everything failed, then default to the current time.
|
1005 |
+
if (is_null($epoch)) :
|
1006 |
+
if (-1 == $default) :
|
1007 |
+
$epoch = time();
|
1008 |
+
else :
|
1009 |
+
$epoch = $default;
|
1010 |
+
endif;
|
1011 |
+
endif;
|
1012 |
+
|
1013 |
+
return $epoch;
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
function update_hash () {
|
1017 |
+
return md5(serialize($this->item));
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
function guid () {
|
1021 |
+
$guid = null;
|
1022 |
+
if (isset($this->item['id'])): // Atom 0.3 / 1.0
|
1023 |
+
$guid = $this->item['id'];
|
1024 |
+
elseif (isset($this->item['atom']['id'])) : // Namespaced Atom
|
1025 |
+
$guid = $this->item['atom']['id'];
|
1026 |
+
elseif (isset($this->item['guid'])) : // RSS 2.0
|
1027 |
+
$guid = $this->item['guid'];
|
1028 |
+
elseif (isset($this->item['dc']['identifier'])) :// yeah, right
|
1029 |
+
$guid = $this->item['dc']['identifier'];
|
1030 |
+
else :
|
1031 |
+
// The feed does not seem to have provided us with a
|
1032 |
+
// unique identifier, so we'll have to cobble together
|
1033 |
+
// a tag: URI that might work for us. The base of the
|
1034 |
+
// URI will be the host name of the feed source ...
|
1035 |
+
$bits = parse_url($this->feedmeta['link/uri']);
|
1036 |
+
$guid = 'tag:'.$bits['host'];
|
1037 |
+
|
1038 |
+
// If we have a date of creation, then we can use that
|
1039 |
+
// to uniquely identify the item. (On the other hand, if
|
1040 |
+
// the feed producer was consicentious enough to
|
1041 |
+
// generate dates of creation, she probably also was
|
1042 |
+
// conscientious enough to generate unique identifiers.)
|
1043 |
+
if (!is_null($this->created())) :
|
1044 |
+
$guid .= '://post.'.date('YmdHis', $this->created());
|
1045 |
+
|
1046 |
+
// Otherwise, use both the URI of the item, *and* the
|
1047 |
+
// item's title. We have to use both because titles are
|
1048 |
+
// often not unique, and sometimes links aren't unique
|
1049 |
+
// either (e.g. Bitch (S)HITLIST, Mozilla Dot Org news,
|
1050 |
+
// some podcasts). But it's rare to have *both* the same
|
1051 |
+
// title *and* the same link for two different items. So
|
1052 |
+
// this is about the best we can do.
|
1053 |
+
else :
|
1054 |
+
$guid .= '://'.md5($this->item['link'].'/'.$this->item['title']);
|
1055 |
+
endif;
|
1056 |
+
endif;
|
1057 |
+
return $guid;
|
1058 |
+
}
|
1059 |
+
|
1060 |
+
function author () {
|
1061 |
+
$author = array ();
|
1062 |
+
|
1063 |
+
if (isset($this->item['author_name'])):
|
1064 |
+
$author['name'] = $this->item['author_name'];
|
1065 |
+
elseif (isset($this->item['dc']['creator'])):
|
1066 |
+
$author['name'] = $this->item['dc']['creator'];
|
1067 |
+
elseif (isset($this->item['dc']['contributor'])):
|
1068 |
+
$author['name'] = $this->item['dc']['contributor'];
|
1069 |
+
elseif (isset($this->feed->channel['dc']['creator'])) :
|
1070 |
+
$author['name'] = $this->feed->channel['dc']['creator'];
|
1071 |
+
elseif (isset($this->feed->channel['dc']['contributor'])) :
|
1072 |
+
$author['name'] = $this->feed->channel['dc']['contributor'];
|
1073 |
+
elseif (isset($this->feed->channel['author_name'])) :
|
1074 |
+
$author['name'] = $this->feed->channel['author_name'];
|
1075 |
+
elseif ($this->feed->is_rss() and isset($this->item['author'])) :
|
1076 |
+
// The author element in RSS is allegedly an
|
1077 |
+
// e-mail address, but lots of people don't use
|
1078 |
+
// it that way. So let's make of it what we can.
|
1079 |
+
$author = parse_email_with_realname($this->item['author']);
|
1080 |
+
|
1081 |
+
if (!isset($author['name'])) :
|
1082 |
+
if (isset($author['email'])) :
|
1083 |
+
$author['name'] = $author['email'];
|
1084 |
+
else :
|
1085 |
+
$author['name'] = $this->feed->channel['title'];
|
1086 |
+
endif;
|
1087 |
+
endif;
|
1088 |
+
else :
|
1089 |
+
$author['name'] = $this->feed->channel['title'];
|
1090 |
+
endif;
|
1091 |
+
|
1092 |
+
if (isset($this->item['author_email'])):
|
1093 |
+
$author['email'] = $this->item['author_email'];
|
1094 |
+
elseif (isset($this->feed->channel['author_email'])) :
|
1095 |
+
$author['email'] = $this->feed->channel['author_email'];
|
1096 |
+
endif;
|
1097 |
+
|
1098 |
+
if (isset($this->item['author_url'])):
|
1099 |
+
$author['uri'] = $this->item['author_url'];
|
1100 |
+
elseif (isset($this->feed->channel['author_url'])) :
|
1101 |
+
$author['uri'] = $this->item['author_url'];
|
1102 |
+
else:
|
1103 |
+
$author['uri'] = $this->feed->channel['link'];
|
1104 |
+
endif;
|
1105 |
+
|
1106 |
+
return $author;
|
1107 |
+
} // SyndicatedPost::author()
|
1108 |
+
|
1109 |
+
var $uri_attrs = array (
|
1110 |
+
array('a', 'href'),
|
1111 |
+
array('applet', 'codebase'),
|
1112 |
+
array('area', 'href'),
|
1113 |
+
array('blockquote', 'cite'),
|
1114 |
+
array('body', 'background'),
|
1115 |
+
array('del', 'cite'),
|
1116 |
+
array('form', 'action'),
|
1117 |
+
array('frame', 'longdesc'),
|
1118 |
+
array('frame', 'src'),
|
1119 |
+
array('iframe', 'longdesc'),
|
1120 |
+
array('iframe', 'src'),
|
1121 |
+
array('head', 'profile'),
|
1122 |
+
array('img', 'longdesc'),
|
1123 |
+
array('img', 'src'),
|
1124 |
+
array('img', 'usemap'),
|
1125 |
+
array('input', 'src'),
|
1126 |
+
array('input', 'usemap'),
|
1127 |
+
array('ins', 'cite'),
|
1128 |
+
array('link', 'href'),
|
1129 |
+
array('object', 'classid'),
|
1130 |
+
array('object', 'codebase'),
|
1131 |
+
array('object', 'data'),
|
1132 |
+
array('object', 'usemap'),
|
1133 |
+
array('q', 'cite'),
|
1134 |
+
array('script', 'src')
|
1135 |
+
); /* var SyndicatedPost::$uri_attrs */
|
1136 |
+
|
1137 |
+
var $_base = null;
|
1138 |
+
|
1139 |
+
function resolve_single_relative_uri ($refs) {
|
1140 |
+
$tag = FeedWordPressHTML::attributeMatch($refs);
|
1141 |
+
$url = Relative_URI::resolve($tag['value'], $this->_base);
|
1142 |
+
return $tag['prefix'] . $url . $tag['suffix'];
|
1143 |
+
} /* function SyndicatedPost::resolve_single_relative_uri() */
|
1144 |
+
|
1145 |
+
function resolve_relative_uris ($content, $obj) {
|
1146 |
+
# The MagpieRSS upgrade has some `xml:base` support baked in.
|
1147 |
+
# However, sometimes people do silly things, like putting
|
1148 |
+
# relative URIs out on a production RSS 2.0 feed or other feeds
|
1149 |
+
# with no good support for `xml:base`. So we'll do our best to
|
1150 |
+
# try to catch any remaining relative URIs and resolve them as
|
1151 |
+
# best we can.
|
1152 |
+
$obj->_base = $obj->item['link']; // Reset the base for resolving relative URIs
|
1153 |
+
|
1154 |
+
foreach ($obj->uri_attrs as $pair) :
|
1155 |
+
list($tag, $attr) = $pair;
|
1156 |
+
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
1157 |
+
$content = preg_replace_callback (
|
1158 |
+
$pattern,
|
1159 |
+
array(&$obj, 'resolve_single_relative_uri'),
|
1160 |
+
$content
|
1161 |
+
);
|
1162 |
+
endforeach;
|
1163 |
+
|
1164 |
+
return $content;
|
1165 |
+
} /* function SyndicatedPost::resolve_relative_uris () */
|
1166 |
+
|
1167 |
+
var $strip_attrs = array (
|
1168 |
+
array('[a-z]+', 'target'),
|
1169 |
+
// array('[a-z]+', 'style'),
|
1170 |
+
// array('[a-z]+', 'on[a-z]+'),
|
1171 |
+
);
|
1172 |
+
|
1173 |
+
function strip_attribute_from_tag ($refs) {
|
1174 |
+
$tag = FeedWordPressHTML::attributeMatch($refs);
|
1175 |
+
return $tag['before_attribute'].$tag['after_attribute'];
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
function sanitize_content ($content, $obj) {
|
1179 |
+
# This kind of sucks. I intend to replace it with
|
1180 |
+
# lib_filter sometime soon.
|
1181 |
+
foreach ($obj->strip_attrs as $pair):
|
1182 |
+
list($tag,$attr) = $pair;
|
1183 |
+
$pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
|
1184 |
+
|
1185 |
+
$content = preg_replace_callback (
|
1186 |
+
$pattern,
|
1187 |
+
array(&$obj, 'strip_attribute_from_tag'),
|
1188 |
+
$content
|
1189 |
+
);
|
1190 |
+
endforeach;
|
1191 |
+
return $content;
|
1192 |
+
}
|
1193 |
+
} // class SyndicatedPost
|
1194 |
+
|
syndication.php
CHANGED
@@ -58,6 +58,23 @@ else :
|
|
58 |
define('FWP_SYNDICATE_NEW', 'Syndicate »');
|
59 |
endif;
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
function fwp_dashboard_update_if_requested () {
|
62 |
global $wpdb;
|
63 |
|
@@ -173,32 +190,38 @@ if ($cont):
|
|
173 |
endif;
|
174 |
|
175 |
if (fwp_test_wp_version(FWP_SCHEMA_27)) :
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
$('.meta-box-sortables').sortable('destroy');
|
183 |
-
|
184 |
-
postboxes.add_postbox_toggles('feedwordpress_syndication');
|
185 |
-
} );
|
186 |
-
</script>
|
187 |
-
<?php
|
188 |
echo "<form style='display: none' method='get' action=''>\n<p>\n";
|
189 |
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
|
190 |
wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
|
191 |
echo "</p>\n</form>\n";
|
192 |
|
193 |
if ($links) :
|
194 |
-
add_meta_box(
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
endif;
|
196 |
-
add_meta_box(
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
?>
|
198 |
<div class="metabox-holder">
|
199 |
-
<div id="
|
200 |
<?php
|
201 |
-
do_meta_boxes('
|
202 |
else :
|
203 |
if ($links): // only display Update panel if there are some links to update....
|
204 |
fwp_syndication_manage_page_update_box();
|
58 |
define('FWP_SYNDICATE_NEW', 'Syndicate »');
|
59 |
endif;
|
60 |
|
61 |
+
function feedwordpress_syndication_toggles () {
|
62 |
+
?>
|
63 |
+
<script type="text/javascript">
|
64 |
+
jQuery(document).ready( function($) {
|
65 |
+
// In case someone got here first.
|
66 |
+
$('.postbox h3, .postbox .handlediv').unbind('click');
|
67 |
+
$('.postbox h3 a').unbind('click');
|
68 |
+
$('.hide-postbox-tog').unbind('click');
|
69 |
+
$('.columns-prefs input[type="radio"]').unbind('click');
|
70 |
+
$('.meta-box-sortables').sortable('destroy');
|
71 |
+
|
72 |
+
postboxes.add_postbox_toggles('feedwordpresssyndication');
|
73 |
+
} );
|
74 |
+
</script>
|
75 |
+
<?php
|
76 |
+
}
|
77 |
+
|
78 |
function fwp_dashboard_update_if_requested () {
|
79 |
global $wpdb;
|
80 |
|
190 |
endif;
|
191 |
|
192 |
if (fwp_test_wp_version(FWP_SCHEMA_27)) :
|
193 |
+
if (fwp_test_wp_version(FWP_SCHEMA_27, FWP_SCHEMA_28)) :
|
194 |
+
$hook_it = 'admin_footer';
|
195 |
+
else : // WordPress 2.8+
|
196 |
+
$hook_it = 'admin_footer-feedwordpress/syndication.php';
|
197 |
+
endif;
|
198 |
+
add_action($hook_it, 'feedwordpress_syndication_toggles', /*priority=*/ 10000);
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
echo "<form style='display: none' method='get' action=''>\n<p>\n";
|
200 |
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
|
201 |
wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
|
202 |
echo "</p>\n</form>\n";
|
203 |
|
204 |
if ($links) :
|
205 |
+
add_meta_box(
|
206 |
+
/*id=*/ 'feedwordpress_update_box',
|
207 |
+
/*title=*/ __('Update feeds now'),
|
208 |
+
/*callback=*/ 'fwp_syndication_manage_page_update_box',
|
209 |
+
/*page=*/ 'feedwordpresssyndication',
|
210 |
+
/*context =*/ 'feedwordpresssyndication'
|
211 |
+
);
|
212 |
endif;
|
213 |
+
add_meta_box(
|
214 |
+
/*id=*/ 'feedwordpress_feeds_box',
|
215 |
+
/*title=*/ __('Syndicated sources'),
|
216 |
+
/*callback=*/ 'fwp_syndication_manage_page_links_box',
|
217 |
+
/*page=*/ 'feedwordpresssyndication',
|
218 |
+
/*context =*/ 'feedwordpresssyndication'
|
219 |
+
);
|
220 |
?>
|
221 |
<div class="metabox-holder">
|
222 |
+
<div id="feedwordpresssyndication-sortables" class="meta-box-sortables ui-sortable">
|
223 |
<?php
|
224 |
+
do_meta_boxes('feedwordpresssyndication', 'feedwordpresssyndication', NULL);
|
225 |
else :
|
226 |
if ($links): // only display Update panel if there are some links to update....
|
227 |
fwp_syndication_manage_page_update_box();
|