Wordpress 3.0.1
[autoinstalls/wordpress.git] / wp-includes / feed.php
1 <?php
2 /**
3  * WordPress Feed API
4  *
5  * Many of the functions used in here belong in The Loop, or The Loop for the
6  * Feeds.
7  *
8  * @package WordPress
9  * @subpackage Feed
10  */
11
12 /**
13  * RSS container for the bloginfo function.
14  *
15  * You can retrieve anything that you can using the get_bloginfo() function.
16  * Everything will be stripped of tags and characters converted, when the values
17  * are retrieved for use in the feeds.
18  *
19  * @package WordPress
20  * @subpackage Feed
21  * @since 1.5.1
22  * @uses apply_filters() Calls 'get_bloginfo_rss' hook with two parameters.
23  * @see get_bloginfo() For the list of possible values to display.
24  *
25  * @param string $show See get_bloginfo() for possible values.
26  * @return string
27  */
28 function get_bloginfo_rss($show = '') {
29         $info = strip_tags(get_bloginfo($show));
30         return apply_filters('get_bloginfo_rss', convert_chars($info), $show);
31 }
32
33 /**
34  * Display RSS container for the bloginfo function.
35  *
36  * You can retrieve anything that you can using the get_bloginfo() function.
37  * Everything will be stripped of tags and characters converted, when the values
38  * are retrieved for use in the feeds.
39  *
40  * @package WordPress
41  * @subpackage Feed
42  * @since 0.71
43  * @uses apply_filters() Calls 'bloginfo_rss' hook with two parameters.
44  * @see get_bloginfo() For the list of possible values to display.
45  *
46  * @param string $show See get_bloginfo() for possible values.
47  */
48 function bloginfo_rss($show = '') {
49         echo apply_filters('bloginfo_rss', get_bloginfo_rss($show), $show);
50 }
51
52 /**
53  * Retrieve the default feed.
54  *
55  * The default feed is 'rss2', unless a plugin changes it through the
56  * 'default_feed' filter.
57  *
58  * @package WordPress
59  * @subpackage Feed
60  * @since 2.5
61  * @uses apply_filters() Calls 'default_feed' hook on the default feed string.
62  *
63  * @return string Default feed, or for example 'rss2', 'atom', etc.
64  */
65 function get_default_feed() {
66         return apply_filters('default_feed', 'rss2');
67 }
68
69 /**
70  * Retrieve the blog title for the feed title.
71  *
72  * @package WordPress
73  * @subpackage Feed
74  * @since 2.2.0
75  * @uses apply_filters() Calls 'get_wp_title_rss' hook on title.
76  * @uses wp_title() See function for $sep parameter usage.
77  *
78  * @param string $sep Optional.How to separate the title. See wp_title() for more info.
79  * @return string Error message on failure or blog title on success.
80  */
81 function get_wp_title_rss($sep = '&#187;') {
82         $title = wp_title($sep, false);
83         if ( is_wp_error( $title ) )
84                 return $title->get_error_message();
85         $title = apply_filters('get_wp_title_rss', $title);
86         return $title;
87 }
88
89 /**
90  * Display the blog title for display of the feed title.
91  *
92  * @package WordPress
93  * @subpackage Feed
94  * @since 2.2.0
95  * @uses apply_filters() Calls 'wp_title_rss' on the blog title.
96  * @see wp_title() $sep parameter usage.
97  *
98  * @param string $sep Optional.
99  */
100 function wp_title_rss($sep = '&#187;') {
101         echo apply_filters('wp_title_rss', get_wp_title_rss($sep));
102 }
103
104 /**
105  * Retrieve the current post title for the feed.
106  *
107  * @package WordPress
108  * @subpackage Feed
109  * @since 2.0.0
110  * @uses apply_filters() Calls 'the_title_rss' on the post title.
111  *
112  * @return string Current post title.
113  */
114 function get_the_title_rss() {
115         $title = get_the_title();
116         $title = apply_filters('the_title_rss', $title);
117         return $title;
118 }
119
120 /**
121  * Display the post title in the feed.
122  *
123  * @package WordPress
124  * @subpackage Feed
125  * @since 0.71
126  * @uses get_the_title_rss() Used to retrieve current post title.
127  */
128 function the_title_rss() {
129         echo get_the_title_rss();
130 }
131
132 /**
133  * Retrieve the post content for feeds.
134  *
135  * @package WordPress
136  * @subpackage Feed
137  * @since 2.9.0
138  * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
139  * @see get_the_content()
140  *
141  * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
142  */
143 function get_the_content_feed($feed_type = null) {
144         if ( !$feed_type )
145                 $feed_type = get_default_feed();
146
147         $content = apply_filters('the_content', get_the_content());
148         $content = str_replace(']]>', ']]&gt;', $content);
149         return apply_filters('the_content_feed', $content, $feed_type);
150 }
151
152 /**
153  * Display the post content for feeds.
154  *
155  * @package WordPress
156  * @subpackage Feed
157  * @since 2.9.0
158  * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
159  * @see get_the_content()
160  *
161  * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
162  */
163 function the_content_feed($feed_type = null) {
164         echo get_the_content_feed();
165 }
166
167 /**
168  * Display the post excerpt for the feed.
169  *
170  * @package WordPress
171  * @subpackage Feed
172  * @since 0.71
173  * @uses apply_filters() Calls 'the_excerpt_rss' hook on the excerpt.
174  */
175 function the_excerpt_rss() {
176         $output = get_the_excerpt();
177         echo apply_filters('the_excerpt_rss', $output);
178 }
179
180 /**
181  * Display the permalink to the post for use in feeds.
182  *
183  * @package WordPress
184  * @subpackage Feed
185  * @since 2.3.0
186  * @uses apply_filters() Call 'the_permalink_rss' on the post permalink
187  */
188 function the_permalink_rss() {
189         echo esc_url( apply_filters('the_permalink_rss', get_permalink() ));
190 }
191
192 /**
193  * Outputs the link to the comments for the current post in an xml safe way
194  *
195  * @since 3.0.0
196  * @return none
197  */
198 function comments_link_feed() {
199         echo esc_url( get_comments_link() );
200 }
201
202 /**
203  * Display the feed GUID for the current comment.
204  *
205  * @package WordPress
206  * @subpackage Feed
207  * @since unknown
208  *
209  * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
210  */
211 function comment_guid($comment_id = null) {
212         echo esc_url( get_comment_guid($comment_id) );
213 }
214
215 /**
216  * Retrieve the feed GUID for the current comment.
217  *
218  * @package WordPress
219  * @subpackage Feed
220  * @since unknown
221  *
222  * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
223  * @return bool|string false on failure or guid for comment on success.
224  */
225 function get_comment_guid($comment_id = null) {
226         $comment = get_comment($comment_id);
227
228         if ( !is_object($comment) )
229                 return false;
230
231         return get_the_guid($comment->comment_post_ID) . '#comment-' . $comment->comment_ID;
232 }
233
234 /**
235  * Display the link to the comments.
236  *
237  * @since 1.5.0
238  */
239 function comment_link() {
240         echo esc_url( get_comment_link() );
241 }
242
243 /**
244  * Retrieve the current comment author for use in the feeds.
245  *
246  * @package WordPress
247  * @subpackage Feed
248  * @since 2.0.0
249  * @uses apply_filters() Calls 'comment_author_rss' hook on comment author.
250  * @uses get_comment_author()
251  *
252  * @return string Comment Author
253  */
254 function get_comment_author_rss() {
255         return apply_filters('comment_author_rss', get_comment_author() );
256 }
257
258 /**
259  * Display the current comment author in the feed.
260  *
261  * @package WordPress
262  * @subpackage Feed
263  * @since 1.0.0
264  */
265 function comment_author_rss() {
266         echo get_comment_author_rss();
267 }
268
269 /**
270  * Display the current comment content for use in the feeds.
271  *
272  * @package WordPress
273  * @subpackage Feed
274  * @since 1.0.0
275  * @uses apply_filters() Calls 'comment_text_rss' filter on comment content.
276  * @uses get_comment_text()
277  */
278 function comment_text_rss() {
279         $comment_text = get_comment_text();
280         $comment_text = apply_filters('comment_text_rss', $comment_text);
281         echo $comment_text;
282 }
283
284 /**
285  * Retrieve all of the post categories, formatted for use in feeds.
286  *
287  * All of the categories for the current post in the feed loop, will be
288  * retrieved and have feed markup added, so that they can easily be added to the
289  * RSS2, Atom, or RSS1 and RSS0.91 RDF feeds.
290  *
291  * @package WordPress
292  * @subpackage Feed
293  * @since 2.1.0
294  * @uses apply_filters()
295  *
296  * @param string $type Optional, default is the type returned by get_default_feed().
297  * @return string All of the post categories for displaying in the feed.
298  */
299 function get_the_category_rss($type = null) {
300         if ( empty($type) )
301                 $type = get_default_feed();
302         $categories = get_the_category();
303         $tags = get_the_tags();
304         $the_list = '';
305         $cat_names = array();
306
307         $filter = 'rss';
308         if ( 'atom' == $type )
309                 $filter = 'raw';
310
311         if ( !empty($categories) ) foreach ( (array) $categories as $category ) {
312                 $cat_names[] = sanitize_term_field('name', $category->name, $category->term_id, 'category', $filter);
313         }
314
315         if ( !empty($tags) ) foreach ( (array) $tags as $tag ) {
316                 $cat_names[] = sanitize_term_field('name', $tag->name, $tag->term_id, 'post_tag', $filter);
317         }
318
319         $cat_names = array_unique($cat_names);
320
321         foreach ( $cat_names as $cat_name ) {
322                 if ( 'rdf' == $type )
323                         $the_list .= "\t\t<dc:subject><![CDATA[$cat_name]]></dc:subject>\n";
324                 elseif ( 'atom' == $type )
325                         $the_list .= sprintf( '<category scheme="%1$s" term="%2$s" />', esc_attr( apply_filters( 'get_bloginfo_rss', get_bloginfo( 'url' ) ) ), esc_attr( $cat_name ) );
326                 else
327                         $the_list .= "\t\t<category><![CDATA[" . @html_entity_decode( $cat_name, ENT_COMPAT, get_option('blog_charset') ) . "]]></category>\n";
328         }
329
330         return apply_filters('the_category_rss', $the_list, $type);
331 }
332
333 /**
334  * Display the post categories in the feed.
335  *
336  * @package WordPress
337  * @subpackage Feed
338  * @since 0.71
339  * @see get_the_category_rss() For better explanation.
340  *
341  * @param string $type Optional, default is the type returned by get_default_feed().
342  */
343 function the_category_rss($type = null) {
344         echo get_the_category_rss($type);
345 }
346
347 /**
348  * Display the HTML type based on the blog setting.
349  *
350  * The two possible values are either 'xhtml' or 'html'.
351  *
352  * @package WordPress
353  * @subpackage Feed
354  * @since 2.2.0
355  */
356 function html_type_rss() {
357         $type = get_bloginfo('html_type');
358         if (strpos($type, 'xhtml') !== false)
359                 $type = 'xhtml';
360         else
361                 $type = 'html';
362         echo $type;
363 }
364
365 /**
366  * Display the rss enclosure for the current post.
367  *
368  * Uses the global $post to check whether the post requires a password and if
369  * the user has the password for the post. If not then it will return before
370  * displaying.
371  *
372  * Also uses the function get_post_custom() to get the post's 'enclosure'
373  * metadata field and parses the value to display the enclosure(s). The
374  * enclosure(s) consist of enclosure HTML tag(s) with a URI and other
375  * attributes.
376  *
377  * @package WordPress
378  * @subpackage Template
379  * @since 1.5.0
380  * @uses apply_filters() Calls 'rss_enclosure' hook on rss enclosure.
381  * @uses get_post_custom() To get the current post enclosure metadata.
382  */
383 function rss_enclosure() {
384         if ( post_password_required() )
385                 return;
386
387         foreach ( (array) get_post_custom() as $key => $val) {
388                 if ($key == 'enclosure') {
389                         foreach ( (array) $val as $enc ) {
390                                 $enclosure = explode("\n", $enc);
391
392                                 //only get the the first element eg, audio/mpeg from 'audio/mpeg mpga mp2 mp3'
393                                 $t = preg_split('/[ \t]/', trim($enclosure[2]) );
394                                 $type = $t[0];
395
396                                 echo apply_filters('rss_enclosure', '<enclosure url="' . trim(htmlspecialchars($enclosure[0])) . '" length="' . trim($enclosure[1]) . '" type="' . $type . '" />' . "\n");
397                         }
398                 }
399         }
400 }
401
402 /**
403  * Display the atom enclosure for the current post.
404  *
405  * Uses the global $post to check whether the post requires a password and if
406  * the user has the password for the post. If not then it will return before
407  * displaying.
408  *
409  * Also uses the function get_post_custom() to get the post's 'enclosure'
410  * metadata field and parses the value to display the enclosure(s). The
411  * enclosure(s) consist of link HTML tag(s) with a URI and other attributes.
412  *
413  * @package WordPress
414  * @subpackage Template
415  * @since 2.2.0
416  * @uses apply_filters() Calls 'atom_enclosure' hook on atom enclosure.
417  * @uses get_post_custom() To get the current post enclosure metadata.
418  */
419 function atom_enclosure() {
420         if ( post_password_required() )
421                 return;
422
423         foreach ( (array) get_post_custom() as $key => $val ) {
424                 if ($key == 'enclosure') {
425                         foreach ( (array) $val as $enc ) {
426                                 $enclosure = split("\n", $enc);
427                                 echo apply_filters('atom_enclosure', '<link href="' . trim(htmlspecialchars($enclosure[0])) . '" rel="enclosure" length="' . trim($enclosure[1]) . '" type="' . trim($enclosure[2]) . '" />' . "\n");
428                         }
429                 }
430         }
431 }
432
433 /**
434  * Determine the type of a string of data with the data formatted.
435  *
436  * Tell whether the type is text, html, or xhtml, per RFC 4287 section 3.1.
437  *
438  * In the case of WordPress, text is defined as containing no markup,
439  * xhtml is defined as "well formed", and html as tag soup (i.e., the rest).
440  *
441  * Container div tags are added to xhtml values, per section 3.1.1.3.
442  *
443  * @link http://www.atomenabled.org/developers/syndication/atom-format-spec.php#rfc.section.3.1
444  *
445  * @package WordPress
446  * @subpackage Feed
447  * @since 2.5
448  *
449  * @param string $data Input string
450  * @return array array(type, value)
451  */
452 function prep_atom_text_construct($data) {
453         if (strpos($data, '<') === false && strpos($data, '&') === false) {
454                 return array('text', $data);
455         }
456
457         $parser = xml_parser_create();
458         xml_parse($parser, '<div>' . $data . '</div>', true);
459         $code = xml_get_error_code($parser);
460         xml_parser_free($parser);
461
462         if (!$code) {
463                 if (strpos($data, '<') === false) {
464                         return array('text', $data);
465                 } else {
466                         $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
467                         return array('xhtml', $data);
468                 }
469         }
470
471         if (strpos($data, ']]>') == false) {
472                 return array('html', "<![CDATA[$data]]>");
473         } else {
474                 return array('html', htmlspecialchars($data));
475         }
476 }
477
478 /**
479  * Display the link for the currently displayed feed in a XSS safe way.
480  *
481  * Generate a correct link for the atom:self element.
482  *
483  * @package WordPress
484  * @subpackage Feed
485  * @since 2.5
486  */
487 function self_link() {
488         $host = @parse_url(home_url());
489         $host = $host['host'];
490         echo esc_url(
491                 'http'
492                 . ( (isset($_SERVER['https']) && $_SERVER['https'] == 'on') ? 's' : '' ) . '://'
493                 . $host
494                 . stripslashes($_SERVER['REQUEST_URI'])
495                 );
496 }
497
498 /**
499  * Return the content type for specified feed type.
500  *
501  * @package WordPress
502  * @subpackage Feed
503  * @since 2.8.0
504  */
505 function feed_content_type( $type = '' ) {
506         if ( empty($type) )
507                 $type = get_default_feed();
508
509         $types = array(
510                 'rss'  => 'application/rss+xml',
511                 'rss2' => 'application/rss+xml',
512                 'rss-http'  => 'text/xml',
513                 'atom' => 'application/atom+xml',
514                 'rdf'  => 'application/rdf+xml'
515         );
516
517         $content_type = ( !empty($types[$type]) ) ? $types[$type] : 'application/octet-stream';
518
519         return apply_filters( 'feed_content_type', $content_type, $type );
520 }
521
522 /**
523  * Build SimplePie object based on RSS or Atom feed from URL.
524  *
525  * @since 2.8
526  *
527  * @param string $url URL to retrieve feed
528  * @return WP_Error|SimplePie WP_Error object on failure or SimplePie object on success
529  */
530 function fetch_feed($url) {
531         require_once (ABSPATH . WPINC . '/class-feed.php');
532
533         $feed = new SimplePie();
534         $feed->set_feed_url($url);
535         $feed->set_cache_class('WP_Feed_Cache');
536         $feed->set_file_class('WP_SimplePie_File');
537         $feed->set_cache_duration(apply_filters('wp_feed_cache_transient_lifetime', 43200, $url));
538         do_action_ref_array( 'wp_feed_options', array( &$feed, $url ) );
539         $feed->init();
540         $feed->handle_content_type();
541
542         if ( $feed->error() )
543                 return new WP_Error('simplepie-error', $feed->error());
544
545         return $feed;
546 }