PluginProbe
FeedWordPress / 2011.0512
FeedWordPress v2011.0512
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.0512, at syndicatedlink.class.php

792 lines 25.1 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 $stale = true;
169 if (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='ping')) :
170 $stale = false; // don't update on any timed updates; pings only
171 elseif (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='next')) :
172 $stale = true; // update on the next timed update
173 elseif (!isset($this->settings['update/ttl']) or !isset($this->settings['update/last'])) :
174 $stale = true; // initial update
175 else :
176 $after = ((int) $this->settings['update/last'])
177 +((int) $this->settings['update/ttl'] * 60);
178 $stale = (time() >= $after);
179 endif;
180 return $stale;
181 } /* SyndicatedLink::stale () */
182
183 function poll ($crash_ts = NULL) {
184 global $wpdb;
185
186 $url = $this->uri(array('add_params' => true));
187 FeedWordPress::diagnostic('updated_feeds', 'Polling feed ['.$url.']');
188
189 $timeout = $this->setting('fetch timeout', 'feedwordpress_fetch_timeout', FEEDWORDPRESS_FETCH_TIMEOUT_DEFAULT);
190
191 $this->simplepie = apply_filters(
192 'syndicated_feed',
193 FeedWordPress::fetch($url, array('timeout' => $timeout)),
194 $this
195 );
196
197 // Filter compatibility mode
198 if (is_wp_error($this->simplepie)) :
199 $this->magpie = $this->simplepie;
200 else :
201 $this->magpie = new MagpieFromSimplePie($this->simplepie, NULL);
202 endif;
203
204 $new_count = NULL;
205
206 $resume = FeedWordPress::affirmative($this->settings, 'update/unfinished');
207 if ($resume) :
208 // pick up where we left off
209 $processed = array_map('trim', explode("\n", $this->settings['update/processed']));
210 else :
211 // begin at the beginning
212 $processed = array();
213 endif;
214
215 if (is_wp_error($this->simplepie)) :
216 $new_count = $this->simplepie;
217 // Error; establish an error setting.
218 $theError = array();
219 $theError['ts'] = time();
220 $theError['since'] = time();
221 $theError['object'] = $this->simplepie;
222
223 $oldError = $this->setting('update/error', NULL, NULL);
224 if (is_string($oldError)) :
225 $oldError = unserialize($oldError);
226 endif;
227
228 if (!is_null($oldError)) :
229 // Copy over the in-error-since timestamp
230 $theError['since'] = $oldError['since'];
231
232 // If this is a repeat error, then we should take
233 // a step back before we try to fetch it again.
234 $this->settings['update/last'] = time();
235 $this->settings['update/ttl'] = $this->automatic_ttl();
236 $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this);
237 $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl_from_error', $this->settings['update/ttl'], $this);
238
239 $this->settings['update/timed'] = 'automatically';
240 endif;
241
242 do_action('syndicated_feed_error', $theError, $oldError, $this);
243
244 $this->settings['update/error'] = serialize($theError);
245 $this->save_settings(/*reload=*/ true);
246
247 elseif (is_object($this->simplepie)) :
248 // Success; clear out error setting, if any.
249 if (isset($this->settings['update/error'])) :
250 unset($this->settings['update/error']);
251 endif;
252
253 $new_count = array('new' => 0, 'updated' => 0);
254
255 # -- Update Link metadata live from feed
256 $channel = $this->magpie->channel;
257
258 if (!isset($channel['id'])) :
259 $channel['id'] = $this->link->link_rss;
260 endif;
261
262 $update = array();
263 if (!$this->hardcode('url') and isset($channel['link'])) :
264 $update[] = "link_url = '".$wpdb->escape($channel['link'])."'";
265 endif;
266
267 if (!$this->hardcode('name') and isset($channel['title'])) :
268 $update[] = "link_name = '".$wpdb->escape($channel['title'])."'";
269 endif;
270
271 if (!$this->hardcode('description')) :
272 if (isset($channel['tagline'])) :
273 $update[] = "link_description = '".$wpdb->escape($channel['tagline'])."'";
274 elseif (isset($channel['description'])) :
275 $update[] = "link_description = '".$wpdb->escape($channel['description'])."'";
276 endif;
277 endif;
278
279 $this->settings = array_merge($this->settings, $this->flatten_array($channel));
280
281 $this->settings['update/last'] = time(); $ttl = $this->ttl();
282 if (!is_null($ttl)) :
283 $this->settings['update/ttl'] = $ttl;
284 $this->settings['update/timed'] = 'feed';
285 else :
286 $this->settings['update/ttl'] = $this->automatic_ttl();
287 $this->settings['update/timed'] = 'automatically';
288 endif;
289 $this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this);
290
291 if (!isset($this->settings['update/hold']) or $this->settings['update/hold']!='ping') :
292 $this->settings['update/hold'] = 'scheduled';
293 endif;
294
295 $this->settings['update/unfinished'] = 'yes';
296
297 $update[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
298
299 $update_set = implode(',', $update);
300
301 // Update the properties of the link from the feed information
302 $result = $wpdb->query("
303 UPDATE $wpdb->links
304 SET $update_set
305 WHERE link_id='$this->id'
306 ");
307 do_action('update_syndicated_feed', $this->id, $this);
308
309 # -- Add new posts from feed and update any updated posts
310 $crashed = false;
311
312 $posts = apply_filters(
313 'syndicated_feed_items',
314 $this->simplepie->get_items(),
315 &$this
316 );
317
318 $this->magpie->originals = $posts;
319
320 if (is_array($posts)) :
321 foreach ($posts as $key => $item) :
322 $post = new SyndicatedPost($item, $this);
323
324 if (!$resume or !in_array(trim($post->guid()), $processed)) :
325 $processed[] = $post->guid();
326 if (!$post->filtered()) :
327 $new = $post->store();
328 if ( $new !== false ) $new_count[$new]++;
329 endif;
330
331 if (!is_null($crash_ts) and (time() > $crash_ts)) :
332 $crashed = true;
333 break;
334 endif;
335 endif;
336 unset($post);
337 endforeach;
338 endif;
339 $suffix = ($crashed ? 'crashed' : 'completed');
340 do_action('update_syndicated_feed_items', $this->id, $this);
341 do_action("update_syndicated_feed_items_${suffix}", $this->id, $this);
342
343 // Copy back any changes to feed settings made in the course of updating (e.g. new author rules)
344 $to_notes = $this->settings;
345
346 $this->settings['update/processed'] = $processed;
347 if (!$crashed) :
348 $this->settings['update/unfinished'] = 'no';
349 endif;
350
351 $update_set = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
352
353 // Update the properties of the link from the feed information
354 $result = $wpdb->query("
355 UPDATE $wpdb->links
356 SET $update_set
357 WHERE link_id='$this->id'
358 ");
359
360 do_action("update_syndicated_feed_completed", $this->id, $this);
361 endif;
362
363 // All done; let's clean up.
364 $this->magpie = NULL;
365
366 // Avoid circular-reference memory leak in PHP < 5.3.
367 // Cf. <http://simplepie.org/wiki/faq/i_m_getting_memory_leaks>
368 if (method_exists($this->simplepie, '__destruct')) :
369 $this->simplepie->__destruct();
370 endif;
371 $this->simplepie = NULL;
372
373 return $new_count;
374 } /* SyndicatedLink::poll() */
375
376 /**
377 * Updates the URL for the feed syndicated by this link.
378 *
379 * @param string $url The new feed URL to use for this source.
380 * @return bool TRUE on success, FALSE on failure.
381 */
382 function set_uri ($url) {
383 global $wpdb;
384
385 if ($this->found()) :
386 // Update link_rss
387 $result = $wpdb->query("
388 UPDATE $wpdb->links
389 SET
390 link_rss = '".$wpdb->escape($url)."'
391 WHERE link_id = '".$wpdb->escape($this->id)."'
392 ");
393
394 $ret = ($result ? true : false);
395 else :
396 $ret = false;
397 endif;
398 return $ret;
399 } /* SyndicatedLink::set_uri () */
400
401 function deactivate () {
402 global $wpdb;
403
404 $wpdb->query($wpdb->prepare("
405 UPDATE $wpdb->links SET link_visible = 'N' WHERE link_id = %d
406 ", (int) $this->id));
407 } /* SyndicatedLink::deactivate () */
408
409 function delete () {
410 global $wpdb;
411
412 $wpdb->query($wpdb->prepare("
413 DELETE FROM $wpdb->postmeta WHERE meta_key='syndication_feed_id'
414 AND meta_value = '%s'
415 ", $this->id));
416
417 $wpdb->query($wpdb->prepare("
418 DELETE FROM $wpdb->links WHERE link_id = %d
419 ", (int) $this->id));
420
421 $this->id = NULL;
422 } /* SyndicatedLink::delete () */
423
424 function nuke () {
425 global $wpdb;
426
427 // Make a list of the items syndicated from this feed...
428 $post_ids = $wpdb->get_col($wpdb->prepare("
429 SELECT post_id FROM $wpdb->postmeta
430 WHERE meta_key = 'syndication_feed_id'
431 AND meta_value = '%s'
432 ", $this->id));
433
434 // ... and kill them all
435 if (count($post_ids) > 0) :
436 foreach ($post_ids as $post_id) :
437 // Force scrubbing of deleted post
438 // rather than sending to Trashcan
439 wp_delete_post(
440 /*postid=*/ $post_id,
441 /*force_delete=*/ true
442 );
443 endforeach;
444 endif;
445
446 $this->delete();
447 } /* SyndicatedLink::nuke () */
448
449 function map_name_to_new_user ($name, $newuser_name) {
450 global $wpdb;
451
452 if (strlen($newuser_name) > 0) :
453 $newuser_id = fwp_insert_new_user($newuser_name);
454 if (is_numeric($newuser_id)) :
455 if (is_null($name)) : // Unfamiliar author
456 $this->settings['unfamiliar author'] = $newuser_id;
457 else :
458 $this->settings['map authors']['name'][$name] = $newuser_id;
459 endif;
460 else :
461 // TODO: Add some error detection and reporting
462 endif;
463 else :
464 // TODO: Add some error reporting
465 endif;
466 } /* SyndicatedLink::map_name_to_new_user () */
467
468 function imploded_settings () {
469 return array('cats', 'tags', 'match/cats', 'match/tags', 'match/filter');
470 }
471 function settings_to_notes () {
472 $to_notes = $this->settings;
473
474 unset($to_notes['link/id']); // Magic setting; don't save
475 unset($to_notes['link/uri']); // Magic setting; don't save
476 unset($to_notes['link/name']); // Magic setting; don't save
477 unset($to_notes['hardcode categories']); // Deprecated
478 unset($to_notes['unfamiliar categories']); // Deprecated
479
480 // Collapse array settings
481 if (isset($to_notes['update/processed']) and (is_array($to_notes['update/processed']))) :
482 $to_notes['update/processed'] = implode("\n", $to_notes['update/processed']);
483 endif;
484
485 foreach ($this->imploded_settings() as $what) :
486 if (isset($to_notes[$what]) and is_array($to_notes[$what])) :
487 $to_notes[$what] = implode(
488 FEEDWORDPRESS_CAT_SEPARATOR,
489 $to_notes[$what]
490 );
491 endif;
492 endforeach;
493
494 if (isset($to_notes['terms']) and is_array($to_notes['terms'])) :
495 // Serialize it.
496 $to_notes['terms'] = serialize($to_notes['terms']);
497 endif;
498
499 // Collapse the author mapping rule structure back into a flat string
500 if (isset($to_notes['map authors'])) :
501 $ma = array();
502 foreach ($to_notes['map authors'] as $rule_type => $author_rules) :
503 foreach ($author_rules as $author_name => $author_action) :
504 $ma[] = $rule_type."\n".$author_name."\n".$author_action;
505 endforeach;
506 endforeach;
507 $to_notes['map authors'] = implode("\n\n", $ma);
508 endif;
509
510 $notes = '';
511 foreach ($to_notes as $key => $value) :
512 $notes .= $key . ": ". addcslashes($value, "\0..\37".'\\') . "\n";
513 endforeach;
514 return $notes;
515 } /* SyndicatedLink::settings_to_notes () */
516
517 function save_settings ($reload = false) {
518 global $wpdb;
519
520 // Save channel-level meta-data
521 foreach (array('link_name', 'link_description', 'link_url') as $what) :
522 $alter[] = "{$what} = '".$wpdb->escape($this->link->{$what})."'";
523 endforeach;
524
525 // Save settings to the notes field
526 $alter[] = "link_notes = '".$wpdb->escape($this->settings_to_notes())."'";
527
528 // Update the properties of the link from settings changes, etc.
529 $update_set = implode(", ", $alter);
530
531 $result = $wpdb->query("
532 UPDATE $wpdb->links
533 SET $update_set
534 WHERE link_id='$this->id'
535 ");
536
537 if ($reload) :
538 // force reload of link information from DB
539 if (function_exists('clean_bookmark_cache')) :
540 clean_bookmark_cache($this->id);
541 endif;
542 endif;
543 } /* SyndicatedLink::save_settings () */
544
545 /**
546 * Retrieves the value of a setting, allowing for a global setting to be
547 * used as a fallback, or a constant value, or both.
548 *
549 * @param string $name The link setting key
550 * @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.
551 * @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.
552 * @return bool TRUE on success, FALSE on failure.
553 */
554 function setting ($name, $fallback_global = NULL, $fallback_value = NULL, $default = 'default') {
555 $ret = NULL;
556 if (isset($this->settings[$name])) :
557 $ret = $this->settings[$name];
558 endif;
559
560 $no_value = (
561 is_null($ret)
562 or (is_string($ret) and strtolower($ret)==$default)
563 );
564
565 if ($no_value and !is_null($fallback_global)) :
566 // Avoid duplication of this correction
567 $fallback_global = preg_replace('/^feedwordpress_/', '', $fallback_global);
568
569 $ret = get_option('feedwordpress_'.$fallback_global, /*default=*/ NULL);
570 endif;
571
572 $no_value = (
573 is_null($ret)
574 or (is_string($ret) and strtolower($ret)==$default)
575 );
576
577 if ($no_value and !is_null($fallback_value)) :
578 $ret = $fallback_value;
579 endif;
580 return $ret;
581 } /* SyndicatedLink::setting () */
582
583 function update_setting ($name, $value, $default = 'default') {
584 if (!is_null($value) and $value != $default) :
585 $this->settings[$name] = $value;
586 else : // Zap it.
587 unset($this->settings[$name]);
588 endif;
589 } /* SyndicatedLink::update_setting () */
590
591 function uri ($params = array()) {
592 $params = shortcode_atts(array(
593 'add_params' => false,
594 ), $params);
595
596 $uri = (is_object($this->link) ? $this->link->link_rss : NULL);
597 if (!is_null($uri) and strlen($uri) > 0 and $params['add_params']) :
598 $qp = maybe_unserialize($this->setting('query parameters', array()));
599
600 // For high-tech HTTP feed request kung fu
601 $qp = apply_filters('syndicated_feed_parameters', $qp, $uri, $this);
602
603 $q = array();
604 if (is_array($qp) and count($qp) > 0) :
605 foreach ($qp as $pair) :
606 $q[] = urlencode($pair[0]).'='.urlencode($pair[1]);
607 endforeach;
608
609 // Are we appending to a URI that already has params?
610 $sep = ((strpos('?', $uri)===false) ? '?' : '&');
611
612 // Tack it on
613 $uri .= $sep . implode("&", $q);
614 endif;
615 endif;
616
617 return $uri;
618 } /* SyndicatedLink::uri () */
619
620 function property_cascade ($fromFeed, $link_field, $setting, $simplepie_method) {
621 $value = NULL;
622 if ($fromFeed) :
623 if (isset($this->settings[$setting])) :
624 $value = $this->settings[$setting];
625 elseif (is_object($this->simplepie)
626 and method_exists($this->simplepie, $simplepie_method)) :
627 $value = $this->simplepie->{$simplepie_method}();
628 endif;
629 else :
630 $value = $this->link->{$link_field};
631 endif;
632 return $value;
633 } /* SyndicatedLink::property_cascade () */
634
635 function homepage ($fromFeed = true) {
636 return $this->property_cascade($fromFeed, 'link_url', 'feed/link', 'get_link');
637 } /* SyndicatedLink::homepage () */
638
639 function name ($fromFeed = true) {
640 return $this->property_cascade($fromFeed, 'link_name', 'feed/title', 'get_title');
641 } /* SyndicatedLink::name () */
642
643 function guid () {
644 $ret = $this->setting('feed/id', NULL, $this->uri());
645
646 // If we can get it live from the feed, do so.
647 if (is_object($this->simplepie)) :
648 $search = array(
649 array(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'),
650 array(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'),
651 array(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'),
652 array(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'),
653 array(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'),
654 );
655
656 foreach ($search as $pair) :
657 if ($id_tags = $this->simplepie->get_feed_tags($pair[0], $pair[1])) :
658 $ret = $id_tags[0]['data'];
659 break;
660 elseif ($id_tags = $this->simplepie->get_channel_tags($pair[0], $pair[1])) :
661 $ret = $id_tags[0]['data'];
662 break;
663 endif;
664 endforeach;
665 endif;
666 return $ret;
667 }
668
669 function ttl () {
670 if (is_object($this->magpie)) :
671 $channel = $this->magpie->channel;
672 else :
673 $channel = array();
674 endif;
675
676 if (isset($channel['ttl'])) :
677 // "ttl stands for time to live. It's a number of
678 // minutes that indicates how long a channel can be
679 // cached before refreshing from the source."
680 // <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>
681 $ret = $channel['ttl'];
682 elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
683 $period_minutes = array (
684 'hourly' => 60, /* minutes in an hour */
685 'daily' => 1440, /* minutes in a day */
686 'weekly' => 10080, /* minutes in a week */
687 'monthly' => 43200, /* minutes in a month */
688 'yearly' => 525600, /* minutes in a year */
689 );
690
691 // "sy:updatePeriod: Describes the period over which the
692 // channel format is updated. Acceptable values are:
693 // hourly, daily, weekly, monthly, yearly. If omitted,
694 // daily is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
695 if (isset($channel['sy']['updateperiod'])) : $period = $channel['sy']['updateperiod'];
696 else : $period = 'daily';
697 endif;
698
699 // "sy:updateFrequency: Used to describe the frequency
700 // of updates in relation to the update period. A
701 // positive integer indicates how many times in that
702 // period the channel is updated. ... If omitted a value
703 // of 1 is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
704 if (isset($channel['sy']['updatefrequency'])) : $freq = (int) $channel['sy']['updatefrequency'];
705 else : $freq = 1;
706 endif;
707
708 $ret = (int) ($period_minutes[$period] / $freq);
709 else :
710 $ret = NULL;
711 endif;
712 return $ret;
713 } /* SyndicatedLink::ttl() */
714
715 function automatic_ttl () {
716 // spread out over a time interval for staggered updates
717 $updateWindow = $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
718 if (!is_numeric($updateWindow) or ($updateWindow < 1)) :
719 $updateWindow = DEFAULT_UPDATE_PERIOD;
720 endif;
721
722 $fudgedInterval = $updateWindow+rand(0, 2*($updateWindow/3));
723 return apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this);
724 } /* SyndicatedLink::automatic_ttl () */
725
726 // SyndicatedLink::flatten_array (): flatten an array. Useful for
727 // hierarchical and namespaced elements.
728 //
729 // Given an array which may contain array or object elements in it,
730 // return a "flattened" array: a one-dimensional array of scalars
731 // containing each of the scalar elements contained within the array
732 // structure. Thus, for example, if $a['b']['c']['d'] == 'e', then the
733 // returned array for FeedWordPress::flatten_array($a) will contain a key
734 // $a['feed/b/c/d'] with value 'e'.
735 function flatten_array ($arr, $prefix = 'feed/', $separator = '/') {
736 $ret = array ();
737 if (is_array($arr)) :
738 foreach ($arr as $key => $value) :
739 if (is_scalar($value)) :
740 $ret[$prefix.$key] = $value;
741 else :
742 $ret = array_merge($ret, $this->flatten_array($value, $prefix.$key.$separator, $separator));
743 endif;
744 endforeach;
745 endif;
746 return $ret;
747 } /* SyndicatedLink::flatten_array () */
748
749 function hardcode ($what) {
750 $default = get_option("feedwordpress_hardcode_$what");
751 if ( $default === 'yes' ) :
752 // If the default is to hardcode, then we want the
753 // negation of negative(): TRUE by default and FALSE if
754 // the setting is explicitly "no"
755 $ret = !FeedWordPress::negative($this->settings, "hardcode $what");
756 else :
757 // If the default is NOT to hardcode, then we want
758 // affirmative(): FALSE by default and TRUE if the
759 // setting is explicitly "yes"
760 $ret = FeedWordPress::affirmative($this->settings, "hardcode $what");
761 endif;
762 return $ret;
763 } /* SyndicatedLink::hardcode () */
764
765 function syndicated_status ($what, $default, $fallback = true) {
766 global $wpdb;
767
768 // Use local setting if we have it
769 if ( isset($this->settings["$what status"]) ) :
770 $ret = $this->settings["$what status"];
771
772 // Or fall back to global default if we can
773 elseif ($fallback) :
774 $ret = FeedWordPress::syndicated_status($what, $default);
775
776 // Or use default value if we can't.
777 else :
778 $ret = $default;
779
780 endif;
781
782 return $wpdb->escape(trim(strtolower($ret)));
783 } /* SyndicatedLink:syndicated_status () */
784
785 function taxonomies () {
786 $post_type = $this->setting('syndicated post type', 'syndicated_post_type', 'post');
787 return get_object_taxonomies(array('object_type' => $post_type), 'names');
788 } /* SyndicatedLink::taxonomies () */
789
790 } // class SyndicatedLink
791
792