FeedWordPress - Version 2012.1212

Version Description

  • WORDPRESS 3.5 COMPATIBILITY: This release has been tested for compatibility with new releases of WordPress, up to version 3.5, and any documented compatibility issues have been cleared -- in particular, if you were seeing error pages stating that you don't have permission to access the FeedWordPress Syndication page within the WordPress admin interface, then upgrading to this release should fix the problem.

    As always, if you encounter any compatibility problems after upgrading your version of WordPress and your version of FeedWordPress to the most recent versions, please contact me with as detailed a description as possible of the issue you are encountering, the circumstances you're encountering it under, what you expect to see happening, and what is happening instead.

  • PHP 5.4 COMPATIBILITY: This release has been audited to fix potential problems with deprecation notices or fatal errors under recent versions of PHP. In particular, all uses of run-time pass-by-reference have been eliminated from the code; if you were seeing a fatal error reading "Call-time pass-by-reference has been removed ..." then upgrading to this release should fix the problem.

  • CUSTOMIZATION FRAMEWORK: A great deal of work has been done to make the underlying framework more flexible, so that PHP add-ons can be written to adapt FeedWordPress to handle custom XML vocabularies, expiration of posts under specified conditions, and other custom behavior.

  • BUGFIX: MANUALLY EDITED POST SLUGS NOT OVERWRITTEN. Thanks to a report by Chris Fritz, I've identified some code that causes post slugs for the posts generated by FWP to be rewritten with every update, even if the user has manually updated the slug from within the WordPress editing interface. This has been fixed: FWP will continue to generate new slugs for syndicated posts, but when syndicated posts are updated, they will retain the slug that they had at the time of the update; any manual changes to the post slug should be preserved.

  • USER-AGENT STRING: FeedWordPress now sends a distinctive User-Agent string identifying itself, and noting that it is a feed aggregator.

  • MISCELLANEOUS PERFORMANCE IMPROVEMENTS: A number of changes have been made to try to reduce the intensity and expense in terms of both database performance and web server memory consumption.

  • DIAGNOSTICS IMPROVEMENTS: A number of new and improved diagnostics have been added which should aid in understanding and troubleshooting issues that may arise.

Download this release

Release Info

Developer radgeek
Plugin Icon wp plugin FeedWordPress
Version 2012.1212
Comparing to
See all releases

Code changes from version 2011.1019 to 2012.1212

admin-ui.php CHANGED
@@ -50,7 +50,7 @@ class FeedWordPressAdminPage {
50
  elseif ($this->save_requested_in($post)) : // User mashed Save Changes
51
  $this->save_settings($post);
52
  endif;
53
- do_action($this->dispatch.'_post', &$post, &$this);
54
  }
55
 
56
  function update_feed () {
@@ -81,7 +81,7 @@ class FeedWordPressAdminPage {
81
  }
82
 
83
  function save_settings ($post) {
84
- do_action($this->dispatch.'_save', &$post, &$this);
85
 
86
  if ($this->for_feed_settings()) :
87
  // Save settings
@@ -257,7 +257,7 @@ class FeedWordPressAdminPage {
257
  "Feed" => array('page' => 'feeds-page.php', 'long' => 'Feeds & Updates'),
258
  "Posts" => array('page' => 'posts-page.php', 'long' => 'Posts & Links'),
259
  "Authors" => array('page' => 'authors-page.php', 'long' => 'Authors'),
260
- 'Categories' => array('page' => 'categories-page.php', 'long' => 'Categories'.FEEDWORDPRESS_AND_TAGS),
261
  );
262
 
263
  $hrefPrefix = 'admin.php?';
@@ -444,7 +444,7 @@ class FeedWordPressAdminPage {
444
  add_meta_box(
445
  /*id=*/ $id,
446
  /*title=*/ $title,
447
- /*callback=*/ array(&$this, $method),
448
  /*page=*/ $this->meta_box_context(),
449
  /*context=*/ $this->meta_box_context()
450
  );
@@ -1118,8 +1118,17 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible =
1118
  endif;
1119
 
1120
  // Prep: get last error timestamp, if any
 
1121
  if (is_null($sLink->setting('update/error'))) :
1122
  $errorsSince = '';
 
 
 
 
 
 
 
 
1123
  else :
1124
  $trClass[] = 'feed-error';
1125
 
@@ -1173,6 +1182,11 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible =
1173
  endif;
1174
  $nextUpdate .= "</div></div>";
1175
 
 
 
 
 
 
1176
  unset($sLink);
1177
 
1178
  $alt_row = !$alt_row;
@@ -1221,6 +1235,7 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible =
1221
  <input type="submit" class="button" name="update_uri[<?php print esc_html($link->link_rss); ?>]" value="<?php _e('Update Now'); ?>" />
1222
  </div>
1223
  <?php print $lastUpdated; ?>
 
1224
  <?php print $errorsSince; ?>
1225
  <?php print $nextUpdate; ?>
1226
  </td>
50
  elseif ($this->save_requested_in($post)) : // User mashed Save Changes
51
  $this->save_settings($post);
52
  endif;
53
+ do_action($this->dispatch.'_post', $post, $this);
54
  }
55
 
56
  function update_feed () {
81
  }
82
 
83
  function save_settings ($post) {
84
+ do_action($this->dispatch.'_save', $post, $this);
85
 
86
  if ($this->for_feed_settings()) :
87
  // Save settings
257
  "Feed" => array('page' => 'feeds-page.php', 'long' => 'Feeds & Updates'),
258
  "Posts" => array('page' => 'posts-page.php', 'long' => 'Posts & Links'),
259
  "Authors" => array('page' => 'authors-page.php', 'long' => 'Authors'),
260
+ 'Categories' => array('page' => 'categories-page.php', 'long' => 'Categories & Tags'),
261
  );
262
 
263
  $hrefPrefix = 'admin.php?';
444
  add_meta_box(
445
  /*id=*/ $id,
446
  /*title=*/ $title,
447
+ /*callback=*/ array($this, $method),
448
  /*page=*/ $this->meta_box_context(),
449
  /*context=*/ $this->meta_box_context()
450
  );
1118
  endif;
1119
 
1120
  // Prep: get last error timestamp, if any
1121
+ $fileSizeLines = array();
1122
  if (is_null($sLink->setting('update/error'))) :
1123
  $errorsSince = '';
1124
+ if (!is_null($sLink->setting('link/item count'))) :
1125
+ $N = $sLink->setting('link/item count');
1126
+ $fileSizeLines[] = sprintf((($N==1) ? __('%d item') : __('%d items')), $N);
1127
+ endif;
1128
+
1129
+ if (!is_null($sLink->setting('link/filesize'))) :
1130
+ $fileSizeLines[] = size_format($sLink->setting('link/filesize')). ' total';
1131
+ endif;
1132
  else :
1133
  $trClass[] = 'feed-error';
1134
 
1182
  endif;
1183
  $nextUpdate .= "</div></div>";
1184
 
1185
+ $fileSize = '';
1186
+ if (count($fileSizeLines) > 0) :
1187
+ $fileSize = '<div>'.implode(" / ", $fileSizeLines)."</div>";
1188
+ endif;
1189
+
1190
  unset($sLink);
1191
 
1192
  $alt_row = !$alt_row;
1235
  <input type="submit" class="button" name="update_uri[<?php print esc_html($link->link_rss); ?>]" value="<?php _e('Update Now'); ?>" />
1236
  </div>
1237
  <?php print $lastUpdated; ?>
1238
+ <?php print $fileSize; ?>
1239
  <?php print $errorsSince; ?>
1240
  <?php print $nextUpdate; ?>
1241
  </td>
categories-page.php CHANGED
@@ -10,9 +10,9 @@ class FeedWordPressCategoriesPage extends FeedWordPressAdminPage {
10
  FeedWordPressAdminPage::FeedWordPressAdminPage('feedwordpresscategories', $link);
11
  $this->dispatch = 'feedwordpress_admin_page_categories';
12
  $this->pagenames = array(
13
- 'default' => 'Categories'.FEEDWORDPRESS_AND_TAGS,
14
- 'settings-update' => 'Syndicated Categories'.FEEDWORDPRESS_AND_TAGS,
15
- 'open-sheet' => 'Categories'.FEEDWORDPRESS_AND_TAGS,
16
  );
17
  $this->filename = __FILE__;
18
  }
@@ -599,12 +599,9 @@ blank.</p></td>
599
  ////////////////////////////////////////////////
600
 
601
  $this->boxes_by_methods = array(
602
- 'feed_categories_box' => __('Feed Categories'.FEEDWORDPRESS_AND_TAGS),
603
  'categories_box' => array('title' => __('Categories'), 'id' => 'categorydiv'),
604
  );
605
- if (!FeedWordPressCompatibility::post_tags()) :
606
- unset($this->boxes_by_methods['tags_box']);
607
- endif;
608
 
609
  parent::display();
610
  }
10
  FeedWordPressAdminPage::FeedWordPressAdminPage('feedwordpresscategories', $link);
11
  $this->dispatch = 'feedwordpress_admin_page_categories';
12
  $this->pagenames = array(
13
+ 'default' => 'Categories & Tags',
14
+ 'settings-update' => 'Syndicated Categories & Tags',
15
+ 'open-sheet' => 'Categories & Tags',
16
  );
17
  $this->filename = __FILE__;
18
  }
599
  ////////////////////////////////////////////////
600
 
601
  $this->boxes_by_methods = array(
602
+ 'feed_categories_box' => __('Feed Categories & Tags'),
603
  'categories_box' => array('title' => __('Categories'), 'id' => 'categorydiv'),
604
  );
 
 
 
605
 
606
  parent::display();
607
  }
compatability.php CHANGED
@@ -69,10 +69,6 @@ class FeedWordPressCompatibility {
69
  return $cat_id;
70
  } /* FeedWordPressCompatibility::link_category_id () */
71
 
72
- /*static*/ function post_tags () {
73
- return FeedWordPressCompatibility::test_version(FWP_SCHEMA_23);
74
- } /* FeedWordPressCompatibility::post_tags () */
75
-
76
  /*static*/ function validate_http_request ($action = -1, $capability = null) {
77
  // Only worry about this if we're using a method with significant side-effects
78
  if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') :
@@ -102,47 +98,11 @@ class FeedWordPressCompatibility {
102
  /*static*/ function bottom_script_hook ($filename) {
103
  global $fwp_path;
104
 
105
- $hook = 'admin_footer';
106
- if (FeedWordPressCompatibility::test_version(FWP_SCHEMA_28)) : // WordPress 2.8+
107
- $hook = $hook . '-' . $fwp_path . '/' . basename($filename);
108
- endif;
109
  return $hook;
110
  } /* FeedWordPressCompatibility::bottom_script_hook() */
111
  } /* class FeedWordPressCompatibility */
112
 
113
- define('FEEDWORDPRESS_AND_TAGS', (FeedWordPressCompatibility::post_tags() ? ' & Tags' : ''));
114
-
115
- if (!function_exists('stripslashes_deep')) {
116
- function stripslashes_deep($value) {
117
- $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
118
- return $value;
119
- }
120
- }
121
-
122
- if (!function_exists('sanitize_user')) {
123
- function sanitize_user ($text, $strict = false) {
124
- return $text; // Don't munge it if it wasn't munged going in...
125
- }
126
- }
127
-
128
- if (!function_exists('disabled')) {
129
- /**
130
- * Outputs the html disabled attribute.
131
- *
132
- * Compares the first two arguments and if identical marks as disabled
133
- *
134
- * @since 3.0.0
135
- *
136
- * @param mixed $disabled One of the values to compare
137
- * @param mixed $current (true) The other value to compare if not just true
138
- * @param bool $echo Whether to echo or just return the string
139
- * @return string html attribute or empty string
140
- */
141
- function disabled( $disabled, $current = true, $echo = true ) {
142
- return __checked_selected_helper( $disabled, $current, $echo, 'disabled' );
143
- }
144
- } /* if */
145
-
146
  // Compat
147
 
148
  if (!function_exists('set_post_field')) {
@@ -175,13 +135,6 @@ if (!function_exists('set_post_field')) {
175
 
176
  } /* if */
177
 
178
- if (!function_exists('term_exists')) {
179
- // Fucking WordPress 3.0 wordsmithing.
180
- function term_exists ( $term, $taxonomy = '', $parent = 0 ) {
181
- return is_term($term, $taxonomy, $parent);
182
- }
183
- } /* if */
184
-
185
  require_once(dirname(__FILE__).'/feedwordpress-walker-category-checklist.class.php');
186
 
187
  function fwp_category_checklist ($post_id = 0, $descendents_and_self = 0, $selected_cats = false, $params = array()) {
69
  return $cat_id;
70
  } /* FeedWordPressCompatibility::link_category_id () */
71
 
 
 
 
 
72
  /*static*/ function validate_http_request ($action = -1, $capability = null) {
73
  // Only worry about this if we're using a method with significant side-effects
74
  if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') :
98
  /*static*/ function bottom_script_hook ($filename) {
99
  global $fwp_path;
100
 
101
+ $hook = 'admin_footer-'.$fwp_path.'/'.basename($filename);
 
 
 
102
  return $hook;
103
  } /* FeedWordPressCompatibility::bottom_script_hook() */
104
  } /* class FeedWordPressCompatibility */
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  // Compat
107
 
108
  if (!function_exists('set_post_field')) {
135
 
136
  } /* if */
137
 
 
 
 
 
 
 
 
138
  require_once(dirname(__FILE__).'/feedwordpress-walker-category-checklist.class.php');
139
 
140
  function fwp_category_checklist ($post_id = 0, $descendents_and_self = 0, $selected_cats = false, $params = array()) {
diagnostics-page.php CHANGED
@@ -7,6 +7,9 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
7
  FeedWordPressAdminPage::FeedWordPressAdminPage('feedwordpressdiagnosticspage');
8
  $this->dispatch = 'feedwordpress_diagnostics';
9
  $this->filename = __FILE__;
 
 
 
10
  }
11
 
12
  function has_link () { return false; }
@@ -42,6 +45,7 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
42
  'info_box' => __('Diagnostic Information'),
43
  'diagnostics_box' => __('Display Diagnostics'),
44
  'updates_box' => __('Updates'),
 
45
  );
46
 
47
  foreach ($boxes_by_methods as $method => $title) :
@@ -68,7 +72,8 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
68
 
69
  function accept_POST ($post) {
70
  if (isset($post['submit'])
71
- or isset($post['save'])) :
 
72
  update_option('feedwordpress_debug', $post['feedwordpress_debug']);
73
  update_option('feedwordpress_secret_key', $post['feedwordpress_secret_key']);
74
 
@@ -102,6 +107,12 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
102
  delete_option('feedwordpress_diagnostics_email_destination');
103
  endif;
104
 
 
 
 
 
 
 
105
  $this->updated = true; // Default update message
106
  endif;
107
  } /* FeedWordPressDiagnosticsPage::accept_POST () */
@@ -242,6 +253,7 @@ testing but absolutely inappropriate for a production server.</p>
242
  'updated_feeds' => 'as each feed is checked for updates',
243
  'updated_feeds:errors:persistent' => 'when attempts to update a feed have resulted in errors</label> <label>for at least <input type="number" min="1" max="360" step="1" name="diagnostics_persistent_error_hours" value="'.$hours.'" /> hours',
244
  'updated_feeds:errors' => 'any time FeedWordPress encounters any errors while checking a feed for updates',
 
245
  'syndicated_posts' => 'as each syndicated post is added to the database',
246
  'feed_items' => 'as each syndicated item is considered on the feed',
247
  'memory_usage' => 'indicating how much memory was used',
@@ -252,6 +264,7 @@ testing but absolutely inappropriate for a production server.</p>
252
  'syndicated_posts:meta_data' => 'as syndication meta-data is added on the post',
253
  ),
254
  'Advanced Diagnostics' => array(
 
255
  'feed_items:freshness:sql' => 'when FeedWordPress issues the SQL query it uses to decide whether to treat items as new, updates, or duplicates',
256
  'syndicated_posts:static_meta_data' => 'providing meta-data about syndicated posts in the Edit Posts interface',
257
  ),
@@ -289,6 +302,101 @@ testing but absolutely inappropriate for a production server.</p>
289
  </table>
290
  <?php
291
  } /* FeedWordPressDiagnosticsPage::updates_box () */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  } /* class FeedWordPressDiagnosticsPage */
293
 
294
  $diagnosticsPage = new FeedWordPressDiagnosticsPage;
7
  FeedWordPressAdminPage::FeedWordPressAdminPage('feedwordpressdiagnosticspage');
8
  $this->dispatch = 'feedwordpress_diagnostics';
9
  $this->filename = __FILE__;
10
+
11
+ $this->test_html = array();
12
+ add_action('feedwordpress_diagnostics_do_http_test', array($this, 'do_http_test'), 10, 1);
13
  }
14
 
15
  function has_link () { return false; }
45
  'info_box' => __('Diagnostic Information'),
46
  'diagnostics_box' => __('Display Diagnostics'),
47
  'updates_box' => __('Updates'),
48
+ 'tests_box' => __('Diagnostic Tests'),
49
  );
50
 
51
  foreach ($boxes_by_methods as $method => $title) :
72
 
73
  function accept_POST ($post) {
74
  if (isset($post['submit'])
75
+ or isset($post['save'])
76
+ or isset($post['feedwordpress_diagnostics_do'])) :
77
  update_option('feedwordpress_debug', $post['feedwordpress_debug']);
78
  update_option('feedwordpress_secret_key', $post['feedwordpress_secret_key']);
79
 
107
  delete_option('feedwordpress_diagnostics_email_destination');
108
  endif;
109
 
110
+ if (isset($post['feedwordpress_diagnostics_do'])) :
111
+ foreach ($post['feedwordpress_diagnostics_do'] as $do => $value) :
112
+ do_action('feedwordpress_diagnostics_do_'.$do, $post);
113
+ endforeach;
114
+ endif;
115
+
116
  $this->updated = true; // Default update message
117
  endif;
118
  } /* FeedWordPressDiagnosticsPage::accept_POST () */
253
  'updated_feeds' => 'as each feed is checked for updates',
254
  'updated_feeds:errors:persistent' => 'when attempts to update a feed have resulted in errors</label> <label>for at least <input type="number" min="1" max="360" step="1" name="diagnostics_persistent_error_hours" value="'.$hours.'" /> hours',
255
  'updated_feeds:errors' => 'any time FeedWordPress encounters any errors while checking a feed for updates',
256
+ 'updated_feeds:http' => "displaying the raw HTTP data passed to and from the feed being checked for updates",
257
  'syndicated_posts' => 'as each syndicated post is added to the database',
258
  'feed_items' => 'as each syndicated item is considered on the feed',
259
  'memory_usage' => 'indicating how much memory was used',
264
  'syndicated_posts:meta_data' => 'as syndication meta-data is added on the post',
265
  ),
266
  'Advanced Diagnostics' => array(
267
+ 'feed_items:freshness:reasons' => 'explaining the reason that a post was treated as an update to an existing post',
268
  'feed_items:freshness:sql' => 'when FeedWordPress issues the SQL query it uses to decide whether to treat items as new, updates, or duplicates',
269
  'syndicated_posts:static_meta_data' => 'providing meta-data about syndicated posts in the Edit Posts interface',
270
  ),
302
  </table>
303
  <?php
304
  } /* FeedWordPressDiagnosticsPage::updates_box () */
305
+
306
+ function tests_box ($page, $box = NULL) {
307
+ ?>
308
+ <script type="text/javascript">
309
+ function clone_http_test_args_keyvalue_prototype () {
310
+ var next = jQuery('#http-test-args').find('.http-test-args-keyvalue').length;
311
+ var newRow = jQuery('#http-test-args-keyvalue-prototype').clone().attr('id', 'http-test-args-keyvalue-' + next);
312
+ newRow.find('.http_test_args_key').attr('name', 'http_test_args_key['+next+']').val('');
313
+ newRow.find('.http_test_args_value').attr('name', 'http_test_args_value['+next+']').val('');
314
+
315
+ newRow.appendTo('#http-test-args');
316
+ return false;
317
+ }
318
+ </script>
319
+
320
+ <table class="edit-form">
321
+ <tr>
322
+ <th scope="row">HTTP:</th>
323
+ <td><div><input type="url" name="http_test_url" value="" placeholder="http://www.example.com/" size="127" style="width: 80%; max-width: 80.0em;" />
324
+ <input type="submit" name="feedwordpress_diagnostics_do[http_test]" value="Test &raquo;" /></div>
325
+ <div><select name="http_test_method" size="1">
326
+ <option value="wp_remote_request">wp_remote_request</option>
327
+ <option value="FeedWordPress_File">FeedWordPress_File</option>
328
+ </select></div>
329
+ <table>
330
+ <tr>
331
+ <td>
332
+ <div id="http-test-args">
333
+ <div id="http-test-args-keyvalue-prototype" class="http-test-args-keyvalue"><label>Args:
334
+ <input type="text" class='http_test_args_key' name="http_test_args_key[0]" value="" placeholder="key" /></label>
335
+ <label>= <input type="text" class='http_test_args_value' name="http_test_args_value[0]" value="" placeholder="value" /></label>
336
+ </div>
337
+ </div>
338
+ </td>
339
+ <td><a href="#http-test-args" onclick="return clone_http_test_args_keyvalue_prototype();">+ Add</a></td>
340
+ </tr>
341
+ </table>
342
+
343
+ <?php if (isset($page->test_html['http_test'])) : ?>
344
+ <div style="position: relative">
345
+ <div style="width: 100%; overflow: scroll; background-color: #eed">
346
+ <pre style="white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -o-pre-wrap;"><?php print $page->test_html['http_test']; ?></pre>
347
+ </div>
348
+ </div>
349
+ <?php endif; ?>
350
+ </td>
351
+ </tr>
352
+ </table>
353
+
354
+ <?php
355
+ } /* FeedWordPressDiagnosticsPage::tests_box () */
356
+
357
+ var $test_html;
358
+ function do_http_test ($post) {
359
+ if (isset($post['http_test_url']) and isset($post['http_test_method'])) :
360
+ $url = $post['http_test_url'];
361
+
362
+ $args = array();
363
+ if (isset($post['http_test_args_key'])) :
364
+ foreach ($post['http_test_args_key'] as $idx => $name) :
365
+ $name = trim($name);
366
+ if (strlen($name) > 0) :
367
+ $value = NULL;
368
+ if (isset($post['http_test_args_value'])
369
+ and isset($post['http_test_args_value'][$idx])) :
370
+ $value = $post['http_test_args_value'][$idx];
371
+ endif;
372
+
373
+ if (preg_match('/^javascript:(.*)$/i', $value, $refs)) :
374
+ if (function_exists('json_decode')) :
375
+ $json_value = json_decode($refs[1]);
376
+ if (!is_null($json_value)) :
377
+ $value = $json_value;
378
+ endif;
379
+ endif;
380
+ endif;
381
+
382
+ $args[$name] = $value;
383
+ endif;
384
+ endforeach;
385
+ endif;
386
+
387
+ switch ($post['http_test_method']) :
388
+ case 'wp_remote_request' :
389
+ $out = wp_remote_request($url, $args);
390
+ break;
391
+ case 'FeedWordPress_File' :
392
+ $out = new FeedWordPress_File($url);
393
+ break;
394
+ endswitch;
395
+
396
+ $this->test_html['http_test'] = esc_html(FeedWordPress::val($out));
397
+ endif;
398
+ } /* FeedWordPressDiagnosticsPage::do_http_test () */
399
+
400
  } /* class FeedWordPressDiagnosticsPage */
