home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Blogs / wordpress2.6.exe / wordpress2.6 / wp-includes / post.php < prev    next >
Encoding:
PHP Script  |  2008-08-13  |  95.6 KB  |  3,446 lines

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