PluginProbe
FeedWordPress / 2011.1018
FeedWordPress v2011.1018
trunk 0.8 0.9 0.91 0.95 0.96 0.97 0.98 0.981 0.99 0.991 0.992 0.993 2008.1030 2008.1101 2008.1105 2008.1214 2009.0612 2009.0613 2009.0618 2009.0707 2009.1111 2009.1112 2010.0127 2010.0528 All 65 releases
feedwordpress / syndicatedlink.class.php

syndicatedlink.class.php in FeedWordPress 2011.1018, at syndicatedlink.class.php

834 lines 26.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 # class SyndicatedLink: represents a syndication feed stored within the
3 # WordPress database
4 #
5 # To keep things compact and editable from within WordPress, we use all the
6 # links under a particular category in the WordPress "Blogroll" for the list of
7 # feeds to syndicate. "Contributors" is the category used by default; you can
8 # configure that under Options --> Syndication.
9 #
10 # Fields used are:
11 #
12 # * link_rss: the URI of the Atom/RSS feed to syndicate
13 #
14 # * link_notes: user-configurable options, with keys and values
15 # like so:
16 #
17 # key: value
18 # cats: computers\nweb
19 # feed/key: value
20 #
21 # Keys that start with "feed/" are gleaned from the data supplied
22 # by the feed itself, and will be overwritten with each update.
23 #
24 # Values have linebreak characters escaped with C-style
25 # backslashes (so, for example, a newline becomes "\n").
26 #
27 # The value of `cats` is used as a newline-separated list of
28 # default categories for any post coming from a particular feed.
29 # (In the example above, any posts from this feed will be placed
30 # in the "computers" and "web" categories--*in addition to* any
31 # categories that may already be applied to the posts.)
32 #
33 # Values of keys in link_notes are accessible from templates using
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;
40 var $link = null;
41 var $settings = array ();
42 var $simplepie = null;
43 var $magpie = null;
44
45 function SyndicatedLink ($link) {
46 global $wpdb;
47
48 if (is_object($link)) :
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
170 $stale = true;
171 if ($this->setting('update/hold')=='ping') :
172 $stale = false; // don't update on any timed updates; pings only
173 elseif ($this->setting('update/hold')=='next') :
174 $stale = true; // update on the next timed update
175 elseif ( !$this->setting('update/last') ) :
176 $stale = true; // initial update
177 elseif ($feedwordpress->force_update_all()) :
178 $stale = true; // forced general updating
179 else :
180 $after = (
181 (int) $this->setting('update/last')
182 + (int) $this->setting('update/fudge')
183 + ((int) $this->setting('update/ttl') * 60)
184 );
185 $stale = (time() >= $after);
186 endif;
187 return $stale;
188 } /* SyndicatedLink::stale () */
189
190 function poll ($crash_ts = NULL) {
191 global $wpdb;
192
193 $url = $this->uri(array('add_params' => true));
194 FeedWordPress::diagnostic('updated_feeds', 'Polling feed ['.$url.']');
195
196 $timeout = $this->setting('fetch timeout', 'feedwordpress_fetch_timeout', FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT);
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;
207 else :
208 $this->magpie = new MagpieFromSimplePie($this->simplepie, NULL);
209 endif;
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();
220 endif;
221
222 if (is_wp_error($this->simplepie)) :
223 $new_count = $this->simplepie;
224 // Error; establish an error setting.
225 $theError = array();
226 $theError['ts'] = time();
227 $theError['since'] = time();
228 $theError['object'] = $this->simplepie;
229
230 $oldError = $this->setting('update/error', NULL, NULL);
231 if (is_string($oldError)) :
232 $oldError = unserialize($oldError);
233 endif;
234
235 if (!is_null($oldError)) :
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
262 # -- Update Link metadata live from feed
263 $channel = $this->magpie->channel;
264
265 if (!isset($channel['id'])) :
266 $channel['id'] = $this->link->link_rss;
267 endif;
268
269 $update = array();
270 if (!$this->hardcode('url') and isset($channel['link'])) :
271 $update[] = "link_url = '".$wpdb->escape($channel['link'])."'";
272 endif;
273
274 if (!$this->hardcode('name') and isset($channel['title'])) :
275 $update[] = "link_name = '".$wpdb->escape($channel['title'])."'";
276 endif;
277
278 if (!$this->hardcode('description')) :
279 if (isset($channel['tagline'])) :
280 $update[] = "link_description = '".$wpdb->escape($channel['tagline'])."'";
281 elseif (isset($channel['description'])) :
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
312 $update_set = implode(',', $update);
313
314 // Update the properties of the link from the feed information
315 $result = $wpdb->query("
316 UPDATE $wpdb->links
317 SET $update_set
318 WHERE link_id='$this->id'
319 ");
320 do_action('update_syndicated_feed', $this->id, $this);
321
322 # -- Add new posts from feed and update any updated posts
323 $crashed = false;
324
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);
336
337 if (!$resume or !in_array(trim($post->guid()), $processed)) :
338 $processed[] = $post->guid();
339 if (!$post->filtered()) :
340 $new = $post->store();
341 if ( $new !== false ) $new_count[$new]++;
342 endif;
343
344 if (!is_null($crash_ts) and (time() > $crash_ts)) :
345 $crashed = true;
346 break;
347 endif;
348 endif;
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
367 $result = $wpdb->query("
368 UPDATE $wpdb->links
369 SET $update_set
370 WHERE link_id='$this->id'
371 ");
372
373 do_action("update_syndicated_feed_completed", $this->id, $this);
374 endif;
375
376 // All done; let's clean up.
377 $this->magpie = NULL;
378
379 // Avoid circular-reference memory leak in PHP < 5.3.
380 // Cf. <http://simplepie.org/wiki/faq/i_m_getting_memory_leaks>
381 if (method_exists($this->simplepie, '__destruct')) :
382 $this->simplepie->__destruct();
383 endif;
384 $this->simplepie = NULL;
385
386 return $new_count;
387 } /* SyndicatedLink::poll() */
388
389 /**
390 * Updates the URL for the feed syndicated by this link.
391 *
392 * @param string $url The new feed URL to use for this source.
393 * @return bool TRUE on success, FALSE on failure.
394 */
395 function set_uri ($url) {
396 global $wpdb;
397
398 if ($this->found()) :
399 // Update link_rss
400 $result = $wpdb->query("
401 UPDATE $wpdb->links
402 SET
403 link_rss = '".$wpdb->escape($url)."'
404 WHERE link_id = '".$wpdb->escape($this->id)."'
405 ");
406
407 $ret = ($result ? true : false);
408 else :
409 $ret = false;
410 endif;
411 return $ret;
412 } /* SyndicatedLink::set_uri () */
413
414 function deactivate () {
415 global $wpdb;
416
417 $wpdb->query($wpdb->prepare("
418 UPDATE $wpdb->links SET link_visible = 'N' WHERE link_id = %d
419 ", (int) $this->id));
420 } /* SyndicatedLink::deactivate () */
421
422 function delete () {
423 global $wpdb;
424
425 $wpdb->query($wpdb->prepare("
426 DELETE FROM $wpdb->postmeta WHERE meta_key='syndication_feed_id'
427 AND meta_value = '%s'
428 ", $this->id));
429
430 $wpdb->query($wpdb->prepare("
431 DELETE FROM $wpdb->links WHERE link_id = %d
432 ", (int) $this->id));
433
434 $this->id = NULL;
435 } /* SyndicatedLink::delete () */
436
437 function nuke () {
438 global $wpdb;
439
440 // Make a list of the items syndicated from this feed...
441 $post_ids = $wpdb->get_col($wpdb->prepare("
442 SELECT post_id FROM $wpdb->postmeta
443 WHERE meta_key = 'syndication_feed_id'
444 AND meta_value = '%s'
445 ", $this->id));
446
447 // ... and kill them all
448 if (count($post_ids) > 0) :
449 foreach ($post_ids as $post_id) :
450 // Force scrubbing of deleted post
451 // rather than sending to Trashcan
452 wp_delete_post(
453 /*postid=*/ $post_id,
454 /*force_delete=*/ true
455 );
456 endforeach;
457 endif;
458
459 $this->delete();
460 } /* SyndicatedLink::nuke () */
461
462 function map_name_to_new_user ($name, $newuser_name) {
463 global $wpdb;
464
465 if (strlen($newuser_name) > 0) :
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
475 endif;
476 else :
477 // TODO: Add some error reporting
478 endif;
479 } /* SyndicatedLink::map_name_to_new_user () */
480
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
487 unset($to_notes['link/id']); // Magic setting; don't save
488 unset($to_notes['link/uri']); // Magic setting; don't save
489 unset($to_notes['link/name']); // Magic setting; don't save
490 unset($to_notes['hardcode categories']); // Deprecated
491 unset($to_notes['unfamiliar categories']); // Deprecated
492
493 // Collapse array settings
494 if (isset($to_notes['update/processed']) and (is_array($to_notes['update/processed']))) :
495 $to_notes['update/processed'] = implode("\n", $to_notes['update/processed']);
496 endif;
497
498 foreach ($this->imploded_settings() as $what) :
499 if (isset($to_notes[$what]) and is_array($to_notes[$what])) :
500 $to_notes[$what] = implode(
501 FEEDWORDPRESS_CAT_SEPARATOR,
502 $to_notes[$what]
503 );
504 endif;
505 endforeach;
506
507 if (isset($to_notes['terms']) and is_array($to_notes['terms'])) :
508 // Serialize it.
509 $to_notes['terms'] = serialize($to_notes['terms']);
510 endif;
511
512 // Collapse the author mapping rule structure back into a flat string
513 if (isset($to_notes['map authors'])) :
514 $ma = array();
515 foreach ($to_notes['map authors'] as $rule_type => $author_rules) :
516 foreach ($author_rules as $author_name => $author_action) :
517 $ma[] = $rule_type."\n".$author_name."\n".$author_action;
518 endforeach;
519 endforeach;
520 $to_notes['map authors'] = implode("\n\n", $ma);
521 endif;
522
523 $notes = '';
524 foreach ($to_notes as $key => $value) :
525 $notes .= $key . ": ". addcslashes($value, "\0..\37".'\\') . "\n";
526 endforeach;
527 return $notes;
528 } /* SyndicatedLink::settings_to_notes () */
529
530 function save_settings ($reload = false) {
531 global $wpdb;
532
533 // Save channel-level meta-data
534 foreach (array('link_name', 'link_description', 'link_url') as $what) :
535 $alter[] = "{$what} = '".$wpdb->escape($this->link->{$what})."'";
536 endforeach;
537
538 // Save settings to the notes field
539 $alter[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
540
541 // Update the properties of the link from settings changes, etc.
542 $update_set = implode(", ", $alter);
543
544 $result = $wpdb->query("
545 UPDATE $wpdb->links
546 SET $update_set
547 WHERE link_id='$this->id'
548 ");
549
550 if ($reload) :
551 // force reload of link information from DB
552 if (function_exists('clean_bookmark_cache')) :
553 clean_bookmark_cache($this->id);
554 endif;
555 endif;
556 } /* SyndicatedLink::save_settings () */
557
558 /**
559 * Retrieves the value of a setting, allowing for a global setting to be
560 * used as a fallback, or a constant value, or both.
561 *
562 * @param string $name The link setting key
563 * @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.
564 * @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.
565 * @return bool TRUE on success, FALSE on failure.
566 */
567 function setting ($name, $fallback_global = NULL, $fallback_value = NULL, $default = 'default') {
568 $ret = NULL;
569 if (isset($this->settings[$name])) :
570 $ret = $this->settings[$name];
571 endif;
572
573 $no_value = (
574 is_null($ret)
575 or (is_string($ret) and strtolower($ret)==$default)
576 );
577
578 if ($no_value and !is_null($fallback_global)) :
579 // Avoid duplication of this correction
580 $fallback_global = preg_replace('/^feedwordpress_/', '', $fallback_global);
581
582 $ret = get_option('feedwordpress_'.$fallback_global, /*default=*/ NULL);
583 endif;
584
585 $no_value = (
586 is_null($ret)
587 or (is_string($ret) and strtolower($ret)==$default)
588 );
589
590 if ($no_value and !is_null($fallback_value)) :
591 $ret = $fallback_value;
592 endif;
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;
599 else : // Zap it.
600 unset($this->settings[$name]);
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']) :
611 $qp = maybe_unserialize($this->setting('query parameters', array()));
612
613 // For high-tech HTTP feed request kung fu
614 $qp = apply_filters('syndicated_feed_parameters', $qp, $uri, $this);
615
616 $q = array();
617 if (is_array($qp) and count($qp) > 0) :
618 foreach ($qp as $pair) :
619 $q[] = urlencode($pair[0]).'='.urlencode($pair[1]);
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;
631 } /* SyndicatedLink::uri () */
632
633 function username () {
634 return $this->setting('http username', 'http_username', NULL);
635 } /* SyndicatedLink::username () */
636
637 function password () {
638 return $this->setting('http password', 'http_password', NULL);
639 } /* SyndicatedLink::password () */
640
641 function authentication_method () {
642 $auth = $this->setting('http auth method', NULL);
643 if (('-' == $auth) or (strlen($auth)==0)) :
644 $auth = NULL;
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};
660 endif;
661 return $value;
662 } /* SyndicatedLink::property_cascade () */
663
664 function homepage ($fromFeed = true) {
665 return $this->property_cascade($fromFeed, 'link_url', 'feed/link', 'get_link');
666 } /* SyndicatedLink::homepage () */
667
668 function name ($fromFeed = true) {
669 return $this->property_cascade($fromFeed, 'link_name', 'feed/title', 'get_title');
670 } /* SyndicatedLink::name () */
671
672 function guid () {
673 $ret = $this->setting('feed/id', NULL, $this->uri());
674
675 // If we can get it live from the feed, do so.
676 if (is_object($this->simplepie)) :
677 $search = array(
678 array(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'),
679 array(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'),
680 array(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'),
681 array(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'),
682 array(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'),
683 );
684
685 foreach ($search as $pair) :
686 if ($id_tags = $this->simplepie->get_feed_tags($pair[0], $pair[1])) :
687 $ret = $id_tags[0]['data'];
688 break;
689 elseif ($id_tags = $this->simplepie->get_channel_tags($pair[0], $pair[1])) :
690 $ret = $id_tags[0]['data'];
691 break;
692 endif;
693 endforeach;
694 endif;
695 return $ret;
696 }
697
698 function ttl ($return_element = false) {
699 if (is_object($this->magpie)) :
700 $channel = $this->magpie->channel;
701 else :
702 $channel = array();
703 endif;
704
705 if (isset($channel['ttl'])) :
706 // "ttl stands for time to live. It's a number of
707 // minutes that indicates how long a channel can be
708 // cached before refreshing from the source."
709 // <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>
710 $xml = 'rss:ttl';
711 $ret = $channel['ttl'];
712 elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
713 $period_minutes = array (
714 'hourly' => 60, /* minutes in an hour */
715 'daily' => 1440, /* minutes in a day */
716 'weekly' => 10080, /* minutes in a week */
717 'monthly' => 43200, /* minutes in a month */
718 'yearly' => 525600, /* minutes in a year */
719 );
720
721 // "sy:updatePeriod: Describes the period over which the
722 // channel format is updated. Acceptable values are:
723 // hourly, daily, weekly, monthly, yearly. If omitted,
724 // daily is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
725 if (isset($channel['sy']['updateperiod'])) : $period = $channel['sy']['updateperiod'];
726 else : $period = 'daily';
727 endif;
728
729 // "sy:updateFrequency: Used to describe the frequency
730 // of updates in relation to the update period. A
731 // positive integer indicates how many times in that
732 // period the channel is updated. ... If omitted a value
733 // of 1 is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
734 if (isset($channel['sy']['updatefrequency'])) : $freq = (int) $channel['sy']['updatefrequency'];
735 else : $freq = 1;
736 endif;
737
738 $xml = 'sy:updateFrequency';
739 $ret = (int) ($period_minutes[$period] / $freq);
740 else :
741 $xml = NULL;
742 $ret = NULL;
743 endif;
744
745 if ('yes'==$this->setting('update/minimum', 'update_minimum', 'no')) :
746 $min = (int) $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
747
748 if ($min > $ret) :
749 $ret = NULL;
750 endif;
751 endif;
752 return ($return_element ? array($ret, $xml) : $ret);
753 } /* SyndicatedLink::ttl() */
754
755 function automatic_ttl () {
756 // spread out over a time interval for staggered updates
757 $updateWindow = $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
758 if (!is_numeric($updateWindow) or ($updateWindow < 1)) :
759 $updateWindow = DEFAULT_UPDATE_PERIOD;
760 endif;
761
762 // We get a fudge of 1/3 of window from elsewhere. We'll do some more
763 // fudging here.
764 $fudgedInterval = $updateWindow+rand(-($updateWindow/6), 5*($updateWindow/12));
765 return apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this);
766 } /* SyndicatedLink::automatic_ttl () */
767
768 // SyndicatedLink::flatten_array (): flatten an array. Useful for
769 // hierarchical and namespaced elements.
770 //
771 // Given an array which may contain array or object elements in it,
772 // return a "flattened" array: a one-dimensional array of scalars
773 // containing each of the scalar elements contained within the array
774 // structure. Thus, for example, if $a['b']['c']['d'] == 'e', then the
775 // returned array for FeedWordPress::flatten_array($a) will contain a key
776 // $a['feed/b/c/d'] with value 'e'.
777 function flatten_array ($arr, $prefix = 'feed/', $separator = '/') {
778 $ret = array ();
779 if (is_array($arr)) :
780 foreach ($arr as $key => $value) :
781 if (is_scalar($value)) :
782 $ret[$prefix.$key] = $value;
783 else :
784 $ret = array_merge($ret, $this->flatten_array($value, $prefix.$key.$separator, $separator));
785 endif;
786 endforeach;
787 endif;
788 return $ret;
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 () */
806
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 () */
826
827 function taxonomies () {
828 $post_type = $this->setting('syndicated post type', 'syndicated_post_type', 'post');
829 return get_object_taxonomies(array('object_type' => $post_type), 'names');
830 } /* SyndicatedLink::taxonomies () */
831
832 } // class SyndicatedLink
833
834