401
 
402
  $diagnosticsPage = new FeedWordPressDiagnosticsPage;
feeds-page.php CHANGED
@@ -111,7 +111,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
111
  'global_feeds_box' => __('Update Scheduling'),
112
  'updated_posts_box' => __('Updated Posts'),
113
  'custom_settings_box' => __('Custom Feed Settings (for use in templates)'),
114
- 'fetch_settings_box' => __('Settings for Fetching Feeds (Advanced)'),
115
  );
116
  if ($this->for_default_settings()) :
117
  unset($this->boxes_by_methods['custom_settings_box']);
@@ -265,13 +265,13 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
265
 
266
  $this->setting_radio_control(
267
  'update/window', 'update_window',
268
- array(&$this, 'update_window_edit_box'),
269
  array(
270
  'global-setting-default' => DEFAULT_UPDATE_PERIOD,
271
  'default-input-name' => 'use_default_update_window',
272
  'default-input-id' => 'use-default-update-window-yes',
273
  'default-input-id-no' => 'use-default-update-window-no',
274
- 'labels' => array(&$this, 'update_window_currently'),
275
  )
276
  );
277
  ?></td>
@@ -363,22 +363,63 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
363
  print number_format(intval($setting)) . " " . (($setting==1) ? "second" : "seconds");
364
  }
365
 
366
- function fetch_settings_box ($page, $box = NULL) {
 
 
 
 
 
 
367
  $this->setting_radio_control(
368
  'fetch timeout', 'fetch_timeout',
369
- array(&$this, 'fetch_timeout_setting'),
370
  array(
371
  'global-setting-default' => FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT,
372
  'input-name' => 'fetch_timeout',
373
  'default-input-name' => 'fetch_timeout_default',
374
- 'labels' => array(&$this, 'fetch_timeout_setting_value'),
375
  )
376
  );
377
- } /* FeedWordPressFeedsPage::fetch_settings_box () */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
 
