+ return $results ? $results : false;
+
+}
+
+/**
+ * Retrieve a single post, based on post ID.
+ *
+ * Has categories in 'post_category' property or key. Has tags in 'tags_input'
+ * property or key.
+ *
+ * @since 1.0.0
+ *
+ * @param int $postid Post ID.
+ * @param string $mode How to return result, either OBJECT, ARRAY_N, or ARRAY_A.
+ * @return object|array Post object or array holding post contents and information
+ */
+function wp_get_single_post($postid = 0, $mode = OBJECT) {
+ $postid = (int) $postid;
+
+ $post = get_post($postid, $mode);
+
+ if (
+ ( OBJECT == $mode && empty( $post->ID ) ) ||
+ ( OBJECT != $mode && empty( $post['ID'] ) )
+ )
+ return ( OBJECT == $mode ? null : array() );
+
+ // Set categories and tags
+ if ( $mode == OBJECT ) {
+ $post->post_category = array();
+ if ( is_object_in_taxonomy($post->post_type, 'category') )
+ $post->post_category = wp_get_post_categories($postid);
+ $post->tags_input = array();
+ if ( is_object_in_taxonomy($post->post_type, 'post_tag') )
+ $post->tags_input = wp_get_post_tags($postid, array('fields' => 'names'));
+ } else {
+ $post['post_category'] = array();
+ if ( is_object_in_taxonomy($post['post_type'], 'category') )
+ $post['post_category'] = wp_get_post_categories($postid);
+ $post['tags_input'] = array();
+ if ( is_object_in_taxonomy($post['post_type'], 'post_tag') )
+ $post['tags_input'] = wp_get_post_tags($postid, array('fields' => 'names'));
+ }
+
+ return $post;
+}
+
+/**
+ * Insert a post.
+ *
+ * If the $postarr parameter has 'ID' set to a value, then post will be updated.
+ *
+ * You can set the post date manually, but setting the values for 'post_date'
+ * and 'post_date_gmt' keys. You can close the comments or open the comments by
+ * setting the value for 'comment_status' key.
+ *
+ * The defaults for the parameter $postarr are:
+ * 'post_status' - Default is 'draft'.
+ * 'post_type' - Default is 'post'.
+ * 'post_author' - Default is current user ID ($user_ID). The ID of the user who added the post.
+ * 'ping_status' - Default is the value in 'default_ping_status' option.
+ * Whether the attachment can accept pings.
+ * 'post_parent' - Default is 0. Set this for the post it belongs to, if any.
+ * 'menu_order' - Default is 0. The order it is displayed.
+ * 'to_ping' - Whether to ping.
+ * 'pinged' - Default is empty string.
+ * 'post_password' - Default is empty string. The password to access the attachment.
+ * 'guid' - Global Unique ID for referencing the attachment.
+ * 'post_content_filtered' - Post content filtered.
+ * 'post_excerpt' - Post excerpt.
+ *
+ * @since 1.0.0
+ * @uses $wpdb
+ * @uses $wp_rewrite
+ * @uses $user_ID
+ * @uses do_action() Calls 'pre_post_update' on post ID if this is an update.
+ * @uses do_action() Calls 'edit_post' action on post ID and post data if this is an update.
+ * @uses do_action() Calls 'save_post' and 'wp_insert_post' on post id and post data just before returning.
+ * @uses apply_filters() Calls 'wp_insert_post_data' passing $data, $postarr prior to database update or insert.
+ * @uses wp_transition_post_status()
+ *
+ * @param array $postarr Elements that make up post to insert.
+ * @param bool $wp_error Optional. Allow return of WP_Error on failure.
+ * @return int|WP_Error The value 0 or WP_Error on failure. The post ID on success.
+ */
+function wp_insert_post($postarr, $wp_error = false) {
+ global $wpdb, $wp_rewrite, $user_ID;
+
+ $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
+ 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
+ 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
+ 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0,
+ 'post_content' => '', 'post_title' => '');
+
+ $postarr = wp_parse_args($postarr, $defaults);
+ $postarr = sanitize_post($postarr, 'db');
+
+ // export array as variables
+ extract($postarr, EXTR_SKIP);
+
+ // Are we updating or creating?
+ $update = false;
+ if ( !empty($ID) ) {
+ $update = true;
+ $previous_status = get_post_field('post_status', $ID);
+ } else {
+ $previous_status = 'new';
+ }
+
+ if ( ('' == $post_content) && ('' == $post_title) && ('' == $post_excerpt) && ('attachment' != $post_type) ) {
+ if ( $wp_error )
+ return new WP_Error('empty_content', __('Content, title, and excerpt are empty.'));
+ else
+ return 0;
+ }
+
+ if ( empty($post_type) )
+ $post_type = 'post';
+
+ if ( empty($post_status) )
+ $post_status = 'draft';
+
+ if ( !empty($post_category) )
+ $post_category = array_filter($post_category); // Filter out empty terms
+
+ // Make sure we set a valid category.
+ if ( empty($post_category) || 0 == count($post_category) || !is_array($post_category) ) {
+ // 'post' requires at least one category.
+ if ( 'post' == $post_type && 'auto-draft' != $post_status )
+ $post_category = array( get_option('default_category') );
+ else
+ $post_category = array();
+ }
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ $post_ID = 0;
+
+ // Get the post ID and GUID
+ if ( $update ) {
+ $post_ID = (int) $ID;
+ $guid = get_post_field( 'guid', $post_ID );
+ $post_before = get_post($post_ID);
+ }
+
+ // Don't allow contributors to set to set the post slug for pending review posts
+ if ( 'pending' == $post_status && !current_user_can( 'publish_posts' ) )
+ $post_name = '';
+
+ // Create a valid post name. Drafts and pending posts are allowed to have an empty
+ // post name.
+ if ( empty($post_name) ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+ $post_name = sanitize_title($post_title);
+ else
+ $post_name = '';
+ } else {
+ $post_name = sanitize_title($post_name);
+ }
+
+ // If the post date is empty (due to having been new or a draft) and status is not 'draft' or 'pending', set date to now
+ if ( empty($post_date) || '0000-00-00 00:00:00' == $post_date )
+ $post_date = current_time('mysql');
+
+ if ( empty($post_date_gmt) || '0000-00-00 00:00:00' == $post_date_gmt ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+ $post_date_gmt = get_gmt_from_date($post_date);
+ else
+ $post_date_gmt = '0000-00-00 00:00:00';
+ }
+
+ if ( $update || '0000-00-00 00:00:00' == $post_date ) {
+ $post_modified = current_time( 'mysql' );
+ $post_modified_gmt = current_time( 'mysql', 1 );
+ } else {
+ $post_modified = $post_date;
+ $post_modified_gmt = $post_date_gmt;
+ }
+
+ if ( 'publish' == $post_status ) {
+ $now = gmdate('Y-m-d H:i:59');
+ if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) )
+ $post_status = 'future';
+ } elseif( 'future' == $post_status ) {
+ $now = gmdate('Y-m-d H:i:59');
+ if ( mysql2date('U', $post_date_gmt, false) <= mysql2date('U', $now, false) )
+ $post_status = 'publish';
+ }
+
+ if ( empty($comment_status) ) {
+ if ( $update )
+ $comment_status = 'closed';
+ else
+ $comment_status = get_option('default_comment_status');
+ }
+ if ( empty($ping_status) )
+ $ping_status = get_option('default_ping_status');
+
+ if ( isset($to_ping) )
+ $to_ping = preg_replace('|\s+|', "\n", $to_ping);
+ else
+ $to_ping = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ if ( isset($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ // Check the post_parent to see if it will cause a hierarchy loop
+ $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) || 'private' == $post_status )
+ $post_password = '';
+
+ $post_name = wp_unique_post_slug($post_name, $post_ID, $post_status, $post_type, $post_parent);
+
+ // expected_slashed (everything!)
+ $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' ) );
+ $data = apply_filters('wp_insert_post_data', $data, $postarr);
+ $data = stripslashes_deep( $data );
+ $where = array( 'ID' => $post_ID );
+
+ if ( $update ) {
+ do_action( 'pre_post_update', $post_ID );
+ if ( false === $wpdb->update( $wpdb->posts, $data, $where ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_update_error', __('Could not update post in the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ } else {
+ if ( isset($post_mime_type) )
+ $data['post_mime_type'] = stripslashes( $post_mime_type ); // This isn't in the update
+ // If there is a suggested ID, use it if not already present
+ if ( !empty($import_id) ) {
+ $import_id = (int) $import_id;
+ if ( ! $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id) ) ) {
+ $data['ID'] = $import_id;
+ }
+ }
+ if ( false === $wpdb->insert( $wpdb->posts, $data ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_insert_error', __('Could not insert post into the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ $post_ID = (int) $wpdb->insert_id;
+
+ // use the newly generated $post_ID
+ $where = array( 'ID' => $post_ID );
+ }
+
+ if ( empty($data['post_name']) && !in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
+ $data['post_name'] = sanitize_title($data['post_title'], $post_ID);
+ $wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
+ }
+
+ if ( is_object_in_taxonomy($post_type, 'category') )
+ wp_set_post_categories( $post_ID, $post_category );
+
+ if ( isset( $tags_input ) && is_object_in_taxonomy($post_type, 'post_tag') )
+ wp_set_post_tags( $post_ID, $tags_input );
+
+ // new-style support for all custom taxonomies
+ if ( !empty($tax_input) ) {
+ foreach ( $tax_input as $taxonomy => $tags ) {
+ $taxonomy_obj = get_taxonomy($taxonomy);
+ if ( is_array($tags) ) // array = hierarchical, string = non-hierarchical.
+ $tags = array_filter($tags);
+ if ( current_user_can($taxonomy_obj->cap->assign_terms) )
+ wp_set_post_terms( $post_ID, $tags, $taxonomy );
+ }
+ }
+
+ $current_guid = get_post_field( 'guid', $post_ID );
+
+ if ( 'page' == $data['post_type'] )
+ clean_page_cache($post_ID);
+ else
+ clean_post_cache($post_ID);
+
+ // Set GUID
+ if ( !$update && '' == $current_guid )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
+
+ $post = get_post($post_ID);
+
+ if ( !empty($page_template) && 'page' == $data['post_type'] ) {
+ $post->page_template = $page_template;
+ $page_templates = get_page_templates();
+ if ( 'default' != $page_template && !in_array($page_template, $page_templates) ) {
+ if ( $wp_error )
+ return new WP_Error('invalid_page_template', __('The page template is invalid.'));
+ else
+ return 0;
+ }
+ update_post_meta($post_ID, '_wp_page_template', $page_template);
+ }
+
+ wp_transition_post_status($data['post_status'], $previous_status, $post);
+
+ if ( $update ) {
+ do_action('edit_post', $post_ID, $post);
+ $post_after = get_post($post_ID);
+ do_action( 'post_updated', $post_ID, $post_after, $post_before);
+ }
+
+ do_action('save_post', $post_ID, $post);
+ do_action('wp_insert_post', $post_ID, $post);
+
+ return $post_ID;
+}
+
+/**
+ * Update a post with new post data.
+ *
+ * The date does not have to be set for drafts. You can set the date and it will
+ * not be overridden.
+ *
+ * @since 1.0.0
+ *
+ * @param array|object $postarr Post data. Arrays are expected to be escaped, objects are not.
+ * @return int 0 on failure, Post ID on success.
+ */
+function wp_update_post($postarr = array()) {
+ if ( is_object($postarr) ) {
+ // non-escaped post was passed
+ $postarr = get_object_vars($postarr);
+ $postarr = add_magic_quotes($postarr);
+ }
+
+ // First, get all of the original fields
+ $post = wp_get_single_post($postarr['ID'], ARRAY_A);
+
+ // Escape data pulled from DB.
+ $post = add_magic_quotes($post);
+
+ // Passed post category list overwrites existing category list if not empty.
+ if ( isset($postarr['post_category']) && is_array($postarr['post_category'])
+ && 0 != count($postarr['post_category']) )
+ $post_cats = $postarr['post_category'];
+ else
+ $post_cats = $post['post_category'];
+
+ // Drafts shouldn't be assigned a date unless explicitly done so by the user
+ if ( isset( $post['post_status'] ) && in_array($post['post_status'], array('draft', 'pending', 'auto-draft')) && empty($postarr['edit_date']) &&
+ ('0000-00-00 00:00:00' == $post['post_date_gmt']) )
+ $clear_date = true;
+ else
+ $clear_date = false;
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $postarr = array_merge($post, $postarr);
+ $postarr['post_category'] = $post_cats;
+ if ( $clear_date ) {
+ $postarr['post_date'] = current_time('mysql');
+ $postarr['post_date_gmt'] = '';
+ }
+
+ if ($postarr['post_type'] == 'attachment')
+ return wp_insert_attachment($postarr);
+
+ return wp_insert_post($postarr);
+}
+
+/**
+ * Publish a post by transitioning the post status.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'edit_post', 'save_post', and 'wp_insert_post' on post_id and post data.
+ *
+ * @param int $post_id Post ID.
+ * @return null
+ */
+function wp_publish_post($post_id) {
+ global $wpdb;
+
+ $post = get_post($post_id);
+
+ if ( empty($post) )
+ return;
+
+ if ( 'publish' == $post->post_status )
+ return;
+
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post_id ) );
+
+ $old_status = $post->post_status;
+ $post->post_status = 'publish';
+ wp_transition_post_status('publish', $old_status, $post);
+
+ // Update counts for the post's terms.
+ foreach ( (array) get_object_taxonomies('post') as $taxonomy ) {
+ $tt_ids = wp_get_object_terms($post_id, $taxonomy, array('fields' => 'tt_ids'));
+ wp_update_term_count($tt_ids, $taxonomy);
+ }
+
+ do_action('edit_post', $post_id, $post);
+ do_action('save_post', $post_id, $post);
+ do_action('wp_insert_post', $post_id, $post);
+}
+
+/**
+ * Publish future post and make sure post ID has future post status.
+ *
+ * Invoked by cron 'publish_future_post' event. This safeguard prevents cron
+ * from publishing drafts, etc.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Post ID.
+ * @return null Nothing is returned. Which can mean that no action is required or post was published.
+ */
+function check_and_publish_future_post($post_id) {
+
+ $post = get_post($post_id);
+
+ if ( empty($post) )
+ return;
+
+ if ( 'future' != $post->post_status )
+ return;
+
+ $time = strtotime( $post->post_date_gmt . ' GMT' );
+
+ if ( $time > time() ) { // Uh oh, someone jumped the gun!
+ wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // clear anything else in the system
+ wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
+ return;
+ }
+
+ return wp_publish_post($post_id);
+}
+
+
+/**
+ * Computes a unique slug for the post, when given the desired slug and some post details.
+ *
+ * @since 2.8.0
+ *
+ * @global wpdb $wpdb
+ * @global WP_Rewrite $wp_rewrite
+ * @param string $slug the desired slug (post_name)
+ * @param integer $post_ID
+ * @param string $post_status no uniqueness checks are made if the post is still draft or pending
+ * @param string $post_type
+ * @param integer $post_parent
+ * @return string unique slug for the post, based on $post_name (with a -1, -2, etc. suffix)
+ */
+function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) {
+ if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+ return $slug;
+
+ global $wpdb, $wp_rewrite;
+
+ $feeds = $wp_rewrite->feeds;
+ if ( ! is_array( $feeds ) )
+ $feeds = array();
+
+ $hierarchical_post_types = get_post_types( array('hierarchical' => true) );
+ if ( 'attachment' == $post_type ) {
+ // Attachment slugs must be unique across all types.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = substr ($slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare($check_sql, $alt_post_name, $post_ID ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ } elseif ( in_array( $post_type, $hierarchical_post_types ) ) {
+ // Page slugs must be unique within their own trees. Pages are in a separate
+ // namespace than posts so page slugs are allowed to overlap post slugs.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( '" . implode( "', '", esc_sql( $hierarchical_post_types ) ) . "' ) AND ID != %d AND post_parent = %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID, $post_parent ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug ) || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID, $post_parent ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ } else {
+ // Post slugs must be unique across all posts.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ }
+
+ return $slug;
+}
+
+/**
+ * Adds tags to a post.
+ *
+ * @uses wp_set_post_tags() Same first two parameters, but the last parameter is always set to true.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.3.0
+ *
+ * @param int $post_id Post ID
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
+ */
+function wp_add_post_tags($post_id = 0, $tags = '') {
+ return wp_set_post_tags($post_id, $tags, true);
+}
+
+
+/**
+ * Set the tags for a post.
+ *
+ * @since 2.3.0
+ * @uses wp_set_object_terms() Sets the tags for the post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
+ * @return mixed Array of affected term IDs. WP_Error or false on failure.
+ */
+function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
+ return wp_set_post_terms( $post_id, $tags, 'post_tag', $append);
+}
+
+/**
+ * Set the terms for a post.
+ *
+ * @since 2.8.0
+ * @uses wp_set_object_terms() Sets the tags for the post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
+ * @return mixed Array of affected term IDs. WP_Error or false on failure.
+ */
+function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = false ) {
+ $post_id = (int) $post_id;
+
+ if ( !$post_id )
+ return false;
+
+ if ( empty($tags) )
+ $tags = array();
+
+ $tags = is_array($tags) ? $tags : explode( ',', trim($tags, " \n\t\r\0\x0B,") );
+
+ // Hierarchical taxonomies must always pass IDs rather than names so that children with the same
+ // names but different parents aren't confused.
+ if ( is_taxonomy_hierarchical( $taxonomy ) ) {
+ $tags = array_map( 'intval', $tags );
+ $tags = array_unique( $tags );
+ }
+
+ return wp_set_object_terms($post_id, $tags, $taxonomy, $append);
+}
+
+/**
+ * Set categories for a post.
+ *
+ * If the post categories parameter is not set, then the default category is
+ * going used.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_ID Post ID.
+ * @param array $post_categories Optional. List of categories.
+ * @return bool|mixed
+ */
+function wp_set_post_categories($post_ID = 0, $post_categories = array()) {
+ $post_ID = (int) $post_ID;
+ $post_type = get_post_type( $post_ID );
+ $post_status = get_post_status( $post_ID );
+ // If $post_categories isn't already an array, make it one:
+ if ( !is_array($post_categories) || empty($post_categories) ) {
+ if ( 'post' == $post_type && 'auto-draft' != $post_status )
+ $post_categories = array( get_option('default_category') );
+ else
+ $post_categories = array();
+ } else if ( 1 == count($post_categories) && '' == reset($post_categories) ) {
+ return true;
+ }
+
+ if ( !empty($post_categories) ) {
+ $post_categories = array_map('intval', $post_categories);
+ $post_categories = array_unique($post_categories);
+ }
+
+ return wp_set_object_terms($post_ID, $post_categories, 'category');
+}
+
+/**
+ * Transition the post status of a post.
+ *
+ * Calls hooks to transition post status.
+ *
+ * The first is 'transition_post_status' with new status, old status, and post data.
+ *
+ * The next action called is 'OLDSTATUS_to_NEWSTATUS' the 'NEWSTATUS' is the
+ * $new_status parameter and the 'OLDSTATUS' is $old_status parameter; it has the
+ * post data.
+ *
+ * The final action is named 'NEWSTATUS_POSTTYPE', 'NEWSTATUS' is from the $new_status
+ * parameter and POSTTYPE is post_type post data.
+ *
+ * @since 2.3.0
+ * @link http://codex.wordpress.org/Post_Status_Transitions
+ *
+ * @uses do_action() Calls 'transition_post_status' on $new_status, $old_status and
+ * $post if there is a status change.
+ * @uses do_action() Calls '{$old_status}_to_{$new_status}' on $post if there is a status change.
+ * @uses do_action() Calls '{$new_status}_{$post->post_type}' on post ID and $post.
+ *
+ * @param string $new_status Transition to this post status.
+ * @param string $old_status Previous post status.
+ * @param object $post Post data.
+ */
+function wp_transition_post_status($new_status, $old_status, $post) {
+ do_action('transition_post_status', $new_status, $old_status, $post);
+ do_action("{$old_status}_to_{$new_status}", $post);
+ do_action("{$new_status}_{$post->post_type}", $post->ID, $post);
+}
+
+//
+// Trackback and ping functions
+//
+
+/**
+ * Add a URL to those already pung.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @param string $uri Ping URI.
+ * @return int How many rows were updated.
+ */
+function add_ping($post_id, $uri) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung[] = $uri;
+ $new = implode("\n", $pung);
+ $new = apply_filters('add_ping', $new);
+ // expected_slashed ($new)
+ $new = stripslashes($new);
+ return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
+}
+
+/**
+ * Retrieve enclosures already enclosed for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @return array List of enclosures
+ */
+function get_enclosed($post_id) {
+ $custom_fields = get_post_custom( $post_id );
+ $pung = array();
+ if ( !is_array( $custom_fields ) )
+ return $pung;
+
+ foreach ( $custom_fields as $key => $val ) {
+ if ( 'enclosure' != $key || !is_array( $val ) )
+ continue;
+ foreach( $val as $enc ) {
+ $enclosure = split( "\n", $enc );
+ $pung[] = trim( $enclosure[ 0 ] );
+ }
+ }
+ $pung = apply_filters('get_enclosed', $pung, $post_id);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs already pinged for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @return array
+ */
+function get_pung($post_id) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung = apply_filters('get_pung', $pung);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs that need to be pinged.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID
+ * @return array
+ */
+function get_to_ping($post_id) {
+ global $wpdb;
+ $to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $to_ping = trim($to_ping);
+ $to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
+ $to_ping = apply_filters('get_to_ping', $to_ping);
+ return $to_ping;
+}
+
+/**
+ * Do trackbacks for a list of URLs.
+ *
+ * @since 1.0.0
+ *
+ * @param string $tb_list Comma separated list of URLs
+ * @param int $post_id Post ID
+ */
+function trackback_url_list($tb_list, $post_id) {
+ if ( ! empty( $tb_list ) ) {
+ // get post data
+ $postdata = wp_get_single_post($post_id, ARRAY_A);
+
+ // import postdata as variables
+ extract($postdata, EXTR_SKIP);
+
+ // form an excerpt
+ $excerpt = strip_tags($post_excerpt ? $post_excerpt : $post_content);
+
+ if (strlen($excerpt) > 255) {
+ $excerpt = substr($excerpt,0,252) . '...';
+ }
+
+ $trackback_urls = explode(',', $tb_list);
+ foreach( (array) $trackback_urls as $tb_url) {
+ $tb_url = trim($tb_url);
+ trackback($tb_url, stripslashes($post_title), $excerpt, $post_id);
+ }
+ }
+}
+
+//
+// Page functions
+//
+
+/**
+ * Get a list of page IDs.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @return array List of page IDs.
+ */
+function get_all_page_ids() {
+ global $wpdb;
+
+ if ( ! $page_ids = wp_cache_get('all_page_ids', 'posts') ) {
+ $page_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'page'");
+ wp_cache_add('all_page_ids', $page_ids, 'posts');
+ }
+
+ return $page_ids;
+}
+
+/**
+ * Retrieves page data given a page ID or page object.
+ *
+ * @since 1.5.1
+ *
+ * @param mixed $page Page object or page ID. Passed by reference.
+ * @param string $output What to output. OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter How the return value should be filtered.
+ * @return mixed Page data.
+ */
+function &get_page(&$page, $output = OBJECT, $filter = 'raw') {
+ $p = get_post($page, $output, $filter);
+ return $p;
+}
+
+/**
+ * Retrieves a page given its path.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_path Page path
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+ * @param string $post_type Optional. Post type. Default page.
+ * @return mixed Null when complete.
+ */
+function get_page_by_path($page_path, $output = OBJECT, $post_type = 'page') {
+ global $wpdb;
+ $null = null;
+ $page_path = rawurlencode(urldecode($page_path));
+ $page_path = str_replace('%2F', '/', $page_path);
+ $page_path = str_replace('%20', ' ', $page_path);
+ $page_paths = '/' . trim($page_path, '/');
+ $leaf_path = sanitize_title(basename($page_paths));
+ $page_paths = explode('/', $page_paths);
+ $full_path = '';
+ foreach ( (array) $page_paths as $pathdir )
+ $full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title($pathdir);
+
+ $pages = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_name = %s AND (post_type = %s OR post_type = 'attachment')", $leaf_path, $post_type ));
+
+ if ( empty($pages) )
+ return $null;
+
+ foreach ( $pages as $page ) {
+ $path = '/' . $leaf_path;
+ $curpage = $page;
+ while ( $curpage->post_parent != 0 ) {
+ $post_parent = $curpage->post_parent;
+ $curpage = wp_cache_get( $post_parent, 'posts' );
+ if ( false === $curpage )
+ $curpage = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE ID = %d and post_type = %s", $post_parent, $post_type ) );
+ $path = '/' . $curpage->post_name . $path;
+ }
+
+ if ( $path == $full_path )
+ return get_page($page->ID, $output, $post_type);
+ }
+
+ return $null;
+}
+
+/**
+ * Retrieve a page given its title.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_title Page title
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+ * @param string $post_type Optional. Post type. Default page.
+ * @return mixed
+ */
+function get_page_by_title($page_title, $output = OBJECT, $post_type = 'page' ) {
+ global $wpdb;
+ $page = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type= %s", $page_title, $post_type ) );
+ if ( $page )
+ return get_page($page, $output);
+
+ return null;
+}
+
+/**
+ * Retrieve child pages from list of pages matching page ID.
+ *
+ * Matches against the pages parameter against the page ID. Also matches all
+ * children for the same to retrieve all children of a page. Does not make any
+ * SQL queries to get the children.
+ *
+ * @since 1.5.1
+ *
+ * @param int $page_id Page ID.
+ * @param array $pages List of pages' objects.
+ * @return array
+ */
+function &get_page_children($page_id, $pages) {
+ $page_list = array();
+ foreach ( (array) $pages as $page ) {
+ if ( $page->post_parent == $page_id ) {
+ $page_list[] = $page;
+ if ( $children = get_page_children($page->ID, $pages) )
+ $page_list = array_merge($page_list, $children);
+ }
+ }
+ return $page_list;
+}
+
+/**
+ * Order the pages with children under parents in a flat list.
+ *
+ * It uses auxiliary structure to hold parent-children relationships and
+ * runs in O(N) complexity
+ *
+ * @since 2.0.0
+ *
+ * @param array $pages Posts array.
+ * @param int $page_id Parent page ID.
+ * @return array A list arranged by hierarchy. Children immediately follow their parents.
+ */
+function &get_page_hierarchy( &$pages, $page_id = 0 ) {
+ if ( empty( $pages ) ) {
+ $result = array();
+ return $result;
+ }
+
+ $children = array();
+ foreach ( (array) $pages as $p ) {
+ $parent_id = intval( $p->post_parent );
+ $children[ $parent_id ][] = $p;
+ }
+
+ $result = array();
+ _page_traverse_name( $page_id, $children, $result );
+
+ return $result;
+}
+
+/**
+ * function to traverse and return all the nested children post names of a root page.
+ * $children contains parent-chilren relations
+ *
+ * @since 2.9.0
+ */
+function _page_traverse_name( $page_id, &$children, &$result ){
+ if ( isset( $children[ $page_id ] ) ){
+ foreach( (array)$children[ $page_id ] as $child ) {
+ $result[ $child->ID ] = $child->post_name;
+ _page_traverse_name( $child->ID, $children, $result );
+ }
+ }
+}
+
+/**
+ * Builds URI for a page.
+ *
+ * Sub pages will be in the "directory" under the parent page post name.
+ *
+ * @since 1.5.0
+ *
+ * @param mixed $page Page object or page ID.
+ * @return string Page URI.
+ */
+function get_page_uri($page) {
+ if ( ! is_object($page) )
+ $page = get_page($page);
+ $uri = $page->post_name;
+
+ // A page cannot be it's own parent.
+ if ( $page->post_parent == $page->ID )
+ return $uri;
+
+ while ($page->post_parent != 0) {
+ $page = get_page($page->post_parent);
+ $uri = $page->post_name . "/" . $uri;
+ }
+
+ return $uri;
+}
+
+/**
+ * Retrieve a list of pages.
+ *
+ * The defaults that can be overridden are the following: 'child_of',
+ * 'sort_order', 'sort_column', 'post_title', 'hierarchical', 'exclude',
+ * 'include', 'meta_key', 'meta_value','authors', 'number', and 'offset'.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param mixed $args Optional. Array or string of options that overrides defaults.
+ * @return array List of pages matching defaults or $args
+ */
+function &get_pages($args = '') {
+ global $wpdb;
+
+ $defaults = array(
+ 'child_of' => 0, 'sort_order' => 'ASC',
+ 'sort_column' => 'post_title', 'hierarchical' => 1,
+ 'exclude' => array(), 'include' => array(),
+ 'meta_key' => '', 'meta_value' => '',
+ 'authors' => '', 'parent' => -1, 'exclude_tree' => '',
+ 'number' => '', 'offset' => 0,
+ 'post_type' => 'page', 'post_status' => 'publish',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+ $number = (int) $number;
+ $offset = (int) $offset;
+
+ // Make sure the post type is hierarchical
+ $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
+ if ( !in_array( $post_type, $hierarchical_post_types ) )
+ return false;
+
+ // Make sure we have a valid post status
+ if ( !in_array($post_status, get_post_stati()) )
+ return false;
+
+ $cache = array();
+ $key = md5( serialize( compact(array_keys($defaults)) ) );
+ if ( $cache = wp_cache_get( 'get_pages', 'posts' ) ) {
+ if ( is_array($cache) && isset( $cache[ $key ] ) ) {
+ $pages = apply_filters('get_pages', $cache[ $key ], $r );
+ return $pages;
+ }
+ }
+
+ if ( !is_array($cache) )
+ $cache = array();
+
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
+ $parent = -1;
+ $exclude = '';
+ $meta_key = '';
+ $meta_value = '';
+ $hierarchical = false;
+ $incpages = wp_parse_id_list( $include );
+ if ( ! empty( $incpages ) ) {
+ foreach ( $incpages as $incpage ) {
+ if (empty($inclusions))
+ $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpage);
+ else
+ $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpage);
+ }
+ }
+ }
+ if (!empty($inclusions))
+ $inclusions .= ')';
+
+ $exclusions = '';