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

818 lines 25.8 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 property_cascade ($fromFeed, $link_field, $setting, $simplepie_method) {
634 $value = NULL;
635 if ($fromFeed) :
636 if (isset($this->settings[$setting])) :
637 $value = $this->settings[$setting];
638 elseif (is_object($this->simplepie)
639 and method_exists($this->simplepie, $simplepie_method)) :
640 $value = $this->simplepie->{$simplepie_method}();
641 endif;
642 else :
643 $value = $this->link->{$link_field};
644 endif;
645 return $value;
646 } /* SyndicatedLink::property_cascade () */
647
648 function homepage ($fromFeed = true) {
649 return $this->property_cascade($fromFeed, 'link_url', 'feed/link', 'get_link');
650 } /* SyndicatedLink::homepage () */
651
652 function name ($fromFeed = true) {
653 return $this->property_cascade($fromFeed, 'link_name', 'feed/title', 'get_title');
654 } /* SyndicatedLink::name () */
655
656 function guid () {
657 $ret = $this->setting('feed/id', NULL, $this->uri());
658
659 // If we can get it live from the feed, do so.
660 if (is_object($this->simplepie)) :
661 $search = array(
662 array(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'),
663 array(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'),
664 array(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'),
665 array(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'),
666 array(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'),
667 );
668
669 foreach ($search as $pair) :
670 if ($id_tags = $this->simplepie->get_feed_tags($pair[0], $pair[1])) :
671 $ret = $id_tags[0]['data'];
672 break;
673 elseif ($id_tags = $this->simplepie->get_channel_tags($pair[0], $pair[1])) :
674 $ret = $id_tags[0]['data'];
675 break;
676 endif;
677 endforeach;
678 endif;
679 return $ret;
680 }
681
682 function ttl ($return_element = false) {
683 if (is_object($this->magpie)) :
684 $channel = $this->magpie->channel;
685 else :
686 $channel = array();
687 endif;
688
689 if (isset($channel['ttl'])) :
690 // "ttl stands for time to live. It's a number of
691 // minutes that indicates how long a channel can be
692 // cached before refreshing from the source."
693 // <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>
694 $xml = 'rss:ttl';
695 $ret = $channel['ttl'];
696 elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
697 $period_minutes = array (
698 'hourly' => 60, /* minutes in an hour */
699 'daily' => 1440, /* minutes in a day */
700 'weekly' => 10080, /* minutes in a week */
701 'monthly' => 43200, /* minutes in a month */
702 'yearly' => 525600, /* minutes in a year */
703 );
704
705 // "sy:updatePeriod: Describes the period over which the
706 // channel format is updated. Acceptable values are:
707 // hourly, daily, weekly, monthly, yearly. If omitted,
708 // daily is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
709 if (isset($channel['sy']['updateperiod'])) : $period = $channel['sy']['updateperiod'];
710 else : $period = 'daily';
711 endif;
712
713 // "sy:updateFrequency: Used to describe the frequency
714 // of updates in relation to the update period. A
715 // positive integer indicates how many times in that
716 // period the channel is updated. ... If omitted a value
717 // of 1 is assumed." <http://web.resource.org/rss/1.0/modules/syndication/>
718 if (isset($channel['sy']['updatefrequency'])) : $freq = (int) $channel['sy']['updatefrequency'];
719 else : $freq = 1;
720 endif;
721
722 $xml = 'sy:updateFrequency';
723 $ret = (int) ($period_minutes[$period] / $freq);
724 else :
725 $xml = NULL;
726 $ret = NULL;
727 endif;
728
729 if ('yes'==$this->setting('update/minimum', 'update_minimum', 'no')) :
730 $min = (int) $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
731
732 if ($min > $ret) :
733 $ret = NULL;
734 endif;
735 endif;
736 return ($return_element ? array($ret, $xml) : $ret);
737 } /* SyndicatedLink::ttl() */
738
739 function automatic_ttl () {
740 // spread out over a time interval for staggered updates
741 $updateWindow = $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
742 if (!is_numeric($updateWindow) or ($updateWindow < 1)) :
743 $updateWindow = DEFAULT_UPDATE_PERIOD;
744 endif;
745
746 // We get a fudge of 1/3 of window from elsewhere. We'll do some more
747 // fudging here.
748 $fudgedInterval = $updateWindow+rand(-($updateWindow/6), 5*($updateWindow/12));
749 return apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this);
750 } /* SyndicatedLink::automatic_ttl () */
751
752 // SyndicatedLink::flatten_array (): flatten an array. Useful for
753 // hierarchical and namespaced elements.
754 //
755 // Given an array which may contain array or object elements in it,
756 // return a "flattened" array: a one-dimensional array of scalars
757 // containing each of the scalar elements contained within the array
758 // structure. Thus, for example, if $a['b']['c']['d'] == 'e', then the
759 // returned array for FeedWordPress::flatten_array($a) will contain a key
760 // $a['feed/b/c/d'] with value 'e'.
761 function flatten_array ($arr, $prefix = 'feed/', $separator = '/') {
762 $ret = array ();
763 if (is_array($arr)) :
764 foreach ($arr as $key => $value) :
765 if (is_scalar($value)) :
766 $ret[$prefix.$key] = $value;
767 else :
768 $ret = array_merge($ret, $this->flatten_array($value, $prefix.$key.$separator, $separator));
769 endif;
770 endforeach;
771 endif;
772 return $ret;
773 } /* SyndicatedLink::flatten_array () */
774
775 function hardcode ($what) {
776 $default = get_option("feedwordpress_hardcode_$what");
777 if ( $default === 'yes' ) :
778 // If the default is to hardcode, then we want the
779 // negation of negative(): TRUE by default and FALSE if
780 // the setting is explicitly "no"
781 $ret = !FeedWordPress::negative($this->settings, "hardcode $what");
782 else :
783 // If the default is NOT to hardcode, then we want
784 // affirmative(): FALSE by default and TRUE if the
785 // setting is explicitly "yes"
786 $ret = FeedWordPress::affirmative($this->settings, "hardcode $what");
787 endif;
788 return $ret;
789 } /* SyndicatedLink::hardcode () */
790
791 function syndicated_status ($what, $default, $fallback = true) {
792 global $wpdb;
793
794 // Use local setting if we have it
795 if ( isset($this->settings["$what status"]) ) :
796 $ret = $this->settings["$what status"];
797
798 // Or fall back to global default if we can
799 elseif ($fallback) :
800 $ret = FeedWordPress::syndicated_status($what, $default);
801
802 // Or use default value if we can't.
803 else :
804 $ret = $default;
805
806 endif;
807
808 return $wpdb->escape(trim(strtolower($ret)));
809 } /* SyndicatedLink:syndicated_status () */
810
811 function taxonomies () {
812 $post_type = $this->setting('syndicated post type', 'syndicated_post_type', 'post');
813 return get_object_taxonomies(array('object_type' => $post_type), 'names');
814 } /* SyndicatedLink::taxonomies () */
815
816 } // class SyndicatedLink
817
818