+ } 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 );
+
+ // Set GUID
+ if ( !$update && '' == $current_guid )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
+
+ clean_post_cache( $post_ID );
+
+ $post = get_post($post_ID);
+
+ if ( !empty($page_template) && 'page' == $data['post_type'] ) {
+ $post->page_template = $page_template;
+ $page_templates = wp_get_theme()->get_page_templates();
+ if ( 'default' != $page_template && ! isset( $page_templates[ $page_template ] ) ) {
+ 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.
+ * @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_update_post( $postarr = array(), $wp_error = false ) {
+ 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 = get_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, $wp_error );
+}
+
+/**
+ * Publish a post by transitioning the post status.
+ *
+ * @since 2.1.0
+ * @uses wp_update_post()
+ *
+ * @param mixed $post Post ID or object.
+ */
+function wp_publish_post( $post ) {
+ if ( ! $post = get_post( $post ) )
+ return;
+ if ( 'publish' == $post->post_status )
+ return;
+
+ $post->post_status = 'publish';
+ wp_update_post( $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;
+
+ $original_slug = $slug;
+
+ $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 ) ) {
+ if ( 'nav_menu_item' == $post_type )
+ return $slug;
+ // 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 apply_filters( 'wp_unique_post_slug', $slug, $post_ID, $post_status, $post_type, $post_parent, $original_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 string $taxonomy Taxonomy name. Defaults to 'post_tag'.
+ * @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();
+
+ if ( ! is_array( $tags ) ) {
+ $comma = _x( ',', 'tag delimiter' );
+ if ( ',' !== $comma )
+ $tags = str_replace( $comma, ',', $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_unique( array_map( 'intval', $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;
+ }
+
+ return wp_set_post_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 = explode( "\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 = sanitize_trackback_urls( $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 = get_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;
+
+ $page_ids = wp_cache_get('all_page_ids', 'posts');
+ if ( ! is_array( $page_ids ) ) {
+ $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.
+ *
+ * Use get_post() instead of get_page().
+ *
+ * @since 1.5.1
+ * @deprecated 3.5.0
+ *
+ * @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 WP_Post|null WP_Post on success or null on failure
+ */
+function get_page( $page, $output = OBJECT, $filter = 'raw') {
+ return get_post( $page, $output, $filter );
+}
+
+/**
+ * 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 WP_Post|null WP_Post on success or null on failure
+ */
+function get_page_by_path($page_path, $output = OBJECT, $post_type = 'page') {
+ global $wpdb;
+
+ $page_path = rawurlencode(urldecode($page_path));
+ $page_path = str_replace('%2F', '/', $page_path);
+ $page_path = str_replace('%20', ' ', $page_path);
+ $parts = explode( '/', trim( $page_path, '/' ) );
+ $parts = array_map( 'esc_sql', $parts );
+ $parts = array_map( 'sanitize_title_for_query', $parts );
+
+ $in_string = "'". implode( "','", $parts ) . "'";
+ $post_type_sql = $post_type;
+ $wpdb->escape_by_ref( $post_type_sql );
+ $pages = $wpdb->get_results( "SELECT ID, post_name, post_parent, post_type FROM $wpdb->posts WHERE post_name IN ($in_string) AND (post_type = '$post_type_sql' OR post_type = 'attachment')", OBJECT_K );
+
+ $revparts = array_reverse( $parts );
+
+ $foundid = 0;
+ foreach ( (array) $pages as $page ) {
+ if ( $page->post_name == $revparts[0] ) {
+ $count = 0;
+ $p = $page;
+ while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
+ $count++;
+ $parent = $pages[ $p->post_parent ];
+ if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] )
+ break;
+ $p = $parent;
+ }
+
+ if ( $p->post_parent == 0 && $count+1 == count( $revparts ) && $p->post_name == $revparts[ $count ] ) {
+ $foundid = $page->ID;
+ if ( $page->post_type == $post_type )
+ break;
+ }
+ }
+ }
+
+ if ( $foundid )
+ return get_post( $foundid, $output );
+
+ 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 WP_Post|null WP_Post on success or null on failure
+ */
+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_post( $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-children 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_post( $page );
+ $uri = $page->post_name;
+
+ foreach ( $page->ancestors as $parent ) {
+ $uri = get_post( $parent )->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;
+
+ $pages = false;
+
+ $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 $pages;
+
+ // Make sure we have a valid post status
+ if ( !is_array( $post_status ) )
+ $post_status = explode( ',', $post_status );
+ if ( array_diff( $post_status, get_post_stati() ) )
+ return $pages;
+
+ $cache = array();
+ $key = md5( serialize( compact(array_keys($defaults)) ) );
+ if ( $cache = wp_cache_get( 'get_pages', 'posts' ) ) {
+ if ( is_array($cache) && isset( $cache[ $key ] ) && is_array( $cache[ $key ] ) ) {
+ // Convert to WP_Post instances
+ $pages = array_map( 'get_post', $cache[ $key ] );
+ $pages = apply_filters( 'get_pages', $pages, $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 = '';
+ if ( !empty($exclude) ) {
+ $expages = wp_parse_id_list( $exclude );
+ if ( ! empty( $expages ) ) {
+ foreach ( $expages as $expage ) {
+ if (empty($exclusions))
+ $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expage);
+ else
+ $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expage);
+ }
+ }
+ }
+ if (!empty($exclusions))
+ $exclusions .= ')';
+
+ $author_query = '';
+ if (!empty($authors)) {
+ $post_authors = preg_split('/[\s,]+/',$authors);
+
+ if ( ! empty( $post_authors ) ) {
+ foreach ( $post_authors as $post_author ) {
+ //Do we have an author id or an author login?
+ if ( 0 == intval($post_author) ) {
+ $post_author = get_user_by('login', $post_author);
+ if ( empty($post_author) )
+ continue;
+ if ( empty($post_author->ID) )
+ continue;
+ $post_author = $post_author->ID;
+ }
+
+ if ( '' == $author_query )
+ $author_query = $wpdb->prepare(' post_author = %d ', $post_author);
+ else
+ $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author);
+ }
+ if ( '' != $author_query )
+ $author_query = " AND ($author_query)";
+ }
+ }
+
+ $join = '';
+ $where = "$exclusions $inclusions ";
+ if ( ! empty( $meta_key ) || ! empty( $meta_value ) ) {
+ $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
+
+ // meta_key and meta_value might be slashed
+ $meta_key = stripslashes($meta_key);
+ $meta_value = stripslashes($meta_value);
+ if ( ! empty( $meta_key ) )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
+ if ( ! empty( $meta_value ) )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
+
+ }
+
+ if ( $parent >= 0 )
+ $where .= $wpdb->prepare(' AND post_parent = %d ', $parent);
+
+ if ( 1 == count( $post_status ) ) {
+ $where_post_type = $wpdb->prepare( "post_type = %s AND post_status = %s", $post_type, array_shift( $post_status ) );
+ } else {
+ $post_status = implode( "', '", $post_status );
+ $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $post_type );
+ }
+
+ $orderby_array = array();
+ $allowed_keys = array('author', 'post_author', 'date', 'post_date', 'title', 'post_title', 'name', 'post_name', 'modified',
+ 'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent',
+ 'ID', 'rand', 'comment_count');
+ foreach ( explode( ',', $sort_column ) as $orderby ) {
+ $orderby = trim( $orderby );
+ if ( !in_array( $orderby, $allowed_keys ) )
+ continue;
+
+ switch ( $orderby ) {
+ case 'menu_order':
+ break;
+ case 'ID':
+ $orderby = "$wpdb->posts.ID";
+ break;
+ case 'rand':
+ $orderby = 'RAND()';
+ break;
+ case 'comment_count':
+ $orderby = "$wpdb->posts.comment_count";
+ break;
+ default:
+ if ( 0 === strpos( $orderby, 'post_' ) )
+ $orderby = "$wpdb->posts." . $orderby;
+ else
+ $orderby = "$wpdb->posts.post_" . $orderby;
+ }
+
+ $orderby_array[] = $orderby;
+
+ }
+ $sort_column = ! empty( $orderby_array ) ? implode( ',', $orderby_array ) : "$wpdb->posts.post_title";
+
+ $sort_order = strtoupper( $sort_order );
+ if ( '' !== $sort_order && !in_array( $sort_order, array( 'ASC', 'DESC' ) ) )
+ $sort_order = 'ASC';
+
+ $query = "SELECT * FROM $wpdb->posts $join WHERE ($where_post_type) $where ";
+ $query .= $author_query;
+ $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
+
+ if ( !empty($number) )
+ $query .= ' LIMIT ' . $offset . ',' . $number;
+
+ $pages = $wpdb->get_results($query);
+
+ if ( empty($pages) ) {
+ $pages = apply_filters('get_pages', array(), $r);
+ return $pages;
+ }
+
+ // Sanitize before caching so it'll only get done once
+ $num_pages = count($pages);
+ for ($i = 0; $i < $num_pages; $i++) {
+ $pages[$i] = sanitize_post($pages[$i], 'raw');
+ }
+
+ // Update cache.
+ update_post_cache( $pages );
+
+ if ( $child_of || $hierarchical )
+ $pages = get_page_children($child_of, $pages);
+
+ if ( !empty($exclude_tree) ) {
+ $exclude = (int) $exclude_tree;
+ $children = get_page_children($exclude, $pages);
+ $excludes = array();
+ foreach ( $children as $child )
+ $excludes[] = $child->ID;
+ $excludes[] = $exclude;
+ $num_pages = count($pages);
+ for ( $i = 0; $i < $num_pages; $i++ ) {
+ if ( in_array($pages[$i]->ID, $excludes) )
+ unset($pages[$i]);
+ }
+ }
+
+ $cache[ $key ] = $pages;
+ wp_cache_set( 'get_pages', $cache, 'posts' );
+
+ // Convert to WP_Post instances
+ $pages = array_map( 'get_post', $pages );
+
+ $pages = apply_filters('get_pages', $pages, $r);
+
+ return $pages;
+}
+
+//
+// Attachment functions
+//
+
+/**
+ * Check if the attachment URI is local one and is really an attachment.
+ *
+ * @since 2.0.0
+ *
+ * @param string $url URL to check
+ * @return bool True on success, false on failure.
+ */
+function is_local_attachment($url) {
+ if (strpos($url, home_url()) === false)
+ return false;
+ if (strpos($url, home_url('/?attachment_id=')) !== false)
+ return true;
+ if ( $id = url_to_postid($url) ) {
+ $post = get_post($id);
+ if ( 'attachment' == $post->post_type )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Insert an attachment.
+ *
+ * If you set the 'ID' in the $object parameter, it will mean that you are
+ * updating and attempt to update the attachment. You can also set the
+ * attachment name or title by setting the key 'post_name' or 'post_title'.
+ *
+ * You can set the dates for the attachment manually by setting the 'post_date'
+ * and 'post_date_gmt' keys' values.
+ *
+ * By default, the comments will use the default settings for whether the
+ * comments are allowed. You can close them manually or keep them open by
+ * setting the value for the 'comment_status' key.
+ *
+ * The $object parameter can have the following:
+ * 'post_status' - Default is 'draft'. Can not be overridden, set the same as parent post.
+ * 'post_type' - Default is 'post', will be set to attachment. Can not override.
+ * 'post_author' - Default is current user ID. The ID of the user, who added the attachment.
+ * 'ping_status' - Default is the value in default ping status option. Whether the attachment
+ * can accept pings.
+ * 'post_parent' - Default is 0. Can use $parent parameter or 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' - Attachment post content filtered.
+ * 'post_excerpt' - Attachment excerpt.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses $user_ID
+ * @uses do_action() Calls 'edit_attachment' on $post_ID if this is an update.
+ * @uses do_action() Calls 'add_attachment' on $post_ID if this is not an update.
+ *
+ * @param string|array $object Arguments to override defaults.
+ * @param string $file Optional filename.
+ * @param int $parent Parent post ID.
+ * @return int Attachment ID.
+ */
+function wp_insert_attachment($object, $file = false, $parent = 0) {
+ global $wpdb, $user_ID;
+
+ $defaults = array('post_status' => 'inherit', '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, 'context' => '');
+
+ $object = wp_parse_args($object, $defaults);
+ if ( !empty($parent) )
+ $object['post_parent'] = $parent;
+
+ unset( $object[ 'filter' ] );
+
+ $object = sanitize_post($object, 'db');
+
+ // export array as variables
+ extract($object, EXTR_SKIP);
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ $post_type = 'attachment';
+
+ if ( ! in_array( $post_status, array( 'inherit', 'private' ) ) )
+ $post_status = 'inherit';
+
+ 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_category = array();
+ }
+
+ // Are we updating or creating?
+ if ( !empty($ID) ) {
+ $update = true;
+ $post_ID = (int) $ID;
+ } else {
+ $update = false;
+ $post_ID = 0;
+ }
+
+ // Create a valid post name.
+ if ( empty($post_name) )
+ $post_name = sanitize_title($post_title);
+ else
+ $post_name = sanitize_title($post_name);
+
+ // expected_slashed ($post_name)
+ $post_name = wp_unique_post_slug($post_name, $post_ID, $post_status, $post_type, $post_parent);
+
+ if ( empty($post_date) )
+ $post_date = current_time('mysql');
+ if ( empty($post_date_gmt) )
+ $post_date_gmt = current_time('mysql', 1);
+
+ if ( empty($post_modified) )
+ $post_modified = $post_date;
+ if ( empty($post_modified_gmt) )
+ $post_modified_gmt = $post_date_gmt;
+
+ 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($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) )
+ $post_password = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ // 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', 'post_mime_type', 'guid' ) );
+ $data = stripslashes_deep( $data );
+
+ if ( $update ) {
+ $wpdb->update( $wpdb->posts, $data, array( 'ID' => $post_ID ) );
+ } else {
+ // 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;
+ }
+ }
+
+ $wpdb->insert( $wpdb->posts, $data );
+ $post_ID = (int) $wpdb->insert_id;
+ }
+
+ if ( empty($post_name) ) {
+ $post_name = sanitize_title($post_title, $post_ID);
+ $wpdb->update( $wpdb->posts, compact("post_name"), array( 'ID' => $post_ID ) );
+ }
+
+ 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 );
+
+ // 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 );
+ }
+ }
+
+ if ( $file )
+ update_attached_file( $post_ID, $file );
+
+ clean_post_cache( $post_ID );
+
+ if ( ! empty( $context ) )
+ add_post_meta( $post_ID, '_wp_attachment_context', $context, true );
+
+ if ( $update) {
+ do_action('edit_attachment', $post_ID);
+ } else {
+ do_action('add_attachment', $post_ID);