WordPress 3.4
[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         $default_feed = apply_filters('default_feed', 'rss2');
67         return 'rss' == $default_feed ? 'rss2' : $default_feed;
68 }
69
70 /**
71  * Retrieve the blog title for the feed title.
72  *
73  * @package WordPress
74  * @subpackage Feed
75  * @since 2.2.0
76  * @uses apply_filters() Calls 'get_wp_title_rss' hook on title.
77  * @uses wp_title() See function for $sep parameter usage.
78  *
79  * @param string $sep Optional.How to separate the title. See wp_title() for more info.
80  * @return string Error message on failure or blog title on success.
81  */
82 function get_wp_title_rss($sep = '&#187;') {
83         $title = wp_title($sep, false);
84         if ( is_wp_error( $title ) )
85                 return $title->get_error_message();
86         $title = apply_filters('get_wp_title_rss', $title);
87         return $title;
88 }
89
90 /**
91  * Display the blog title for display of the feed title.
92  *
93  * @package WordPress
94  * @subpackage Feed
95  * @since 2.2.0
96  * @uses apply_filters() Calls 'wp_title_rss' on the blog title.
97  * @see wp_title() $sep parameter usage.
98  *
99  * @param string $sep Optional.
100  */
101 function wp_title_rss($sep = '&#187;') {
102         echo apply_filters('wp_title_rss', get_wp_title_rss($sep));
103 }
104
105 /**
106  * Retrieve the current post title for the feed.
107  *
108  * @package WordPress
109  * @subpackage Feed
110  * @since 2.0.0
111  * @uses apply_filters() Calls 'the_title_rss' on the post title.
112  *
113  * @return string Current post title.
114  */
115 function get_the_title_rss() {
116         $title = get_the_title();
117         $title = apply_filters('the_title_rss', $title);
118         return $title;
119 }
120
121 /**
122  * Display the post title in the feed.
123  *
124  * @package WordPress
125  * @subpackage Feed
126  * @since 0.71
127  * @uses get_the_title_rss() Used to retrieve current post title.
128  */
129 function the_title_rss() {
130         echo get_the_title_rss();
131 }
132
133 /**
134  * Retrieve the post content for feeds.
135  *
136  * @package WordPress
137  * @subpackage Feed
138  * @since 2.9.0
139  * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
140  * @see get_the_content()
141  *
142  * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
143  */
144 function get_the_content_feed($feed_type = null) {
145         if ( !$feed_type )
146                 $feed_type = get_default_feed();
147
148         $content = apply_filters('the_content', get_the_content());
149         $content = str_replace(']]>', ']]&gt;', $content);
150         return apply_filters('the_content_feed', $content, $feed_type);
151 }
152
153 /**
154  * Display the post content for feeds.
155  *
156  * @package WordPress
157  * @subpackage Feed
158  * @since 2.9.0
159  * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
160  * @see get_the_content()
161  *
162  * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
163  */
164 function the_content_feed($feed_type = null) {
165         echo get_the_content_feed($feed_type);
166 }
167
168 /**
169  * Display the post excerpt for the feed.
170  *
171  * @package WordPress
172  * @subpackage Feed
173  * @since 0.71
174  * @uses apply_filters() Calls 'the_excerpt_rss' hook on the excerpt.
175  */
176 function the_excerpt_rss() {
177         $output = get_the_excerpt();
178         echo apply_filters('the_excerpt_rss', $output);
179 }
180
181 /**
182  * Display the permalink to the post for use in feeds.
183  *
184  * @package WordPress
185  * @subpackage Feed
186  * @since 2.3.0
187  * @uses apply_filters() Call 'the_permalink_rss' on the post permalink
188  */
189 function the_permalink_rss() {
190         echo esc_url( apply_filters('the_permalink_rss', get_permalink() ));
191 }
192
193 /**
194  * Outputs the link to the comments for the current post in an xml safe way
195  *
196  * @since 3.0.0
197  * @return none
198  */
199 function comments_link_feed() {
200         echo esc_url( get_comments_link() );
201 }
202
203 /**
204  * Display the feed GUID for the current comment.
205  *
206  * @package WordPress
207  * @subpackage Feed
208  * @since 2.5.0
209  *
210  * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
211  */
212 function comment_guid($comment_id = null) {
213         echo esc_url( get_comment_guid($comment_id) );
214 }
215
216 /**
217  * Retrieve the feed GUID for the current comment.
218  *
219  * @package WordPress
220  * @subpackage Feed
221  * @since 2.5.0
222  *
223  * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
224  * @return bool|string false on failure or guid for comment on success.
225  */
226 function get_comment_guid($comment_id = null) {
227         $comment = get_comment($comment_id);
228
229         if ( !is_object($comment) )
230                 return false;
231
232         return get_the_guid($comment->comment_post_ID) . '#comment-' . $comment->comment_ID;
233 }
234
235 /**
236  * Display the link to the comments.
237  *
238  * @since 1.5.0
239  */
240 function comment_link() {
241         echo esc_url( get_comment_link() );
242 }
243
244 /**
245  * Retrieve the current comment author for use in the feeds.
246  *
247  * @package WordPress
248  * @subpackage Feed
249  * @since 2.0.0
250  * @uses apply_filters() Calls 'comment_author_rss' hook on comment author.
251  * @uses get_comment_author()
252  *
253  * @return string Comment Author
254  */
255 function get_comment_author_rss() {
256         return apply_filters('comment_author_rss', get_comment_author() );
257 }
258
259 /**
260  * Display the current comment author in the feed.
261  *
262  * @package WordPress
263  * @subpackage Feed
264  * @since 1.0.0
265  */
266 function comment_author_rss() {
267         echo get_comment_author_rss();
268 }
269
270 /**
271  * Display the current comment content for use in the feeds.
272  *
273  * @package WordPress
274  * @subpackage Feed
275  * @since 1.0.0
276  * @uses apply_filters() Calls 'comment_text_rss' filter on comment content.
277  * @uses get_comment_text()
278  */
279 function comment_text_rss() {
280         $comment_text = get_comment_text();
281         $comment_text = apply_filters('comment_text_rss', $comment_text);
282         echo $comment_text;
283 }
284
285 /**
286  * Retrieve all of the post categories, formatted for use in feeds.
287  *
288  * All of the categories for the current post in the feed loop, will be
289  * retrieved and have feed markup added, so that they can easily be added to the
290  * RSS2, Atom, or RSS1 and RSS0.91 RDF feeds.
291  *
292  * @package WordPress
293  * @subpackage Feed
294  * @since 2.1.0
295  * @uses apply_filters()
296  *
297  * @param string $type Optional, default is the type returned by get_default_feed().
298  * @return string All of the post categories for displaying in the feed.
299  */
300 function get_the_category_rss($type = null) {
301         if ( empty($type) )
302                 $type = get_default_feed();
303         $categories = get_the_category();
304         $tags = get_the_tags();
305         $the_list = '';
306         $cat_names = array();
307
308         $filter = 'rss';
309         if ( 'atom' == $type )
310                 $filter = 'raw';
311
312         if ( !empty($categories) ) foreach ( (array) $categories as $category ) {
313                 $cat_names[] = sanitize_term_field('name', $category->name, $category->term_id, 'category', $filter);
314         }
315
316         if ( !empty($tags) ) foreach ( (array) $tags as $tag ) {
317                 $cat_names[] = sanitize_term_field('name', $tag->name, $tag->term_id, 'post_tag', $filter);
318         }
319
320         $cat_names = array_unique($cat_names);
321
322         foreach ( $cat_names as $cat_name ) {
323                 if ( 'rdf' == $type )
324                         $the_list .= "\t\t<dc:subject><![CDATA[$cat_name]]></dc:subject>\n";
325                 elseif ( 'atom' == $type )
326                         $the_list .= sprintf( '<category scheme="%1$s" term="%2$s" />', esc_attr( apply_filters( 'get_bloginfo_rss', get_bloginfo( 'url' ) ) ), esc_attr( $cat_name ) );
327                 else
328                         $the_list .= "\t\t<category><![CDATA[" . @html_entity_decode( $cat_name, ENT_COMPAT, get_option('blog_charset') ) . "]]></category>\n";
329         }
330
331         return apply_filters('the_category_rss', $the_list, $type);
332 }
333
334 /**
335  * Display the post categories in the feed.
336  *
337  * @package WordPress
338  * @subpackage Feed
339  * @since 0.71
340  * @see get_the_category_rss() For better explanation.
341  *
342  * @param string $type Optional, default is the type returned by get_default_feed().
343  */
344 function the_category_rss($type = null) {
345         echo get_the_category_rss($type);
346 }
347
348 /**
349  * Display the HTML type based on the blog setting.
350  *
351  * The two possible values are either 'xhtml' or 'html'.
352  *
353  * @package WordPress
354  * @subpackage Feed
355  * @since 2.2.0
356  */
357 function html_type_rss() {
358         $type = get_bloginfo('html_type');
359         if (strpos($type, 'xhtml') !== false)
360                 $type = 'xhtml';
361         else
362                 $type = 'html';
363         echo $type;
364 }
365
366 /**
367  * Display the rss enclosure for the current post.
368  *
369  * Uses the global $post to check whether the post requires a password and if
370  * the user has the password for the post. If not then it will return before
371  * displaying.
372  *
373  * Also uses the function get_post_custom() to get the post's 'enclosure'
374  * metadata field and parses the value to display the enclosure(s). The
375  * enclosure(s) consist of enclosure HTML tag(s) with a URI and other
376  * attributes.
377  *
378  * @package WordPress
379  * @subpackage Template
380  * @since 1.5.0
381  * @uses apply_filters() Calls 'rss_enclosure' hook on rss enclosure.
382  * @uses get_post_custom() To get the current post enclosure metadata.
383  */
384 function rss_enclosure() {
385         if ( post_password_required() )
386                 return;
387
388         foreach ( (array) get_post_custom() as $key => $val) {
389                 if ($key == 'enclosure') {
390                         foreach ( (array) $val as $enc ) {
391                                 $enclosure = explode("\n", $enc);
392
393                                 //only get the the first element eg, audio/mpeg from 'audio/mpeg mpga mp2 mp3'
394                                 $t = preg_split('/[ \t]/', trim($enclosure[2]) );
395                                 $type = $t[0];
396
397                                 echo apply_filters('rss_enclosure', '<enclosure url="' . trim(htmlspecialchars($enclosure[0])) . '" length="' . trim($enclosure[1]) . '" type="' . $type . '" />' . "\n");
398                         }
399                 }
400         }
401 }
402
403 /**
404  * Display the atom enclosure for the current post.
405  *
406  * Uses the global $post to check whether the post requires a password and if
407  * the user has the password for the post. If not then it will return before
408  * displaying.
409  *
410  * Also uses the function get_post_custom() to get the post's 'enclosure'
411  * metadata field and parses the value to display the enclosure(s). The
412  * enclosure(s) consist of link HTML tag(s) with a URI and other attributes.
413  *
414  * @package WordPress
415  * @subpackage Template
416  * @since 2.2.0
417  * @uses apply_filters() Calls 'atom_enclosure' hook on atom enclosure.
418  * @uses get_post_custom() To get the current post enclosure metadata.
419  */
420 function atom_enclosure() {
421         if ( post_password_required() )
422                 return;
423
424         foreach ( (array) get_post_custom() as $key => $val ) {
425                 if ($key == 'enclosure') {
426                         foreach ( (array) $val as $enc ) {
427                                 $enclosure = explode("\n", $enc);
428                                 echo apply_filters('atom_enclosure', '<link href="' . trim(htmlspecialchars($enclosure[0])) . '" rel="enclosure" length="' . trim($enclosure[1]) . '" type="' . trim($enclosure[2]) . '" />' . "\n");
429                         }
430                 }
431         }
432 }
433
434 /**
435  * Determine the type of a string of data with the data formatted.
436  *
437  * Tell whether the type is text, html, or xhtml, per RFC 4287 section 3.1.
438  *
439  * In the case of WordPress, text is defined as containing no markup,
440  * xhtml is defined as "well formed", and html as tag soup (i.e., the rest).
441  *
442  * Container div tags are added to xhtml values, per section 3.1.1.3.
443  *
444  * @link http://www.atomenabled.org/developers/syndication/atom-format-spec.php#rfc.section.3.1
445  *
446  * @package WordPress
447  * @subpackage Feed
448  * @since 2.5
449  *
450  * @param string $data Input string
451  * @return array array(type, value)
452  */
453 function prep_atom_text_construct($data) {
454         if (strpos($data, '<') === false && strpos($data, '&') === false) {
455                 return array('text', $data);
456         }
457
458         $parser = xml_parser_create();
459         xml_parse($parser, '<div>' . $data . '</div>', true);
460         $code = xml_get_error_code($parser);
461         xml_parser_free($parser);
462
463         if (!$code) {
464                 if (strpos($data, '<') === false) {
465                         return array('text', $data);
466                 } else {
467                         $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
468                         return array('xhtml', $data);
469                 }
470         }
471
472         if (strpos($data, ']]>') == false) {
473                 return array('html', "<![CDATA[$data]]>");
474         } else {
475                 return array('html', htmlspecialchars($data));
476         }
477 }
478
479 /**
480  * Display the link for the currently displayed feed in a XSS safe way.
481  *
482  * Generate a correct link for the atom:self element.
483  *
484  * @package WordPress
485  * @subpackage Feed
486  * @since 2.5
487  */
488 function self_link() {
489         $host = @parse_url(home_url());
490         $host = $host['host'];
491         echo esc_url(
492                 ( is_ssl() ? 'https' : 'http' ) . '://'
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 }