Wordpress 2.5.1
[autoinstalls/wordpress.git] / wp-includes / post.php
1 <?php
2 /**
3  * Post functions and post utility function
4  *
5  * @package WordPress
6  * @subpackage Post
7  * @since 1.5
8  */
9
10 /**
11  * get_attached_file() - Get metadata for an attached file
12  *
13  * {@internal Missing Long Description}}
14  *
15  * @package WordPress
16  * @subpackage Post
17  * @since 2.0
18  *
19  * @param int $attachment_id Attachment ID
20  * @param bool $unfiltered Whether to apply filters or not
21  * @return array {@internal Missing Description}}
22  */
23 function get_attached_file( $attachment_id, $unfiltered = false ) {
24         $file = get_post_meta( $attachment_id, '_wp_attached_file', true );
25         if ( $unfiltered )
26                 return $file;
27         return apply_filters( 'get_attached_file', $file, $attachment_id );
28 }
29
30 /**
31  * update_attached_file() - Update attached file metadata
32  *
33  * {@internal Missing Long Description}}
34  *
35  * @package WordPress
36  * @subpackage Post
37  * @since 2.1
38  *
39  * @param int $attachment_id Attachment ID
40  * @param string $file {@internal Missing Description}}
41  * @return bool|mixed {@internal Missing Description}}
42  */
43 function update_attached_file( $attachment_id, $file ) {
44         if ( !get_post( $attachment_id ) )
45                 return false;
46
47         $old_file = get_attached_file( $attachment_id, true );
48
49         $file = apply_filters( 'update_attached_file', $file, $attachment_id );
50
51         if ( $old_file )
52                 return update_post_meta( $attachment_id, '_wp_attached_file', $file, $old_file );
53         else
54                 return add_post_meta( $attachment_id, '_wp_attached_file', $file );
55 }
56
57 /**
58  * get_children() - Get post children
59  *
60  * {@internal Missing Long Description}}
61  *
62  * @package WordPress
63  * @subpackage Post
64  * @since 2.0
65  *
66  * @param mixed $args {@internal Missing Description}}
67  * @param string $output {@internal Missing Description}}
68  * @return mixed {@internal Missing Description}}
69  */
70 function &get_children($args = '', $output = OBJECT) {
71         if ( empty( $args ) ) {
72                 if ( isset( $GLOBALS['post'] ) ) {
73                         $args = 'post_parent=' . (int) $GLOBALS['post']->post_parent;
74                 } else {
75                         return false;
76                 }
77         } elseif ( is_object( $args ) ) {
78                 $args = 'post_parent=' . (int) $args->post_parent;
79         } elseif ( is_numeric( $args ) ) {
80                 $args = 'post_parent=' . (int) $args;
81         }
82
83         $defaults = array(
84                 'numberposts' => -1, 'post_type' => '',
85                 'post_status' => '', 'post_parent' => 0
86         );
87
88         $r = wp_parse_args( $args, $defaults );
89
90         $children = get_posts( $r );
91
92         if ( !$children )
93                 return false;
94
95         update_post_cache($children);
96
97         foreach ( $children as $key => $child )
98                 $kids[$child->ID] =& $children[$key];
99
100         if ( $output == OBJECT ) {
101                 return $kids;
102         } elseif ( $output == ARRAY_A ) {
103                 foreach ( $kids as $kid )
104                         $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
105                 return $weeuns;
106         } elseif ( $output == ARRAY_N ) {
107                 foreach ( $kids as $kid )
108                         $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
109                 return $babes;
110         } else {
111                 return $kids;
112         }
113 }
114
115 /**
116  * get_extended() - get extended entry info (<!--more-->)
117  *
118  * {@internal Missing Long Description}}
119  *
120  * @package WordPress
121  * @subpackage Post
122  * @since 1.0.1
123  *
124  * @param string $post {@internal Missing Description}}
125  * @return array {@internal Missing Description}}
126  */
127 function get_extended($post) {
128         //Match the new style more links
129         if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
130                 list($main, $extended) = explode($matches[0], $post, 2);
131         } else {
132                 $main = $post;
133                 $extended = '';
134         }
135
136         // Strip leading and trailing whitespace
137         $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
138         $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
139
140         return array('main' => $main, 'extended' => $extended);
141 }
142
143 /**
144  * get_post() - Retrieves post data given a post ID or post object.
145  *
146  * {@internal Missing Long Description}}
147  *
148  * @package WordPress
149  * @subpackage Post
150  * @since 1.5.1
151  * @uses $wpdb
152  *
153  * @param int|object &$post post ID or post object
154  * @param string $output {@internal Missing Description}}
155  * @param string $filter {@internal Missing Description}}
156  * @return mixed {@internal Missing Description}}
157  */
158 function &get_post(&$post, $output = OBJECT, $filter = 'raw') {
159         global $wpdb;
160         $null = null;
161
162         if ( empty($post) ) {
163                 if ( isset($GLOBALS['post']) )
164                         $_post = & $GLOBALS['post'];
165                 else
166                         return $null;
167         } elseif ( is_object($post) ) {
168                 _get_post_ancestors($post);
169                 wp_cache_add($post->ID, $post, 'posts');
170                 $_post = &$post;
171         } else {
172                 $post = (int) $post;
173                 if ( ! $_post = wp_cache_get($post, 'posts') ) {
174                         $_post = & $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post));
175                         _get_post_ancestors($_post);
176                         wp_cache_add($_post->ID, $_post, 'posts');
177                 }
178         }
179
180         $_post = sanitize_post($_post, $filter);
181
182         if ( $output == OBJECT ) {
183                 return $_post;
184         } elseif ( $output == ARRAY_A ) {
185                 $__post = get_object_vars($_post);
186                 return $__post;
187         } elseif ( $output == ARRAY_N ) {
188                 $__post = array_values(get_object_vars($_post));
189                 return $__post;
190         } else {
191                 return $_post;
192         }
193 }
194
195 /**
196  * get_post_ancestors() - Retrieve ancestors for a post
197  *
198  * @package WordPress
199  * @subpackage Post
200  * @since 2.5
201  *
202  * @param string $field {@internal Missing Description}}
203  * @param int|object &$post post ID or post object
204  * @return array of ancestor IDs
205  */
206 function get_post_ancestors($post) {
207         $post = get_post();
208
209         if ( !empty($post->ancestors) )
210                 return $post->ancestors;
211
212         return array();
213 }
214
215 /**
216  * get_post_field() - Retrieve a field based on a post ID.
217  *
218  * @package WordPress
219  * @subpackage Post
220  * @since 2.3
221  *
222  * @param string $field {@internal Missing Description}}
223  * @param id $post Post ID
224  * @param string $context Optional. How to filter the field
225  * @return WP_Error|string Value in post field or WP_Error on failure
226  */
227 function get_post_field( $field, $post, $context = 'display' ) {
228         $post = (int) $post;
229         $post = get_post( $post );
230
231         if ( is_wp_error($post) )
232                 return $post;
233
234         if ( !is_object($post) )
235                 return '';
236
237         if ( !isset($post->$field) )
238                 return '';
239
240         return sanitize_post_field($field, $post->$field, $post->ID, $context);
241 }
242
243 /**
244  * get_post_mime_type() - Takes a post ID, returns its mime type.
245  *
246  * @package WordPress
247  * @subpackage Post
248  * @since 2.0
249  *
250  * @param int $ID Post ID
251  * @return bool|string False on failure or returns the mime type
252  */
253 function get_post_mime_type($ID = '') {
254         $post = & get_post($ID);
255
256         if ( is_object($post) )
257                 return $post->post_mime_type;
258
259         return false;
260 }
261
262 /**
263  * get_post_status() - Takes a post ID and returns its status
264  *
265  * {@internal Missing Long Description}}
266  *
267  * @package WordPress
268  * @subpackage Post
269  * @since 2.0
270  *
271  * @param int $ID {@internal Missing Description}}
272  * @return string|bool post status or false
273  */
274 function get_post_status($ID = '') {
275         $post = get_post($ID);
276
277         if ( is_object($post) ) {
278                 if ( ('attachment' == $post->post_type) && $post->post_parent && ($post->ID != $post->post_parent) )
279                         return get_post_status($post->post_parent);
280                 else
281                         return $post->post_status;
282         }
283
284         return false;
285 }
286
287 /**
288  * get_post_statuses( ) - Retuns the possible user post status values
289  *
290  * Posts have a limited set of valid status values, this provides the
291  * post_status values and descriptions.
292  *
293  * @package WordPress
294  * @subpackage Post
295  * @since 2.5
296  *
297  * @return array
298  */
299 function get_post_statuses( ) {
300         $status = array(
301                 'draft'                 => __('Draft'),
302                 'pending'               => __('Pending Review'),
303                 'private'               => __('Private'),
304                 'publish'               => __('Published')
305         );
306
307         return $status;
308 }
309
310 /**
311  * get_page_statuses( ) - Retuns the possible user page status values
312  *
313  * Pages have a limited set of valid status values, this provides the
314  * post_status values and descriptions.
315  *
316  * @package WordPress
317  * @subpackage Page
318  * @since 2.5
319  *
320  * @return array
321  */
322 function get_page_statuses( ) {
323         $status = array(
324                 'draft'                 => __('Draft'),
325                 'private'               => __('Private'),
326                 'publish'               => __('Published')
327         );
328
329         return $status;
330 }
331
332 /**
333  * get_post_type() - Returns post type
334  *
335  * {@internal Missing Long Description}}
336  *
337  * @package WordPress
338  * @subpackage Post
339  * @since 2.1
340  *
341  * @uses $wpdb
342  * @uses $posts {@internal Missing Description}}
343  *
344  * @param mixed $post post object or post ID
345  * @return mixed post type or false
346  */
347 function get_post_type($post = false) {
348         global $posts;
349
350         if ( false === $post )
351                 $post = $posts[0];
352         elseif ( (int) $post )
353                 $post = get_post($post, OBJECT);
354
355         if ( is_object($post) )
356                 return $post->post_type;
357
358         return false;
359 }
360
361 /**
362  * set_post_type() - Set post type
363  *
364  * {@internal Missing Long Description}}
365  *
366  * @package WordPress
367  * @subpackage Post
368  * @since 2.5
369  *
370  * @uses $wpdb
371  * @uses $posts {@internal Missing Description}}
372  *
373  * @param mixed $post_id post ID
374  * @param mixed post type
375  * @return bool {@internal Missing Description}}
376  */
377 function set_post_type( $post_id = 0, $post_type = 'post' ) {
378         global $wpdb;
379
380         $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
381         $return = $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_type = %s WHERE ID = %d", $post_type, $post_id) );
382
383         if ( 'page' == $post_type )
384                 clean_page_cache($post_id);
385         else
386                 clean_post_cache($post_id);
387
388         return $return;
389 }
390
391 /**
392  * get_posts() - Returns a number of posts
393  *
394  * {@internal Missing Long Description}}
395  *
396  * @package WordPress
397  * @subpackage Post
398  * @since 1.2
399  * @uses $wpdb
400  *
401  * @param array $args {@internal Missing Description}}
402  * @return array {@internal Missing Description}}
403  */
404 function get_posts($args = null) {
405         global $wpdb;
406
407         $defaults = array(
408                 'numberposts' => 5, 'offset' => 0,
409                 'category' => 0, 'orderby' => 'post_date',
410                 'order' => 'DESC', 'include' => '',
411                 'exclude' => '', 'meta_key' => '',
412                 'meta_value' =>'', 'post_type' => 'post',
413                 'post_status' => 'publish', 'post_parent' => 0
414         );
415
416         $r = wp_parse_args( $args, $defaults );
417         extract( $r, EXTR_SKIP );
418
419         $numberposts = (int) $numberposts;
420         $offset = (int) $offset;
421         $category = (int) $category;
422         $post_parent = (int) $post_parent;
423
424         $inclusions = '';
425         if ( !empty($include) ) {
426                 $offset = 0;    //ignore offset, category, exclude, meta_key, and meta_value, post_parent if using include
427                 $category = 0;
428                 $exclude = '';
429                 $meta_key = '';
430                 $meta_value = '';
431                 $post_parent = 0;
432                 $incposts = preg_split('/[\s,]+/',$include);
433                 $numberposts = count($incposts);  // only the number of posts included
434                 if ( count($incposts) ) {
435                         foreach ( $incposts as $incpost ) {
436                                 if (empty($inclusions))
437                                         $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpost);
438                                 else
439                                         $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpost);
440                         }
441                 }
442         }
443         if (!empty($inclusions))
444                 $inclusions .= ')';
445
446         $exclusions = '';
447         if ( !empty($exclude) ) {
448                 $exposts = preg_split('/[\s,]+/',$exclude);
449                 if ( count($exposts) ) {
450                         foreach ( $exposts as $expost ) {
451                                 if (empty($exclusions))
452                                         $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expost);
453                                 else
454                                         $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expost);
455                         }
456                 }
457         }
458         if (!empty($exclusions))
459                 $exclusions .= ')';
460
461         // orderby
462         if ( preg_match( '/.+ +(ASC|DESC)/i', $orderby ) )
463                 $order = ''; // orderby has its own order, so we'll use that
464
465         $query  = "SELECT DISTINCT * FROM $wpdb->posts ";
466         $query .= empty( $category ) ? '' : ", $wpdb->term_relationships, $wpdb->term_taxonomy  ";
467         $query .= empty( $meta_key ) ? '' : ", $wpdb->postmeta ";
468         $query .= " WHERE 1=1 ";
469         $query .= empty( $post_type ) ? '' : $wpdb->prepare("AND post_type = %s ", $post_type);
470         $query .= empty( $post_status ) ? '' : $wpdb->prepare("AND post_status = %s ", $post_status);
471         $query .= "$exclusions $inclusions " ;
472         $query .= empty( $category ) ? '' : $wpdb->prepare("AND ($wpdb->posts.ID = $wpdb->term_relationships.object_id AND $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id AND $wpdb->term_taxonomy.term_id = %d AND $wpdb->term_taxonomy.taxonomy = 'category')", $category);
473         $query .= empty( $post_parent ) ? '' : $wpdb->prepare("AND $wpdb->posts.post_parent = %d ", $post_parent);
474         // expected_slashed ($meta_key, $meta_value) -- Also, this looks really funky, doesn't seem like it works
475         $query .= empty( $meta_key ) | empty($meta_value)  ? '' : " AND ($wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '$meta_key' AND $wpdb->postmeta.meta_value = '$meta_value' )";
476         $query .= empty( $post_mime_type ) ? '' : wp_post_mime_type_where($post_mime_type);
477         $query .= " GROUP BY $wpdb->posts.ID ORDER BY " . $orderby . ' ' . $order;
478         if ( 0 < $numberposts )
479                 $query .= $wpdb->prepare(" LIMIT %d,%d", $offset, $numberposts);
480
481         $posts = $wpdb->get_results($query);
482
483         update_post_caches($posts);
484
485         return $posts;
486 }
487
488 //
489 // Post meta functions
490 //
491
492 /**
493  * add_post_meta() - adds metadata for post
494  *
495  * {@internal Missing Long Description}}
496  *
497  * @package WordPress
498  * @subpackage Post
499  * @since 1.5
500  * @uses $wpdb
501  *
502  * @param int $post_id post ID
503  * @param string $key {@internal Missing Description}}
504  * @param mixed $value {@internal Missing Description}}
505  * @param bool $unique whether to check for a value with the same key
506  * @return bool {@internal Missing Description}}
507  */
508 function add_post_meta($post_id, $meta_key, $meta_value, $unique = false) {
509         global $wpdb;
510
511         // expected_slashed ($meta_key)
512         $meta_key = stripslashes($meta_key);
513
514         if ( $unique && $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) )
515                 return false;
516
517         $meta_value = maybe_serialize($meta_value);
518
519         $wpdb->insert( $wpdb->postmeta, compact( 'post_id', 'meta_key', 'meta_value' ) );
520
521         wp_cache_delete($post_id, 'post_meta');
522
523         return true;
524 }
525
526 /**
527  * delete_post_meta() - delete post metadata
528  *
529  * {@internal Missing Long Description}}
530  *
531  * @package WordPress
532  * @subpackage Post
533  * @since 1.5
534  * @uses $wpdb
535  *
536  * @param int $post_id post ID
537  * @param string $key {@internal Missing Description}}
538  * @param mixed $value {@internal Missing Description}}
539  * @return bool {@internal Missing Description}}
540  */
541 function delete_post_meta($post_id, $key, $value = '') {
542         global $wpdb;
543
544         $post_id = absint( $post_id );
545
546         // expected_slashed ($key, $value)
547         $key = stripslashes( $key );
548         $value = stripslashes( $value );
549
550         if ( empty( $value ) )
551                 $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $key ) );
552         else
553                 $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $key, $value ) );
554
555         if ( !$meta_id )
556                 return false;
557
558         if ( empty( $value ) )
559                 $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $key ) );
560         else
561                 $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $key, $value ) );
562
563         wp_cache_delete($post_id, 'post_meta');
564
565         return true;
566 }
567
568 /**
569  * get_post_meta() - Get a post meta field
570  *
571  * {@internal Missing Long Description}}
572  *
573  * @package WordPress
574  * @subpackage Post
575  * @since 1.5
576  * @uses $wpdb
577  *
578  * @param int $post_id post ID
579  * @param string $key The meta key to retrieve
580  * @param bool $single Whether to return a single value
581  * @return mixed {@internal Missing Description}}
582  */
583 function get_post_meta($post_id, $key, $single = false) {
584         $post_id = (int) $post_id;
585
586         $meta_cache = wp_cache_get($post_id, 'post_meta');
587
588         if ( isset($meta_cache[$key]) ) {
589                 if ( $single ) {
590                         return maybe_unserialize( $meta_cache[$key][0] );
591                 } else {
592                         return maybe_unserialize( $meta_cache[$key] );
593                 }
594         }
595
596         if ( !$meta_cache ) {
597                 update_postmeta_cache($post_id);
598                 $meta_cache = wp_cache_get($post_id, 'post_meta');
599         }
600
601         if ( $single ) {
602                 if ( isset($meta_cache[$key][0]) )
603                         return maybe_unserialize($meta_cache[$key][0]);
604                 else
605                         return '';
606         } else {
607                 return maybe_unserialize($meta_cache[$key]);
608         }
609 }
610
611 /**
612  * update_post_meta() - Update a post meta field
613  *
614  * {@internal Missing Long Description}}
615  *
616  * @package WordPress
617  * @subpackage Post
618  * @since 1.5
619  * @uses $wpdb
620  *
621  * @param int $post_id post ID
622  * @param string $key {@internal Missing Description}}
623  * @param mixed $value {@internal Missing Description}}
624  * @param mixed $prev_value previous value (for differentiating between meta fields with the same key and post ID)
625  * @return bool {@internal Missing Description}}
626  */
627 function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') {
628         global $wpdb;
629
630         $meta_value = maybe_serialize($meta_value);
631         $prev_value = maybe_serialize($prev_value);
632
633         // expected_slashed ($meta_key)
634         $meta_key = stripslashes($meta_key);
635
636         if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) )
637                 return false;
638
639         $data  = compact( 'meta_value' );
640         $where = compact( 'meta_key', 'post_id' );
641
642         if ( !empty( $prev_value ) )
643                 $where['meta_value'] = $prev_value;
644
645         $wpdb->update( $wpdb->postmeta, $data, $where );
646         wp_cache_delete($post_id, 'post_meta');
647         return true;
648 }
649
650 /**
651  * delete_post_meta_by_key() - Delete everything from post meta matching $post_meta_key
652  *
653  * @package WordPress
654  * @subpackage Post
655  * @since 2.3
656  * @uses $wpdb
657  *
658  * @param string $post_meta_key What to search for when deleting
659  * @return bool Whether the post meta key was deleted from the database
660  */
661 function delete_post_meta_by_key($post_meta_key) {
662         global $wpdb;
663         if ( $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_key = %s", $post_meta_key)) ) {
664                 /** @todo Get post_ids and delete cache */
665                 // wp_cache_delete($post_id, 'post_meta');
666                 return true;
667         }
668         return false;
669 }
670
671 /**
672  * get_post_custom() - Retrieve post custom fields
673  *
674  * {@internal Missing Long Description}}
675  *
676  * @package WordPress
677  * @subpackage Post
678  * @since 1.2
679  *
680  * @uses $id
681  * @uses $wpdb
682  *
683  * @param int $post_id post ID
684  * @return array {@internal Missing Description}}
685  */
686 function get_post_custom($post_id = 0) {
687         global $id;
688
689         if ( !$post_id )
690                 $post_id = (int) $id;
691
692         $post_id = (int) $post_id;
693
694         if ( ! wp_cache_get($post_id, 'post_meta') )
695                 update_postmeta_cache($post_id);
696
697         return wp_cache_get($post_id, 'post_meta');
698 }
699
700 /**
701  * get_post_custom_keys() - Retrieve post custom field names
702  *
703  * @package WordPress
704  * @subpackage Post
705  * @since 1.2
706  *
707  * @param int $post_id post ID
708  * @return array|null Either array of the keys, or null if keys would not be retrieved
709  */
710 function get_post_custom_keys( $post_id = 0 ) {
711         $custom = get_post_custom( $post_id );
712
713         if ( !is_array($custom) )
714                 return;
715
716         if ( $keys = array_keys($custom) )
717                 return $keys;
718 }
719
720
721 function get_post_custom_values( $key = '', $post_id = 0 ) {
722         $custom = get_post_custom($post_id);
723
724         return $custom[$key];
725 }
726
727 function sanitize_post($post, $context = 'display') {
728         if ( 'raw' == $context )
729                 return $post;
730         if ( is_object($post) ) {
731                 foreach ( array_keys(get_object_vars($post)) as $field )
732                         $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
733         } else {
734                 foreach ( array_keys($post) as $field )
735                         $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
736         }
737         return $post;
738 }
739
740 /**
741  * sanitize_post_field() - Sanitize post field based on context
742  *
743  * {@internal Missing Long Description}}
744  *
745  * @package WordPress
746  * @subpackage Post
747  * @since 2.3
748  *
749  * @param string $field The Post Object field name
750  * @param string $value The Post Object value
751  * @param int $postid Post ID
752  * @param string $context How to sanitize post fields
753  * @return string Sanitized value
754  */
755 function sanitize_post_field($field, $value, $post_id, $context) {
756         $int_fields = array('ID', 'post_parent', 'menu_order');
757         if ( in_array($field, $int_fields) )
758                 $value = (int) $value;
759
760         if ( 'raw' == $context )
761                 return $value;
762
763         $prefixed = false;
764         if ( false !== strpos($field, 'post_') ) {
765                 $prefixed = true;
766                 $field_no_prefix = str_replace('post_', '', $field);
767         }
768
769         if ( 'edit' == $context ) {
770                 $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
771
772                 if ( $prefixed ) {
773                         $value = apply_filters("edit_$field", $value, $post_id);
774                         // Old school
775                         $value = apply_filters("${field_no_prefix}_edit_pre", $value, $post_id);
776                 } else {
777                         $value = apply_filters("edit_post_$field", $value, $post_id);
778                 }
779
780                 if ( in_array($field, $format_to_edit) ) {
781                         if ( 'post_content' == $field )
782                                 $value = format_to_edit($value, user_can_richedit());
783                         else
784                                 $value = format_to_edit($value);
785                 } else {
786                         $value = attribute_escape($value);
787                 }
788         } else if ( 'db' == $context ) {
789                 if ( $prefixed ) {
790                         $value = apply_filters("pre_$field", $value);
791                         $value = apply_filters("${field_no_prefix}_save_pre", $value);
792                 } else {
793                         $value = apply_filters("pre_post_$field", $value);
794                         $value = apply_filters("${field}_pre", $value);
795                 }
796         } else {
797                 // Use display filters by default.
798                 if ( $prefixed )
799                         $value = apply_filters($field, $value, $post_id, $context);
800                 else
801                         $value = apply_filters("post_$field", $value, $post_id, $context);
802         }
803
804         if ( 'attribute' == $context )
805                 $value = attribute_escape($value);
806         else if ( 'js' == $context )
807                 $value = js_escape($value);
808
809         return $value;
810 }
811
812 /**
813  * wp_count_posts() - Count number of posts with a given type
814  *
815  * {@internal Missing Long Description}}
816  *
817  * @package WordPress
818  * @subpackage Post
819  * @since 2.5
820  *
821  * @param string $type Post type
822  * @return array Number of posts for each status
823  */
824 function wp_count_posts( $type = 'post', $perm = '' ) {
825         global $wpdb;
826
827         $user = wp_get_current_user();
828
829         $cache_key = $type;
830
831         $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
832         if ( 'readable' == $perm && is_user_logged_in() ) {
833                 if ( !current_user_can("read_private_{$type}s") ) {
834                         $cache_key .= '_' . $perm . '_' . $user->ID;
835                         $query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
836                 }
837         }
838         $query .= ' GROUP BY post_status';
839
840         $count = wp_cache_get($cache_key, 'counts');
841         if ( false !== $count )
842                 return $count;
843
844         $count = $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
845
846         $stats = array( );
847         foreach( (array) $count as $row_num => $row ) {
848                 $stats[$row['post_status']] = $row['num_posts'];
849         }
850
851         $stats = (object) $stats;
852         wp_cache_set($cache_key, $stats, 'counts');
853
854         return $stats;
855 }
856
857
858 /**
859  * wp_count_attachments() - Count number of attachments
860  *
861  * {@internal Missing Long Description}}
862  *
863  * @package WordPress
864  * @subpackage Post
865  * @since 2.5
866  *
867  * @param string|array $post_mime_type Array or comma-separated list of MIME patterns
868  * @return array Number of posts for each post_mime_type
869  */
870
871 function wp_count_attachments( $mime_type = '' ) {
872         global $wpdb;
873
874         $and = wp_post_mime_type_where( $mime_type );
875         $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' $and GROUP BY post_mime_type", ARRAY_A );
876
877         $stats = array( );
878         foreach( (array) $count as $row ) {
879                 $stats[$row['post_mime_type']] = $row['num_posts'];
880         }
881
882         return (object) $stats;
883 }
884
885 /**
886  * wp_match_mime_type() - Check a MIME-Type against a list
887  *
888  * {@internal Missing Long Description}}
889  *
890  * @package WordPress
891  * @subpackage Post
892  * @since 2.5
893  *
894  * @param string|array $wildcard_mime_types e.g. audio/mpeg or image (same as image/*) or flash (same as *flash*)
895  * @param string|array $real_mime_types post_mime_type values
896  * @return array array(wildcard=>array(real types))
897  */
898 function wp_match_mime_types($wildcard_mime_types, $real_mime_types) {
899         $matches = array();
900         if ( is_string($wildcard_mime_types) )
901                 $wildcard_mime_types = array_map('trim', explode(',', $wildcard_mime_types));
902         if ( is_string($real_mime_types) )
903                 $real_mime_types = array_map('trim', explode(',', $real_mime_types));
904         $wild = '[-._a-z0-9]*';
905         foreach ( (array) $wildcard_mime_types as $type ) {
906                 $type = str_replace('*', $wild, $type);
907                 $patternses[1][$type] = "^$type$";
908                 if ( false === strpos($type, '/') ) {
909                         $patternses[2][$type] = "^$type/";
910                         $patternses[3][$type] = $type;
911                 }
912         }
913         asort($patternses);
914         foreach ( $patternses as $patterns )
915                 foreach ( $patterns as $type => $pattern )
916                         foreach ( (array) $real_mime_types as $real )
917                                 if ( preg_match("#$pattern#", $real) && ( empty($matches[$type]) || false === array_search($real, $matches[$type]) ) )
918                                         $matches[$type][] = $real;
919         return $matches;
920 }
921
922 /**
923  * wp_get_post_mime_type_where() - Convert MIME types into SQL
924  *
925  * @package WordPress
926  * @subpackage Post
927  * @since 2.5
928  *
929  * @param string|array $mime_types MIME types
930  * @return string SQL AND clause
931  */
932 function wp_post_mime_type_where($post_mime_types) {
933         $where = '';
934         $wildcards = array('', '%', '%/%');
935         if ( is_string($post_mime_types) )
936                 $post_mime_types = array_map('trim', explode(',', $post_mime_types));
937         foreach ( (array) $post_mime_types as $mime_type ) {
938                 $mime_type = preg_replace('/\s/', '', $mime_type);
939                 $slashpos = strpos($mime_type, '/');
940                 if ( false !== $slashpos ) {
941                         $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
942                         $mime_subgroup = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
943                         if ( empty($mime_subgroup) )
944                                 $mime_subgroup = '*';
945                         else
946                                 $mime_subgroup = str_replace('/', '', $mime_subgroup);
947                         $mime_pattern = "$mime_group/$mime_subgroup";
948                 } else {
949                         $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
950                         if ( false === strpos($mime_pattern, '*') )
951                                 $mime_pattern .= '/*';
952                 }
953
954                 $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
955
956                 if ( in_array( $mime_type, $wildcards ) )
957                         return '';
958
959                 if ( false !== strpos($mime_pattern, '%') )
960                         $wheres[] = "post_mime_type LIKE '$mime_pattern'";
961                 else
962                         $wheres[] = "post_mime_type = '$mime_pattern'";
963         }
964         if ( !empty($wheres) )
965                 $where = ' AND (' . join(' OR ', $wheres) . ') ';
966         return $where;
967 }
968
969 /**
970  * wp_delete_post() - Deletes a Post
971  *
972  * {@internal Missing Long Description}}
973  *
974  * @package WordPress
975  * @subpackage Post
976  * @since 1.0.1
977  *
978  * @param int $postid post ID
979  * @return mixed {@internal Missing Description}}
980  */
981 function wp_delete_post($postid = 0) {
982         global $wpdb, $wp_rewrite;
983
984         if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
985                 return $post;
986
987         if ( 'attachment' == $post->post_type )
988                 return wp_delete_attachment($postid);
989
990         do_action('delete_post', $postid);
991
992         /** @todo delete for pluggable post taxonomies too */
993         wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
994
995         $parent_data = array( 'post_parent' => $post->post_parent );
996         $parent_where = array( 'post_parent' => $postid );
997
998         if ( 'page' == $post->post_type) {
999                 // if the page is defined in option page_on_front or post_for_posts,
1000                 // adjust the corresponding options
1001                 if ( get_option('page_on_front') == $postid ) {
1002                         update_option('show_on_front', 'posts');
1003                         delete_option('page_on_front');
1004                 }
1005                 if ( get_option('page_for_posts') == $postid ) {
1006                         delete_option('page_for_posts');
1007                 }
1008
1009                 // Point children of this page to its parent, also clean the cache of affected children
1010                 $children_query = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type='page'", $postid);
1011                 $children = $wpdb->get_results($children_query);
1012
1013                 $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'page' ) );
1014         }
1015
1016         // Point all attachments to this post up one level
1017         $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
1018
1019         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
1020
1021         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
1022
1023         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d", $postid ));
1024
1025         if ( 'page' == $post->post_type ) {
1026                 clean_page_cache($postid);
1027
1028                 foreach ( (array) $children as $child )
1029                         clean_page_cache($child->ID);
1030
1031                 $wp_rewrite->flush_rules();
1032         } else {
1033                 clean_post_cache($postid);
1034         }
1035
1036         do_action('deleted_post', $postid);
1037
1038         return $post;
1039 }
1040
1041 /**
1042  * wp_get_post_categories() - Retrieve the list of categories for a post
1043  *
1044  * Compatibility layer for themes and plugins. Also an easy layer of abstraction
1045  * away from the complexity of the taxonomy layer.
1046  *
1047  * @package WordPress
1048  * @subpackage Post
1049  * @since 2.1
1050  *
1051  * @uses wp_get_object_terms() Retrieves the categories. Args details can be found here
1052  *
1053  * @param int $post_id Optional. The Post ID
1054  * @param array $args Optional. Overwrite the defaults
1055  * @return array {@internal Missing Description}}
1056  */
1057 function wp_get_post_categories( $post_id = 0, $args = array() ) {
1058         $post_id = (int) $post_id;
1059
1060         $defaults = array('fields' => 'ids');
1061         $args = wp_parse_args( $args, $defaults );
1062
1063         $cats = wp_get_object_terms($post_id, 'category', $args);
1064         return $cats;
1065 }
1066
1067 /**
1068  * wp_get_post_tags() - Retrieve the post tags
1069  *
1070  * @package WordPress
1071  * @subpackage Post
1072  * @since 2.3
1073  *
1074  * @uses wp_get_object_terms() Gets the tags for returning. Args can be found here
1075  *
1076  * @param int $post_id Optional. The Post ID
1077  * @param array $args Optional. Overwrite the defaults
1078  * @return mixed The tags the post has currently
1079  */
1080 function wp_get_post_tags( $post_id = 0, $args = array() ) {
1081         $post_id = (int) $post_id;
1082
1083         $defaults = array('fields' => 'all');
1084         $args = wp_parse_args( $args, $defaults );
1085
1086         $tags = wp_get_object_terms($post_id, 'post_tag', $args);
1087
1088         return $tags;
1089 }
1090
1091 /**
1092  * wp_get_recent_posts() - Get the $num most recent posts
1093  *
1094  * {@internal Missing Long Description}}
1095  *
1096  * @package WordPress
1097  * @subpackage Post
1098  * @since 1.0.1
1099  *
1100  * @param int $num number of posts to get
1101  * @return array {@internal Missing Description}}
1102  */
1103 function wp_get_recent_posts($num = 10) {
1104         global $wpdb;
1105
1106         // Set the limit clause, if we got a limit
1107         $num = (int) $num;
1108         if ($num) {
1109                 $limit = "LIMIT $num";
1110         }
1111
1112         $sql = "SELECT * FROM $wpdb->posts WHERE post_type = 'post' ORDER BY post_date DESC $limit";
1113         $result = $wpdb->get_results($sql,ARRAY_A);
1114
1115         return $result?$result:array();
1116 }
1117
1118 /**
1119  * wp_get_single_post() - Get one post
1120  *
1121  * {@internal Missing Long Description}}
1122  *
1123  * @package WordPress
1124  * @subpackage Post
1125  * @since 1.0.1
1126  * @uses $wpdb
1127  *
1128  * @param int $postid post ID
1129  * @param string $mode How to return result, either OBJECT, ARRAY_N, or ARRAY_A
1130  * @return object|array Post object or array holding post contents and information
1131  */
1132 function wp_get_single_post($postid = 0, $mode = OBJECT) {
1133         $postid = (int) $postid;
1134
1135         $post = get_post($postid, $mode);
1136
1137         // Set categories and tags
1138         if($mode == OBJECT) {
1139                 $post->post_category = wp_get_post_categories($postid);
1140                 $post->tags_input = wp_get_post_tags($postid, array('fields' => 'names'));
1141         }
1142         else {
1143                 $post['post_category'] = wp_get_post_categories($postid);
1144                 $post['tags_input'] = wp_get_post_tags($postid, array('fields' => 'names'));
1145         }
1146
1147         return $post;
1148 }
1149
1150 /**
1151  * wp_insert_post() - Insert a post
1152  *
1153  * {@internal Missing Long Description}}
1154  *
1155  * @package WordPress
1156  * @subpackage Post
1157  * @since 1.0.1
1158  *
1159  * @uses $wpdb
1160  * @uses $wp_rewrite
1161  * @uses $user_ID
1162  * @uses $allowedtags
1163  *
1164  * @param array $postarr post contents
1165  * @return int post ID or 0 on error
1166  */
1167 function wp_insert_post($postarr = array()) {
1168         global $wpdb, $wp_rewrite, $user_ID;
1169
1170         $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
1171                 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
1172                 'menu_order' => 0, 'to_ping' =>  '', 'pinged' => '', 'post_password' => '',
1173                 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '');
1174
1175         $postarr = wp_parse_args($postarr, $defaults);
1176         $postarr = sanitize_post($postarr, 'db');
1177
1178         // export array as variables
1179         extract($postarr, EXTR_SKIP);
1180
1181         // Are we updating or creating?
1182         $update = false;
1183         if ( !empty($ID) ) {
1184                 $update = true;
1185                 $previous_status = get_post_field('post_status', $ID);
1186         } else {
1187                 $previous_status = 'new';
1188         }
1189
1190         if ( ('' == $post_content) && ('' == $post_title) && ('' == $post_excerpt) )
1191                 return 0;
1192
1193         // Make sure we set a valid category
1194         if (0 == count($post_category) || !is_array($post_category)) {
1195                 $post_category = array(get_option('default_category'));
1196         }
1197
1198         if ( empty($post_author) )
1199                 $post_author = $user_ID;
1200
1201         if ( empty($post_status) )
1202                 $post_status = 'draft';
1203
1204         if ( empty($post_type) )
1205                 $post_type = 'post';
1206
1207         // Get the post ID and GUID
1208         if ( $update ) {
1209                 $post_ID = (int) $ID;
1210                 $guid = get_post_field( 'guid', $post_ID );
1211         }
1212
1213         // Create a valid post name.  Drafts are allowed to have an empty
1214         // post name.
1215         if ( empty($post_name) ) {
1216                 if ( 'draft' != $post_status )
1217                         $post_name = sanitize_title($post_title);
1218         } else {
1219                 $post_name = sanitize_title($post_name);
1220         }
1221
1222         // If the post date is empty (due to having been new or a draft) and status is not 'draft', set date to now
1223         if (empty($post_date)) {
1224                 if ( !in_array($post_status, array('draft', 'pending')) )
1225                         $post_date = current_time('mysql');
1226                 else
1227                         $post_date = '0000-00-00 00:00:00';
1228         }
1229
1230         if (empty($post_date_gmt)) {
1231                 if ( !in_array($post_status, array('draft', 'pending')) )
1232                         $post_date_gmt = get_gmt_from_date($post_date);
1233                 else
1234                         $post_date_gmt = '0000-00-00 00:00:00';
1235         }
1236
1237         if ( $update || '0000-00-00 00:00:00' == $post_date ) {
1238                 $post_modified     = current_time( 'mysql' );
1239                 $post_modified_gmt = current_time( 'mysql', 1 );
1240         } else {
1241                 $post_modified     = $post_date;
1242                 $post_modified_gmt = $post_date_gmt;
1243         }
1244
1245         if ( 'publish' == $post_status ) {
1246                 $now = gmdate('Y-m-d H:i:59');
1247                 if ( mysql2date('U', $post_date_gmt) > mysql2date('U', $now) )
1248                         $post_status = 'future';
1249         }
1250
1251         if ( empty($comment_status) ) {
1252                 if ( $update )
1253                         $comment_status = 'closed';
1254                 else
1255                         $comment_status = get_option('default_comment_status');
1256         }
1257         if ( empty($ping_status) )
1258                 $ping_status = get_option('default_ping_status');
1259
1260         if ( isset($to_ping) )
1261                 $to_ping = preg_replace('|\s+|', "\n", $to_ping);
1262         else
1263                 $to_ping = '';
1264
1265         if ( ! isset($pinged) )
1266                 $pinged = '';
1267
1268         if ( isset($post_parent) )
1269                 $post_parent = (int) $post_parent;
1270         else
1271                 $post_parent = 0;
1272
1273         if ( isset($menu_order) )
1274                 $menu_order = (int) $menu_order;
1275         else
1276                 $menu_order = 0;
1277
1278         if ( !isset($post_password) )
1279                 $post_password = '';
1280
1281         if ( 'draft' != $post_status ) {
1282                 $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $post_name, $post_type, $post_ID, $post_parent));
1283
1284                 if ($post_name_check || in_array($post_name, $wp_rewrite->feeds) ) {
1285                         $suffix = 2;
1286                         do {
1287                                 $alt_post_name = substr($post_name, 0, 200-(strlen($suffix)+1)). "-$suffix";
1288                                 // expected_slashed ($alt_post_name, $post_name, $post_type)
1289                                 $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = '$alt_post_name' AND post_type = '$post_type' AND ID != %d AND post_parent = %d LIMIT 1", $post_ID, $post_parent));
1290                                 $suffix++;
1291                         } while ($post_name_check);
1292                         $post_name = $alt_post_name;
1293                 }
1294         }
1295
1296         // expected_slashed (everything!)
1297         $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'guid' ) );
1298         $data = stripslashes_deep( $data );
1299         $where = array( 'ID' => $post_ID );
1300
1301         if ($update) {
1302                 do_action( 'pre_post_update', $post_ID );
1303                 $wpdb->update( $wpdb->posts, $data, $where );
1304         } else {
1305                 $data['post_mime_type'] = stripslashes( $post_mime_type ); // This isn't in the update
1306                 $wpdb->insert( $wpdb->posts, $data );
1307                 $post_ID = (int) $wpdb->insert_id;
1308
1309                 // use the newly generated $post_ID
1310                 $where = array( 'ID' => $post_ID );
1311         }
1312
1313         if ( empty($post_name) && 'draft' != $post_status ) {
1314                 $post_name = sanitize_title($post_title, $post_ID);
1315                 $wpdb->update( $wpdb->posts, compact( 'post_name' ), $where );
1316         }
1317
1318         wp_set_post_categories( $post_ID, $post_category );
1319         wp_set_post_tags( $post_ID, $tags_input );
1320
1321         $current_guid = get_post_field( 'guid', $post_ID );
1322
1323         if ( 'page' == $post_type ) {
1324                 clean_page_cache($post_ID);
1325         } else {
1326                 clean_post_cache($post_ID);
1327         }
1328
1329         // Set GUID
1330         if ( !$update && '' == $current_guid )
1331                 $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
1332
1333         $post = get_post($post_ID);
1334         if ( !empty($page_template) )
1335                 $post->page_template = $page_template;
1336
1337         wp_transition_post_status($post_status, $previous_status, $post);
1338
1339         if ( $update)
1340                 do_action('edit_post', $post_ID, $post);
1341
1342         do_action('save_post', $post_ID, $post);
1343         do_action('wp_insert_post', $post_ID, $post);
1344
1345         return $post_ID;
1346 }
1347
1348 /**
1349  * wp_update_post() - Update a post
1350  *
1351  * {@internal Missing Long Description}}
1352  *
1353  * @package WordPress
1354  * @subpackage Post
1355  * @since 1.0.1
1356  * @uses $wpdb
1357  *
1358  * @param array $postarr post data
1359  * @return int {@internal Missing Description}}
1360  */
1361 function wp_update_post($postarr = array()) {
1362         if ( is_object($postarr) )
1363                 $postarr = get_object_vars($postarr);
1364
1365         // First, get all of the original fields
1366         $post = wp_get_single_post($postarr['ID'], ARRAY_A);
1367
1368         // Escape data pulled from DB.
1369         $post = add_magic_quotes($post);
1370
1371         // Passed post category list overwrites existing category list if not empty.
1372         if ( isset($postarr['post_category']) && is_array($postarr['post_category'])
1373                          && 0 != count($postarr['post_category']) )
1374                 $post_cats = $postarr['post_category'];
1375         else
1376                 $post_cats = $post['post_category'];
1377
1378         // Drafts shouldn't be assigned a date unless explicitly done so by the user
1379         if ( in_array($post['post_status'], array('draft', 'pending')) && empty($postarr['edit_date']) && empty($postarr['post_date']) &&
1380                          ('0000-00-00 00:00:00' == $post['post_date']) )
1381                 $clear_date = true;
1382         else
1383                 $clear_date = false;
1384
1385         // Merge old and new fields with new fields overwriting old ones.
1386         $postarr = array_merge($post, $postarr);
1387         $postarr['post_category'] = $post_cats;
1388         if ( $clear_date ) {
1389                 $postarr['post_date'] = '';
1390                 $postarr['post_date_gmt'] = '';
1391         }
1392
1393         if ($postarr['post_type'] == 'attachment')
1394                 return wp_insert_attachment($postarr);
1395
1396         return wp_insert_post($postarr);
1397 }
1398
1399 /**
1400  * wp_publish_post() - Mark a post as "published"
1401  *
1402  * {@internal Missing Long Description}}
1403  *
1404  * @package WordPress
1405  * @subpackage Post
1406  * @since 2.1
1407  * @uses $wpdb
1408  *
1409  * @param int $post_id Post ID
1410  * @return int|null {@internal Missing Description}}
1411  */
1412 function wp_publish_post($post_id) {
1413         global $wpdb;
1414
1415         $post = get_post($post_id);
1416
1417         if ( empty($post) )
1418                 return;
1419
1420         if ( 'publish' == $post->post_status )
1421                 return;
1422
1423         $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post_id ) );
1424
1425         $old_status = $post->post_status;
1426         $post->post_status = 'publish';
1427         wp_transition_post_status('publish', $old_status, $post);
1428
1429         // Update counts for the post's terms.
1430         foreach ( get_object_taxonomies('post') as $taxonomy ) {
1431                 $terms = wp_get_object_terms($post_id, $taxonomy, 'fields=tt_ids');
1432                 wp_update_term_count($terms, $taxonomy);
1433         }
1434
1435         do_action('edit_post', $post_id, $post);
1436         do_action('save_post', $post_id, $post);
1437         do_action('wp_insert_post', $post_id, $post);
1438 }
1439
1440 /**
1441  * check_and_publish_future_post() - check to make sure post has correct status before
1442  * passing it on to be published. Invoked by cron 'publish_future_post' event
1443  * This safeguard prevents cron from publishing drafts, etc.
1444  *
1445  * {@internal Missing Long Description}}
1446  *
1447  * @package WordPress
1448  * @subpackage Post
1449  * @since 2.5
1450  * @uses $wpdb
1451  *
1452  * @param int $post_id Post ID
1453  * @return int|null {@internal Missing Description}}
1454  */
1455 function check_and_publish_future_post($post_id) {
1456
1457         $post = get_post($post_id);
1458
1459         if ( empty($post) )
1460                 return;
1461
1462         if ( 'future' != $post->post_status )
1463                 return;
1464
1465         return wp_publish_post($post_id);
1466 }
1467
1468 function wp_add_post_tags($post_id = 0, $tags = '') {
1469         return wp_set_post_tags($post_id, $tags, true);
1470 }
1471
1472 function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
1473         /* $append - true = don't delete existing tags, just add on, false = replace the tags with the new tags */
1474
1475         $post_id = (int) $post_id;
1476
1477         if ( !$post_id )
1478                 return false;
1479
1480         if ( empty($tags) )
1481                 $tags = array();
1482         $tags = (is_array($tags)) ? $tags : explode( ',', trim($tags, " \n\t\r\0\x0B,") );
1483         wp_set_object_terms($post_id, $tags, 'post_tag', $append);
1484 }
1485
1486 /**
1487  * wp_set_post_categories() - Set categories for a post
1488  *
1489  * {@internal Missing Long Description}}
1490  *
1491  * @package WordPress
1492  * @subpackage Post
1493  * @since 2.1
1494  * @uses $wpdb
1495  *
1496  * @param int $post_ID post ID
1497  * @param array $post_categories
1498  * @return bool|mixed {@internal Missing Description}}
1499  */
1500 function wp_set_post_categories($post_ID = 0, $post_categories = array()) {
1501         $post_ID = (int) $post_ID;
1502         // If $post_categories isn't already an array, make it one:
1503         if (!is_array($post_categories) || 0 == count($post_categories) || empty($post_categories))
1504                 $post_categories = array(get_option('default_category'));
1505         else if ( 1 == count($post_categories) && '' == $post_categories[0] )
1506                 return true;
1507
1508         $post_categories = array_map('intval', $post_categories);
1509         $post_categories = array_unique($post_categories);
1510
1511         return wp_set_object_terms($post_ID, $post_categories, 'category');
1512 }       // wp_set_post_categories()
1513
1514 /**
1515  * wp_transition_post_status() - Change the post transition status
1516  *
1517  * {@internal Missing Long Description}}
1518  *
1519  * @package WordPress
1520  * @subpackage Post
1521  * @since 2.3
1522  *
1523  * @param string $new_status {@internal Missing Description}}
1524  * @param string $old_status {@internal Missing Description}}
1525  * @param int $post {@internal Missing Description}}
1526  */
1527 function wp_transition_post_status($new_status, $old_status, $post) {
1528         if ( $new_status != $old_status ) {
1529                 do_action('transition_post_status', $new_status, $old_status, $post);
1530                 do_action("${old_status}_to_$new_status", $post);
1531         }
1532         do_action("${new_status}_$post->post_type", $post->ID, $post);
1533 }
1534
1535 //
1536 // Trackback and ping functions
1537 //
1538
1539 /**
1540  * add_ping() - Add a URL to those already pung
1541  *
1542  * {@internal Missing Long Description}}
1543  *
1544  * @package WordPress
1545  * @subpackage Post
1546  * @since 1.5
1547  * @uses $wpdb
1548  *
1549  * @param int $post_id post ID
1550  * @param string $uri {@internal Missing Description}}
1551  * @return mixed {@internal Missing Description}}
1552  */
1553 function add_ping($post_id, $uri) {
1554         global $wpdb;
1555         $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
1556         $pung = trim($pung);
1557         $pung = preg_split('/\s/', $pung);
1558         $pung[] = $uri;
1559         $new = implode("\n", $pung);
1560         $new = apply_filters('add_ping', $new);
1561         // expected_slashed ($new)
1562         $new = stripslashes($new);
1563         return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
1564 }
1565
1566 function get_enclosed($post_id) { // Get enclosures already enclosed for a post
1567         $custom_fields = get_post_custom( $post_id );
1568         $pung = array();
1569         if ( !is_array( $custom_fields ) )
1570                 return $pung;
1571
1572         foreach ( $custom_fields as $key => $val ) {
1573                 if ( 'enclosure' != $key || !is_array( $val ) )
1574                         continue;
1575                 foreach( $val as $enc ) {
1576                         $enclosure = split( "\n", $enc );
1577                         $pung[] = trim( $enclosure[ 0 ] );
1578                 }
1579         }
1580         $pung = apply_filters('get_enclosed', $pung);
1581         return $pung;
1582 }
1583
1584 /**
1585  * get_pung() - Get URLs already pinged for a post
1586  *
1587  * {@internal Missing Long Description}}
1588  *
1589  * @package WordPress
1590  * @subpackage Post
1591  * @since 1.5
1592  * @uses $wpdb
1593  *
1594  * @param int $post_id post ID
1595  * @return array {@internal Missing Description}}
1596  */
1597 function get_pung($post_id) {
1598         global $wpdb;
1599         $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
1600         $pung = trim($pung);
1601         $pung = preg_split('/\s/', $pung);
1602         $pung = apply_filters('get_pung', $pung);
1603         return $pung;
1604 }
1605
1606 /**
1607  * get_to_ping() - Get any URLs in the todo list
1608  *
1609  * {@internal Missing Long Description}}
1610  *
1611  * @package WordPress
1612  * @subpackage Post
1613  * @since 1.5
1614  * @uses $wpdb
1615  *
1616  * @param int $post_id post ID
1617  * @return array {@internal Missing Description}}
1618  */
1619 function get_to_ping($post_id) {
1620         global $wpdb;
1621         $to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
1622         $to_ping = trim($to_ping);
1623         $to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
1624         $to_ping = apply_filters('get_to_ping',  $to_ping);
1625         return $to_ping;
1626 }
1627
1628 /**
1629  * trackback_url_list() - Do trackbacks for a list of urls
1630  *
1631  * {@internal Missing Long Description}}
1632  *
1633  * @package WordPress
1634  * @subpackage Post
1635  * @since 1.0.1
1636  *
1637  * @param string $tb_list comma separated list of URLs
1638  * @param int $post_id post ID
1639  */
1640 function trackback_url_list($tb_list, $post_id) {
1641         if (!empty($tb_list)) {
1642                 // get post data
1643                 $postdata = wp_get_single_post($post_id, ARRAY_A);
1644
1645                 // import postdata as variables
1646                 extract($postdata, EXTR_SKIP);
1647
1648                 // form an excerpt
1649                 $excerpt = strip_tags($post_excerpt?$post_excerpt:$post_content);
1650
1651                 if (strlen($excerpt) > 255) {
1652                         $excerpt = substr($excerpt,0,252) . '...';
1653                 }
1654
1655                 $trackback_urls = explode(',', $tb_list);
1656                 foreach($trackback_urls as $tb_url) {
1657                                 $tb_url = trim($tb_url);
1658                                 trackback($tb_url, stripslashes($post_title), $excerpt, $post_id);
1659                 }
1660                 }
1661 }
1662
1663 //
1664 // Page functions
1665 //
1666
1667 /**
1668  * get_all_page_ids() - Get a list of page IDs
1669  *
1670  * {@internal Missing Long Description}}
1671  *
1672  * @package WordPress
1673  * @subpackage Post
1674  * @since 2.0
1675  * @uses $wpdb
1676  *
1677  * @return array {@internal Missing Description}}
1678  */
1679 function get_all_page_ids() {
1680         global $wpdb;
1681
1682         if ( ! $page_ids = wp_cache_get('all_page_ids', 'posts') ) {
1683                 $page_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'page'");
1684                 wp_cache_add('all_page_ids', $page_ids, 'posts');
1685         }
1686
1687         return $page_ids;
1688 }
1689
1690 /**
1691  * get_page() - Retrieves page data given a page ID or page object
1692  *
1693  * {@internal Missing Long Description}}
1694  *
1695  * @package WordPress
1696  * @subpackage Post
1697  * @since 1.5.1
1698  *
1699  * @param mixed &$page page object or page ID
1700  * @param string $output what to output
1701  * @param string $filter How the return value should be filtered.
1702  * @return mixed {@internal Missing Description}}
1703  */
1704 function &get_page(&$page, $output = OBJECT, $filter = 'raw') {
1705         if ( empty($page) ) {
1706                 if ( isset( $GLOBALS['page'] ) && isset( $GLOBALS['page']->ID ) )
1707                         return get_post($GLOBALS['page'], $output, $filter);
1708                 else
1709                         return null;
1710         }
1711
1712         return get_post($page, $output, $filter);
1713 }
1714
1715 /**
1716  * get_page_by_path() - Retrieves a page given its path
1717  *
1718  * {@internal Missing Long Description}}
1719  *
1720  * @package WordPress
1721  * @subpackage Post
1722  * @since 2.1
1723  * @uses $wpdb
1724  *
1725  * @param string $page_path page path
1726  * @param string $output output type
1727  * @return mixed {@internal Missing Description}}
1728  */
1729 function get_page_by_path($page_path, $output = OBJECT) {
1730         global $wpdb;
1731         $page_path = rawurlencode(urldecode($page_path));
1732         $page_path = str_replace('%2F', '/', $page_path);
1733         $page_path = str_replace('%20', ' ', $page_path);
1734         $page_paths = '/' . trim($page_path, '/');
1735         $leaf_path  = sanitize_title(basename($page_paths));
1736         $page_paths = explode('/', $page_paths);
1737         foreach($page_paths as $pathdir)
1738                 $full_path .= ($pathdir!=''?'/':'') . sanitize_title($pathdir);
1739
1740         $pages = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_name = %s AND (post_type = 'page' OR post_type = 'attachment')", $leaf_path ));
1741
1742         if ( empty($pages) )
1743                 return NULL;
1744
1745         foreach ($pages as $page) {
1746                 $path = '/' . $leaf_path;
1747                 $curpage = $page;
1748                 while ($curpage->post_parent != 0) {
1749                         $curpage = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE ID = %d and post_type='page'", $curpage->post_parent ));
1750                         $path = '/' . $curpage->post_name . $path;
1751                 }
1752
1753                 if ( $path == $full_path )
1754                         return get_page($page->ID, $output);
1755         }
1756
1757         return NULL;
1758 }
1759
1760 /**
1761  * get_page_by_title() - Retrieve a page given its title
1762  *
1763  * {@internal Missing Long Description}}
1764  *
1765  * @package WordPress
1766  * @subpackage Post
1767  * @since 2.1
1768  * @uses $wpdb
1769  *
1770  * @param string $page_title page title
1771  * @param string $output output type
1772  * @return mixed {@internal Missing Description}}
1773  */
1774 function get_page_by_title($page_title, $output = OBJECT) {
1775         global $wpdb;
1776         $page = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type='page'", $page_title ));
1777         if ( $page )
1778                 return get_page($page, $output);
1779
1780         return NULL;
1781 }
1782
1783 /**
1784  * get_page_children() - Retrieve child pages
1785  *
1786  * {@internal Missing Long Description}}
1787  *
1788  * @package WordPress
1789  * @subpackage Post
1790  * @since 1.5.1
1791  *
1792  * @param int $page_id page ID
1793  * @param array $pages list of pages
1794  * @return array {@internal Missing Description}}
1795  */
1796 function &get_page_children($page_id, $pages) {
1797         $page_list = array();
1798         foreach ( $pages as $page ) {
1799                 if ( $page->post_parent == $page_id ) {
1800                         $page_list[] = $page;
1801                         if ( $children = get_page_children($page->ID, $pages) )
1802                                 $page_list = array_merge($page_list, $children);
1803                 }
1804         }
1805         return $page_list;
1806 }
1807
1808 /**
1809  * get_page_hierarchy() - {@internal Missing Short Description}}
1810  *
1811  * Fetches the pages returned as a FLAT list, but arranged in order of their hierarchy,
1812  * i.e., child parents immediately follow their parents.
1813  *
1814  * @package WordPress
1815  * @subpackage Post
1816  * @since 2.0
1817  *
1818  * @param array $posts posts array
1819  * @param int $parent parent page ID
1820  * @return array {@internal Missing Description}}
1821  */
1822 function get_page_hierarchy($posts, $parent = 0) {
1823         $result = array ( );
1824         if ($posts) { foreach ($posts as $post) {
1825                 if ($post->post_parent == $parent) {
1826                         $result[$post->ID] = $post->post_name;
1827                         $children = get_page_hierarchy($posts, $post->ID);
1828                         $result += $children; //append $children to $result
1829                 }
1830         } }
1831         return $result;
1832 }
1833
1834 /**
1835  * get_page_uri() - Builds a page URI
1836  *
1837  * {@internal Missing Long Description}}
1838  *
1839  * @package WordPress
1840  * @subpackage Post
1841  * @since 1.5
1842  *
1843  * @param int $page_id page ID
1844  * @return string {@internal Missing Description}}
1845  */
1846 function get_page_uri($page_id) {
1847         $page = get_page($page_id);
1848         $uri = urldecode($page->post_name);
1849
1850         // A page cannot be it's own parent.
1851         if ( $page->post_parent == $page->ID )
1852                 return $uri;
1853
1854         while ($page->post_parent != 0) {
1855                 $page = get_page($page->post_parent);
1856                 $uri = urldecode($page->post_name) . "/" . $uri;
1857         }
1858
1859         return $uri;
1860 }
1861
1862 /**
1863  * get_pages() - Retrieve a list of pages
1864  *
1865  * {@internal Missing Long Description}}
1866  *
1867  * @package WordPress
1868  * @subpackage Post
1869  * @since 1.5
1870  * @uses $wpdb
1871  *
1872  * @param mixed $args Optional. Array or string of options
1873  * @return array List of pages matching defaults or $args
1874  */
1875 function &get_pages($args = '') {
1876         global $wpdb;
1877
1878         $defaults = array(
1879                 'child_of' => 0, 'sort_order' => 'ASC',
1880                 'sort_column' => 'post_title', 'hierarchical' => 1,
1881                 'exclude' => '', 'include' => '',
1882                 'meta_key' => '', 'meta_value' => '',
1883                 'authors' => ''
1884         );
1885
1886         $r = wp_parse_args( $args, $defaults );
1887         extract( $r, EXTR_SKIP );
1888
1889         $key = md5( serialize( $r ) );
1890         if ( $cache = wp_cache_get( 'get_pages', 'posts' ) )
1891                 if ( isset( $cache[ $key ] ) )
1892                         return apply_filters('get_pages', $cache[ $key ], $r );
1893
1894         $inclusions = '';
1895         if ( !empty($include) ) {
1896                 $child_of = 0; //ignore child_of, exclude, meta_key, and meta_value params if using include
1897                 $exclude = '';
1898                 $meta_key = '';
1899                 $meta_value = '';
1900                 $hierarchical = false;
1901                 $incpages = preg_split('/[\s,]+/',$include);
1902                 if ( count($incpages) ) {
1903                         foreach ( $incpages as $incpage ) {
1904                                 if (empty($inclusions))
1905                                         $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpage);
1906                                 else
1907                                         $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpage);
1908                         }
1909                 }
1910         }
1911         if (!empty($inclusions))
1912                 $inclusions .= ')';
1913
1914         $exclusions = '';
1915         if ( !empty($exclude) ) {
1916                 $expages = preg_split('/[\s,]+/',$exclude);
1917                 if ( count($expages) ) {
1918                         foreach ( $expages as $expage ) {
1919                                 if (empty($exclusions))
1920                                         $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expage);
1921                                 else
1922                                         $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expage);
1923                         }
1924                 }
1925         }
1926         if (!empty($exclusions))
1927                 $exclusions .= ')';
1928
1929         $author_query = '';
1930         if (!empty($authors)) {
1931                 $post_authors = preg_split('/[\s,]+/',$authors);
1932
1933                 if ( count($post_authors) ) {
1934                         foreach ( $post_authors as $post_author ) {
1935                                 //Do we have an author id or an author login?
1936                                 if ( 0 == intval($post_author) ) {
1937                                         $post_author = get_userdatabylogin($post_author);
1938                                         if ( empty($post_author) )
1939                                                 continue;
1940                                         if ( empty($post_author->ID) )
1941                                                 continue;
1942                                         $post_author = $post_author->ID;
1943                                 }
1944
1945                                 if ( '' == $author_query )
1946                                         $author_query = $wpdb->prepare(' post_author = %d ', $post_author);
1947                                 else
1948                                         $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author);
1949                         }
1950                         if ( '' != $author_query )
1951                                 $author_query = " AND ($author_query)";
1952                 }
1953         }
1954
1955         $query = "SELECT * FROM $wpdb->posts " ;
1956         $query .= ( empty( $meta_key ) ? "" : ", $wpdb->postmeta " ) ;
1957         $query .= " WHERE (post_type = 'page' AND post_status = 'publish') $exclusions $inclusions " ;
1958         // expected_slashed ($meta_key, $meta_value) -- also, it looks funky
1959         $query .= ( empty( $meta_key ) | empty($meta_value)  ? "" : " AND ($wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '$meta_key' AND $wpdb->postmeta.meta_value = '$meta_value' )" ) ;
1960         $query .= $author_query;
1961         $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
1962
1963         $pages = $wpdb->get_results($query);
1964
1965         if ( empty($pages) )
1966                 return apply_filters('get_pages', array(), $r);
1967
1968         // Update cache.
1969         update_page_cache($pages);
1970
1971         if ( $child_of || $hierarchical )
1972                 $pages = & get_page_children($child_of, $pages);
1973
1974         $cache[ $key ] = $pages;
1975         wp_cache_set( 'get_pages', $cache, 'posts' );
1976
1977         $pages = apply_filters('get_pages', $pages, $r);
1978
1979         return $pages;
1980 }
1981
1982 //
1983 // Attachment functions
1984 //
1985
1986 /**
1987  * is_local_attachment() - Check if the attachment URI is local one and is really an attachment.
1988  *
1989  * {@internal Missing Long Description}}
1990  *
1991  * @package WordPress
1992  * @subpackage Post
1993  * @since 2.0
1994  *
1995  * @param string $url URL to check
1996  * @return bool {@internal Missing Description}}
1997  */
1998 function is_local_attachment($url) {
1999         if (strpos($url, get_bloginfo('url')) === false)
2000                 return false;
2001         if (strpos($url, get_bloginfo('url') . '/?attachment_id=') !== false)
2002                 return true;
2003         if ( $id = url_to_postid($url) ) {
2004                 $post = & get_post($id);
2005                 if ( 'attachment' == $post->post_type )
2006                         return true;
2007         }
2008         return false;
2009 }
2010
2011 /**
2012  * wp_insert_attachment() - Insert an attachment
2013  *
2014  * {@internal Missing Long Description}}
2015  *
2016  * @package WordPress
2017  * @subpackage Post
2018  * @since 2.0
2019  *
2020  * @uses $wpdb
2021  * @uses $user_ID
2022  *
2023  * @param object $object attachment object
2024  * @param string $file filename
2025  * @param int $post_parent parent post ID
2026  * @return int {@internal Missing Description}}
2027  */
2028 function wp_insert_attachment($object, $file = false, $parent = 0) {
2029         global $wpdb, $user_ID;
2030
2031         $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
2032                 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
2033                 'menu_order' => 0, 'to_ping' =>  '', 'pinged' => '', 'post_password' => '',
2034                 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '');
2035
2036         $object = wp_parse_args($object, $defaults);
2037         if ( !empty($parent) )
2038                 $object['post_parent'] = $parent;
2039
2040         $object = sanitize_post($object, 'db');
2041
2042         // export array as variables
2043         extract($object, EXTR_SKIP);
2044
2045         // Make sure we set a valid category
2046         if (0 == count($post_category) || !is_array($post_category)) {
2047                 $post_category = array(get_option('default_category'));
2048         }
2049
2050         if ( empty($post_author) )
2051                 $post_author = $user_ID;
2052
2053         $post_type = 'attachment';
2054         $post_status = 'inherit';
2055
2056         // Are we updating or creating?
2057         $update = false;
2058         if ( !empty($ID) ) {
2059                 $update = true;
2060                 $post_ID = (int) $ID;
2061         }
2062
2063         // Create a valid post name.
2064         if ( empty($post_name) )
2065                 $post_name = sanitize_title($post_title);
2066         else
2067                 $post_name = sanitize_title($post_name);
2068
2069         // expected_slashed ($post_name)
2070         $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = '$post_name' AND post_status = 'inherit' AND ID != %d LIMIT 1", $post_ID));
2071
2072         if ($post_name_check) {
2073                 $suffix = 2;
2074                 while ($post_name_check) {
2075                         $alt_post_name = $post_name . "-$suffix";
2076                         // expected_slashed ($alt_post_name, $post_name)
2077                         $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = '$alt_post_name' AND post_status = 'inherit' AND ID != %d AND post_parent = %d LIMIT 1", $post_ID, $post_parent));
2078                         $suffix++;
2079                 }
2080                 $post_name = $alt_post_name;
2081         }
2082
2083         if ( empty($post_date) )
2084                 $post_date = current_time('mysql');
2085         if ( empty($post_date_gmt) )
2086                 $post_date_gmt = current_time('mysql', 1);
2087
2088         if ( empty($post_modified) )
2089                 $post_modified = $post_date;
2090         if ( empty($post_modified_gmt) )
2091                 $post_modified_gmt = $post_date_gmt;
2092
2093         if ( empty($comment_status) ) {
2094                 if ( $update )
2095                         $comment_status = 'closed';
2096                 else
2097                         $comment_status = get_option('default_comment_status');
2098         }
2099         if ( empty($ping_status) )
2100                 $ping_status = get_option('default_ping_status');
2101
2102         if ( isset($to_ping) )
2103                 $to_ping = preg_replace('|\s+|', "\n", $to_ping);
2104         else
2105                 $to_ping = '';
2106
2107         if ( isset($post_parent) )
2108                 $post_parent = (int) $post_parent;
2109         else
2110                 $post_parent = 0;
2111
2112         if ( isset($menu_order) )
2113                 $menu_order = (int) $menu_order;
2114         else
2115                 $menu_order = 0;
2116
2117         if ( !isset($post_password) )
2118                 $post_password = '';
2119
2120         if ( ! isset($pinged) )
2121                 $pinged = '';
2122
2123         // expected_slashed (everything!)
2124         $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ) );
2125         $data = stripslashes_deep( $data );
2126
2127         if ( $update ) {
2128                 $wpdb->update( $wpdb->posts, $data, array( 'ID' => $post_ID ) );
2129         } else {
2130                 $wpdb->insert( $wpdb->posts, $data );
2131                 $post_ID = (int) $wpdb->insert_id;
2132         }
2133
2134         if ( empty($post_name) ) {
2135                 $post_name = sanitize_title($post_title, $post_ID);
2136                 $wpdb->update( $wpdb->posts, compact("post_name"), array( 'ID' => $post_ID ) );
2137         }
2138
2139         wp_set_post_categories($post_ID, $post_category);
2140
2141         if ( $file )
2142                 update_attached_file( $post_ID, $file );
2143                 
2144         clean_post_cache($post_ID);
2145
2146         if ( $update) {
2147                 do_action('edit_attachment', $post_ID);
2148         } else {
2149                 do_action('add_attachment', $post_ID);
2150         }
2151
2152         return $post_ID;
2153 }
2154
2155 /**
2156  * wp_delete_attachment() - Delete an attachment
2157  *
2158  * {@internal Missing Long Description}}
2159  *
2160  * @package WordPress
2161  * @subpackage Post
2162  * @since 2.0
2163  * @uses $wpdb
2164  *
2165  * @param int $postid attachment Id
2166  * @return mixed {@internal Missing Description}}
2167  */
2168 function wp_delete_attachment($postid) {
2169         global $wpdb;
2170
2171         if ( !$post = $wpdb->get_row(  $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
2172                 return $post;
2173
2174         if ( 'attachment' != $post->post_type )
2175                 return false;
2176
2177         $meta = wp_get_attachment_metadata( $postid );
2178         $file = get_attached_file( $postid );
2179
2180         /** @todo Delete for pluggable post taxonomies too */
2181         wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
2182
2183         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
2184
2185         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
2186
2187         $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
2188
2189         if ( ! empty($meta['thumb']) ) {
2190                 // Don't delete the thumb if another attachment uses it
2191                 if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%'.$meta['thumb'].'%', $postid)) ) {
2192                         $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
2193                         $thumbfile = apply_filters('wp_delete_file', $thumbfile);
2194                         @ unlink($thumbfile);
2195                 }
2196         }
2197
2198         // remove intermediate images if there are any
2199         $sizes = apply_filters('intermediate_image_sizes', array('thumbnail', 'medium'));
2200         foreach ( $sizes as $size ) {
2201                 if ( $intermediate = image_get_intermediate_size($postid, $size) ) {
2202                         $intermediate_file = apply_filters('wp_delete_file', $intermediate['path']);
2203                         @ unlink($intermediate_file);
2204                 }
2205         }
2206
2207         $file = apply_filters('wp_delete_file', $file);
2208
2209         if ( ! empty($file) )
2210                 @ unlink($file);
2211
2212         clean_post_cache($postid);
2213
2214         do_action('delete_attachment', $postid);
2215
2216         return $post;
2217 }
2218
2219 /**
2220  * wp_get_attachment_metadata() - Retrieve metadata for an attachment
2221  *
2222  * {@internal Missing Long Description}}
2223  *
2224  * @package WordPress
2225  * @subpackage Post
2226  * @since 2.1
2227  *
2228  * @param int $post_id attachment ID
2229  * @param bool $unfiltered Optional, default is false. If true, filters are not run
2230  * @return array {@internal Missing Description}}
2231  */
2232 function wp_get_attachment_metadata( $post_id, $unfiltered = false ) {
2233         $post_id = (int) $post_id;
2234         if ( !$post =& get_post( $post_id ) )
2235                 return false;
2236
2237         $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
2238         if ( $unfiltered )
2239                 return $data;
2240         return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
2241 }
2242
2243 /**
2244  * wp_update_attachment_metadata() - Update metadata for an attachment
2245  *
2246  * {@internal Missing Long Description}}
2247  *
2248  * @package WordPress
2249  * @subpackage Post
2250  * @since 2.1
2251  *
2252  * @param int $post_id attachment ID
2253  * @param array $data attachment data
2254  * @return int {@internal Missing Description}}
2255  */
2256 function wp_update_attachment_metadata( $post_id, $data ) {
2257         $post_id = (int) $post_id;
2258         if ( !$post =& get_post( $post_id ) )
2259                 return false;
2260
2261         $old_data = wp_get_attachment_metadata( $post->ID, true );
2262
2263         $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID );
2264
2265         if ( $old_data )
2266                 return update_post_meta( $post->ID, '_wp_attachment_metadata', $data, $old_data );
2267         else
2268                 return add_post_meta( $post->ID, '_wp_attachment_metadata', $data );
2269 }
2270
2271 /**
2272  * wp_get_attachment_url() - Retrieve the URL for an attachment
2273  *
2274  * {@internal Missing Long Description}}
2275  *
2276  * @package WordPress
2277  * @subpackage Post
2278  * @since 2.1
2279  *
2280  * @param int $post_id attachment ID
2281  * @return string {@internal Missing Description}}
2282  */
2283 function wp_get_attachment_url( $post_id = 0 ) {
2284         $post_id = (int) $post_id;
2285         if ( !$post =& get_post( $post_id ) )
2286                 return false;
2287
2288         $url = get_the_guid( $post->ID );
2289
2290         if ( 'attachment' != $post->post_type || !$url )
2291                 return false;
2292
2293         return apply_filters( 'wp_get_attachment_url', $url, $post->ID );
2294 }
2295
2296 /**
2297  * wp_get_attachment_thumb_file() - Retrieve thumbnail for an attachment
2298  *
2299  * {@internal Missing Long Description}}
2300  *
2301  * @package WordPress
2302  * @subpackage Post
2303  * @since 2.1
2304  *
2305  * @param int $post_id attachment ID
2306  * @return mixed {@internal Missing Description}}
2307  */
2308 function wp_get_attachment_thumb_file( $post_id = 0 ) {
2309         $post_id = (int) $post_id;
2310         if ( !$post =& get_post( $post_id ) )
2311                 return false;
2312         if ( !$imagedata = wp_get_attachment_metadata( $post->ID ) )
2313                 return false;
2314
2315         $file = get_attached_file( $post->ID );
2316
2317         if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) )
2318                 return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
2319         return false;
2320 }
2321
2322 /**
2323  * wp_get_attachment_thumb_url() - Retrieve URL for an attachment thumbnail
2324  *
2325  * {@internal Missing Long Description}}
2326  *
2327  * @package WordPress
2328  * @subpackage Post
2329  * @since 2.1
2330  *
2331  * @param int $post_id attachment ID
2332  * @return string {@internal Missing Description}}
2333  */
2334 function wp_get_attachment_thumb_url( $post_id = 0 ) {
2335         $post_id = (int) $post_id;
2336         if ( !$post =& get_post( $post_id ) )
2337                 return false;
2338         if ( !$url = wp_get_attachment_url( $post->ID ) )
2339                 return false;
2340                 
2341         $sized = image_downsize( $post_id, 'thumbnail' );
2342         if ( $sized )
2343                 return $sized[0];
2344
2345         if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
2346                 return false;
2347
2348         $url = str_replace(basename($url), basename($thumb), $url);
2349
2350         return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
2351 }
2352
2353 /**
2354  * wp_attachment_is_image() - Check if the attachment is an image
2355  *
2356  * {@internal Missing Long Description}}
2357  *
2358  * @package WordPress
2359  * @subpackage Post
2360  * @since 2.1
2361  *
2362  * @param int $post_id attachment ID
2363  * @return bool {@internal Missing Description}}
2364  */
2365 function wp_attachment_is_image( $post_id = 0 ) {
2366         $post_id = (int) $post_id;
2367         if ( !$post =& get_post( $post_id ) )
2368                 return false;
2369
2370         if ( !$file = get_attached_file( $post->ID ) )
2371                 return false;
2372
2373         $ext = preg_match('/\.([^.]+)$/', $file, $matches) ? strtolower($matches[1]) : false;
2374
2375         $image_exts = array('jpg', 'jpeg', 'gif', 'png');
2376
2377         if ( 'image/' == substr($post->post_mime_type, 0, 6) || $ext && 'import' == $post->post_mime_type && in_array($ext, $image_exts) )
2378                 return true;
2379         return false;
2380 }
2381
2382 /**
2383  * wp_mime_type_icon() - Retrieve the icon for a MIME type
2384  *
2385  * {@internal Missing Long Description}}
2386  *
2387  * @package WordPress
2388  * @subpackage Post
2389  * @since 2.1
2390  *
2391  * @param string $mime MIME type
2392  * @return string|bool {@internal Missing Description}}
2393  */
2394 function wp_mime_type_icon( $mime = 0 ) {
2395         if ( !is_numeric($mime) )
2396                 $icon = wp_cache_get("mime_type_icon_$mime");
2397         if ( empty($icon) ) {
2398                 $post_id = 0;
2399                 $post_mimes = array();
2400                 if ( is_numeric($mime) ) {
2401                         $mime = (int) $mime;
2402                         if ( $post =& get_post( $mime ) ) {
2403                                 $post_id = (int) $post->ID;
2404                                 $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $post->guid);
2405                                 if ( !empty($ext) ) {
2406                                         $post_mimes[] = $ext;
2407                                         if ( $ext_type = wp_ext2type( $ext ) )
2408                                                 $post_mimes[] = $ext_type;
2409                                 }
2410                                 $mime = $post->post_mime_type;
2411                         } else {
2412                                 $mime = 0;
2413                         }
2414                 } else {
2415                         $post_mimes[] = $mime;
2416                 }
2417
2418                 $icon_files = wp_cache_get('icon_files');
2419
2420                 if ( !is_array($icon_files) ) {
2421                         $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
2422                         $icon_dir_uri = apply_filters( 'icon_dir_uri', trailingslashit(get_option('siteurl')) . WPINC . '/images/crystal' );
2423                         $dirs = apply_filters( 'icon_dirs', array($icon_dir => $icon_dir_uri) );
2424                         $icon_files = array();
2425                         while ( $dirs ) {
2426                                 $dir = array_shift($keys = array_keys($dirs));
2427                                 $uri = array_shift($dirs);
2428                                 if ( $dh = opendir($dir) ) {
2429                                         while ( false !== $file = readdir($dh) ) {
2430                                                 $file = basename($file);
2431                                                 if ( substr($file, 0, 1) == '.' )
2432                                                         continue;
2433                                                 if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
2434                                                         if ( is_dir("$dir/$file") )
2435                                                                 $dirs["$dir/$file"] = "$uri/$file";
2436                                                         continue;
2437                                                 }
2438                                                 $icon_files["$dir/$file"] = "$uri/$file";
2439                                         }
2440                                         closedir($dh);
2441                                 }
2442                         }
2443                         wp_cache_set('icon_files', $icon_files, 600);
2444                 }
2445
2446                 // Icon basename - extension = MIME wildcard
2447                 foreach ( $icon_files as $file => $uri )
2448                         $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
2449
2450                 if ( ! empty($mime) ) {
2451                         $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
2452                         $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
2453                         $post_mimes[] = str_replace('/', '_', $mime);
2454                 }
2455
2456                 $matches = wp_match_mime_types(array_keys($types), $post_mimes);
2457                 $matches['default'] = array('default');
2458
2459                 foreach ( $matches as $match => $wilds ) {
2460                         if ( isset($types[$wilds[0]])) {
2461                                 $icon = $types[$wilds[0]];
2462                                 if ( !is_numeric($mime) )
2463                                         wp_cache_set("mime_type_icon_$mime", $icon);
2464                                 break;
2465                         }
2466                 }
2467         }
2468
2469         return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id ); // Last arg is 0 if function pass mime type.
2470 }
2471
2472 /**
2473  * wp_check_for_changed_slugs() - {@internal Missing Short Description}}
2474  *
2475  * {@internal Missing Long Description}}
2476  *
2477  * @package WordPress
2478  * @subpackage Post
2479  * @since 2.1
2480  *
2481  * @param int $post_id The Post ID
2482  * @return int Same as $post_id
2483  */
2484 function wp_check_for_changed_slugs($post_id) {
2485         if ( !isset($_POST['wp-old-slug']) || !strlen($_POST['wp-old-slug']) )
2486                 return $post_id;
2487
2488         $post = &get_post($post_id);
2489
2490         // we're only concerned with published posts
2491         if ( $post->post_status != 'publish' || $post->post_type != 'post' )
2492                 return $post_id;
2493
2494         // only bother if the slug has changed
2495         if ( $post->post_name == $_POST['wp-old-slug'] )
2496                 return $post_id;
2497
2498         $old_slugs = (array) get_post_meta($post_id, '_wp_old_slug');
2499
2500         // if we haven't added this old slug before, add it now
2501         if ( !count($old_slugs) || !in_array($_POST['wp-old-slug'], $old_slugs) )
2502                 add_post_meta($post_id, '_wp_old_slug', $_POST['wp-old-slug']);
2503
2504         // if the new slug was used previously, delete it from the list
2505         if ( in_array($post->post_name, $old_slugs) )
2506                 delete_post_meta($post_id, '_wp_old_slug', $post->post_name);
2507
2508         return $post_id;
2509 }
2510
2511 /**
2512  * get_private_posts_cap_sql() - {@internal Missing Short Description}}
2513  *
2514  * This function provides a standardized way to appropriately select on
2515  * the post_status of posts/pages. The function will return a piece of
2516  * SQL code that can be added to a WHERE clause; this SQL is constructed
2517  * to allow all published posts, and all private posts to which the user
2518  * has access.
2519  *
2520  * @package WordPress
2521  * @subpackage Post
2522  * @since 2.2
2523  *
2524  * @uses $user_ID
2525  * @uses apply_filters() Call 'pub_priv_sql_capability' filter for plugins with different post types
2526  *
2527  * @param string $post_type currently only supports 'post' or 'page'.
2528  * @return string SQL code that can be added to a where clause.
2529  */
2530 function get_private_posts_cap_sql($post_type) {
2531         global $user_ID;
2532         $cap = '';
2533
2534         // Private posts
2535         if ($post_type == 'post') {
2536                 $cap = 'read_private_posts';
2537         // Private pages
2538         } elseif ($post_type == 'page') {
2539                 $cap = 'read_private_pages';
2540         // Dunno what it is, maybe plugins have their own post type?
2541         } else {
2542                 $cap = apply_filters('pub_priv_sql_capability', $cap);
2543
2544                 if (empty($cap)) {
2545                         // We don't know what it is, filters don't change anything,
2546                         // so set the SQL up to return nothing.
2547                         return '1 = 0';
2548                 }
2549         }
2550
2551         $sql = '(post_status = \'publish\'';
2552
2553         if (current_user_can($cap)) {
2554                 // Does the user have the capability to view private posts? Guess so.
2555                 $sql .= ' OR post_status = \'private\'';
2556         } elseif (is_user_logged_in()) {
2557                 // Users can view their own private posts.
2558                 $sql .= ' OR post_status = \'private\' AND post_author = \'' . $user_ID . '\'';
2559         }
2560
2561         $sql .= ')';
2562
2563         return $sql;
2564 }
2565
2566 /**
2567  * get_lastpostdate() - {@internal Missing Short Description}}
2568  *
2569  * {@internal Missing Long Description}}
2570  *
2571  * @package WordPress
2572  * @subpackage Post
2573  * @since 0.71
2574  *
2575  * @uses $wpdb
2576  * @uses $blog_id
2577  * @uses apply_filters() Calls 'get_lastpostdate' filter
2578  *
2579  * @global mixed $cache_lastpostdate Stores the last post date
2580  * @global mixed $pagenow The current page being viewed
2581  *
2582  * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
2583  * @return string The date of the last post.
2584  */
2585 function get_lastpostdate($timezone = 'server') {
2586         global $cache_lastpostdate, $wpdb, $blog_id;
2587         $add_seconds_server = date('Z');
2588         if ( !isset($cache_lastpostdate[$blog_id][$timezone]) ) {
2589                 switch(strtolower($timezone)) {
2590                         case 'gmt':
2591                                 $lastpostdate = $wpdb->get_var("SELECT post_date_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
2592                                 break;
2593                         case 'blog':
2594                                 $lastpostdate = $wpdb->get_var("SELECT post_date FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
2595                                 break;
2596                         case 'server':
2597                                 $lastpostdate = $wpdb->get_var("SELECT DATE_ADD(post_date_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
2598                                 break;
2599                 }
2600                 $cache_lastpostdate[$blog_id][$timezone] = $lastpostdate;
2601         } else {
2602                 $lastpostdate = $cache_lastpostdate[$blog_id][$timezone];
2603         }
2604         return apply_filters( 'get_lastpostdate', $lastpostdate, $timezone );
2605 }
2606
2607 /**
2608  * get_lastpostmodified() - {@internal Missing Short Description}}
2609  *
2610  * {@internal Missing Long Description}}
2611  *
2612  * @package WordPress
2613  * @subpackage Post
2614  * @since 1.2
2615  *
2616  * @uses $wpdb
2617  * @uses $blog_id
2618  * @uses apply_filters() Calls 'get_lastpostmodified' filter
2619  *
2620  * @global mixed $cache_lastpostmodified Stores the date the last post was modified
2621  * @global mixed $pagenow The current page being viewed
2622  *
2623  * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
2624  * @return string The date the post was last modified.
2625  */
2626 function get_lastpostmodified($timezone = 'server') {
2627         global $cache_lastpostmodified, $wpdb, $blog_id;
2628         $add_seconds_server = date('Z');
2629         if ( !isset($cache_lastpostmodified[$blog_id][$timezone]) ) {
2630                 switch(strtolower($timezone)) {
2631                         case 'gmt':
2632                                 $lastpostmodified = $wpdb->get_var("SELECT post_modified_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
2633                                 break;
2634                         case 'blog':
2635                                 $lastpostmodified = $wpdb->get_var("SELECT post_modified FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
2636                                 break;
2637                         case 'server':
2638                                 $lastpostmodified = $wpdb->get_var("SELECT DATE_ADD(post_modified_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
2639                                 break;
2640                 }
2641                 $lastpostdate = get_lastpostdate($timezone);
2642                 if ( $lastpostdate > $lastpostmodified ) {
2643                         $lastpostmodified = $lastpostdate;
2644                 }
2645                 $cache_lastpostmodified[$blog_id][$timezone] = $lastpostmodified;
2646         } else {
2647                 $lastpostmodified = $cache_lastpostmodified[$blog_id][$timezone];
2648         }
2649         return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
2650 }
2651
2652 /**
2653  * update_post_cache() - Updates posts in cache
2654  *
2655  * @usedby update_page_cache() update_page_cache() aliased by this function.
2656  *
2657  * @package WordPress
2658  * @subpackage Cache
2659  * @since 1.5.1
2660  *
2661  * @param array $posts Array of post objects
2662  */
2663 function update_post_cache(&$posts) {
2664         if ( !$posts )
2665                 return;
2666
2667         foreach ( $posts as $post )
2668                 wp_cache_add($post->ID, $post, 'posts');
2669 }
2670
2671 /**
2672  * clean_post_cache() - Will clean the post in the cache
2673  *
2674  * Cleaning means delete from the cache of the post. Will call to clean
2675  * the term object cache associated with the post ID.
2676  *
2677  * @package WordPress
2678  * @subpackage Cache
2679  * @since 2.0
2680  *
2681  * @uses do_action() Will call the 'clean_post_cache' hook action.
2682  *
2683  * @param int $id The Post ID in the cache to clean
2684  */
2685 function clean_post_cache($id) {
2686         global $wpdb;
2687         $id = (int) $id;
2688
2689         wp_cache_delete($id, 'posts');
2690         wp_cache_delete($id, 'post_meta');
2691
2692         clean_object_term_cache($id, 'post');
2693
2694         wp_cache_delete( 'wp_get_archives', 'general' );
2695
2696         do_action('clean_post_cache', $id);
2697
2698         if ( $children = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d", $id) ) ) {
2699                 foreach( $children as $cid )
2700                         clean_post_cache( $cid );
2701         }
2702 }
2703
2704 /**
2705  * update_page_cache() - Alias of update_post_cache()
2706  *
2707  * @see update_post_cache() Posts and pages are the same, alias is intentional
2708  *
2709  * @package WordPress
2710  * @subpackage Cache
2711  * @since 1.5.1
2712  *
2713  * @param array $pages list of page objects
2714  */
2715 function update_page_cache(&$pages) {
2716         update_post_cache($pages);
2717 }
2718
2719 /**
2720  * clean_page_cache() - Will clean the page in the cache
2721  *
2722  * Clean (read: delete) page from cache that matches $id. Will also clean
2723  * cache associated with 'all_page_ids' and 'get_pages'.
2724  *
2725  * @package WordPress
2726  * @subpackage Cache
2727  * @since 2.0
2728  *
2729  * @uses do_action() Will call the 'clean_page_cache' hook action.
2730  *
2731  * @param int $id Page ID to clean
2732  */
2733 function clean_page_cache($id) {
2734         clean_post_cache($id);
2735
2736         wp_cache_delete( 'all_page_ids', 'posts' );
2737         wp_cache_delete( 'get_pages', 'posts' );
2738
2739         do_action('clean_page_cache', $id);
2740 }
2741
2742 /**
2743  * update_post_caches() - Call major cache updating functions for list of Post objects.
2744  *
2745  * @package WordPress
2746  * @subpackage Cache
2747  * @since 1.5
2748  *
2749  * @uses $wpdb
2750  * @uses update_post_cache()
2751  * @uses update_object_term_cache()
2752  * @uses update_postmeta_cache()
2753  *
2754  * @param array $posts Array of Post objects
2755  */
2756 function update_post_caches(&$posts) {
2757         // No point in doing all this work if we didn't match any posts.
2758         if ( !$posts )
2759                 return;
2760
2761         update_post_cache($posts);
2762
2763         $post_ids = array();
2764
2765         for ($i = 0; $i < count($posts); $i++)
2766                 $post_ids[] = $posts[$i]->ID;
2767
2768         update_object_term_cache($post_ids, 'post');
2769
2770         update_postmeta_cache($post_ids);
2771 }
2772
2773 /**
2774  * update_postmeta_cache() - {@internal Missing Short Description}}
2775  *
2776  * {@internal Missing Long Description}}
2777  *
2778  * @package WordPress
2779  * @subpackage Cache
2780  * @since 2.1
2781  *
2782  * @uses $wpdb
2783  *
2784  * @param array $post_ids {@internal Missing Description}}
2785  * @return bool|array Returns false if there is nothing to update or an array of metadata
2786  */
2787 function update_postmeta_cache($post_ids) {
2788         global $wpdb;
2789
2790         if ( empty( $post_ids ) )
2791                 return false;
2792
2793         if ( !is_array($post_ids) ) {
2794                 $post_ids = preg_replace('|[^0-9,]|', '', $post_ids);
2795                 $post_ids = explode(',', $post_ids);
2796         }
2797
2798         $post_ids = array_map('intval', $post_ids);
2799
2800         $ids = array();
2801         foreach ( (array) $post_ids as $id ) {
2802                 if ( false === wp_cache_get($id, 'post_meta') )
2803                         $ids[] = $id;
2804         }
2805
2806         if ( empty( $ids ) )
2807                 return false;
2808
2809         // Get post-meta info
2810         $id_list = join(',', $ids);
2811         $cache = array();
2812         if ( $meta_list = $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM $wpdb->postmeta WHERE post_id IN ($id_list) ORDER BY post_id, meta_key", ARRAY_A) ) {
2813                 foreach ( (array) $meta_list as $metarow) {
2814                         $mpid = (int) $metarow['post_id'];
2815                         $mkey = $metarow['meta_key'];
2816                         $mval = $metarow['meta_value'];
2817
2818                         // Force subkeys to be array type:
2819                         if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
2820                                 $cache[$mpid] = array();
2821                         if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
2822                                 $cache[$mpid][$mkey] = array();
2823
2824                         // Add a value to the current pid/key:
2825                         $cache[$mpid][$mkey][] = $mval;
2826                 }
2827         }
2828
2829         foreach ( (array) $ids as $id ) {
2830                 if ( ! isset($cache[$id]) )
2831                         $cache[$id] = array();
2832         }
2833
2834         foreach ( array_keys($cache) as $post)
2835                 wp_cache_set($post, $cache[$post], 'post_meta');
2836
2837         return $cache;
2838 }
2839
2840 //
2841 // Hooks
2842 //
2843
2844 /**
2845  * _transition_post_status() - Hook {@internal Missing Short Description}}
2846  *
2847  * {@internal Missing Long Description}}
2848  *
2849  * @package WordPress
2850  * @subpackage Post
2851  * @since 2.3
2852  *
2853  * @uses $wpdb
2854  *
2855  * @param string $new_status {@internal Missing Description}}
2856  * @param string $old_status {@internal Missing Description}}
2857  * @param object $post Object type containing the post information
2858  */
2859 function _transition_post_status($new_status, $old_status, $post) {
2860         global $wpdb;
2861
2862         if ( $old_status != 'publish' && $new_status == 'publish' ) {
2863                 // Reset GUID if transitioning to publish and it is empty
2864                 if ( '' == get_the_guid($post->ID) )
2865                         $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
2866                 do_action('private_to_published', $post->ID);  // Deprecated, use private_to_publish
2867         }
2868
2869         // Always clears the hook in case the post status bounced from future to draft.
2870         wp_clear_scheduled_hook('publish_future_post', $post->ID);
2871 }
2872
2873 /**
2874  * _future_post_hook() - Hook used to schedule publication for a post marked for the future.
2875  *
2876  * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
2877  *
2878  * @package WordPress
2879  * @subpackage Post
2880  * @since 2.3
2881  *
2882  * @param int $post_id Not Used. Can be set to null.
2883  * @param object $post Object type containing the post information
2884  */
2885 function _future_post_hook($deprecated = '', $post) {
2886         wp_clear_scheduled_hook( 'publish_future_post', $post->ID );
2887         wp_schedule_single_event(strtotime($post->post_date_gmt. ' GMT'), 'publish_future_post', array($post->ID));
2888 }
2889
2890 /**
2891  * _publish_post_hook() - Hook {@internal Missing Short Description}}
2892  *
2893  * {@internal Missing Long Description}}
2894  *
2895  * @package WordPress
2896  * @subpackage Post
2897  * @since 2.3
2898  *
2899  * @uses $wpdb
2900  * @uses XMLRPC_REQUEST
2901  * @uses APP_REQUEST
2902  * @uses do_action Calls 'xmlprc_publish_post' action if XMLRPC_REQUEST is defined. Calls 'app_publish_post'
2903  *      action if APP_REQUEST is defined.
2904  *
2905  * @param int $post_id The ID in the database table of the post being published
2906  */
2907 function _publish_post_hook($post_id) {
2908         global $wpdb;
2909
2910         if ( defined('XMLRPC_REQUEST') )
2911                 do_action('xmlrpc_publish_post', $post_id);
2912         if ( defined('APP_REQUEST') )
2913                 do_action('app_publish_post', $post_id);
2914
2915         if ( defined('WP_IMPORTING') )
2916                 return;
2917
2918         $data = array( 'post_id' => $post_id, 'meta_value' => '1' );
2919         if ( get_option('default_pingback_flag') )
2920                 $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_pingme' ) );
2921         $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_encloseme' ) );
2922         wp_schedule_single_event(time(), 'do_pings');
2923 }
2924
2925 /**
2926  * _save_post_hook() - Hook used to prevent page/post cache and rewrite rules from staying dirty
2927  *
2928  * Does two things. If the post is a page and has a template then it will update/add that
2929  * template to the meta. For both pages and posts, it will clean the post cache to make sure
2930  * that the cache updates to the changes done recently. For pages, the rewrite rules of
2931  * WordPress are flushed to allow for any changes.
2932  *
2933  * The $post parameter, only uses 'post_type' property and 'page_template' property.
2934  *
2935  * @package WordPress
2936  * @subpackage Post
2937  * @since 2.3
2938  *
2939  * @uses $wp_rewrite Flushes Rewrite Rules.
2940  *
2941  * @param int $post_id The ID in the database table for the $post
2942  * @param object $post Object type containing the post information
2943  */
2944 function _save_post_hook($post_id, $post) {
2945         if ( $post->post_type == 'page' ) {
2946                 if ( !empty($post->page_template) )
2947                         if ( ! update_post_meta($post_id, '_wp_page_template',  $post->page_template))
2948                                 add_post_meta($post_id, '_wp_page_template',  $post->page_template, true);
2949
2950                 clean_page_cache($post_id);
2951                 global $wp_rewrite;
2952                 $wp_rewrite->flush_rules();
2953         } else {
2954                 clean_post_cache($post_id);
2955         }
2956 }
2957
2958 //
2959 // Private
2960 //
2961
2962 function _get_post_ancestors(&$_post) {
2963         global $wpdb;
2964
2965         if ( isset($_post->ancestors) )
2966                 return;
2967
2968         $_post->ancestors = array();
2969
2970         if ( empty($_post->post_parent) || $_post->ID == $_post->post_parent )
2971                 return;
2972
2973         $id = $_post->ancestors[] = $_post->post_parent;
2974         while ( $ancestor = $wpdb->get_var( $wpdb->prepare("SELECT `post_parent` FROM $wpdb->posts WHERE ID = %d LIMIT 1", $id) ) ) {
2975                 if ( $id == $ancestor )
2976                         break;
2977                 $id = $_post->ancestors[] = $ancestor;
2978         }
2979 }
2980
2981 ?>