| @@ -32,12 +32,15 @@ | ||
| 32 | 32 | # |
| 33 | 33 | # Values of keys in link_notes are accessible from templates using |
| 34 | 34 | # the function `get_feed_meta($key)` if this plugin is activated. |
| 35 | 35 | |
| 36 | +require_once(dirname(__FILE__).'/magpiefromsimplepie.class.php'); | |
| 37 | + | |
| 36 | 38 | class SyndicatedLink { |
| 37 | 39 | var $id = null; |
| 38 | 40 | var $link = null; |
| 39 | 41 | var $settings = array (); |
| 42 | + var $simplepie = null; | |
| 40 | 43 | var $magpie = null; |
| 41 | 44 | |
| 42 | 45 | function SyndicatedLink ($link) { |
| 43 | 46 | global $wpdb; |
| @@ -123,9 +126,9 @@ | ||
| 123 | 126 | endif; |
| 124 | 127 | } /* SyndicatedLink::SyndicatedLink () */ |
| 125 | 128 | |
| 126 | 129 | function found () { |
| 127 | - return is_object($this->link); | |
| 130 | + return is_object($this->link) and !is_wp_error($this->link); | |
| 128 | 131 | } /* SyndicatedLink::found () */ |
| 129 | 132 | |
| 130 | 133 | function stale () { |
| 131 | 134 | $stale = true; |
| @@ -145,9 +148,21 @@ | ||
| 145 | 148 | |
| 146 | 149 | function poll ($crash_ts = NULL) { |
| 147 | 150 | global $wpdb; |
| 148 | 151 | |
| 149 | - $this->magpie = fetch_rss($this->link->link_rss); | |
| 152 | + $this->simplepie = apply_filters( | |
| 153 | + 'syndicated_feed', | |
| 154 | + FeedWordPress::fetch($this->link->link_rss), | |
| 155 | + $this | |
| 156 | + ); | |
| 157 | + | |
| 158 | + // Filter compatibility mode | |
| 159 | + if (is_wp_error($this->simplepie)) : | |
| 160 | + $this->magpie = $this->simplepie; | |
| 161 | + else : | |
| 162 | + $this->magpie = new MagpieFromSimplePie($this->simplepie); | |
| 163 | + endif; | |
| 164 | + | |
| 150 | 165 | $new_count = NULL; |
| 151 | 166 | |
| 152 | 167 | $resume = FeedWordPress::affirmative($this->settings, 'update/unfinished'); |
| 153 | 168 | if ($resume) : |
| @@ -157,9 +172,11 @@ | ||
| 157 | 172 | // begin at the beginning |
| 158 | 173 | $processed = array(); |
| 159 | 174 | endif; |
| 160 | 175 | |
| 161 | - if (is_object($this->magpie)) : | |
| 176 | + if (is_wp_error($this->simplepie)) : | |
| 177 | + $new_count = $this->simplepie; | |
| 178 | + elseif (is_object($this->simplepie)) : | |
| 162 | 179 | $new_count = array('new' => 0, 'updated' => 0); |
| 163 | 180 | |
| 164 | 181 | # -- Update Link metadata live from feed |
| 165 | 182 | $channel = $this->magpie->channel; |
| @@ -191,11 +208,23 @@ | ||
| 191 | 208 | if (!is_null($ttl)) : |
| 192 | 209 | $this->settings['update/ttl'] = $ttl; |
| 193 | 210 | $this->settings['update/timed'] = 'feed'; |
| 194 | 211 | else : |
| 195 | - $this->settings['update/ttl'] = rand(30, 120); // spread over time interval for staggered updates | |
| 212 | + // spread out over a time interval for staggered updates | |
| 213 | + $updateWindow = $this->setting( | |
| 214 | + 'update/window', | |
| 215 | + 'update_window', | |
| 216 | + DEFAULT_UPDATE_PERIOD | |
| 217 | + ); | |
| 218 | + if (!is_numeric($updateWindow) or ($updateWindow < 1)) : | |
| 219 | + $updateWindow = DEFAULT_UPDATE_PERIOD; | |
| 220 | + endif; | |
| 221 | + | |
| 222 | + $fudgedInterval = $updateWindow+rand(0, 2*($updateWindow/3)); | |
| 223 | + $this->settings['update/ttl'] = apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this); | |
| 196 | 224 | $this->settings['update/timed'] = 'automatically'; |
| 197 | 225 | endif; |
| 226 | + $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this); | |
| 198 | 227 | |
| 199 | 228 | if (!isset($this->settings['update/hold']) or $this->settings['update/hold']!='ping') : |
| 200 | 229 | $this->settings['update/hold'] = 'scheduled'; |
| 201 | 230 | endif; |
| @@ -211,15 +240,26 @@ | ||
| 211 | 240 | UPDATE $wpdb->links |
| 212 | 241 | SET $update_set |
| 213 | 242 | WHERE link_id='$this->id' |
| 214 | 243 | "); |
| 244 | + do_action('update_syndicated_feed', $this->id, $this); | |
| 215 | 245 | |
| 216 | 246 | # -- Add new posts from feed and update any updated posts |
| 217 | 247 | $crashed = false; |
| 218 | 248 | |
| 219 | - if (is_array($this->magpie->items)) : | |
| 220 | - foreach ($this->magpie->items as $item) : | |
| 221 | - $post =& new SyndicatedPost($item, $this); | |
| 249 | + $posts = apply_filters( | |
| 250 | + 'syndicated_feed_items', | |
| 251 | + $this->magpie->originals, | |
| 252 | + $this | |
| 253 | + ); | |
| 254 | + if (is_array($posts)) : | |
| 255 | + foreach ($posts as $key => $original) : | |
| 256 | + $item = $this->magpie->items[$key]; | |
| 257 | + $post = new SyndicatedPost(array( | |
| 258 | + 'simplepie' => $original, | |
| 259 | + 'magpie' => $item, | |
| 260 | + ), $this); | |
| 261 | + | |
| 222 | 262 | if (!$resume or !in_array(trim($post->guid()), $processed)) : |
| 223 | 263 | $processed[] = $post->guid(); |
| 224 | 264 | if (!$post->filtered()) : |
| 225 | 265 | $new = $post->store(); |
| @@ -230,11 +270,15 @@ | ||
| 230 | 270 | $crashed = true; |
| 231 | 271 | break; |
| 232 | 272 | endif; |
| 233 | 273 | endif; |
| 274 | + unset($post); | |
| 234 | 275 | endforeach; |
| 235 | 276 | endif; |
| 236 | - | |
| 277 | + $suffix = ($crashed ? 'crashed' : 'completed'); | |
| 278 | + do_action('update_syndicated_feed_items', $this->id, $this); | |
| 279 | + do_action("update_syndicated_feed_items_${suffix}", $this->id, $this); | |
| 280 | + | |
| 237 | 281 | // Copy back any changes to feed settings made in the course of updating (e.g. new author rules) |
| 238 | 282 | $to_notes = $this->settings; |
| 239 | 283 | |
| 240 | 284 | $this->settings['update/processed'] = $processed; |
| @@ -249,13 +293,40 @@ | ||
| 249 | 293 | UPDATE $wpdb->links |
| 250 | 294 | SET $update_set |
| 251 | 295 | WHERE link_id='$this->id' |
| 252 | 296 | "); |
| 297 | + | |
| 298 | + do_action("update_syndicated_feed_completed", $this->id, $this); | |
| 253 | 299 | endif; |
| 254 | 300 | |
| 255 | 301 | return $new_count; |
| 256 | 302 | } /* SyndicatedLink::poll() */ |
| 257 | 303 | |
| 304 | + /** | |
| 305 | + * Updates the URL for the feed syndicated by this link. | |
| 306 | + * | |
| 307 | + * @param string $url The new feed URL to use for this source. | |
| 308 | + * @return bool TRUE on success, FALSE on failure. | |
| 309 | + */ | |
| 310 | + function set_uri ($url) { | |
| 311 | + global $wpdb; | |
| 312 | + | |
| 313 | + if ($this->found()) : | |
| 314 | + // Update link_rss | |
| 315 | + $result = $wpdb->query(" | |
| 316 | + UPDATE $wpdb->links | |
| 317 | + SET | |
| 318 | + link_rss = '".$wpdb->escape($url)."' | |
| 319 | + WHERE link_id = '".$wpdb->escape($this->id)."' | |
| 320 | + "); | |
| 321 | + | |
| 322 | + $ret = ($result ? true : false); | |
| 323 | + else : | |
| 324 | + $ret = false; | |
| 325 | + endif; | |
| 326 | + return $ret; | |
| 327 | + } /* SyndicatedLink::set_uri () */ | |
| 328 | + | |
| 258 | 329 | function map_name_to_new_user ($name, $newuser_name) { |
| 259 | 330 | global $wpdb; |
| 260 | 331 | |
| 261 | 332 | if (strlen($newuser_name) > 0) : |
| @@ -323,16 +394,93 @@ | ||
| 323 | 394 | endforeach; |
| 324 | 395 | return $notes; |
| 325 | 396 | } /* SyndicatedLink::settings_to_notes () */ |
| 326 | 397 | |
| 398 | + function save_settings ($reload = false) { | |
| 399 | + global $wpdb; | |
| 400 | + | |
| 401 | + // Save channel-level meta-data | |
| 402 | + foreach (array('link_name', 'link_description', 'link_url') as $what) : | |
| 403 | + $alter[] = "{$what} = '".$wpdb->escape($this->link->{$what})."'"; | |
| 404 | + endforeach; | |
| 405 | + | |
| 406 | + // Save settings to the notes field | |
| 407 | + $alter[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'"; | |
| 408 | + | |
| 409 | + // Update the properties of the link from settings changes, etc. | |
| 410 | + $update_set = implode(", ", $alter); | |
| 411 | + | |
| 412 | + $result = $wpdb->query(" | |
| 413 | + UPDATE $wpdb->links | |
| 414 | + SET $update_set | |
| 415 | + WHERE link_id='$this->id' | |
| 416 | + "); | |
| 417 | + | |
| 418 | + if ($reload) : | |
| 419 | + // force reload of link information from DB | |
| 420 | + if (function_exists('clean_bookmark_cache')) : | |
| 421 | + clean_bookmark_cache($this->id); | |
| 422 | + endif; | |
| 423 | + endif; | |
| 424 | + } /* SyndicatedLink::save_settings () */ | |
| 425 | + | |
| 426 | + /** | |
| 427 | + * Retrieves the value of a setting, allowing for a global setting to be | |
| 428 | + * used as a fallback, or a constant value, or both. | |
| 429 | + * | |
| 430 | + * @param string $name The link setting key | |
| 431 | + * @param mixed $fallback_global If the link setting is nonexistent or marked as a use-default value, fall back to the value of this global setting. | |
| 432 | + * @param mixed $fallback_value If the link setting and the global setting are nonexistent or marked as a use-default value, fall back to this constant value. | |
| 433 | + * @return bool TRUE on success, FALSE on failure. | |
| 434 | + */ | |
| 435 | + function setting ($name, $fallback_global = NULL, $fallback_value = NULL) { | |
| 436 | + $ret = NULL; | |
| 437 | + if (isset($this->settings[$name])) : | |
| 438 | + $ret = $this->settings[$name]; | |
| 439 | + endif; | |
| 440 | + | |
| 441 | + $no_value = ( | |
| 442 | + is_null($ret) | |
| 443 | + or (is_string($ret) and strtolower($ret)=='default') | |
| 444 | + ); | |
| 445 | + | |
| 446 | + if ($no_value and !is_null($fallback_global)) : | |
| 447 | + $ret = get_option('feedwordpress_'.$fallback_global, /*default=*/ NULL); | |
| 448 | + endif; | |
| 449 | + | |
| 450 | + $no_value = ( | |
| 451 | + is_null($ret) | |
| 452 | + or (is_string($ret) and strtolower($ret)=='default') | |
| 453 | + ); | |
| 454 | + | |
| 455 | + if ($no_value and !is_null($fallback_value)) : | |
| 456 | + $ret = $fallback_value; | |
| 457 | + endif; | |
| 458 | + return $ret; | |
| 459 | + } /* SyndicatedLink::setting () */ | |
| 460 | + | |
| 327 | 461 | function uri () { |
| 328 | 462 | return (is_object($this->link) ? $this->link->link_rss : NULL); |
| 329 | 463 | } /* SyndicatedLink::uri () */ |
| 330 | 464 | |
| 331 | - function homepage () { | |
| 332 | - return (isset($this->settings['feed/link']) ? $this->settings['feed/link'] : NULL); | |
| 465 | + function homepage ($fromFeed = true) { | |
| 466 | + if ($fromFeed) : | |
| 467 | + $url = (isset($this->settings['feed/link']) ? $this->settings['feed/link'] : NULL); | |
| 468 | + else : | |
| 469 | + $url = $this->link->link_url; | |
| 470 | + endif; | |
| 471 | + return $url; | |
| 333 | 472 | } /* SyndicatedLink::homepage () */ |
| 334 | 473 | |
| 474 | + function name ($fromFeed = true) { | |
| 475 | + if ($fromFeed) : | |
| 476 | + $name = (isset($this->settings['feed/title']) ? $this->settings['feed/title'] : NULL); | |
| 477 | + else : | |
| 478 | + $name = $this->link->link_name; | |
| 479 | + endif; | |
| 480 | + return $name; | |
| 481 | + } /* SyndicatedLink::name () */ | |
| 482 | + | |
| 335 | 483 | function ttl () { |
| 336 | 484 | if (is_object($this->magpie)) : |
| 337 | 485 | $channel = $this->magpie->channel; |
| 338 | 486 | else : |
| @@ -416,17 +564,25 @@ | ||
| 416 | 564 | endif; |
| 417 | 565 | return $ret; |
| 418 | 566 | } /* SyndicatedLink::hardcode () */ |
| 419 | 567 | |
| 420 | - function syndicated_status ($what, $default) { | |
| 568 | + function syndicated_status ($what, $default, $fallback = true) { | |
| 421 | 569 | global $wpdb; |
| 422 | 570 | |
| 423 | - $ret = get_option("feedwordpress_syndicated_{$what}_status"); | |
| 571 | + // Use local setting if we have it | |
| 424 | 572 | if ( isset($this->settings["$what status"]) ) : |
| 425 | 573 | $ret = $this->settings["$what status"]; |
| 426 | - elseif (!$ret) : | |
| 574 | + | |
| 575 | + // Or fall back to global default if we can | |
| 576 | + elseif ($fallback) : | |
| 577 | + $ret = FeedWordPress::syndicated_status($what, $default); | |
| 578 | + | |
| 579 | + // Or use default value if we can't. | |
| 580 | + else : | |
| 427 | 581 | $ret = $default; |
| 582 | + | |
| 428 | 583 | endif; |
| 584 | + | |
| 429 | 585 | return $wpdb->escape(trim(strtolower($ret))); |
| 430 | 586 | } /* SyndicatedLink:syndicated_status () */ |
| 431 | 587 | } // class SyndicatedLink |
| 432 | 588 | |