379
  function display_authentication_credentials_box ($params = array()) {
380
  static $count = 0;
381
-
382
  $params = wp_parse_args($params, array(
383
  'username' => NULL,
384
  'password' => NULL,
@@ -502,7 +543,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
502
 
503
  global $feedwordpress;
504
 
505
- if (is_null($auth)) :
506
  $auth = '-';
507
  $hideAuth = true;
508
  endif;
@@ -789,7 +830,21 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
789
  $feeds = array_values( // Renumber from 0..(N-1)
790
  $feeds
791
  );
792
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  if (count($feeds) > 0):
794
  if ($feedSwitch) :
795
  ?>
@@ -815,7 +870,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
815
  foreach ($feeds as $key => $f):
816
  $ofc = $fwp_credentials;
817
  $fwp_credentials = $credentials; // Set
818
- $pie = FeedWordPress::fetch($f);
819
  $fwp_credentials = $ofc; // Re-Set
820
 
821
  $rss = (is_wp_error($pie) ? $pie : new MagpieFromSimplePie($pie));
@@ -1161,6 +1216,14 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
1161
  endif;
1162
  $this->update_setting('fetch timeout', $timeout);
1163
  endif;
 
 
 
 
 
 
 
 
1164
 
1165
  if (isset($post['update_minimum'])) :
1166
  $this->update_setting('update/minimum', $post['update_minimum']);
111
  'global_feeds_box' => __('Update Scheduling'),
112
  'updated_posts_box' => __('Updated Posts'),
113
  'custom_settings_box' => __('Custom Feed Settings (for use in templates)'),
114
+ 'advanced_settings_box' => __('Advanced Settings'),
115
  );
116
  if ($this->for_default_settings()) :
117
  unset($this->boxes_by_methods['custom_settings_box']);
265
 
266
  $this->setting_radio_control(
267
  'update/window', 'update_window',
268
+ array($this, 'update_window_edit_box'),
269
  array(
270
  'global-setting-default' => DEFAULT_UPDATE_PERIOD,
271
  'default-input-name' => 'use_default_update_window',
272
  'default-input-id' => 'use-default-update-window-yes',
273
  'default-input-id-no' => 'use-default-update-window-no',
274
+ 'labels' => array($this, 'update_window_currently'),
275
  )
276
  );
277
  ?></td>
363
  print number_format(intval($setting)) . " " . (($setting==1) ? "second" : "seconds");
364
  }
365
 
366
+ function advanced_settings_box ($page, $box = NULL) {
367
+ ?>
368
+ <table class="edit-form">
369
+ <tr>
370
+ <th>Fetch Timeout:</th>
371
+ <td>
372
+ <?php
373
  $this->setting_radio_control(
374
  'fetch timeout', 'fetch_timeout',
375
+ array($this, 'fetch_timeout_setting'),
376
  array(
377
  'global-setting-default' => FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT,
378
  'input-name' => 'fetch_timeout',
379
  'default-input-name' => 'fetch_timeout_default',
380
+ 'labels' => array($this, 'fetch_timeout_setting_value'),
381
  )
382
  );
383
+ ?>
384
+ </td>
385
+ </tr>
386
+ <tr>
387
+ <th>Feed Update Type:</th>
388
+ <td><?php
389
+ $this->setting_radio_control('update_incremental', 'update_incremental',
390
+ /*options=*/ array(
391
+ 'incremental' => '<strong>Incremental.</strong> When items no longer appear on the feed, keep them in the WordPress posts table.',
392
+ 'complete' => '<strong>Complete.</strong> When items no longer appear on the feed, they are obsolete; retire them from the WordPress posts table.',
393
+ ),
394
+ /*params=*/ array(
395
+ 'setting-default' => NULL,
396
+ 'global-setting-default' => 'incremental',
397
+ 'default-input-value' => 'default',
398
+ )
399
+ ); ?></td>
400
+ </tr>
401
+ <tr>
402
+ <th>Allow Feeds to Delete Posts:</th>
403
+ <td><?php
404
+ $this->setting_radio_control('tombstones', 'tombstones',
405
+ /*options=*/ array(
406
+ 'yes' => 'Yes. If a feed indicates that one of its posts has been deleted, delete the local copy syndicated to this website.',
407
+ 'no' => 'No. Even if a feed indicates that one of its posts has been deleted, retain the local copy on this website.',
408
+ ),
409
+ /*params=*/ array(
410
+ 'setting-default' => NULL,
411
+ 'global-setting-default' => 'yes',
412
+ 'default-input-value' => 'default',
413
+ )
414
+ ); ?></td>
415
+ </tr>
416
+ </table>
417
+ <?php
418
+ } /* FeedWordPressFeedsPage::advanced_settings_box () */
419
 
420
  function display_authentication_credentials_box ($params = array()) {
421
  static $count = 0;
422
+
423
  $params = wp_parse_args($params, array(
424
  'username' => NULL,
425
  'password' => NULL,
543
 
544
  global $feedwordpress;
545
 
546
+ if (is_null($auth) or (strlen($auth)==0)) :
547
  $auth = '-';
548
  $hideAuth = true;
549
  endif;
830
  $feeds = array_values( // Renumber from 0..(N-1)
831
  $feeds
832
  );
833
+
834
+ // Allow for some simple FeedFinder results filtering
835
+ $feeds = apply_filters(
836
+ 'feedwordpress_feedfinder_results',
837
+ $feeds,
838
+ array(
839
+ "url" => $lookup,
840
+ "auth" => $auth,
841
+ "username" => $username,
842
+ "password" => $password,
843
+ "finder" => $finder,
844
+ ),
845
+ $this
846
+ );
847
+
848
  if (count($feeds) > 0):
849
  if ($feedSwitch) :
850
  ?>
870
  foreach ($feeds as $key => $f):
871
  $ofc = $fwp_credentials;
872
  $fwp_credentials = $credentials; // Set
873
+ $pie = FeedWordPress::fetch($f, array("cache" => false));
874
  $fwp_credentials = $ofc; // Re-Set
875
 
876
  $rss = (is_wp_error($pie) ? $pie : new MagpieFromSimplePie($pie));
1216
  endif;
1217
  $this->update_setting('fetch timeout', $timeout);
1218
  endif;
1219
+
1220
+ if (isset($post['update_incremental'])) :
1221
+ $this->update_setting('update_incremental', $post['update_incremental']);
1222
+ endif;
1223
+
1224
+ if (isset($post['tombstones'])) :
1225
+ $this->update_setting('tombstones', $post['tombstones']);
1226
+ endif;
1227
 
1228
  if (isset($post['update_minimum'])) :
1229
  $this->update_setting('update/minimum', $post['update_minimum']);
feedtime.class.php CHANGED
@@ -1,7 +1,24 @@
1
  <?php
2
  /**
3
  * class FeedTime: handle common date-time formats used in feeds.
 
 
 
 
4
  *
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  */
6
  class FeedTime {
7
  var $rep;
@@ -21,10 +38,10 @@ class FeedTime {
21
  $this->ts = $this->parse_w3cdtf();
22
 
23
  if ($this->failed()) :
24
- // In some versions of PHP, strtotime() does not support
25
- // the UT timezone. Since UT is by definition within 1
26
- // second of UTC, we'll just convert it preemptively to avoid
27
- // problems.
28
  $time = preg_replace(
29
  '/(\s)UT$/',
30
  '$1UTC',
1
  <?php
2
  /**
3
  * class FeedTime: handle common date-time formats used in feeds.
4
+ * We will try to be as tolerant as possible of different representations, since
5
+ * RSS Is A Fucking Mess, broken dates seem to be especially pervasive, etc.
6
+ * Supports anything that your version of PHP's strtotime() can handle; also has
7
+ * a built-in parser for W3C DTF, in case your PHP doesn't have that.
8
  *
9
+ * Tries to parse a W3C DTF first; then falls back to strtotime(). If strtotime
10
+ * fails due to a mystery timezone, then we will try again on local time, with
11
+ * the timezone stripped out.
12
+ *
13
+ * To parse a string representation of a date-time from a feed, instantiate and
14
+ * then pull the timestamp:
15
+ *
16
+ * $time = new FeedTime($s);
17
+ * if (!$time->failed()) :
18
+ * $ts = $time->timestamp();
19
+ * else :
20
+ * // ...
21
+ * endif;
22
  */
23
  class FeedTime {
24
  var $rep;
38
  $this->ts = $this->parse_w3cdtf();
39
 
40
  if ($this->failed()) :
41
+ // In some versions of PHP, strtotime() does not
42
+ // support the UT timezone. But since UT is by
43
+ // definition within 1 second of UTC, we'll just
44
+ // convert it preemptively to avoid problems.
45
  $time = preg_replace(
46
  '/(\s)UT$/',
47
  '$1UTC',
feedwordpie.class.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define('FEEDWORDPIE_TYPE_CUSTOM_XML', ~SIMPLEPIE_TYPE_NONE & ~SIMPLEPIE_TYPE_ALL);
3
+
4
+ class FeedWordPie extends SimplePie {
5
+ var $subscription = NULL;
6
+
7
+ function set_feed_url ($url) {
8
+ global $fwp_oLinks;
9
+ if ($url InstanceOf SyndicatedLink) :
10
+
11
+ // Get URL with relevant parameters attached.
12
+ // Credentials will be handled further down.
13
+ $new_url = $url->uri(array('add_params' => true));
14
+
15
+ // Store for reference.
16
+ $this->subscription = $url->id();
17
+
18
+ // Pass it along down the line.
19
+ $url = $new_url;
20
+
21
+ else :
22
+ $this->subscription = NULL;
23
+ endif;
24
+
25
+ // OK, let's go.
26
+ return parent::set_feed_url($url);
27
+ } /* class SimplePie */
28
+
29
+ function get_type () {
30
+ // Allow filters to pre-empt a type determination from SimplePie
31
+ $ret = apply_filters(
32
+ 'feedwordpie_get_type',
33
+ NULL,
34
+ $this
35
+ );
36
+
37
+ // If not preempted by a filter, fall back on SimplePie
38
+ if (is_null($ret)) :
39
+ $ret = parent::get_type();
40
+ endif;
41
+
42
+ return $ret;
43
+ }
44
+
45
+ function get_feed_tags ($namespace, $tag) {
46
+ // Allow filters to filter SimplePie handling
47
+ return apply_filters(
48
+ 'feedwordpie_get_feed_tags',
49
+ parent::get_feed_tags($namespace, $tag),
50
+ $namespace,
51
+ $tag,
52
+ $this
53
+ );
54
+ }
55
+
56
+ function get_items ($start = 0, $end = 0) {
57
+ // Allow filters to set up for, or pre-empt, SimplePie handling
58
+ $ret = apply_filters(
59
+ 'feedwordpie_get_items',
60
+ NULL,
61
+ $start,
62
+ $end,
63
+ $this
64
+ );
65
+
66
+ if (is_null($ret)) :
67
+ $ret = parent::get_items();
68
+ endif;
69
+ return $ret;
70
+ }
71
+
72
+ } /* class FeedWordPie */
73
+
feedwordpie_item.class.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FeedWordPie_Item extends SimplePie_Item {
3
+
4
+ function get_id ($hash = false) {
5
+ return apply_filters('feedwordpie_item_get_id', parent::get_id($hash), $hash, $this);
6
+ }
7
+
8
+ function get_title () {
9
+ return apply_filters('feedwordpie_item_get_title', parent::get_title(), $this);
10
+ }
11
+
12
+ function get_description ($description_only = false) {
13
+ return apply_filters('feedwordpie_item_get_description', parent::get_description($description_only), $description_only, $this);
14
+ }
15
+
16
+ function get_content ($content_only = false) {
17
+ return apply_filters('feedwordpie_item_get_content', parent::get_content($content_only), $content_only, $this);
18
+ }
19
+
20
+ function get_categories () {
21
+ return apply_filters('feedwordpie_item_get_categories', parent::get_categories(), $this);
22
+ }
23
+
24
+ function get_authors () {
25
+ return apply_filters('feedwordpie_item_get_authors', parent::get_authors(), $this);
26
+ }
27
+ function get_contributors () {
28
+ return apply_filters('feedwordpie_item_get_contributors', parent::get_contributors(), $this);
29
+ }
30
+ function get_copyright () {
31
+ return apply_filters('feedwordpie_item_get_copyright', parent::get_copyright(), $this);
32
+ }
33
+ function get_date ($date_format = 'j F Y, g:i a') {
34
+ return apply_filters('feedwordpie_item_get_date', parent::get_date($date_format), $date_format, $this);
35
+ }
36
+ function get_local_date ($date_format = '%c') {
37
+ return apply_filters('feedwordpie_item_get_local_date', parent::get_local_date($date_format), $date_format, $this);
38
+ }
39
+ function get_links ($rel = 'alternate') {
40
+ return apply_filters('feedwordpie_item_get_links', parent::get_links($rel), $rel, $this);
41
+ }
42
+ function get_enclosures () {
43
+ return apply_filters('feedwordpie_item_get_enclosures', parent::get_enclosures(), $this);
44
+ }
45
+ function get_latitude () {
46
+ return apply_filters('feedwordpie_item_get_lattitude', parent::get_lattitude(), $this);
47
+ }
48
+ function get_longitude () {
49
+ return apply_filters('feedwordpie_item_get_longitude', parent::get_longtidue(), $this);
50
+ }
51
+ function get_source () {
52
+ return apply_filters('feedwordpie_item_get_source', parent::get_source(), $this);
53
+ }
54
+ } /* class FeedWordPie_Item */
55
+
feedwordpress-content-type-sniffer.class.php CHANGED
@@ -17,7 +17,7 @@ class FeedWordPress_Content_Type_Sniffer extends SimplePie_Content_Type_Sniffer
17
  endif;
18
 
19
  foreach ($this->file->headers['content-type'] as $type) :
20
- $parts = array_map('trim', split(";", $type, 2));
21
  if (isset($parts[1])) :
22
  $type = $parts[0];
23
  $charset = $parts[1];
17
  endif;
18
 
19
  foreach ($this->file->headers['content-type'] as $type) :
20
+ $parts = array_map('trim', explode(";", $type, 2));
21
  if (isset($parts[1])) :
22
  $type = $parts[0];
23
  $charset = $parts[1];
feedwordpress.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: FeedWordPress
4
  Plugin URI: http://feedwordpress.radgeek.com/
5
  Description: simple and flexible Atom/RSS syndication for WordPress
6
- Version: 2011.1019
7
  Author: Charles Johnson
8
  Author URI: http://radgeek.com/
9
  License: GPL
@@ -11,7 +11,7 @@ License: GPL
11
 
12
  /**
13
  * @package FeedWordPress
14
- * @version 2011.1019
15
  */
16
 
17
  # This uses code derived from:
@@ -34,7 +34,7 @@ License: GPL
34
 
35
  # -- Don't change these unless you know what you're doing...
36
 
37
- define ('FEEDWORDPRESS_VERSION', '2011.1019');
38
  define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
39
 
40
  if (!defined('FEEDWORDPRESS_BLEG')) :
@@ -54,6 +54,8 @@ else :
54
  endif;
55
  endif;
56
  define ('FEEDWORDPRESS_DEBUG', $feedwordpress_debug);
 
 
57
 
58
  define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
59
  define ('FEEDWORDPRESS_CAT_SEPARATOR', "\n");
@@ -119,6 +121,8 @@ require_once("${dir}/feedwordpresshtml.class.php");
119
  require_once("${dir}/feedwordpress-content-type-sniffer.class.php");
120
  require_once("${dir}/inspectpostmeta.class.php");
121
  require_once("${dir}/syndicationdataqueries.class.php");
 
 
122
  require_once("${dir}/feedwordpress_file.class.php");
123
  require_once("${dir}/feedwordpress_parser.class.php");
124
  require_once("${dir}/feedwordpressrpc.class.php");
@@ -183,6 +187,7 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
183
  remove_filter('pre_link_url', 'wp_filter_kses');
184
 
185
  # Admin menu
 
186
  add_action('admin_menu', 'fwp_add_pages');
187
  add_action('admin_notices', 'fwp_check_debug');
188
 
@@ -214,12 +219,12 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
214
  # Cron-less auto-update. Hooray!
215
  $autoUpdateHook = $feedwordpress->automatic_update_hook();
216
  if (!is_null($autoUpdateHook)) :
217
- add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
218
  endif;
219
 
220
- add_action('init', array(&$feedwordpress, 'init'));
221
- add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
222
- add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
223
 
224
  # Default sanitizers
225
  add_filter('syndicated_item_content', array('SyndicatedPost', 'resolve_relative_uris'), 0, 2);
@@ -392,23 +397,12 @@ function get_syndication_feed_guid ($original = NULL, $id = NULL) {
392
  function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_values('syndication_feed_id', $id); return $u; }
393
  function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
394
 
395
- $feedwordpress_linkcache = array (); // only load links from database once
396
  function get_syndication_feed_object ($id = NULL) {
397
- global $feedwordpress_linkcache;
398
-
399
- $link = NULL;
400
-
401
  $feed_id = get_syndication_feed_id($id);
402
- if (strlen($feed_id) > 0):
403
- if (isset($feedwordpress_linkcache[$feed_id])) :
404
- $link = $feedwordpress_linkcache[$feed_id];
405
- else :
406
- $link = new SyndicatedLink($feed_id);
407
- $feedwordpress_linkcache[$feed_id] = $link;
408
- endif;
409
- endif;
410
- return $link;
411
- }
412
 
413
  function get_feed_meta ($key, $id = NULL) {
414
  $ret = NULL;
@@ -418,7 +412,7 @@ function get_feed_meta ($key, $id = NULL) {
418
  $ret = $link->settings[$key];
419
  endif;
420
  return $ret;
421
- } /* get_feed_meta() */
422
 
423
  function get_syndication_permalink ($id = NULL) {
424
  list($u) = get_post_custom_values('syndication_permalink', $id); return $u;
@@ -680,6 +674,12 @@ function fwp_add_pages () {
680
  WP_PLUGIN_URL.'/'.FeedWordPress::path('feedwordpress-tiny.png')
681
  );
682
 
 
 
 
 
 
 
683
  do_action('feedwordpress_admin_menu_pre_feeds', $menu_cap, $settings_cap);
684
  add_submenu_page(
685
  $syndicationMenu, 'Syndicated Feeds & Updates', 'Feeds & Updates',
@@ -700,7 +700,7 @@ function fwp_add_pages () {
700
 
701
  do_action('feedwordpress_admin_menu_pre_categories', $menu_cap, $settings_cap);
702
  add_submenu_page(
703
- $syndicationMenu, 'Categories'.FEEDWORDPRESS_AND_TAGS, 'Categories'.FEEDWORDPRESS_AND_TAGS,
704
  $settings_cap, FeedWordPress::path('categories-page.php')
705
  );
706
 
@@ -797,7 +797,13 @@ function fwp_publish_post_hook ($post_id) {
797
  }
798
 
799
  function feedwordpress_add_post_edit_controls () {
 
 
 
800
  add_meta_box('feedwordpress-post-controls', __('Syndication'), 'feedwordpress_post_edit_controls', 'post', 'side', 'high');
 
 
 
801
  if (FeedWordPress::diagnostic_on('syndicated_posts:static_meta_data')) :
802
  $GLOBALS['inspectPostMeta'] = new InspectPostMeta;
803
  endif;
@@ -897,19 +903,53 @@ class FeedWordPress {
897
  );
898
 
899
  var $feeds = NULL;
900
-
901
  var $httpauth = NULL;
 
902
  # function FeedWordPress (): Contructor; retrieve a list of feeds
903
  function FeedWordPress () {
904
  $this->feeds = array ();
 
905
  $links = FeedWordPress::syndicated_links();
906
  if ($links): foreach ($links as $link):
907
- $this->feeds[] = new SyndicatedLink($link);
 
 
 
 
 
 
 
908
  endforeach; endif;
909
-
910
  $this->httpauth = new FeedWordPressHTTPAuthenticator;
911
  } // FeedWordPress::FeedWordPress ()
912
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
913
  # function update (): polls for updates on one or more Contributor feeds
914
  #
915
  # Arguments:
@@ -986,7 +1026,7 @@ class FeedWordPress {
986
  endif;
987
 
988
  // Randomize order for load balancing purposes
989
- $feed_set = $this->feeds;
990
  shuffle($feed_set);
991
 
992
  $updateWindow = (int) get_option('feedwordpress_update_window', DEFAULT_UPDATE_PERIOD) * 60 /* sec/min */;
@@ -1001,10 +1041,13 @@ class FeedWordPress {
1001
  ), $uri);
1002
 
1003
  $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri);
1004
-
 
1005
  // Loop through and check for new posts
1006
  $delta = NULL; $remaining = $max_polls;
1007
- foreach ($feed_set as $feed) :
 
 
1008
 
1009
  // Has this process overstayed its welcome?
1010
  if (
@@ -1157,6 +1200,15 @@ class FeedWordPress {
1157
  return $ret;
1158
  } // FeedWordPress::stale()
1159
 
 
 
 
 
 
 
 
 
 
1160
  function init () {
1161
  global $fwp_path;
1162
 
@@ -1174,15 +1226,49 @@ class FeedWordPress {
1174
  wp_enqueue_style('dashboard');
1175
  wp_enqueue_style('feedwordpress-elements');
1176
 
1177
- if (function_exists('wp_admin_css')) :
1178
  wp_admin_css('css/dashboard');
1179
- endif;
1180
  endif;
1181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1182
  $this->clear_cache_magic_url();
1183
  $this->update_magic_url();
1184
  } /* FeedWordPress::init() */
1185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1186
  function dashboard_setup () {
1187
  $see_it = FeedWordPress::menu_cap();
1188
 
@@ -1202,12 +1288,12 @@ class FeedWordPress {
1202
  add_meta_box(
1203
  /*id=*/ $widget_id,
1204
  /*title=*/ $widget_name,
1205
- /*callback=*/ array(&$this, 'dashboard'),
1206
  /*page=*/ 'dashboard',
1207
  /*context=*/ $column,
1208
  /*priority=*/ $priority
1209
  );
1210
- /*control_callback= array(&$this, 'dashboard_control') */
1211
 
1212
  // This is kind of rude, I know, but the dashboard widget isn't
1213
  // worth much if users don't know that it exists, and I don't
@@ -1244,6 +1330,20 @@ class FeedWordPress {
1244
  $syndicationPage->dashboard_box($syndicationPage);
1245
  } /* FeedWordPress::dashboard () */
1246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1247
  function update_magic_url () {
1248
  global $wpdb;
1249
 
@@ -1604,11 +1704,11 @@ class FeedWordPress {
1604
  endif;
1605
  $timeout = intval($timeout);
1606
 
1607
- $pie_class = apply_filters('feedwordpress_simplepie_class', 'SimplePie');
1608
  $cache_class = apply_filters('feedwordpress_cache_class', 'WP_Feed_Cache');
1609
  $file_class = apply_filters('feedwordpress_file_class', 'FeedWordPress_File');
1610
  $parser_class = apply_filters('feedwordpress_parser_class', 'FeedWordPress_Parser');
1611
-
1612
  $sniffer_class = apply_filters('feedwordpress_sniffer_class', 'FeedWordPress_Content_Type_Sniffer');
1613
 
1614
  $feed = new $pie_class;
@@ -1619,8 +1719,9 @@ class FeedWordPress {
1619
  $feed->set_content_type_sniffer_class($sniffer_class);
1620
  $feed->set_file_class($file_class);
1621
  $feed->set_parser_class($parser_class);
 
1622
  $feed->force_feed($force_feed);
1623
- $feed->set_cache_duration(FeedWordPress::cache_duration());
1624
  $feed->init();
1625
  $feed->handle_content_type();
1626
 
@@ -1657,9 +1758,15 @@ class FeedWordPress {
1657
  return ($magpies + $simplepies);
1658
  } /* FeedWordPress::clear_cache () */
1659
 
1660
- function cache_duration () {
 
 
 
 
1661
  $duration = NULL;
1662
- if (defined('FEEDWORDPRESS_CACHE_AGE')) :
 
 
1663
  $duration = FEEDWORDPRESS_CACHE_AGE;
1664
  endif;
1665
  return $duration;
@@ -1760,6 +1867,7 @@ class FeedWordPress {
1760
  error_log(FeedWordPress::log_prefix().' '.$out);
1761
  break;
1762
  case 'email' :
 
1763
  if (is_null($persist)) :
1764
  $sect = 'occurrent';
1765
  $hook = (isset($dlog['mesg'][$sect]) ? count($dlog['mesg'][$sect]) : 0);
@@ -1801,7 +1909,11 @@ class FeedWordPress {
1801
  return $ret;
1802
  }
1803
 
1804
- function email_diagnostic_log () {
 
 
 
 
1805
  $dlog = get_option('feedwordpress_diagnostics_log', array());
1806
 
1807
  if ($this->has_emailed_diagnostics($dlog)) :
@@ -1886,9 +1998,26 @@ EOMAIL;
1886
  $recipients = FeedWordPressDiagnostic::admin_emails();
1887
  endif;
1888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1889
  foreach ($recipients as $email) :
1890
  add_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1891
- wp_mail($email, $subj, $body);
1892
  remove_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
1893
  endforeach;
1894
  endif;
3
  Plugin Name: FeedWordPress
4
  Plugin URI: http://feedwordpress.radgeek.com/
5
  Description: simple and flexible Atom/RSS syndication for WordPress
6
+ Version: 2012.1212
7
  Author: Charles Johnson
8
  Author URI: http://radgeek.com/
9
  License: GPL
11
 
12
  /**
13
  * @package FeedWordPress
14
+ * @version 2012.1212
15
  */
16
 
17
  # This uses code derived from:
34
 
35
  # -- Don't change these unless you know what you're doing...
36
 
37
+ define ('FEEDWORDPRESS_VERSION', '2012.1212');
38
  define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
39
 
40
  if (!defined('FEEDWORDPRESS_BLEG')) :
54
  endif;
55
  endif;
56
  define ('FEEDWORDPRESS_DEBUG', $feedwordpress_debug);
57
+ $feedwordpress_compatibility = true;
58
+ define ('FEEDWORDPRESS_COMPATIBILITY', $feedwordpress_compatibility);
59
 
60
  define ('FEEDWORDPRESS_CAT_SEPARATOR_PATTERN', '/[:\n]/');
61
  define ('FEEDWORDPRESS_CAT_SEPARATOR', "\n");
121
  require_once("${dir}/feedwordpress-content-type-sniffer.class.php");
122
  require_once("${dir}/inspectpostmeta.class.php");
123
  require_once("${dir}/syndicationdataqueries.class.php");
124
+ require_once("${dir}/feedwordpie.class.php");
125
+ require_once("${dir}/feedwordpie_item.class.php");
126
  require_once("${dir}/feedwordpress_file.class.php");
127
  require_once("${dir}/feedwordpress_parser.class.php");
128
  require_once("${dir}/feedwordpressrpc.class.php");
187
  remove_filter('pre_link_url', 'wp_filter_kses');
188
 
189
  # Admin menu
190
+ add_action('admin_init', array('feedwordpress', 'admin_init'));
191
  add_action('admin_menu', 'fwp_add_pages');
192
  add_action('admin_notices', 'fwp_check_debug');
193
 
219
  # Cron-less auto-update. Hooray!
220
  $autoUpdateHook = $feedwordpress->automatic_update_hook();
221
  if (!is_null($autoUpdateHook)) :
222
+ add_action($autoUpdateHook, array($feedwordpress, 'auto_update'));
223
  endif;
224
 
225
+ add_action('init', array($feedwordpress, 'init'));
226
+ add_action('shutdown', array($feedwordpress, 'email_diagnostic_log'));
227
+ add_action('wp_dashboard_setup', array($feedwordpress, 'dashboard_setup'));
228
 
229
  # Default sanitizers
230
  add_filter('syndicated_item_content', array('SyndicatedPost', 'resolve_relative_uris'), 0, 2);
397
  function get_syndication_feed_id ($id = NULL) { list($u) = get_post_custom_values('syndication_feed_id', $id); return $u; }
398
  function the_syndication_feed_id ($id = NULL) { echo get_syndication_feed_id($id); }
399
 
 
400
  function get_syndication_feed_object ($id = NULL) {
401
+ global $feedwordpress;
402
+
 
 
403
  $feed_id = get_syndication_feed_id($id);
404
+ return $feedwordpress->subscription($feed_id);
405
+ } /* function get_syndication_feed_object() */
 
 
 
 
 
 
 
 
406
 
407
  function get_feed_meta ($key, $id = NULL) {
408
  $ret = NULL;
412
  $ret = $link->settings[$key];
413
  endif;
414
  return $ret;
415
+ } /* function get_feed_meta() */
416
 
417
  function get_syndication_permalink ($id = NULL) {
418
  list($u) = get_post_custom_values('syndication_permalink', $id); return $u;
674
  WP_PLUGIN_URL.'/'.FeedWordPress::path('feedwordpress-tiny.png')
675
  );
676
 
677
+ do_action('feedwordpress_admin_menu_pre_feeds', $menu_cap, $settings_cap);
678
+ add_submenu_page(
679
+ $syndicationMenu, 'Syndicated Sites', 'Syndicated Sites',
680
+ $settings_cap, $syndicationMenu
681
+ );
682
+
683
  do_action('feedwordpress_admin_menu_pre_feeds', $menu_cap, $settings_cap);
684
  add_submenu_page(
685
  $syndicationMenu, 'Syndicated Feeds & Updates', 'Feeds & Updates',
700
 
701
  do_action('feedwordpress_admin_menu_pre_categories', $menu_cap, $settings_cap);
702
  add_submenu_page(
703
+ $syndicationMenu, 'Categories & Tags', 'Categories & Tags',
704
  $settings_cap, FeedWordPress::path('categories-page.php')
705
  );
706
 
797
  }
798
 
799
  function feedwordpress_add_post_edit_controls () {
800
+ global $feedwordpress;
801
+
802
+ // Put in Manual Editing checkbox
803
  add_meta_box('feedwordpress-post-controls', __('Syndication'), 'feedwordpress_post_edit_controls', 'post', 'side', 'high');
804
+
805
+ add_filter('user_can_richedit', array($feedwordpress, 'user_can_richedit'), 1000, 1);
806
+
807
  if (FeedWordPress::diagnostic_on('syndicated_posts:static_meta_data')) :
808
  $GLOBALS['inspectPostMeta'] = new InspectPostMeta;
809
  endif;
903
  );
904
 
905
  var $feeds = NULL;
906
+ var $feedurls = NULL;
907
  var $httpauth = NULL;
908
+
909
  # function FeedWordPress (): Contructor; retrieve a list of feeds
910
  function FeedWordPress () {
911
  $this->feeds = array ();
912
+ $this->feedurls = array();
913
  $links = FeedWordPress::syndicated_links();
914
  if ($links): foreach ($links as $link):
915
+ $id = intval($link->link_id);
916
+ $url = $link->link_rss;
917
+
918
+ // Store for later reference.
919
+ $this->feeds[$id] = $id;
920
+ if (strlen($url) > 0) :
921
+ $this->feedurls[$url] = $id;
922
+ endif;
923
  endforeach; endif;
924
+
925
  $this->httpauth = new FeedWordPressHTTPAuthenticator;
926
  } // FeedWordPress::FeedWordPress ()
927
 
928
+ function subscribed ($id) {
929
+ return (isset($this->feedurls[$id]) or isset($this->feeds[$id]));
930
+ } /* FeedWordPress::subscribed () */
931
+
932
+ function subscription ($which) {
933
+ $sub = NULL;
934
+
935
+ if (is_string($which) and isset($this->feedurls[$which])) :
936
+ $which = $this->feedurls[$which];
937
+ endif;
938
+
939
+ if (isset($this->feeds[$which])) :
940
+ $sub = $this->feeds[$which];
941
+ endif;
942
+
943
+ // Load 'er up if you haven't already.
944
+ if (!is_null($sub) and !($sub InstanceOf SyndicatedLink)) :
945
+ $link = new SyndicatedLink($sub);
946
+ $this->feeds[$which] = $link;
947
+ $sub = $link;
948
+ endif;
949
+
950
+ return $sub;
951
+ } /* FeedWordPress::subscriptions () */
952
+
953
  # function update (): polls for updates on one or more Contributor feeds
954
  #
955
  # Arguments:
1026
  endif;
1027
 
1028
  // Randomize order for load balancing purposes
1029
+ $feed_set = array_keys($this->feeds);
1030
  shuffle($feed_set);
1031
 
1032
  $updateWindow = (int) get_option('feedwordpress_update_window', DEFAULT_UPDATE_PERIOD) * 60 /* sec/min */;
1041
  ), $uri);
1042
 
1043
  $feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri);
1044
+
1045
+
1046
  // Loop through and check for new posts
1047
  $delta = NULL; $remaining = $max_polls;
1048
+ foreach ($feed_set as $feed_id) :
1049
+
1050
+ $feed = $this->subscription($feed_id);
1051
 
1052
  // Has this process overstayed its welcome?
1053
  if (
1200
  return $ret;
1201
  } // FeedWordPress::stale()
1202
 
1203
+ static function admin_init () {
1204
+ // WordPress 3.5+ compat: the WP devs are in the midst of removing Links from the WordPress core. Eventually we'll have to deal
1205
+ // with the possible disappearance of the wp_links table as a whole; but in the meantime, we just need to turn on the interface
1206
+ // element to avoid problems with user capabilities that presume the presence of the Links Manager in the admin UI.
1207
+ if (!intval(get_option('link_manager_enabled', false))) :
1208
+ update_option('link_manager_enabled', true);
1209
+ endif;
1210
+ } /* FeedWordPress::admin_init() */
1211
+
1212
  function init () {
1213
  global $fwp_path;
1214
 
1226
  wp_enqueue_style('dashboard');
1227
  wp_enqueue_style('feedwordpress-elements');
1228
 
1229
+ /*if (function_exists('wp_admin_css')) :
1230
  wp_admin_css('css/dashboard');
1231
+ endif;*/
1232
  endif;
1233
 
1234
+ // This is a special post status for hiding posts that have expired
1235
+ register_post_status('fwpretired', array(
1236
+ 'label' => _x('Retired', 'post'),
1237
+ 'label_count' => _n_noop('Retired <span class="count">(%s)</span>', 'Retired <span class="count">(%s)</span>'),
1238
+ 'exclude_from_search' => true,
1239
+ 'public' => false,
1240
+ 'publicly_queryable' => false,
1241
+ 'show_in_admin_all_list' => false,
1242
+ 'show_in_admin_status_list' => true,
1243
+ ));
1244
+ add_action(
1245
+ /*hook=*/ 'template_redirect',
1246
+ /*function=*/ array($this, 'redirect_retired'),
1247
+ /*priority=*/ -100
1248
+ );
1249
+
1250
  $this->clear_cache_magic_url();
1251
  $this->update_magic_url();
1252
  } /* FeedWordPress::init() */
1253
 
1254
+ function redirect_retired () {
1255
+ global $wp_query;
1256
+ if (is_singular()) :
1257
+ if ('fwpretired'==$wp_query->post->post_status) :
1258
+ do_action('feedwordpress_redirect_retired', $wp_query->post);
1259
+
1260
+ if (!($template = get_404_template())) :
1261
+ $template = get_index_template();
1262
+ endif;
1263
+ if ($template = apply_filters('template_include', $template)) :
1264
+ header("HTTP/1.1 410 Gone");
1265
+ include($template);
1266
+ endif;
1267
+ exit;
1268
+ endif;
1269
+ endif;
1270
+ }
1271
+
1272
  function dashboard_setup () {
1273
  $see_it = FeedWordPress::menu_cap();
1274
 
1288
  add_meta_box(
1289
  /*id=*/ $widget_id,
1290
  /*title=*/ $widget_name,
1291
+ /*callback=*/ array($this, 'dashboard'),
1292
  /*page=*/ 'dashboard',
1293
  /*context=*/ $column,
1294
  /*priority=*/ $priority
1295
  );
1296
+ /*control_callback= array($this, 'dashboard_control') */
1297
 
1298
  // This is kind of rude, I know, but the dashboard widget isn't
1299
  // worth much if users don't know that it exists, and I don't
1330
  $syndicationPage->dashboard_box($syndicationPage);
1331
  } /* FeedWordPress::dashboard () */
1332
 
1333
+ function user_can_richedit ($rich_edit) {
1334
+
1335
+ global $post;
1336
+
1337
+ if (is_syndicated($post->ID)) :
1338
+ // Disable visual editor and only allow operations
1339
+ // directly on HTML if post is syndicated.
1340
+ $rich_edit = false;
1341
+ endif;
1342
+
1343
+ return $rich_edit;
1344
+
1345
+ } /* FeedWordPress::user_can_richedit () */
1346
+
1347
  function update_magic_url () {
1348
  global $wpdb;
1349
 
1704
  endif;
1705
  $timeout = intval($timeout);
1706
 
1707
+ $pie_class = apply_filters('feedwordpress_simplepie_class', 'FeedWordPie');
1708
  $cache_class = apply_filters('feedwordpress_cache_class', 'WP_Feed_Cache');
1709
  $file_class = apply_filters('feedwordpress_file_class', 'FeedWordPress_File');
1710
  $parser_class = apply_filters('feedwordpress_parser_class', 'FeedWordPress_Parser');
1711
+ $item_class = apply_filters('feedwordpress_item_class', 'FeedWordPie_Item');
1712
  $sniffer_class = apply_filters('feedwordpress_sniffer_class', 'FeedWordPress_Content_Type_Sniffer');
1713
 
1714
  $feed = new $pie_class;
1719
  $feed->set_content_type_sniffer_class($sniffer_class);
1720
  $feed->set_file_class($file_class);
1721
  $feed->set_parser_class($parser_class);
1722
+ $feed->set_item_class($item_class);
1723
  $feed->force_feed($force_feed);
1724
+ $feed->set_cache_duration(FeedWordPress::cache_duration($params));
1725
  $feed->init();
1726
  $feed->handle_content_type();
1727
 
1758
  return ($magpies + $simplepies);
1759
  } /* FeedWordPress::clear_cache () */
1760
 
1761
+ function cache_duration ($params = array()) {
1762
+ $params = wp_parse_args($params, array(
1763
+ "cache" => true,
1764
+ ));
1765
+
1766
  $duration = NULL;
1767
+ if (!$params['cache']) :
1768
+ $duration = 0;
1769
+ elseif (defined('FEEDWORDPRESS_CACHE_AGE')) :
1770
  $duration = FEEDWORDPRESS_CACHE_AGE;
1771
  endif;
1772
  return $duration;
1867
  error_log(FeedWordPress::log_prefix().' '.$out);
1868
  break;
1869
  case 'email' :
1870
+
1871
  if (is_null($persist)) :
1872
  $sect = 'occurrent';
1873
  $hook = (isset($dlog['mesg'][$sect]) ? count($dlog['mesg'][$sect]) : 0);
1909
  return $ret;
1910
  }
1911
 
1912
+ function email_diagnostic_log ($params = array()) {
1913
+ $params = wp_parse_args($params, array(
1914
+ "force" => false,
1915
+ ));
1916
+
1917
  $dlog = get_option('feedwordpress_diagnostics_log', array());
1918
 
1919
  if ($this->has_emailed_diagnostics($dlog)) :
1998
  $recipients = FeedWordPressDiagnostic::admin_emails();
1999
  endif;
2000
 
2001
+ $mesgId = 'feedwordpress+'.time().'@'.$home;
2002
+ $parentId = get_option('feedwordpress_diagnostics_email_root_message_id', NULL);
2003
+
2004
+ $head = array("Message-ID: <$mesgId>");
2005
+ if (!is_null($parentId)) :
2006
+ // We've already sent off a diagnostic message in the past. Let's do some
2007
+ // magic to help with threading, in the hopes that all diagnostic messages
2008
+ // get threaded together.
2009
+ $head[] = "References: <$parentId>";
2010
+ $head[] = "In-Reply-To: <$parentId>";
2011
+ $subj = "Re: ".$subj;
2012
+ else :
2013
+ // This is the first of its kind. Let's mark it as such.
2014
+ update_option('feedwordpress_diagnostics_email_root_message_id', $mesgId);
2015
+ endif;
2016
+ $head = apply_filters('feedwordpress_diagnostic_email_headers', $head);
2017
+
2018
  foreach ($recipients as $email) :
2019
  add_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
2020
+ wp_mail($email, $subj, $body, $head);
2021
  remove_filter('wp_mail_content_type', array('FeedWordPress', 'allow_html_mail'));
2022
  endforeach;
2023
  endif;
feedwordpress_file.class.php CHANGED
@@ -7,12 +7,20 @@ class FeedWordPress_File extends WP_SimplePie_File {
7
  }
8
 
9
  function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
 
 
 
 
 
 
 
 
10
  $this->url = $url;
11
  $this->timeout = $timeout;
12
  $this->redirects = $redirects;
13
  $this->headers = $headers;
14
  $this->useragent = $useragent;
15
-
16
  $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE;
17
 
18
  global $wpdb;
@@ -24,8 +32,19 @@ class FeedWordPress_File extends WP_SimplePie_File {
24
  if ( !empty($this->headers) )
25
  $args['headers'] = $this->headers;
26
 
27
- if ( SIMPLEPIE_USERAGENT != $this->useragent ) //Use default WP user agent unless custom has been specified
 
28
  $args['user-agent'] = $this->useragent;
 
 
 
 
 
 
 
 
 
 
29
 
30
  // This is ugly as hell, but communicating up and down the chain
31
  // in any other way is difficult.
@@ -36,21 +55,17 @@ class FeedWordPress_File extends WP_SimplePie_File {
36
  $args['username'] = $fwp_credentials['username'];
37
  $args['password'] = $fwp_credentials['password'];
38
 
39
- else :
40
-
41
- $links = $wpdb->get_results(
42
- $wpdb->prepare("SELECT * FROM {$wpdb->links} WHERE link_rss = '%s'", $url)
43
- );
44
- if ($links) :
45
- $source = new SyndicatedLink($links[0]);
46
- $args['authentication'] = $source->authentication_method();
47
- $args['username'] = $source->username();
48
- $args['password'] = $source->password();
49
- endif;
50
 
51
  endif;
52
-
 
53
  $res = wp_remote_request($url, $args);
 
54
 
55
  if ( is_wp_error($res) ) {
56
  $this->error = 'WP HTTP Error: ' . $res->get_error_message();
@@ -60,6 +75,13 @@ class FeedWordPress_File extends WP_SimplePie_File {
60
  $this->body = wp_remote_retrieve_body( $res );
61
  $this->status_code = wp_remote_retrieve_response_code( $res );
62
  }
 
 
 
 
 
 
 
63
  } else {
64
  if ( ! $this->body = file_get_contents($url) ) {
65
  $this->error = 'file_get_contents could not read the file';
7
  }
8
 
9
  function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
10
+ global $feedwordpress;
11
+ global $wp_version;
12
+
13
+ $source = NULL;
14
+ if ($feedwordpress->subscribed($url)) :
15
+ $source = $feedwordpress->subscription($url);
16
+ endif;
17
+
18
  $this->url = $url;
19
  $this->timeout = $timeout;
20
  $this->redirects = $redirects;
21
  $this->headers = $headers;
22
  $this->useragent = $useragent;
23
+
24
  $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE;
25
 
26
  global $wpdb;
32
  if ( !empty($this->headers) )
33
  $args['headers'] = $this->headers;
34
 
35
+ // Use default FWP user agent unless custom has been specified
36
+ if ( SIMPLEPIE_USERAGENT != $this->useragent ) :
37
  $args['user-agent'] = $this->useragent;
38
+ else :
39
+ $args['user-agent'] = apply_filters('feedwordpress_user_agent',
40
+ 'FeedWordPress/'.FEEDWORDPRESS_VERSION
41
+ .' (aggregator:feedwordpress; WordPress/'.$wp_version
42
+ .' + '.SIMPLEPIE_NAME.'/'.SIMPLEPIE_VERSION
43
+ .'; Allow like Gecko; +http://feedwordpress.radgeek.com/) at '
44
+ . feedwordpress_display_url(get_bloginfo('url')),
45
+ $this
46
+ );
47
+ endif;
48
 
49
  // This is ugly as hell, but communicating up and down the chain
50
  // in any other way is difficult.
55
  $args['username'] = $fwp_credentials['username'];
56
  $args['password'] = $fwp_credentials['password'];
57
 
58
+ elseif ($source InstanceOf SyndicatedLink) :
59
+
60
+ $args['authentication'] = $source->authentication_method();
61
+ $args['username'] = $source->username();
62
+ $args['password'] = $source->password();
 
 
 
 
 
 
63
 
64
  endif;
65
+
66
+ FeedWordPress::diagnostic('updated_feeds:http', "HTTP [$url] &#8668; ".esc_html(FeedWordPress::val($args)));
67
  $res = wp_remote_request($url, $args);
68
+ FeedWordPress::diagnostic('updated_feeds:http', "HTTP [$url] &#8669; ".esc_html(FeedWordPress::val($res)));
69
 
70
  if ( is_wp_error($res) ) {
71
  $this->error = 'WP HTTP Error: ' . $res->get_error_message();
75
  $this->body = wp_remote_retrieve_body( $res );
76
  $this->status_code = wp_remote_retrieve_response_code( $res );
77
  }
78
+
79
+ if ($source InstanceOf SyndicatedLink) :
80
+ $source->update_setting('link/filesize', strlen($this->body));
81
+ $source->update_setting('link/http status', $this->status_code);
82
+ $source->save_settings(/*reload=*/ true);
83
+ endif;
84
+
85
  } else {
86
  if ( ! $this->body = file_get_contents($url) ) {
87
  $this->error = 'file_get_contents could not read the file';
feedwordpress_parser.class.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  class FeedWordPress_Parser extends SimplePie_Parser {
3
  function parse (&$data, $encoding) {
 
 
4
  // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
5
  if (strtoupper($encoding) === 'US-ASCII')
6
  {
@@ -40,7 +42,7 @@ class FeedWordPress_Parser extends SimplePie_Parser {
40
 
41
  if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
42
  {
43
- $declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
44
  if ($declaration->parse())
45
  {
46
  $data = substr($data, $pos + 2);
@@ -78,8 +80,23 @@ class FeedWordPress_Parser extends SimplePie_Parser {
78
  // Parse!
79
  if (!xml_parse($xml, $data, true))
80
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  $this->error_code = xml_get_error_code($xml);
82
  $this->error_string = xml_error_string($this->error_code);
 
83
  $return = false;
84
  }
85
 
@@ -93,7 +110,7 @@ class FeedWordPress_Parser extends SimplePie_Parser {
93
  else
94
  {
95
  libxml_clear_errors();
96
- $xml =& new XMLReader();
97
  $xml->xml($data);
98
  while (@$xml->read())
99
  {
1
  <?php
2
  class FeedWordPress_Parser extends SimplePie_Parser {
3
  function parse (&$data, $encoding) {
4
+ $data = apply_filters('feedwordpress_parser_parse', $data, $encoding, $this);
5
+
6
  // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
7
  if (strtoupper($encoding) === 'US-ASCII')
8
  {
42
 
43
  if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
44
  {
45
+ $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
46
  if ($declaration->parse())
47
  {
48
  $data = substr($data, $pos + 2);
80
  // Parse!
81
  if (!xml_parse($xml, $data, true))
82
  {
83
+ if (class_exists('DOMDocument')) :
84
+ libxml_use_internal_errors(true);
85
+ $doc = new DOMDocument;
86
+ $doc->loadHTML('<html>'.$data.'</html>');
87
+ ///*DBG*/ echo "<plaintext>";
88
+ ///*DBG*/ $dd = $doc->getElementsByTagName('html');
89
+ ///*DBG*/ for ($i = 0; $i < $dd->length; $i++) :
90
+ ///*DBG*/ var_dump($dd->item($i)->nodeName);
91
+ ///*DBG*/ endfor;
92
+ ///*DBG*/ var_dump($doc);
93
+ libxml_use_internal_errors(false);
94
+ ///*DBG*/ die;
95
+ endif;
96
+
97
  $this->error_code = xml_get_error_code($xml);
98
  $this->error_string = xml_error_string($this->error_code);
99
+ ///*DBG*/ echo "WOOGA WOOGA"; var_dump($this->error_string); die;
100
  $return = false;
101
  }
102
 
110
  else
111
  {
112
  libxml_clear_errors();
113
+ $xml = new XMLReader();
114
  $xml->xml($data);
115
  while (@$xml->read())
116
  {
feedwordpresshtml.class.php CHANGED
@@ -38,7 +38,7 @@ class FeedWordPressHTML {
38
  );
39
  } /* function FeedWordPressHTML::attributeMatch () */
40
 
41
- function tagWithAttributeRegex ($tag, $attr, $value) {
42
  return ":(
43
  (<($tag)\s+[^>]*)
44
  ($attr)=
@@ -50,13 +50,14 @@ class FeedWordPressHTML {
50
  |
51
  \s*((?!/>)($value))
52
  ([^>]*>)
53
- )
54
  (((?!</($tag)>).)*)
55
  (</($tag)>)
 
56
  :ix";
57
  } /* FeedWordPressHTML::tagWithAttributeRegex () */
58
 
59
- function tagWithAttributeMatch ($matches) {
60
  for ($i = 0; $i <= 21; $i++) :
61
  if (!isset($matches[$i])) :
62
  $matches[$i] = '';
@@ -77,8 +78,8 @@ class FeedWordPressHTML {
77
  "before_attribute" => $matches[2],
78
  "after_attribute" => $suffix,
79
  "open_tag" => $matches[1].$matches[6].$value.$matches[6].$suffix,
80
- "content" => $matches[17],
81
- "close_tag" => $matches[20],
82
  );
83
 
84
  } /* FeedWordPressHTML::tagWithAttributeMatch () */
38
  );
39
  } /* function FeedWordPressHTML::attributeMatch () */
40
 
41
+ function tagWithAttributeRegex ($tag, $attr, $value, $closing = true) {
42
  return ":(
43
  (<($tag)\s+[^>]*)
44
  ($attr)=
50
  |
51
  \s*((?!/>)($value))
52
  ([^>]*>)
53
+ )".($closing ? "
54
  (((?!</($tag)>).)*)
55
  (</($tag)>)
56
+ " : "")."
57
  :ix";
58
  } /* FeedWordPressHTML::tagWithAttributeRegex () */
59
 
60
+ function tagWithAttributeMatch ($matches, $closing = true) {
61
  for ($i = 0; $i <= 21; $i++) :
62
  if (!isset($matches[$i])) :
63
  $matches[$i] = '';
78
  "before_attribute" => $matches[2],
79
  "after_attribute" => $suffix,
80
  "open_tag" => $matches[1].$matches[6].$value.$matches[6].$suffix,
81
+ "content" => ($closing ? $matches[17] : NULL),
82
+ "close_tag" => ($closing ? $matches[20] : NULL),
83
  );
84
 
85
  } /* FeedWordPressHTML::tagWithAttributeMatch () */
feedwordpresshttpauthenticator.class.php CHANGED
@@ -2,18 +2,14 @@
2
  class FeedWordPressHTTPAuthenticator {
3
  var $args = array();
4
 
5
- function FeedWordPressHTTPAuthenticator () {
6
- self::__construct();
7
- }
8
-
9
  function __construct () {
10
- add_filter('use_curl_transport', array(&$this, 'digest_do_it'), 2, 1000);
11
  foreach (array('fsockopen', 'fopen', 'streams', 'http_extension') as $transport) :
12
- add_filter("use_{$transport}_transport", array(&$this, 'digest_dont'), 2, 1000);
13
  endforeach;
14
 
15
- add_filter('pre_http_request', array(&$this, 'pre_http_request'), 10, 3);
16
- add_action('http_api_curl', array(&$this, 'set_auth_options'), 1000, 1);
17
  } /* FeedWordPressHTTPAuthenticator::__construct () */
18
 
19
  function methods_available () {
@@ -45,70 +41,74 @@ class FeedWordPressHTTPAuthenticator {
45
  ));
46
 
47
  // Ruh roh...
48
- if (!is_null($this->args['authentication'])) :
49
- switch ($this->args['authentication']) :
50
- case '-' :
51
- // No HTTP Auth method. Remove this stuff.
52
- $this->args['authentication'] = NULL;
53
- $this->args['username'] = NULL;
54
- $this->args['password'] = NULL;
 
 
 
 
 
 
 
 
 
55
  break;
56
- case 'basic' :
57
- if ($this->have_curl($args, $url)) :
58
- // Don't need to do anything. http_api_curl hook takes care
59
- // of it.
60
- break;
61
- elseif ($this->have_streams($args, $url)) :
62
- // curl has a nice native way to jam in the username and
63
- // passwd but streams and fsockopen do not. So we have to
64
- // make a recursive call with the credentials in the URL.
65
- // Wee ha!
66
- $method = $this->args['authentication'];
67
- $credentials = $this->args['username'];
68
- if (!is_null($this->args['password'])) :
69
- $credentials .= ':'.$args['password'];
70
- endif;
71
-
72
- // Remove these so we don't recurse all the way down
73
- unset($this->args['authentication']);
74
- unset($this->args['username']);
75
- unset($this->args['password']);
76
-
77
- $url = preg_replace('!(https?://)!', '$1'.$credentials.'@', $url);
78
-
79
- // Subsidiary request
80
- $pre = wp_remote_request($url, $this->args);
81
- break;
82
- endif;
83
- case 'digest' :
84
- if ($this->have_curl($args, $url)) :
85
- // Don't need to do anything. http_api_curl hook takes care
86
- // of it.
87
- break;
88
- endif;
89
- default :
90
- if (is_callable('WP_Http', '_get_first_available_transport')) :
91
- $trans = WP_Http::_get_first_available_transport($args, $url);
92
- if (!$trans) :
93
- $trans = WP_Http::_get_first_available_transport(array(), $url);
94
- endif;
95
- elseif (is_callable('WP_Http', '_getTransport')) :
96
- $transports = WP_Http::_getTransport($args);
97
- $trans = get_class(reset($transports));
98
- else :
99
- $trans = 'HTTP';
100
  endif;
101
 
102
- $pre = new WP_Error('http_request_failed',
103
- sprintf(
104
- __('%s cannot use %s authentication with the %s transport.'),
105
- __CLASS__,
106
- $args['authentication'],
107
- $trans
108
- )
109
- );
110
- endswitch;
111
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  return $pre;
113
  } /* FeedWordPressHTTPAuthenticator::pre_http_request () */
114
 
2
  class FeedWordPressHTTPAuthenticator {
3
  var $args = array();
4
 
 
 
 
 
5
  function __construct () {
6
+ add_filter('use_curl_transport', array($this, 'digest_do_it'), 2, 1000);
7
  foreach (array('fsockopen', 'fopen', 'streams', 'http_extension') as $transport) :
8
+ add_filter("use_{$transport}_transport", array($this, 'digest_dont'), 2, 1000);
9
  endforeach;
10
 
11
+ add_filter('pre_http_request', array($this, 'pre_http_request'), 10, 3);
12
+ add_action('http_api_curl', array($this, 'set_auth_options'), 1000, 1);
13
  } /* FeedWordPressHTTPAuthenticator::__construct () */
14
 
15
  function methods_available () {
41
  ));
42
 
43
  // Ruh roh...
44
+ $auth = $this->args['authentication'];
45
+ if (is_null($auth) or (strlen($auth) == 0)) :
46
+ $this->args['authentication'] = '-';
47
+ endif;
48
+
49
+ switch ($this->args['authentication']) :
50
+ case '-' :
51
+ // No HTTP Auth method. Remove this stuff.
52
+ $this->args['authentication'] = NULL;
53
+ $this->args['username'] = NULL;
54
+ $this->args['password'] = NULL;
55
+ break;
56
+ case 'basic' :
57
+ if ($this->have_curl($args, $url)) :
58
+ // Don't need to do anything. http_api_curl hook takes care
59
+ // of it.
60
  break;
61
+ elseif ($this->have_streams($args, $url)) :
62
+ // curl has a nice native way to jam in the username and
63
+ // passwd but streams and fsockopen do not. So we have to
64
+ // make a recursive call with the credentials in the URL.
65
+ // Wee ha!
66
+ $method = $this->args['authentication'];
67
+ $credentials = $this->args['username'];
68
+ if (!is_null($this->args['password'])) :
69
+ $credentials .= ':'.$args['password'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  endif;
71
 
72
+ // Remove these so we don't recurse all the way down
73
+ unset($this->args['authentication']);
74
+ unset($this->args['username']);
75
+ unset($this->args['password']);
76
+
77
+ $url = preg_replace('!(https?://)!', '$1'.$credentials.'@', $url);
78
+
79
+ // Subsidiary request
80
+ $pre = wp_remote_request($url, $this->args);
81
+ break;
82
+ endif;
83
+ case 'digest' :
84
+ if ($this->have_curl($args, $url)) :
85
+ // Don't need to do anything. http_api_curl hook takes care
86
+ // of it.
87
+ break;
88
+ endif;
89
+ default :
90
+ if (is_callable('WP_Http', '_get_first_available_transport')) :
91
+ $trans = WP_Http::_get_first_available_transport($args, $url);
92
+ if (!$trans) :
93
+ $trans = WP_Http::_get_first_available_transport(array(), $url);
94
+ endif;
95
+ elseif (is_callable('WP_Http', '_getTransport')) :
96
+ $transports = WP_Http::_getTransport($args);
97
+ $trans = get_class(reset($transports));
98
+ else :
99
+ $trans = 'HTTP';
100
+ endif;
101
+
102
+ $pre = new WP_Error('http_request_failed',
103
+ sprintf(
104
+ __('%s cannot use %s authentication with the %s transport.'),
105
+ __CLASS__,
106
+ $args['authentication'],
107
+ $trans
108
+ )
109
+ );
110
+ endswitch;
111
+
112
  return $pre;
113
  } /* FeedWordPressHTTPAuthenticator::pre_http_request () */
114
 
feedwordpressparsedpostmeta.class.php ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FeedWordPressParsedPostMeta {
3
+ var $s, $ptr, $ptrEOS;
4
+ var $delims, $delimCount, $delimPtr;
5
+ var $paren;
6
+
7
+ var $parsed = NULL;
8
+
9
+ function __construct ($s) {
10
+ $this->s = $s;
11
+ $this->reset();
12
+ }
13
+
14
+ function reset () {
15
+ $this->parsed = NULL;
16
+
17
+ $this->ptr = 0;
18
+ $this->paren = 0;
19
+ $this->ptrEOS = strlen($this->s);
20
+
21
+ $this->delimCount['CDATA'] = preg_match_all('/\$/', $this->s, $this->delims['CDATA'], PREG_OFFSET_CAPTURE);
22
+ $this->delimPtr['CDATA'] = 0;
23
+
24
+ $this->delimCount['EXPR'] = preg_match_all('/[()\s]/', $this->s, $this->delims['EXPR'], PREG_OFFSET_CAPTURE);
25
+ $this->delimPtr['EXPR'] = 0;
26
+ }
27
+
28
+ function look () { return $this->s[$this->ptr]; }
29
+ function drop () { $this->anchor = $this->ptr; }
30
+ function take () { return substr($this->s, $this->anchor, ($this->ptr - $this->anchor)); }
31
+ function EOS () { return ($this->ptr >= $this->ptrEOS); }
32
+
33
+ function nextDelim ($which) {
34
+ $N = $this->delimCount[$which]; $ptr = $this->delimPtr[$which];
35
+
36
+ $next = -1;
37
+ while ( ($ptr < $N) and ($next < $this->ptr) ) :
38
+ $next = $this->delims[$which][0][$ptr][1];
39
+ $ptr++;
40
+ endwhile;
41
+ $this->delimPtr[$which] = $ptr;
42
+
43
+ if ($next < $this->ptr) :
44
+ $next = $this->ptrEOS;
45
+ endif;
46
+ return $next;
47
+ }
48
+
49
+ function substitute_terms ($post, $piece, $values = NULL) {
50
+ $terms = array();
51
+ if ('EXPR'==$piece[0]) :
52
+ // Parameter stored in $piece[1]
53
+ $param = $piece[1];
54
+ if (is_string($param)) :
55
+ if (!isset($values[$param])) :
56
+ $values[$param] = $post->query($param);
57
+ endif;
58
+ $term = $param;
59
+ $results = $values[$param];
60
+ else :
61
+ list($results, $term, $values) = $this->substitute_terms($post, $piece[1], $values);
62
+ endif;
63
+
64
+ // Filtering function, if any, stored in $piece[2]
65
+ if (isset($piece[2])) :
66
+ $filter = $post->substitution_function(trim(strtolower($piece[2])));
67
+ if (!is_null($filter)) :
68
+ foreach ($results as $key => $result) :
69
+ $results[$key] = $filter($result);
70
+ endforeach;
71
+ else :
72
+ $results = array(
73
+ "[[ERR: No such function (".$piece[2].")]]",
74
+ );
75
+ endif;
76
+ endif;
77
+
78
+ elseif ('CDATA'==$piece[0]) :
79
+ // Literal string stored in $piece[1]
80
+ $results = array($piece[1]);
81
+ $term = NULL;
82
+ endif;
83
+ return array($results, $term, $values);
84
+ }
85
+
86
+ function do_substitutions ($post, $in = NULL, $scratchpad = NULL) {
87
+ if (is_null($in)) :
88
+ $in = $this->get();
89
+ endif;
90
+
91
+ if (count($in) > 0) :
92
+ $out = array();
93
+
94
+ // Init. results set if not already initialized.
95
+ if (is_null($scratchpad)) :
96
+ $scratchpad = array(array('', array()));
97
+ endif;
98
+
99
+ // Grab the first
100
+ $piece = array_shift($in);
101
+
102
+ foreach ($scratchpad as $key => $scratch) :
103
+ $line = $scratch[0];
104
+ $element_values = $scratch[1];
105
+
106
+ switch ($piece[0]) :
107
+ case 'CDATA' :
108
+ $subs = array($piece[1]);
109
+ $term = NULL;
110
+ break;
111
+ case 'EXPR' :
112
+ list($subs, $term, $element_values) = $this->substitute_terms($post, $piece, $element_values);
113
+ break;
114
+ endswitch;
115
+
116
+ $constrained_values = $element_values;
117
+ foreach ($subs as $sub) :
118
+
119
+ if (isset($term)) :
120
+ $constrained_values[$term] = array($sub);
121
+ endif;
122
+
123
+ $out[] = array($line . $sub, $constrained_values);
124
+ endforeach;
125
+
126
+ endforeach;
127
+
128
+ if (count($in) > 0) :
129
+ $out = $this->do_substitutions($post, $in, $out);
130
+ endif;
131
+ else :
132
+ $out = NULL;
133
+ endif;
134
+
135
+ // Now that we are done, strip out the namespace elements.
136
+ if (is_array($out)) :
137
+ foreach ($out as $idx => $line) :
138
+ if (is_array($line)) :
139
+ $out[$idx] = $line[0];
140
+ endif;
141
+ endforeach;
142
+ endif;
143
+
144
+ return $out;
145
+ }
146
+
147
+ function get ($idx = NULL) {
148
+ $ret = $this->parse();
149
+ if ($idx) : $ret = $ret[$idx]; endif;
150
+
151
+ return $ret;
152
+ }
153
+
154
+ function parse () {
155
+ if (is_null($this->parsed)) :
156
+ $out = array();
157
+
158
+ $this->reset();
159
+ while (!$this->EOS()) :
160
+ switch ($this->look()) :
161
+ case '$' :
162
+ $this->ptr++;
163
+ $out[] = $this->EXPR();
164
+ break;
165
+ default :
166
+ $out[] = $this->CDATA();
167
+ endswitch;
168
+ endwhile;
169
+
170
+ $this->parsed = $out;
171
+ endif;
172
+ return $this->parsed;
173
+ }
174
+
175
+ function CDATA () {
176
+ $this->drop();
177
+ $this->ptr = $this->nextDelim('CDATA');
178
+ return array(__FUNCTION__, $this->take());
179
+ } /* FeedWordPressParsedPostMeta::CDATA() */
180
+
181
+ function EXPR () {
182
+ $ret = array(__FUNCTION__);
183
+ $paren0 = $this->paren;
184
+ $this->drop();
185
+
186
+ $ptr0 = $this->ptr;
187
+
188
+ $complete = false;
189
+ while (!$this->EOS() and !$complete) :
190
+ $tok = $this->look();
191
+ switch ($tok) :
192
+ case '(' :
193
+
194
+ $fun = $this->take();
195
+
196
+ // We're at the open paren; skip ahead past that.
197
+ $this->ptr++;
198
+
199
+ // And indent us one level in.
200
+ $this->paren++;
201
+
202
+ $delta = $this->EXPR();
203
+ if (isset($delta[2])) :
204
+ $ret[1] = $delta;
205
+ else :
206
+ $ret[1] = $delta[1];
207
+ endif;
208
+
209
+ if (strlen(trim($fun)) > 0) :
210
+ $ret[2] = trim($fun);
211
+ endif;
212
+
213
+ // We should be stopped on either a close paren or on EOS.
214
+ $this->ptr++;
215
+
216
+ // A top level expression terminates
217
+ // immediately with the closing of its
218
+ // parens. Lower-level expressions may
219
+ // have whitespace wrapper, etc.
220
+ $complete = ($this->paren <= 0);
221
+
222
+ $this->drop();
223
+ break;
224
+
225
+ case ')' :
226
+
227
+ if ($this->paren > 0) :
228
+ $this->paren--;
229
+
230
+ $complete = ($this->paren <= $paren0);
231
+
232
+ $fun = $this->take();
233
+ if (strlen(trim($fun)) > 0) :
234
+ $ret[1] = trim($fun);
235
+ endif;
236
+
237
+ $this->drop();
238
+ else :
239
+ $this->ptr++;
240
+ endif;
241
+ break;
242
+
243
+ case '$' :
244
+ if ($ptr0 == $this->ptr) :
245
+ // This is an escaped literal $
246
+ $this->ptr++;
247
+ $ret = array('CDATA', $tok);
248
+ $this->drop();
249
+ $complete = true;
250
+ break;
251
+ endif;
252
+
253
+ default :
254
+ if (ctype_space($tok) and ($this->paren <= 0)) :
255
+ // A loose $ should be treated as a literal $
256
+ if ($ptr0 == $this->ptr) :
257
+ $ret = array('CDATA', '$');
258
+ $this->drop();
259
+ endif;
260
+ $complete = true;
261
+ else :
262
+ $next = $this->nextDelim('EXPR');
263
+
264
+ // Skip ahead to the next potentially interesting character.
265
+ if (!is_null($next)) :
266
+ $this->ptr = $next;
267
+ else :
268
+ $this->ptr = $this->ptrEOS;
269
+ endif;
270
+
271
+ endif;
272
+ endswitch;
273
+ endwhile;
274
+
275
+ $var = '';
276
+ if ($this->anchor < $this->ptr) :
277
+ $var = trim($this->take());
278
+ endif;
279
+ if (strlen($var) > 0) :
280
+ $ret[1] = $var;
281
+ endif;
282
+ return $ret;
283
+ } /* FeedWordPressParsedPostMeta::EXPR () */
284
+ } /* class FeedWordPressParsedPostMeta */
285
+
286
+ if (basename($_SERVER['SCRIPT_FILENAME'])==basename(__FILE__)) :
287
+ $argv = $_SERVER['argv'];
288
+ array_shift($argv);
289
+ $N = reset($argv);
290
+ if (is_numeric($N)) :
291
+ array_shift($argv);
292
+ else :
293
+ $N = 1;
294
+ endif;
295
+
296
+ $t0 = microtime(/*float=*/ true);
297
+ for ($i = 0; $i < $N; $i++) :
298
+ $parse = new FeedWordPressParsedPostMeta(implode(" ", $argv));
299
+ $voo = ($parse->parse());
300
+ unset($parse);
301
+ endfor;
302
+ $t1 = microtime(/*float=*/ true);
303
+
304
+ echo "RESULT: "; var_dump($voo);
305
+ echo "ELAPSED TIME: "; print number_format(1000.0 * ($t1 - $t0)) . "ms\n";
306
+ echo "CONSUMED MEMORY: "; print number_format(memory_get_peak_usage() / 1024) . "KB\n";
307
+ endif;
308
+
feedwordpressrpc.class.php CHANGED
@@ -5,15 +5,15 @@
5
 
6
  class FeedWordPressRPC {
7
  function FeedWordPressRPC () {
8
- add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
9
  }
10
 
11
  function xmlrpc_methods ($args = array()) {
12
- $args['weblogUpdates.ping'] = array(&$this, 'ping');
13
- $args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
14
- $args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
15
- $args['feedwordpress.delete'] = array(&$this, 'delete');
16
- $args['feedwordpress.nuke'] = array(&$this, 'nuke');
17
  return $args;
18
  }
19
 
5
 
6
  class FeedWordPressRPC {
7
  function FeedWordPressRPC () {
8
+ add_filter('xmlrpc_methods', array($this, 'xmlrpc_methods'));
9
  }
10
 
11
  function xmlrpc_methods ($args = array()) {
12
+ $args['weblogUpdates.ping'] = array($this, 'ping');
13
+ $args['feedwordpress.subscribe'] = array($this, 'subscribe');
14
+ $args['feedwordpress.deactivate'] = array($this, 'deactivate');
15
+ $args['feedwordpress.delete'] = array($this, 'delete');
16
+ $args['feedwordpress.nuke'] = array($this, 'nuke');
17
  return $args;
18
  }
19
 
feedwordpresssyndicationpage.class.php CHANGED
@@ -340,8 +340,6 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
340
  return;
341
  endif;
342
 
343
- ?>
344
- <?php
345
  $cont = true;
346
  $dispatcher = array(
347
  "feedfinder" => 'fwp_feedfinder_page',
@@ -352,8 +350,10 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
352
  'Unsubscribe' => 'multidelete_page',
353
  FWP_RESUB_CHECKED => 'multiundelete_page',
354
  );
355
- if (isset($_REQUEST['action']) and isset($dispatcher[$_REQUEST['action']])) :
356
- $method = $dispatcher[$_REQUEST['action']];
 
 
357
  if (method_exists($this, $method)) :
358
  $cont = $this->{$method}();
359
  else :
@@ -384,7 +384,7 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
384
  add_meta_box(
385
  /*id=*/ 'feedwordpress_feeds_box',
386
  /*title=*/ __('Syndicated sources'),
387
- /*callback=*/ array(&$this, 'syndicated_sources_box'),
388
  /*page=*/ $this->meta_box_context(),
389
  /*context =*/ $this->meta_box_context()
390
  );
@@ -431,10 +431,11 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
431
 
432
  // Hey ho, let's go...
433
  ?>
 
 
434
  <p class="info" style="margin-bottom: 0px; border-bottom: 1px dotted black;">Managed by <a href="http://feedwordpress.radgeek.com/">FeedWordPress</a>
435
  <?php print FEEDWORDPRESS_VERSION; ?>.</p>
436
  <?php if (FEEDWORDPRESS_BLEG) : ?>
437
- <div style="float: left; background: white; margin-top: 5px; margin-right: 5px;"><a href="<?php print $this->form_action(); ?>"><img src="<?php print esc_html(WP_PLUGIN_URL.'/'.$GLOBALS['fwp_path'].'/feedwordpress.png'); ?>" alt="" /></a></div>
438
  <p class="info" style="margin-top: 0px; font-style: italic; font-size: 75%; color: #666;">If you find this tool useful for your daily work, you can
439
  contribute to ongoing support and development with
440
  <a href="http://feedwordpress.radgeek.com/donate/">a modest donation</a>.</p>
@@ -488,8 +489,8 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
488
  value="Source URL" style="width: 55%;" /></label>
489
 
490
  <?php FeedWordPressSettingsUI::magic_input_tip_js('add-uri'); ?>
491
-
492
- <input style="vertical-align: middle;" type="image" src="<?php print WP_PLUGIN_URL.'/'.$fwp_path; ?>/plus.png" alt="<?php print FWP_SYNDICATE_NEW; ?>" name="action" value="<?php print FWP_SYNDICATE_NEW; ?>" /></div>
493
  </form>
494
  </div> <!-- id="add-single-uri" -->
495
 
@@ -1145,7 +1146,7 @@ updated to &lt;<a href="<?php echo esc_html($fwp_post['feed']); ?>"><?php echo e
1145
 
1146
  if (isset($existingLink)) :
1147
  $auth = FeedWordPress::post('link_rss_auth_method');
1148
- if (!is_null($auth) and $auth != '-') :
1149
  $existingLink->update_setting('http auth method', $auth);
1150
  $existingLink->update_setting('http username',
1151
  FeedWordPress::post('link_rss_username')
340
  return;
341
  endif;
342
 
 
 
343
  $cont = true;
344
  $dispatcher = array(
345
  "feedfinder" => 'fwp_feedfinder_page',
350
  'Unsubscribe' => 'multidelete_page',
351
  FWP_RESUB_CHECKED => 'multiundelete_page',
352
  );
353
+
354
+ $act = FeedWordPress::param('action');
355
+ if (isset($dispatcher[$act])) :
356
+ $method = $dispatcher[$act];
357
  if (method_exists($this, $method)) :
358
  $cont = $this->{$method}();
359
  else :
384
  add_meta_box(
385
  /*id=*/ 'feedwordpress_feeds_box',
386
  /*title=*/ __('Syndicated sources'),
387
+ /*callback=*/ array($this, 'syndicated_sources_box'),
388
  /*page=*/ $this->meta_box_context(),
389
  /*context =*/ $this->meta_box_context()
390
  );
431
 
432
  // Hey ho, let's go...
433
  ?>
434
+ <div style="float: left; background: #F5F5F5; padding-top: 5px; padding-right: 5px;"><a href="<?php print $this->form_action(); ?>"><img src="<?php print esc_html(WP_PLUGIN_URL.'/'.$GLOBALS['fwp_path'].'/feedwordpress.png'); ?>" alt="" /></a></div>
435
+
436
  <p class="info" style="margin-bottom: 0px; border-bottom: 1px dotted black;">Managed by <a href="http://feedwordpress.radgeek.com/">FeedWordPress</a>
437
  <?php print FEEDWORDPRESS_VERSION; ?>.</p>
438
  <?php if (FEEDWORDPRESS_BLEG) : ?>
 
439
  <p class="info" style="margin-top: 0px; font-style: italic; font-size: 75%; color: #666;">If you find this tool useful for your daily work, you can
440
  contribute to ongoing support and development with
441
  <a href="http://feedwordpress.radgeek.com/donate/">a modest donation</a>.</p>
489
  value="Source URL" style="width: 55%;" /></label>
490
 
491
  <?php FeedWordPressSettingsUI::magic_input_tip_js('add-uri'); ?>
492
+ <input type="hidden" name="action" value="<?php print FWP_SYNDICATE_NEW; ?>" />
493
+ <input style="vertical-align: middle;" type="image" src="<?php print WP_PLUGIN_URL.'/'.$fwp_path; ?>/plus.png" alt="<?php print FWP_SYNDICATE_NEW; ?>" /></div>
494
  </form>
495
  </div> <!-- id="add-single-uri" -->
496
 
1146
 
1147
  if (isset($existingLink)) :
1148
  $auth = FeedWordPress::post('link_rss_auth_method');
1149
+ if (!is_null($auth) and (strlen($auth) > 0) and ($auth != '-')) :
1150
  $existingLink->update_setting('http auth method', $auth);
1151
  $existingLink->update_setting('http username',
1152
  FeedWordPress::post('link_rss_username')
magpiefromsimplepie.class.php CHANGED
@@ -155,7 +155,8 @@ class MagpieFromSimplePie {
155
  endforeach;
156
  endforeach;
157
  endforeach; endif;
158
- return $ret;
 
159
  } /* MagpieFromSimplePie::processFeedData() */
160
 
161
  /**
@@ -183,7 +184,7 @@ class MagpieFromSimplePie {
183
  + $this->handleChildren($data, $path, 'processChannelData')
184
  + $ret;
185
 
186
- return $ret;
187
  } /* MagpieFromSimplePie::processChannelData() */
188
 
189
  /**
@@ -213,7 +214,7 @@ class MagpieFromSimplePie {
213
  + $this->handleChildren($data, $path, 'processItemData')
214
  + $ret;
215
 
216
- return $ret;
217
  } /* MagpieFromSimplePie::processItemData() */
218
 
219
  /**
@@ -250,7 +251,8 @@ class MagpieFromSimplePie {
250
  endif;
251
  endforeach;
252
  endforeach; endif;
253
- return $ret;
 
254
  } /* MagpieFromSimplePie::handleAttributes() */
255
 
256
  var $inImage = false;
@@ -346,7 +348,8 @@ class MagpieFromSimplePie {
346
  endforeach; endforeach;
347
 
348
  endforeach; endif;
349
- return $ret;
 
350
  } /* MagpieFromSimplePie::handleChildren() */
351
 
352
  /**
@@ -386,6 +389,8 @@ class MagpieFromSimplePie {
386
  * @uses FeedTime::timestamp
387
  */
388
  function normalize () {
 
 
389
  if (!is_null($this->channel)) :
390
  // Normalize channel data
391
  if ( $this->is_atom() ) :
@@ -497,6 +502,8 @@ class MagpieFromSimplePie {
497
  $this->items[$i] = $item;
498
  endfor;
499
  endif;
 
 
500
  } /* MagpieFromSimplePie::normalize() */
501
 
502
  /**
155
  endforeach;
156
  endforeach;
157
  endforeach; endif;
158
+
159
+ return apply_filters('feedwordpress_magpiefromsimplepie_processfeeddata', $ret, $data, $this);
160
  } /* MagpieFromSimplePie::processFeedData() */
161
 
162
  /**
184
  + $this->handleChildren($data, $path, 'processChannelData')
185
  + $ret;
186
 
187
+ return apply_filters('feedwordpress_magpiefromsimplepie_processchanneldata', $ret, $data, $path, $this);
188
  } /* MagpieFromSimplePie::processChannelData() */
189
 
190
  /**
214
  + $this->handleChildren($data, $path, 'processItemData')
215
  + $ret;
216
 
217
+ return apply_filters('feedwordpress_magpiefromsimplepie_processitemdata', $ret, $data, $path, $this);
218
  } /* MagpieFromSimplePie::processItemData() */
219
 
220
  /**
251
  endif;
252
  endforeach;
253
  endforeach; endif;
254
+
255
+ return apply_filters('feedwordpress_magpiefromsimplepie_handleattributes', $ret, $data, $path, $this);
256
  } /* MagpieFromSimplePie::handleAttributes() */
257
 
258
  var $inImage = false;
348
  endforeach; endforeach;
349
 
350
  endforeach; endif;
351
+
352
+ return apply_filters('feedwordpress_magpiefromsimplepie_handlechildren', $ret, $data, $path, $method, $this);
353
  } /* MagpieFromSimplePie::handleChildren() */
354
 
355
  /**
389
  * @uses FeedTime::timestamp
390
  */
391
  function normalize () {
392
+ do_action('feedwordpress_magpiefromsimplepie_normalize_pre', $this);
393
+
394
  if (!is_null($this->channel)) :
395
  // Normalize channel data
396
  if ( $this->is_atom() ) :
502
  $this->items[$i] = $item;
503
  endfor;
504
  endif;
505
+
506
+ do_action('feedwordpress_magpiefromsimplepie_normalize_post', $this);
507
  } /* MagpieFromSimplePie::normalize() */
508
 
509
  /**
performance-page.php CHANGED
@@ -79,9 +79,19 @@ class FeedWordPressPerformancePage extends FeedWordPressAdminPage {
79
  $feeds = (($N == 1) ? __("feed") : __("feeds"));
80
  $this->updated = sprintf(__("Cleared %d cached %s from WordPress database."), $N, $feeds);
81
  endif;
 
 
 
 
 
 
 
 
82
  } /* FeedWordPressPerformancePage::accept_POST () */
83
 
84
  /*static*/ function performance_box ($page, $box = NULL) {
 
 
85
  // Hey ho, let's go...
86
  ?>
87
  <table class="editform" width="100%" cellspacing="2" cellpadding="5">
@@ -106,6 +116,34 @@ table. If you'd like to remove the index for any reason, you can do so here.</p>
106
 
107
  <?php endif; ?>
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  </td>
111
  </tr>
79
  $feeds = (($N == 1) ? __("feed") : __("feeds"));
80
  $this->updated = sprintf(__("Cleared %d cached %s from WordPress database."), $N, $feeds);
81
  endif;
82
+
83
+ if (isset($post['optimize_in'])) :
84
+ update_option('feedwordpress_optimize_in_clauses', true);
85
+ $this->updated = sprintf(__("Enabled optimizing inefficient IN clauses in SQL queries."));
86
+ elseif (isset($post['optimize_out'])) :
87
+ update_option('feedwordpress_optimize_in_clauses', false);
88
+ $this->updated = sprintf(__("Disabled optimizing inefficient IN clauses in SQL queries."));
89
+ endif;
90
  } /* FeedWordPressPerformancePage::accept_POST () */
91
 
92
  /*static*/ function performance_box ($page, $box = NULL) {
93
+ $optimize_in = get_option('feedwordpress_optimize_in_clauses', false);
94
+
95
  // Hey ho, let's go...
96
  ?>
97
  <table class="editform" width="100%" cellspacing="2" cellpadding="5">
116
 
117
  <?php endif; ?>
118
 
119
+ <tr style="vertical-align: top">
120
+ <th width="33%" scope="row">Optimize IN clauses:</th>
121
+ <td width="67%"><?php if (!$optimize_in) : ?>
122
+ <input class="button" type="submit" name="optimize_in" value="Optimize inefficient IN clauses in SQL queries" />
123
+
124
+ <p><strong>Advanced setting.</strong> As of releases up to 3.3.2, WordPress
125
+ still generates many SQL queries with an extremely inefficient use of the IN
126
+ operator (for example, <code>SELECT user_id, meta_key, meta_value FROM
127
+ wp_usermeta WHERE user_id IN (1)</code>). When there is only one item in the
128
+ set, the IN operator is unnecessary; and inefficient, because it prevents SQL
129
+ from making use of indexes on the table being queried. Activating this setting
130
+ will cause these queries to get rewritten to use a simple equality operator when
131
+ there is only one item in the set (for example, the example query above would be
132
+ rewritten as <code>SELECT user_id, meta_key, meta_value FROM wp_usermeta WHERE
133
+ user_id = 1</code>).</p>
134
+
135
+ <p><strong>Note.</strong> This is an advanced setting, which affects WordPress's
136
+ database queries at a very low level. The change should be harmless, but
137
+ proceed with caution, and only if you are confident in your ability to restore
138
+ your WordPress installation from backups if something important should stop
139
+ working.</p>
140
+
141
+ <?php else : ?>
142
+ <input class="button" type="submit" name="optimize_out" value="Disable optimizing inefficient IN clauses" />
143
+ <p>You can use this setting to disable any attempts by FeedWordPress to optimize
144
+ or rewrite WordPress's SQL queries.</p>
145
+ <?php endif; ?></td>
146
+ </tr>
147
 
148
  </td>
149
  </tr>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: Charles Johnson
3
  Donate link: http://feedwordpress.radgeek.com/
4
  Tags: syndication, aggregation, feed, atom, rss
5
  Requires at least: 3.0
6
- Tested up to: 3.2.1
7
- Stable tag: 2011.1019
8
 
9
  FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
10
 
@@ -94,6 +94,53 @@ outs, see the documentation at the [FeedWordPress project homepage][].
94
 
95
  == Changelog ==
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  = 2011.1019 =
98
 
99
  * BUGFIX: "THERE ARE NO HTTP TRANSPORTS AVAILABLE" ERROR FIXED: The initial
3
  Donate link: http://feedwordpress.radgeek.com/
4
  Tags: syndication, aggregation, feed, atom, rss
5
  Requires at least: 3.0
6
+ Tested up to: 3.5
7
+ Stable tag: 2012.1212
8
 
9
  FeedWordPress syndicates content from feeds you choose into your WordPress weblog.
10
 
94
 
95
  == Changelog ==
96
 
97
+ = 2012.1212 =
98
+
99
+ * WORDPRESS 3.5 COMPATIBILITY: This release has been tested for compatibility
100
+ with new releases of WordPress, up to version 3.5, and any documented
101
+ compatibility issues have been cleared -- in particular, if you were seeing
102
+ error pages stating that you don't have permission to access the
103
+ FeedWordPress Syndication page within the WordPress admin interface, then
104
+ upgrading to this release should fix the problem.
105
+
106
+ As always, if you encounter any compatibility problems after upgrading your
107
+ version of WordPress and your version of FeedWordPress to the most recent
108
+ versions, please contact me with as detailed a description as possible of
109
+ the issue you are encountering, the circumstances you're encountering it
110
+ under, what you expect to see happening, and what is happening instead.
111
+
112
+ * PHP 5.4 COMPATIBILITY: This release has been audited to fix potential
113
+ problems with deprecation notices or fatal errors under recent versions
114
+ of PHP. In particular, all uses of run-time pass-by-reference have been
115
+ eliminated from the code; if you were seeing a fatal error reading
116
+ "Call-time pass-by-reference has been removed ..." then upgrading to
117
+ this release should fix the problem.
118
+
119
+ * CUSTOMIZATION FRAMEWORK: A great deal of work has been done to make the
120
+ underlying framework more flexible, so that PHP add-ons can be written
121
+ to adapt FeedWordPress to handle custom XML vocabularies, expiration of
122
+ posts under specified conditions, and other custom behavior.
123
+
124
+ * BUGFIX: MANUALLY EDITED POST SLUGS NOT OVERWRITTEN. Thanks to a report
125
+ by Chris Fritz, I've identified some code that causes post slugs for the
126
+ posts generated by FWP to be rewritten with every update, even if the
127
+ user has manually updated the slug from within the WordPress editing
128
+ interface. This has been fixed: FWP will continue to generate new slugs
129
+ for syndicated posts, but when syndicated posts are updated, they will
130
+ retain the slug that they had at the time of the update; any manual
131
+ changes to the post slug should be preserved.
132
+
133
+ * USER-AGENT STRING: FeedWordPress now sends a distinctive User-Agent
134
+ string identifying itself, and noting that it is a feed aggregator.
135
+
136
+ * MISCELLANEOUS PERFORMANCE IMPROVEMENTS: A number of changes have been
137
+ made to try to reduce the intensity and expense in terms of both
138
+ database performance and web server memory consumption.
139
+
140
+ * DIAGNOSTICS IMPROVEMENTS: A number of new and improved diagnostics have
141
+ been added which should aid in understanding and troubleshooting issues
142
+ that may arise.
143
+
144
  = 2011.1019 =
145
 
146
  * BUGFIX: "THERE ARE NO HTTP TRANSPORTS AVAILABLE" ERROR FIXED: The initial
syndicatedlink.class.php CHANGED
@@ -34,6 +34,7 @@
34
  # the function `get_feed_meta($key)` if this plugin is activated.
35
 
36
  require_once(dirname(__FILE__).'/magpiefromsimplepie.class.php');
 
37
 
38
  class SyndicatedLink {
39
  var $id = null;
@@ -49,121 +50,25 @@ class SyndicatedLink {
49
  $this->link = $link;
50
  $this->id = $link->link_id;
51
  else :
52
- $this->id = $link;
53
- if (function_exists('get_bookmark')) : // WP 2.1+
54
- $this->link = get_bookmark($link);
55
- else :
56
- $this->link = $wpdb->get_row("
57
- SELECT * FROM $wpdb->links
58
- WHERE (link_id = '".$wpdb->escape($link)."')"
59
- );
60
- endif;
61
  endif;
62
 
63
  if (strlen($this->link->link_rss) > 0) :
64
- // Read off feed settings from link_notes
65
- $notes = explode("\n", $this->link->link_notes);
66
- foreach ($notes as $note):
67
- $pair = explode(": ", $note, 2);
68
- $key = (isset($pair[0]) ? $pair[0] : null);
69
- $value = (isset($pair[1]) ? $pair[1] : null);
70
- if (!is_null($key) and !is_null($value)) :
71
- // Unescape and trim() off the whitespace.
72
- // Thanks to Ray Lischner for pointing out the
73
- // need to trim off whitespace.
74
- $this->settings[$key] = stripcslashes (trim($value));
75
- endif;
76
- endforeach;
77
-
78
- // "Magic" feed settings
79
- $this->settings['link/uri'] = $this->link->link_rss;
80
- $this->settings['link/name'] = $this->link->link_name;
81
- $this->settings['link/id'] = $this->link->link_id;
82
-
83
- // `hardcode categories` and `unfamiliar categories` are deprecated in favor of `unfamiliar category`
84
- if (
85
- isset($this->settings['unfamiliar categories'])
86
- and !isset($this->settings['unfamiliar category'])
87
- ) :
88
- $this->settings['unfamiliar category'] = $this->settings['unfamiliar categories'];
89
- endif;
90
- if (
91
- FeedWordPress::affirmative($this->settings, 'hardcode categories')
92
- and !isset($this->settings['unfamiliar category'])
93
- ) :
94
- $this->settings['unfamiliar category'] = 'default';
95
- endif;
96
-
97
- // Set this up automagically for del.icio.us
98
- $bits = parse_url($this->link->link_rss);
99
- $tagspacers = array('del.icio.us', 'feeds.delicious.com');
100
- if (!isset($this->settings['cat_split']) and in_array($bits['host'], $tagspacers)) :
101
- $this->settings['cat_split'] = '\s'; // Whitespace separates multiple tags in del.icio.us RSS feeds
102
- endif;
103
-
104
- // Simple lists
105
- foreach ($this->imploded_settings() as $what) :
106
- if (isset($this->settings[$what])):
107
- $this->settings[$what] = explode(
108
- FEEDWORDPRESS_CAT_SEPARATOR,
109
- $this->settings[$what]
110
- );
111
- endif;
112
- endforeach;
113
-
114
- if (isset($this->settings['terms'])) :
115
- // Look for new format
116
- $this->settings['terms'] = maybe_unserialize($this->settings['terms']);
117
-
118
- if (!is_array($this->settings['terms'])) :
119
- // Deal with old format instead. Ugh.
120
-
121
- // Split on two *or more* consecutive breaks
122
- // because in the old format, a taxonomy
123
- // without any associated terms would
124
- // produce tax_name#1\n\n\ntax_name#2\nterm,
125
- // and the naive split on the first \n\n
126
- // would screw up the tax_name#2 list.
127
- //
128
- // Props to David Morris for pointing this
129
- // out.
130
-
131
- $this->settings['terms'] = preg_split(
132
- "/".FEEDWORDPRESS_CAT_SEPARATOR."{2,}/",
133
- $this->settings['terms']
134
- );
135
- $terms = array();
136
- foreach ($this->settings['terms'] as $line) :
137
- $line = explode(FEEDWORDPRESS_CAT_SEPARATOR, $line);
138
- $tax = array_shift($line);
139
- $terms[$tax] = $line;
140
- endforeach;
141
- $this->settings['terms'] = $terms;
142
- endif;
143
- endif;
144
-
145
- if (isset($this->settings['map authors'])) :
146
- $author_rules = explode("\n\n", $this->settings['map authors']);
147
- $ma = array();
148
- foreach ($author_rules as $rule) :
149
- list($rule_type, $author_name, $author_action) = explode("\n", $rule);
150
-
151
- // Normalize for case and whitespace
152
- $rule_type = strtolower(trim($rule_type));
153
- $author_name = strtolower(trim($author_name));
154
- $author_action = strtolower(trim($author_action));
155
-
156
- $ma[$rule_type][$author_name] = $author_action;
157
- endforeach;
158
- $this->settings['map authors'] = $ma;
159
- endif;
160
  endif;
 
 
161
  } /* SyndicatedLink::SyndicatedLink () */
162
 
163
  function found () {
164
  return is_object($this->link) and !is_wp_error($this->link);
165
  } /* SyndicatedLink::found () */
166
 
 
 
 
 
167
  function stale () {
168
  global $feedwordpress;
169
 
@@ -197,10 +102,10 @@ class SyndicatedLink {
197
 
198
  $this->simplepie = apply_filters(
199
  'syndicated_feed',
200
- FeedWordPress::fetch($url, array('timeout' => $timeout)),
201
  $this
202
  );
203
-
204
  // Filter compatibility mode
205
  if (is_wp_error($this->simplepie)) :
206
  $this->magpie = $this->simplepie;
@@ -210,10 +115,10 @@ class SyndicatedLink {
210
 
211
  $new_count = NULL;
212
 
213
- $resume = FeedWordPress::affirmative($this->settings, 'update/unfinished');
214
  if ($resume) :
215
  // pick up where we left off
216
- $processed = array_map('trim', explode("\n", $this->settings['update/processed']));
217
  else :
218
  // begin at the beginning
219
  $processed = array();
@@ -236,26 +141,25 @@ class SyndicatedLink {
236
  // Copy over the in-error-since timestamp
237
  $theError['since'] = $oldError['since'];
238
 
239
- // If this is a repeat error, then we should take
240
- // a step back before we try to fetch it again.
241
- $this->settings['update/last'] = time();
242
- $this->settings['update/ttl'] = $this->automatic_ttl();
243
- $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this);
244
- $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl_from_error', $this->settings['update/ttl'], $this);
245
-
246
- $this->settings['update/timed'] = 'automatically';
 
247
  endif;
248
 
249
  do_action('syndicated_feed_error', $theError, $oldError, $this);
250
 
251
- $this->settings['update/error'] = serialize($theError);
252
  $this->save_settings(/*reload=*/ true);
253
 
254
  elseif (is_object($this->simplepie)) :
255
  // Success; clear out error setting, if any.
256
- if (isset($this->settings['update/error'])) :
257
- unset($this->settings['update/error']);
258
- endif;
259
 
260
  $new_count = array('new' => 0, 'updated' => 0);
261
 
@@ -282,30 +186,34 @@ class SyndicatedLink {
282
  $update[] = "link_description = '".$wpdb->escape($channel['description'])."'";
283
  endif;
284
  endif;
285
-
286
- $this->settings = array_merge($this->settings, $this->flatten_array($channel));
287
 
288
- $this->settings['update/last'] = time();
 
 
289
  list($ttl, $xml) = $this->ttl(/*return element=*/ true);
290
 
291
  if (!is_null($ttl)) :
292
- $this->settings['update/ttl'] = $ttl;
293
- $this->settings['update/xml'] = $xml;
294
- $this->settings['update/timed'] = 'feed';
295
  else :
296
  $ttl = $this->automatic_ttl();
297
- $this->settings['update/ttl'] = $ttl;
298
- $this->settings['update/xml'] = NULL;
299
- $this->settings['update/timed'] = 'automatically';
300
  endif;
301
- $this->settings['update/fudge'] = rand(0, ($ttl/3))*60;
302
- $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->setting('update/ttl'), $this);
 
 
 
 
303
 
304
  if (!$this->setting('update/hold') != 'ping') :
305
- $this->settings['update/hold'] = 'scheduled';
306
  endif;
307
 
308
- $this->settings['update/unfinished'] = 'yes';
309
 
310
  $update[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
311
 
@@ -325,11 +233,26 @@ class SyndicatedLink {
325
  $posts = apply_filters(
326
  'syndicated_feed_items',
327
  $this->simplepie->get_items(),
328
- &$this
329
  );
330
 
331
  $this->magpie->originals = $posts;
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  if (is_array($posts)) :
334
  foreach ($posts as $key => $item) :
335
  $post = new SyndicatedPost($item, $this);
@@ -349,18 +272,51 @@ class SyndicatedLink {
349
  unset($post);
350
  endforeach;
351
  endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  $suffix = ($crashed ? 'crashed' : 'completed');
353
  do_action('update_syndicated_feed_items', $this->id, $this);
354
  do_action("update_syndicated_feed_items_${suffix}", $this->id, $this);
355
 
356
- // Copy back any changes to feed settings made in the course of updating (e.g. new author rules)
357
- $to_notes = $this->settings;
358
-
359
- $this->settings['update/processed'] = $processed;
360
  if (!$crashed) :
361
- $this->settings['update/unfinished'] = 'no';
362
  endif;
 
363
 
 
 
364
  $update_set = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
365
 
366
  // Update the properties of the link from the feed information
@@ -386,6 +342,28 @@ class SyndicatedLink {
386
  return $new_count;
387
  } /* SyndicatedLink::poll() */
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  /**
390
  * Updates the URL for the feed syndicated by this link.
391
  *
@@ -466,9 +444,11 @@ class SyndicatedLink {
466
  $newuser_id = fwp_insert_new_user($newuser_name);
467
  if (is_numeric($newuser_id)) :
468
  if (is_null($name)) : // Unfamiliar author
469
- $this->settings['unfamiliar author'] = $newuser_id;
470
  else :
471
- $this->settings['map authors']['name'][$name] = $newuser_id;
 
 
472
  endif;
473
  else :
474
  // TODO: Add some error detection and reporting
@@ -481,6 +461,108 @@ class SyndicatedLink {
481
  function imploded_settings () {
482
  return array('cats', 'tags', 'match/cats', 'match/tags', 'match/filter');
483
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  function settings_to_notes () {
485
  $to_notes = $this->settings;
486
 
@@ -593,6 +675,11 @@ class SyndicatedLink {
593
  return $ret;
594
  } /* SyndicatedLink::setting () */
595
 
 
 
 
 
 
596
  function update_setting ($name, $value, $default = 'default') {
597
  if (!is_null($value) and $value != $default) :
598
  $this->settings[$name] = $value;
@@ -601,10 +688,14 @@ class SyndicatedLink {
601
  endif;
602
  } /* SyndicatedLink::update_setting () */
603
 
 
 
 
 
604
  function uri ($params = array()) {
605
- $params = shortcode_atts(array(
606
  'add_params' => false,
607
- ), $params);
608
 
609
  $uri = (is_object($this->link) ? $this->link->link_rss : NULL);
610
  if (!is_null($uri) and strlen($uri) > 0 and $params['add_params']) :
@@ -620,11 +711,11 @@ class SyndicatedLink {
620
  endforeach;
621
 
622
  // Are we appending to a URI that already has params?
623
- $sep = ((strpos('?', $uri)===false) ? '?' : '&');
624
 
625
  // Tack it on
626
  $uri .= $sep . implode("&", $q);
627
- endif;
628
  endif;
629
 
630
  return $uri;
@@ -645,15 +736,61 @@ class SyndicatedLink {
645
  endif;
646
  return $auth;
647
  } /* SyndicatedLink::authentication_method () */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
 
649
- function property_cascade ($fromFeed, $link_field, $setting, $simplepie_method) {
650
  $value = NULL;
651
  if ($fromFeed) :
652
- if (isset($this->settings[$setting])) :
653
- $value = $this->settings[$setting];
654
- elseif (is_object($this->simplepie)
655
- and method_exists($this->simplepie, $simplepie_method)) :
656
- $value = $this->simplepie->{$simplepie_method}();
 
657
  endif;
658
  else :
659
  $value = $this->link->{$link_field};
@@ -789,17 +926,13 @@ class SyndicatedLink {
789
  } /* SyndicatedLink::flatten_array () */
790
 
791
  function hardcode ($what) {
792
- $default = get_option("feedwordpress_hardcode_$what");
793
- if ( $default === 'yes' ) :
794
- // If the default is to hardcode, then we want the
795
- // negation of negative(): TRUE by default and FALSE if
796
- // the setting is explicitly "no"
797
- $ret = !FeedWordPress::negative($this->settings, "hardcode $what");
798
  else :
799
- // If the default is NOT to hardcode, then we want
800
- // affirmative(): FALSE by default and TRUE if the
801
- // setting is explicitly "yes"
802
- $ret = FeedWordPress::affirmative($this->settings, "hardcode $what");
803
  endif;
804
  return $ret;
805
  } /* SyndicatedLink::hardcode () */
@@ -807,19 +940,8 @@ class SyndicatedLink {
807
  function syndicated_status ($what, $default, $fallback = true) {
808
  global $wpdb;
809
 
810
- // Use local setting if we have it
811
- if ( isset($this->settings["$what status"]) ) :
812
- $ret = $this->settings["$what status"];
813
-
814
- // Or fall back to global default if we can
815
- elseif ($fallback) :
816
- $ret = FeedWordPress::syndicated_status($what, $default);
817
-
818
- // Or use default value if we can't.
819
- else :
820
- $ret = $default;
821
-
822
- endif;
823
 
824
  return $wpdb->escape(trim(strtolower($ret)));
825
  } /* SyndicatedLink:syndicated_status () */
34
  # the function `get_feed_meta($key)` if this plugin is activated.
35
 
36
  require_once(dirname(__FILE__).'/magpiefromsimplepie.class.php');
37
+ require_once(dirname(__FILE__).'/feedwordpressparsedpostmeta.class.php');
38
 
39
  class SyndicatedLink {
40
  var $id = null;
50
  $this->link = $link;
51
  $this->id = $link->link_id;
52
  else :
53
+ $this->id = $link;
54
+ $this->link = get_bookmark($link);
 
 
 
 
 
 
 
55
  endif;
56
 
57
  if (strlen($this->link->link_rss) > 0) :
58
+ $this->get_settings_from_notes();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  endif;
60
+
61
+ add_filter('feedwordpress_update_complete', array($this, 'process_retirements'), 1000, 1);
62
  } /* SyndicatedLink::SyndicatedLink () */
63
 
64
  function found () {
65
  return is_object($this->link) and !is_wp_error($this->link);
66
  } /* SyndicatedLink::found () */
67
 
68
+ function id () {
69
+ return (is_object($this->link) ? $this->link->link_id : NULL);
70
+ }
71
+
72
  function stale () {
73
  global $feedwordpress;
74
 
102
 
103
  $this->simplepie = apply_filters(
104
  'syndicated_feed',
105
+ FeedWordPress::fetch($this, array('timeout' => $timeout)),
106
  $this
107
  );
108
+
109
  // Filter compatibility mode
110
  if (is_wp_error($this->simplepie)) :
111
  $this->magpie = $this->simplepie;
115
 
116
  $new_count = NULL;
117
 
118
+ $resume = ('yes'==$this->setting('update/unfinished'));
119
  if ($resume) :
120
  // pick up where we left off
121
+ $processed = array_map('trim', explode("\n", $this->setting('update/processed')));
122
  else :
123
  // begin at the beginning
124
  $processed = array();
141
  // Copy over the in-error-since timestamp
142
  $theError['since'] = $oldError['since'];
143
 
144
+ // If this is a repeat error, then we should
145
+ // take a step back before we try to fetch it
146
+ // again.
147
+ $this->update_setting('update/last', time(), NULL);
148
+ $ttl = $this->automatic_ttl();
149
+ $ttl = apply_filters('syndicated_feed_ttl', $ttl, $this);
150
+ $ttl = apply_filters('syndicated_feed_ttl_from_error', $ttl, $this);
151
+ $this->update_setting('update/ttl', $ttl, $this);
152
+ $this->update_setting('update/timed', 'automatically');
153
  endif;
154
 
155
  do_action('syndicated_feed_error', $theError, $oldError, $this);
156
 
157
+ $this->update_setting('update/error', serialize($theError));
158
  $this->save_settings(/*reload=*/ true);
159
 
160
  elseif (is_object($this->simplepie)) :
161
  // Success; clear out error setting, if any.
162
+ $this->update_setting('update/error', NULL);
 
 
163
 
164
  $new_count = array('new' => 0, 'updated' => 0);
165
 
186
  $update[] = "link_description = '".$wpdb->escape($channel['description'])."'";
187
  endif;
188
  endif;
 
 
189
 
190
+ $this->merge_settings($channel, 'feed/');
191
+
192
+ $this->update_setting('update/last', time());
193
  list($ttl, $xml) = $this->ttl(/*return element=*/ true);
194
 
195
  if (!is_null($ttl)) :
196
+ $this->update_setting('update/ttl', $ttl);
197
+ $this->update_setting('update/xml', $xml);
198
+ $this->update_setting('update/timed', 'feed');
199
  else :
200
  $ttl = $this->automatic_ttl();
201
+ $this->update_setting('update/ttl', $ttl);
202
+ $this->update_setting('update/xml', NULL);
203
+ $this->update_setting('update/timed', 'automatically');
204
  endif;
205
+ $this->update_setting('update/fudge', rand(0, ($ttl/3))*60);
206
+ $this->update_setting('update/ttl', apply_filters(
207
+ 'syndicated_feed_ttl',
208
+ $this->setting('update/ttl'),
209
+ $this
210
+ ));
211
 
212
  if (!$this->setting('update/hold') != 'ping') :
213
+ $this->update_setting('update/hold', 'scheduled');
214
  endif;
215
 
216
+ $this->update_setting('update/unfinished', 'yes');
217
 
218
  $update[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
219
 
233
  $posts = apply_filters(
234
  'syndicated_feed_items',
235
  $this->simplepie->get_items(),
236
+ $this
237
  );
238
 
239
  $this->magpie->originals = $posts;
240
 
241
+ // If this is a complete feed, rather than an incremental feed, we
242
+ // need to prepare to mark everything for presumptive retirement.
243
+ if ($this->is_incremental()) :
244
+ $q = new WP_Query(array(
245
+ 'fields' => '_synfrom',
246
+ 'post_status__not' => 'fwpretired',
247
+ 'ignore_sticky_posts' => true,
248
+ 'meta_key' => 'syndication_feed_id',
249
+ 'meta_value' => $this->id,
250
+ ));
251
+ foreach ($q->posts as $p) :
252
+ update_post_meta($p->ID, '_feedwordpress_retire_me_'.$this->id, '1');
253
+ endforeach;
254
+ endif;
255
+
256
  if (is_array($posts)) :
257
  foreach ($posts as $key => $item) :
258
  $post = new SyndicatedPost($item, $this);
272
  unset($post);
273
  endforeach;
274
  endif;
275
+
276
+ if ('yes'==$this->setting('tombstones', 'tombstones', 'yes')) :
277
+ // Check for use of Atom tombstones. Spec:
278
+ // <http://tools.ietf.org/html/draft-snell-atompub-tombstones-18>
279
+ $tombstones = $this->simplepie->get_feed_tags('http://purl.org/atompub/tombstones/1.0', 'deleted-entry');
280
+ if (count($tombstones) > 0) :
281
+ foreach ($tombstones as $tombstone) :
282
+ $ref = NULL;
283
+ foreach (array('', 'http://purl.org/atompub/tombstones/1.0') as $ns) :
284
+ if (isset($tombstone['attribs'][$ns])
285
+ and isset($tombstone['attribs'][$ns]['ref'])) :
286
+ $ref = $tombstone['attribs'][$ns]['ref'];
287
+ endif;
288
+ endforeach;
289
+
290
+ $q = new WP_Query(array(
291
+ 'ignore_sticky_posts' => true,
292
+ 'guid' => $ref,
293
+ 'meta_key' => 'syndication_feed_id',
294
+ 'meta_value' => $this->id, // Only allow a feed to tombstone its own entries.
295
+ ));
296
+
297
+ foreach ($q->posts as $p) :
298
+ $old_status = $p->post_status;
299
+ FeedWordPress::diagnostic('syndicated_posts', 'Retiring existing post # '.$p->ID.' "'.$p->post_title.'" due to Atom tombstone element in feed.');
300
+ set_post_field('post_status', 'fwpretired', $p->ID);
301
+ wp_transition_post_status('fwpretired', $old_status, $p);
302
+ endforeach;
303
+
304
+ endforeach;
305
+ endif;
306
+ endif;
307
+
308
  $suffix = ($crashed ? 'crashed' : 'completed');
309
  do_action('update_syndicated_feed_items', $this->id, $this);
310
  do_action("update_syndicated_feed_items_${suffix}", $this->id, $this);
311
 
312
+ $this->update_setting('update/processed', $processed);
 
 
 
313
  if (!$crashed) :
314
+ $this->update_setting('update/unfinished', 'no');
315
  endif;
316
+ $this->update_setting('link/item count', count($posts));
317
 
318
+ // Copy back any changes to feed settings made in the
319
+ // course of updating (e.g. new author rules)
320
  $update_set = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
321
 
322
  // Update the properties of the link from the feed information
342
  return $new_count;
343
  } /* SyndicatedLink::poll() */
344
 
345
+ function process_retirements ($delta) {
346
+ global $post;
347
+
348
+ $q = new WP_Query(array(
349
+ 'fields' => '_synfrom',
350
+ 'post_status__not' => 'fwpretired',
351
+ 'ignore_sticky_posts' => true,
352
+ 'meta_key' => '_feedwordpress_retire_me_'.$this->id,
353
+ 'meta_value' => '1',
354
+ ));
355
+ if ($q->have_posts()) :
356
+ foreach ($q->posts as $p) :
357
+ $old_status = $p->post_status;
358
+ FeedWordPress::diagnostic('syndicated_posts', 'Retiring existing post # '.$p->ID.' "'.$p->post_title.'" due to absence from a non-incremental feed.');
359
+ set_post_field('post_status', 'fwpretired', $p->ID);
360
+ wp_transition_post_status('fwpretired', $old_status, $p);
361
+ delete_post_meta($p->ID, '_feedwordpress_retire_me_'.$this->id);
362
+ endforeach;
363
+ endif;
364
+ return $delta;
365
+ }
366
+
367
  /**
368
  * Updates the URL for the feed syndicated by this link.
369
  *
444
  $newuser_id = fwp_insert_new_user($newuser_name);
445
  if (is_numeric($newuser_id)) :
446
  if (is_null($name)) : // Unfamiliar author
447
+ $this->update_setting('unfamiliar author', $newuser_id);
448
  else :
449
+ $map = $this->setting('map authors');
450
+ $map['name'][$name] = $newuser_id;
451
+ $this->update_setting('map authors', $map);
452
  endif;
453
  else :
454
  // TODO: Add some error detection and reporting
461
  function imploded_settings () {
462
  return array('cats', 'tags', 'match/cats', 'match/tags', 'match/filter');
463
  }
464
+
465
+ function get_settings_from_notes () {
466
+ // Read off feed settings from link_notes
467
+ $notes = explode("\n", $this->link->link_notes);
468
+ foreach ($notes as $note):
469
+ $pair = explode(": ", $note, 2);
470
+ $key = (isset($pair[0]) ? $pair[0] : null);
471
+ $value = (isset($pair[1]) ? $pair[1] : null);
472
+ if (!is_null($key) and !is_null($value)) :
473
+ // Unescape and trim() off the whitespace.
474
+ // Thanks to Ray Lischner for pointing out the
475
+ // need to trim off whitespace.
476
+ $this->settings[$key] = stripcslashes (trim($value));
477
+ endif;
478
+ endforeach;
479
+
480
+ // "Magic" feed settings
481
+ $this->settings['link/uri'] = $this->link->link_rss;
482
+ $this->settings['link/name'] = $this->link->link_name;
483
+ $this->settings['link/id'] = $this->link->link_id;
484
+
485
+ // `hardcode categories` and `unfamiliar categories` are
486
+ // deprecated in favor of `unfamiliar category`
487
+ if (
488
+ isset($this->settings['unfamiliar categories'])
489
+ and !isset($this->settings['unfamiliar category'])
490
+ ) :
491
+ $this->settings['unfamiliar category'] = $this->settings['unfamiliar categories'];
492
+ endif;
493
+ if (
494
+ FeedWordPress::affirmative($this->settings, 'hardcode categories')
495
+ and !isset($this->settings['unfamiliar category'])
496
+ ) :
497
+ $this->settings['unfamiliar category'] = 'default';
498
+ endif;
499
+
500
+ // Set this up automagically for del.icio.us
501
+ $bits = parse_url($this->link->link_rss);
502
+ $tagspacers = array('del.icio.us', 'feeds.delicious.com');
503
+ if (!isset($this->settings['cat_split']) and in_array($bits['host'], $tagspacers)) :
504
+ $this->settings['cat_split'] = '\s'; // Whitespace separates multiple tags in del.icio.us RSS feeds
505
+ endif;
506
+
507
+ // Simple lists
508
+ foreach ($this->imploded_settings() as $what) :
509
+ if (isset($this->settings[$what])):
510
+ $this->settings[$what] = explode(
511
+ FEEDWORDPRESS_CAT_SEPARATOR,
512
+ $this->settings[$what]
513
+ );
514
+ endif;
515
+ endforeach;
516
+
517
+ if (isset($this->settings['terms'])) :
518
+ // Look for new format
519
+ $this->settings['terms'] = maybe_unserialize($this->settings['terms']);
520
+
521
+ if (!is_array($this->settings['terms'])) :
522
+ // Deal with old format instead. Ugh.
523
+
524
+ // Split on two *or more* consecutive breaks
525
+ // because in the old format, a taxonomy
526
+ // without any associated terms would
527
+ // produce tax_name#1\n\n\ntax_name#2\nterm,
528
+ // and the naive split on the first \n\n
529
+ // would screw up the tax_name#2 list.
530
+ //
531
+ // Props to David Morris for pointing this
532
+ // out.
533
+
534
+ $this->settings['terms'] = preg_split(
535
+ "/".FEEDWORDPRESS_CAT_SEPARATOR."{2,}/",
536
+ $this->settings['terms']
537
+ );
538
+ $terms = array();
539
+ foreach ($this->settings['terms'] as $line) :
540
+ $line = explode(FEEDWORDPRESS_CAT_SEPARATOR, $line);
541
+ $tax = array_shift($line);
542
+ $terms[$tax] = $line;
543
+ endforeach;
544
+ $this->settings['terms'] = $terms;
545
+ endif;
546
+ endif;
547
+
548
+ if (isset($this->settings['map authors'])) :
549
+ $author_rules = explode("\n\n", $this->settings['map authors']);
550
+ $ma = array();
551
+ foreach ($author_rules as $rule) :
552
+ list($rule_type, $author_name, $author_action) = explode("\n", $rule);
553
+
554
+ // Normalize for case and whitespace
555
+ $rule_type = strtolower(trim($rule_type));
556
+ $author_name = strtolower(trim($author_name));
557
+ $author_action = strtolower(trim($author_action));
558
+
559
+ $ma[$rule_type][$author_name] = $author_action;
560
+ endforeach;
561
+ $this->settings['map authors'] = $ma;
562
+ endif;
563
+
564
+ } /* SyndicatedLink::get_settings_from_notes () */
565
+
566
  function settings_to_notes () {
567
  $to_notes = $this->settings;
568
 
675
  return $ret;
676
  } /* SyndicatedLink::setting () */
677
 
678
+ function merge_settings ($data, $prefix, $separator = '/') {
679
+ $dd = $this->flatten_array($data, $prefix, $separator);
680
+ $this->settings = array_merge($this->settings, $dd);
681
+ } /* SyndicatedLink::merge_settings () */
682
+
683
  function update_setting ($name, $value, $default = 'default') {
684
  if (!is_null($value) and $value != $default) :
685
  $this->settings[$name] = $value;
688
  endif;
689
  } /* SyndicatedLink::update_setting () */
690
 
691
+ function is_incremental () {
692
+ return ('complete'==$this->setting('update_incremental', 'update_incremental', 'incremental'));
693
+ } /* SyndicatedLink::is_incremental () */
694
+
695
  function uri ($params = array()) {
696
+ $params = wp_parse_args($params, array(
697
  'add_params' => false,
698
+ ));
699
 
700
  $uri = (is_object($this->link) ? $this->link->link_rss : NULL);
701
  if (!is_null($uri) and strlen($uri) > 0 and $params['add_params']) :
711
  endforeach;
712
 
713
  // Are we appending to a URI that already has params?
714
+ $sep = ((strpos($uri, "?")===false) ? '?' : '&');
715
 
716
  // Tack it on
717
  $uri .= $sep . implode("&", $q);
718
+ endif;
719
  endif;
720
 
721
  return $uri;
736
  endif;
737
  return $auth;
738
  } /* SyndicatedLink::authentication_method () */
739
+
740
+ var $postmeta = array();
741
+ function postmeta ($params = array()) {
742
+ $params = wp_parse_args($params, /*defaults=*/ array(
743
+ "field" => NULL,
744
+ "parsed" => false,
745
+ "force" => false,
746
+ ));
747
+
748
+ if ($params['force'] or !isset($this->postmeta[/*parsed = */ false])) :
749
+ // First, get the global settings.
750
+ $default_custom_settings = get_option('feedwordpress_custom_settings');
751
+ if ($default_custom_settings and !is_array($default_custom_settings)) :
752
+ $default_custom_settings = unserialize($default_custom_settings);
753
+ endif;
754
+ if (!is_array($default_custom_settings)) :
755
+ $default_custom_settings = array();
756
+ endif;
757
+
758
+ // Next, get the settings for this particular feed.
759
+ $custom_settings = $this->setting('postmeta', NULL, NULL);
760
+ if ($custom_settings and !is_array($custom_settings)) :
761
+ $custom_settings = unserialize($custom_settings);
762
+ endif;
763
+ if (!is_array($custom_settings)) :
764
+ $custom_settings = array();
765
+ endif;
766
+
767
+ $this->postmeta[/*parsed=*/ false] = array_merge($default_custom_settings, $custom_settings);
768
+ $this->postmeta[/*parsed=*/ true] = array();
769
+
770
+ // Now, run through and parse them all.
771
+ foreach ($this->postmeta[/*parsed=*/ false] as $key => $meta) :
772
+ $meta = apply_filters("syndicated_link_post_meta_${key}_pre", $meta, $this);
773
+ $this->postmeta[/*parsed=*/ false][$key] = $meta;
774
+ $this->postmeta[/*parsed=*/ true][$key] = new FeedWordPressParsedPostMeta($meta);
775
+ endforeach;
776
+ endif;
777
+
778
+ $ret = $this->postmeta[!!$params['parsed']];
779
+ if (is_string($params['field'])) :
780
+ $ret = $ret[$params['field']];
781
+ endif;
782
+ return $ret;
783
+ } /* SyndicatedLink::postmeta () */
784
 
785
+ function property_cascade ($fromFeed, $link_field, $setting, $method) {
786
  $value = NULL;
787
  if ($fromFeed) :
788
+ $value = $this->setting($setting, NULL, NULL, NULL);
789
+
790
+ $s = $this->simplepie;
791
+ $callable = (is_object($s) and method_exists($s, $method));
792
+ if (is_null($value) and $callable) :
793
+ $fallback = $s->{$method}();
794
  endif;
795
  else :
796
  $value = $this->link->{$link_field};
926
  } /* SyndicatedLink::flatten_array () */
927
 
928
  function hardcode ($what) {
929
+
930
+ $ret = $this->setting('hardcode '.$what, 'hardcode_'.$what, NULL);
931
+
932
+ if ('yes' == $ret) :
933
+ $ret = true;
 
934
  else :
935
+ $ret = false;
 
 
 
936
  endif;
937
  return $ret;
938
  } /* SyndicatedLink::hardcode () */
940
  function syndicated_status ($what, $default, $fallback = true) {
941
  global $wpdb;
942
 
943
+ $g_set = ($fallback ? 'syndicated_' . $what . '_status' : NULL);
944
+ $ret = $this->setting($what.' status', $g_set, $default);
 
 
 
 
 
 
 
 
 
 
 
945
 
946
  return $wpdb->escape(trim(strtolower($ret)));
947
  } /* SyndicatedLink:syndicated_status () */
syndicatedpost.class.php CHANGED
@@ -30,6 +30,7 @@ class SyndicatedPost {
30
 
31
  var $_freshness = null;
32
  var $_wp_id = null;
 
33
 
34
  /**
35
  * SyndicatedPost constructor: Given a feed item and the source from
@@ -158,48 +159,16 @@ class SyndicatedPost {
158
  // Unique ID (hopefully a unique tag: URI); failing that, the permalink
159
  $this->post['guid'] = apply_filters('syndicated_item_guid', $this->guid(), $this);
160
 
161
- // 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
162
- $default_custom_settings = get_option('feedwordpress_custom_settings');
163
- if ($default_custom_settings and !is_array($default_custom_settings)) :
164
- $default_custom_settings = unserialize($default_custom_settings);
165
- endif;
166
- if (!is_array($default_custom_settings)) :
167
- $default_custom_settings = array();
168
- endif;
169
-
170
- $custom_settings = (isset($this->link->settings['postmeta']) ? $this->link->settings['postmeta'] : null);
171
- if ($custom_settings and !is_array($custom_settings)) :
172
- $custom_settings = unserialize($custom_settings);
173
- endif;
174
- if (!is_array($custom_settings)) :
175
- $custom_settings = array();
176
- endif;
177
-
178
- $postMetaIn = array_merge($default_custom_settings, $custom_settings);
179
  $postMetaOut = array();
180
-
181
- // Big ugly fuckin loop to do any element substitutions
182
- // that we may need.
183
- foreach ($postMetaIn as $key => $values) :
184
- if (is_string($values)) : $values = array($values); endif;
185
-
186
- $postMetaOut[$key] = array();
187
- foreach ($values as $value) :
188
- if (preg_match('/\$\( ([^)]+) \)/x', $value, $ref)) :
189
- $elements = $this->query($ref[1]);
190
- foreach ($elements as $element) :
191
- $postMetaOut[$key][] = str_replace(
192
- $ref[0],
193
- $element,
194
- $value
195
- );
196
- endforeach;
197
- else :
198
- $postMetaOut[$key][] = $value;
199
- endif;
200
- endforeach;
201
  endforeach;
202
-
203
  foreach ($postMetaOut as $key => $values) :
204
  $this->post['meta'][$key] = array();
205
  foreach ($values as $value) :
@@ -380,6 +349,23 @@ class SyndicatedPost {
380
  #####################################
381
  #### EXTRACT DATA FROM FEED ITEM ####
382
  #####################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
  /**
385
  * SyndicatedPost::query uses an XPath-like syntax to query arbitrary
@@ -772,8 +758,20 @@ class SyndicatedPost {
772
  return $this->_hashes[$id];
773
  }
774
 
775
- function update_hash () {
776
- return md5(serialize($this->item));
 
 
 
 
 
 
 
 
 
 
 
 
777
  } /* SyndicatedPost::update_hash() */
778
 
779
  /*static*/ function normalize_guid_prefix () {
@@ -853,56 +851,77 @@ class SyndicatedPost {
853
  function author () {
854
  $author = array ();
855
 
856
- if (isset($this->item['author_name'])):
857
- $author['name'] = $this->item['author_name'];
858
- elseif (isset($this->item['dc']['creator'])):
859
- $author['name'] = $this->item['dc']['creator'];
860
- elseif (isset($this->item['dc']['contributor'])):
861
- $author['name'] = $this->item['dc']['contributor'];
862
- elseif (isset($this->feed->channel['dc']['creator'])) :
863
- $author['name'] = $this->feed->channel['dc']['creator'];
864
- elseif (isset($this->feed->channel['dc']['contributor'])) :
865
- $author['name'] = $this->feed->channel['dc']['contributor'];
866
- elseif (isset($this->feed->channel['author_name'])) :
867
- $author['name'] = $this->feed->channel['author_name'];
868
- elseif ($this->feed->is_rss() and isset($this->item['author'])) :
869
- // The author element in RSS is allegedly an
870
- // e-mail address, but lots of people don't use
871
- // it that way. So let's make of it what we can.
872
- $author = parse_email_with_realname($this->item['author']);
873
-
874
- if (!isset($author['name'])) :
875
- if (isset($author['email'])) :
876
- $author['name'] = $author['email'];
877
- else :
878
- $author['name'] = $this->feed->channel['title'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
  endif;
880
  endif;
881
- elseif ($this->link->name()) :
882
- $author['name'] = $this->link->name();
883
- else :
884
- $url = parse_url($this->link->uri());
885
- $author['name'] = $url['host'];
886
  endif;
887
 
888
- if (isset($this->item['author_email'])):
889
- $author['email'] = $this->item['author_email'];
890
- elseif (isset($this->feed->channel['author_email'])) :
891
- $author['email'] = $this->feed->channel['author_email'];
 
 
 
 
892
  endif;
893
 
894
- if (isset($this->item['author_uri'])):
895
- $author['uri'] = $this->item['author_uri'];
896
- elseif (isset($this->item['author_url'])):
897
- $author['uri'] = $this->item['author_url'];
898
- elseif (isset($this->feed->channel['author_uri'])) :
899
- $author['uri'] = $this->item['author_uri'];
900
- elseif (isset($this->feed->channel['author_url'])) :
901
- $author['uri'] = $this->item['author_url'];
902
- elseif (isset($this->feed->channel['link'])) :
903
- $author['uri'] = $this->feed->channel['link'];
 
 
 
 
 
 
 
 
904
  endif;
905
-
906
  return $author;
907
  } /* SyndicatedPost::author() */
908
 
@@ -1170,7 +1189,7 @@ class SyndicatedPost {
1170
  $pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
1171
  $content = preg_replace_callback (
1172
  $pattern,
1173
- array(&$obj, 'resolve_single_relative_uri'),
1174
  $content
1175
  );
1176
  endforeach;
@@ -1199,7 +1218,7 @@ class SyndicatedPost {
1199
 
1200
  $content = preg_replace_callback (
1201
  $pattern,
1202
- array(&$obj, 'strip_attribute_from_tag'),
1203
  $content
1204
  );
1205
  endforeach;
@@ -1270,9 +1289,18 @@ class SyndicatedPost {
1270
  !is_null($updated_ts)
1271
  and ($updated_ts > $last_rev_ts)
1272
  );
1273
-
1274
-
1275
- if (!$updated) :
 
 
 
 
 
 
 
 
 
1276
  // Or the hash...
1277
  $hash = $this->update_hash();
1278
  $seen = $this->stored_hashes($old_post->ID);
@@ -1281,6 +1309,15 @@ class SyndicatedPost {
1281
  else :
1282
  $updated = true; // Can't find syndication meta-data
1283
  endif;
 
 
 
 
 
 
 
 
 
1284
  endif;
1285
 
1286
  $frozen = false;
@@ -1289,15 +1326,26 @@ class SyndicatedPost {
1289
  if (!$frozen) :
1290
  $frozen_values = get_post_custom_values('_syndication_freeze_updates', $old_post->ID);
1291
  $frozen = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]);
 
 
 
 
 
 
1292
  endif;
1293
  endif;
1294
  $updated = ($updated and !$frozen);
1295
 
1296
  if ($updated) :
1297
  FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$guid.'] "'.$this->entry->get_title().'" is an update of an existing post.');
 
 
 
 
1298
  $this->_freshness = 1; // Updated content
1299
  $this->_wp_id = $old_post->ID;
1300
-
 
1301
  // We want this to keep a running list of all the
1302
  // processed update hashes.
1303
  $this->post['meta']['syndication_item_hash'] = array_merge(
@@ -1427,8 +1475,13 @@ class SyndicatedPost {
1427
  if (!$this->filtered() and $freshness > 0) :
1428
  // Filter some individual fields
1429
 
 
 
 
 
 
1430
  // Allow filters to set post slug. Props niska.
1431
- $post_name = apply_filters('syndicated_post_slug', NULL, $this);
1432
  if (!empty($post_name)) :
1433
  $this->post['post_name'] = $post_name;
1434
  endif;
@@ -1446,7 +1499,7 @@ class SyndicatedPost {
1446
  // Hook in early to make sure these get inserted if at all possible
1447
  add_action(
1448
  /*hook=*/ 'transition_post_status',
1449
- /*callback=*/ array(&$this, 'add_rss_meta'),
1450
  /*priority=*/ -10000, /* very early */
1451
  /*arguments=*/ 3
1452
  );
@@ -1469,10 +1522,24 @@ class SyndicatedPost {
1469
  $ret = $retval[$freshness];
1470
  endif;
1471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1472
  // Remove add_rss_meta hook
1473
  remove_action(
1474
  /*hook=*/ 'transition_post_status',
1475
- /*callback=*/ array(&$this, 'add_rss_meta'),
1476
  /*priority=*/ -10000, /* very early */
1477
  /*arguments=*/ 3
1478
  );
@@ -1509,14 +1576,14 @@ class SyndicatedPost {
1509
 
1510
  foreach ($doNotMunge as $field) :
1511
  $dbpost[$field] = get_post_field($field, $this->wp_id());
1512
- endforeach;
1513
  endif;
1514
 
1515
  // WP3's wp_insert_post scans current_user_can() for the
1516
  // tax_input, with no apparent way to override. Ugh.
1517
  add_action(
1518
  /*hook=*/ 'transition_post_status',
1519
- /*callback=*/ array(&$this, 'add_terms'),
1520
  /*priority=*/ -10001, /* very early */
1521
  /*arguments=*/ 3
1522
  );
@@ -1525,7 +1592,7 @@ class SyndicatedPost {
1525
  // post_modified. Ugh.
1526
  add_action(
1527
  /*hook=*/ 'transition_post_status',
1528
- /*callback=*/ array(&$this, 'fix_post_modified_ts'),
1529
  /*priority=*/ -10000, /* very early */
1530
  /*arguments=*/ 3
1531
  );
@@ -1539,14 +1606,14 @@ class SyndicatedPost {
1539
 
1540
  remove_action(
1541
  /*hook=*/ 'transition_post_status',
1542
- /*callback=*/ array(&$this, 'add_terms'),
1543
  /*priority=*/ -10001, /* very early */
1544
  /*arguments=*/ 3
1545
  );
1546
 
1547
  remove_action(
1548
  /*hook=*/ 'transition_post_status',
1549
- /*callback=*/ array(&$this, 'fix_post_modified_ts'),
1550
  /*priority=*/ -10000, /* very early */
1551
  /*arguments=*/ 3
1552
  );
@@ -1554,7 +1621,7 @@ class SyndicatedPost {
1554
  // Turn off ridiculous fucking kludges #1 and #2
1555
  remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
1556
  foreach ($removed as $filter) :
1557
- add_filter('content_save_pre', $removed);
1558
  endforeach;
1559
 
1560
  $this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__));
30
 
31
  var $_freshness = null;
32
  var $_wp_id = null;
33
+ var $_wp_post = null;
34
 
35
  /**
36
  * SyndicatedPost constructor: Given a feed item and the source from
159
  // Unique ID (hopefully a unique tag: URI); failing that, the permalink
160
  $this->post['guid'] = apply_filters('syndicated_item_guid', $this->guid(), $this);
161
 
162
+ // User-supplied custom settings to apply to each post.
163
+ // Do first so that FWP-generated custom settings will
164
+ // overwrite if necessary; thus preventing any munging.
165
+ $postMetaIn = $this->link->postmeta(array("parsed" => true));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  $postMetaOut = array();
167
+
168
+ foreach ($postMetaIn as $key => $meta) :
169
+ $postMetaOut[$key] = $meta->do_substitutions($this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  endforeach;
171
+
172
  foreach ($postMetaOut as $key => $values) :
173
  $this->post['meta'][$key] = array();
174
  foreach ($values as $value) :
349
  #####################################
350
  #### EXTRACT DATA FROM FEED ITEM ####
351
  #####################################
352
+
353
+ function substitution_function ($name) {
354
+ $ret = NULL;
355
+
356
+ switch ($name) :
357
+ // Allowed PHP string functions
358
+ case 'trim':
359
+ case 'ltrim':
360
+ case 'rtrim':
361
+ case 'strtoupper':
362
+ case 'strtolower':
363
+ case 'urlencode':
364
+ case 'urldecode':
365
+ $ret = $name;
366
+ endswitch;
367
+ return $ret;
368
+ }
369
 
370
  /**
371
  * SyndicatedPost::query uses an XPath-like syntax to query arbitrary
758
  return $this->_hashes[$id];
759
  }
760
 
761
+ function update_hash ($hashed = true) {
762
+ // Basis for tracking possible changes to item.
763
+ $hash = array(
764
+ "title" => $this->entry->get_title(),
765
+ "link" => $this->permalink(),
766
+ "content" => $this->content(),
767
+ "excerpt" => $this->excerpt(),
768
+ );
769
+
770
+ if ($hashed) :
771
+ $hash = md5(serialize($hash));
772
+ endif;
773
+
774
+ return $hash;
775
  } /* SyndicatedPost::update_hash() */
776
 
777
  /*static*/ function normalize_guid_prefix () {
851
  function author () {
852
  $author = array ();
853
 
854
+ $aa = $this->entry->get_authors();
855
+ if (count($aa) > 0) :
856
+ $a = reset($aa);
857
+
858
+ $author = array(
859
+ 'name' => $a->get_name(),
860
+ 'email' => $a->get_email(),
861
+ 'uri' => $a->get_link(),
862
+ );
863
+ endif;
864
+
865
+ if (FEEDWORDPRESS_COMPATIBILITY) :
866
+ // Search through the MagpieRSS elements: Atom, Dublin Core, RSS
867
+ if (isset($this->item['author_name'])):
868
+ $author['name'] = $this->item['author_name'];
869
+ elseif (isset($this->item['dc']['creator'])):
870
+ $author['name'] = $this->item['dc']['creator'];
871
+ elseif (isset($this->item['dc']['contributor'])):
872
+ $author['name'] = $this->item['dc']['contributor'];
873
+ elseif (isset($this->feed->channel['dc']['creator'])) :
874
+ $author['name'] = $this->feed->channel['dc']['creator'];
875
+ elseif (isset($this->feed->channel['dc']['contributor'])) :
876
+ $author['name'] = $this->feed->channel['dc']['contributor'];
877
+ elseif (isset($this->feed->channel['author_name'])) :
878
+ $author['name'] = $this->feed->channel['author_name'];
879
+ elseif ($this->feed->is_rss() and isset($this->item['author'])) :
880
+ // The author element in RSS is allegedly an
881
+ // e-mail address, but lots of people don't use
882
+ // it that way. So let's make of it what we can.
883
+ $author = parse_email_with_realname($this->item['author']);
884
+
885
+ if (!isset($author['name'])) :
886
+ if (isset($author['email'])) :
887
+ $author['name'] = $author['email'];
888
+ else :
889
+ $author['name'] = $this->feed->channel['title'];
890
+ endif;
891
  endif;
892
  endif;
 
 
 
 
 
893
  endif;
894
 
895
+ if (!isset($author['name']) or is_null($author['name'])) :
896
+ // Nothing found. Try some crappy defaults.
897
+ if ($this->link->name()) :
898
+ $author['name'] = $this->link->name();
899
+ else :
900
+ $url = parse_url($this->link->uri());
901
+ $author['name'] = $url['host'];
902
+ endif;
903
  endif;
904
 
905
+ if (FEEDWORDPRESS_COMPATIBILITY) :
906
+ if (isset($this->item['author_email'])):
907
+ $author['email'] = $this->item['author_email'];
908
+ elseif (isset($this->feed->channel['author_email'])) :
909
+ $author['email'] = $this->feed->channel['author_email'];
910
+ endif;
911
+
912
+ if (isset($this->item['author_uri'])):
913
+ $author['uri'] = $this->item['author_uri'];
914
+ elseif (isset($this->item['author_url'])):
915
+ $author['uri'] = $this->item['author_url'];
916
+ elseif (isset($this->feed->channel['author_uri'])) :
917
+ $author['uri'] = $this->item['author_uri'];
918
+ elseif (isset($this->feed->channel['author_url'])) :
919
+ $author['uri'] = $this->item['author_url'];
920
+ elseif (isset($this->feed->channel['link'])) :
921
+ $author['uri'] = $this->feed->channel['link'];
922
+ endif;
923
  endif;
924
+
925
  return $author;
926
  } /* SyndicatedPost::author() */
927
 
1189
  $pattern = FeedWordPressHTML::attributeRegex($tag, $attr);
1190
  $content = preg_replace_callback (
1191
  $pattern,
1192
+ array($obj, 'resolve_single_relative_uri'),
1193
  $content
1194
  );
1195
  endforeach;
1218
 
1219
  $content = preg_replace_callback (
1220
  $pattern,
1221
+ array($obj, 'strip_attribute_from_tag'),
1222
  $content
1223
  );
1224
  endforeach;
1289
  !is_null($updated_ts)
1290
  and ($updated_ts > $last_rev_ts)
1291
  );
1292
+
1293
+ $updatedReason = NULL;
1294
+ if ($updated) :
1295
+ $updatedReason = preg_replace(
1296
+ "/\s+/", " ",
1297
+ 'has been marked with a new timestamp ('
1298
+ .date('Y-m-d H:i:s', $updated_ts)
1299
+ ." > "
1300
+ .date('Y-m-d H:i:s', $last_rev_ts)
1301
+ .')'
1302
+ );
1303
+ else :
1304
  // Or the hash...
1305
  $hash = $this->update_hash();
1306
  $seen = $this->stored_hashes($old_post->ID);
1309
  else :
1310
  $updated = true; // Can't find syndication meta-data
1311
  endif;
1312
+
1313
+ if ($updated and FeedWordPress::diagnostic_on('feed_items:freshness:reasons')) :
1314
+ $updatedReason = ' has a not-yet-seen update hash: '
1315
+ .FeedWordPress::val($hash)
1316
+ .' not in {'
1317
+ .implode(", ", array_map(array('FeedWordPress', 'val'), $seen))
1318
+ .'}. Basis: '
1319
+ .FeedWordPress::val(array_keys($this->update_hash(false)));
1320
+ endif;
1321
  endif;
1322
 
1323
  $frozen = false;
1326
  if (!$frozen) :
1327
  $frozen_values = get_post_custom_values('_syndication_freeze_updates', $old_post->ID);
1328
  $frozen = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]);
1329
+
1330
+ if ($frozen) :
1331
+ $updatedReason = ' IS BLOCKED FROM BEING UPDATED BY A UPDATE LOCK ON THIS POST, EVEN THOUGH IT '.$updatedReason;
1332
+ endif;
1333
+ else :
1334
+ $updatedReason = ' IS BLOCKED FROM BEING UPDATED BY A FEEDWORDPRESS UPDATE LOCK, EVEN THOUGH IT '.$updatedReason;
1335
  endif;
1336
  endif;
1337
  $updated = ($updated and !$frozen);
1338
 
1339
  if ($updated) :
1340
  FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$guid.'] "'.$this->entry->get_title().'" is an update of an existing post.');
1341
+ if (!is_null($updatedReason)) :
1342
+ $updatedReason = preg_replace('/\s+/', ' ', $updatedReason);
1343
+ FeedWordPress::diagnostic('feed_items:freshness:reasons', 'Item ['.$guid.'] "'.$this->entry->get_title().'" '.$updatedReason);
1344
+ endif;
1345
  $this->_freshness = 1; // Updated content
1346
  $this->_wp_id = $old_post->ID;
1347
+ $this->_wp_post = $old_post;
1348
+
1349
  // We want this to keep a running list of all the
1350
  // processed update hashes.
1351
  $this->post['meta']['syndication_item_hash'] = array_merge(
1475
  if (!$this->filtered() and $freshness > 0) :
1476
  // Filter some individual fields
1477
 
1478
+ // If there already is a post slug (from syndication or by manual
1479
+ // editing) don't cause WP to overwrite it by sending in a NULL
1480
+ // post_name. Props Chris Fritz 2012-11-28.
1481
+ $post_name = (is_null($this->_wp_post) ? NULL : $this->_wp_post->post_name);
1482
+
1483
  // Allow filters to set post slug. Props niska.
1484
+ $post_name = apply_filters('syndicated_post_slug', $post_name, $this);
1485
  if (!empty($post_name)) :
1486
  $this->post['post_name'] = $post_name;
1487
  endif;
1499
  // Hook in early to make sure these get inserted if at all possible
1500
  add_action(
1501
  /*hook=*/ 'transition_post_status',
1502
+ /*callback=*/ array($this, 'add_rss_meta'),
1503
  /*priority=*/ -10000, /* very early */
1504
  /*arguments=*/ 3
1505
  );
1522
  $ret = $retval[$freshness];
1523
  endif;
1524
 
1525
+ // If this is a legit, non-filtered post, tag it as found on the feed
1526
+ // regardless of fresh or stale status
1527
+ if (!$this->filtered()) :
1528
+ $key = '_feedwordpress_retire_me_' . $this->link->id;
1529
+ delete_post_meta($this->wp_id(), $key);
1530
+
1531
+ $status = get_post_field('post_status', $this->wp_id());
1532
+ if ('fwpretired'==$status and $this->link->is_incremental()) :
1533
+ FeedWordPress::diagnostic('syndicated_posts', "Un-retiring previously retired post # ".$this->wp_id()." due to re-appearance on non-incremental feed.");
1534
+ set_post_field('post_status', $this->post['post_status'], $this->wp_id());
1535
+ wp_transition_post_status($this->post['post_status'], $status, $old_status, $this->post);
1536
+ endif;
1537
+ endif;
1538
+
1539
  // Remove add_rss_meta hook
1540
  remove_action(
1541
  /*hook=*/ 'transition_post_status',
1542
+ /*callback=*/ array($this, 'add_rss_meta'),
1543
  /*priority=*/ -10000, /* very early */
1544
  /*arguments=*/ 3
1545
  );
1576
 
1577
  foreach ($doNotMunge as $field) :
1578
  $dbpost[$field] = get_post_field($field, $this->wp_id());
1579
+ endforeach;
1580
  endif;
1581
 
1582
  // WP3's wp_insert_post scans current_user_can() for the
1583
  // tax_input, with no apparent way to override. Ugh.
1584
  add_action(
1585
  /*hook=*/ 'transition_post_status',
1586
+ /*callback=*/ array($this, 'add_terms'),
1587
  /*priority=*/ -10001, /* very early */
1588
  /*arguments=*/ 3
1589
  );
1592
  // post_modified. Ugh.
1593
  add_action(
1594
  /*hook=*/ 'transition_post_status',
1595
+ /*callback=*/ array($this, 'fix_post_modified_ts'),
1596
  /*priority=*/ -10000, /* very early */
1597
  /*arguments=*/ 3
1598
  );
1606
 
1607
  remove_action(
1608
  /*hook=*/ 'transition_post_status',
1609
+ /*callback=*/ array($this, 'add_terms'),
1610
  /*priority=*/ -10001, /* very early */
1611
  /*arguments=*/ 3
1612
  );
1613
 
1614
  remove_action(
1615
  /*hook=*/ 'transition_post_status',
1616
+ /*callback=*/ array($this, 'fix_post_modified_ts'),
1617
  /*priority=*/ -10000, /* very early */
1618
  /*arguments=*/ 3
1619
  );
1621
  // Turn off ridiculous fucking kludges #1 and #2
1622
  remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
1623
  foreach ($removed as $filter) :
1624
+ add_filter('content_save_pre', $filter);
1625
  endforeach;
1626
 
1627
  $this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__));
syndicationdataqueries.class.php CHANGED
@@ -1,12 +1,15 @@
1
  <?php
 
 
2
  class SyndicationDataQueries {
3
  function SyndicationDataQueries () {
4
- add_action('init', array(&$this, 'init'));
5
- add_action('parse_query', array(&$this, 'parse_query'), 10, 1);
6
- add_filter('posts_search', array(&$this, 'posts_search'), 10, 2);
7
- add_filter('posts_where', array(&$this, 'posts_where'), 10, 2);
8
- add_filter('posts_fields', array(&$this, 'posts_fields'), 10, 2);
9
- add_filter('posts_request', array(&$this, 'posts_request'), 10, 2);
 
10
  }
11
 
12
  function init () {
@@ -14,13 +17,36 @@ class SyndicationDataQueries {
14
  $wp->add_query_var('guid');
15
  }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  function parse_query (&$q) {
18
  if ($q->get('guid')) :
19
- $q->is_single = false; // Causes nasty side-effects.
20
  $q->is_singular = true; // Doesn't?
21
  endif;
22
 
23
- if ($q->get('fields') == '_synfresh') :
 
24
  $q->query_vars['cache_results'] = false; // Not suitable.
25
  endif;
26
  } /* SyndicationDataQueries::parse_query () */
@@ -35,7 +61,7 @@ class SyndicationDataQueries {
35
  endif;
36
  return $sql;
37
  }
38
-
39
  function posts_search ($search, &$query) {
40
  global $wpdb;
41
  if ($guid = $query->get('guid')) :
@@ -67,17 +93,26 @@ class SyndicationDataQueries {
67
  // Ugly hack to ensure we ONLY check by guid in syndicated freshness
68
  // checks -- for reasons of both performance and correctness. Pitch:
69
  $search .= " -- '";
 
 
70
  endif;
71
  return $search;
72
  } /* SyndicationDataQueries::posts_search () */
73
 
74
  function posts_where ($where, &$q) {
 
 
75
  // Ugly hack to ensure we ONLY check by guid in syndicated freshness
76
  // checks -- for reasons of both performance and correctness. Catch:
77
  if (strpos($where, " -- '") !== false) :
78
  $bits = explode(" -- '", $where, 2);
79
  $where = $bits[0];
80
  endif;
 
 
 
 
 
81
  return $where;
82
  } /* SyndicationDataQueries::post_where () */
83
 
@@ -86,7 +121,10 @@ class SyndicationDataQueries {
86
  if ($f = $query->get('fields')) :
87
  switch ($f) :
88
  case '_synfresh' :
89
- $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_modified_gmt";
 
 
 
90
  break;
91
  default :
92
  // Do nothing.
1
  <?php
2
+ define('FEEDWORDPRESS_OPTIMIZE_IN_CLAUSES', get_option('feedwordpress_optimize_in_clauses', false));
3
+
4
  class SyndicationDataQueries {
5
  function SyndicationDataQueries () {
6
+ add_action('init', array($this, 'init'));
7
+ add_filter('query', array($this, 'optimize_in_clauses'));
8
+ add_action('parse_query', array($this, 'parse_query'), 10, 1);
9
+ add_filter('posts_search', array($this, 'posts_search'), 10, 2);
10
+ add_filter('posts_where', array($this, 'posts_where'), 10, 2);
11
+ add_filter('posts_fields', array($this, 'posts_fields'), 10, 2);
12
+ add_filter('posts_request', array($this, 'posts_request'), 10, 2);
13
  }
14
 
15
  function init () {
17
  $wp->add_query_var('guid');
18
  }
19
 
20
+ function optimize_in_clauses ($q) {
21
+ // This is kind of a dicey, low-level thing to do, and Christ,
22
+ // this is something WordPress should be doing on its own,
23
+ // so it's disabled by default. But you can enable it in
24
+ // Performance --> Optimize IN clauses
25
+ if (FEEDWORDPRESS_OPTIMIZE_IN_CLAUSES) :
26
+ if (preg_match_all('/ \s+ IN \s* \((\s*([0-9]+)\s*)\)/x', $q, $r, PREG_OFFSET_CAPTURE)) :
27
+ $from = 0; $nq = '';
28
+ foreach ($r[0] as $idx => $ref) :
29
+ $len = $ref[1] - $from;
30
+ $nq .= substr($q, $from, $len);
31
+ $nq .= ' = ' . $r[1][$idx][0];
32
+ $from = $ref[1] + strlen($ref[0]);
33
+ endforeach;
34
+
35
+ $q = $nq;
36
+ endif;
37
+ endif;
38
+
39
+ return $q;
40
+ }
41
+
42
  function parse_query (&$q) {
43
  if ($q->get('guid')) :
44
+ $q->is_single = false; // Causes nasty side-effects.
45
  $q->is_singular = true; // Doesn't?
46
  endif;
47
 
48
+ $ff = $q->get('fields');
49
+ if ($ff == '_synfresh' or $ff == '_synfrom') :
50
  $q->query_vars['cache_results'] = false; // Not suitable.
51
  endif;
52
  } /* SyndicationDataQueries::parse_query () */
61
  endif;
62
  return $sql;
63
  }
64
+
65
  function posts_search ($search, &$query) {
66
  global $wpdb;
67
  if ($guid = $query->get('guid')) :
93
  // Ugly hack to ensure we ONLY check by guid in syndicated freshness
94
  // checks -- for reasons of both performance and correctness. Pitch:
95
  $search .= " -- '";
96
+ elseif ($query->get('fields')=='_synfrom') :
97
+ $search .= " AND ({$wpdb->postmeta}.meta_key = '".$query->get('meta_key')."' AND wp_postmeta.meta_value = '".$query->get('meta_value')."') -- '";
98
  endif;
99
  return $search;
100
  } /* SyndicationDataQueries::posts_search () */
101
 
102
  function posts_where ($where, &$q) {
103
+ global $wpdb;
104
+
105
  // Ugly hack to ensure we ONLY check by guid in syndicated freshness
106
  // checks -- for reasons of both performance and correctness. Catch:
107
  if (strpos($where, " -- '") !== false) :
108
  $bits = explode(" -- '", $where, 2);
109
  $where = $bits[0];
110
  endif;
111
+
112
+ if ($psn = $q->get('post_status__not')) :
113
+ $where .= " AND ({$wpdb->posts}.post_status <> '".$wpdb->escape($psn)."')";
114
+ endif;
115
+
116
  return $where;
117
  } /* SyndicationDataQueries::post_where () */
118
 
121
  if ($f = $query->get('fields')) :
122
  switch ($f) :
123
  case '_synfresh' :
124
+ $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_modified_gmt, {$wpdb->posts}.post_name";
125
+ break;
126
+ case '_synfrom' :
127
+ $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_title, {$wpdb->postmeta}.meta_value";
128
  break;
129
  default :
130
  // Do nothing.