<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[35718] trunk/src: Simplify the include graph after work to split out classes.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/35718">35718</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/35718","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>nacin</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-11-20 07:23:04 +0000 (Fri, 20 Nov 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Simplify the include graph after work to split out classes.

see <a href="https://core.trac.wordpress.org/ticket/33413">#33413</a>. More details there.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludesadminphp">trunk/src/wp-admin/includes/admin.php</a></li>
<li><a href="#trunksrcwpadminincludesupdatecorephp">trunk/src/wp-admin/includes/update-core.php</a></li>
<li><a href="#trunksrcwpincludesclasswpcustomizemanagerphp">trunk/src/wp-includes/class-wp-customize-manager.php</a></li>
<li><a href="#trunksrcwpsettingsphp">trunk/src/wp-settings.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludestemplatephp">trunk/src/wp-admin/includes/template.php</a></li>
<li><a href="#trunksrcwpincludescapabilitiesphp">trunk/src/wp-includes/capabilities.php</a></li>
<li><a href="#trunksrcwpincludescategoryphp">trunk/src/wp-includes/category.php</a></li>
<li><a href="#trunksrcwpincludescommentphp">trunk/src/wp-includes/comment.php</a></li>
<li><a href="#trunksrcwpincludesembedphp">trunk/src/wp-includes/embed.php</a></li>
<li><a href="#trunksrcwpincludeshttpphp">trunk/src/wp-includes/http.php</a></li>
<li><a href="#trunksrcwpincludesmetaphp">trunk/src/wp-includes/meta.php</a></li>
<li><a href="#trunksrcwpincludespostphp">trunk/src/wp-includes/post.php</a></li>
<li><a href="#trunksrcwpincludesrestapiphp">trunk/src/wp-includes/rest-api.php</a></li>
<li><a href="#trunksrcwpincludesrewritephp">trunk/src/wp-includes/rewrite.php</a></li>
<li><a href="#trunksrcwpincludestaxonomyphp">trunk/src/wp-includes/taxonomy.php</a></li>
<li><a href="#trunksrcwpincludesuserphp">trunk/src/wp-includes/user.php</a></li>
<li><a href="#trunksrcwpincludeswidgetsphp">trunk/src/wp-includes/widgets.php</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludestemplatefunctionsphp">trunk/src/wp-admin/includes/template-functions.php</a></li>
<li><a href="#trunksrcwpadminincludestemplatephp">trunk/src/wp-admin/includes/template.php</a></li>
<li><a href="#trunksrcwpincludescapabilitiesfunctionsphp">trunk/src/wp-includes/capabilities-functions.php</a></li>
<li><a href="#trunksrcwpincludescapabilitiesphp">trunk/src/wp-includes/capabilities.php</a></li>
<li><a href="#trunksrcwpincludescategoryfunctionsphp">trunk/src/wp-includes/category-functions.php</a></li>
<li><a href="#trunksrcwpincludescategoryphp">trunk/src/wp-includes/category.php</a></li>
<li><a href="#trunksrcwpincludescommentfunctionsphp">trunk/src/wp-includes/comment-functions.php</a></li>
<li><a href="#trunksrcwpincludescommentphp">trunk/src/wp-includes/comment.php</a></li>
<li><a href="#trunksrcwpincludesembedfunctionsphp">trunk/src/wp-includes/embed-functions.php</a></li>
<li><a href="#trunksrcwpincludeshttpfunctionsphp">trunk/src/wp-includes/http-functions.php</a></li>
<li><a href="#trunksrcwpincludeshttpphp">trunk/src/wp-includes/http.php</a></li>
<li><a href="#trunksrcwpincludesmetafunctionsphp">trunk/src/wp-includes/meta-functions.php</a></li>
<li><a href="#trunksrcwpincludesmetaphp">trunk/src/wp-includes/meta.php</a></li>
<li><a href="#trunksrcwpincludespostfunctionsphp">trunk/src/wp-includes/post-functions.php</a></li>
<li><a href="#trunksrcwpincludespostphp">trunk/src/wp-includes/post.php</a></li>
<li><a href="#trunksrcwpincludesrestapirestfunctionsphp">trunk/src/wp-includes/rest-api/rest-functions.php</a></li>
<li><a href="#trunksrcwpincludesrestapiphp">trunk/src/wp-includes/rest-api.php</a></li>
<li><a href="#trunksrcwpincludesrewriteconstantsphp">trunk/src/wp-includes/rewrite-constants.php</a></li>
<li><a href="#trunksrcwpincludesrewritefunctionsphp">trunk/src/wp-includes/rewrite-functions.php</a></li>
<li><a href="#trunksrcwpincludesrewritephp">trunk/src/wp-includes/rewrite.php</a></li>
<li><a href="#trunksrcwpincludestaxonomyfunctionsphp">trunk/src/wp-includes/taxonomy-functions.php</a></li>
<li><a href="#trunksrcwpincludestaxonomyphp">trunk/src/wp-includes/taxonomy.php</a></li>
<li><a href="#trunksrcwpincludesuserfunctionsphp">trunk/src/wp-includes/user-functions.php</a></li>
<li><a href="#trunksrcwpincludesuserphp">trunk/src/wp-includes/user.php</a></li>
<li><a href="#trunksrcwpincludeswidgetfunctionsphp">trunk/src/wp-includes/widget-functions.php</a></li>
<li><a href="#trunksrcwpincludeswidgetsphp">trunk/src/wp-includes/widgets.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminincludesadminphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/admin.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/admin.php     2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-admin/includes/admin.php       2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -58,6 +58,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /** WordPress Template Administration API */
</span><span class="cx" style="display: block; padding: 0 10px"> require_once(ABSPATH . 'wp-admin/includes/template.php');
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require_once(ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php');
+require_once(ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /** WordPress List Table Administration API and base class */
</span><span class="cx" style="display: block; padding: 0 10px"> require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
</span></span></pre></div>
<a id="trunksrcwpadminincludestemplatefunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-admin/includes/template-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/template-functions.php        2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-admin/includes/template-functions.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,2074 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Administration API: Top-level admin template functionality
- *
- * A Big Mess. Also some neat functions that are nicely written.
- *
- * @package WordPress
- * @subpackage Administration
- * @since 4.4.0
- */
-
-//
-// Category Checklists
-//
-
-/**
- * Output an unordered list of checkbox input elements labeled with category names.
- *
- * @since 2.5.1
- *
- * @see wp_terms_checklist()
- *
- * @param int    $post_id              Optional. Post to generate a categories checklist for. Default 0.
- *                                     $selected_cats must not be an array. Default 0.
- * @param int    $descendants_and_self Optional. ID of the category to output along with its descendants.
- *                                     Default 0.
- * @param array  $selected_cats        Optional. List of categories to mark as checked. Default false.
- * @param array  $popular_cats         Optional. List of categories to receive the "popular-category" class.
- *                                     Default false.
- * @param object $walker               Optional. Walker object to use to build the output.
- *                                     Default is a Walker_Category_Checklist instance.
- * @param bool   $checked_ontop        Optional. Whether to move checked items out of the hierarchy and to
- *                                     the top of the list. Default true.
- */
-function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) {
-       wp_terms_checklist( $post_id, array(
-               'taxonomy' => 'category',
-               'descendants_and_self' => $descendants_and_self,
-               'selected_cats' => $selected_cats,
-               'popular_cats' => $popular_cats,
-               'walker' => $walker,
-               'checked_ontop' => $checked_ontop
-       ) );
-}
-
-/**
- * Output an unordered list of checkbox input elements labelled with term names.
- *
- * Taxonomy-independent version of wp_category_checklist().
- *
- * @since 3.0.0
- * @since 4.4.0 Introduced the `$echo` argument.
- *
- * @param int          $post_id Optional. Post ID. Default 0.
- * @param array|string $args {
- *     Optional. Array or string of arguments for generating a terms checklist. Default empty array.
- *
- *     @type int    $descendants_and_self ID of the category to output along with its descendants.
- *                                        Default 0.
- *     @type array  $selected_cats        List of categories to mark as checked. Default false.
- *     @type array  $popular_cats         List of categories to receive the "popular-category" class.
- *                                        Default false.
- *     @type object $walker               Walker object to use to build the output.
- *                                        Default is a Walker_Category_Checklist instance.
- *     @type string $taxonomy             Taxonomy to generate the checklist for. Default 'category'.
- *     @type bool   $checked_ontop        Whether to move checked items out of the hierarchy and to
- *                                        the top of the list. Default true.
- *     @type bool   $echo                 Whether to echo the generated markup. False to return the markup instead
- *                                        of echoing it. Default true.
- * }
- */
-function wp_terms_checklist( $post_id = 0, $args = array() ) {
-       $defaults = array(
-               'descendants_and_self' => 0,
-               'selected_cats' => false,
-               'popular_cats' => false,
-               'walker' => null,
-               'taxonomy' => 'category',
-               'checked_ontop' => true,
-               'echo' => true,
-       );
-
-       /**
-        * Filter the taxonomy terms checklist arguments.
-        *
-        * @since 3.4.0
-        *
-        * @see wp_terms_checklist()
-        *
-        * @param array $args    An array of arguments.
-        * @param int   $post_id The post ID.
-        */
-       $params = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
-
-       $r = wp_parse_args( $params, $defaults );
-
-       if ( empty( $r['walker'] ) || ! ( $r['walker'] instanceof Walker ) ) {
-               $walker = new Walker_Category_Checklist;
-       } else {
-               $walker = $r['walker'];
-       }
-
-       $taxonomy = $r['taxonomy'];
-       $descendants_and_self = (int) $r['descendants_and_self'];
-
-       $args = array( 'taxonomy' => $taxonomy );
-
-       $tax = get_taxonomy( $taxonomy );
-       $args['disabled'] = ! current_user_can( $tax->cap->assign_terms );
-
-       $args['list_only'] = ! empty( $r['list_only'] );
-
-       if ( is_array( $r['selected_cats'] ) ) {
-               $args['selected_cats'] = $r['selected_cats'];
-       } elseif ( $post_id ) {
-               $args['selected_cats'] = wp_get_object_terms( $post_id, $taxonomy, array_merge( $args, array( 'fields' => 'ids' ) ) );
-       } else {
-               $args['selected_cats'] = array();
-       }
-       if ( is_array( $r['popular_cats'] ) ) {
-               $args['popular_cats'] = $r['popular_cats'];
-       } else {
-               $args['popular_cats'] = get_terms( $taxonomy, array(
-                       'fields' => 'ids',
-                       'orderby' => 'count',
-                       'order' => 'DESC',
-                       'number' => 10,
-                       'hierarchical' => false
-               ) );
-       }
-       if ( $descendants_and_self ) {
-               $categories = (array) get_terms( $taxonomy, array(
-                       'child_of' => $descendants_and_self,
-                       'hierarchical' => 0,
-                       'hide_empty' => 0
-               ) );
-               $self = get_term( $descendants_and_self, $taxonomy );
-               array_unshift( $categories, $self );
-       } else {
-               $categories = (array) get_terms( $taxonomy, array( 'get' => 'all' ) );
-       }
-
-       $output = '';
-
-       if ( $r['checked_ontop'] ) {
-               // Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
-               $checked_categories = array();
-               $keys = array_keys( $categories );
-
-               foreach ( $keys as $k ) {
-                       if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
-                               $checked_categories[] = $categories[$k];
-                               unset( $categories[$k] );
-                       }
-               }
-
-               // Put checked cats on top
-               $output .= call_user_func_array( array( $walker, 'walk' ), array( $checked_categories, 0, $args ) );
-       }
-       // Then the rest of them
-       $output .= call_user_func_array( array( $walker, 'walk' ), array( $categories, 0, $args ) );
-
-       if ( $r['echo'] ) {
-               echo $output;
-       }
-
-       return $output;
-}
-
-/**
- * Retrieve a list of the most popular terms from the specified taxonomy.
- *
- * If the $echo argument is true then the elements for a list of checkbox
- * `<input>` elements labelled with the names of the selected terms is output.
- * If the $post_ID global isn't empty then the terms associated with that
- * post will be marked as checked.
- *
- * @since 2.5.0
- *
- * @param string $taxonomy Taxonomy to retrieve terms from.
- * @param int $default Not used.
- * @param int $number Number of terms to retrieve. Defaults to 10.
- * @param bool $echo Optionally output the list as well. Defaults to true.
- * @return array List of popular term IDs.
- */
-function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
-       $post = get_post();
-
-       if ( $post && $post->ID )
-               $checked_terms = wp_get_object_terms($post->ID, $taxonomy, array('fields'=>'ids'));
-       else
-               $checked_terms = array();
-
-       $terms = get_terms( $taxonomy, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false ) );
-
-       $tax = get_taxonomy($taxonomy);
-
-       $popular_ids = array();
-       foreach ( (array) $terms as $term ) {
-               $popular_ids[] = $term->term_id;
-               if ( !$echo ) // hack for AJAX use
-                       continue;
-               $id = "popular-$taxonomy-$term->term_id";
-               $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
-               ?>
-
-               <li id="<?php echo $id; ?>" class="popular-category">
-                       <label class="selectit">
-                               <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php disabled( ! current_user_can( $tax->cap->assign_terms ) ); ?> />
-                               <?php
-                               /** This filter is documented in wp-includes/category-template.php */
-                               echo esc_html( apply_filters( 'the_category', $term->name ) );
-                               ?>
-                       </label>
-               </li>
-
-               <?php
-       }
-       return $popular_ids;
-}
-
-/**
- * Outputs a link category checklist element.
- *
- * @since 2.5.1
- *
- * @param int $link_id
- */
-function wp_link_category_checklist( $link_id = 0 ) {
-       $default = 1;
-
-       $checked_categories = array();
-
-       if ( $link_id ) {
-               $checked_categories = wp_get_link_cats( $link_id );
-               // No selected categories, strange
-               if ( ! count( $checked_categories ) ) {
-                       $checked_categories[] = $default;
-               }
-       } else {
-               $checked_categories[] = $default;
-       }
-
-       $categories = get_terms( 'link_category', array( 'orderby' => 'name', 'hide_empty' => 0 ) );
-
-       if ( empty( $categories ) )
-               return;
-
-       foreach ( $categories as $category ) {
-               $cat_id = $category->term_id;
-
-               /** This filter is documented in wp-includes/category-template.php */
-               $name = esc_html( apply_filters( 'the_category', $category->name ) );
-               $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
-               echo '<li id="link-category-', $cat_id, '"><label for="in-link-category-', $cat_id, '" class="selectit"><input value="', $cat_id, '" type="checkbox" name="link_category[]" id="in-link-category-', $cat_id, '"', $checked, '/> ', $name, "</label></li>";
-       }
-}
-
-/**
- * Adds hidden fields with the data for use in the inline editor for posts and pages.
- *
- * @since 2.7.0
- *
- * @param WP_Post $post Post object.
- */
-function get_inline_data($post) {
-       $post_type_object = get_post_type_object($post->post_type);
-       if ( ! current_user_can( 'edit_post', $post->ID ) )
-               return;
-
-       $title = esc_textarea( trim( $post->post_title ) );
-
-       /** This filter is documented in wp-admin/edit-tag-form.php */
-       echo '
-<div class="hidden" id="inline_' . $post->ID . '">
-       <div class="post_title">' . $title . '</div>' .
-       /** This filter is documented in wp-admin/edit-tag-form.php */
-       '<div class="post_name">' . apply_filters( 'editable_slug', $post->post_name, $post ) . '</div>
-       <div class="post_author">' . $post->post_author . '</div>
-       <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
-       <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
-       <div class="_status">' . esc_html( $post->post_status ) . '</div>
-       <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
-       <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
-       <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
-       <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
-       <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
-       <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
-       <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
-
-       if ( $post_type_object->hierarchical )
-               echo '<div class="post_parent">' . $post->post_parent . '</div>';
-
-       if ( $post->post_type == 'page' )
-               echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
-
-       if ( post_type_supports( $post->post_type, 'page-attributes' ) )
-               echo '<div class="menu_order">' . $post->menu_order . '</div>';
-
-       $taxonomy_names = get_object_taxonomies( $post->post_type );
-       foreach ( $taxonomy_names as $taxonomy_name) {
-               $taxonomy = get_taxonomy( $taxonomy_name );
-
-               if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
-
-                       $terms = get_object_term_cache( $post->ID, $taxonomy_name );
-                       if ( false === $terms ) {
-                               $terms = wp_get_object_terms( $post->ID, $taxonomy_name );
-                               wp_cache_add( $post->ID, $terms, $taxonomy_name . '_relationships' );
-                       }
-                       $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' );
-
-                       echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">' . implode( ',', $term_ids ) . '</div>';
-
-               } elseif ( $taxonomy->show_ui ) {
-
-                       $terms_to_edit = get_terms_to_edit( $post->ID, $taxonomy_name );
-                       if ( ! is_string( $terms_to_edit ) ) {
-                               $terms_to_edit = '';
-                       }
-
-                       echo '<div class="tags_input" id="'.$taxonomy_name.'_'.$post->ID.'">'
-                               . esc_html( str_replace( ',', ', ', $terms_to_edit ) ) . '</div>';
-
-               }
-       }
-
-       if ( !$post_type_object->hierarchical )
-               echo '<div class="sticky">' . (is_sticky($post->ID) ? 'sticky' : '') . '</div>';
-
-       if ( post_type_supports( $post->post_type, 'post-formats' ) )
-               echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
-
-       echo '</div>';
-}
-
-/**
- * Outputs the in-line comment reply-to form in the Comments list table.
- *
- * @since 2.7.0
- *
- * @global WP_List_Table $wp_list_table
- *
- * @param int    $position
- * @param bool   $checkbox
- * @param string $mode
- * @param bool   $table_row
- */
-function wp_comment_reply( $position = 1, $checkbox = false, $mode = 'single', $table_row = true ) {
-       global $wp_list_table;
-       /**
-        * Filter the in-line comment reply-to form output in the Comments
-        * list table.
-        *
-        * Returning a non-empty value here will short-circuit display
-        * of the in-line comment-reply form in the Comments list table,
-        * echoing the returned value instead.
-        *
-        * @since 2.7.0
-        *
-        * @see wp_comment_reply()
-        *
-        * @param string $content The reply-to form content.
-        * @param array  $args    An array of default args.
-        */
-       $content = apply_filters( 'wp_comment_reply', '', array( 'position' => $position, 'checkbox' => $checkbox, 'mode' => $mode ) );
-
-       if ( ! empty($content) ) {
-               echo $content;
-               return;
-       }
-
-       if ( ! $wp_list_table ) {
-               if ( $mode == 'single' ) {
-                       $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
-               } else {
-                       $wp_list_table = _get_list_table('WP_Comments_List_Table');
-               }
-       }
-
-?>
-<form method="get">
-<?php if ( $table_row ) : ?>
-<table style="display:none;"><tbody id="com-reply"><tr id="replyrow" class="inline-edit-row" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange">
-<?php else : ?>
-<div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
-<?php endif; ?>
-       <fieldset class="comment-reply">
-       <legend>
-               <span class="hidden" id="editlegend"><?php _e( 'Edit Comment' ); ?></span>
-               <span class="hidden" id="replyhead"><?php _e( 'Reply to Comment' ); ?></span>
-               <span class="hidden" id="addhead"><?php _e( 'Add new Comment' ); ?></span>
-       </legend>
-
-       <div id="replycontainer">
-       <label for="replycontent" class="screen-reader-text"><?php _e( 'Comment' ); ?></label>
-       <?php
-       $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
-       wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
-       ?>
-       </div>
-
-       <div id="edithead" style="display:none;">
-               <div class="inside">
-               <label for="author-name"><?php _e( 'Name' ) ?></label>
-               <input type="text" name="newcomment_author" size="50" value="" id="author-name" />
-               </div>
-
-               <div class="inside">
-               <label for="author-email"><?php _e('Email') ?></label>
-               <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
-               </div>
-
-               <div class="inside">
-               <label for="author-url"><?php _e('URL') ?></label>
-               <input type="text" id="author-url" name="newcomment_author_url" class="code" size="103" value="" />
-               </div>
-       </div>
-
-       <p id="replysubmit" class="submit">
-       <a href="#comments-form" class="save button-primary alignright">
-       <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
-       <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
-       <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
-       <a href="#comments-form" class="cancel button-secondary alignleft"><?php _e('Cancel'); ?></a>
-       <span class="waiting spinner"></span>
-       <span class="error" style="display:none;"></span>
-       </p>
-
-       <input type="hidden" name="action" id="action" value="" />
-       <input type="hidden" name="comment_ID" id="comment_ID" value="" />
-       <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
-       <input type="hidden" name="status" id="status" value="" />
-       <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
-       <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
-       <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr($mode); ?>" />
-       <?php
-               wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
-               if ( current_user_can( 'unfiltered_html' ) )
-                       wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
-       ?>
-       </fieldset>
-<?php if ( $table_row ) : ?>
-</td></tr></tbody></table>
-<?php else : ?>
-</div></div>
-<?php endif; ?>
-</form>
-<?php
-}
-
-/**
- * Output 'undo move to trash' text for comments
- *
- * @since 2.9.0
- */
-function wp_comment_trashnotice() {
-?>
-<div class="hidden" id="trash-undo-holder">
-       <div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
-</div>
-<div class="hidden" id="spam-undo-holder">
-       <div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
-</div>
-<?php
-}
-
-/**
- * Outputs a post's public meta data in the Custom Fields meta box.
- *
- * @since 1.2.0
- *
- * @param array $meta
- */
-function list_meta( $meta ) {
-       // Exit if no meta
-       if ( ! $meta ) {
-               echo '
-<table id="list-table" style="display: none;">
-       <thead>
-       <tr>
-               <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
-               <th>' . __( 'Value' ) . '</th>
-       </tr>
-       </thead>
-       <tbody id="the-list" data-wp-lists="list:meta">
-       <tr><td></td></tr>
-       </tbody>
-</table>'; //TBODY needed for list-manipulation JS
-               return;
-       }
-       $count = 0;
-?>
-<table id="list-table">
-       <thead>
-       <tr>
-               <th class="left"><?php _ex( 'Name', 'meta name' ) ?></th>
-               <th><?php _e( 'Value' ) ?></th>
-       </tr>
-       </thead>
-       <tbody id='the-list' data-wp-lists='list:meta'>
-<?php
-       foreach ( $meta as $entry )
-               echo _list_meta_row( $entry, $count );
-?>
-       </tbody>
-</table>
-<?php
-}
-
-/**
- * Outputs a single row of public meta data in the Custom Fields meta box.
- *
- * @since 2.5.0
- *
- * @staticvar string $update_nonce
- *
- * @param array $entry
- * @param int   $count
- * @return string
- */
-function _list_meta_row( $entry, &$count ) {
-       static $update_nonce = '';
-
-       if ( is_protected_meta( $entry['meta_key'], 'post' ) )
-               return '';
-
-       if ( ! $update_nonce )
-               $update_nonce = wp_create_nonce( 'add-meta' );
-
-       $r = '';
-       ++ $count;
-
-       if ( is_serialized( $entry['meta_value'] ) ) {
-               if ( is_serialized_string( $entry['meta_value'] ) ) {
-                       // This is a serialized string, so we should display it.
-                       $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
-               } else {
-                       // This is a serialized array/object so we should NOT display it.
-                       --$count;
-                       return '';
-               }
-       }
-
-       $entry['meta_key'] = esc_attr($entry['meta_key']);
-       $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // using a <textarea />
-       $entry['meta_id'] = (int) $entry['meta_id'];
-
-       $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
-
-       $r .= "\n\t<tr id='meta-{$entry['meta_id']}'>";
-       $r .= "\n\t\t<td class='left'><label class='screen-reader-text' for='meta-{$entry['meta_id']}-key'>" . __( 'Key' ) . "</label><input name='meta[{$entry['meta_id']}][key]' id='meta-{$entry['meta_id']}-key' type='text' size='20' value='{$entry['meta_key']}' />";
-
-       $r .= "\n\t\t<div class='submit'>";
-       $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) );
-       $r .= "\n\t\t";
-       $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) );
-       $r .= "</div>";
-       $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
-       $r .= "</td>";
-
-       $r .= "\n\t\t<td><label class='screen-reader-text' for='meta-{$entry['meta_id']}-value'>" . __( 'Value' ) . "</label><textarea name='meta[{$entry['meta_id']}][value]' id='meta-{$entry['meta_id']}-value' rows='2' cols='30'>{$entry['meta_value']}</textarea></td>\n\t</tr>";
-       return $r;
-}
-
-/**
- * Prints the form in the Custom Fields meta box.
- *
- * @since 1.2.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param WP_Post $post Optional. The post being edited.
- */
-function meta_form( $post = null ) {
-       global $wpdb;
-       $post = get_post( $post );
-
-       /**
-        * Filter values for the meta key dropdown in the Custom Fields meta box.
-        *
-        * Returning a non-null value will effectively short-circuit and avoid a
-        * potentially expensive query against postmeta.
-        *
-        * @since 4.4.0
-        *
-        * @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
-        */
-       $keys = apply_filters( 'postmeta_form_keys', null );
-
-       if ( null === $keys ) {
-               /**
-                * Filter the number of custom fields to retrieve for the drop-down
-                * in the Custom Fields meta box.
-                *
-                * @since 2.1.0
-                *
-                * @param int $limit Number of custom fields to retrieve. Default 30.
-                */
-               $limit = apply_filters( 'postmeta_form_limit', 30 );
-               $sql = "SELECT DISTINCT meta_key
-                       FROM $wpdb->postmeta
-                       WHERE meta_key NOT BETWEEN '_' AND '_z'
-                       HAVING meta_key NOT LIKE %s
-                       ORDER BY meta_key
-                       LIMIT %d";
-               $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
-       }
-
-       if ( $keys ) {
-               natcasesort( $keys );
-               $meta_key_input_id = 'metakeyselect';
-       } else {
-               $meta_key_input_id = 'metakeyinput';
-       }
-?>
-<p><strong><?php _e( 'Add New Custom Field:' ) ?></strong></p>
-<table id="newmeta">
-<thead>
-<tr>
-<th class="left"><label for="<?php echo $meta_key_input_id; ?>"><?php _ex( 'Name', 'meta name' ) ?></label></th>
-<th><label for="metavalue"><?php _e( 'Value' ) ?></label></th>
-</tr>
-</thead>
-
-<tbody>
-<tr>
-<td id="newmetaleft" class="left">
-<?php if ( $keys ) { ?>
-<select id="metakeyselect" name="metakeyselect">
-<option value="#NONE#"><?php _e( '&mdash; Select &mdash;' ); ?></option>
-<?php
-
-       foreach ( $keys as $key ) {
-               if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) )
-                       continue;
-               echo "\n<option value='" . esc_attr($key) . "'>" . esc_html($key) . "</option>";
-       }
-?>
-</select>
-<input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
-<a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
-<span id="enternew"><?php _e('Enter new'); ?></span>
-<span id="cancelnew" class="hidden"><?php _e('Cancel'); ?></span></a>
-<?php } else { ?>
-<input type="text" id="metakeyinput" name="metakeyinput" value="" />
-<?php } ?>
-</td>
-<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
-</tr>
-
-<tr><td colspan="2">
-<div class="submit">
-<?php submit_button( __( 'Add Custom Field' ), 'secondary', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta' ) ); ?>
-</div>
-<?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
-</td></tr>
-</tbody>
-</table>
-<?php
-
-}
-
-/**
- * Print out HTML form date elements for editing post or comment publish date.
- *
- * @since 0.71
- * @since 4.4.0 Converted to use get_comment() instead of the global `$comment`.
- *
- * @global WP_Locale  $wp_locale
- *
- * @param int|bool $edit      Accepts 1|true for editing the date, 0|false for adding the date.
- * @param int|bool $for_post  Accepts 1|true for applying the date to a post, 0|false for a comment.
- * @param int      $tab_index The tabindex attribute to add. Default 0.
- * @param int|bool $multi     Optional. Whether the additional fields and buttons should be added.
- *                            Default 0|false.
- */
-function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
-       global $wp_locale;
-       $post = get_post();
-
-       if ( $for_post )
-               $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
-
-       $tab_index_attribute = '';
-       if ( (int) $tab_index > 0 )
-               $tab_index_attribute = " tabindex=\"$tab_index\"";
-
-       // todo: Remove this?
-       // echo '<label for="timestamp" style="display: block;"><input type="checkbox" class="checkbox" name="edit_date" value="1" id="timestamp"'.$tab_index_attribute.' /> '.__( 'Edit timestamp' ).'</label><br />';
-
-       $time_adj = current_time('timestamp');
-       $post_date = ($for_post) ? $post->post_date : get_comment()->comment_date;
-       $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
-       $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
-       $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
-       $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
-       $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
-       $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
-
-       $cur_jj = gmdate( 'd', $time_adj );
-       $cur_mm = gmdate( 'm', $time_adj );
-       $cur_aa = gmdate( 'Y', $time_adj );
-       $cur_hh = gmdate( 'H', $time_adj );
-       $cur_mn = gmdate( 'i', $time_adj );
-
-       $month = '<label><span class="screen-reader-text">' . __( 'Month' ) . '</span><select ' . ( $multi ? '' : 'id="mm" ' ) . 'name="mm"' . $tab_index_attribute . ">\n";
-       for ( $i = 1; $i < 13; $i = $i +1 ) {
-               $monthnum = zeroise($i, 2);
-               $monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) );
-               $month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $mm, false ) . '>';
-               /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
-               $month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $monthtext ) . "</option>\n";
-       }
-       $month .= '</select></label>';
-
-       $day = '<label><span class="screen-reader-text">' . __( 'Day' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
-       $year = '<label><span class="screen-reader-text">' . __( 'Year' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" /></label>';
-       $hour = '<label><span class="screen-reader-text">' . __( 'Hour' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
-       $minute = '<label><span class="screen-reader-text">' . __( 'Minute' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
-
-       echo '<div class="timestamp-wrap">';
-       /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
-       printf( __( '%1$s %2$s, %3$s @ %4$s:%5$s' ), $month, $day, $year, $hour, $minute );
-
-       echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
-
-       if ( $multi ) return;
-
-       echo "\n\n";
-       $map = array(
-               'mm' => array( $mm, $cur_mm ),
-               'jj' => array( $jj, $cur_jj ),
-               'aa' => array( $aa, $cur_aa ),
-               'hh' => array( $hh, $cur_hh ),
-               'mn' => array( $mn, $cur_mn ),
-       );
-       foreach ( $map as $timeunit => $value ) {
-               list( $unit, $curr ) = $value;
-
-               echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $unit . '" />' . "\n";
-               $cur_timeunit = 'cur_' . $timeunit;
-               echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
-       }
-?>
-
-<p>
-<a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
-<a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js button-cancel"><?php _e('Cancel'); ?></a>
-</p>
-<?php
-}
-
-/**
- * Print out option HTML elements for the page templates drop-down.
- *
- * @since 1.5.0
- *
- * @param string $default Optional. The template file name. Default empty.
- */
-function page_template_dropdown( $default = '' ) {
-       $templates = get_page_templates( get_post() );
-       ksort( $templates );
-       foreach ( array_keys( $templates ) as $template ) {
-               $selected = selected( $default, $templates[ $template ], false );
-               echo "\n\t<option value='" . $templates[ $template ] . "' $selected>$template</option>";
-       }
-}
-
-/**
- * Print out option HTML elements for the page parents drop-down.
- *
- * @since 1.5.0
- * @since 4.4.0 `$post` argument was added.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int         $default Optional. The default page ID to be pre-selected. Default 0.
- * @param int         $parent  Optional. The parent page ID. Default 0.
- * @param int         $level   Optional. Page depth level. Default 0.
- * @param int|WP_Post $post    Post ID or WP_Post object.
- *
- * @return null|false Boolean False if page has no children, otherwise print out html elements
- */
-function parent_dropdown( $default = 0, $parent = 0, $level = 0, $post = null ) {
-       global $wpdb;
-       $post = get_post( $post );
-       $items = $wpdb->get_results( $wpdb->prepare("SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' ORDER BY menu_order", $parent) );
-
-       if ( $items ) {
-               foreach ( $items as $item ) {
-                       // A page cannot be its own parent.
-                       if ( $post && $post->ID && $item->ID == $post->ID )
-                               continue;
-
-                       $pad = str_repeat( '&nbsp;', $level * 3 );
-                       $selected = selected( $default, $item->ID, false );
-
-                       echo "\n\t<option class='level-$level' value='$item->ID' $selected>$pad " . esc_html($item->post_title) . "</option>";
-                       parent_dropdown( $default, $item->ID, $level +1 );
-               }
-       } else {
-               return false;
-       }
-}
-
-/**
- * Print out option html elements for role selectors.
- *
- * @since 2.1.0
- *
- * @param string $selected Slug for the role that should be already selected.
- */
-function wp_dropdown_roles( $selected = '' ) {
-       $p = '';
-       $r = '';
-
-       $editable_roles = array_reverse( get_editable_roles() );
-
-       foreach ( $editable_roles as $role => $details ) {
-               $name = translate_user_role($details['name'] );
-               if ( $selected == $role ) // preselect specified role
-                       $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
-               else
-                       $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
-       }
-       echo $p . $r;
-}
-
-/**
- * Outputs the form used by the importers to accept the data to be imported
- *
- * @since 2.0.0
- *
- * @param string $action The action attribute for the form.
- */
-function wp_import_upload_form( $action ) {
-
-       /**
-        * Filter the maximum allowed upload size for import files.
-        *
-        * @since 2.3.0
-        *
-        * @see wp_max_upload_size()
-        *
-        * @param int $max_upload_size Allowed upload size. Default 1 MB.
-        */
-       $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
-       $size = size_format( $bytes );
-       $upload_dir = wp_upload_dir();
-       if ( ! empty( $upload_dir['error'] ) ) :
-               ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
-               <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
-       else :
-?>
-<form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>">
-<p>
-<label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
-<input type="file" id="upload" name="import" size="25" />
-<input type="hidden" name="action" value="save" />
-<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
-</p>
-<?php submit_button( __('Upload file and import'), 'primary' ); ?>
-</form>
-<?php
-       endif;
-}
-
-/**
- * Adds a meta box to one or more screens.
- *
- * @since 2.5.0
- * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
- *
- * @global array $wp_meta_boxes
- *
- * @param string                 $id            Meta box ID (used in the 'id' attribute for the meta box).
- * @param string                 $title         Title of the meta box.
- * @param callable               $callback      Function that fills the box with the desired content.
- *                                              The function should echo its output.
- * @param string|array|WP_Screen $screen        Optional. The screen or screens on which to show the box
- *                                              (such as a post type, 'link', or 'comment'). Accepts a single
- *                                              screen ID, WP_Screen object, or array of screen IDs. Default
- *                                              is the current screen.
- * @param string                 $context       Optional. The context within the screen where the boxes
- *                                              should display. Available contexts vary from screen to
- *                                              screen. Post edit screen contexts include 'normal', 'side',
- *                                              and 'advanced'. Comments screen contexts include 'normal'
- *                                              and 'side'. Menus meta boxes (accordion sections) all use
- *                                              the 'side' context. Global default is 'advanced'.
- * @param string                 $priority      Optional. The priority within the context where the boxes
- *                                              should show ('high', 'low'). Default 'default'.
- * @param array                  $callback_args Optional. Data that should be set as the $args property
- *                                              of the box array (which is the second parameter passed
- *                                              to your callback). Default null.
- */
-function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
-       global $wp_meta_boxes;
-
-       if ( empty( $screen ) ) {
-               $screen = get_current_screen();
-       } elseif ( is_string( $screen ) ) {
-               $screen = convert_to_screen( $screen );
-       } elseif ( is_array( $screen ) ) {
-               foreach ( $screen as $single_screen ) {
-                       add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args );
-               }
-       }
-
-       if ( ! isset( $screen->id ) ) {
-               return;
-       }
-
-       $page = $screen->id;
-
-       if ( !isset($wp_meta_boxes) )
-               $wp_meta_boxes = array();
-       if ( !isset($wp_meta_boxes[$page]) )
-               $wp_meta_boxes[$page] = array();
-       if ( !isset($wp_meta_boxes[$page][$context]) )
-               $wp_meta_boxes[$page][$context] = array();
-
-       foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
-               foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
-                       if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
-                               continue;
-
-                       // If a core box was previously added or removed by a plugin, don't add.
-                       if ( 'core' == $priority ) {
-                               // If core box previously deleted, don't add
-                               if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
-                                       return;
-
-                               /*
-                                * If box was added with default priority, give it core priority to
-                                * maintain sort order.
-                                */
-                               if ( 'default' == $a_priority ) {
-                                       $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
-                                       unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
-                               }
-                               return;
-                       }
-                       // If no priority given and id already present, use existing priority.
-                       if ( empty($priority) ) {
-                               $priority = $a_priority;
-                       /*
-                        * Else, if we're adding to the sorted priority, we don't know the title
-                        * or callback. Grab them from the previously added context/priority.
-                        */
-                       } elseif ( 'sorted' == $priority ) {
-                               $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
-                               $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
-                               $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
-                       }
-                       // An id can be in only one priority and one context.
-                       if ( $priority != $a_priority || $context != $a_context )
-                               unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
-               }
-       }
-
-       if ( empty($priority) )
-               $priority = 'low';
-
-       if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
-               $wp_meta_boxes[$page][$context][$priority] = array();
-
-       $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
-}
-
-/**
- * Meta-Box template function
- *
- * @since 2.5.0
- *
- * @global array $wp_meta_boxes
- *
- * @staticvar bool $already_sorted
- * @param string|WP_Screen $screen  Screen identifier
- * @param string           $context box context
- * @param mixed            $object  gets passed to the box callback function as first parameter
- * @return int number of meta_boxes
- */
-function do_meta_boxes( $screen, $context, $object ) {
-       global $wp_meta_boxes;
-       static $already_sorted = false;
-
-       if ( empty( $screen ) )
-               $screen = get_current_screen();
-       elseif ( is_string( $screen ) )
-               $screen = convert_to_screen( $screen );
-
-       $page = $screen->id;
-
-       $hidden = get_hidden_meta_boxes( $screen );
-
-       printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
-
-       // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
-       if ( ! $already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
-               foreach ( $sorted as $box_context => $ids ) {
-                       foreach ( explode( ',', $ids ) as $id ) {
-                               if ( $id && 'dashboard_browser_nag' !== $id ) {
-                                       add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
-                               }
-                       }
-               }
-       }
-
-       $already_sorted = true;
-
-       $i = 0;
-
-       if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
-               foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) {
-                       if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ]) ) {
-                               foreach ( (array) $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
-                                       if ( false == $box || ! $box['title'] )
-                                               continue;
-                                       $i++;
-                                       $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
-                                       echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
-                                       if ( 'dashboard_browser_nag' != $box['id'] ) {
-                                               echo '<button type="button" class="handlediv button-link" aria-expanded="true">';
-                                               echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $box['title'] ) . '</span>';
-                                               echo '<span class="toggle-indicator" aria-hidden="true"></span>';
-                                               echo '</button>';
-                                       }
-                                       echo "<h2 class='hndle'><span>{$box['title']}</span></h2>\n";
-                                       echo '<div class="inside">' . "\n";
-                                       call_user_func($box['callback'], $object, $box);
-                                       echo "</div>\n";
-                                       echo "</div>\n";
-                               }
-                       }
-               }
-       }
-
-       echo "</div>";
-
-       return $i;
-
-}
-
-/**
- * Removes a meta box from one or more screens.
- *
- * @since 2.6.0
- * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
- *
- * @global array $wp_meta_boxes
- *
- * @param string                 $id      Meta box ID (used in the 'id' attribute for the meta box).
- * @param string|array|WP_Screen $screen  The screen or screens on which the meta box is shown (such as a
- *                                        post type, 'link', or 'comment'). Accepts a single screen ID,
- *                                        WP_Screen object, or array of screen IDs.
- * @param string                 $context Optional. The context within the screen where the boxes
- *                                        should display. Available contexts vary from screen to
- *                                        screen. Post edit screen contexts include 'normal', 'side',
- *                                        and 'advanced'. Comments screen contexts include 'normal'
- *                                        and 'side'. Menus meta boxes (accordion sections) all use
- *                                        the 'side' context. Global default is 'advanced'.
- */
-function remove_meta_box( $id, $screen, $context ) {
-       global $wp_meta_boxes;
-
-       if ( empty( $screen ) ) {
-               $screen = get_current_screen();
-       } elseif ( is_string( $screen ) ) {
-               $screen = convert_to_screen( $screen );
-       } elseif ( is_array( $screen ) ) {
-               foreach ( $screen as $single_screen ) {
-                       remove_meta_box( $id, $single_screen, $context );
-               }
-       }
-
-       if ( ! isset( $screen->id ) ) {
-               return;
-       }
-
-       $page = $screen->id;
-
-       if ( !isset($wp_meta_boxes) )
-               $wp_meta_boxes = array();
-       if ( !isset($wp_meta_boxes[$page]) )
-               $wp_meta_boxes[$page] = array();
-       if ( !isset($wp_meta_boxes[$page][$context]) )
-               $wp_meta_boxes[$page][$context] = array();
-
-       foreach ( array('high', 'core', 'default', 'low') as $priority )
-               $wp_meta_boxes[$page][$context][$priority][$id] = false;
-}
-
-/**
- * Meta Box Accordion Template Function
- *
- * Largely made up of abstracted code from {@link do_meta_boxes()}, this
- * function serves to build meta boxes as list items for display as
- * a collapsible accordion.
- *
- * @since 3.6.0
- *
- * @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
- *
- * @param string|object $screen  The screen identifier.
- * @param string        $context The meta box context.
- * @param mixed         $object  gets passed to the section callback function as first parameter.
- * @return int number of meta boxes as accordion sections.
- */
-function do_accordion_sections( $screen, $context, $object ) {
-       global $wp_meta_boxes;
-
-       wp_enqueue_script( 'accordion' );
-
-       if ( empty( $screen ) )
-               $screen = get_current_screen();
-       elseif ( is_string( $screen ) )
-               $screen = convert_to_screen( $screen );
-
-       $page = $screen->id;
-
-       $hidden = get_hidden_meta_boxes( $screen );
-       ?>
-       <div id="side-sortables" class="accordion-container">
-               <ul class="outer-border">
-       <?php
-       $i = 0;
-       $first_open = false;
-
-       if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
-               foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
-                       if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
-                               foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
-                                       if ( false == $box || ! $box['title'] )
-                                               continue;
-                                       $i++;
-                                       $hidden_class = in_array( $box['id'], $hidden ) ? 'hide-if-js' : '';
-
-                                       $open_class = '';
-                                       if ( ! $first_open && empty( $hidden_class ) ) {
-                                               $first_open = true;
-                                               $open_class = 'open';
-                                       }
-                                       ?>
-                                       <li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
-                                               <h3 class="accordion-section-title hndle" tabindex="0">
-                                                       <?php echo esc_html( $box['title'] ); ?>
-                                                       <span class="screen-reader-text"><?php _e( 'Press return or enter to open this section' ); ?></span>
-                                               </h3>
-                                               <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
-                                                       <div class="inside">
-                                                               <?php call_user_func( $box['callback'], $object, $box ); ?>
-                                                       </div><!-- .inside -->
-                                               </div><!-- .accordion-section-content -->
-                                       </li><!-- .accordion-section -->
-                                       <?php
-                               }
-                       }
-               }
-       }
-       ?>
-               </ul><!-- .outer-border -->
-       </div><!-- .accordion-container -->
-       <?php
-       return $i;
-}
-
-/**
- * Add a new section to a settings page.
- *
- * Part of the Settings API. Use this to define new settings sections for an admin page.
- * Show settings sections in your admin page callback function with do_settings_sections().
- * Add settings fields to your section with add_settings_field()
- *
- * The $callback argument should be the name of a function that echoes out any
- * content you want to show at the top of the settings section before the actual
- * fields. It can output nothing if you want.
- *
- * @since 2.7.0
- *
- * @global $wp_settings_sections Storage array of all settings sections added to admin pages
- *
- * @param string $id       Slug-name to identify the section. Used in the 'id' attribute of tags.
- * @param string $title    Formatted title of the section. Shown as the heading for the section.
- * @param string $callback Function that echos out any content at the top of the section (between heading and fields).
- * @param string $page     The slug-name of the settings page on which to show the section. Built-in pages include 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using add_options_page();
- */
-function add_settings_section($id, $title, $callback, $page) {
-       global $wp_settings_sections;
-
-       if ( 'misc' == $page ) {
-               _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
-               $page = 'general';
-       }
-
-       if ( 'privacy' == $page ) {
-               _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
-               $page = 'reading';
-       }
-
-       $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
-}
-
-/**
- * Add a new field to a section of a settings page
- *
- * Part of the Settings API. Use this to define a settings field that will show
- * as part of a settings section inside a settings page. The fields are shown using
- * do_settings_fields() in do_settings-sections()
- *
- * The $callback argument should be the name of a function that echoes out the
- * html input tags for this setting field. Use get_option() to retrieve existing
- * values to show.
- *
- * @since 2.7.0
- * @since 4.2.0 The `$class` argument was added.
- *
- * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
- *
- * @param string $id       Slug-name to identify the field. Used in the 'id' attribute of tags.
- * @param string $title    Formatted title of the field. Shown as the label for the field
- *                         during output.
- * @param string $callback Function that fills the field with the desired form inputs. The
- *                         function should echo its output.
- * @param string $page     The slug-name of the settings page on which to show the section
- *                         (general, reading, writing, ...).
- * @param string $section  Optional. The slug-name of the section of the settings page
- *                         in which to show the box. Default 'default'.
- * @param array  $args {
- *     Optional. Extra arguments used when outputting the field.
- *
- *     @type string $label_for When supplied, the setting title will be wrapped
- *                             in a `<label>` element, its `for` attribute populated
- *                             with this value.
- *     @type string $class     CSS Class to be added to the `<tr>` element when the
- *                             field is output.
- * }
- */
-function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
-       global $wp_settings_fields;
-
-       if ( 'misc' == $page ) {
-               _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
-               $page = 'general';
-       }
-
-       if ( 'privacy' == $page ) {
-               _deprecated_argument( __FUNCTION__, '3.5', __( 'The privacy options group has been removed. Use another settings group.' ) );
-               $page = 'reading';
-       }
-
-       $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
-}
-
-/**
- * Prints out all settings sections added to a particular settings page
- *
- * Part of the Settings API. Use this in a settings page callback function
- * to output all the sections and fields that were added to that $page with
- * add_settings_section() and add_settings_field()
- *
- * @global $wp_settings_sections Storage array of all settings sections added to admin pages
- * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
- * @since 2.7.0
- *
- * @param string $page The slug name of the page whose settings sections you want to output
- */
-function do_settings_sections( $page ) {
-       global $wp_settings_sections, $wp_settings_fields;
-
-       if ( ! isset( $wp_settings_sections[$page] ) )
-               return;
-
-       foreach ( (array) $wp_settings_sections[$page] as $section ) {
-               if ( $section['title'] )
-                       echo "<h2>{$section['title']}</h2>\n";
-
-               if ( $section['callback'] )
-                       call_user_func( $section['callback'], $section );
-
-               if ( ! isset( $wp_settings_fields ) || !isset( $wp_settings_fields[$page] ) || !isset( $wp_settings_fields[$page][$section['id']] ) )
-                       continue;
-               echo '<table class="form-table">';
-               do_settings_fields( $page, $section['id'] );
-               echo '</table>';
-       }
-}
-
-/**
- * Print out the settings fields for a particular settings section
- *
- * Part of the Settings API. Use this in a settings page to output
- * a specific section. Should normally be called by do_settings_sections()
- * rather than directly.
- *
- * @global $wp_settings_fields Storage array of settings fields and their pages/sections
- *
- * @since 2.7.0
- *
- * @param string $page Slug title of the admin page who's settings fields you want to show.
- * @param string $section Slug title of the settings section who's fields you want to show.
- */
-function do_settings_fields($page, $section) {
-       global $wp_settings_fields;
-
-       if ( ! isset( $wp_settings_fields[$page][$section] ) )
-               return;
-
-       foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
-               $class = '';
-
-               if ( ! empty( $field['args']['class'] ) ) {
-                       $class = ' class="' . esc_attr( $field['args']['class'] ) . '"';
-               }
-
-               echo "<tr{$class}>";
-
-               if ( ! empty( $field['args']['label_for'] ) ) {
-                       echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
-               } else {
-                       echo '<th scope="row">' . $field['title'] . '</th>';
-               }
-
-               echo '<td>';
-               call_user_func($field['callback'], $field['args']);
-               echo '</td>';
-               echo '</tr>';
-       }
-}
-
-/**
- * Register a settings error to be displayed to the user
- *
- * Part of the Settings API. Use this to show messages to users about settings validation
- * problems, missing settings or anything else.
- *
- * Settings errors should be added inside the $sanitize_callback function defined in
- * register_setting() for a given setting to give feedback about the submission.
- *
- * By default messages will show immediately after the submission that generated the error.
- * Additional calls to settings_errors() can be used to show errors even when the settings
- * page is first accessed.
- *
- * @since 3.0.0
- *
- * @global array $wp_settings_errors Storage array of errors registered during this pageload
- *
- * @param string $setting Slug title of the setting to which this error applies
- * @param string $code    Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
- * @param string $message The formatted message text to display to the user (will be shown inside styled
- *                        `<div>` and `<p>` tags).
- * @param string $type    Optional. Message type, controls HTML class. Accepts 'error' or 'updated'.
- *                        Default 'error'.
- */
-function add_settings_error( $setting, $code, $message, $type = 'error' ) {
-       global $wp_settings_errors;
-
-       $wp_settings_errors[] = array(
-               'setting' => $setting,
-               'code'    => $code,
-               'message' => $message,
-               'type'    => $type
-       );
-}
-
-/**
- * Fetch settings errors registered by add_settings_error()
- *
- * Checks the $wp_settings_errors array for any errors declared during the current
- * pageload and returns them.
- *
- * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
- * to the 'settings_errors' transient then those errors will be returned instead. This
- * is used to pass errors back across pageloads.
- *
- * Use the $sanitize argument to manually re-sanitize the option before returning errors.
- * This is useful if you have errors or notices you want to show even when the user
- * hasn't submitted data (i.e. when they first load an options page, or in admin_notices action hook)
- *
- * @since 3.0.0
- *
- * @global array $wp_settings_errors Storage array of errors registered during this pageload
- *
- * @param string $setting Optional slug title of a specific setting who's errors you want.
- * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
- * @return array Array of settings errors
- */
-function get_settings_errors( $setting = '', $sanitize = false ) {
-       global $wp_settings_errors;
-
-       /*
-        * If $sanitize is true, manually re-run the sanitization for this option
-        * This allows the $sanitize_callback from register_setting() to run, adding
-        * any settings errors you want to show by default.
-        */
-       if ( $sanitize )
-               sanitize_option( $setting, get_option( $setting ) );
-
-       // If settings were passed back from options.php then use them.
-       if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
-               $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
-               delete_transient( 'settings_errors' );
-       }
-
-       // Check global in case errors have been added on this pageload.
-       if ( ! count( $wp_settings_errors ) )
-               return array();
-
-       // Filter the results to those of a specific setting if one was set.
-       if ( $setting ) {
-               $setting_errors = array();
-               foreach ( (array) $wp_settings_errors as $key => $details ) {
-                       if ( $setting == $details['setting'] )
-                               $setting_errors[] = $wp_settings_errors[$key];
-               }
-               return $setting_errors;
-       }
-
-       return $wp_settings_errors;
-}
-
-/**
- * Display settings errors registered by {@see add_settings_error()}.
- *
- * Part of the Settings API. Outputs a div for each error retrieved by
- * {@see get_settings_errors()}.
- *
- * This is called automatically after a settings page based on the
- * Settings API is submitted. Errors should be added during the validation
- * callback function for a setting defined in {@see register_setting()}
- *
- * The $sanitize option is passed into {@see get_settings_errors()} and will
- * re-run the setting sanitization
- * on its current value.
- *
- * The $hide_on_update option will cause errors to only show when the settings
- * page is first loaded. if the user has already saved new values it will be
- * hidden to avoid repeating messages already shown in the default error
- * reporting after submission. This is useful to show general errors like
- * missing settings when the user arrives at the settings page.
- *
- * @since 3.0.0
- *
- * @param string $setting        Optional slug title of a specific setting who's errors you want.
- * @param bool   $sanitize       Whether to re-sanitize the setting value before returning errors.
- * @param bool   $hide_on_update If set to true errors will not be shown if the settings page has already been submitted.
- */
-function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
-
-       if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
-               return;
-
-       $settings_errors = get_settings_errors( $setting, $sanitize );
-
-       if ( empty( $settings_errors ) )
-               return;
-
-       $output = '';
-       foreach ( $settings_errors as $key => $details ) {
-               $css_id = 'setting-error-' . $details['code'];
-               $css_class = $details['type'] . ' settings-error notice is-dismissible';
-               $output .= "<div id='$css_id' class='$css_class'> \n";
-               $output .= "<p><strong>{$details['message']}</strong></p>";
-               $output .= "</div> \n";
-       }
-       echo $output;
-}
-
-/**
- * Outputs the modal window used for attaching media to posts or pages in the media-listing screen.
- *
- * @since 2.7.0
- *
- * @param string $found_action
- */
-function find_posts_div($found_action = '') {
-?>
-       <div id="find-posts" class="find-box" style="display: none;">
-               <div id="find-posts-head" class="find-box-head">
-                       <?php _e( 'Find Posts or Pages' ); ?>
-                       <div id="find-posts-close"></div>
-               </div>
-               <div class="find-box-inside">
-                       <div class="find-box-search">
-                               <?php if ( $found_action ) { ?>
-                                       <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
-                               <?php } ?>
-                               <input type="hidden" name="affected" id="affected" value="" />
-                               <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
-                               <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
-                               <input type="text" id="find-posts-input" name="ps" value="" />
-                               <span class="spinner"></span>
-                               <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
-                               <div class="clear"></div>
-                       </div>
-                       <div id="find-posts-response"></div>
-               </div>
-               <div class="find-box-buttons">
-                       <?php submit_button( __( 'Select' ), 'button-primary alignright', 'find-posts-submit', false ); ?>
-                       <div class="clear"></div>
-               </div>
-       </div>
-<?php
-}
-
-/**
- * Display the post password.
- *
- * The password is passed through {@link esc_attr()} to ensure that it
- * is safe for placing in an html attribute.
- *
- * @since 2.7.0
- */
-function the_post_password() {
-       $post = get_post();
-       if ( isset( $post->post_password ) )
-               echo esc_attr( $post->post_password );
-}
-
-/**
- * Get the post title.
- *
- * The post title is fetched and if it is blank then a default string is
- * returned.
- *
- * @since 2.7.0
- *
- * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
- * @return string The post title if set.
- */
-function _draft_or_post_title( $post = 0 ) {
-       $title = get_the_title( $post );
-       if ( empty( $title ) )
-               $title = __( '(no title)' );
-       return esc_html( $title );
-}
-
-/**
- * Display the search query.
- *
- * A simple wrapper to display the "s" parameter in a GET URI. This function
- * should only be used when {@link the_search_query()} cannot.
- *
- * @since 2.7.0
- */
-function _admin_search_query() {
-       echo isset($_REQUEST['s']) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
-}
-
-/**
- * Generic Iframe header for use with Thickbox
- *
- * @since 2.7.0
- *
- * @global string    $hook_suffix
- * @global string    $admin_body_class
- * @global WP_Locale $wp_locale
- *
- * @param string $title      Optional. Title of the Iframe page. Default empty.
- * @param bool   $deprecated Not used.
- */
-function iframe_header( $title = '', $deprecated = false ) {
-       show_admin_bar( false );
-       global $hook_suffix, $admin_body_class, $wp_locale;
-       $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
-
-       $current_screen = get_current_screen();
-
-       @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
-       _wp_admin_html_begin();
-?>
-<title><?php bloginfo('name') ?> &rsaquo; <?php echo $title ?> &#8212; <?php _e('WordPress'); ?></title>
-<?php
-wp_enqueue_style( 'colors' );
-?>
-<script type="text/javascript">
-addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
-function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
-var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
-       pagenow = '<?php echo $current_screen->id; ?>',
-       typenow = '<?php echo $current_screen->post_type; ?>',
-       adminpage = '<?php echo $admin_body_class; ?>',
-       thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
-       decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
-       isRtl = <?php echo (int) is_rtl(); ?>;
-</script>
-<?php
-/** This action is documented in wp-admin/admin-header.php */
-do_action( 'admin_enqueue_scripts', $hook_suffix );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( "admin_print_styles-$hook_suffix" );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( 'admin_print_styles' );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( "admin_print_scripts-$hook_suffix" );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( 'admin_print_scripts' );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( "admin_head-$hook_suffix" );
-
-/** This action is documented in wp-admin/admin-header.php */
-do_action( 'admin_head' );
-
-$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
-
-if ( is_rtl() )
-       $admin_body_class .= ' rtl';
-
-?>
-</head>
-<?php
-/** This filter is documented in wp-admin/admin-header.php */
-$admin_body_classes = apply_filters( 'admin_body_class', '' );
-?>
-<body<?php
-/**
- * @global string $body_id
- */
-if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin wp-core-ui no-js iframe <?php echo $admin_body_classes . ' ' . $admin_body_class; ?>">
-<script type="text/javascript">
-(function(){
-var c = document.body.className;
-c = c.replace(/no-js/, 'js');
-document.body.className = c;
-})();
-</script>
-<?php
-}
-
-/**
- * Generic Iframe footer for use with Thickbox
- *
- * @since 2.7.0
- */
-function iframe_footer() {
-       /*
-        * We're going to hide any footer output on iFrame pages,
-        * but run the hooks anyway since they output JavaScript
-        * or other needed content.
-        */
-        ?>
-       <div class="hidden">
-<?php
-       /** This action is documented in wp-admin/admin-footer.php */
-       do_action( 'admin_footer', '' );
-
-       /** This action is documented in wp-admin/admin-footer.php */
-       do_action( 'admin_print_footer_scripts' );
-?>
-       </div>
-<script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
-</body>
-</html>
-<?php
-}
-
-/**
- *
- * @param WP_Post $post
- */
-function _post_states($post) {
-       $post_states = array();
-       if ( isset( $_REQUEST['post_status'] ) )
-               $post_status = $_REQUEST['post_status'];
-       else
-               $post_status = '';
-
-       if ( !empty($post->post_password) )
-               $post_states['protected'] = __('Password protected');
-       if ( 'private' == $post->post_status && 'private' != $post_status )
-               $post_states['private'] = __('Private');
-       if ( 'draft' == $post->post_status && 'draft' != $post_status )
-               $post_states['draft'] = __('Draft');
-       if ( 'pending' == $post->post_status && 'pending' != $post_status )
-               /* translators: post state */
-               $post_states['pending'] = _x('Pending', 'post state');
-       if ( is_sticky($post->ID) )
-               $post_states['sticky'] = __('Sticky');
-
-       if ( 'future' === $post->post_status ) {
-               $post_states['scheduled'] = __( 'Scheduled' );
-       }
-
-       if ( 'page' === get_option( 'show_on_front' ) ) {
-               if ( intval( get_option( 'page_on_front' ) ) === $post->ID ) {
-                       $post_states['page_on_front'] = __( 'Front Page' );
-               }
-
-               if ( intval( get_option( 'page_for_posts' ) ) === $post->ID ) {
-                       $post_states['page_for_posts'] = __( 'Posts Page' );
-               }
-       }
-
-       /**
-        * Filter the default post display states used in the posts list table.
-        *
-        * @since 2.8.0
-        *
-        * @param array   $post_states An array of post display states.
-        * @param WP_Post $post        The current post object.
-        */
-       $post_states = apply_filters( 'display_post_states', $post_states, $post );
-
-       if ( ! empty($post_states) ) {
-               $state_count = count($post_states);
-               $i = 0;
-               echo ' &mdash; ';
-               foreach ( $post_states as $state ) {
-                       ++$i;
-                       ( $i == $state_count ) ? $sep = '' : $sep = ', ';
-                       echo "<span class='post-state'>$state$sep</span>";
-               }
-       }
-
-}
-
-/**
- *
- * @param WP_Post $post
- */
-function _media_states( $post ) {
-       $media_states = array();
-       $stylesheet = get_option('stylesheet');
-
-       if ( current_theme_supports( 'custom-header') ) {
-               $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
-               if ( ! empty( $meta_header ) && $meta_header == $stylesheet )
-                       $media_states[] = __( 'Header Image' );
-       }
-
-       if ( current_theme_supports( 'custom-background') ) {
-               $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
-               if ( ! empty( $meta_background ) && $meta_background == $stylesheet )
-                       $media_states[] = __( 'Background Image' );
-       }
-
-       if ( $post->ID == get_option( 'site_icon' ) ) {
-               $media_states[] = __( 'Site Icon' );
-       }
-
-       /**
-        * Filter the default media display states for items in the Media list table.
-        *
-        * @since 3.2.0
-        *
-        * @param array $media_states An array of media states. Default 'Header Image',
-        *                            'Background Image', 'Site Icon'.
-        */
-       $media_states = apply_filters( 'display_media_states', $media_states );
-
-       if ( ! empty( $media_states ) ) {
-               $state_count = count( $media_states );
-               $i = 0;
-               echo ' &mdash; ';
-               foreach ( $media_states as $state ) {
-                       ++$i;
-                       ( $i == $state_count ) ? $sep = '' : $sep = ', ';
-                       echo "<span class='post-state'>$state$sep</span>";
-               }
-       }
-}
-
-/**
- * Test support for compressing JavaScript from PHP
- *
- * Outputs JavaScript that tests if compression from PHP works as expected
- * and sets an option with the result. Has no effect when the current user
- * is not an administrator. To run the test again the option 'can_compress_scripts'
- * has to be deleted.
- *
- * @since 2.8.0
- */
-function compression_test() {
-?>
-       <script type="text/javascript">
-       var testCompression = {
-               get : function(test) {
-                       var x;
-                       if ( window.XMLHttpRequest ) {
-                               x = new XMLHttpRequest();
-                       } else {
-                               try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
-                       }
-
-                       if (x) {
-                               x.onreadystatechange = function() {
-                                       var r, h;
-                                       if ( x.readyState == 4 ) {
-                                               r = x.responseText.substr(0, 18);
-                                               h = x.getResponseHeader('Content-Encoding');
-                                               testCompression.check(r, h, test);
-                                       }
-                               };
-
-                               x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&'+(new Date()).getTime(), true);
-                               x.send('');
-                       }
-               },
-
-               check : function(r, h, test) {
-                       if ( ! r && ! test )
-                               this.get(1);
-
-                       if ( 1 == test ) {
-                               if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
-                                       this.get('no');
-                               else
-                                       this.get(2);
-
-                               return;
-                       }
-
-                       if ( 2 == test ) {
-                               if ( '"wpCompressionTest' == r )
-                                       this.get('yes');
-                               else
-                                       this.get('no');
-                       }
-               }
-       };
-       testCompression.check();
-       </script>
-<?php
-}
-
-/**
- * Echoes a submit button, with provided text and appropriate class(es).
- *
- * @since 3.1.0
- *
- * @see get_submit_button()
- *
- * @param string       $text             The text of the button (defaults to 'Save Changes')
- * @param string       $type             Optional. The type and CSS class(es) of the button. Core values
- *                                       include 'primary', 'secondary', 'delete'. Default 'primary'
- * @param string       $name             The HTML name of the submit button. Defaults to "submit". If no
- *                                       id attribute is given in $other_attributes below, $name will be
- *                                       used as the button's id.
- * @param bool         $wrap             True if the output button should be wrapped in a paragraph tag,
- *                                       false otherwise. Defaults to true
- * @param array|string $other_attributes Other attributes that should be output with the button, mapping
- *                                       attributes to their values, such as setting tabindex to 1, etc.
- *                                       These key/value attribute pairs will be output as attribute="value",
- *                                       where attribute is the key. Other attributes can also be provided
- *                                       as a string such as 'tabindex="1"', though the array format is
- *                                       preferred. Default null.
- */
-function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
-       echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
-}
-
-/**
- * Returns a submit button, with provided text and appropriate class
- *
- * @since 3.1.0
- *
- * @param string       $text             Optional. The text of the button. Default 'Save Changes'.
- * @param string       $type             Optional. The type of button. Accepts 'primary', 'secondary',
- *                                       or 'delete'. Default 'primary large'.
- * @param string       $name             Optional. The HTML name of the submit button. Defaults to "submit".
- *                                       If no id attribute is given in $other_attributes below, `$name` will
- *                                       be used as the button's id. Default 'submit'.
- * @param bool         $wrap             Optional. True if the output button should be wrapped in a paragraph
- *                                       tag, false otherwise. Default true.
- * @param array|string $other_attributes Optional. Other attributes that should be output with the button,
- *                                       mapping attributes to their values, such as `array( 'tabindex' => '1' )`.
- *                                       These attributes will be output as `attribute="value"`, such as
- *                                       `tabindex="1"`. Other attributes can also be provided as a string such
- *                                       as `tabindex="1"`, though the array format is typically cleaner.
- *                                       Default empty.
- * @return string Submit button HTML.
- */
-function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) {
-       if ( ! is_array( $type ) )
-               $type = explode( ' ', $type );
-
-       $button_shorthand = array( 'primary', 'small', 'large' );
-       $classes = array( 'button' );
-       foreach ( $type as $t ) {
-               if ( 'secondary' === $t || 'button-secondary' === $t )
-                       continue;
-               $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
-       }
-       $class = implode( ' ', array_unique( $classes ) );
-
-       if ( 'delete' === $type )
-               $class = 'button-secondary delete';
-
-       $text = $text ? $text : __( 'Save Changes' );
-
-       // Default the id attribute to $name unless an id was specifically provided in $other_attributes
-       $id = $name;
-       if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
-               $id = $other_attributes['id'];
-               unset( $other_attributes['id'] );
-       }
-
-       $attributes = '';
-       if ( is_array( $other_attributes ) ) {
-               foreach ( $other_attributes as $attribute => $value ) {
-                       $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
-               }
-       } elseif ( ! empty( $other_attributes ) ) { // Attributes provided as a string
-               $attributes = $other_attributes;
-       }
-
-       // Don't output empty name and id attributes.
-       $name_attr = $name ? ' name="' . esc_attr( $name ) . '"' : '';
-       $id_attr = $id ? ' id="' . esc_attr( $id ) . '"' : '';
-
-       $button = '<input type="submit"' . $name_attr . $id_attr . ' class="' . esc_attr( $class );
-       $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
-
-       if ( $wrap ) {
-               $button = '<p class="submit">' . $button . '</p>';
-       }
-
-       return $button;
-}
-
-/**
- *
- * @global bool $is_IE
- */
-function _wp_admin_html_begin() {
-       global $is_IE;
-
-       $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
-
-       if ( $is_IE )
-               @header('X-UA-Compatible: IE=edge');
-
-?>
-<!DOCTYPE html>
-<!--[if IE 8]>
-<html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php
-       /**
-        * Fires inside the HTML tag in the admin header.
-        *
-        * @since 2.2.0
-        */
-       do_action( 'admin_xml_ns' );
-?> <?php language_attributes(); ?>>
-<![endif]-->
-<!--[if !(IE 8) ]><!-->
-<html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php
-       /** This action is documented in wp-admin/includes/template-functions.php */
-       do_action( 'admin_xml_ns' );
-?> <?php language_attributes(); ?>>
-<!--<![endif]-->
-<head>
-<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
-<?php
-}
-
-/**
- * Convert a screen string to a screen object
- *
- * @since 3.0.0
- *
- * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
- * @return WP_Screen Screen object.
- */
-function convert_to_screen( $hook_name ) {
-       if ( ! class_exists( 'WP_Screen', false ) ) {
-               _doing_it_wrong( 'convert_to_screen(), add_meta_box()', __( "Likely direct inclusion of wp-admin/includes/template.php in order to use add_meta_box(). This is very wrong. Hook the add_meta_box() call into the add_meta_boxes action instead." ), '3.3' );
-               return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
-       }
-
-       return WP_Screen::get( $hook_name );
-}
-
-/**
- * Output the HTML for restoring the post data from DOM storage
- *
- * @since 3.6.0
- * @access private
- */
-function _local_storage_notice() {
-       ?>
-       <div id="local-storage-notice" class="hidden notice">
-       <p class="local-restore">
-               <?php _e('The backup of this post in your browser is different from the version below.'); ?>
-               <a class="restore-backup" href="#"><?php _e('Restore the backup.'); ?></a>
-       </p>
-       <p class="undo-restore hidden">
-               <?php _e('Post restored successfully.'); ?>
-               <a class="undo-restore-backup" href="#"><?php _e('Undo.'); ?></a>
-       </p>
-       </div>
-       <?php
-}
-
-/**
- * Output a HTML element with a star rating for a given rating.
- *
- * Outputs a HTML element with the star rating exposed on a 0..5 scale in
- * half star increments (ie. 1, 1.5, 2 stars). Optionally, if specified, the
- * number of ratings may also be displayed by passing the $number parameter.
- *
- * @since 3.8.0
- * @since 4.4.0 Introduced the `echo` parameter.
- *
- * @param array $args {
- *     Optional. Array of star ratings arguments.
- *
- *     @type int    $rating The rating to display, expressed in either a 0.5 rating increment,
- *                          or percentage. Default 0.
- *     @type string $type   Format that the $rating is in. Valid values are 'rating' (default),
- *                          or, 'percent'. Default 'rating'.
- *     @type int    $number The number of ratings that makes up this rating. Default 0.
- *     @type bool   $echo   Whether to echo the generated markup. False to return the markup instead
- *                          of echoing it. Default true.
- * }
- */
-function wp_star_rating( $args = array() ) {
-       $defaults = array(
-               'rating' => 0,
-               'type'   => 'rating',
-               'number' => 0,
-               'echo'   => true,
-       );
-       $r = wp_parse_args( $args, $defaults );
-
-       // Non-english decimal places when the $rating is coming from a string
-       $rating = str_replace( ',', '.', $r['rating'] );
-
-       // Convert Percentage to star rating, 0..5 in .5 increments
-       if ( 'percent' == $r['type'] ) {
-               $rating = round( $rating / 10, 0 ) / 2;
-       }
-
-       // Calculate the number of each type of star needed
-       $full_stars = floor( $rating );
-       $half_stars = ceil( $rating - $full_stars );
-       $empty_stars = 5 - $full_stars - $half_stars;
-
-       if ( $r['number'] ) {
-               /* translators: 1: The rating, 2: The number of ratings */
-               $format = _n( '%1$s rating based on %2$s rating', '%1$s rating based on %2$s ratings', $r['number'] );
-               $title = sprintf( $format, number_format_i18n( $rating, 1 ), number_format_i18n( $r['number'] ) );
-       } else {
-               /* translators: 1: The rating */
-               $title = sprintf( __( '%s rating' ), number_format_i18n( $rating, 1 ) );
-       }
-
-       $output = '<div class="star-rating" title="' . esc_attr( $title ) . '">';
-       $output .= '<span class="screen-reader-text">' . $title . '</span>';
-       $output .= str_repeat( '<div class="star star-full"></div>', $full_stars );
-       $output .= str_repeat( '<div class="star star-half"></div>', $half_stars );
-       $output .= str_repeat( '<div class="star star-empty"></div>', $empty_stars );
-       $output .= '</div>';
-
-       if ( $r['echo'] ) {
-               echo $output;
-       }
-
-       return $output;
-}
-
-/**
- * Output a notice when editing the page for posts (internal use only).
- *
- * @ignore
- * @since 4.2.0
- */
-function _wp_posts_page_notice() {
-       echo '<div class="notice notice-warning inline"><p>' . __( 'You are currently editing the page that shows your latest posts.' ) . '</p></div>';
-}
</del></span></pre></div>
<a id="trunksrcwpadminincludestemplatephp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-admin/includes/template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/template.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-admin/includes/template.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,18 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Template WordPress Administration API.
- *
- * A Big Mess. Also some neat functions that are nicely written.
- *
- * @package WordPress
- * @subpackage Administration
- */
-
-/** Walker_Category_Checklist class */
-require_once( ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php' );
-
-/** WP_Internal_Pointers class */
-require_once( ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php' );
-
-/** Admin template functionality */
-require_once( ABSPATH . 'wp-admin/includes/template-functions.php' );
</del></span></pre></div>
<a id="trunksrcwpadminincludestemplatephpfromrev35717trunksrcwpadminincludestemplatefunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-admin/includes/template.php (from rev 35717, trunk/src/wp-admin/includes/template-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/template.php                          (rev 0)
+++ trunk/src/wp-admin/includes/template.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,2073 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Template WordPress Administration API.
+ *
+ * A Big Mess. Also some neat functions that are nicely written.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+//
+// Category Checklists
+//
+
+/**
+ * Output an unordered list of checkbox input elements labeled with category names.
+ *
+ * @since 2.5.1
+ *
+ * @see wp_terms_checklist()
+ *
+ * @param int    $post_id              Optional. Post to generate a categories checklist for. Default 0.
+ *                                     $selected_cats must not be an array. Default 0.
+ * @param int    $descendants_and_self Optional. ID of the category to output along with its descendants.
+ *                                     Default 0.
+ * @param array  $selected_cats        Optional. List of categories to mark as checked. Default false.
+ * @param array  $popular_cats         Optional. List of categories to receive the "popular-category" class.
+ *                                     Default false.
+ * @param object $walker               Optional. Walker object to use to build the output.
+ *                                     Default is a Walker_Category_Checklist instance.
+ * @param bool   $checked_ontop        Optional. Whether to move checked items out of the hierarchy and to
+ *                                     the top of the list. Default true.
+ */
+function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) {
+       wp_terms_checklist( $post_id, array(
+               'taxonomy' => 'category',
+               'descendants_and_self' => $descendants_and_self,
+               'selected_cats' => $selected_cats,
+               'popular_cats' => $popular_cats,
+               'walker' => $walker,
+               'checked_ontop' => $checked_ontop
+       ) );
+}
+
+/**
+ * Output an unordered list of checkbox input elements labelled with term names.
+ *
+ * Taxonomy-independent version of wp_category_checklist().
+ *
+ * @since 3.0.0
+ * @since 4.4.0 Introduced the `$echo` argument.
+ *
+ * @param int          $post_id Optional. Post ID. Default 0.
+ * @param array|string $args {
+ *     Optional. Array or string of arguments for generating a terms checklist. Default empty array.
+ *
+ *     @type int    $descendants_and_self ID of the category to output along with its descendants.
+ *                                        Default 0.
+ *     @type array  $selected_cats        List of categories to mark as checked. Default false.
+ *     @type array  $popular_cats         List of categories to receive the "popular-category" class.
+ *                                        Default false.
+ *     @type object $walker               Walker object to use to build the output.
+ *                                        Default is a Walker_Category_Checklist instance.
+ *     @type string $taxonomy             Taxonomy to generate the checklist for. Default 'category'.
+ *     @type bool   $checked_ontop        Whether to move checked items out of the hierarchy and to
+ *                                        the top of the list. Default true.
+ *     @type bool   $echo                 Whether to echo the generated markup. False to return the markup instead
+ *                                        of echoing it. Default true.
+ * }
+ */
+function wp_terms_checklist( $post_id = 0, $args = array() ) {
+       $defaults = array(
+               'descendants_and_self' => 0,
+               'selected_cats' => false,
+               'popular_cats' => false,
+               'walker' => null,
+               'taxonomy' => 'category',
+               'checked_ontop' => true,
+               'echo' => true,
+       );
+
+       /**
+        * Filter the taxonomy terms checklist arguments.
+        *
+        * @since 3.4.0
+        *
+        * @see wp_terms_checklist()
+        *
+        * @param array $args    An array of arguments.
+        * @param int   $post_id The post ID.
+        */
+       $params = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
+
+       $r = wp_parse_args( $params, $defaults );
+
+       if ( empty( $r['walker'] ) || ! ( $r['walker'] instanceof Walker ) ) {
+               $walker = new Walker_Category_Checklist;
+       } else {
+               $walker = $r['walker'];
+       }
+
+       $taxonomy = $r['taxonomy'];
+       $descendants_and_self = (int) $r['descendants_and_self'];
+
+       $args = array( 'taxonomy' => $taxonomy );
+
+       $tax = get_taxonomy( $taxonomy );
+       $args['disabled'] = ! current_user_can( $tax->cap->assign_terms );
+
+       $args['list_only'] = ! empty( $r['list_only'] );
+
+       if ( is_array( $r['selected_cats'] ) ) {
+               $args['selected_cats'] = $r['selected_cats'];
+       } elseif ( $post_id ) {
+               $args['selected_cats'] = wp_get_object_terms( $post_id, $taxonomy, array_merge( $args, array( 'fields' => 'ids' ) ) );
+       } else {
+               $args['selected_cats'] = array();
+       }
+       if ( is_array( $r['popular_cats'] ) ) {
+               $args['popular_cats'] = $r['popular_cats'];
+       } else {
+               $args['popular_cats'] = get_terms( $taxonomy, array(
+                       'fields' => 'ids',
+                       'orderby' => 'count',
+                       'order' => 'DESC',
+                       'number' => 10,
+                       'hierarchical' => false
+               ) );
+       }
+       if ( $descendants_and_self ) {
+               $categories = (array) get_terms( $taxonomy, array(
+                       'child_of' => $descendants_and_self,
+                       'hierarchical' => 0,
+                       'hide_empty' => 0
+               ) );
+               $self = get_term( $descendants_and_self, $taxonomy );
+               array_unshift( $categories, $self );
+       } else {
+               $categories = (array) get_terms( $taxonomy, array( 'get' => 'all' ) );
+       }
+
+       $output = '';
+
+       if ( $r['checked_ontop'] ) {
+               // Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
+               $checked_categories = array();
+               $keys = array_keys( $categories );
+
+               foreach ( $keys as $k ) {
+                       if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
+                               $checked_categories[] = $categories[$k];
+                               unset( $categories[$k] );
+                       }
+               }
+
+               // Put checked cats on top
+               $output .= call_user_func_array( array( $walker, 'walk' ), array( $checked_categories, 0, $args ) );
+       }
+       // Then the rest of them
+       $output .= call_user_func_array( array( $walker, 'walk' ), array( $categories, 0, $args ) );
+
+       if ( $r['echo'] ) {
+               echo $output;
+       }
+
+       return $output;
+}
+
+/**
+ * Retrieve a list of the most popular terms from the specified taxonomy.
+ *
+ * If the $echo argument is true then the elements for a list of checkbox
+ * `<input>` elements labelled with the names of the selected terms is output.
+ * If the $post_ID global isn't empty then the terms associated with that
+ * post will be marked as checked.
+ *
+ * @since 2.5.0
+ *
+ * @param string $taxonomy Taxonomy to retrieve terms from.
+ * @param int $default Not used.
+ * @param int $number Number of terms to retrieve. Defaults to 10.
+ * @param bool $echo Optionally output the list as well. Defaults to true.
+ * @return array List of popular term IDs.
+ */
+function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
+       $post = get_post();
+
+       if ( $post && $post->ID )
+               $checked_terms = wp_get_object_terms($post->ID, $taxonomy, array('fields'=>'ids'));
+       else
+               $checked_terms = array();
+
+       $terms = get_terms( $taxonomy, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false ) );
+
+       $tax = get_taxonomy($taxonomy);
+
+       $popular_ids = array();
+       foreach ( (array) $terms as $term ) {
+               $popular_ids[] = $term->term_id;
+               if ( !$echo ) // hack for AJAX use
+                       continue;
+               $id = "popular-$taxonomy-$term->term_id";
+               $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
+               ?>
+
+               <li id="<?php echo $id; ?>" class="popular-category">
+                       <label class="selectit">
+                               <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php disabled( ! current_user_can( $tax->cap->assign_terms ) ); ?> />
+                               <?php
+                               /** This filter is documented in wp-includes/category-template.php */
+                               echo esc_html( apply_filters( 'the_category', $term->name ) );
+                               ?>
+                       </label>
+               </li>
+
+               <?php
+       }
+       return $popular_ids;
+}
+
+/**
+ * Outputs a link category checklist element.
+ *
+ * @since 2.5.1
+ *
+ * @param int $link_id
+ */
+function wp_link_category_checklist( $link_id = 0 ) {
+       $default = 1;
+
+       $checked_categories = array();
+
+       if ( $link_id ) {
+               $checked_categories = wp_get_link_cats( $link_id );
+               // No selected categories, strange
+               if ( ! count( $checked_categories ) ) {
+                       $checked_categories[] = $default;
+               }
+       } else {
+               $checked_categories[] = $default;
+       }
+
+       $categories = get_terms( 'link_category', array( 'orderby' => 'name', 'hide_empty' => 0 ) );
+
+       if ( empty( $categories ) )
+               return;
+
+       foreach ( $categories as $category ) {
+               $cat_id = $category->term_id;
+
+               /** This filter is documented in wp-includes/category-template.php */
+               $name = esc_html( apply_filters( 'the_category', $category->name ) );
+               $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
+               echo '<li id="link-category-', $cat_id, '"><label for="in-link-category-', $cat_id, '" class="selectit"><input value="', $cat_id, '" type="checkbox" name="link_category[]" id="in-link-category-', $cat_id, '"', $checked, '/> ', $name, "</label></li>";
+       }
+}
+
+/**
+ * Adds hidden fields with the data for use in the inline editor for posts and pages.
+ *
+ * @since 2.7.0
+ *
+ * @param WP_Post $post Post object.
+ */
+function get_inline_data($post) {
+       $post_type_object = get_post_type_object($post->post_type);
+       if ( ! current_user_can( 'edit_post', $post->ID ) )
+               return;
+
+       $title = esc_textarea( trim( $post->post_title ) );
+
+       /** This filter is documented in wp-admin/edit-tag-form.php */
+       echo '
+<div class="hidden" id="inline_' . $post->ID . '">
+       <div class="post_title">' . $title . '</div>' .
+       /** This filter is documented in wp-admin/edit-tag-form.php */
+       '<div class="post_name">' . apply_filters( 'editable_slug', $post->post_name, $post ) . '</div>
+       <div class="post_author">' . $post->post_author . '</div>
+       <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
+       <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
+       <div class="_status">' . esc_html( $post->post_status ) . '</div>
+       <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
+       <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
+       <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
+       <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
+       <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
+       <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
+       <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
+
+       if ( $post_type_object->hierarchical )
+               echo '<div class="post_parent">' . $post->post_parent . '</div>';
+
+       if ( $post->post_type == 'page' )
+               echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
+
+       if ( post_type_supports( $post->post_type, 'page-attributes' ) )
+               echo '<div class="menu_order">' . $post->menu_order . '</div>';
+
+       $taxonomy_names = get_object_taxonomies( $post->post_type );
+       foreach ( $taxonomy_names as $taxonomy_name) {
+               $taxonomy = get_taxonomy( $taxonomy_name );
+
+               if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
+
+                       $terms = get_object_term_cache( $post->ID, $taxonomy_name );
+                       if ( false === $terms ) {
+                               $terms = wp_get_object_terms( $post->ID, $taxonomy_name );
+                               wp_cache_add( $post->ID, $terms, $taxonomy_name . '_relationships' );
+                       }
+                       $term_ids = empty( $terms ) ? array() : wp_list_pluck( $terms, 'term_id' );
+
+                       echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">' . implode( ',', $term_ids ) . '</div>';
+
+               } elseif ( $taxonomy->show_ui ) {
+
+                       $terms_to_edit = get_terms_to_edit( $post->ID, $taxonomy_name );
+                       if ( ! is_string( $terms_to_edit ) ) {
+                               $terms_to_edit = '';
+                       }
+
+                       echo '<div class="tags_input" id="'.$taxonomy_name.'_'.$post->ID.'">'
+                               . esc_html( str_replace( ',', ', ', $terms_to_edit ) ) . '</div>';
+
+               }
+       }
+
+       if ( !$post_type_object->hierarchical )
+               echo '<div class="sticky">' . (is_sticky($post->ID) ? 'sticky' : '') . '</div>';
+
+       if ( post_type_supports( $post->post_type, 'post-formats' ) )
+               echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
+
+       echo '</div>';
+}
+
+/**
+ * Outputs the in-line comment reply-to form in the Comments list table.
+ *
+ * @since 2.7.0
+ *
+ * @global WP_List_Table $wp_list_table
+ *
+ * @param int    $position
+ * @param bool   $checkbox
+ * @param string $mode
+ * @param bool   $table_row
+ */
+function wp_comment_reply( $position = 1, $checkbox = false, $mode = 'single', $table_row = true ) {
+       global $wp_list_table;
+       /**
+        * Filter the in-line comment reply-to form output in the Comments
+        * list table.
+        *
+        * Returning a non-empty value here will short-circuit display
+        * of the in-line comment-reply form in the Comments list table,
+        * echoing the returned value instead.
+        *
+        * @since 2.7.0
+        *
+        * @see wp_comment_reply()
+        *
+        * @param string $content The reply-to form content.
+        * @param array  $args    An array of default args.
+        */
+       $content = apply_filters( 'wp_comment_reply', '', array( 'position' => $position, 'checkbox' => $checkbox, 'mode' => $mode ) );
+
+       if ( ! empty($content) ) {
+               echo $content;
+               return;
+       }
+
+       if ( ! $wp_list_table ) {
+               if ( $mode == 'single' ) {
+                       $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
+               } else {
+                       $wp_list_table = _get_list_table('WP_Comments_List_Table');
+               }
+       }
+
+?>
+<form method="get">
+<?php if ( $table_row ) : ?>
+<table style="display:none;"><tbody id="com-reply"><tr id="replyrow" class="inline-edit-row" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange">
+<?php else : ?>
+<div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
+<?php endif; ?>
+       <fieldset class="comment-reply">
+       <legend>
+               <span class="hidden" id="editlegend"><?php _e( 'Edit Comment' ); ?></span>
+               <span class="hidden" id="replyhead"><?php _e( 'Reply to Comment' ); ?></span>
+               <span class="hidden" id="addhead"><?php _e( 'Add new Comment' ); ?></span>
+       </legend>
+
+       <div id="replycontainer">
+       <label for="replycontent" class="screen-reader-text"><?php _e( 'Comment' ); ?></label>
+       <?php
+       $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
+       wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
+       ?>
+       </div>
+
+       <div id="edithead" style="display:none;">
+               <div class="inside">
+               <label for="author-name"><?php _e( 'Name' ) ?></label>
+               <input type="text" name="newcomment_author" size="50" value="" id="author-name" />
+               </div>
+
+               <div class="inside">
+               <label for="author-email"><?php _e('Email') ?></label>
+               <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
+               </div>
+
+               <div class="inside">
+               <label for="author-url"><?php _e('URL') ?></label>
+               <input type="text" id="author-url" name="newcomment_author_url" class="code" size="103" value="" />
+               </div>
+       </div>
+
+       <p id="replysubmit" class="submit">
+       <a href="#comments-form" class="save button-primary alignright">
+       <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
+       <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
+       <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
+       <a href="#comments-form" class="cancel button-secondary alignleft"><?php _e('Cancel'); ?></a>
+       <span class="waiting spinner"></span>
+       <span class="error" style="display:none;"></span>
+       </p>
+
+       <input type="hidden" name="action" id="action" value="" />
+       <input type="hidden" name="comment_ID" id="comment_ID" value="" />
+       <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
+       <input type="hidden" name="status" id="status" value="" />
+       <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
+       <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
+       <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr($mode); ?>" />
+       <?php
+               wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
+               if ( current_user_can( 'unfiltered_html' ) )
+                       wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
+       ?>
+       </fieldset>
+<?php if ( $table_row ) : ?>
+</td></tr></tbody></table>
+<?php else : ?>
+</div></div>
+<?php endif; ?>
+</form>
+<?php
+}
+
+/**
+ * Output 'undo move to trash' text for comments
+ *
+ * @since 2.9.0
+ */
+function wp_comment_trashnotice() {
+?>
+<div class="hidden" id="trash-undo-holder">
+       <div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
+</div>
+<div class="hidden" id="spam-undo-holder">
+       <div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
+</div>
+<?php
+}
+
+/**
+ * Outputs a post's public meta data in the Custom Fields meta box.
+ *
+ * @since 1.2.0
+ *
+ * @param array $meta
+ */
+function list_meta( $meta ) {
+       // Exit if no meta
+       if ( ! $meta ) {
+               echo '
+<table id="list-table" style="display: none;">
+       <thead>
+       <tr>
+               <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
+               <th>' . __( 'Value' ) . '</th>
+       </tr>
+       </thead>
+       <tbody id="the-list" data-wp-lists="list:meta">
+       <tr><td></td></tr>
+       </tbody>
+</table>'; //TBODY needed for list-manipulation JS
+               return;
+       }
+       $count = 0;
+?>
+<table id="list-table">
+       <thead>
+       <tr>
+               <th class="left"><?php _ex( 'Name', 'meta name' ) ?></th>
+               <th><?php _e( 'Value' ) ?></th>
+       </tr>
+       </thead>
+       <tbody id='the-list' data-wp-lists='list:meta'>
+<?php
+       foreach ( $meta as $entry )
+               echo _list_meta_row( $entry, $count );
+?>
+       </tbody>
+</table>
+<?php
+}
+
+/**
+ * Outputs a single row of public meta data in the Custom Fields meta box.
+ *
+ * @since 2.5.0
+ *
+ * @staticvar string $update_nonce
+ *
+ * @param array $entry
+ * @param int   $count
+ * @return string
+ */
+function _list_meta_row( $entry, &$count ) {
+       static $update_nonce = '';
+
+       if ( is_protected_meta( $entry['meta_key'], 'post' ) )
+               return '';
+
+       if ( ! $update_nonce )
+               $update_nonce = wp_create_nonce( 'add-meta' );
+
+       $r = '';
+       ++ $count;
+
+       if ( is_serialized( $entry['meta_value'] ) ) {
+               if ( is_serialized_string( $entry['meta_value'] ) ) {
+                       // This is a serialized string, so we should display it.
+                       $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
+               } else {
+                       // This is a serialized array/object so we should NOT display it.
+                       --$count;
+                       return '';
+               }
+       }
+
+       $entry['meta_key'] = esc_attr($entry['meta_key']);
+       $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // using a <textarea />
+       $entry['meta_id'] = (int) $entry['meta_id'];
+
+       $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
+
+       $r .= "\n\t<tr id='meta-{$entry['meta_id']}'>";
+       $r .= "\n\t\t<td class='left'><label class='screen-reader-text' for='meta-{$entry['meta_id']}-key'>" . __( 'Key' ) . "</label><input name='meta[{$entry['meta_id']}][key]' id='meta-{$entry['meta_id']}-key' type='text' size='20' value='{$entry['meta_key']}' />";
+
+       $r .= "\n\t\t<div class='submit'>";
+       $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) );
+       $r .= "\n\t\t";
+       $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) );
+       $r .= "</div>";
+       $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
+       $r .= "</td>";
+
+       $r .= "\n\t\t<td><label class='screen-reader-text' for='meta-{$entry['meta_id']}-value'>" . __( 'Value' ) . "</label><textarea name='meta[{$entry['meta_id']}][value]' id='meta-{$entry['meta_id']}-value' rows='2' cols='30'>{$entry['meta_value']}</textarea></td>\n\t</tr>";
+       return $r;
+}
+
+/**
+ * Prints the form in the Custom Fields meta box.
+ *
+ * @since 1.2.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param WP_Post $post Optional. The post being edited.
+ */
+function meta_form( $post = null ) {
+       global $wpdb;
+       $post = get_post( $post );
+
+       /**
+        * Filter values for the meta key dropdown in the Custom Fields meta box.
+        *
+        * Returning a non-null value will effectively short-circuit and avoid a
+        * potentially expensive query against postmeta.
+        *
+        * @since 4.4.0
+        *
+        * @param array|null $keys Pre-defined meta keys to be used in place of a postmeta query. Default null.
+        */
+       $keys = apply_filters( 'postmeta_form_keys', null );
+
+       if ( null === $keys ) {
+               /**
+                * Filter the number of custom fields to retrieve for the drop-down
+                * in the Custom Fields meta box.
+                *
+                * @since 2.1.0
+                *
+                * @param int $limit Number of custom fields to retrieve. Default 30.
+                */
+               $limit = apply_filters( 'postmeta_form_limit', 30 );
+               $sql = "SELECT DISTINCT meta_key
+                       FROM $wpdb->postmeta
+                       WHERE meta_key NOT BETWEEN '_' AND '_z'
+                       HAVING meta_key NOT LIKE %s
+                       ORDER BY meta_key
+                       LIMIT %d";
+               $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
+       }
+
+       if ( $keys ) {
+               natcasesort( $keys );
+               $meta_key_input_id = 'metakeyselect';
+       } else {
+               $meta_key_input_id = 'metakeyinput';
+       }
+?>
+<p><strong><?php _e( 'Add New Custom Field:' ) ?></strong></p>
+<table id="newmeta">
+<thead>
+<tr>
+<th class="left"><label for="<?php echo $meta_key_input_id; ?>"><?php _ex( 'Name', 'meta name' ) ?></label></th>
+<th><label for="metavalue"><?php _e( 'Value' ) ?></label></th>
+</tr>
+</thead>
+
+<tbody>
+<tr>
+<td id="newmetaleft" class="left">
+<?php if ( $keys ) { ?>
+<select id="metakeyselect" name="metakeyselect">
+<option value="#NONE#"><?php _e( '&mdash; Select &mdash;' ); ?></option>
+<?php
+
+       foreach ( $keys as $key ) {
+               if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) )
+                       continue;
+               echo "\n<option value='" . esc_attr($key) . "'>" . esc_html($key) . "</option>";
+       }
+?>
+</select>
+<input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
+<a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
+<span id="enternew"><?php _e('Enter new'); ?></span>
+<span id="cancelnew" class="hidden"><?php _e('Cancel'); ?></span></a>
+<?php } else { ?>
+<input type="text" id="metakeyinput" name="metakeyinput" value="" />
+<?php } ?>
+</td>
+<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
+</tr>
+
+<tr><td colspan="2">
+<div class="submit">
+<?php submit_button( __( 'Add Custom Field' ), 'secondary', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta' ) ); ?>
+</div>
+<?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
+</td></tr>
+</tbody>
+</table>
+<?php
+
+}
+
+/**
+ * Print out HTML form date elements for editing post or comment publish date.
+ *
+ * @since 0.71
+ * @since 4.4.0 Converted to use get_comment() instead of the global `$comment`.
+ *
+ * @global WP_Locale  $wp_locale
+ *
+ * @param int|bool $edit      Accepts 1|true for editing the date, 0|false for adding the date.
+ * @param int|bool $for_post  Accepts 1|true for applying the date to a post, 0|false for a comment.
+ * @param int      $tab_index The tabindex attribute to add. Default 0.
+ * @param int|bool $multi     Optional. Whether the additional fields and buttons should be added.
+ *                            Default 0|false.
+ */
+function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
+       global $wp_locale;
+       $post = get_post();
+
+       if ( $for_post )
+               $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
+
+       $tab_index_attribute = '';
+       if ( (int) $tab_index > 0 )
+               $tab_index_attribute = " tabindex=\"$tab_index\"";
+
+       // todo: Remove this?
+       // echo '<label for="timestamp" style="display: block;"><input type="checkbox" class="checkbox" name="edit_date" value="1" id="timestamp"'.$tab_index_attribute.' /> '.__( 'Edit timestamp' ).'</label><br />';
+
+       $time_adj = current_time('timestamp');
+       $post_date = ($for_post) ? $post->post_date : get_comment()->comment_date;
+       $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
+       $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
+       $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
+       $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
+       $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
+       $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
+
+       $cur_jj = gmdate( 'd', $time_adj );
+       $cur_mm = gmdate( 'm', $time_adj );
+       $cur_aa = gmdate( 'Y', $time_adj );
+       $cur_hh = gmdate( 'H', $time_adj );
+       $cur_mn = gmdate( 'i', $time_adj );
+
+       $month = '<label><span class="screen-reader-text">' . __( 'Month' ) . '</span><select ' . ( $multi ? '' : 'id="mm" ' ) . 'name="mm"' . $tab_index_attribute . ">\n";
+       for ( $i = 1; $i < 13; $i = $i +1 ) {
+               $monthnum = zeroise($i, 2);
+               $monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) );
+               $month .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $mm, false ) . '>';
+               /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
+               $month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $monthtext ) . "</option>\n";
+       }
+       $month .= '</select></label>';
+
+       $day = '<label><span class="screen-reader-text">' . __( 'Day' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
+       $year = '<label><span class="screen-reader-text">' . __( 'Year' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" /></label>';
+       $hour = '<label><span class="screen-reader-text">' . __( 'Hour' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
+       $minute = '<label><span class="screen-reader-text">' . __( 'Minute' ) . '</span><input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" /></label>';
+
+       echo '<div class="timestamp-wrap">';
+       /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
+       printf( __( '%1$s %2$s, %3$s @ %4$s:%5$s' ), $month, $day, $year, $hour, $minute );
+
+       echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
+
+       if ( $multi ) return;
+
+       echo "\n\n";
+       $map = array(
+               'mm' => array( $mm, $cur_mm ),
+               'jj' => array( $jj, $cur_jj ),
+               'aa' => array( $aa, $cur_aa ),
+               'hh' => array( $hh, $cur_hh ),
+               'mn' => array( $mn, $cur_mn ),
+       );
+       foreach ( $map as $timeunit => $value ) {
+               list( $unit, $curr ) = $value;
+
+               echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $unit . '" />' . "\n";
+               $cur_timeunit = 'cur_' . $timeunit;
+               echo '<input type="hidden" id="' . $cur_timeunit . '" name="' . $cur_timeunit . '" value="' . $curr . '" />' . "\n";
+       }
+?>
+
+<p>
+<a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
+<a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js button-cancel"><?php _e('Cancel'); ?></a>
+</p>
+<?php
+}
+
+/**
+ * Print out option HTML elements for the page templates drop-down.
+ *
+ * @since 1.5.0
+ *
+ * @param string $default Optional. The template file name. Default empty.
+ */
+function page_template_dropdown( $default = '' ) {
+       $templates = get_page_templates( get_post() );
+       ksort( $templates );
+       foreach ( array_keys( $templates ) as $template ) {
+               $selected = selected( $default, $templates[ $template ], false );
+               echo "\n\t<option value='" . $templates[ $template ] . "' $selected>$template</option>";
+       }
+}
+
+/**
+ * Print out option HTML elements for the page parents drop-down.
+ *
+ * @since 1.5.0
+ * @since 4.4.0 `$post` argument was added.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int         $default Optional. The default page ID to be pre-selected. Default 0.
+ * @param int         $parent  Optional. The parent page ID. Default 0.
+ * @param int         $level   Optional. Page depth level. Default 0.
+ * @param int|WP_Post $post    Post ID or WP_Post object.
+ *
+ * @return null|false Boolean False if page has no children, otherwise print out html elements
+ */
+function parent_dropdown( $default = 0, $parent = 0, $level = 0, $post = null ) {
+       global $wpdb;
+       $post = get_post( $post );
+       $items = $wpdb->get_results( $wpdb->prepare("SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' ORDER BY menu_order", $parent) );
+
+       if ( $items ) {
+               foreach ( $items as $item ) {
+                       // A page cannot be its own parent.
+                       if ( $post && $post->ID && $item->ID == $post->ID )
+                               continue;
+
+                       $pad = str_repeat( '&nbsp;', $level * 3 );
+                       $selected = selected( $default, $item->ID, false );
+
+                       echo "\n\t<option class='level-$level' value='$item->ID' $selected>$pad " . esc_html($item->post_title) . "</option>";
+                       parent_dropdown( $default, $item->ID, $level +1 );
+               }
+       } else {
+               return false;
+       }
+}
+
+/**
+ * Print out option html elements for role selectors.
+ *
+ * @since 2.1.0
+ *
+ * @param string $selected Slug for the role that should be already selected.
+ */
+function wp_dropdown_roles( $selected = '' ) {
+       $p = '';
+       $r = '';
+
+       $editable_roles = array_reverse( get_editable_roles() );
+
+       foreach ( $editable_roles as $role => $details ) {
+               $name = translate_user_role($details['name'] );
+               if ( $selected == $role ) // preselect specified role
+                       $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
+               else
+                       $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
+       }
+       echo $p . $r;
+}
+
+/**
+ * Outputs the form used by the importers to accept the data to be imported
+ *
+ * @since 2.0.0
+ *
+ * @param string $action The action attribute for the form.
+ */
+function wp_import_upload_form( $action ) {
+
+       /**
+        * Filter the maximum allowed upload size for import files.
+        *
+        * @since 2.3.0
+        *
+        * @see wp_max_upload_size()
+        *
+        * @param int $max_upload_size Allowed upload size. Default 1 MB.
+        */
+       $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
+       $size = size_format( $bytes );
+       $upload_dir = wp_upload_dir();
+       if ( ! empty( $upload_dir['error'] ) ) :
+               ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
+               <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
+       else :
+?>
+<form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>">
+<p>
+<label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
+<input type="file" id="upload" name="import" size="25" />
+<input type="hidden" name="action" value="save" />
+<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
+</p>
+<?php submit_button( __('Upload file and import'), 'primary' ); ?>
+</form>
+<?php
+       endif;
+}
+
+/**
+ * Adds a meta box to one or more screens.
+ *
+ * @since 2.5.0
+ * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
+ *
+ * @global array $wp_meta_boxes
+ *
+ * @param string                 $id            Meta box ID (used in the 'id' attribute for the meta box).
+ * @param string                 $title         Title of the meta box.
+ * @param callable               $callback      Function that fills the box with the desired content.
+ *                                              The function should echo its output.
+ * @param string|array|WP_Screen $screen        Optional. The screen or screens on which to show the box
+ *                                              (such as a post type, 'link', or 'comment'). Accepts a single
+ *                                              screen ID, WP_Screen object, or array of screen IDs. Default
+ *                                              is the current screen.
+ * @param string                 $context       Optional. The context within the screen where the boxes
+ *                                              should display. Available contexts vary from screen to
+ *                                              screen. Post edit screen contexts include 'normal', 'side',
+ *                                              and 'advanced'. Comments screen contexts include 'normal'
+ *                                              and 'side'. Menus meta boxes (accordion sections) all use
+ *                                              the 'side' context. Global default is 'advanced'.
+ * @param string                 $priority      Optional. The priority within the context where the boxes
+ *                                              should show ('high', 'low'). Default 'default'.
+ * @param array                  $callback_args Optional. Data that should be set as the $args property
+ *                                              of the box array (which is the second parameter passed
+ *                                              to your callback). Default null.
+ */
+function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
+       global $wp_meta_boxes;
+
+       if ( empty( $screen ) ) {
+               $screen = get_current_screen();
+       } elseif ( is_string( $screen ) ) {
+               $screen = convert_to_screen( $screen );
+       } elseif ( is_array( $screen ) ) {
+               foreach ( $screen as $single_screen ) {
+                       add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args );
+               }
+       }
+
+       if ( ! isset( $screen->id ) ) {
+               return;
+       }
+
+       $page = $screen->id;
+
+       if ( !isset($wp_meta_boxes) )
+               $wp_meta_boxes = array();
+       if ( !isset($wp_meta_boxes[$page]) )
+               $wp_meta_boxes[$page] = array();
+       if ( !isset($wp_meta_boxes[$page][$context]) )
+               $wp_meta_boxes[$page][$context] = array();
+
+       foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
+               foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
+                       if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
+                               continue;
+
+                       // If a core box was previously added or removed by a plugin, don't add.
+                       if ( 'core' == $priority ) {
+                               // If core box previously deleted, don't add
+                               if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
+                                       return;
+
+                               /*
+                                * If box was added with default priority, give it core priority to
+                                * maintain sort order.
+                                */
+                               if ( 'default' == $a_priority ) {
+                                       $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
+                                       unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
+                               }
+                               return;
+                       }
+                       // If no priority given and id already present, use existing priority.
+                       if ( empty($priority) ) {
+                               $priority = $a_priority;
+                       /*
+                        * Else, if we're adding to the sorted priority, we don't know the title
+                        * or callback. Grab them from the previously added context/priority.
+                        */
+                       } elseif ( 'sorted' == $priority ) {
+                               $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
+                               $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
+                               $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
+                       }
+                       // An id can be in only one priority and one context.
+                       if ( $priority != $a_priority || $context != $a_context )
+                               unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
+               }
+       }
+
+       if ( empty($priority) )
+               $priority = 'low';
+
+       if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
+               $wp_meta_boxes[$page][$context][$priority] = array();
+
+       $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
+}
+
+/**
+ * Meta-Box template function
+ *
+ * @since 2.5.0
+ *
+ * @global array $wp_meta_boxes
+ *
+ * @staticvar bool $already_sorted
+ * @param string|WP_Screen $screen  Screen identifier
+ * @param string           $context box context
+ * @param mixed            $object  gets passed to the box callback function as first parameter
+ * @return int number of meta_boxes
+ */
+function do_meta_boxes( $screen, $context, $object ) {
+       global $wp_meta_boxes;
+       static $already_sorted = false;
+
+       if ( empty( $screen ) )
+               $screen = get_current_screen();
+       elseif ( is_string( $screen ) )
+               $screen = convert_to_screen( $screen );
+
+       $page = $screen->id;
+
+       $hidden = get_hidden_meta_boxes( $screen );
+
+       printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
+
+       // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
+       if ( ! $already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
+               foreach ( $sorted as $box_context => $ids ) {
+                       foreach ( explode( ',', $ids ) as $id ) {
+                               if ( $id && 'dashboard_browser_nag' !== $id ) {
+                                       add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
+                               }
+                       }
+               }
+       }
+
+       $already_sorted = true;
+
+       $i = 0;
+
+       if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
+               foreach ( array( 'high', 'sorted', 'core', 'default', 'low' ) as $priority ) {
+                       if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ]) ) {
+                               foreach ( (array) $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
+                                       if ( false == $box || ! $box['title'] )
+                                               continue;
+                                       $i++;
+                                       $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
+                                       echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
+                                       if ( 'dashboard_browser_nag' != $box['id'] ) {
+                                               echo '<button type="button" class="handlediv button-link" aria-expanded="true">';
+                                               echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $box['title'] ) . '</span>';
+                                               echo '<span class="toggle-indicator" aria-hidden="true"></span>';
+                                               echo '</button>';
+                                       }
+                                       echo "<h2 class='hndle'><span>{$box['title']}</span></h2>\n";
+                                       echo '<div class="inside">' . "\n";
+                                       call_user_func($box['callback'], $object, $box);
+                                       echo "</div>\n";
+                                       echo "</div>\n";
+                               }
+                       }
+               }
+       }
+
+       echo "</div>";
+
+       return $i;
+
+}
+
+/**
+ * Removes a meta box from one or more screens.
+ *
+ * @since 2.6.0
+ * @since 4.4.0 The `$screen` parameter now accepts an array of screen IDs.
+ *
+ * @global array $wp_meta_boxes
+ *
+ * @param string                 $id      Meta box ID (used in the 'id' attribute for the meta box).
+ * @param string|array|WP_Screen $screen  The screen or screens on which the meta box is shown (such as a
+ *                                        post type, 'link', or 'comment'). Accepts a single screen ID,
+ *                                        WP_Screen object, or array of screen IDs.
+ * @param string                 $context Optional. The context within the screen where the boxes
+ *                                        should display. Available contexts vary from screen to
+ *                                        screen. Post edit screen contexts include 'normal', 'side',
+ *                                        and 'advanced'. Comments screen contexts include 'normal'
+ *                                        and 'side'. Menus meta boxes (accordion sections) all use
+ *                                        the 'side' context. Global default is 'advanced'.
+ */
+function remove_meta_box( $id, $screen, $context ) {
+       global $wp_meta_boxes;
+
+       if ( empty( $screen ) ) {
+               $screen = get_current_screen();
+       } elseif ( is_string( $screen ) ) {
+               $screen = convert_to_screen( $screen );
+       } elseif ( is_array( $screen ) ) {
+               foreach ( $screen as $single_screen ) {
+                       remove_meta_box( $id, $single_screen, $context );
+               }
+       }
+
+       if ( ! isset( $screen->id ) ) {
+               return;
+       }
+
+       $page = $screen->id;
+
+       if ( !isset($wp_meta_boxes) )
+               $wp_meta_boxes = array();
+       if ( !isset($wp_meta_boxes[$page]) )
+               $wp_meta_boxes[$page] = array();
+       if ( !isset($wp_meta_boxes[$page][$context]) )
+               $wp_meta_boxes[$page][$context] = array();
+
+       foreach ( array('high', 'core', 'default', 'low') as $priority )
+               $wp_meta_boxes[$page][$context][$priority][$id] = false;
+}
+
+/**
+ * Meta Box Accordion Template Function
+ *
+ * Largely made up of abstracted code from {@link do_meta_boxes()}, this
+ * function serves to build meta boxes as list items for display as
+ * a collapsible accordion.
+ *
+ * @since 3.6.0
+ *
+ * @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
+ *
+ * @param string|object $screen  The screen identifier.
+ * @param string        $context The meta box context.
+ * @param mixed         $object  gets passed to the section callback function as first parameter.
+ * @return int number of meta boxes as accordion sections.
+ */
+function do_accordion_sections( $screen, $context, $object ) {
+       global $wp_meta_boxes;
+
+       wp_enqueue_script( 'accordion' );
+
+       if ( empty( $screen ) )
+               $screen = get_current_screen();
+       elseif ( is_string( $screen ) )
+               $screen = convert_to_screen( $screen );
+
+       $page = $screen->id;
+
+       $hidden = get_hidden_meta_boxes( $screen );
+       ?>
+       <div id="side-sortables" class="accordion-container">
+               <ul class="outer-border">
+       <?php
+       $i = 0;
+       $first_open = false;
+
+       if ( isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
+               foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
+                       if ( isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
+                               foreach ( $wp_meta_boxes[ $page ][ $context ][ $priority ] as $box ) {
+                                       if ( false == $box || ! $box['title'] )
+                                               continue;
+                                       $i++;
+                                       $hidden_class = in_array( $box['id'], $hidden ) ? 'hide-if-js' : '';
+
+                                       $open_class = '';
+                                       if ( ! $first_open && empty( $hidden_class ) ) {
+                                               $first_open = true;
+                                               $open_class = 'open';
+                                       }
+                                       ?>
+                                       <li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
+                                               <h3 class="accordion-section-title hndle" tabindex="0">
+                                                       <?php echo esc_html( $box['title'] ); ?>
+                                                       <span class="screen-reader-text"><?php _e( 'Press return or enter to open this section' ); ?></span>
+                                               </h3>
+                                               <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
+                                                       <div class="inside">
+                                                               <?php call_user_func( $box['callback'], $object, $box ); ?>
+                                                       </div><!-- .inside -->
+                                               </div><!-- .accordion-section-content -->
+                                       </li><!-- .accordion-section -->
+                                       <?php
+                               }
+                       }
+               }
+       }
+       ?>
+               </ul><!-- .outer-border -->
+       </div><!-- .accordion-container -->
+       <?php
+       return $i;
+}
+
+/**
+ * Add a new section to a settings page.
+ *
+ * Part of the Settings API. Use this to define new settings sections for an admin page.
+ * Show settings sections in your admin page callback function with do_settings_sections().
+ * Add settings fields to your section with add_settings_field()
+ *
+ * The $callback argument should be the name of a function that echoes out any
+ * content you want to show at the top of the settings section before the actual
+ * fields. It can output nothing if you want.
+ *
+ * @since 2.7.0
+ *
+ * @global $wp_settings_sections Storage array of all settings sections added to admin pages
+ *
+ * @param string $id       Slug-name to identify the section. Used in the 'id' attribute of tags.
+ * @param string $title    Formatted title of the section. Shown as the heading for the section.
+ * @param string $callback Function that echos out any content at the top of the section (between heading and fields).
+ * @param string $page     The slug-name of the settings page on which to show the section. Built-in pages include 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using add_options_page();
+ */
+function add_settings_section($id, $title, $callback, $page) {
+       global $wp_settings_sections;
+
+       if ( 'misc' == $page ) {
+               _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
+               $page = 'general';
+       }
+
+       if ( 'privacy' == $page ) {
+               _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
+               $page = 'reading';
+       }
+
+       $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
+}
+
+/**
+ * Add a new field to a section of a settings page
+ *
+ * Part of the Settings API. Use this to define a settings field that will show
+ * as part of a settings section inside a settings page. The fields are shown using
+ * do_settings_fields() in do_settings-sections()
+ *
+ * The $callback argument should be the name of a function that echoes out the
+ * html input tags for this setting field. Use get_option() to retrieve existing
+ * values to show.
+ *
+ * @since 2.7.0
+ * @since 4.2.0 The `$class` argument was added.
+ *
+ * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
+ *
+ * @param string $id       Slug-name to identify the field. Used in the 'id' attribute of tags.
+ * @param string $title    Formatted title of the field. Shown as the label for the field
+ *                         during output.
+ * @param string $callback Function that fills the field with the desired form inputs. The
+ *                         function should echo its output.
+ * @param string $page     The slug-name of the settings page on which to show the section
+ *                         (general, reading, writing, ...).
+ * @param string $section  Optional. The slug-name of the section of the settings page
+ *                         in which to show the box. Default 'default'.
+ * @param array  $args {
+ *     Optional. Extra arguments used when outputting the field.
+ *
+ *     @type string $label_for When supplied, the setting title will be wrapped
+ *                             in a `<label>` element, its `for` attribute populated
+ *                             with this value.
+ *     @type string $class     CSS Class to be added to the `<tr>` element when the
+ *                             field is output.
+ * }
+ */
+function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
+       global $wp_settings_fields;
+
+       if ( 'misc' == $page ) {
+               _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
+               $page = 'general';
+       }
+
+       if ( 'privacy' == $page ) {
+               _deprecated_argument( __FUNCTION__, '3.5', __( 'The privacy options group has been removed. Use another settings group.' ) );
+               $page = 'reading';
+       }
+
+       $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
+}
+
+/**
+ * Prints out all settings sections added to a particular settings page
+ *
+ * Part of the Settings API. Use this in a settings page callback function
+ * to output all the sections and fields that were added to that $page with
+ * add_settings_section() and add_settings_field()
+ *
+ * @global $wp_settings_sections Storage array of all settings sections added to admin pages
+ * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
+ * @since 2.7.0
+ *
+ * @param string $page The slug name of the page whose settings sections you want to output
+ */
+function do_settings_sections( $page ) {
+       global $wp_settings_sections, $wp_settings_fields;
+
+       if ( ! isset( $wp_settings_sections[$page] ) )
+               return;
+
+       foreach ( (array) $wp_settings_sections[$page] as $section ) {
+               if ( $section['title'] )
+                       echo "<h2>{$section['title']}</h2>\n";
+
+               if ( $section['callback'] )
+                       call_user_func( $section['callback'], $section );
+
+               if ( ! isset( $wp_settings_fields ) || !isset( $wp_settings_fields[$page] ) || !isset( $wp_settings_fields[$page][$section['id']] ) )
+                       continue;
+               echo '<table class="form-table">';
+               do_settings_fields( $page, $section['id'] );
+               echo '</table>';
+       }
+}
+
+/**
+ * Print out the settings fields for a particular settings section
+ *
+ * Part of the Settings API. Use this in a settings page to output
+ * a specific section. Should normally be called by do_settings_sections()
+ * rather than directly.
+ *
+ * @global $wp_settings_fields Storage array of settings fields and their pages/sections
+ *
+ * @since 2.7.0
+ *
+ * @param string $page Slug title of the admin page who's settings fields you want to show.
+ * @param string $section Slug title of the settings section who's fields you want to show.
+ */
+function do_settings_fields($page, $section) {
+       global $wp_settings_fields;
+
+       if ( ! isset( $wp_settings_fields[$page][$section] ) )
+               return;
+
+       foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
+               $class = '';
+
+               if ( ! empty( $field['args']['class'] ) ) {
+                       $class = ' class="' . esc_attr( $field['args']['class'] ) . '"';
+               }
+
+               echo "<tr{$class}>";
+
+               if ( ! empty( $field['args']['label_for'] ) ) {
+                       echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
+               } else {
+                       echo '<th scope="row">' . $field['title'] . '</th>';
+               }
+
+               echo '<td>';
+               call_user_func($field['callback'], $field['args']);
+               echo '</td>';
+               echo '</tr>';
+       }
+}
+
+/**
+ * Register a settings error to be displayed to the user
+ *
+ * Part of the Settings API. Use this to show messages to users about settings validation
+ * problems, missing settings or anything else.
+ *
+ * Settings errors should be added inside the $sanitize_callback function defined in
+ * register_setting() for a given setting to give feedback about the submission.
+ *
+ * By default messages will show immediately after the submission that generated the error.
+ * Additional calls to settings_errors() can be used to show errors even when the settings
+ * page is first accessed.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_settings_errors Storage array of errors registered during this pageload
+ *
+ * @param string $setting Slug title of the setting to which this error applies
+ * @param string $code    Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
+ * @param string $message The formatted message text to display to the user (will be shown inside styled
+ *                        `<div>` and `<p>` tags).
+ * @param string $type    Optional. Message type, controls HTML class. Accepts 'error' or 'updated'.
+ *                        Default 'error'.
+ */
+function add_settings_error( $setting, $code, $message, $type = 'error' ) {
+       global $wp_settings_errors;
+
+       $wp_settings_errors[] = array(
+               'setting' => $setting,
+               'code'    => $code,
+               'message' => $message,
+               'type'    => $type
+       );
+}
+
+/**
+ * Fetch settings errors registered by add_settings_error()
+ *
+ * Checks the $wp_settings_errors array for any errors declared during the current
+ * pageload and returns them.
+ *
+ * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
+ * to the 'settings_errors' transient then those errors will be returned instead. This
+ * is used to pass errors back across pageloads.
+ *
+ * Use the $sanitize argument to manually re-sanitize the option before returning errors.
+ * This is useful if you have errors or notices you want to show even when the user
+ * hasn't submitted data (i.e. when they first load an options page, or in admin_notices action hook)
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_settings_errors Storage array of errors registered during this pageload
+ *
+ * @param string $setting Optional slug title of a specific setting who's errors you want.
+ * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
+ * @return array Array of settings errors
+ */
+function get_settings_errors( $setting = '', $sanitize = false ) {
+       global $wp_settings_errors;
+
+       /*
+        * If $sanitize is true, manually re-run the sanitization for this option
+        * This allows the $sanitize_callback from register_setting() to run, adding
+        * any settings errors you want to show by default.
+        */
+       if ( $sanitize )
+               sanitize_option( $setting, get_option( $setting ) );
+
+       // If settings were passed back from options.php then use them.
+       if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
+               $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
+               delete_transient( 'settings_errors' );
+       }
+
+       // Check global in case errors have been added on this pageload.
+       if ( ! count( $wp_settings_errors ) )
+               return array();
+
+       // Filter the results to those of a specific setting if one was set.
+       if ( $setting ) {
+               $setting_errors = array();
+               foreach ( (array) $wp_settings_errors as $key => $details ) {
+                       if ( $setting == $details['setting'] )
+                               $setting_errors[] = $wp_settings_errors[$key];
+               }
+               return $setting_errors;
+       }
+
+       return $wp_settings_errors;
+}
+
+/**
+ * Display settings errors registered by {@see add_settings_error()}.
+ *
+ * Part of the Settings API. Outputs a div for each error retrieved by
+ * {@see get_settings_errors()}.
+ *
+ * This is called automatically after a settings page based on the
+ * Settings API is submitted. Errors should be added during the validation
+ * callback function for a setting defined in {@see register_setting()}
+ *
+ * The $sanitize option is passed into {@see get_settings_errors()} and will
+ * re-run the setting sanitization
+ * on its current value.
+ *
+ * The $hide_on_update option will cause errors to only show when the settings
+ * page is first loaded. if the user has already saved new values it will be
+ * hidden to avoid repeating messages already shown in the default error
+ * reporting after submission. This is useful to show general errors like
+ * missing settings when the user arrives at the settings page.
+ *
+ * @since 3.0.0
+ *
+ * @param string $setting        Optional slug title of a specific setting who's errors you want.
+ * @param bool   $sanitize       Whether to re-sanitize the setting value before returning errors.
+ * @param bool   $hide_on_update If set to true errors will not be shown if the settings page has already been submitted.
+ */
+function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
+
+       if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
+               return;
+
+       $settings_errors = get_settings_errors( $setting, $sanitize );
+
+       if ( empty( $settings_errors ) )
+               return;
+
+       $output = '';
+       foreach ( $settings_errors as $key => $details ) {
+               $css_id = 'setting-error-' . $details['code'];
+               $css_class = $details['type'] . ' settings-error notice is-dismissible';
+               $output .= "<div id='$css_id' class='$css_class'> \n";
+               $output .= "<p><strong>{$details['message']}</strong></p>";
+               $output .= "</div> \n";
+       }
+       echo $output;
+}
+
+/**
+ * Outputs the modal window used for attaching media to posts or pages in the media-listing screen.
+ *
+ * @since 2.7.0
+ *
+ * @param string $found_action
+ */
+function find_posts_div($found_action = '') {
+?>
+       <div id="find-posts" class="find-box" style="display: none;">
+               <div id="find-posts-head" class="find-box-head">
+                       <?php _e( 'Find Posts or Pages' ); ?>
+                       <div id="find-posts-close"></div>
+               </div>
+               <div class="find-box-inside">
+                       <div class="find-box-search">
+                               <?php if ( $found_action ) { ?>
+                                       <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
+                               <?php } ?>
+                               <input type="hidden" name="affected" id="affected" value="" />
+                               <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
+                               <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
+                               <input type="text" id="find-posts-input" name="ps" value="" />
+                               <span class="spinner"></span>
+                               <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
+                               <div class="clear"></div>
+                       </div>
+                       <div id="find-posts-response"></div>
+               </div>
+               <div class="find-box-buttons">
+                       <?php submit_button( __( 'Select' ), 'button-primary alignright', 'find-posts-submit', false ); ?>
+                       <div class="clear"></div>
+               </div>
+       </div>
+<?php
+}
+
+/**
+ * Display the post password.
+ *
+ * The password is passed through {@link esc_attr()} to ensure that it
+ * is safe for placing in an html attribute.
+ *
+ * @since 2.7.0
+ */
+function the_post_password() {
+       $post = get_post();
+       if ( isset( $post->post_password ) )
+               echo esc_attr( $post->post_password );
+}
+
+/**
+ * Get the post title.
+ *
+ * The post title is fetched and if it is blank then a default string is
+ * returned.
+ *
+ * @since 2.7.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
+ * @return string The post title if set.
+ */
+function _draft_or_post_title( $post = 0 ) {
+       $title = get_the_title( $post );
+       if ( empty( $title ) )
+               $title = __( '(no title)' );
+       return esc_html( $title );
+}
+
+/**
+ * Display the search query.
+ *
+ * A simple wrapper to display the "s" parameter in a GET URI. This function
+ * should only be used when {@link the_search_query()} cannot.
+ *
+ * @since 2.7.0
+ */
+function _admin_search_query() {
+       echo isset($_REQUEST['s']) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
+}
+
+/**
+ * Generic Iframe header for use with Thickbox
+ *
+ * @since 2.7.0
+ *
+ * @global string    $hook_suffix
+ * @global string    $admin_body_class
+ * @global WP_Locale $wp_locale
+ *
+ * @param string $title      Optional. Title of the Iframe page. Default empty.
+ * @param bool   $deprecated Not used.
+ */
+function iframe_header( $title = '', $deprecated = false ) {
+       show_admin_bar( false );
+       global $hook_suffix, $admin_body_class, $wp_locale;
+       $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
+
+       $current_screen = get_current_screen();
+
+       @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
+       _wp_admin_html_begin();
+?>
+<title><?php bloginfo('name') ?> &rsaquo; <?php echo $title ?> &#8212; <?php _e('WordPress'); ?></title>
+<?php
+wp_enqueue_style( 'colors' );
+?>
+<script type="text/javascript">
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
+var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
+       pagenow = '<?php echo $current_screen->id; ?>',
+       typenow = '<?php echo $current_screen->post_type; ?>',
+       adminpage = '<?php echo $admin_body_class; ?>',
+       thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
+       decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
+       isRtl = <?php echo (int) is_rtl(); ?>;
+</script>
+<?php
+/** This action is documented in wp-admin/admin-header.php */
+do_action( 'admin_enqueue_scripts', $hook_suffix );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( "admin_print_styles-$hook_suffix" );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( 'admin_print_styles' );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( "admin_print_scripts-$hook_suffix" );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( 'admin_print_scripts' );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( "admin_head-$hook_suffix" );
+
+/** This action is documented in wp-admin/admin-header.php */
+do_action( 'admin_head' );
+
+$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+
+if ( is_rtl() )
+       $admin_body_class .= ' rtl';
+
+?>
+</head>
+<?php
+/** This filter is documented in wp-admin/admin-header.php */
+$admin_body_classes = apply_filters( 'admin_body_class', '' );
+?>
+<body<?php
+/**
+ * @global string $body_id
+ */
+if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin wp-core-ui no-js iframe <?php echo $admin_body_classes . ' ' . $admin_body_class; ?>">
+<script type="text/javascript">
+(function(){
+var c = document.body.className;
+c = c.replace(/no-js/, 'js');
+document.body.className = c;
+})();
+</script>
+<?php
+}
+
+/**
+ * Generic Iframe footer for use with Thickbox
+ *
+ * @since 2.7.0
+ */
+function iframe_footer() {
+       /*
+        * We're going to hide any footer output on iFrame pages,
+        * but run the hooks anyway since they output JavaScript
+        * or other needed content.
+        */
+        ?>
+       <div class="hidden">
+<?php
+       /** This action is documented in wp-admin/admin-footer.php */
+       do_action( 'admin_footer', '' );
+
+       /** This action is documented in wp-admin/admin-footer.php */
+       do_action( 'admin_print_footer_scripts' );
+?>
+       </div>
+<script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
+</body>
+</html>
+<?php
+}
+
+/**
+ *
+ * @param WP_Post $post
+ */
+function _post_states($post) {
+       $post_states = array();
+       if ( isset( $_REQUEST['post_status'] ) )
+               $post_status = $_REQUEST['post_status'];
+       else
+               $post_status = '';
+
+       if ( !empty($post->post_password) )
+               $post_states['protected'] = __('Password protected');
+       if ( 'private' == $post->post_status && 'private' != $post_status )
+               $post_states['private'] = __('Private');
+       if ( 'draft' == $post->post_status && 'draft' != $post_status )
+               $post_states['draft'] = __('Draft');
+       if ( 'pending' == $post->post_status && 'pending' != $post_status )
+               /* translators: post state */
+               $post_states['pending'] = _x('Pending', 'post state');
+       if ( is_sticky($post->ID) )
+               $post_states['sticky'] = __('Sticky');
+
+       if ( 'future' === $post->post_status ) {
+               $post_states['scheduled'] = __( 'Scheduled' );
+       }
+
+       if ( 'page' === get_option( 'show_on_front' ) ) {
+               if ( intval( get_option( 'page_on_front' ) ) === $post->ID ) {
+                       $post_states['page_on_front'] = __( 'Front Page' );
+               }
+
+               if ( intval( get_option( 'page_for_posts' ) ) === $post->ID ) {
+                       $post_states['page_for_posts'] = __( 'Posts Page' );
+               }
+       }
+
+       /**
+        * Filter the default post display states used in the posts list table.
+        *
+        * @since 2.8.0
+        *
+        * @param array   $post_states An array of post display states.
+        * @param WP_Post $post        The current post object.
+        */
+       $post_states = apply_filters( 'display_post_states', $post_states, $post );
+
+       if ( ! empty($post_states) ) {
+               $state_count = count($post_states);
+               $i = 0;
+               echo ' &mdash; ';
+               foreach ( $post_states as $state ) {
+                       ++$i;
+                       ( $i == $state_count ) ? $sep = '' : $sep = ', ';
+                       echo "<span class='post-state'>$state$sep</span>";
+               }
+       }
+
+}
+
+/**
+ *
+ * @param WP_Post $post
+ */
+function _media_states( $post ) {
+       $media_states = array();
+       $stylesheet = get_option('stylesheet');
+
+       if ( current_theme_supports( 'custom-header') ) {
+               $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
+               if ( ! empty( $meta_header ) && $meta_header == $stylesheet )
+                       $media_states[] = __( 'Header Image' );
+       }
+
+       if ( current_theme_supports( 'custom-background') ) {
+               $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
+               if ( ! empty( $meta_background ) && $meta_background == $stylesheet )
+                       $media_states[] = __( 'Background Image' );
+       }
+
+       if ( $post->ID == get_option( 'site_icon' ) ) {
+               $media_states[] = __( 'Site Icon' );
+       }
+
+       /**
+        * Filter the default media display states for items in the Media list table.
+        *
+        * @since 3.2.0
+        *
+        * @param array $media_states An array of media states. Default 'Header Image',
+        *                            'Background Image', 'Site Icon'.
+        */
+       $media_states = apply_filters( 'display_media_states', $media_states );
+
+       if ( ! empty( $media_states ) ) {
+               $state_count = count( $media_states );
+               $i = 0;
+               echo ' &mdash; ';
+               foreach ( $media_states as $state ) {
+                       ++$i;
+                       ( $i == $state_count ) ? $sep = '' : $sep = ', ';
+                       echo "<span class='post-state'>$state$sep</span>";
+               }
+       }
+}
+
+/**
+ * Test support for compressing JavaScript from PHP
+ *
+ * Outputs JavaScript that tests if compression from PHP works as expected
+ * and sets an option with the result. Has no effect when the current user
+ * is not an administrator. To run the test again the option 'can_compress_scripts'
+ * has to be deleted.
+ *
+ * @since 2.8.0
+ */
+function compression_test() {
+?>
+       <script type="text/javascript">
+       var testCompression = {
+               get : function(test) {
+                       var x;
+                       if ( window.XMLHttpRequest ) {
+                               x = new XMLHttpRequest();
+                       } else {
+                               try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
+                       }
+
+                       if (x) {
+                               x.onreadystatechange = function() {
+                                       var r, h;
+                                       if ( x.readyState == 4 ) {
+                                               r = x.responseText.substr(0, 18);
+                                               h = x.getResponseHeader('Content-Encoding');
+                                               testCompression.check(r, h, test);
+                                       }
+                               };
+
+                               x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&'+(new Date()).getTime(), true);
+                               x.send('');
+                       }
+               },
+
+               check : function(r, h, test) {
+                       if ( ! r && ! test )
+                               this.get(1);
+
+                       if ( 1 == test ) {
+                               if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
+                                       this.get('no');
+                               else
+                                       this.get(2);
+
+                               return;
+                       }
+
+                       if ( 2 == test ) {
+                               if ( '"wpCompressionTest' == r )
+                                       this.get('yes');
+                               else
+                                       this.get('no');
+                       }
+               }
+       };
+       testCompression.check();
+       </script>
+<?php
+}
+
+/**
+ * Echoes a submit button, with provided text and appropriate class(es).
+ *
+ * @since 3.1.0
+ *
+ * @see get_submit_button()
+ *
+ * @param string       $text             The text of the button (defaults to 'Save Changes')
+ * @param string       $type             Optional. The type and CSS class(es) of the button. Core values
+ *                                       include 'primary', 'secondary', 'delete'. Default 'primary'
+ * @param string       $name             The HTML name of the submit button. Defaults to "submit". If no
+ *                                       id attribute is given in $other_attributes below, $name will be
+ *                                       used as the button's id.
+ * @param bool         $wrap             True if the output button should be wrapped in a paragraph tag,
+ *                                       false otherwise. Defaults to true
+ * @param array|string $other_attributes Other attributes that should be output with the button, mapping
+ *                                       attributes to their values, such as setting tabindex to 1, etc.
+ *                                       These key/value attribute pairs will be output as attribute="value",
+ *                                       where attribute is the key. Other attributes can also be provided
+ *                                       as a string such as 'tabindex="1"', though the array format is
+ *                                       preferred. Default null.
+ */
+function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
+       echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
+}
+
+/**
+ * Returns a submit button, with provided text and appropriate class
+ *
+ * @since 3.1.0
+ *
+ * @param string       $text             Optional. The text of the button. Default 'Save Changes'.
+ * @param string       $type             Optional. The type of button. Accepts 'primary', 'secondary',
+ *                                       or 'delete'. Default 'primary large'.
+ * @param string       $name             Optional. The HTML name of the submit button. Defaults to "submit".
+ *                                       If no id attribute is given in $other_attributes below, `$name` will
+ *                                       be used as the button's id. Default 'submit'.
+ * @param bool         $wrap             Optional. True if the output button should be wrapped in a paragraph
+ *                                       tag, false otherwise. Default true.
+ * @param array|string $other_attributes Optional. Other attributes that should be output with the button,
+ *                                       mapping attributes to their values, such as `array( 'tabindex' => '1' )`.
+ *                                       These attributes will be output as `attribute="value"`, such as
+ *                                       `tabindex="1"`. Other attributes can also be provided as a string such
+ *                                       as `tabindex="1"`, though the array format is typically cleaner.
+ *                                       Default empty.
+ * @return string Submit button HTML.
+ */
+function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) {
+       if ( ! is_array( $type ) )
+               $type = explode( ' ', $type );
+
+       $button_shorthand = array( 'primary', 'small', 'large' );
+       $classes = array( 'button' );
+       foreach ( $type as $t ) {
+               if ( 'secondary' === $t || 'button-secondary' === $t )
+                       continue;
+               $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
+       }
+       $class = implode( ' ', array_unique( $classes ) );
+
+       if ( 'delete' === $type )
+               $class = 'button-secondary delete';
+
+       $text = $text ? $text : __( 'Save Changes' );
+
+       // Default the id attribute to $name unless an id was specifically provided in $other_attributes
+       $id = $name;
+       if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
+               $id = $other_attributes['id'];
+               unset( $other_attributes['id'] );
+       }
+
+       $attributes = '';
+       if ( is_array( $other_attributes ) ) {
+               foreach ( $other_attributes as $attribute => $value ) {
+                       $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
+               }
+       } elseif ( ! empty( $other_attributes ) ) { // Attributes provided as a string
+               $attributes = $other_attributes;
+       }
+
+       // Don't output empty name and id attributes.
+       $name_attr = $name ? ' name="' . esc_attr( $name ) . '"' : '';
+       $id_attr = $id ? ' id="' . esc_attr( $id ) . '"' : '';
+
+       $button = '<input type="submit"' . $name_attr . $id_attr . ' class="' . esc_attr( $class );
+       $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
+
+       if ( $wrap ) {
+               $button = '<p class="submit">' . $button . '</p>';
+       }
+
+       return $button;
+}
+
+/**
+ *
+ * @global bool $is_IE
+ */
+function _wp_admin_html_begin() {
+       global $is_IE;
+
+       $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
+
+       if ( $is_IE )
+               @header('X-UA-Compatible: IE=edge');
+
+?>
+<!DOCTYPE html>
+<!--[if IE 8]>
+<html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php
+       /**
+        * Fires inside the HTML tag in the admin header.
+        *
+        * @since 2.2.0
+        */
+       do_action( 'admin_xml_ns' );
+?> <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if !(IE 8) ]><!-->
+<html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php
+       /** This action is documented in wp-admin/includes/template-functions.php */
+       do_action( 'admin_xml_ns' );
+?> <?php language_attributes(); ?>>
+<!--<![endif]-->
+<head>
+<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
+<?php
+}
+
+/**
+ * Convert a screen string to a screen object
+ *
+ * @since 3.0.0
+ *
+ * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
+ * @return WP_Screen Screen object.
+ */
+function convert_to_screen( $hook_name ) {
+       if ( ! class_exists( 'WP_Screen', false ) ) {
+               _doing_it_wrong( 'convert_to_screen(), add_meta_box()', __( "Likely direct inclusion of wp-admin/includes/template.php in order to use add_meta_box(). This is very wrong. Hook the add_meta_box() call into the add_meta_boxes action instead." ), '3.3' );
+               return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
+       }
+
+       return WP_Screen::get( $hook_name );
+}
+
+/**
+ * Output the HTML for restoring the post data from DOM storage
+ *
+ * @since 3.6.0
+ * @access private
+ */
+function _local_storage_notice() {
+       ?>
+       <div id="local-storage-notice" class="hidden notice">
+       <p class="local-restore">
+               <?php _e('The backup of this post in your browser is different from the version below.'); ?>
+               <a class="restore-backup" href="#"><?php _e('Restore the backup.'); ?></a>
+       </p>
+       <p class="undo-restore hidden">
+               <?php _e('Post restored successfully.'); ?>
+               <a class="undo-restore-backup" href="#"><?php _e('Undo.'); ?></a>
+       </p>
+       </div>
+       <?php
+}
+
+/**
+ * Output a HTML element with a star rating for a given rating.
+ *
+ * Outputs a HTML element with the star rating exposed on a 0..5 scale in
+ * half star increments (ie. 1, 1.5, 2 stars). Optionally, if specified, the
+ * number of ratings may also be displayed by passing the $number parameter.
+ *
+ * @since 3.8.0
+ * @since 4.4.0 Introduced the `echo` parameter.
+ *
+ * @param array $args {
+ *     Optional. Array of star ratings arguments.
+ *
+ *     @type int    $rating The rating to display, expressed in either a 0.5 rating increment,
+ *                          or percentage. Default 0.
+ *     @type string $type   Format that the $rating is in. Valid values are 'rating' (default),
+ *                          or, 'percent'. Default 'rating'.
+ *     @type int    $number The number of ratings that makes up this rating. Default 0.
+ *     @type bool   $echo   Whether to echo the generated markup. False to return the markup instead
+ *                          of echoing it. Default true.
+ * }
+ */
+function wp_star_rating( $args = array() ) {
+       $defaults = array(
+               'rating' => 0,
+               'type'   => 'rating',
+               'number' => 0,
+               'echo'   => true,
+       );
+       $r = wp_parse_args( $args, $defaults );
+
+       // Non-english decimal places when the $rating is coming from a string
+       $rating = str_replace( ',', '.', $r['rating'] );
+
+       // Convert Percentage to star rating, 0..5 in .5 increments
+       if ( 'percent' == $r['type'] ) {
+               $rating = round( $rating / 10, 0 ) / 2;
+       }
+
+       // Calculate the number of each type of star needed
+       $full_stars = floor( $rating );
+       $half_stars = ceil( $rating - $full_stars );
+       $empty_stars = 5 - $full_stars - $half_stars;
+
+       if ( $r['number'] ) {
+               /* translators: 1: The rating, 2: The number of ratings */
+               $format = _n( '%1$s rating based on %2$s rating', '%1$s rating based on %2$s ratings', $r['number'] );
+               $title = sprintf( $format, number_format_i18n( $rating, 1 ), number_format_i18n( $r['number'] ) );
+       } else {
+               /* translators: 1: The rating */
+               $title = sprintf( __( '%s rating' ), number_format_i18n( $rating, 1 ) );
+       }
+
+       $output = '<div class="star-rating" title="' . esc_attr( $title ) . '">';
+       $output .= '<span class="screen-reader-text">' . $title . '</span>';
+       $output .= str_repeat( '<div class="star star-full"></div>', $full_stars );
+       $output .= str_repeat( '<div class="star star-half"></div>', $half_stars );
+       $output .= str_repeat( '<div class="star star-empty"></div>', $empty_stars );
+       $output .= '</div>';
+
+       if ( $r['echo'] ) {
+               echo $output;
+       }
+
+       return $output;
+}
+
+/**
+ * Output a notice when editing the page for posts (internal use only).
+ *
+ * @ignore
+ * @since 4.2.0
+ */
+function _wp_posts_page_notice() {
+       echo '<div class="notice notice-warning inline"><p>' . __( 'You are currently editing the page that shows your latest posts.' ) . '</p></div>';
+}
</ins></span></pre></div>
<a id="trunksrcwpadminincludesupdatecorephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/update-core.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/update-core.php       2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-admin/includes/update-core.php 2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43,6 +43,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'wp-admin/link-categories.php',
</span><span class="cx" style="display: block; padding: 0 10px"> 'wp-admin/list-manipulation.js',
</span><span class="cx" style="display: block; padding: 0 10px"> 'wp-admin/list-manipulation.php',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+'wp-includes/comment-functions.php',
</ins><span class="cx" style="display: block; padding: 0 10px"> 'wp-includes/feed-functions.php',
</span><span class="cx" style="display: block; padding: 0 10px"> 'wp-includes/functions-compat.php',
</span><span class="cx" style="display: block; padding: 0 10px"> 'wp-includes/functions-formatting.php',
</span></span></pre></div>
<a id="trunksrcwpincludescapabilitiesfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/capabilities-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/capabilities-functions.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/capabilities-functions.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,612 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * User API: Top-level role and capabilities functionality
- *
- * @package WordPress
- * @subpackage Users
- * @since 4.4.0
- */
-
-/**
- * Map meta capabilities to primitive capabilities.
- *
- * This does not actually compare whether the user ID has the actual capability,
- * just what the capability or capabilities are. Meta capability list value can
- * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
- * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
- *
- * @since 2.0.0
- *
- * @param string $cap       Capability name.
- * @param int    $user_id   User ID.
- * @param int    $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
- *                          "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
- *                          by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
- *                          'edit_others_posts', etc. The parameter is accessed via func_get_args().
- * @return array Actual capabilities for meta capability.
- */
-function map_meta_cap( $cap, $user_id ) {
-       $args = array_slice( func_get_args(), 2 );
-       $caps = array();
-
-       switch ( $cap ) {
-       case 'remove_user':
-               $caps[] = 'remove_users';
-               break;
-       case 'promote_user':
-       case 'add_users':
-               $caps[] = 'promote_users';
-               break;
-       case 'edit_user':
-       case 'edit_users':
-               // Allow user to edit itself
-               if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] )
-                       break;
-
-               // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
-               if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
-                       $caps[] = 'do_not_allow';
-               } else {
-                       $caps[] = 'edit_users'; // edit_user maps to edit_users.
-               }
-               break;
-       case 'delete_post':
-       case 'delete_page':
-               $post = get_post( $args[0] );
-               if ( ! $post ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               if ( 'revision' == $post->post_type ) {
-                       $post = get_post( $post->post_parent );
-                       if ( ! $post ) {
-                               $caps[] = 'do_not_allow';
-                               break;
-                       }
-               }
-
-               $post_type = get_post_type_object( $post->post_type );
-               if ( ! $post_type ) {
-                       /* translators: 1: post type, 2: capability name */
-                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
-                       $caps[] = 'edit_others_posts';
-                       break;
-               }
-
-               if ( ! $post_type->map_meta_cap ) {
-                       $caps[] = $post_type->cap->$cap;
-                       // Prior to 3.1 we would re-call map_meta_cap here.
-                       if ( 'delete_post' == $cap )
-                               $cap = $post_type->cap->$cap;
-                       break;
-               }
-
-               // If the post author is set and the user is the author...
-               if ( $post->post_author && $user_id == $post->post_author ) {
-                       // If the post is published...
-                       if ( 'publish' == $post->post_status ) {
-                               $caps[] = $post_type->cap->delete_published_posts;
-                       } elseif ( 'trash' == $post->post_status ) {
-                               if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
-                                       $caps[] = $post_type->cap->delete_published_posts;
-                               }
-                       } else {
-                               // If the post is draft...
-                               $caps[] = $post_type->cap->delete_posts;
-                       }
-               } else {
-                       // The user is trying to edit someone else's post.
-                       $caps[] = $post_type->cap->delete_others_posts;
-                       // The post is published, extra cap required.
-                       if ( 'publish' == $post->post_status ) {
-                               $caps[] = $post_type->cap->delete_published_posts;
-                       } elseif ( 'private' == $post->post_status ) {
-                               $caps[] = $post_type->cap->delete_private_posts;
-                       }
-               }
-               break;
-               // edit_post breaks down to edit_posts, edit_published_posts, or
-               // edit_others_posts
-       case 'edit_post':
-       case 'edit_page':
-               $post = get_post( $args[0] );
-               if ( ! $post ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               if ( 'revision' == $post->post_type ) {
-                       $post = get_post( $post->post_parent );
-                       if ( ! $post ) {
-                               $caps[] = 'do_not_allow';
-                               break;
-                       }
-               }
-
-               $post_type = get_post_type_object( $post->post_type );
-               if ( ! $post_type ) {
-                       /* translators: 1: post type, 2: capability name */
-                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
-                       $caps[] = 'edit_others_posts';
-                       break;
-               }
-
-               if ( ! $post_type->map_meta_cap ) {
-                       $caps[] = $post_type->cap->$cap;
-                       // Prior to 3.1 we would re-call map_meta_cap here.
-                       if ( 'edit_post' == $cap )
-                               $cap = $post_type->cap->$cap;
-                       break;
-               }
-
-               // If the post author is set and the user is the author...
-               if ( $post->post_author && $user_id == $post->post_author ) {
-                       // If the post is published...
-                       if ( 'publish' == $post->post_status ) {
-                               $caps[] = $post_type->cap->edit_published_posts;
-                       } elseif ( 'trash' == $post->post_status ) {
-                               if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
-                                       $caps[] = $post_type->cap->edit_published_posts;
-                               }
-                       } else {
-                               // If the post is draft...
-                               $caps[] = $post_type->cap->edit_posts;
-                       }
-               } else {
-                       // The user is trying to edit someone else's post.
-                       $caps[] = $post_type->cap->edit_others_posts;
-                       // The post is published, extra cap required.
-                       if ( 'publish' == $post->post_status ) {
-                               $caps[] = $post_type->cap->edit_published_posts;
-                       } elseif ( 'private' == $post->post_status ) {
-                               $caps[] = $post_type->cap->edit_private_posts;
-                       }
-               }
-               break;
-       case 'read_post':
-       case 'read_page':
-               $post = get_post( $args[0] );
-               if ( ! $post ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               if ( 'revision' == $post->post_type ) {
-                       $post = get_post( $post->post_parent );
-                       if ( ! $post ) {
-                               $caps[] = 'do_not_allow';
-                               break;
-                       }
-               }
-
-               $post_type = get_post_type_object( $post->post_type );
-               if ( ! $post_type ) {
-                       /* translators: 1: post type, 2: capability name */
-                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
-                       $caps[] = 'edit_others_posts';
-                       break;
-               }
-
-               if ( ! $post_type->map_meta_cap ) {
-                       $caps[] = $post_type->cap->$cap;
-                       // Prior to 3.1 we would re-call map_meta_cap here.
-                       if ( 'read_post' == $cap )
-                               $cap = $post_type->cap->$cap;
-                       break;
-               }
-
-               $status_obj = get_post_status_object( $post->post_status );
-               if ( $status_obj->public ) {
-                       $caps[] = $post_type->cap->read;
-                       break;
-               }
-
-               if ( $post->post_author && $user_id == $post->post_author ) {
-                       $caps[] = $post_type->cap->read;
-               } elseif ( $status_obj->private ) {
-                       $caps[] = $post_type->cap->read_private_posts;
-               } else {
-                       $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
-               }
-               break;
-       case 'publish_post':
-               $post = get_post( $args[0] );
-               if ( ! $post ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               $post_type = get_post_type_object( $post->post_type );
-               if ( ! $post_type ) {
-                       /* translators: 1: post type, 2: capability name */
-                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
-                       $caps[] = 'edit_others_posts';
-                       break;
-               }
-
-               $caps[] = $post_type->cap->publish_posts;
-               break;
-       case 'edit_post_meta':
-       case 'delete_post_meta':
-       case 'add_post_meta':
-               $post = get_post( $args[0] );
-               if ( ! $post ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
-
-               $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
-
-               if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) {
-                       /**
-                        * Filter whether the user is allowed to add post meta to a post.
-                        *
-                        * The dynamic portion of the hook name, `$meta_key`, refers to the
-                        * meta key passed to {@see map_meta_cap()}.
-                        *
-                        * @since 3.3.0
-                        *
-                        * @param bool   $allowed  Whether the user can add the post meta. Default false.
-                        * @param string $meta_key The meta key.
-                        * @param int    $post_id  Post ID.
-                        * @param int    $user_id  User ID.
-                        * @param string $cap      Capability name.
-                        * @param array  $caps     User capabilities.
-                        */
-                       $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
-                       if ( ! $allowed )
-                               $caps[] = $cap;
-               } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
-                       $caps[] = $cap;
-               }
-               break;
-       case 'edit_comment':
-               $comment = get_comment( $args[0] );
-               if ( ! $comment ) {
-                       $caps[] = 'do_not_allow';
-                       break;
-               }
-
-               $post = get_post( $comment->comment_post_ID );
-
-               /*
-                * If the post doesn't exist, we have an orphaned comment.
-                * Fall back to the edit_posts capability, instead.
-                */
-               if ( $post ) {
-                       $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
-               } else {
-                       $caps = map_meta_cap( 'edit_posts', $user_id );
-               }
-               break;
-       case 'unfiltered_upload':
-               if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) )  )
-                       $caps[] = $cap;
-               else
-                       $caps[] = 'do_not_allow';
-               break;
-       case 'unfiltered_html' :
-               // Disallow unfiltered_html for all users, even admins and super admins.
-               if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
-                       $caps[] = 'do_not_allow';
-               elseif ( is_multisite() && ! is_super_admin( $user_id ) )
-                       $caps[] = 'do_not_allow';
-               else
-                       $caps[] = $cap;
-               break;
-       case 'edit_files':
-       case 'edit_plugins':
-       case 'edit_themes':
-               // Disallow the file editors.
-               if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT )
-                       $caps[] = 'do_not_allow';
-               elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
-                       $caps[] = 'do_not_allow';
-               elseif ( is_multisite() && ! is_super_admin( $user_id ) )
-                       $caps[] = 'do_not_allow';
-               else
-                       $caps[] = $cap;
-               break;
-       case 'update_plugins':
-       case 'delete_plugins':
-       case 'install_plugins':
-       case 'upload_plugins':
-       case 'update_themes':
-       case 'delete_themes':
-       case 'install_themes':
-       case 'upload_themes':
-       case 'update_core':
-               // Disallow anything that creates, deletes, or updates core, plugin, or theme files.
-               // Files in uploads are excepted.
-               if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
-                       $caps[] = 'do_not_allow';
-               } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
-                       $caps[] = 'do_not_allow';
-               } elseif ( 'upload_themes' === $cap ) {
-                       $caps[] = 'install_themes';
-               } elseif ( 'upload_plugins' === $cap ) {
-                       $caps[] = 'install_plugins';
-               } else {
-                       $caps[] = $cap;
-               }
-               break;
-       case 'activate_plugins':
-               $caps[] = $cap;
-               if ( is_multisite() ) {
-                       // update_, install_, and delete_ are handled above with is_super_admin().
-                       $menu_perms = get_site_option( 'menu_items', array() );
-                       if ( empty( $menu_perms['plugins'] ) )
-                               $caps[] = 'manage_network_plugins';
-               }
-               break;
-       case 'delete_user':
-       case 'delete_users':
-               // If multisite only super admins can delete users.
-               if ( is_multisite() && ! is_super_admin( $user_id ) )
-                       $caps[] = 'do_not_allow';
-               else
-                       $caps[] = 'delete_users'; // delete_user maps to delete_users.
-               break;
-       case 'create_users':
-               if ( !is_multisite() )
-                       $caps[] = $cap;
-               elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) )
-                       $caps[] = $cap;
-               else
-                       $caps[] = 'do_not_allow';
-               break;
-       case 'manage_links' :
-               if ( get_option( 'link_manager_enabled' ) )
-                       $caps[] = $cap;
-               else
-                       $caps[] = 'do_not_allow';
-               break;
-       case 'customize' :
-               $caps[] = 'edit_theme_options';
-               break;
-       case 'delete_site':
-               $caps[] = 'manage_options';
-               break;
-       default:
-               // Handle meta capabilities for custom post types.
-               $post_type_meta_caps = _post_type_meta_capabilities();
-               if ( isset( $post_type_meta_caps[ $cap ] ) ) {
-                       $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
-                       return call_user_func_array( 'map_meta_cap', $args );
-               }
-
-               // If no meta caps match, return the original cap.
-               $caps[] = $cap;
-       }
-
-       /**
-        * Filter a user's capabilities depending on specific context and/or privilege.
-        *
-        * @since 2.8.0
-        *
-        * @param array  $caps    Returns the user's actual capabilities.
-        * @param string $cap     Capability name.
-        * @param int    $user_id The user ID.
-        * @param array  $args    Adds the context to the cap. Typically the object ID.
-        */
-       return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
-}
-
-/**
- * Whether the current user has a specific capability.
- *
- * While checking against particular roles in place of a capability is supported
- * in part, this practice is discouraged as it may produce unreliable results.
- *
- * @since 2.0.0
- *
- * @see WP_User::has_cap()
- * @see map_meta_cap()
- *
- * @param string $capability Capability name.
- * @param int    $object_id  Optional. ID of the specific object to check against if `$capability` is a "meta" cap.
- *                           "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
- *                           by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
- *                           'edit_others_posts', etc. Accessed via func_get_args() and passed to WP_User::has_cap(),
- *                           then map_meta_cap().
- * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
- *              passed, whether the current user has the given meta capability for the given object.
- */
-function current_user_can( $capability ) {
-       $current_user = wp_get_current_user();
-
-       if ( empty( $current_user ) )
-               return false;
-
-       $args = array_slice( func_get_args(), 1 );
-       $args = array_merge( array( $capability ), $args );
-
-       return call_user_func_array( array( $current_user, 'has_cap' ), $args );
-}
-
-/**
- * Whether current user has a capability or role for a given blog.
- *
- * @since 3.0.0
- *
- * @param int $blog_id Blog ID
- * @param string $capability Capability or role name.
- * @return bool
- */
-function current_user_can_for_blog( $blog_id, $capability ) {
-       $switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
-
-       $current_user = wp_get_current_user();
-
-       if ( empty( $current_user ) ) {
-               if ( $switched ) {
-                       restore_current_blog();
-               }
-               return false;
-       }
-
-       $args = array_slice( func_get_args(), 2 );
-       $args = array_merge( array( $capability ), $args );
-
-       $can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
-
-       if ( $switched ) {
-               restore_current_blog();
-       }
-
-       return $can;
-}
-
-/**
- * Whether author of supplied post has capability or role.
- *
- * @since 2.9.0
- *
- * @param int|object $post Post ID or post object.
- * @param string $capability Capability or role name.
- * @return bool
- */
-function author_can( $post, $capability ) {
-       if ( !$post = get_post($post) )
-               return false;
-
-       $author = get_userdata( $post->post_author );
-
-       if ( ! $author )
-               return false;
-
-       $args = array_slice( func_get_args(), 2 );
-       $args = array_merge( array( $capability ), $args );
-
-       return call_user_func_array( array( $author, 'has_cap' ), $args );
-}
-
-/**
- * Whether a particular user has capability or role.
- *
- * @since 3.1.0
- *
- * @param int|object $user User ID or object.
- * @param string $capability Capability or role name.
- * @return bool
- */
-function user_can( $user, $capability ) {
-       if ( ! is_object( $user ) )
-               $user = get_userdata( $user );
-
-       if ( ! $user || ! $user->exists() )
-               return false;
-
-       $args = array_slice( func_get_args(), 2 );
-       $args = array_merge( array( $capability ), $args );
-
-       return call_user_func_array( array( $user, 'has_cap' ), $args );
-}
-
-/**
- * Retrieves the global WP_Roles instance and instantiates it if necessary.
- *
- * @since 4.3.0
- *
- * @global WP_Roles $wp_roles WP_Roles global instance.
- *
- * @return WP_Roles WP_Roles global instance if not already instantiated.
- */
-function wp_roles() {
-       global $wp_roles;
-
-       if ( ! isset( $wp_roles ) ) {
-               $wp_roles = new WP_Roles();
-       }
-       return $wp_roles;
-}
-
-/**
- * Retrieve role object.
- *
- * @since 2.0.0
- *
- * @param string $role Role name.
- * @return WP_Role|null WP_Role object if found, null if the role does not exist.
- */
-function get_role( $role ) {
-       return wp_roles()->get_role( $role );
-}
-
-/**
- * Add role, if it does not exist.
- *
- * @since 2.0.0
- *
- * @param string $role Role name.
- * @param string $display_name Display name for role.
- * @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
- * @return WP_Role|null WP_Role object if role is added, null if already exists.
- */
-function add_role( $role, $display_name, $capabilities = array() ) {
-       if ( empty( $role ) ) {
-               return;
-       }
-       return wp_roles()->add_role( $role, $display_name, $capabilities );
-}
-
-/**
- * Remove role, if it exists.
- *
- * @since 2.0.0
- *
- * @param string $role Role name.
- */
-function remove_role( $role ) {
-       wp_roles()->remove_role( $role );
-}
-
-/**
- * Retrieve a list of super admins.
- *
- * @since 3.0.0
- *
- * @global array $super_admins
- *
- * @return array List of super admin logins
- */
-function get_super_admins() {
-       global $super_admins;
-
-       if ( isset($super_admins) )
-               return $super_admins;
-       else
-               return get_site_option( 'site_admins', array('admin') );
-}
-
-/**
- * Determine if user is a site admin.
- *
- * @since 3.0.0
- *
- * @param int $user_id (Optional) The ID of a user. Defaults to the current user.
- * @return bool True if the user is a site admin.
- */
-function is_super_admin( $user_id = false ) {
-       if ( ! $user_id || $user_id == get_current_user_id() )
-               $user = wp_get_current_user();
-       else
-               $user = get_userdata( $user_id );
-
-       if ( ! $user || ! $user->exists() )
-               return false;
-
-       if ( is_multisite() ) {
-               $super_admins = get_super_admins();
-               if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) )
-                       return true;
-       } else {
-               if ( $user->has_cap('delete_users') )
-                       return true;
-       }
-
-       return false;
-}
</del></span></pre></div>
<a id="trunksrcwpincludescapabilitiesphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/capabilities.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/capabilities.php    2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/capabilities.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,20 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core User Role & Capabilities API
- *
- * @package WordPress
- * @subpackage Users
- * @since 2.0.0
- */
-
-/** WP_Roles class */
-require_once( ABSPATH . WPINC . '/class-wp-roles.php' );
-
-/** WP_Role class */
-require_once( ABSPATH . WPINC . '/class-wp-role.php' );
-
-/** WP_User class */
-require_once( ABSPATH . WPINC . '/class-wp-user.php' );
-
-/** Core capabilities functionality */
-require_once( ABSPATH . WPINC . '/capabilities-functions.php' );
</del></span></pre></div>
<a id="trunksrcwpincludescapabilitiesphpfromrev35717trunksrcwpincludescapabilitiesfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/capabilities.php (from rev 35717, trunk/src/wp-includes/capabilities-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/capabilities.php                            (rev 0)
+++ trunk/src/wp-includes/capabilities.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,611 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core User Role & Capabilities API
+ *
+ * @package WordPress
+ * @subpackage Users
+ */
+
+/**
+ * Map meta capabilities to primitive capabilities.
+ *
+ * This does not actually compare whether the user ID has the actual capability,
+ * just what the capability or capabilities are. Meta capability list value can
+ * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
+ * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
+ *
+ * @since 2.0.0
+ *
+ * @param string $cap       Capability name.
+ * @param int    $user_id   User ID.
+ * @param int    $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
+ *                          "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
+ *                          by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
+ *                          'edit_others_posts', etc. The parameter is accessed via func_get_args().
+ * @return array Actual capabilities for meta capability.
+ */
+function map_meta_cap( $cap, $user_id ) {
+       $args = array_slice( func_get_args(), 2 );
+       $caps = array();
+
+       switch ( $cap ) {
+       case 'remove_user':
+               $caps[] = 'remove_users';
+               break;
+       case 'promote_user':
+       case 'add_users':
+               $caps[] = 'promote_users';
+               break;
+       case 'edit_user':
+       case 'edit_users':
+               // Allow user to edit itself
+               if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] )
+                       break;
+
+               // In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
+               if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
+                       $caps[] = 'do_not_allow';
+               } else {
+                       $caps[] = 'edit_users'; // edit_user maps to edit_users.
+               }
+               break;
+       case 'delete_post':
+       case 'delete_page':
+               $post = get_post( $args[0] );
+               if ( ! $post ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               if ( 'revision' == $post->post_type ) {
+                       $post = get_post( $post->post_parent );
+                       if ( ! $post ) {
+                               $caps[] = 'do_not_allow';
+                               break;
+                       }
+               }
+
+               $post_type = get_post_type_object( $post->post_type );
+               if ( ! $post_type ) {
+                       /* translators: 1: post type, 2: capability name */
+                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
+                       $caps[] = 'edit_others_posts';
+                       break;
+               }
+
+               if ( ! $post_type->map_meta_cap ) {
+                       $caps[] = $post_type->cap->$cap;
+                       // Prior to 3.1 we would re-call map_meta_cap here.
+                       if ( 'delete_post' == $cap )
+                               $cap = $post_type->cap->$cap;
+                       break;
+               }
+
+               // If the post author is set and the user is the author...
+               if ( $post->post_author && $user_id == $post->post_author ) {
+                       // If the post is published...
+                       if ( 'publish' == $post->post_status ) {
+                               $caps[] = $post_type->cap->delete_published_posts;
+                       } elseif ( 'trash' == $post->post_status ) {
+                               if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
+                                       $caps[] = $post_type->cap->delete_published_posts;
+                               }
+                       } else {
+                               // If the post is draft...
+                               $caps[] = $post_type->cap->delete_posts;
+                       }
+               } else {
+                       // The user is trying to edit someone else's post.
+                       $caps[] = $post_type->cap->delete_others_posts;
+                       // The post is published, extra cap required.
+                       if ( 'publish' == $post->post_status ) {
+                               $caps[] = $post_type->cap->delete_published_posts;
+                       } elseif ( 'private' == $post->post_status ) {
+                               $caps[] = $post_type->cap->delete_private_posts;
+                       }
+               }
+               break;
+               // edit_post breaks down to edit_posts, edit_published_posts, or
+               // edit_others_posts
+       case 'edit_post':
+       case 'edit_page':
+               $post = get_post( $args[0] );
+               if ( ! $post ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               if ( 'revision' == $post->post_type ) {
+                       $post = get_post( $post->post_parent );
+                       if ( ! $post ) {
+                               $caps[] = 'do_not_allow';
+                               break;
+                       }
+               }
+
+               $post_type = get_post_type_object( $post->post_type );
+               if ( ! $post_type ) {
+                       /* translators: 1: post type, 2: capability name */
+                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
+                       $caps[] = 'edit_others_posts';
+                       break;
+               }
+
+               if ( ! $post_type->map_meta_cap ) {
+                       $caps[] = $post_type->cap->$cap;
+                       // Prior to 3.1 we would re-call map_meta_cap here.
+                       if ( 'edit_post' == $cap )
+                               $cap = $post_type->cap->$cap;
+                       break;
+               }
+
+               // If the post author is set and the user is the author...
+               if ( $post->post_author && $user_id == $post->post_author ) {
+                       // If the post is published...
+                       if ( 'publish' == $post->post_status ) {
+                               $caps[] = $post_type->cap->edit_published_posts;
+                       } elseif ( 'trash' == $post->post_status ) {
+                               if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
+                                       $caps[] = $post_type->cap->edit_published_posts;
+                               }
+                       } else {
+                               // If the post is draft...
+                               $caps[] = $post_type->cap->edit_posts;
+                       }
+               } else {
+                       // The user is trying to edit someone else's post.
+                       $caps[] = $post_type->cap->edit_others_posts;
+                       // The post is published, extra cap required.
+                       if ( 'publish' == $post->post_status ) {
+                               $caps[] = $post_type->cap->edit_published_posts;
+                       } elseif ( 'private' == $post->post_status ) {
+                               $caps[] = $post_type->cap->edit_private_posts;
+                       }
+               }
+               break;
+       case 'read_post':
+       case 'read_page':
+               $post = get_post( $args[0] );
+               if ( ! $post ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               if ( 'revision' == $post->post_type ) {
+                       $post = get_post( $post->post_parent );
+                       if ( ! $post ) {
+                               $caps[] = 'do_not_allow';
+                               break;
+                       }
+               }
+
+               $post_type = get_post_type_object( $post->post_type );
+               if ( ! $post_type ) {
+                       /* translators: 1: post type, 2: capability name */
+                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
+                       $caps[] = 'edit_others_posts';
+                       break;
+               }
+
+               if ( ! $post_type->map_meta_cap ) {
+                       $caps[] = $post_type->cap->$cap;
+                       // Prior to 3.1 we would re-call map_meta_cap here.
+                       if ( 'read_post' == $cap )
+                               $cap = $post_type->cap->$cap;
+                       break;
+               }
+
+               $status_obj = get_post_status_object( $post->post_status );
+               if ( $status_obj->public ) {
+                       $caps[] = $post_type->cap->read;
+                       break;
+               }
+
+               if ( $post->post_author && $user_id == $post->post_author ) {
+                       $caps[] = $post_type->cap->read;
+               } elseif ( $status_obj->private ) {
+                       $caps[] = $post_type->cap->read_private_posts;
+               } else {
+                       $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+               }
+               break;
+       case 'publish_post':
+               $post = get_post( $args[0] );
+               if ( ! $post ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               $post_type = get_post_type_object( $post->post_type );
+               if ( ! $post_type ) {
+                       /* translators: 1: post type, 2: capability name */
+                       _doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
+                       $caps[] = 'edit_others_posts';
+                       break;
+               }
+
+               $caps[] = $post_type->cap->publish_posts;
+               break;
+       case 'edit_post_meta':
+       case 'delete_post_meta':
+       case 'add_post_meta':
+               $post = get_post( $args[0] );
+               if ( ! $post ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+
+               $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
+
+               if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) {
+                       /**
+                        * Filter whether the user is allowed to add post meta to a post.
+                        *
+                        * The dynamic portion of the hook name, `$meta_key`, refers to the
+                        * meta key passed to {@see map_meta_cap()}.
+                        *
+                        * @since 3.3.0
+                        *
+                        * @param bool   $allowed  Whether the user can add the post meta. Default false.
+                        * @param string $meta_key The meta key.
+                        * @param int    $post_id  Post ID.
+                        * @param int    $user_id  User ID.
+                        * @param string $cap      Capability name.
+                        * @param array  $caps     User capabilities.
+                        */
+                       $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
+                       if ( ! $allowed )
+                               $caps[] = $cap;
+               } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
+                       $caps[] = $cap;
+               }
+               break;
+       case 'edit_comment':
+               $comment = get_comment( $args[0] );
+               if ( ! $comment ) {
+                       $caps[] = 'do_not_allow';
+                       break;
+               }
+
+               $post = get_post( $comment->comment_post_ID );
+
+               /*
+                * If the post doesn't exist, we have an orphaned comment.
+                * Fall back to the edit_posts capability, instead.
+                */
+               if ( $post ) {
+                       $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+               } else {
+                       $caps = map_meta_cap( 'edit_posts', $user_id );
+               }
+               break;
+       case 'unfiltered_upload':
+               if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) )  )
+                       $caps[] = $cap;
+               else
+                       $caps[] = 'do_not_allow';
+               break;
+       case 'unfiltered_html' :
+               // Disallow unfiltered_html for all users, even admins and super admins.
+               if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
+                       $caps[] = 'do_not_allow';
+               elseif ( is_multisite() && ! is_super_admin( $user_id ) )
+                       $caps[] = 'do_not_allow';
+               else
+                       $caps[] = $cap;
+               break;
+       case 'edit_files':
+       case 'edit_plugins':
+       case 'edit_themes':
+               // Disallow the file editors.
+               if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT )
+                       $caps[] = 'do_not_allow';
+               elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
+                       $caps[] = 'do_not_allow';
+               elseif ( is_multisite() && ! is_super_admin( $user_id ) )
+                       $caps[] = 'do_not_allow';
+               else
+                       $caps[] = $cap;
+               break;
+       case 'update_plugins':
+       case 'delete_plugins':
+       case 'install_plugins':
+       case 'upload_plugins':
+       case 'update_themes':
+       case 'delete_themes':
+       case 'install_themes':
+       case 'upload_themes':
+       case 'update_core':
+               // Disallow anything that creates, deletes, or updates core, plugin, or theme files.
+               // Files in uploads are excepted.
+               if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
+                       $caps[] = 'do_not_allow';
+               } elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
+                       $caps[] = 'do_not_allow';
+               } elseif ( 'upload_themes' === $cap ) {
+                       $caps[] = 'install_themes';
+               } elseif ( 'upload_plugins' === $cap ) {
+                       $caps[] = 'install_plugins';
+               } else {
+                       $caps[] = $cap;
+               }
+               break;
+       case 'activate_plugins':
+               $caps[] = $cap;
+               if ( is_multisite() ) {
+                       // update_, install_, and delete_ are handled above with is_super_admin().
+                       $menu_perms = get_site_option( 'menu_items', array() );
+                       if ( empty( $menu_perms['plugins'] ) )
+                               $caps[] = 'manage_network_plugins';
+               }
+               break;
+       case 'delete_user':
+       case 'delete_users':
+               // If multisite only super admins can delete users.
+               if ( is_multisite() && ! is_super_admin( $user_id ) )
+                       $caps[] = 'do_not_allow';
+               else
+                       $caps[] = 'delete_users'; // delete_user maps to delete_users.
+               break;
+       case 'create_users':
+               if ( !is_multisite() )
+                       $caps[] = $cap;
+               elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) )
+                       $caps[] = $cap;
+               else
+                       $caps[] = 'do_not_allow';
+               break;
+       case 'manage_links' :
+               if ( get_option( 'link_manager_enabled' ) )
+                       $caps[] = $cap;
+               else
+                       $caps[] = 'do_not_allow';
+               break;
+       case 'customize' :
+               $caps[] = 'edit_theme_options';
+               break;
+       case 'delete_site':
+               $caps[] = 'manage_options';
+               break;
+       default:
+               // Handle meta capabilities for custom post types.
+               $post_type_meta_caps = _post_type_meta_capabilities();
+               if ( isset( $post_type_meta_caps[ $cap ] ) ) {
+                       $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
+                       return call_user_func_array( 'map_meta_cap', $args );
+               }
+
+               // If no meta caps match, return the original cap.
+               $caps[] = $cap;
+       }
+
+       /**
+        * Filter a user's capabilities depending on specific context and/or privilege.
+        *
+        * @since 2.8.0
+        *
+        * @param array  $caps    Returns the user's actual capabilities.
+        * @param string $cap     Capability name.
+        * @param int    $user_id The user ID.
+        * @param array  $args    Adds the context to the cap. Typically the object ID.
+        */
+       return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
+}
+
+/**
+ * Whether the current user has a specific capability.
+ *
+ * While checking against particular roles in place of a capability is supported
+ * in part, this practice is discouraged as it may produce unreliable results.
+ *
+ * @since 2.0.0
+ *
+ * @see WP_User::has_cap()
+ * @see map_meta_cap()
+ *
+ * @param string $capability Capability name.
+ * @param int    $object_id  Optional. ID of the specific object to check against if `$capability` is a "meta" cap.
+ *                           "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
+ *                           by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
+ *                           'edit_others_posts', etc. Accessed via func_get_args() and passed to WP_User::has_cap(),
+ *                           then map_meta_cap().
+ * @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
+ *              passed, whether the current user has the given meta capability for the given object.
+ */
+function current_user_can( $capability ) {
+       $current_user = wp_get_current_user();
+
+       if ( empty( $current_user ) )
+               return false;
+
+       $args = array_slice( func_get_args(), 1 );
+       $args = array_merge( array( $capability ), $args );
+
+       return call_user_func_array( array( $current_user, 'has_cap' ), $args );
+}
+
+/**
+ * Whether current user has a capability or role for a given blog.
+ *
+ * @since 3.0.0
+ *
+ * @param int $blog_id Blog ID
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function current_user_can_for_blog( $blog_id, $capability ) {
+       $switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
+
+       $current_user = wp_get_current_user();
+
+       if ( empty( $current_user ) ) {
+               if ( $switched ) {
+                       restore_current_blog();
+               }
+               return false;
+       }
+
+       $args = array_slice( func_get_args(), 2 );
+       $args = array_merge( array( $capability ), $args );
+
+       $can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
+
+       if ( $switched ) {
+               restore_current_blog();
+       }
+
+       return $can;
+}
+
+/**
+ * Whether author of supplied post has capability or role.
+ *
+ * @since 2.9.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function author_can( $post, $capability ) {
+       if ( !$post = get_post($post) )
+               return false;
+
+       $author = get_userdata( $post->post_author );
+
+       if ( ! $author )
+               return false;
+
+       $args = array_slice( func_get_args(), 2 );
+       $args = array_merge( array( $capability ), $args );
+
+       return call_user_func_array( array( $author, 'has_cap' ), $args );
+}
+
+/**
+ * Whether a particular user has capability or role.
+ *
+ * @since 3.1.0
+ *
+ * @param int|object $user User ID or object.
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function user_can( $user, $capability ) {
+       if ( ! is_object( $user ) )
+               $user = get_userdata( $user );
+
+       if ( ! $user || ! $user->exists() )
+               return false;
+
+       $args = array_slice( func_get_args(), 2 );
+       $args = array_merge( array( $capability ), $args );
+
+       return call_user_func_array( array( $user, 'has_cap' ), $args );
+}
+
+/**
+ * Retrieves the global WP_Roles instance and instantiates it if necessary.
+ *
+ * @since 4.3.0
+ *
+ * @global WP_Roles $wp_roles WP_Roles global instance.
+ *
+ * @return WP_Roles WP_Roles global instance if not already instantiated.
+ */
+function wp_roles() {
+       global $wp_roles;
+
+       if ( ! isset( $wp_roles ) ) {
+               $wp_roles = new WP_Roles();
+       }
+       return $wp_roles;
+}
+
+/**
+ * Retrieve role object.
+ *
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ * @return WP_Role|null WP_Role object if found, null if the role does not exist.
+ */
+function get_role( $role ) {
+       return wp_roles()->get_role( $role );
+}
+
+/**
+ * Add role, if it does not exist.
+ *
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ * @param string $display_name Display name for role.
+ * @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
+ * @return WP_Role|null WP_Role object if role is added, null if already exists.
+ */
+function add_role( $role, $display_name, $capabilities = array() ) {
+       if ( empty( $role ) ) {
+               return;
+       }
+       return wp_roles()->add_role( $role, $display_name, $capabilities );
+}
+
+/**
+ * Remove role, if it exists.
+ *
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ */
+function remove_role( $role ) {
+       wp_roles()->remove_role( $role );
+}
+
+/**
+ * Retrieve a list of super admins.
+ *
+ * @since 3.0.0
+ *
+ * @global array $super_admins
+ *
+ * @return array List of super admin logins
+ */
+function get_super_admins() {
+       global $super_admins;
+
+       if ( isset($super_admins) )
+               return $super_admins;
+       else
+               return get_site_option( 'site_admins', array('admin') );
+}
+
+/**
+ * Determine if user is a site admin.
+ *
+ * @since 3.0.0
+ *
+ * @param int $user_id (Optional) The ID of a user. Defaults to the current user.
+ * @return bool True if the user is a site admin.
+ */
+function is_super_admin( $user_id = false ) {
+       if ( ! $user_id || $user_id == get_current_user_id() )
+               $user = wp_get_current_user();
+       else
+               $user = get_userdata( $user_id );
+
+       if ( ! $user || ! $user->exists() )
+               return false;
+
+       if ( is_multisite() ) {
+               $super_admins = get_super_admins();
+               if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) )
+                       return true;
+       } else {
+               if ( $user->has_cap('delete_users') )
+                       return true;
+       }
+
+       return false;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludescategoryfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/category-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/category-functions.php      2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/category-functions.php        2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,349 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Taxonomy API: Top-level core category-specific functionality
- *
- * @package WordPress
- * @subpackage Taxonomy
- * @since 4.4.0
- */
-
-/**
- * Retrieve list of category objects.
- *
- * If you change the type to 'link' in the arguments, then the link categories
- * will be returned instead. Also all categories will be updated to be backwards
- * compatible with pre-2.3 plugins and themes.
- *
- * @since 2.1.0
- * @see get_terms() Type of arguments that can be changed.
- * @link https://codex.wordpress.org/Function_Reference/get_categories
- *
- * @param string|array $args Optional. Change the defaults retrieving categories.
- * @return array List of categories.
- */
-function get_categories( $args = '' ) {
-       $defaults = array( 'taxonomy' => 'category' );
-       $args = wp_parse_args( $args, $defaults );
-
-       $taxonomy = $args['taxonomy'];
-
-       /**
-        * Filter the taxonomy used to retrieve terms when calling {@see get_categories()}.
-        *
-        * @since 2.7.0
-        *
-        * @param string $taxonomy Taxonomy to retrieve terms from.
-        * @param array  $args     An array of arguments. See {@see get_terms()}.
-        */
-       $taxonomy = apply_filters( 'get_categories_taxonomy', $taxonomy, $args );
-
-       // Back compat
-       if ( isset($args['type']) && 'link' == $args['type'] ) {
-               /* translators: 1: "type => link", 2: "taxonomy => link_category" alternative */
-               _deprecated_argument( __FUNCTION__, '3.0',
-                       sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
-                               '<code>type => link</code>',
-                               '<code>taxonomy => link_category</code>'
-                       )
-               );
-               $taxonomy = $args['taxonomy'] = 'link_category';
-       }
-
-       $categories = (array) get_terms( $taxonomy, $args );
-
-       foreach ( array_keys( $categories ) as $k )
-               _make_cat_compat( $categories[$k] );
-
-       return $categories;
-}
-
-/**
- * Retrieves category data given a category ID or category object.
- *
- * If you pass the $category parameter an object, which is assumed to be the
- * category row object retrieved the database. It will cache the category data.
- *
- * If you pass $category an integer of the category ID, then that category will
- * be retrieved from the database, if it isn't already cached, and pass it back.
- *
- * If you look at get_term(), then both types will be passed through several
- * filters and finally sanitized based on the $filter parameter value.
- *
- * The category will converted to maintain backwards compatibility.
- *
- * @since 1.5.1
- *
- * @param int|object $category Category ID or Category row object
- * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
- * @return object|array|WP_Error|null Category data in type defined by $output parameter.
- *                                    WP_Error if $category is empty, null if it does not exist.
- */
-function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
-       $category = get_term( $category, 'category', $output, $filter );
-
-       if ( is_wp_error( $category ) )
-               return $category;
-
-       _make_cat_compat( $category );
-
-       return $category;
-}
-
-/**
- * Retrieve category based on URL containing the category slug.
- *
- * Breaks the $category_path parameter up to get the category slug.
- *
- * Tries to find the child path and will return it. If it doesn't find a
- * match, then it will return the first category matching slug, if $full_match,
- * is set to false. If it does not, then it will return null.
- *
- * It is also possible that it will return a WP_Error object on failure. Check
- * for it when using this function.
- *
- * @since 2.1.0
- *
- * @param string $category_path URL containing category slugs.
- * @param bool $full_match Optional. Whether full path should be matched.
- * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
- * @return object|array|WP_Error|void Type is based on $output value.
- */
-function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
-       $category_path = rawurlencode( urldecode( $category_path ) );
-       $category_path = str_replace( '%2F', '/', $category_path );
-       $category_path = str_replace( '%20', ' ', $category_path );
-       $category_paths = '/' . trim( $category_path, '/' );
-       $leaf_path  = sanitize_title( basename( $category_paths ) );
-       $category_paths = explode( '/', $category_paths );
-       $full_path = '';
-       foreach ( (array) $category_paths as $pathdir ) {
-               $full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
-       }
-       $categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
-
-       if ( empty( $categories ) ) {
-               return;
-       }
-
-       foreach ( $categories as $category ) {
-               $path = '/' . $leaf_path;
-               $curcategory = $category;
-               while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
-                       $curcategory = get_term( $curcategory->parent, 'category' );
-                       if ( is_wp_error( $curcategory ) ) {
-                               return $curcategory;
-                       }
-                       $path = '/' . $curcategory->slug . $path;
-               }
-
-               if ( $path == $full_path ) {
-                       $category = get_term( $category->term_id, 'category', $output );
-                       _make_cat_compat( $category );
-                       return $category;
-               }
-       }
-
-       // If full matching is not required, return the first cat that matches the leaf.
-       if ( ! $full_match ) {
-               $category = get_term( reset( $categories )->term_id, 'category', $output );
-               _make_cat_compat( $category );
-               return $category;
-       }
-}
-
-/**
- * Retrieve category object by category slug.
- *
- * @since 2.3.0
- *
- * @param string $slug The category slug.
- * @return object Category data object
- */
-function get_category_by_slug( $slug  ) {
-       $category = get_term_by( 'slug', $slug, 'category' );
-       if ( $category )
-               _make_cat_compat( $category );
-
-       return $category;
-}
-
-/**
- * Retrieve the ID of a category from its name.
- *
- * @since 1.0.0
- *
- * @param string $cat_name Category name.
- * @return int 0, if failure and ID of category on success.
- */
-function get_cat_ID( $cat_name ) {
-       $cat = get_term_by( 'name', $cat_name, 'category' );
-       if ( $cat )
-               return $cat->term_id;
-       return 0;
-}
-
-/**
- * Retrieve the name of a category from its ID.
- *
- * @since 1.0.0
- *
- * @param int $cat_id Category ID
- * @return string Category name, or an empty string if category doesn't exist.
- */
-function get_cat_name( $cat_id ) {
-       $cat_id = (int) $cat_id;
-       $category = get_term( $cat_id, 'category' );
-       if ( ! $category || is_wp_error( $category ) )
-               return '';
-       return $category->name;
-}
-
-/**
- * Check if a category is an ancestor of another category.
- *
- * You can use either an id or the category object for both parameters. If you
- * use an integer the category will be retrieved.
- *
- * @since 2.1.0
- *
- * @param int|object $cat1 ID or object to check if this is the parent category.
- * @param int|object $cat2 The child category.
- * @return bool Whether $cat2 is child of $cat1
- */
-function cat_is_ancestor_of( $cat1, $cat2 ) {
-       return term_is_ancestor_of( $cat1, $cat2, 'category' );
-}
-
-/**
- * Sanitizes category data based on context.
- *
- * @since 2.3.0
- *
- * @param object|array $category Category data
- * @param string $context Optional. Default is 'display'.
- * @return object|array Same type as $category with sanitized data for safe use.
- */
-function sanitize_category( $category, $context = 'display' ) {
-       return sanitize_term( $category, 'category', $context );
-}
-
-/**
- * Sanitizes data in single category key field.
- *
- * @since 2.3.0
- *
- * @param string $field Category key to sanitize
- * @param mixed $value Category value to sanitize
- * @param int $cat_id Category ID
- * @param string $context What filter to use, 'raw', 'display', etc.
- * @return mixed Same type as $value after $value has been sanitized.
- */
-function sanitize_category_field( $field, $value, $cat_id, $context ) {
-       return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
-}
-
-/* Tags */
-
-/**
- * Retrieves all post tags.
- *
- * @since 2.3.0
- * @see get_terms() For list of arguments to pass.
- *
- * @param string|array $args Tag arguments to use when retrieving tags.
- * @return array List of tags.
- */
-function get_tags( $args = '' ) {
-       $tags = get_terms( 'post_tag', $args );
-
-       if ( empty( $tags ) ) {
-               $return = array();
-               return $return;
-       }
-
-       /**
-        * Filter the array of term objects returned for the 'post_tag' taxonomy.
-        *
-        * @since 2.3.0
-        *
-        * @param array $tags Array of 'post_tag' term objects.
-        * @param array $args An array of arguments. @see get_terms()
-        */
-       $tags = apply_filters( 'get_tags', $tags, $args );
-       return $tags;
-}
-
-/**
- * Retrieve post tag by tag ID or tag object.
- *
- * If you pass the $tag parameter an object, which is assumed to be the tag row
- * object retrieved the database. It will cache the tag data.
- *
- * If you pass $tag an integer of the tag ID, then that tag will
- * be retrieved from the database, if it isn't already cached, and pass it back.
- *
- * If you look at get_term(), then both types will be passed through several
- * filters and finally sanitized based on the $filter parameter value.
- *
- * @since 2.3.0
- *
- * @param int|object $tag
- * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
- * @return object|array|WP_Error|null Tag data in type defined by $output parameter. WP_Error if $tag is empty, null if it does not exist.
- */
-function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
-       return get_term( $tag, 'post_tag', $output, $filter );
-}
-
-/* Cache */
-
-/**
- * Remove the category cache data based on ID.
- *
- * @since 2.1.0
- *
- * @param int $id Category ID
- */
-function clean_category_cache( $id ) {
-       clean_term_cache( $id, 'category' );
-}
-
-/**
- * Update category structure to old pre 2.3 from new taxonomy structure.
- *
- * This function was added for the taxonomy support to update the new category
- * structure with the old category one. This will maintain compatibility with
- * plugins and themes which depend on the old key or property names.
- *
- * The parameter should only be passed a variable and not create the array or
- * object inline to the parameter. The reason for this is that parameter is
- * passed by reference and PHP will fail unless it has the variable.
- *
- * There is no return value, because everything is updated on the variable you
- * pass to it. This is one of the features with using pass by reference in PHP.
- *
- * @since 2.3.0
- * @since 4.4.0 The `$category` parameter now also accepts a WP_Term object.
- * @access private
- *
- * @param array|object|WP_Term $category Category Row object or array
- */
-function _make_cat_compat( &$category ) {
-       if ( is_object( $category ) && ! is_wp_error( $category ) ) {
-               $category->cat_ID = $category->term_id;
-               $category->category_count = $category->count;
-               $category->category_description = $category->description;
-               $category->cat_name = $category->name;
-               $category->category_nicename = $category->slug;
-               $category->category_parent = $category->parent;
-       } elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
-               $category['cat_ID'] = &$category['term_id'];
-               $category['category_count'] = &$category['count'];
-               $category['category_description'] = &$category['description'];
-               $category['cat_name'] = &$category['name'];
-               $category['category_nicename'] = &$category['slug'];
-               $category['category_parent'] = &$category['parent'];
-       }
-}
</del></span></pre></div>
<a id="trunksrcwpincludescategoryphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/category.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/category.php        2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/category.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,17 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Taxonomy API: Core category-specific functionality
- *
- * @package WordPress
- * @subpackage Taxonomy
- * @since 2.1.0
- */
-
-/** Core category functionality */
-require_once( ABSPATH . WPINC . '/category-functions.php' );
-
-/** Walker_Category class */
-require_once( ABSPATH . WPINC . '/class-walker-category.php' );
-
-/** Walker_CategoryDropdown class */
-require_once( ABSPATH . WPINC . '/class-walker-category-dropdown.php' );
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludescategoryphpfromrev35712trunksrcwpincludescategoryfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/category.php (from rev 35712, trunk/src/wp-includes/category-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/category.php                                (rev 0)
+++ trunk/src/wp-includes/category.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,348 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Taxonomy API: Core category-specific functionality
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ */
+
+/**
+ * Retrieve list of category objects.
+ *
+ * If you change the type to 'link' in the arguments, then the link categories
+ * will be returned instead. Also all categories will be updated to be backwards
+ * compatible with pre-2.3 plugins and themes.
+ *
+ * @since 2.1.0
+ * @see get_terms() Type of arguments that can be changed.
+ * @link https://codex.wordpress.org/Function_Reference/get_categories
+ *
+ * @param string|array $args Optional. Change the defaults retrieving categories.
+ * @return array List of categories.
+ */
+function get_categories( $args = '' ) {
+       $defaults = array( 'taxonomy' => 'category' );
+       $args = wp_parse_args( $args, $defaults );
+
+       $taxonomy = $args['taxonomy'];
+
+       /**
+        * Filter the taxonomy used to retrieve terms when calling {@see get_categories()}.
+        *
+        * @since 2.7.0
+        *
+        * @param string $taxonomy Taxonomy to retrieve terms from.
+        * @param array  $args     An array of arguments. See {@see get_terms()}.
+        */
+       $taxonomy = apply_filters( 'get_categories_taxonomy', $taxonomy, $args );
+
+       // Back compat
+       if ( isset($args['type']) && 'link' == $args['type'] ) {
+               /* translators: 1: "type => link", 2: "taxonomy => link_category" alternative */
+               _deprecated_argument( __FUNCTION__, '3.0',
+                       sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
+                               '<code>type => link</code>',
+                               '<code>taxonomy => link_category</code>'
+                       )
+               );
+               $taxonomy = $args['taxonomy'] = 'link_category';
+       }
+
+       $categories = (array) get_terms( $taxonomy, $args );
+
+       foreach ( array_keys( $categories ) as $k )
+               _make_cat_compat( $categories[$k] );
+
+       return $categories;
+}
+
+/**
+ * Retrieves category data given a category ID or category object.
+ *
+ * If you pass the $category parameter an object, which is assumed to be the
+ * category row object retrieved the database. It will cache the category data.
+ *
+ * If you pass $category an integer of the category ID, then that category will
+ * be retrieved from the database, if it isn't already cached, and pass it back.
+ *
+ * If you look at get_term(), then both types will be passed through several
+ * filters and finally sanitized based on the $filter parameter value.
+ *
+ * The category will converted to maintain backwards compatibility.
+ *
+ * @since 1.5.1
+ *
+ * @param int|object $category Category ID or Category row object
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
+ * @return object|array|WP_Error|null Category data in type defined by $output parameter.
+ *                                    WP_Error if $category is empty, null if it does not exist.
+ */
+function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
+       $category = get_term( $category, 'category', $output, $filter );
+
+       if ( is_wp_error( $category ) )
+               return $category;
+
+       _make_cat_compat( $category );
+
+       return $category;
+}
+
+/**
+ * Retrieve category based on URL containing the category slug.
+ *
+ * Breaks the $category_path parameter up to get the category slug.
+ *
+ * Tries to find the child path and will return it. If it doesn't find a
+ * match, then it will return the first category matching slug, if $full_match,
+ * is set to false. If it does not, then it will return null.
+ *
+ * It is also possible that it will return a WP_Error object on failure. Check
+ * for it when using this function.
+ *
+ * @since 2.1.0
+ *
+ * @param string $category_path URL containing category slugs.
+ * @param bool $full_match Optional. Whether full path should be matched.
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @return object|array|WP_Error|void Type is based on $output value.
+ */
+function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
+       $category_path = rawurlencode( urldecode( $category_path ) );
+       $category_path = str_replace( '%2F', '/', $category_path );
+       $category_path = str_replace( '%20', ' ', $category_path );
+       $category_paths = '/' . trim( $category_path, '/' );
+       $leaf_path  = sanitize_title( basename( $category_paths ) );
+       $category_paths = explode( '/', $category_paths );
+       $full_path = '';
+       foreach ( (array) $category_paths as $pathdir ) {
+               $full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
+       }
+       $categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
+
+       if ( empty( $categories ) ) {
+               return;
+       }
+
+       foreach ( $categories as $category ) {
+               $path = '/' . $leaf_path;
+               $curcategory = $category;
+               while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
+                       $curcategory = get_term( $curcategory->parent, 'category' );
+                       if ( is_wp_error( $curcategory ) ) {
+                               return $curcategory;
+                       }
+                       $path = '/' . $curcategory->slug . $path;
+               }
+
+               if ( $path == $full_path ) {
+                       $category = get_term( $category->term_id, 'category', $output );
+                       _make_cat_compat( $category );
+                       return $category;
+               }
+       }
+
+       // If full matching is not required, return the first cat that matches the leaf.
+       if ( ! $full_match ) {
+               $category = get_term( reset( $categories )->term_id, 'category', $output );
+               _make_cat_compat( $category );
+               return $category;
+       }
+}
+
+/**
+ * Retrieve category object by category slug.
+ *
+ * @since 2.3.0
+ *
+ * @param string $slug The category slug.
+ * @return object Category data object
+ */
+function get_category_by_slug( $slug  ) {
+       $category = get_term_by( 'slug', $slug, 'category' );
+       if ( $category )
+               _make_cat_compat( $category );
+
+       return $category;
+}
+
+/**
+ * Retrieve the ID of a category from its name.
+ *
+ * @since 1.0.0
+ *
+ * @param string $cat_name Category name.
+ * @return int 0, if failure and ID of category on success.
+ */
+function get_cat_ID( $cat_name ) {
+       $cat = get_term_by( 'name', $cat_name, 'category' );
+       if ( $cat )
+               return $cat->term_id;
+       return 0;
+}
+
+/**
+ * Retrieve the name of a category from its ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $cat_id Category ID
+ * @return string Category name, or an empty string if category doesn't exist.
+ */
+function get_cat_name( $cat_id ) {
+       $cat_id = (int) $cat_id;
+       $category = get_term( $cat_id, 'category' );
+       if ( ! $category || is_wp_error( $category ) )
+               return '';
+       return $category->name;
+}
+
+/**
+ * Check if a category is an ancestor of another category.
+ *
+ * You can use either an id or the category object for both parameters. If you
+ * use an integer the category will be retrieved.
+ *
+ * @since 2.1.0
+ *
+ * @param int|object $cat1 ID or object to check if this is the parent category.
+ * @param int|object $cat2 The child category.
+ * @return bool Whether $cat2 is child of $cat1
+ */
+function cat_is_ancestor_of( $cat1, $cat2 ) {
+       return term_is_ancestor_of( $cat1, $cat2, 'category' );
+}
+
+/**
+ * Sanitizes category data based on context.
+ *
+ * @since 2.3.0
+ *
+ * @param object|array $category Category data
+ * @param string $context Optional. Default is 'display'.
+ * @return object|array Same type as $category with sanitized data for safe use.
+ */
+function sanitize_category( $category, $context = 'display' ) {
+       return sanitize_term( $category, 'category', $context );
+}
+
+/**
+ * Sanitizes data in single category key field.
+ *
+ * @since 2.3.0
+ *
+ * @param string $field Category key to sanitize
+ * @param mixed $value Category value to sanitize
+ * @param int $cat_id Category ID
+ * @param string $context What filter to use, 'raw', 'display', etc.
+ * @return mixed Same type as $value after $value has been sanitized.
+ */
+function sanitize_category_field( $field, $value, $cat_id, $context ) {
+       return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
+}
+
+/* Tags */
+
+/**
+ * Retrieves all post tags.
+ *
+ * @since 2.3.0
+ * @see get_terms() For list of arguments to pass.
+ *
+ * @param string|array $args Tag arguments to use when retrieving tags.
+ * @return array List of tags.
+ */
+function get_tags( $args = '' ) {
+       $tags = get_terms( 'post_tag', $args );
+
+       if ( empty( $tags ) ) {
+               $return = array();
+               return $return;
+       }
+
+       /**
+        * Filter the array of term objects returned for the 'post_tag' taxonomy.
+        *
+        * @since 2.3.0
+        *
+        * @param array $tags Array of 'post_tag' term objects.
+        * @param array $args An array of arguments. @see get_terms()
+        */
+       $tags = apply_filters( 'get_tags', $tags, $args );
+       return $tags;
+}
+
+/**
+ * Retrieve post tag by tag ID or tag object.
+ *
+ * If you pass the $tag parameter an object, which is assumed to be the tag row
+ * object retrieved the database. It will cache the tag data.
+ *
+ * If you pass $tag an integer of the tag ID, then that tag will
+ * be retrieved from the database, if it isn't already cached, and pass it back.
+ *
+ * If you look at get_term(), then both types will be passed through several
+ * filters and finally sanitized based on the $filter parameter value.
+ *
+ * @since 2.3.0
+ *
+ * @param int|object $tag
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
+ * @return object|array|WP_Error|null Tag data in type defined by $output parameter. WP_Error if $tag is empty, null if it does not exist.
+ */
+function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
+       return get_term( $tag, 'post_tag', $output, $filter );
+}
+
+/* Cache */
+
+/**
+ * Remove the category cache data based on ID.
+ *
+ * @since 2.1.0
+ *
+ * @param int $id Category ID
+ */
+function clean_category_cache( $id ) {
+       clean_term_cache( $id, 'category' );
+}
+
+/**
+ * Update category structure to old pre 2.3 from new taxonomy structure.
+ *
+ * This function was added for the taxonomy support to update the new category
+ * structure with the old category one. This will maintain compatibility with
+ * plugins and themes which depend on the old key or property names.
+ *
+ * The parameter should only be passed a variable and not create the array or
+ * object inline to the parameter. The reason for this is that parameter is
+ * passed by reference and PHP will fail unless it has the variable.
+ *
+ * There is no return value, because everything is updated on the variable you
+ * pass to it. This is one of the features with using pass by reference in PHP.
+ *
+ * @since 2.3.0
+ * @since 4.4.0 The `$category` parameter now also accepts a WP_Term object.
+ * @access private
+ *
+ * @param array|object|WP_Term $category Category Row object or array
+ */
+function _make_cat_compat( &$category ) {
+       if ( is_object( $category ) && ! is_wp_error( $category ) ) {
+               $category->cat_ID = $category->term_id;
+               $category->category_count = $category->count;
+               $category->category_description = $category->description;
+               $category->cat_name = $category->name;
+               $category->category_nicename = $category->slug;
+               $category->category_parent = $category->parent;
+       } elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
+               $category['cat_ID'] = &$category['term_id'];
+               $category['category_count'] = &$category['count'];
+               $category['category_description'] = &$category['description'];
+               $category['cat_name'] = &$category['name'];
+               $category['category_nicename'] = &$category['slug'];
+               $category['category_parent'] = &$category['parent'];
+       }
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesclasswpcustomizemanagerphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-customize-manager.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-customize-manager.php      2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/class-wp-customize-manager.php        2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -192,6 +192,37 @@
</span><span class="cx" style="display: block; padding: 0 10px">                require_once( ABSPATH . WPINC . '/class-wp-customize-section.php' );
</span><span class="cx" style="display: block; padding: 0 10px">                require_once( ABSPATH . WPINC . '/class-wp-customize-control.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-color-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-media-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-upload-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-image-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-cropped-image-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-site-icon-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-theme-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-widget-area-customize-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-widget-form-customize-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-location-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-control.php' );
+
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menus-panel.php' );
+
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-themes-section.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-sidebar-section.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-section.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-section.php' );
+
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-filter-setting.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-setting.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-setting.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-setting.php' );
+               require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-setting.php' );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 /**
</span><span class="cx" style="display: block; padding: 0 10px">                 * Filter the core Customizer components to load.
</span><span class="cx" style="display: block; padding: 0 10px">                 *
</span></span></pre></div>
<a id="trunksrcwpincludescommentfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/comment-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/comment-functions.php       2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/comment-functions.php 2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,2797 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Comment API: Top-level comments functionality
- *
- * @package WordPress
- * @subpackage Comments
- * @since 4.4.0
- */
-
-/**
- * Check whether a comment passes internal checks to be allowed to add.
- *
- * If manual comment moderation is set in the administration, then all checks,
- * regardless of their type and whitelist, will fail and the function will
- * return false.
- *
- * If the number of links exceeds the amount in the administration, then the
- * check fails. If any of the parameter contents match the blacklist of words,
- * then the check fails.
- *
- * If the comment author was approved before, then the comment is automatically
- * whitelisted.
- *
- * If all checks pass, the function will return true.
- *
- * @since 1.2.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $author       Comment author name.
- * @param string $email        Comment author email.
- * @param string $url          Comment author URL.
- * @param string $comment      Content of the comment.
- * @param string $user_ip      Comment author IP address.
- * @param string $user_agent   Comment author User-Agent.
- * @param string $comment_type Comment type, either user-submitted comment,
- *                                    trackback, or pingback.
- * @return bool If all checks pass, true, otherwise false.
- */
-function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
-       global $wpdb;
-
-       // If manual moderation is enabled, skip all checks and return false.
-       if ( 1 == get_option('comment_moderation') )
-               return false;
-
-       /** This filter is documented in wp-includes/comment-template.php */
-       $comment = apply_filters( 'comment_text', $comment );
-
-       // Check for the number of external links if a max allowed number is set.
-       if ( $max_links = get_option( 'comment_max_links' ) ) {
-               $num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
-
-               /**
-                * Filter the maximum number of links allowed in a comment.
-                *
-                * @since 3.0.0
-                *
-                * @param int    $num_links The number of links allowed.
-                * @param string $url       Comment author's URL. Included in allowed links total.
-                */
-               $num_links = apply_filters( 'comment_max_links_url', $num_links, $url );
-
-               /*
-                * If the number of links in the comment exceeds the allowed amount,
-                * fail the check by returning false.
-                */
-               if ( $num_links >= $max_links )
-                       return false;
-       }
-
-       $mod_keys = trim(get_option('moderation_keys'));
-
-       // If moderation 'keys' (keywords) are set, process them.
-       if ( !empty($mod_keys) ) {
-               $words = explode("\n", $mod_keys );
-
-               foreach ( (array) $words as $word) {
-                       $word = trim($word);
-
-                       // Skip empty lines.
-                       if ( empty($word) )
-                               continue;
-
-                       /*
-                        * Do some escaping magic so that '#' (number of) characters in the spam
-                        * words don't break things:
-                        */
-                       $word = preg_quote($word, '#');
-
-                       /*
-                        * Check the comment fields for moderation keywords. If any are found,
-                        * fail the check for the given field by returning false.
-                        */
-                       $pattern = "#$word#i";
-                       if ( preg_match($pattern, $author) ) return false;
-                       if ( preg_match($pattern, $email) ) return false;
-                       if ( preg_match($pattern, $url) ) return false;
-                       if ( preg_match($pattern, $comment) ) return false;
-                       if ( preg_match($pattern, $user_ip) ) return false;
-                       if ( preg_match($pattern, $user_agent) ) return false;
-               }
-       }
-
-       /*
-        * Check if the option to approve comments by previously-approved authors is enabled.
-        *
-        * If it is enabled, check whether the comment author has a previously-approved comment,
-        * as well as whether there are any moderation keywords (if set) present in the author
-        * email address. If both checks pass, return true. Otherwise, return false.
-        */
-       if ( 1 == get_option('comment_whitelist')) {
-               if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
-                       // expected_slashed ($author, $email)
-                       $ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
-                       if ( ( 1 == $ok_to_comment ) &&
-                               ( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
-                                       return true;
-                       else
-                               return false;
-               } else {
-                       return false;
-               }
-       }
-       return true;
-}
-
-/**
- * Retrieve the approved comments for post $post_id.
- *
- * @since 2.0.0
- * @since 4.1.0 Refactored to leverage {@see WP_Comment_Query} over a direct query.
- *
- * @param  int   $post_id The ID of the post.
- * @param  array $args    Optional. See {@see WP_Comment_Query::query()} for information
- *                        on accepted arguments.
- * @return int|array $comments The approved comments, or number of comments if `$count`
- *                             argument is true.
- */
-function get_approved_comments( $post_id, $args = array() ) {
-       if ( ! $post_id ) {
-               return array();
-       }
-
-       $defaults = array(
-               'status'  => 1,
-               'post_id' => $post_id,
-               'order'   => 'ASC',
-       );
-       $r = wp_parse_args( $args, $defaults );
-
-       $query = new WP_Comment_Query;
-       return $query->query( $r );
-}
-
-/**
- * Retrieves comment data given a comment ID or comment object.
- *
- * If an object is passed then the comment data will be cached and then returned
- * after being passed through a filter. If the comment is empty, then the global
- * comment variable will be used, if it is set.
- *
- * @since 2.0.0
- *
- * @global WP_Comment $comment
- *
- * @param WP_Comment|string|int $comment Comment to retrieve.
- * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
- * @return WP_Comment|array|null Depends on $output value.
- */
-function get_comment( &$comment = null, $output = OBJECT ) {
-       if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
-               $comment = $GLOBALS['comment'];
-       }
-
-       if ( $comment instanceof WP_Comment ) {
-               $_comment = $comment;
-       } elseif ( is_object( $comment ) ) {
-               $_comment = new WP_Comment( $comment );
-       } else {
-               $_comment = WP_Comment::get_instance( $comment );
-       }
-
-       if ( ! $_comment ) {
-               return null;
-       }
-
-       /**
-        * Fires after a comment is retrieved.
-        *
-        * @since 2.3.0
-        *
-        * @param mixed $_comment Comment data.
-        */
-       $_comment = apply_filters( 'get_comment', $_comment );
-
-       if ( $output == OBJECT ) {
-               return $_comment;
-       } elseif ( $output == ARRAY_A ) {
-               return $_comment->to_array();
-       } elseif ( $output == ARRAY_N ) {
-               return array_values( $_comment->to_array() );
-       }
-       return $_comment;
-}
-
-/**
- * Retrieve a list of comments.
- *
- * The comment list can be for the blog as a whole or for an individual post.
- *
- * @since 2.7.0
- *
- * @param string|array $args Optional. Array or string of arguments. See {@see WP_Comment_Query::parse_query()}
- *                           for information on accepted arguments. Default empty.
- * @return int|array List of comments or number of found comments if `$count` argument is true.
- */
-function get_comments( $args = '' ) {
-       $query = new WP_Comment_Query;
-       return $query->query( $args );
-}
-
-/**
- * Retrieve all of the WordPress supported comment statuses.
- *
- * Comments have a limited set of valid status values, this provides the comment
- * status values and descriptions.
- *
- * @since 2.7.0
- *
- * @return array List of comment statuses.
- */
-function get_comment_statuses() {
-       $status = array(
-               'hold'          => __('Unapproved'),
-               /* translators: comment status  */
-               'approve'       => _x('Approved', 'adjective'),
-               /* translators: comment status */
-               'spam'          => _x('Spam', 'adjective'),
-               /* translators: comment status */
-               'trash'         => _x('Trash', 'adjective'),
-       );
-
-       return $status;
-}
-
-/**
- * Gets the default comment status for a post type.
- *
- * @since 4.3.0
- *
- * @param string $post_type    Optional. Post type. Default 'post'.
- * @param string $comment_type Optional. Comment type. Default 'comment'.
- * @return string Expected return value is 'open' or 'closed'.
- */
-function get_default_comment_status( $post_type = 'post', $comment_type = 'comment' ) {
-       switch ( $comment_type ) {
-               case 'pingback' :
-               case 'trackback' :
-                       $supports = 'trackbacks';
-                       $option = 'ping';
-                       break;
-               default :
-                       $supports = 'comments';
-                       $option = 'comment';
-       }
-
-       // Set the status.
-       if ( 'page' === $post_type ) {
-               $status = 'closed';
-       } elseif ( post_type_supports( $post_type, $supports ) ) {
-               $status = get_option( "default_{$option}_status" );
-       } else {
-               $status = 'closed';
-       }
-
-       /**
-        * Filter the default comment status for the given post type.
-        *
-        * @since 4.3.0
-        *
-        * @param string $status       Default status for the given post type,
-        *                             either 'open' or 'closed'.
-        * @param string $post_type    Post type. Default is `post`.
-        * @param string $comment_type Type of comment. Default is `comment`.
-        */
-       return apply_filters( 'get_default_comment_status' , $status, $post_type, $comment_type );
-}
-
-/**
- * The date the last comment was modified.
- *
- * @since 1.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @staticvar array $cache_lastcommentmodified
- *
- * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
- *             or 'server' locations.
- * @return string Last comment modified date.
- */
-function get_lastcommentmodified($timezone = 'server') {
-       global $wpdb;
-       static $cache_lastcommentmodified = array();
-
-       if ( isset($cache_lastcommentmodified[$timezone]) )
-               return $cache_lastcommentmodified[$timezone];
-
-       $add_seconds_server = date('Z');
-
-       switch ( strtolower($timezone)) {
-               case 'gmt':
-                       $lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
-                       break;
-               case 'blog':
-                       $lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
-                       break;
-               case 'server':
-                       $lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
-                       break;
-       }
-
-       $cache_lastcommentmodified[$timezone] = $lastcommentmodified;
-
-       return $lastcommentmodified;
-}
-
-/**
- * The amount of comments in a post or total comments.
- *
- * A lot like {@link wp_count_comments()}, in that they both return comment
- * stats (albeit with different types). The {@link wp_count_comments()} actual
- * caches, but this function does not.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
- * @return array The amount of spam, approved, awaiting moderation, and total comments.
- */
-function get_comment_count( $post_id = 0 ) {
-       global $wpdb;
-
-       $post_id = (int) $post_id;
-
-       $where = '';
-       if ( $post_id > 0 ) {
-               $where = $wpdb->prepare("WHERE comment_post_ID = %d", $post_id);
-       }
-
-       $totals = (array) $wpdb->get_results("
-               SELECT comment_approved, COUNT( * ) AS total
-               FROM {$wpdb->comments}
-               {$where}
-               GROUP BY comment_approved
-       ", ARRAY_A);
-
-       $comment_count = array(
-               'approved'            => 0,
-               'awaiting_moderation' => 0,
-               'spam'                => 0,
-               'trash'               => 0,
-               'post-trashed'        => 0,
-               'total_comments'      => 0,
-               'all'                 => 0,
-       );
-
-       foreach ( $totals as $row ) {
-               switch ( $row['comment_approved'] ) {
-                       case 'trash':
-                               $comment_count['trash'] = $row['total'];
-                               break;
-                       case 'post-trashed':
-                               $comment_count['post-trashed'] = $row['total'];
-                               break;
-                       case 'spam':
-                               $comment_count['spam'] = $row['total'];
-                               $comment_count['total_comments'] += $row['total'];
-                               break;
-                       case '1':
-                               $comment_count['approved'] = $row['total'];
-                               $comment_count['total_comments'] += $row['total'];
-                               $comment_count['all'] += $row['total'];
-                               break;
-                       case '0':
-                               $comment_count['awaiting_moderation'] = $row['total'];
-                               $comment_count['total_comments'] += $row['total'];
-                               $comment_count['all'] += $row['total'];
-                               break;
-                       default:
-                               break;
-               }
-       }
-
-       return $comment_count;
-}
-
-//
-// Comment meta functions
-//
-
-/**
- * Add meta data field to a comment.
- *
- * @since 2.9.0
- * @link https://codex.wordpress.org/Function_Reference/add_comment_meta
- *
- * @param int $comment_id Comment ID.
- * @param string $meta_key Metadata name.
- * @param mixed $meta_value Metadata value.
- * @param bool $unique Optional, default is false. Whether the same key should not be added.
- * @return int|bool Meta ID on success, false on failure.
- */
-function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
-       return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
-}
-
-/**
- * Remove metadata matching criteria from a comment.
- *
- * You can match based on the key, or key and value. Removing based on key and
- * value, will keep from removing duplicate metadata with the same key. It also
- * allows removing all metadata matching key, if needed.
- *
- * @since 2.9.0
- * @link https://codex.wordpress.org/Function_Reference/delete_comment_meta
- *
- * @param int $comment_id comment ID
- * @param string $meta_key Metadata name.
- * @param mixed $meta_value Optional. Metadata value.
- * @return bool True on success, false on failure.
- */
-function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
-       return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
-}
-
-/**
- * Retrieve comment meta field for a comment.
- *
- * @since 2.9.0
- * @link https://codex.wordpress.org/Function_Reference/get_comment_meta
- *
- * @param int $comment_id Comment ID.
- * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
- * @param bool $single Whether to return a single value.
- * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
- *  is true.
- */
-function get_comment_meta($comment_id, $key = '', $single = false) {
-       return get_metadata('comment', $comment_id, $key, $single);
-}
-
-/**
- * Update comment meta field based on comment ID.
- *
- * Use the $prev_value parameter to differentiate between meta fields with the
- * same key and comment ID.
- *
- * If the meta field for the comment does not exist, it will be added.
- *
- * @since 2.9.0
- * @link https://codex.wordpress.org/Function_Reference/update_comment_meta
- *
- * @param int $comment_id Comment ID.
- * @param string $meta_key Metadata key.
- * @param mixed $meta_value Metadata value.
- * @param mixed $prev_value Optional. Previous value to check before removing.
- * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
- */
-function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
-       return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
-}
-
-/**
- * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
- * to recall previous comments by this commentator that are still held in moderation.
- *
- * @param WP_Comment $comment Comment object.
- * @param object     $user    Comment author's object.
- *
- * @since 3.4.0
- */
-function wp_set_comment_cookies($comment, $user) {
-       if ( $user->exists() )
-               return;
-
-       /**
-        * Filter the lifetime of the comment cookie in seconds.
-        *
-        * @since 2.8.0
-        *
-        * @param int $seconds Comment cookie lifetime. Default 30000000.
-        */
-       $comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
-       $secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
-       setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
-       setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
-       setcookie( 'comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
-}
-
-/**
- * Sanitizes the cookies sent to the user already.
- *
- * Will only do anything if the cookies have already been created for the user.
- * Mostly used after cookies had been sent to use elsewhere.
- *
- * @since 2.0.4
- */
-function sanitize_comment_cookies() {
-       if ( isset( $_COOKIE['comment_author_' . COOKIEHASH] ) ) {
-               /**
-                * Filter the comment author's name cookie before it is set.
-                *
-                * When this filter hook is evaluated in wp_filter_comment(),
-                * the comment author's name string is passed.
-                *
-                * @since 1.5.0
-                *
-                * @param string $author_cookie The comment author name cookie.
-                */
-               $comment_author = apply_filters( 'pre_comment_author_name', $_COOKIE['comment_author_' . COOKIEHASH] );
-               $comment_author = wp_unslash($comment_author);
-               $comment_author = esc_attr($comment_author);
-               $_COOKIE['comment_author_' . COOKIEHASH] = $comment_author;
-       }
-
-       if ( isset( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
-               /**
-                * Filter the comment author's email cookie before it is set.
-                *
-                * When this filter hook is evaluated in wp_filter_comment(),
-                * the comment author's email string is passed.
-                *
-                * @since 1.5.0
-                *
-                * @param string $author_email_cookie The comment author email cookie.
-                */
-               $comment_author_email = apply_filters( 'pre_comment_author_email', $_COOKIE['comment_author_email_' . COOKIEHASH] );
-               $comment_author_email = wp_unslash($comment_author_email);
-               $comment_author_email = esc_attr($comment_author_email);
-               $_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
-       }
-
-       if ( isset( $_COOKIE['comment_author_url_' . COOKIEHASH] ) ) {
-               /**
-                * Filter the comment author's URL cookie before it is set.
-                *
-                * When this filter hook is evaluated in wp_filter_comment(),
-                * the comment author's URL string is passed.
-                *
-                * @since 1.5.0
-                *
-                * @param string $author_url_cookie The comment author URL cookie.
-                */
-               $comment_author_url = apply_filters( 'pre_comment_author_url', $_COOKIE['comment_author_url_' . COOKIEHASH] );
-               $comment_author_url = wp_unslash($comment_author_url);
-               $_COOKIE['comment_author_url_'.COOKIEHASH] = $comment_author_url;
-       }
-}
-
-/**
- * Validates whether this comment is allowed to be made.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $commentdata Contains information on the comment
- * @return int|string Signifies the approval status (0|1|'spam')
- */
-function wp_allow_comment( $commentdata ) {
-       global $wpdb;
-
-       // Simple duplicate check
-       // expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
-       $dupe = $wpdb->prepare(
-               "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ",
-               wp_unslash( $commentdata['comment_post_ID'] ),
-               wp_unslash( $commentdata['comment_parent'] ),
-               wp_unslash( $commentdata['comment_author'] )
-       );
-       if ( $commentdata['comment_author_email'] ) {
-               $dupe .= $wpdb->prepare(
-                       "OR comment_author_email = %s ",
-                       wp_unslash( $commentdata['comment_author_email'] )
-               );
-       }
-       $dupe .= $wpdb->prepare(
-               ") AND comment_content = %s LIMIT 1",
-               wp_unslash( $commentdata['comment_content'] )
-       );
-
-       $dupe_id = $wpdb->get_var( $dupe );
-
-       /**
-        * Filters the ID, if any, of the duplicate comment found when creating a new comment.
-        *
-        * Return an empty value from this filter to allow what WP considers a duplicate comment.
-        *
-        * @since 4.4.0
-        *
-        * @param int   $dupe_id     ID of the comment identified as a duplicate.
-        * @param array $commentdata Data for the comment being created.
-        */
-       $dupe_id = apply_filters( 'duplicate_comment_id', $dupe_id, $commentdata );
-
-       if ( $dupe_id ) {
-               /**
-                * Fires immediately after a duplicate comment is detected.
-                *
-                * @since 3.0.0
-                *
-                * @param array $commentdata Comment data.
-                */
-               do_action( 'comment_duplicate_trigger', $commentdata );
-               if ( defined( 'DOING_AJAX' ) ) {
-                       die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
-               }
-               wp_die( __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ), 409 );
-       }
-
-       /**
-        * Fires immediately before a comment is marked approved.
-        *
-        * Allows checking for comment flooding.
-        *
-        * @since 2.3.0
-        *
-        * @param string $comment_author_IP    Comment author's IP address.
-        * @param string $comment_author_email Comment author's email.
-        * @param string $comment_date_gmt     GMT date the comment was posted.
-        */
-       do_action(
-               'check_comment_flood',
-               $commentdata['comment_author_IP'],
-               $commentdata['comment_author_email'],
-               $commentdata['comment_date_gmt']
-       );
-
-       if ( ! empty( $commentdata['user_id'] ) ) {
-               $user = get_userdata( $commentdata['user_id'] );
-               $post_author = $wpdb->get_var( $wpdb->prepare(
-                       "SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1",
-                       $commentdata['comment_post_ID']
-               ) );
-       }
-
-       if ( isset( $user ) && ( $commentdata['user_id'] == $post_author || $user->has_cap( 'moderate_comments' ) ) ) {
-               // The author and the admins get respect.
-               $approved = 1;
-       } else {
-               // Everyone else's comments will be checked.
-               if ( check_comment(
-                       $commentdata['comment_author'],
-                       $commentdata['comment_author_email'],
-                       $commentdata['comment_author_url'],
-                       $commentdata['comment_content'],
-                       $commentdata['comment_author_IP'],
-                       $commentdata['comment_agent'],
-                       $commentdata['comment_type']
-               ) ) {
-                       $approved = 1;
-               } else {
-                       $approved = 0;
-               }
-
-               if ( wp_blacklist_check(
-                       $commentdata['comment_author'],
-                       $commentdata['comment_author_email'],
-                       $commentdata['comment_author_url'],
-                       $commentdata['comment_content'],
-                       $commentdata['comment_author_IP'],
-                       $commentdata['comment_agent']
-               ) ) {
-                       $approved = EMPTY_TRASH_DAYS ? 'trash' : 'spam';
-               }
-       }
-
-       /**
-        * Filter a comment's approval status before it is set.
-        *
-        * @since 2.1.0
-        *
-        * @param bool|string $approved    The approval status. Accepts 1, 0, or 'spam'.
-        * @param array       $commentdata Comment data.
-        */
-       $approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
-       return $approved;
-}
-
-/**
- * Check whether comment flooding is occurring.
- *
- * Won't run, if current user can manage options, so to not block
- * administrators.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $ip Comment IP.
- * @param string $email Comment author email address.
- * @param string $date MySQL time string.
- */
-function check_comment_flood_db( $ip, $email, $date ) {
-       global $wpdb;
-       // don't throttle admins or moderators
-       if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
-               return;
-       }
-       $hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
-
-       if ( is_user_logged_in() ) {
-               $user = get_current_user_id();
-               $check_column = '`user_id`';
-       } else {
-               $user = $ip;
-               $check_column = '`comment_author_IP`';
-       }
-
-       $sql = $wpdb->prepare(
-               "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( $check_column = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1",
-               $hour_ago,
-               $user,
-               $email
-       );
-       $lasttime = $wpdb->get_var( $sql );
-       if ( $lasttime ) {
-               $time_lastcomment = mysql2date('U', $lasttime, false);
-               $time_newcomment  = mysql2date('U', $date, false);
-               /**
-                * Filter the comment flood status.
-                *
-                * @since 2.1.0
-                *
-                * @param bool $bool             Whether a comment flood is occurring. Default false.
-                * @param int  $time_lastcomment Timestamp of when the last comment was posted.
-                * @param int  $time_newcomment  Timestamp of when the new comment was posted.
-                */
-               $flood_die = apply_filters( 'comment_flood_filter', false, $time_lastcomment, $time_newcomment );
-               if ( $flood_die ) {
-                       /**
-                        * Fires before the comment flood message is triggered.
-                        *
-                        * @since 1.5.0
-                        *
-                        * @param int $time_lastcomment Timestamp of when the last comment was posted.
-                        * @param int $time_newcomment  Timestamp of when the new comment was posted.
-                        */
-                       do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
-
-                       if ( defined('DOING_AJAX') )
-                               die( __('You are posting comments too quickly. Slow down.') );
-
-                       wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
-               }
-       }
-}
-
-/**
- * Separates an array of comments into an array keyed by comment_type.
- *
- * @since 2.7.0
- *
- * @param array $comments Array of comments
- * @return array Array of comments keyed by comment_type.
- */
-function separate_comments(&$comments) {
-       $comments_by_type = array('comment' => array(), 'trackback' => array(), 'pingback' => array(), 'pings' => array());
-       $count = count($comments);
-       for ( $i = 0; $i < $count; $i++ ) {
-               $type = $comments[$i]->comment_type;
-               if ( empty($type) )
-                       $type = 'comment';
-               $comments_by_type[$type][] = &$comments[$i];
-               if ( 'trackback' == $type || 'pingback' == $type )
-                       $comments_by_type['pings'][] = &$comments[$i];
-       }
-
-       return $comments_by_type;
-}
-
-/**
- * Calculate the total number of comment pages.
- *
- * @since 2.7.0
- *
- * @uses Walker_Comment
- *
- * @global WP_Query $wp_query
- *
- * @param array $comments Optional array of WP_Comment objects. Defaults to $wp_query->comments
- * @param int   $per_page Optional comments per page.
- * @param bool  $threaded Optional control over flat or threaded comments.
- * @return int Number of comment pages.
- */
-function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
-       global $wp_query;
-
-       if ( null === $comments && null === $per_page && null === $threaded && !empty($wp_query->max_num_comment_pages) )
-               return $wp_query->max_num_comment_pages;
-
-       if ( ( ! $comments || ! is_array( $comments ) ) && ! empty( $wp_query->comments )  )
-               $comments = $wp_query->comments;
-
-       if ( empty($comments) )
-               return 0;
-
-       if ( ! get_option( 'page_comments' ) ) {
-               return 1;
-       }
-
-       if ( !isset($per_page) )
-               $per_page = (int) get_query_var('comments_per_page');
-       if ( 0 === $per_page )
-               $per_page = (int) get_option('comments_per_page');
-       if ( 0 === $per_page )
-               return 1;
-
-       if ( !isset($threaded) )
-               $threaded = get_option('thread_comments');
-
-       if ( $threaded ) {
-               $walker = new Walker_Comment;
-               $count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
-       } else {
-               $count = ceil( count( $comments ) / $per_page );
-       }
-
-       return $count;
-}
-
-/**
- * Calculate what page number a comment will appear on for comment paging.
- *
- * @since 2.7.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int   $comment_ID Comment ID.
- * @param array $args {
- *      Array of optional arguments.
- *      @type string     $type      Limit paginated comments to those matching a given type. Accepts 'comment',
- *                                  'trackback', 'pingback', 'pings' (trackbacks and pingbacks), or 'all'.
- *                                  Default is 'all'.
- *      @type int        $per_page  Per-page count to use when calculating pagination. Defaults to the value of the
- *                                  'comments_per_page' option.
- *      @type int|string $max_depth If greater than 1, comment page will be determined for the top-level parent of
- *                                  `$comment_ID`. Defaults to the value of the 'thread_comments_depth' option.
- * } *
- * @return int|null Comment page number or null on error.
- */
-function get_page_of_comment( $comment_ID, $args = array() ) {
-       global $wpdb;
-
-       $page = null;
-
-       if ( !$comment = get_comment( $comment_ID ) )
-               return;
-
-       $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
-       $args = wp_parse_args( $args, $defaults );
-       $original_args = $args;
-
-       // Order of precedence: 1. `$args['per_page']`, 2. 'comments_per_page' query_var, 3. 'comments_per_page' option.
-       if ( get_option( 'page_comments' ) ) {
-               if ( '' === $args['per_page'] ) {
-                       $args['per_page'] = get_query_var( 'comments_per_page' );
-               }
-
-               if ( '' === $args['per_page'] ) {
-                       $args['per_page'] = get_option( 'comments_per_page' );
-               }
-       }
-
-       if ( empty($args['per_page']) ) {
-               $args['per_page'] = 0;
-               $args['page'] = 0;
-       }
-
-       if ( $args['per_page'] < 1 ) {
-               $page = 1;
-       }
-
-       if ( null === $page ) {
-               if ( '' === $args['max_depth'] ) {
-                       if ( get_option('thread_comments') )
-                               $args['max_depth'] = get_option('thread_comments_depth');
-                       else
-                               $args['max_depth'] = -1;
-               }
-
-               // Find this comment's top level parent if threading is enabled
-               if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
-                       return get_page_of_comment( $comment->comment_parent, $args );
-
-               $comment_args = array(
-                       'type'       => $args['type'],
-                       'post_id'    => $comment->comment_post_ID,
-                       'fields'     => 'ids',
-                       'count'      => true,
-                       'status'     => 'approve',
-                       'parent'     => 0,
-                       'date_query' => array(
-                               array(
-                                       'column' => "$wpdb->comments.comment_date_gmt",
-                                       'before' => $comment->comment_date_gmt,
-                               )
-                       ),
-               );
-
-               $comment_query = new WP_Comment_Query();
-               $older_comment_count = $comment_query->query( $comment_args );
-
-               // No older comments? Then it's page #1.
-               if ( 0 == $older_comment_count ) {
-                       $page = 1;
-
-               // Divide comments older than this one by comments per page to get this comment's page number
-               } else {
-                       $page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
-               }
-       }
-
-       /**
-        * Filters the calculated page on which a comment appears.
-        *
-        * @since 4.4.0
-        *
-        * @param int   $page          Comment page.
-        * @param array $args {
-        *     Arguments used to calculate pagination. These include arguments auto-detected by the function,
-        *     based on query vars, system settings, etc. For pristine arguments passed to the function,
-        *     see `$original_args`.
-        *
-        *     @type string $type      Type of comments to count.
-        *     @type int    $page      Calculated current page.
-        *     @type int    $per_page  Calculated number of comments per page.
-        *     @type int    $max_depth Maximum comment threading depth allowed.
-        * }
-        * @param array $original_args {
-        *     Array of arguments passed to the function. Some or all of these may not be set.
-        *
-        *     @type string $type      Type of comments to count.
-        *     @type int    $page      Current comment page.
-        *     @type int    $per_page  Number of comments per page.
-        *     @type int    $max_depth Maximum comment threading depth allowed.
-        * }
-        */
-       return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args );
-}
-
-/**
- * Does comment contain blacklisted characters or words.
- *
- * @since 1.5.0
- *
- * @param string $author The author of the comment
- * @param string $email The email of the comment
- * @param string $url The url used in the comment
- * @param string $comment The comment content
- * @param string $user_ip The comment author IP address
- * @param string $user_agent The author's browser user agent
- * @return bool True if comment contains blacklisted content, false if comment does not
- */
-function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
-       /**
-        * Fires before the comment is tested for blacklisted characters or words.
-        *
-        * @since 1.5.0
-        *
-        * @param string $author     Comment author.
-        * @param string $email      Comment author's email.
-        * @param string $url        Comment author's URL.
-        * @param string $comment    Comment content.
-        * @param string $user_ip    Comment author's IP address.
-        * @param string $user_agent Comment author's browser user agent.
-        */
-       do_action( 'wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent );
-
-       $mod_keys = trim( get_option('blacklist_keys') );
-       if ( '' == $mod_keys )
-               return false; // If moderation keys are empty
-       $words = explode("\n", $mod_keys );
-
-       foreach ( (array) $words as $word ) {
-               $word = trim($word);
-
-               // Skip empty lines
-               if ( empty($word) ) { continue; }
-
-               // Do some escaping magic so that '#' chars in the
-               // spam words don't break things:
-               $word = preg_quote($word, '#');
-
-               $pattern = "#$word#i";
-               if (
-                          preg_match($pattern, $author)
-                       || preg_match($pattern, $email)
-                       || preg_match($pattern, $url)
-                       || preg_match($pattern, $comment)
-                       || preg_match($pattern, $user_ip)
-                       || preg_match($pattern, $user_agent)
-                )
-                       return true;
-       }
-       return false;
-}
-
-/**
- * Retrieve total comments for blog or single post.
- *
- * The properties of the returned object contain the 'moderated', 'approved',
- * and spam comments for either the entire blog or single post. Those properties
- * contain the amount of comments that match the status. The 'total_comments'
- * property contains the integer of total comments.
- *
- * The comment stats are cached and then retrieved, if they already exist in the
- * cache.
- *
- * @since 2.5.0
- *
- * @param int $post_id Optional. Post ID.
- * @return object|array Comment stats.
- */
-function wp_count_comments( $post_id = 0 ) {
-       $post_id = (int) $post_id;
-
-       /**
-        * Filter the comments count for a given post.
-        *
-        * @since 2.7.0
-        *
-        * @param array $count   An empty array.
-        * @param int   $post_id The post ID.
-        */
-       $filtered = apply_filters( 'wp_count_comments', array(), $post_id );
-       if ( ! empty( $filtered ) ) {
-               return $filtered;
-       }
-
-       $count = wp_cache_get( "comments-{$post_id}", 'counts' );
-       if ( false !== $count ) {
-               return $count;
-       }
-
-       $stats = get_comment_count( $post_id );
-       $stats['moderated'] = $stats['awaiting_moderation'];
-       unset( $stats['awaiting_moderation'] );
-
-       $stats_object = (object) $stats;
-       wp_cache_set( "comments-{$post_id}", $stats_object, 'counts' );
-
-       return $stats_object;
-}
-
-/**
- * Trashes or deletes a comment.
- *
- * The comment is moved to trash instead of permanently deleted unless trash is
- * disabled, item is already in the trash, or $force_delete is true.
- *
- * The post comment count will be updated if the comment was approved and has a
- * post ID available.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
- * @param bool           $force_delete Whether to bypass trash and force deletion. Default is false.
- * @return bool True on success, false on failure.
- */
-function wp_delete_comment($comment_id, $force_delete = false) {
-       global $wpdb;
-       if (!$comment = get_comment($comment_id))
-               return false;
-
-       if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ) ) )
-               return wp_trash_comment($comment_id);
-
-       /**
-        * Fires immediately before a comment is deleted from the database.
-        *
-        * @since 1.2.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'delete_comment', $comment->comment_ID );
-
-       // Move children up a level.
-       $children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID) );
-       if ( !empty($children) ) {
-               $wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment->comment_ID));
-               clean_comment_cache($children);
-       }
-
-       // Delete metadata
-       $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
-       foreach ( $meta_ids as $mid )
-               delete_metadata_by_mid( 'comment', $mid );
-
-       if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) )
-               return false;
-
-       /**
-        * Fires immediately after a comment is deleted from the database.
-        *
-        * @since 2.9.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'deleted_comment', $comment->comment_ID );
-
-       $post_id = $comment->comment_post_ID;
-       if ( $post_id && $comment->comment_approved == 1 )
-               wp_update_comment_count($post_id);
-
-       clean_comment_cache( $comment->comment_ID );
-
-       /** This action is documented in wp-includes/comment-functions.php */
-       do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
-
-       wp_transition_comment_status('delete', $comment->comment_approved, $comment);
-       return true;
-}
-
-/**
- * Moves a comment to the Trash
- *
- * If trash is disabled, comment is permanently deleted.
- *
- * @since 2.9.0
- *
- * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
- * @return bool True on success, false on failure.
- */
-function wp_trash_comment($comment_id) {
-       if ( !EMPTY_TRASH_DAYS )
-               return wp_delete_comment($comment_id, true);
-
-       if ( !$comment = get_comment($comment_id) )
-               return false;
-
-       /**
-        * Fires immediately before a comment is sent to the Trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'trash_comment', $comment->comment_ID );
-
-       if ( wp_set_comment_status( $comment, 'trash' ) ) {
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
-               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
-               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
-
-               /**
-                * Fires immediately after a comment is sent to Trash.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_id The comment ID.
-                */
-               do_action( 'trashed_comment', $comment->comment_ID );
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * Removes a comment from the Trash
- *
- * @since 2.9.0
- *
- * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
- * @return bool True on success, false on failure.
- */
-function wp_untrash_comment($comment_id) {
-       $comment = get_comment( $comment_id );
-       if ( ! $comment ) {
-               return false;
-       }
-
-       /**
-        * Fires immediately before a comment is restored from the Trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'untrash_comment', $comment->comment_ID );
-
-       $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
-       if ( empty($status) )
-               $status = '0';
-
-       if ( wp_set_comment_status( $comment, $status ) ) {
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
-               /**
-                * Fires immediately after a comment is restored from the Trash.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_id The comment ID.
-                */
-               do_action( 'untrashed_comment', $comment->comment_ID );
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * Marks a comment as Spam
- *
- * @since 2.9.0
- *
- * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
- * @return bool True on success, false on failure.
- */
-function wp_spam_comment( $comment_id ) {
-       $comment = get_comment( $comment_id );
-       if ( ! $comment ) {
-               return false;
-       }
-
-       /**
-        * Fires immediately before a comment is marked as Spam.
-        *
-        * @since 2.9.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'spam_comment', $comment->comment_ID );
-
-       if ( wp_set_comment_status( $comment, 'spam' ) ) {
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
-               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
-               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
-               /**
-                * Fires immediately after a comment is marked as Spam.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_id The comment ID.
-                */
-               do_action( 'spammed_comment', $comment->comment_ID );
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * Removes a comment from the Spam
- *
- * @since 2.9.0
- *
- * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
- * @return bool True on success, false on failure.
- */
-function wp_unspam_comment( $comment_id ) {
-       $comment = get_comment( $comment_id );
-       if ( ! $comment ) {
-               return false;
-       }
-
-       /**
-        * Fires immediately before a comment is unmarked as Spam.
-        *
-        * @since 2.9.0
-        *
-        * @param int $comment_id The comment ID.
-        */
-       do_action( 'unspam_comment', $comment->comment_ID );
-
-       $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
-       if ( empty($status) )
-               $status = '0';
-
-       if ( wp_set_comment_status( $comment, $status ) ) {
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
-               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
-               /**
-                * Fires immediately after a comment is unmarked as Spam.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_id The comment ID.
-                */
-               do_action( 'unspammed_comment', $comment->comment_ID );
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * The status of a comment by ID.
- *
- * @since 1.0.0
- *
- * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
- * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
- */
-function wp_get_comment_status($comment_id) {
-       $comment = get_comment($comment_id);
-       if ( !$comment )
-               return false;
-
-       $approved = $comment->comment_approved;
-
-       if ( $approved == null )
-               return false;
-       elseif ( $approved == '1' )
-               return 'approved';
-       elseif ( $approved == '0' )
-               return 'unapproved';
-       elseif ( $approved == 'spam' )
-               return 'spam';
-       elseif ( $approved == 'trash' )
-               return 'trash';
-       else
-               return false;
-}
-
-/**
- * Call hooks for when a comment status transition occurs.
- *
- * Calls hooks for comment status transitions. If the new comment status is not the same
- * as the previous comment status, then two hooks will be ran, the first is
- * 'transition_comment_status' with new status, old status, and comment data. The
- * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
- * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
- * comment data.
- *
- * The final action will run whether or not the comment statuses are the same. The
- * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
- * parameter and COMMENTTYPE is comment_type comment data.
- *
- * @since 2.7.0
- *
- * @param string $new_status New comment status.
- * @param string $old_status Previous comment status.
- * @param object $comment Comment data.
- */
-function wp_transition_comment_status($new_status, $old_status, $comment) {
-       /*
-        * Translate raw statuses to human readable formats for the hooks.
-        * This is not a complete list of comment status, it's only the ones
-        * that need to be renamed
-        */
-       $comment_statuses = array(
-               0         => 'unapproved',
-               'hold'    => 'unapproved', // wp_set_comment_status() uses "hold"
-               1         => 'approved',
-               'approve' => 'approved', // wp_set_comment_status() uses "approve"
-       );
-       if ( isset($comment_statuses[$new_status]) ) $new_status = $comment_statuses[$new_status];
-       if ( isset($comment_statuses[$old_status]) ) $old_status = $comment_statuses[$old_status];
-
-       // Call the hooks
-       if ( $new_status != $old_status ) {
-               /**
-                * Fires when the comment status is in transition.
-                *
-                * @since 2.7.0
-                *
-                * @param int|string $new_status The new comment status.
-                * @param int|string $old_status The old comment status.
-                * @param object     $comment    The comment data.
-                */
-               do_action( 'transition_comment_status', $new_status, $old_status, $comment );
-               /**
-                * Fires when the comment status is in transition from one specific status to another.
-                *
-                * The dynamic portions of the hook name, `$old_status`, and `$new_status`,
-                * refer to the old and new comment statuses, respectively.
-                *
-                * @since 2.7.0
-                *
-                * @param WP_Comment $comment Comment object.
-                */
-               do_action( "comment_{$old_status}_to_{$new_status}", $comment );
-       }
-       /**
-        * Fires when the status of a specific comment type is in transition.
-        *
-        * The dynamic portions of the hook name, `$new_status`, and `$comment->comment_type`,
-        * refer to the new comment status, and the type of comment, respectively.
-        *
-        * Typical comment types include an empty string (standard comment), 'pingback',
-        * or 'trackback'.
-        *
-        * @since 2.7.0
-        *
-        * @param int        $comment_ID The comment ID.
-        * @param WP_Comment $comment    Comment object.
-        */
-       do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
-}
-
-/**
- * Get current commenter's name, email, and URL.
- *
- * Expects cookies content to already be sanitized. User of this function might
- * wish to recheck the returned array for validity.
- *
- * @see sanitize_comment_cookies() Use to sanitize cookies
- *
- * @since 2.0.4
- *
- * @return array Comment author, email, url respectively.
- */
-function wp_get_current_commenter() {
-       // Cookies should already be sanitized.
-
-       $comment_author = '';
-       if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) )
-               $comment_author = $_COOKIE['comment_author_'.COOKIEHASH];
-
-       $comment_author_email = '';
-       if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) )
-               $comment_author_email = $_COOKIE['comment_author_email_'.COOKIEHASH];
-
-       $comment_author_url = '';
-       if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
-               $comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
-
-       /**
-        * Filter the current commenter's name, email, and URL.
-        *
-        * @since 3.1.0
-        *
-        * @param array $comment_author_data {
-        *     An array of current commenter variables.
-        *
-        *     @type string $comment_author       The name of the author of the comment. Default empty.
-        *     @type string $comment_author_email The email address of the `$comment_author`. Default empty.
-        *     @type string $comment_author_url   The URL address of the `$comment_author`. Default empty.
-        * }
-        */
-       return apply_filters( 'wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url') );
-}
-
-/**
- * Inserts a comment into the database.
- *
- * @since 2.0.0
- * @since 4.4.0 Introduced `$comment_meta` argument.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $commentdata {
- *     Array of arguments for inserting a new comment.
- *
- *     @type string     $comment_agent        The HTTP user agent of the `$comment_author` when
- *                                            the comment was submitted. Default empty.
- *     @type int|string $comment_approved     Whether the comment has been approved. Default 1.
- *     @type string     $comment_author       The name of the author of the comment. Default empty.
- *     @type string     $comment_author_email The email address of the `$comment_author`. Default empty.
- *     @type string     $comment_author_IP    The IP address of the `$comment_author`. Default empty.
- *     @type string     $comment_author_url   The URL address of the `$comment_author`. Default empty.
- *     @type string     $comment_content      The content of the comment. Default empty.
- *     @type string     $comment_date         The date the comment was submitted. To set the date
- *                                            manually, `$comment_date_gmt` must also be specified.
- *                                            Default is the current time.
- *     @type string     $comment_date_gmt     The date the comment was submitted in the GMT timezone.
- *                                            Default is `$comment_date` in the site's GMT timezone.
- *     @type int        $comment_karma        The karma of the comment. Default 0.
- *     @type int        $comment_parent       ID of this comment's parent, if any. Default 0.
- *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
- *                                            Default empty.
- *     @type string     $comment_type         Comment type. Default empty.
- *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
- *                                            new comment.
- *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
- * }
- * @return int|false The new comment's ID on success, false on failure.
- */
-function wp_insert_comment( $commentdata ) {
-       global $wpdb;
-       $data = wp_unslash( $commentdata );
-
-       $comment_author       = ! isset( $data['comment_author'] )       ? '' : $data['comment_author'];
-       $comment_author_email = ! isset( $data['comment_author_email'] ) ? '' : $data['comment_author_email'];
-       $comment_author_url   = ! isset( $data['comment_author_url'] )   ? '' : $data['comment_author_url'];
-       $comment_author_IP    = ! isset( $data['comment_author_IP'] )    ? '' : $data['comment_author_IP'];
-
-       $comment_date     = ! isset( $data['comment_date'] )     ? current_time( 'mysql' )            : $data['comment_date'];
-       $comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt'];
-
-       $comment_post_ID  = ! isset( $data['comment_post_ID'] )  ? '' : $data['comment_post_ID'];
-       $comment_content  = ! isset( $data['comment_content'] )  ? '' : $data['comment_content'];
-       $comment_karma    = ! isset( $data['comment_karma'] )    ? 0  : $data['comment_karma'];
-       $comment_approved = ! isset( $data['comment_approved'] ) ? 1  : $data['comment_approved'];
-       $comment_agent    = ! isset( $data['comment_agent'] )    ? '' : $data['comment_agent'];
-       $comment_type     = ! isset( $data['comment_type'] )     ? '' : $data['comment_type'];
-       $comment_parent   = ! isset( $data['comment_parent'] )   ? 0  : $data['comment_parent'];
-
-       $user_id  = ! isset( $data['user_id'] ) ? 0 : $data['user_id'];
-
-       $compacted = compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id' );
-       if ( ! $wpdb->insert( $wpdb->comments, $compacted ) ) {
-               return false;
-       }
-
-       $id = (int) $wpdb->insert_id;
-
-       if ( $comment_approved == 1 ) {
-               wp_update_comment_count( $comment_post_ID );
-       }
-       $comment = get_comment( $id );
-
-       // If metadata is provided, store it.
-       if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) {
-               foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) {
-                       add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true );
-               }
-       }
-
-       /**
-        * Fires immediately after a comment is inserted into the database.
-        *
-        * @since 2.8.0
-        *
-        * @param int        $id      The comment ID.
-        * @param WP_Comment $comment Comment object.
-        */
-       do_action( 'wp_insert_comment', $id, $comment );
-
-       wp_cache_set( 'last_changed', microtime(), 'comment' );
-
-       return $id;
-}
-
-/**
- * Filters and sanitizes comment data.
- *
- * Sets the comment data 'filtered' field to true when finished. This can be
- * checked as to whether the comment should be filtered and to keep from
- * filtering the same comment more than once.
- *
- * @since 2.0.0
- *
- * @param array $commentdata Contains information on the comment.
- * @return array Parsed comment information.
- */
-function wp_filter_comment($commentdata) {
-       if ( isset( $commentdata['user_ID'] ) ) {
-               /**
-                * Filter the comment author's user id before it is set.
-                *
-                * The first time this filter is evaluated, 'user_ID' is checked
-                * (for back-compat), followed by the standard 'user_id' value.
-                *
-                * @since 1.5.0
-                *
-                * @param int $user_ID The comment author's user ID.
-                */
-               $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_ID'] );
-       } elseif ( isset( $commentdata['user_id'] ) ) {
-               /** This filter is documented in wp-includes/comment-functions.php */
-               $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] );
-       }
-
-       /**
-        * Filter the comment author's browser user agent before it is set.
-        *
-        * @since 1.5.0
-        *
-        * @param int $comment_agent The comment author's browser user agent.
-        */
-       $commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
-       /** This filter is documented in wp-includes/comment-functions.php */
-       $commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] );
-       /**
-        * Filter the comment content before it is set.
-        *
-        * @since 1.5.0
-        *
-        * @param int $comment_content The comment content.
-        */
-       $commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] );
-       /**
-        * Filter the comment author's IP before it is set.
-        *
-        * @since 1.5.0
-        *
-        * @param int $comment_author_ip The comment author's IP.
-        */
-       $commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] );
-       /** This filter is documented in wp-includes/comment-functions.php */
-       $commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] );
-       /** This filter is documented in wp-includes/comment-functions.php */
-       $commentdata['comment_author_email'] = apply_filters( 'pre_comment_author_email', $commentdata['comment_author_email'] );
-       $commentdata['filtered'] = true;
-       return $commentdata;
-}
-
-/**
- * Whether a comment should be blocked because of comment flood.
- *
- * @since 2.1.0
- *
- * @param bool $block Whether plugin has already blocked comment.
- * @param int $time_lastcomment Timestamp for last comment.
- * @param int $time_newcomment Timestamp for new comment.
- * @return bool Whether comment should be blocked.
- */
-function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
-       if ( $block ) // a plugin has already blocked... we'll let that decision stand
-               return $block;
-       if ( ($time_newcomment - $time_lastcomment) < 15 )
-               return true;
-       return false;
-}
-
-/**
- * Adds a new comment to the database.
- *
- * Filters new comment to ensure that the fields are sanitized and valid before
- * inserting comment into database. Calls 'comment_post' action with comment ID
- * and whether comment is approved by WordPress. Also has 'preprocess_comment'
- * filter for processing the comment data before the function handles it.
- *
- * We use REMOTE_ADDR here directly. If you are behind a proxy, you should ensure
- * that it is properly set, such as in wp-config.php, for your environment.
- * See {@link https://core.trac.wordpress.org/ticket/9235}
- *
- * @since 1.5.0
- * @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
- *
- * @see wp_insert_comment()
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $commentdata {
- *     Comment data.
- *
- *     @type string $comment_author       The name of the comment author.
- *     @type string $comment_author_email The comment author email address.
- *     @type string $comment_author_url   The comment author URL.
- *     @type string $comment_content      The content of the comment.
- *     @type string $comment_date         The date the comment was submitted. Default is the current time.
- *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
- *                                        Default is `$comment_date` in the GMT timezone.
- *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
- *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
- *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
- *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
- *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
- *                                        in the `$_SERVER` superglobal sent in the original request.
- *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
- *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
- * }
- * @return int|false The ID of the comment on success, false on failure.
- */
-function wp_new_comment( $commentdata ) {
-       global $wpdb;
-
-       if ( isset( $commentdata['user_ID'] ) ) {
-               $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
-       }
-
-       $prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
-
-       /**
-        * Filter a comment's data before it is sanitized and inserted into the database.
-        *
-        * @since 1.5.0
-        *
-        * @param array $commentdata Comment data.
-        */
-       $commentdata = apply_filters( 'preprocess_comment', $commentdata );
-
-       $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
-       if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
-               $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
-       } elseif ( isset( $commentdata['user_id'] ) ) {
-               $commentdata['user_id'] = (int) $commentdata['user_id'];
-       }
-
-       $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
-       $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
-       $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
-
-       if ( ! isset( $commentdata['comment_author_IP'] ) ) {
-               $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
-       }
-       $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
-
-       if ( ! isset( $commentdata['comment_agent'] ) ) {
-               $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT']: '';
-       }
-       $commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
-
-       if ( empty( $commentdata['comment_date'] ) ) {
-               $commentdata['comment_date'] = current_time('mysql');
-       }
-
-       if ( empty( $commentdata['comment_date_gmt'] ) ) {
-               $commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
-       }
-
-       $commentdata = wp_filter_comment($commentdata);
-
-       $commentdata['comment_approved'] = wp_allow_comment($commentdata);
-
-       $comment_ID = wp_insert_comment($commentdata);
-       if ( ! $comment_ID ) {
-               $fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
-
-               foreach ( $fields as $field ) {
-                       if ( isset( $commentdata[ $field ] ) ) {
-                               $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
-                       }
-               }
-
-               $commentdata = wp_filter_comment( $commentdata );
-
-               $commentdata['comment_approved'] = wp_allow_comment( $commentdata );
-
-               $comment_ID = wp_insert_comment( $commentdata );
-               if ( ! $comment_ID ) {
-                       return false;
-               }
-       }
-
-       /**
-        * Fires immediately after a comment is inserted into the database.
-        *
-        * @since 1.2.0
-        *
-        * @param int        $comment_ID       The comment ID.
-        * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
-        */
-       do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'] );
-
-       return $comment_ID;
-}
-
-/**
- * Send a comment moderation notification to the comment moderator.
- *
- * @since 4.4.0
- *
- * @param int $comment_ID ID of the comment.
- * @return bool True on success, false on failure.
- */
-function wp_new_comment_notify_moderator( $comment_ID ) {
-       $comment = get_comment( $comment_ID );
-
-       // Only send notifications for pending comments.
-       $maybe_notify = ( '0' == $comment->comment_approved );
-
-       /** This filter is documented in wp-includes/comment-functions.php */
-       $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_ID );
-
-       if ( ! $maybe_notify ) {
-               return false;
-       }
-
-       return wp_notify_moderator( $comment_ID );
-}
-
-/**
- * Send a notification of a new comment to the post author.
- *
- * @since 4.4.0
- *
- * Uses the {@see 'notify_post_author'} filter to determine whether the post author
- * should be notified when a new comment is added, overriding site setting.
- *
- * @param int $comment_ID Comment ID.
- * @return bool True on success, false on failure.
- */
-function wp_new_comment_notify_postauthor( $comment_ID ) {
-       $comment = get_comment( $comment_ID );
-
-       $maybe_notify = get_option( 'comments_notify' );
-
-       /**
-        * Filter whether to send the post author new comment notification emails,
-        * overriding the site setting.
-        *
-        * @since 4.4.0
-        *
-        * @param bool $maybe_notify Whether to notify the post author about the new comment.
-        * @param int  $comment_ID   The ID of the comment for the notification.
-        */
-       $maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_ID );
-
-       /*
-        * wp_notify_postauthor() checks if notifying the author of their own comment.
-        * By default, it won't, but filters can override this.
-        */
-       if ( ! $maybe_notify ) {
-               return false;
-       }
-
-       // Only send notifications for approved comments.
-       if ( ! isset( $comment->comment_approved ) || 'spam' === $comment->comment_approved || ! $comment->comment_approved ) {
-               return false;
-       }
-
-       return wp_notify_postauthor( $comment_ID );
-}
-
-/**
- * Sets the status of a comment.
- *
- * The 'wp_set_comment_status' action is called after the comment is handled.
- * If the comment status is not in the list, then false is returned.
- *
- * @since 1.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
- * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
- * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default is false.
- * @return bool|WP_Error True on success, false or WP_Error on failure.
- */
-function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
-       global $wpdb;
-
-       switch ( $comment_status ) {
-               case 'hold':
-               case '0':
-                       $status = '0';
-                       break;
-               case 'approve':
-               case '1':
-                       $status = '1';
-                       add_action( 'wp_set_comment_status', 'wp_new_comment_notify_postauthor' );
-                       break;
-               case 'spam':
-                       $status = 'spam';
-                       break;
-               case 'trash':
-                       $status = 'trash';
-                       break;
-               default:
-                       return false;
-       }
-
-       $comment_old = clone get_comment($comment_id);
-
-       if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
-               if ( $wp_error )
-                       return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
-               else
-                       return false;
-       }
-
-       clean_comment_cache( $comment_old->comment_ID );
-
-       $comment = get_comment( $comment_old->comment_ID );
-
-       /**
-        * Fires immediately before transitioning a comment's status from one to another
-        * in the database.
-        *
-        * @since 1.5.0
-        *
-        * @param int         $comment_id     Comment ID.
-        * @param string|bool $comment_status Current comment status. Possible values include
-        *                                    'hold', 'approve', 'spam', 'trash', or false.
-        */
-       do_action( 'wp_set_comment_status', $comment->comment_ID, $comment_status );
-
-       wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
-
-       wp_update_comment_count($comment->comment_post_ID);
-
-       return true;
-}
-
-/**
- * Updates an existing comment in the database.
- *
- * Filters the comment and makes sure certain fields are valid before updating.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $commentarr Contains information on the comment.
- * @return int Comment was updated if value is 1, or was not updated if value is 0.
- */
-function wp_update_comment($commentarr) {
-       global $wpdb;
-
-       // First, get all of the original fields
-       $comment = get_comment($commentarr['comment_ID'], ARRAY_A);
-       if ( empty( $comment ) ) {
-               return 0;
-       }
-
-       // Make sure that the comment post ID is valid (if specified).
-       if ( isset( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
-               return 0;
-       }
-
-       // Escape data pulled from DB.
-       $comment = wp_slash($comment);
-
-       $old_status = $comment['comment_approved'];
-
-       // Merge old and new fields with new fields overwriting old ones.
-       $commentarr = array_merge($comment, $commentarr);
-
-       $commentarr = wp_filter_comment( $commentarr );
-
-       // Now extract the merged array.
-       $data = wp_unslash( $commentarr );
-
-       /**
-        * Filter the comment content before it is updated in the database.
-        *
-        * @since 1.5.0
-        *
-        * @param string $comment_content The comment data.
-        */
-       $data['comment_content'] = apply_filters( 'comment_save_pre', $data['comment_content'] );
-
-       $data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] );
-
-       if ( ! isset( $data['comment_approved'] ) ) {
-               $data['comment_approved'] = 1;
-       } elseif ( 'hold' == $data['comment_approved'] ) {
-               $data['comment_approved'] = 0;
-       } elseif ( 'approve' == $data['comment_approved'] ) {
-               $data['comment_approved'] = 1;
-       }
-
-       $comment_ID = $data['comment_ID'];
-       $comment_post_ID = $data['comment_post_ID'];
-       $keys = array( 'comment_post_ID', 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_type', 'comment_parent', 'user_id' );
-       $data = wp_array_slice_assoc( $data, $keys );
-       $rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
-
-       clean_comment_cache( $comment_ID );
-       wp_update_comment_count( $comment_post_ID );
-       /**
-        * Fires immediately after a comment is updated in the database.
-        *
-        * The hook also fires immediately before comment status transition hooks are fired.
-        *
-        * @since 1.2.0
-        *
-        * @param int $comment_ID The comment ID.
-        */
-       do_action( 'edit_comment', $comment_ID );
-       $comment = get_comment($comment_ID);
-       wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
-       return $rval;
-}
-
-/**
- * Whether to defer comment counting.
- *
- * When setting $defer to true, all post comment counts will not be updated
- * until $defer is set to false. When $defer is set to false, then all
- * previously deferred updated post comment counts will then be automatically
- * updated without having to call wp_update_comment_count() after.
- *
- * @since 2.5.0
- * @staticvar bool $_defer
- *
- * @param bool $defer
- * @return bool
- */
-function wp_defer_comment_counting($defer=null) {
-       static $_defer = false;
-
-       if ( is_bool($defer) ) {
-               $_defer = $defer;
-               // flush any deferred counts
-               if ( !$defer )
-                       wp_update_comment_count( null, true );
-       }
-
-       return $_defer;
-}
-
-/**
- * Updates the comment count for post(s).
- *
- * When $do_deferred is false (is by default) and the comments have been set to
- * be deferred, the post_id will be added to a queue, which will be updated at a
- * later date and only updated once per post ID.
- *
- * If the comments have not be set up to be deferred, then the post will be
- * updated. When $do_deferred is set to true, then all previous deferred post
- * IDs will be updated along with the current $post_id.
- *
- * @since 2.1.0
- * @see wp_update_comment_count_now() For what could cause a false return value
- *
- * @staticvar array $_deferred
- *
- * @param int $post_id Post ID
- * @param bool $do_deferred Whether to process previously deferred post comment counts
- * @return bool|void True on success, false on failure
- */
-function wp_update_comment_count($post_id, $do_deferred=false) {
-       static $_deferred = array();
-
-       if ( $do_deferred ) {
-               $_deferred = array_unique($_deferred);
-               foreach ( $_deferred as $i => $_post_id ) {
-                       wp_update_comment_count_now($_post_id);
-                       unset( $_deferred[$i] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */
-               }
-       }
-
-       if ( wp_defer_comment_counting() ) {
-               $_deferred[] = $post_id;
-               return true;
-       }
-       elseif ( $post_id ) {
-               return wp_update_comment_count_now($post_id);
-       }
-
-}
-
-/**
- * Updates the comment count for the post.
- *
- * @since 2.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int $post_id Post ID
- * @return bool True on success, false on '0' $post_id or if post with ID does not exist.
- */
-function wp_update_comment_count_now($post_id) {
-       global $wpdb;
-       $post_id = (int) $post_id;
-       if ( !$post_id )
-               return false;
-
-       wp_cache_delete( 'comments-0', 'counts' );
-       wp_cache_delete( "comments-{$post_id}", 'counts' );
-
-       if ( !$post = get_post($post_id) )
-               return false;
-
-       $old = (int) $post->comment_count;
-       $new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
-       $wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
-
-       clean_post_cache( $post );
-
-       /**
-        * Fires immediately after a post's comment count is updated in the database.
-        *
-        * @since 2.3.0
-        *
-        * @param int $post_id Post ID.
-        * @param int $new     The new comment count.
-        * @param int $old     The old comment count.
-        */
-       do_action( 'wp_update_comment_count', $post_id, $new, $old );
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'edit_post', $post_id, $post );
-
-       return true;
-}
-
-//
-// Ping and trackback functions.
-//
-
-/**
- * Finds a pingback server URI based on the given URL.
- *
- * Checks the HTML for the rel="pingback" link and x-pingback headers. It does
- * a check for the x-pingback headers first and returns that, if available. The
- * check for the rel="pingback" has more overhead than just the header.
- *
- * @since 1.5.0
- *
- * @param string $url URL to ping.
- * @param int $deprecated Not Used.
- * @return false|string False on failure, string containing URI on success.
- */
-function discover_pingback_server_uri( $url, $deprecated = '' ) {
-       if ( !empty( $deprecated ) )
-               _deprecated_argument( __FUNCTION__, '2.7' );
-
-       $pingback_str_dquote = 'rel="pingback"';
-       $pingback_str_squote = 'rel=\'pingback\'';
-
-       /** @todo Should use Filter Extension or custom preg_match instead. */
-       $parsed_url = parse_url($url);
-
-       if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
-               return false;
-
-       //Do not search for a pingback server on our own uploads
-       $uploads_dir = wp_upload_dir();
-       if ( 0 === strpos($url, $uploads_dir['baseurl']) )
-               return false;
-
-       $response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
-
-       if ( is_wp_error( $response ) )
-               return false;
-
-       if ( wp_remote_retrieve_header( $response, 'x-pingback' ) )
-               return wp_remote_retrieve_header( $response, 'x-pingback' );
-
-       // Not an (x)html, sgml, or xml page, no use going further.
-       if ( preg_match('#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' )) )
-               return false;
-
-       // Now do a GET since we're going to look in the html headers (and we're sure it's not a binary file)
-       $response = wp_safe_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
-
-       if ( is_wp_error( $response ) )
-               return false;
-
-       $contents = wp_remote_retrieve_body( $response );
-
-       $pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
-       $pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
-       if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
-               $quote = ($pingback_link_offset_dquote) ? '"' : '\'';
-               $pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
-               $pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
-               $pingback_href_start = $pingback_href_pos+6;
-               $pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
-               $pingback_server_url_len = $pingback_href_end - $pingback_href_start;
-               $pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
-
-               // We may find rel="pingback" but an incomplete pingback URL
-               if ( $pingback_server_url_len > 0 ) { // We got it!
-                       return $pingback_server_url;
-               }
-       }
-
-       return false;
-}
-
-/**
- * Perform all pingbacks, enclosures, trackbacks, and send to pingback services.
- *
- * @since 2.1.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- */
-function do_all_pings() {
-       global $wpdb;
-
-       // Do pingbacks
-       while ($ping = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1")) {
-               delete_metadata_by_mid( 'post', $ping->meta_id );
-               pingback( $ping->post_content, $ping->ID );
-       }
-
-       // Do Enclosures
-       while ($enclosure = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1")) {
-               delete_metadata_by_mid( 'post', $enclosure->meta_id );
-               do_enclose( $enclosure->post_content, $enclosure->ID );
-       }
-
-       // Do Trackbacks
-       $trackbacks = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'");
-       if ( is_array($trackbacks) )
-               foreach ( $trackbacks as $trackback )
-                       do_trackbacks($trackback);
-
-       //Do Update Services/Generic Pings
-       generic_ping();
-}
-
-/**
- * Perform trackbacks.
- *
- * @since 1.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int $post_id Post ID to do trackbacks on.
- */
-function do_trackbacks($post_id) {
-       global $wpdb;
-
-       $post = get_post( $post_id );
-       $to_ping = get_to_ping($post_id);
-       $pinged  = get_pung($post_id);
-       if ( empty($to_ping) ) {
-               $wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
-               return;
-       }
-
-       if ( empty($post->post_excerpt) ) {
-               /** This filter is documented in wp-includes/post-template.php */
-               $excerpt = apply_filters( 'the_content', $post->post_content, $post->ID );
-       } else {
-               /** This filter is documented in wp-includes/post-template.php */
-               $excerpt = apply_filters( 'the_excerpt', $post->post_excerpt );
-       }
-
-       $excerpt = str_replace(']]>', ']]&gt;', $excerpt);
-       $excerpt = wp_html_excerpt($excerpt, 252, '&#8230;');
-
-       /** This filter is documented in wp-includes/post-template.php */
-       $post_title = apply_filters( 'the_title', $post->post_title, $post->ID );
-       $post_title = strip_tags($post_title);
-
-       if ( $to_ping ) {
-               foreach ( (array) $to_ping as $tb_ping ) {
-                       $tb_ping = trim($tb_ping);
-                       if ( !in_array($tb_ping, $pinged) ) {
-                               trackback($tb_ping, $post_title, $excerpt, $post_id);
-                               $pinged[] = $tb_ping;
-                       } else {
-                               $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
-                       }
-               }
-       }
-}
-
-/**
- * Sends pings to all of the ping site services.
- *
- * @since 1.2.0
- *
- * @param int $post_id Post ID.
- * @return int Same as Post ID from parameter
- */
-function generic_ping( $post_id = 0 ) {
-       $services = get_option('ping_sites');
-
-       $services = explode("\n", $services);
-       foreach ( (array) $services as $service ) {
-               $service = trim($service);
-               if ( '' != $service )
-                       weblog_ping($service);
-       }
-
-       return $post_id;
-}
-
-/**
- * Pings back the links found in a post.
- *
- * @since 0.71
- *
- * @global string $wp_version
- *
- * @param string $content Post content to check for links.
- * @param int $post_ID Post ID.
- */
-function pingback($content, $post_ID) {
-       global $wp_version;
-       include_once(ABSPATH . WPINC . '/class-IXR.php');
-       include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
-
-       // original code by Mort (http://mort.mine.nu:8080)
-       $post_links = array();
-
-       $pung = get_pung($post_ID);
-
-       // Step 1
-       // Parsing the post, external links (if any) are stored in the $post_links array
-       $post_links_temp = wp_extract_urls( $content );
-
-       // Step 2.
-       // Walking thru the links array
-       // first we get rid of links pointing to sites, not to specific files
-       // Example:
-       // http://dummy-weblog.org
-       // http://dummy-weblog.org/
-       // http://dummy-weblog.org/post.php
-       // We don't wanna ping first and second types, even if they have a valid <link/>
-
-       foreach ( (array) $post_links_temp as $link_test ) :
-               if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
-                               && !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
-                       if ( $test = @parse_url($link_test) ) {
-                               if ( isset($test['query']) )
-                                       $post_links[] = $link_test;
-                               elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
-                                       $post_links[] = $link_test;
-                       }
-               endif;
-       endforeach;
-
-       $post_links = array_unique( $post_links );
-       /**
-        * Fires just before pinging back links found in a post.
-        *
-        * @since 2.0.0
-        *
-        * @param array &$post_links An array of post links to be checked, passed by reference.
-        * @param array &$pung       Whether a link has already been pinged, passed by reference.
-        * @param int   $post_ID     The post ID.
-        */
-       do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post_ID ) );
-
-       foreach ( (array) $post_links as $pagelinkedto ) {
-               $pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
-
-               if ( $pingback_server_url ) {
-                       @ set_time_limit( 60 );
-                       // Now, the RPC call
-                       $pagelinkedfrom = get_permalink($post_ID);
-
-                       // using a timeout of 3 seconds should be enough to cover slow servers
-                       $client = new WP_HTTP_IXR_Client($pingback_server_url);
-                       $client->timeout = 3;
-                       /**
-                        * Filter the user agent sent when pinging-back a URL.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param string $concat_useragent    The user agent concatenated with ' -- WordPress/'
-                        *                                    and the WordPress version.
-                        * @param string $useragent           The useragent.
-                        * @param string $pingback_server_url The server URL being linked to.
-                        * @param string $pagelinkedto        URL of page linked to.
-                        * @param string $pagelinkedfrom      URL of page linked from.
-                        */
-                       $client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
-                       // when set to true, this outputs debug messages by itself
-                       $client->debug = false;
-
-                       if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
-                               add_ping( $post_ID, $pagelinkedto );
-               }
-       }
-}
-
-/**
- * Check whether blog is public before returning sites.
- *
- * @since 2.1.0
- *
- * @param mixed $sites Will return if blog is public, will not return if not public.
- * @return mixed Empty string if blog is not public, returns $sites, if site is public.
- */
-function privacy_ping_filter($sites) {
-       if ( '0' != get_option('blog_public') )
-               return $sites;
-       else
-               return '';
-}
-
-/**
- * Send a Trackback.
- *
- * Updates database when sending trackback to prevent duplicates.
- *
- * @since 0.71
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $trackback_url URL to send trackbacks.
- * @param string $title Title of post.
- * @param string $excerpt Excerpt of post.
- * @param int $ID Post ID.
- * @return int|false|void Database query from update.
- */
-function trackback($trackback_url, $title, $excerpt, $ID) {
-       global $wpdb;
-
-       if ( empty($trackback_url) )
-               return;
-
-       $options = array();
-       $options['timeout'] = 10;
-       $options['body'] = array(
-               'title' => $title,
-               'url' => get_permalink($ID),
-               'blog_name' => get_option('blogname'),
-               'excerpt' => $excerpt
-       );
-
-       $response = wp_safe_remote_post( $trackback_url, $options );
-
-       if ( is_wp_error( $response ) )
-               return;
-
-       $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $ID) );
-       return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $ID) );
-}
-
-/**
- * Send a pingback.
- *
- * @since 1.2.0
- *
- * @global string $wp_version
- *
- * @param string $server Host of blog to connect to.
- * @param string $path Path to send the ping.
- */
-function weblog_ping($server = '', $path = '') {
-       global $wp_version;
-       include_once(ABSPATH . WPINC . '/class-IXR.php');
-       include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
-
-       // using a timeout of 3 seconds should be enough to cover slow servers
-       $client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
-       $client->timeout = 3;
-       $client->useragent .= ' -- WordPress/'.$wp_version;
-
-       // when set to true, this outputs debug messages by itself
-       $client->debug = false;
-       $home = trailingslashit( home_url() );
-       if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
-               $client->query('weblogUpdates.ping', get_option('blogname'), $home);
-}
-
-/**
- * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
- *
- * @since 3.5.1
- * @see wp_http_validate_url()
- *
- * @param string $source_uri
- * @return string
- */
-function pingback_ping_source_uri( $source_uri ) {
-       return (string) wp_http_validate_url( $source_uri );
-}
-
-/**
- * Default filter attached to xmlrpc_pingback_error.
- *
- * Returns a generic pingback error code unless the error code is 48,
- * which reports that the pingback is already registered.
- *
- * @since 3.5.1
- * @link http://www.hixie.ch/specs/pingback/pingback#TOC3
- *
- * @param IXR_Error $ixr_error
- * @return IXR_Error
- */
-function xmlrpc_pingback_error( $ixr_error ) {
-       if ( $ixr_error->code === 48 )
-               return $ixr_error;
-       return new IXR_Error( 0, '' );
-}
-
-//
-// Cache
-//
-
-/**
- * Removes comment ID from the comment cache.
- *
- * @since 2.3.0
- *
- * @param int|array $ids Comment ID or array of comment IDs to remove from cache
- */
-function clean_comment_cache($ids) {
-       foreach ( (array) $ids as $id ) {
-               wp_cache_delete( $id, 'comment' );
-       }
-
-       wp_cache_set( 'last_changed', microtime(), 'comment' );
-}
-
-/**
- * Updates the comment cache of given comments.
- *
- * Will add the comments in $comments to the cache. If comment ID already exists
- * in the comment cache then it will not be updated. The comment is added to the
- * cache using the comment group with the key using the ID of the comments.
- *
- * @since 2.3.0
- * @since 4.4.0 Introduced the `$update_meta_cache` parameter.
- *
- * @param array $comments          Array of comment row objects
- * @param bool  $update_meta_cache Whether to update commentmeta cache. Default true.
- */
-function update_comment_cache( $comments, $update_meta_cache = true ) {
-       foreach ( (array) $comments as $comment )
-               wp_cache_add($comment->comment_ID, $comment, 'comment');
-
-       if ( $update_meta_cache ) {
-               // Avoid `wp_list_pluck()` in case `$comments` is passed by reference.
-               $comment_ids = array();
-               foreach ( $comments as $comment ) {
-                       $comment_ids[] = $comment->comment_ID;
-               }
-               update_meta_cache( 'comment', $comment_ids );
-       }
-}
-
-/**
- * Adds any comments from the given IDs to the cache that do not already exist in cache.
- *
- * @since 4.4.0
- * @access private
- *
- * @see update_comment_cache()
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $comment_ids       Array of comment IDs.
- * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
- */
-function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
-       global $wpdb;
-
-       $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
-       if ( !empty( $non_cached_ids ) ) {
-               $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
-
-               update_comment_cache( $fresh_comments, $update_meta_cache );
-       }
-}
-
-//
-// Internal
-//
-
-/**
- * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
- *
- * @access private
- * @since 2.7.0
- *
- * @param WP_Post  $posts Post data object.
- * @param WP_Query $query Query object.
- * @return array
- */
-function _close_comments_for_old_posts( $posts, $query ) {
-       if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
-               return $posts;
-
-       /**
-        * Filter the list of post types to automatically close comments for.
-        *
-        * @since 3.2.0
-        *
-        * @param array $post_types An array of registered post types. Default array with 'post'.
-        */
-       $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
-       if ( ! in_array( $posts[0]->post_type, $post_types ) )
-               return $posts;
-
-       $days_old = (int) get_option( 'close_comments_days_old' );
-       if ( ! $days_old )
-               return $posts;
-
-       if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) {
-               $posts[0]->comment_status = 'closed';
-               $posts[0]->ping_status = 'closed';
-       }
-
-       return $posts;
-}
-
-/**
- * Close comments on an old post. Hooked to comments_open and pings_open.
- *
- * @access private
- * @since 2.7.0
- *
- * @param bool $open Comments open or closed
- * @param int $post_id Post ID
- * @return bool $open
- */
-function _close_comments_for_old_post( $open, $post_id ) {
-       if ( ! $open )
-               return $open;
-
-       if ( !get_option('close_comments_for_old_posts') )
-               return $open;
-
-       $days_old = (int) get_option('close_comments_days_old');
-       if ( !$days_old )
-               return $open;
-
-       $post = get_post($post_id);
-
-       /** This filter is documented in wp-includes/comment-functions.php */
-       $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
-       if ( ! in_array( $post->post_type, $post_types ) )
-               return $open;
-
-       // Undated drafts should not show up as comments closed.
-       if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
-               return $open;
-       }
-
-       if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
-               return false;
-
-       return $open;
-}
-
-/**
- * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
- *
- * This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which
- * expect slashed data.
- *
- * @since 4.4.0
- *
- * @param array $comment_data {
- *     Comment data.
- *
- *     @type string|int $comment_post_ID             The ID of the post that relates to the comment.
- *     @type string     $author                      The name of the comment author.
- *     @type string     $email                       The comment author email address.
- *     @type string     $url                         The comment author URL.
- *     @type string     $comment                     The content of the comment.
- *     @type string|int $comment_parent              The ID of this comment's parent, if any. Default 0.
- *     @type string     $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML.
- * }
- * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
- */
-function wp_handle_comment_submission( $comment_data ) {
-
-       $comment_post_ID = $comment_parent = 0;
-       $comment_author = $comment_author_email = $comment_author_url = $comment_content = $_wp_unfiltered_html_comment = null;
-
-       if ( isset( $comment_data['comment_post_ID'] ) ) {
-               $comment_post_ID = (int) $comment_data['comment_post_ID'];
-       }
-       if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
-               $comment_author = trim( strip_tags( $comment_data['author'] ) );
-       }
-       if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) {
-               $comment_author_email = trim( $comment_data['email'] );
-       }
-       if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) {
-               $comment_author_url = trim( $comment_data['url'] );
-       }
-       if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) {
-               $comment_content = trim( $comment_data['comment'] );
-       }
-       if ( isset( $comment_data['comment_parent'] ) ) {
-               $comment_parent = absint( $comment_data['comment_parent'] );
-       }
-       if ( isset( $comment_data['_wp_unfiltered_html_comment'] ) && is_string( $comment_data['_wp_unfiltered_html_comment'] ) ) {
-               $_wp_unfiltered_html_comment = trim( $comment_data['_wp_unfiltered_html_comment'] );
-       }
-
-       $post = get_post( $comment_post_ID );
-
-       if ( empty( $post->comment_status ) ) {
-
-               /**
-                * Fires when a comment is attempted on a post that does not exist.
-                *
-                * @since 1.5.0
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'comment_id_not_found', $comment_post_ID );
-
-               return new WP_Error( 'comment_id_not_found' );
-
-       }
-
-       // get_post_status() will get the parent status for attachments.
-       $status = get_post_status( $post );
-
-       $status_obj = get_post_status_object( $status );
-
-       if ( ! comments_open( $comment_post_ID ) ) {
-
-               /**
-                * Fires when a comment is attempted on a post that has comments closed.
-                *
-                * @since 1.5.0
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'comment_closed', $comment_post_ID );
-
-               return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
-
-       } elseif ( 'trash' == $status ) {
-
-               /**
-                * Fires when a comment is attempted on a trashed post.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'comment_on_trash', $comment_post_ID );
-
-               return new WP_Error( 'comment_on_trash' );
-
-       } elseif ( ! $status_obj->public && ! $status_obj->private ) {
-
-               /**
-                * Fires when a comment is attempted on a post in draft mode.
-                *
-                * @since 1.5.1
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'comment_on_draft', $comment_post_ID );
-
-               return new WP_Error( 'comment_on_draft' );
-
-       } elseif ( post_password_required( $comment_post_ID ) ) {
-
-               /**
-                * Fires when a comment is attempted on a password-protected post.
-                *
-                * @since 2.9.0
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'comment_on_password_protected', $comment_post_ID );
-
-               return new WP_Error( 'comment_on_password_protected' );
-
-       } else {
-
-               /**
-                * Fires before a comment is posted.
-                *
-                * @since 2.8.0
-                *
-                * @param int $comment_post_ID Post ID.
-                */
-               do_action( 'pre_comment_on_post', $comment_post_ID );
-
-       }
-
-       // If the user is logged in
-       $user = wp_get_current_user();
-       if ( $user->exists() ) {
-               if ( empty( $user->display_name ) ) {
-                       $user->display_name=$user->user_login;
-               }
-               $comment_author       = $user->display_name;
-               $comment_author_email = $user->user_email;
-               $comment_author_url   = $user->user_url;
-               $user_id              = $user->ID;
-               if ( current_user_can( 'unfiltered_html' ) ) {
-                       if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
-                               || ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
-                       ) {
-                               kses_remove_filters(); // start with a clean slate
-                               kses_init_filters(); // set up the filters
-                       }
-               }
-       } else {
-               if ( get_option( 'comment_registration' ) || 'private' == $status ) {
-                       return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to post a comment.' ), 403 );
-               }
-       }
-
-       $comment_type = '';
-
-       if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
-               if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
-                       return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
-               } elseif ( ! is_email( $comment_author_email ) ) {
-                       return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
-               }
-       }
-
-       if ( '' == $comment_content ) {
-               return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
-       }
-
-       $commentdata = compact(
-               'comment_post_ID',
-               'comment_author',
-               'comment_author_email',
-               'comment_author_url',
-               'comment_content',
-               'comment_type',
-               'comment_parent',
-               'user_id'
-       );
-
-       $comment_id = wp_new_comment( wp_slash( $commentdata ) );
-       if ( ! $comment_id ) {
-               return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
-       }
-
-       return get_comment( $comment_id );
-
-}
</del></span></pre></div>
<a id="trunksrcwpincludescommentphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/comment.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/comment.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/comment.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,20 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core Comment API
- *
- * @package WordPress
- * @subpackage Comment
- * @since 1.5.0
- */
-
-/** WP_Comment class */
-require_once( ABSPATH . WPINC . '/class-wp-comment.php' );
-
-/** WP_Comment_Query class */
-require_once( ABSPATH . WPINC . '/class-wp-comment-query.php' );
-
-/** Walker_Comment class */
-require_once( ABSPATH . WPINC . '/class-walker-comment.php' );
-
-/** Core comments functionality */
-require_once( ABSPATH . WPINC . '/comment-functions.php' );
</del></span></pre></div>
<a id="trunksrcwpincludescommentphpfromrev35712trunksrcwpincludescommentfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/comment.php (from rev 35712, trunk/src/wp-includes/comment-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/comment.php                         (rev 0)
+++ trunk/src/wp-includes/comment.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,2796 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core Comment API
+ *
+ * @package WordPress
+ * @subpackage Comment
+ */
+
+/**
+ * Check whether a comment passes internal checks to be allowed to add.
+ *
+ * If manual comment moderation is set in the administration, then all checks,
+ * regardless of their type and whitelist, will fail and the function will
+ * return false.
+ *
+ * If the number of links exceeds the amount in the administration, then the
+ * check fails. If any of the parameter contents match the blacklist of words,
+ * then the check fails.
+ *
+ * If the comment author was approved before, then the comment is automatically
+ * whitelisted.
+ *
+ * If all checks pass, the function will return true.
+ *
+ * @since 1.2.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $author       Comment author name.
+ * @param string $email        Comment author email.
+ * @param string $url          Comment author URL.
+ * @param string $comment      Content of the comment.
+ * @param string $user_ip      Comment author IP address.
+ * @param string $user_agent   Comment author User-Agent.
+ * @param string $comment_type Comment type, either user-submitted comment,
+ *                                    trackback, or pingback.
+ * @return bool If all checks pass, true, otherwise false.
+ */
+function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
+       global $wpdb;
+
+       // If manual moderation is enabled, skip all checks and return false.
+       if ( 1 == get_option('comment_moderation') )
+               return false;
+
+       /** This filter is documented in wp-includes/comment-template.php */
+       $comment = apply_filters( 'comment_text', $comment );
+
+       // Check for the number of external links if a max allowed number is set.
+       if ( $max_links = get_option( 'comment_max_links' ) ) {
+               $num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
+
+               /**
+                * Filter the maximum number of links allowed in a comment.
+                *
+                * @since 3.0.0
+                *
+                * @param int    $num_links The number of links allowed.
+                * @param string $url       Comment author's URL. Included in allowed links total.
+                */
+               $num_links = apply_filters( 'comment_max_links_url', $num_links, $url );
+
+               /*
+                * If the number of links in the comment exceeds the allowed amount,
+                * fail the check by returning false.
+                */
+               if ( $num_links >= $max_links )
+                       return false;
+       }
+
+       $mod_keys = trim(get_option('moderation_keys'));
+
+       // If moderation 'keys' (keywords) are set, process them.
+       if ( !empty($mod_keys) ) {
+               $words = explode("\n", $mod_keys );
+
+               foreach ( (array) $words as $word) {
+                       $word = trim($word);
+
+                       // Skip empty lines.
+                       if ( empty($word) )
+                               continue;
+
+                       /*
+                        * Do some escaping magic so that '#' (number of) characters in the spam
+                        * words don't break things:
+                        */
+                       $word = preg_quote($word, '#');
+
+                       /*
+                        * Check the comment fields for moderation keywords. If any are found,
+                        * fail the check for the given field by returning false.
+                        */
+                       $pattern = "#$word#i";
+                       if ( preg_match($pattern, $author) ) return false;
+                       if ( preg_match($pattern, $email) ) return false;
+                       if ( preg_match($pattern, $url) ) return false;
+                       if ( preg_match($pattern, $comment) ) return false;
+                       if ( preg_match($pattern, $user_ip) ) return false;
+                       if ( preg_match($pattern, $user_agent) ) return false;
+               }
+       }
+
+       /*
+        * Check if the option to approve comments by previously-approved authors is enabled.
+        *
+        * If it is enabled, check whether the comment author has a previously-approved comment,
+        * as well as whether there are any moderation keywords (if set) present in the author
+        * email address. If both checks pass, return true. Otherwise, return false.
+        */
+       if ( 1 == get_option('comment_whitelist')) {
+               if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
+                       // expected_slashed ($author, $email)
+                       $ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
+                       if ( ( 1 == $ok_to_comment ) &&
+                               ( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
+                                       return true;
+                       else
+                               return false;
+               } else {
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
+ * Retrieve the approved comments for post $post_id.
+ *
+ * @since 2.0.0
+ * @since 4.1.0 Refactored to leverage {@see WP_Comment_Query} over a direct query.
+ *
+ * @param  int   $post_id The ID of the post.
+ * @param  array $args    Optional. See {@see WP_Comment_Query::query()} for information
+ *                        on accepted arguments.
+ * @return int|array $comments The approved comments, or number of comments if `$count`
+ *                             argument is true.
+ */
+function get_approved_comments( $post_id, $args = array() ) {
+       if ( ! $post_id ) {
+               return array();
+       }
+
+       $defaults = array(
+               'status'  => 1,
+               'post_id' => $post_id,
+               'order'   => 'ASC',
+       );
+       $r = wp_parse_args( $args, $defaults );
+
+       $query = new WP_Comment_Query;
+       return $query->query( $r );
+}
+
+/**
+ * Retrieves comment data given a comment ID or comment object.
+ *
+ * If an object is passed then the comment data will be cached and then returned
+ * after being passed through a filter. If the comment is empty, then the global
+ * comment variable will be used, if it is set.
+ *
+ * @since 2.0.0
+ *
+ * @global WP_Comment $comment
+ *
+ * @param WP_Comment|string|int $comment Comment to retrieve.
+ * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
+ * @return WP_Comment|array|null Depends on $output value.
+ */
+function get_comment( &$comment = null, $output = OBJECT ) {
+       if ( empty( $comment ) && isset( $GLOBALS['comment'] ) ) {
+               $comment = $GLOBALS['comment'];
+       }
+
+       if ( $comment instanceof WP_Comment ) {
+               $_comment = $comment;
+       } elseif ( is_object( $comment ) ) {
+               $_comment = new WP_Comment( $comment );
+       } else {
+               $_comment = WP_Comment::get_instance( $comment );
+       }
+
+       if ( ! $_comment ) {
+               return null;
+       }
+
+       /**
+        * Fires after a comment is retrieved.
+        *
+        * @since 2.3.0
+        *
+        * @param mixed $_comment Comment data.
+        */
+       $_comment = apply_filters( 'get_comment', $_comment );
+
+       if ( $output == OBJECT ) {
+               return $_comment;
+       } elseif ( $output == ARRAY_A ) {
+               return $_comment->to_array();
+       } elseif ( $output == ARRAY_N ) {
+               return array_values( $_comment->to_array() );
+       }
+       return $_comment;
+}
+
+/**
+ * Retrieve a list of comments.
+ *
+ * The comment list can be for the blog as a whole or for an individual post.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $args Optional. Array or string of arguments. See {@see WP_Comment_Query::parse_query()}
+ *                           for information on accepted arguments. Default empty.
+ * @return int|array List of comments or number of found comments if `$count` argument is true.
+ */
+function get_comments( $args = '' ) {
+       $query = new WP_Comment_Query;
+       return $query->query( $args );
+}
+
+/**
+ * Retrieve all of the WordPress supported comment statuses.
+ *
+ * Comments have a limited set of valid status values, this provides the comment
+ * status values and descriptions.
+ *
+ * @since 2.7.0
+ *
+ * @return array List of comment statuses.
+ */
+function get_comment_statuses() {
+       $status = array(
+               'hold'          => __('Unapproved'),
+               /* translators: comment status  */
+               'approve'       => _x('Approved', 'adjective'),
+               /* translators: comment status */
+               'spam'          => _x('Spam', 'adjective'),
+               /* translators: comment status */
+               'trash'         => _x('Trash', 'adjective'),
+       );
+
+       return $status;
+}
+
+/**
+ * Gets the default comment status for a post type.
+ *
+ * @since 4.3.0
+ *
+ * @param string $post_type    Optional. Post type. Default 'post'.
+ * @param string $comment_type Optional. Comment type. Default 'comment'.
+ * @return string Expected return value is 'open' or 'closed'.
+ */
+function get_default_comment_status( $post_type = 'post', $comment_type = 'comment' ) {
+       switch ( $comment_type ) {
+               case 'pingback' :
+               case 'trackback' :
+                       $supports = 'trackbacks';
+                       $option = 'ping';
+                       break;
+               default :
+                       $supports = 'comments';
+                       $option = 'comment';
+       }
+
+       // Set the status.
+       if ( 'page' === $post_type ) {
+               $status = 'closed';
+       } elseif ( post_type_supports( $post_type, $supports ) ) {
+               $status = get_option( "default_{$option}_status" );
+       } else {
+               $status = 'closed';
+       }
+
+       /**
+        * Filter the default comment status for the given post type.
+        *
+        * @since 4.3.0
+        *
+        * @param string $status       Default status for the given post type,
+        *                             either 'open' or 'closed'.
+        * @param string $post_type    Post type. Default is `post`.
+        * @param string $comment_type Type of comment. Default is `comment`.
+        */
+       return apply_filters( 'get_default_comment_status' , $status, $post_type, $comment_type );
+}
+
+/**
+ * The date the last comment was modified.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @staticvar array $cache_lastcommentmodified
+ *
+ * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
+ *             or 'server' locations.
+ * @return string Last comment modified date.
+ */
+function get_lastcommentmodified($timezone = 'server') {
+       global $wpdb;
+       static $cache_lastcommentmodified = array();
+
+       if ( isset($cache_lastcommentmodified[$timezone]) )
+               return $cache_lastcommentmodified[$timezone];
+
+       $add_seconds_server = date('Z');
+
+       switch ( strtolower($timezone)) {
+               case 'gmt':
+                       $lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
+                       break;
+               case 'blog':
+                       $lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
+                       break;
+               case 'server':
+                       $lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
+                       break;
+       }
+
+       $cache_lastcommentmodified[$timezone] = $lastcommentmodified;
+
+       return $lastcommentmodified;
+}
+
+/**
+ * The amount of comments in a post or total comments.
+ *
+ * A lot like {@link wp_count_comments()}, in that they both return comment
+ * stats (albeit with different types). The {@link wp_count_comments()} actual
+ * caches, but this function does not.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
+ * @return array The amount of spam, approved, awaiting moderation, and total comments.
+ */
+function get_comment_count( $post_id = 0 ) {
+       global $wpdb;
+
+       $post_id = (int) $post_id;
+
+       $where = '';
+       if ( $post_id > 0 ) {
+               $where = $wpdb->prepare("WHERE comment_post_ID = %d", $post_id);
+       }
+
+       $totals = (array) $wpdb->get_results("
+               SELECT comment_approved, COUNT( * ) AS total
+               FROM {$wpdb->comments}
+               {$where}
+               GROUP BY comment_approved
+       ", ARRAY_A);
+
+       $comment_count = array(
+               'approved'            => 0,
+               'awaiting_moderation' => 0,
+               'spam'                => 0,
+               'trash'               => 0,
+               'post-trashed'        => 0,
+               'total_comments'      => 0,
+               'all'                 => 0,
+       );
+
+       foreach ( $totals as $row ) {
+               switch ( $row['comment_approved'] ) {
+                       case 'trash':
+                               $comment_count['trash'] = $row['total'];
+                               break;
+                       case 'post-trashed':
+                               $comment_count['post-trashed'] = $row['total'];
+                               break;
+                       case 'spam':
+                               $comment_count['spam'] = $row['total'];
+                               $comment_count['total_comments'] += $row['total'];
+                               break;
+                       case '1':
+                               $comment_count['approved'] = $row['total'];
+                               $comment_count['total_comments'] += $row['total'];
+                               $comment_count['all'] += $row['total'];
+                               break;
+                       case '0':
+                               $comment_count['awaiting_moderation'] = $row['total'];
+                               $comment_count['total_comments'] += $row['total'];
+                               $comment_count['all'] += $row['total'];
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       return $comment_count;
+}
+
+//
+// Comment meta functions
+//
+
+/**
+ * Add meta data field to a comment.
+ *
+ * @since 2.9.0
+ * @link https://codex.wordpress.org/Function_Reference/add_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return int|bool Meta ID on success, false on failure.
+ */
+function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
+       return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a comment.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 2.9.0
+ * @link https://codex.wordpress.org/Function_Reference/delete_comment_meta
+ *
+ * @param int $comment_id comment ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool True on success, false on failure.
+ */
+function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
+       return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve comment meta field for a comment.
+ *
+ * @since 2.9.0
+ * @link https://codex.wordpress.org/Function_Reference/get_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ *  is true.
+ */
+function get_comment_meta($comment_id, $key = '', $single = false) {
+       return get_metadata('comment', $comment_id, $key, $single);
+}
+
+/**
+ * Update comment meta field based on comment ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and comment ID.
+ *
+ * If the meta field for the comment does not exist, it will be added.
+ *
+ * @since 2.9.0
+ * @link https://codex.wordpress.org/Function_Reference/update_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
+ */
+function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
+       return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
+ * to recall previous comments by this commentator that are still held in moderation.
+ *
+ * @param WP_Comment $comment Comment object.
+ * @param object     $user    Comment author's object.
+ *
+ * @since 3.4.0
+ */
+function wp_set_comment_cookies($comment, $user) {
+       if ( $user->exists() )
+               return;
+
+       /**
+        * Filter the lifetime of the comment cookie in seconds.
+        *
+        * @since 2.8.0
+        *
+        * @param int $seconds Comment cookie lifetime. Default 30000000.
+        */
+       $comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
+       $secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
+       setcookie( 'comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
+       setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
+       setcookie( 'comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
+}
+
+/**
+ * Sanitizes the cookies sent to the user already.
+ *
+ * Will only do anything if the cookies have already been created for the user.
+ * Mostly used after cookies had been sent to use elsewhere.
+ *
+ * @since 2.0.4
+ */
+function sanitize_comment_cookies() {
+       if ( isset( $_COOKIE['comment_author_' . COOKIEHASH] ) ) {
+               /**
+                * Filter the comment author's name cookie before it is set.
+                *
+                * When this filter hook is evaluated in wp_filter_comment(),
+                * the comment author's name string is passed.
+                *
+                * @since 1.5.0
+                *
+                * @param string $author_cookie The comment author name cookie.
+                */
+               $comment_author = apply_filters( 'pre_comment_author_name', $_COOKIE['comment_author_' . COOKIEHASH] );
+               $comment_author = wp_unslash($comment_author);
+               $comment_author = esc_attr($comment_author);
+               $_COOKIE['comment_author_' . COOKIEHASH] = $comment_author;
+       }
+
+       if ( isset( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
+               /**
+                * Filter the comment author's email cookie before it is set.
+                *
+                * When this filter hook is evaluated in wp_filter_comment(),
+                * the comment author's email string is passed.
+                *
+                * @since 1.5.0
+                *
+                * @param string $author_email_cookie The comment author email cookie.
+                */
+               $comment_author_email = apply_filters( 'pre_comment_author_email', $_COOKIE['comment_author_email_' . COOKIEHASH] );
+               $comment_author_email = wp_unslash($comment_author_email);
+               $comment_author_email = esc_attr($comment_author_email);
+               $_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
+       }
+
+       if ( isset( $_COOKIE['comment_author_url_' . COOKIEHASH] ) ) {
+               /**
+                * Filter the comment author's URL cookie before it is set.
+                *
+                * When this filter hook is evaluated in wp_filter_comment(),
+                * the comment author's URL string is passed.
+                *
+                * @since 1.5.0
+                *
+                * @param string $author_url_cookie The comment author URL cookie.
+                */
+               $comment_author_url = apply_filters( 'pre_comment_author_url', $_COOKIE['comment_author_url_' . COOKIEHASH] );
+               $comment_author_url = wp_unslash($comment_author_url);
+               $_COOKIE['comment_author_url_'.COOKIEHASH] = $comment_author_url;
+       }
+}
+
+/**
+ * Validates whether this comment is allowed to be made.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $commentdata Contains information on the comment
+ * @return int|string Signifies the approval status (0|1|'spam')
+ */
+function wp_allow_comment( $commentdata ) {
+       global $wpdb;
+
+       // Simple duplicate check
+       // expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
+       $dupe = $wpdb->prepare(
+               "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ",
+               wp_unslash( $commentdata['comment_post_ID'] ),
+               wp_unslash( $commentdata['comment_parent'] ),
+               wp_unslash( $commentdata['comment_author'] )
+       );
+       if ( $commentdata['comment_author_email'] ) {
+               $dupe .= $wpdb->prepare(
+                       "OR comment_author_email = %s ",
+                       wp_unslash( $commentdata['comment_author_email'] )
+               );
+       }
+       $dupe .= $wpdb->prepare(
+               ") AND comment_content = %s LIMIT 1",
+               wp_unslash( $commentdata['comment_content'] )
+       );
+
+       $dupe_id = $wpdb->get_var( $dupe );
+
+       /**
+        * Filters the ID, if any, of the duplicate comment found when creating a new comment.
+        *
+        * Return an empty value from this filter to allow what WP considers a duplicate comment.
+        *
+        * @since 4.4.0
+        *
+        * @param int   $dupe_id     ID of the comment identified as a duplicate.
+        * @param array $commentdata Data for the comment being created.
+        */
+       $dupe_id = apply_filters( 'duplicate_comment_id', $dupe_id, $commentdata );
+
+       if ( $dupe_id ) {
+               /**
+                * Fires immediately after a duplicate comment is detected.
+                *
+                * @since 3.0.0
+                *
+                * @param array $commentdata Comment data.
+                */
+               do_action( 'comment_duplicate_trigger', $commentdata );
+               if ( defined( 'DOING_AJAX' ) ) {
+                       die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
+               }
+               wp_die( __( 'Duplicate comment detected; it looks as though you&#8217;ve already said that!' ), 409 );
+       }
+
+       /**
+        * Fires immediately before a comment is marked approved.
+        *
+        * Allows checking for comment flooding.
+        *
+        * @since 2.3.0
+        *
+        * @param string $comment_author_IP    Comment author's IP address.
+        * @param string $comment_author_email Comment author's email.
+        * @param string $comment_date_gmt     GMT date the comment was posted.
+        */
+       do_action(
+               'check_comment_flood',
+               $commentdata['comment_author_IP'],
+               $commentdata['comment_author_email'],
+               $commentdata['comment_date_gmt']
+       );
+
+       if ( ! empty( $commentdata['user_id'] ) ) {
+               $user = get_userdata( $commentdata['user_id'] );
+               $post_author = $wpdb->get_var( $wpdb->prepare(
+                       "SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1",
+                       $commentdata['comment_post_ID']
+               ) );
+       }
+
+       if ( isset( $user ) && ( $commentdata['user_id'] == $post_author || $user->has_cap( 'moderate_comments' ) ) ) {
+               // The author and the admins get respect.
+               $approved = 1;
+       } else {
+               // Everyone else's comments will be checked.
+               if ( check_comment(
+                       $commentdata['comment_author'],
+                       $commentdata['comment_author_email'],
+                       $commentdata['comment_author_url'],
+                       $commentdata['comment_content'],
+                       $commentdata['comment_author_IP'],
+                       $commentdata['comment_agent'],
+                       $commentdata['comment_type']
+               ) ) {
+                       $approved = 1;
+               } else {
+                       $approved = 0;
+               }
+
+               if ( wp_blacklist_check(
+                       $commentdata['comment_author'],
+                       $commentdata['comment_author_email'],
+                       $commentdata['comment_author_url'],
+                       $commentdata['comment_content'],
+                       $commentdata['comment_author_IP'],
+                       $commentdata['comment_agent']
+               ) ) {
+                       $approved = EMPTY_TRASH_DAYS ? 'trash' : 'spam';
+               }
+       }
+
+       /**
+        * Filter a comment's approval status before it is set.
+        *
+        * @since 2.1.0
+        *
+        * @param bool|string $approved    The approval status. Accepts 1, 0, or 'spam'.
+        * @param array       $commentdata Comment data.
+        */
+       $approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
+       return $approved;
+}
+
+/**
+ * Check whether comment flooding is occurring.
+ *
+ * Won't run, if current user can manage options, so to not block
+ * administrators.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $ip Comment IP.
+ * @param string $email Comment author email address.
+ * @param string $date MySQL time string.
+ */
+function check_comment_flood_db( $ip, $email, $date ) {
+       global $wpdb;
+       // don't throttle admins or moderators
+       if ( current_user_can( 'manage_options' ) || current_user_can( 'moderate_comments' ) ) {
+               return;
+       }
+       $hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
+
+       if ( is_user_logged_in() ) {
+               $user = get_current_user_id();
+               $check_column = '`user_id`';
+       } else {
+               $user = $ip;
+               $check_column = '`comment_author_IP`';
+       }
+
+       $sql = $wpdb->prepare(
+               "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( $check_column = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1",
+               $hour_ago,
+               $user,
+               $email
+       );
+       $lasttime = $wpdb->get_var( $sql );
+       if ( $lasttime ) {
+               $time_lastcomment = mysql2date('U', $lasttime, false);
+               $time_newcomment  = mysql2date('U', $date, false);
+               /**
+                * Filter the comment flood status.
+                *
+                * @since 2.1.0
+                *
+                * @param bool $bool             Whether a comment flood is occurring. Default false.
+                * @param int  $time_lastcomment Timestamp of when the last comment was posted.
+                * @param int  $time_newcomment  Timestamp of when the new comment was posted.
+                */
+               $flood_die = apply_filters( 'comment_flood_filter', false, $time_lastcomment, $time_newcomment );
+               if ( $flood_die ) {
+                       /**
+                        * Fires before the comment flood message is triggered.
+                        *
+                        * @since 1.5.0
+                        *
+                        * @param int $time_lastcomment Timestamp of when the last comment was posted.
+                        * @param int $time_newcomment  Timestamp of when the new comment was posted.
+                        */
+                       do_action( 'comment_flood_trigger', $time_lastcomment, $time_newcomment );
+
+                       if ( defined('DOING_AJAX') )
+                               die( __('You are posting comments too quickly. Slow down.') );
+
+                       wp_die( __( 'You are posting comments too quickly. Slow down.' ), 429 );
+               }
+       }
+}
+
+/**
+ * Separates an array of comments into an array keyed by comment_type.
+ *
+ * @since 2.7.0
+ *
+ * @param array $comments Array of comments
+ * @return array Array of comments keyed by comment_type.
+ */
+function separate_comments(&$comments) {
+       $comments_by_type = array('comment' => array(), 'trackback' => array(), 'pingback' => array(), 'pings' => array());
+       $count = count($comments);
+       for ( $i = 0; $i < $count; $i++ ) {
+               $type = $comments[$i]->comment_type;
+               if ( empty($type) )
+                       $type = 'comment';
+               $comments_by_type[$type][] = &$comments[$i];
+               if ( 'trackback' == $type || 'pingback' == $type )
+                       $comments_by_type['pings'][] = &$comments[$i];
+       }
+
+       return $comments_by_type;
+}
+
+/**
+ * Calculate the total number of comment pages.
+ *
+ * @since 2.7.0
+ *
+ * @uses Walker_Comment
+ *
+ * @global WP_Query $wp_query
+ *
+ * @param array $comments Optional array of WP_Comment objects. Defaults to $wp_query->comments
+ * @param int   $per_page Optional comments per page.
+ * @param bool  $threaded Optional control over flat or threaded comments.
+ * @return int Number of comment pages.
+ */
+function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
+       global $wp_query;
+
+       if ( null === $comments && null === $per_page && null === $threaded && !empty($wp_query->max_num_comment_pages) )
+               return $wp_query->max_num_comment_pages;
+
+       if ( ( ! $comments || ! is_array( $comments ) ) && ! empty( $wp_query->comments )  )
+               $comments = $wp_query->comments;
+
+       if ( empty($comments) )
+               return 0;
+
+       if ( ! get_option( 'page_comments' ) ) {
+               return 1;
+       }
+
+       if ( !isset($per_page) )
+               $per_page = (int) get_query_var('comments_per_page');
+       if ( 0 === $per_page )
+               $per_page = (int) get_option('comments_per_page');
+       if ( 0 === $per_page )
+               return 1;
+
+       if ( !isset($threaded) )
+               $threaded = get_option('thread_comments');
+
+       if ( $threaded ) {
+               $walker = new Walker_Comment;
+               $count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
+       } else {
+               $count = ceil( count( $comments ) / $per_page );
+       }
+
+       return $count;
+}
+
+/**
+ * Calculate what page number a comment will appear on for comment paging.
+ *
+ * @since 2.7.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int   $comment_ID Comment ID.
+ * @param array $args {
+ *      Array of optional arguments.
+ *      @type string     $type      Limit paginated comments to those matching a given type. Accepts 'comment',
+ *                                  'trackback', 'pingback', 'pings' (trackbacks and pingbacks), or 'all'.
+ *                                  Default is 'all'.
+ *      @type int        $per_page  Per-page count to use when calculating pagination. Defaults to the value of the
+ *                                  'comments_per_page' option.
+ *      @type int|string $max_depth If greater than 1, comment page will be determined for the top-level parent of
+ *                                  `$comment_ID`. Defaults to the value of the 'thread_comments_depth' option.
+ * } *
+ * @return int|null Comment page number or null on error.
+ */
+function get_page_of_comment( $comment_ID, $args = array() ) {
+       global $wpdb;
+
+       $page = null;
+
+       if ( !$comment = get_comment( $comment_ID ) )
+               return;
+
+       $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
+       $args = wp_parse_args( $args, $defaults );
+       $original_args = $args;
+
+       // Order of precedence: 1. `$args['per_page']`, 2. 'comments_per_page' query_var, 3. 'comments_per_page' option.
+       if ( get_option( 'page_comments' ) ) {
+               if ( '' === $args['per_page'] ) {
+                       $args['per_page'] = get_query_var( 'comments_per_page' );
+               }
+
+               if ( '' === $args['per_page'] ) {
+                       $args['per_page'] = get_option( 'comments_per_page' );
+               }
+       }
+
+       if ( empty($args['per_page']) ) {
+               $args['per_page'] = 0;
+               $args['page'] = 0;
+       }
+
+       if ( $args['per_page'] < 1 ) {
+               $page = 1;
+       }
+
+       if ( null === $page ) {
+               if ( '' === $args['max_depth'] ) {
+                       if ( get_option('thread_comments') )
+                               $args['max_depth'] = get_option('thread_comments_depth');
+                       else
+                               $args['max_depth'] = -1;
+               }
+
+               // Find this comment's top level parent if threading is enabled
+               if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
+                       return get_page_of_comment( $comment->comment_parent, $args );
+
+               $comment_args = array(
+                       'type'       => $args['type'],
+                       'post_id'    => $comment->comment_post_ID,
+                       'fields'     => 'ids',
+                       'count'      => true,
+                       'status'     => 'approve',
+                       'parent'     => 0,
+                       'date_query' => array(
+                               array(
+                                       'column' => "$wpdb->comments.comment_date_gmt",
+                                       'before' => $comment->comment_date_gmt,
+                               )
+                       ),
+               );
+
+               $comment_query = new WP_Comment_Query();
+               $older_comment_count = $comment_query->query( $comment_args );
+
+               // No older comments? Then it's page #1.
+               if ( 0 == $older_comment_count ) {
+                       $page = 1;
+
+               // Divide comments older than this one by comments per page to get this comment's page number
+               } else {
+                       $page = ceil( ( $older_comment_count + 1 ) / $args['per_page'] );
+               }
+       }
+
+       /**
+        * Filters the calculated page on which a comment appears.
+        *
+        * @since 4.4.0
+        *
+        * @param int   $page          Comment page.
+        * @param array $args {
+        *     Arguments used to calculate pagination. These include arguments auto-detected by the function,
+        *     based on query vars, system settings, etc. For pristine arguments passed to the function,
+        *     see `$original_args`.
+        *
+        *     @type string $type      Type of comments to count.
+        *     @type int    $page      Calculated current page.
+        *     @type int    $per_page  Calculated number of comments per page.
+        *     @type int    $max_depth Maximum comment threading depth allowed.
+        * }
+        * @param array $original_args {
+        *     Array of arguments passed to the function. Some or all of these may not be set.
+        *
+        *     @type string $type      Type of comments to count.
+        *     @type int    $page      Current comment page.
+        *     @type int    $per_page  Number of comments per page.
+        *     @type int    $max_depth Maximum comment threading depth allowed.
+        * }
+        */
+       return apply_filters( 'get_page_of_comment', (int) $page, $args, $original_args );
+}
+
+/**
+ * Does comment contain blacklisted characters or words.
+ *
+ * @since 1.5.0
+ *
+ * @param string $author The author of the comment
+ * @param string $email The email of the comment
+ * @param string $url The url used in the comment
+ * @param string $comment The comment content
+ * @param string $user_ip The comment author IP address
+ * @param string $user_agent The author's browser user agent
+ * @return bool True if comment contains blacklisted content, false if comment does not
+ */
+function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
+       /**
+        * Fires before the comment is tested for blacklisted characters or words.
+        *
+        * @since 1.5.0
+        *
+        * @param string $author     Comment author.
+        * @param string $email      Comment author's email.
+        * @param string $url        Comment author's URL.
+        * @param string $comment    Comment content.
+        * @param string $user_ip    Comment author's IP address.
+        * @param string $user_agent Comment author's browser user agent.
+        */
+       do_action( 'wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent );
+
+       $mod_keys = trim( get_option('blacklist_keys') );
+       if ( '' == $mod_keys )
+               return false; // If moderation keys are empty
+       $words = explode("\n", $mod_keys );
+
+       foreach ( (array) $words as $word ) {
+               $word = trim($word);
+
+               // Skip empty lines
+               if ( empty($word) ) { continue; }
+
+               // Do some escaping magic so that '#' chars in the
+               // spam words don't break things:
+               $word = preg_quote($word, '#');
+
+               $pattern = "#$word#i";
+               if (
+                          preg_match($pattern, $author)
+                       || preg_match($pattern, $email)
+                       || preg_match($pattern, $url)
+                       || preg_match($pattern, $comment)
+                       || preg_match($pattern, $user_ip)
+                       || preg_match($pattern, $user_agent)
+                )
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * Retrieve total comments for blog or single post.
+ *
+ * The properties of the returned object contain the 'moderated', 'approved',
+ * and spam comments for either the entire blog or single post. Those properties
+ * contain the amount of comments that match the status. The 'total_comments'
+ * property contains the integer of total comments.
+ *
+ * The comment stats are cached and then retrieved, if they already exist in the
+ * cache.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return object|array Comment stats.
+ */
+function wp_count_comments( $post_id = 0 ) {
+       $post_id = (int) $post_id;
+
+       /**
+        * Filter the comments count for a given post.
+        *
+        * @since 2.7.0
+        *
+        * @param array $count   An empty array.
+        * @param int   $post_id The post ID.
+        */
+       $filtered = apply_filters( 'wp_count_comments', array(), $post_id );
+       if ( ! empty( $filtered ) ) {
+               return $filtered;
+       }
+
+       $count = wp_cache_get( "comments-{$post_id}", 'counts' );
+       if ( false !== $count ) {
+               return $count;
+       }
+
+       $stats = get_comment_count( $post_id );
+       $stats['moderated'] = $stats['awaiting_moderation'];
+       unset( $stats['awaiting_moderation'] );
+
+       $stats_object = (object) $stats;
+       wp_cache_set( "comments-{$post_id}", $stats_object, 'counts' );
+
+       return $stats_object;
+}
+
+/**
+ * Trashes or deletes a comment.
+ *
+ * The comment is moved to trash instead of permanently deleted unless trash is
+ * disabled, item is already in the trash, or $force_delete is true.
+ *
+ * The post comment count will be updated if the comment was approved and has a
+ * post ID available.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|WP_Comment $comment_id   Comment ID or WP_Comment object.
+ * @param bool           $force_delete Whether to bypass trash and force deletion. Default is false.
+ * @return bool True on success, false on failure.
+ */
+function wp_delete_comment($comment_id, $force_delete = false) {
+       global $wpdb;
+       if (!$comment = get_comment($comment_id))
+               return false;
+
+       if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ) ) )
+               return wp_trash_comment($comment_id);
+
+       /**
+        * Fires immediately before a comment is deleted from the database.
+        *
+        * @since 1.2.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'delete_comment', $comment->comment_ID );
+
+       // Move children up a level.
+       $children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID) );
+       if ( !empty($children) ) {
+               $wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment->comment_ID));
+               clean_comment_cache($children);
+       }
+
+       // Delete metadata
+       $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
+       foreach ( $meta_ids as $mid )
+               delete_metadata_by_mid( 'comment', $mid );
+
+       if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) )
+               return false;
+
+       /**
+        * Fires immediately after a comment is deleted from the database.
+        *
+        * @since 2.9.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'deleted_comment', $comment->comment_ID );
+
+       $post_id = $comment->comment_post_ID;
+       if ( $post_id && $comment->comment_approved == 1 )
+               wp_update_comment_count($post_id);
+
+       clean_comment_cache( $comment->comment_ID );
+
+       /** This action is documented in wp-includes/comment-functions.php */
+       do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
+
+       wp_transition_comment_status('delete', $comment->comment_approved, $comment);
+       return true;
+}
+
+/**
+ * Moves a comment to the Trash
+ *
+ * If trash is disabled, comment is permanently deleted.
+ *
+ * @since 2.9.0
+ *
+ * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
+ * @return bool True on success, false on failure.
+ */
+function wp_trash_comment($comment_id) {
+       if ( !EMPTY_TRASH_DAYS )
+               return wp_delete_comment($comment_id, true);
+
+       if ( !$comment = get_comment($comment_id) )
+               return false;
+
+       /**
+        * Fires immediately before a comment is sent to the Trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'trash_comment', $comment->comment_ID );
+
+       if ( wp_set_comment_status( $comment, 'trash' ) ) {
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
+               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
+               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
+
+               /**
+                * Fires immediately after a comment is sent to Trash.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_id The comment ID.
+                */
+               do_action( 'trashed_comment', $comment->comment_ID );
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Removes a comment from the Trash
+ *
+ * @since 2.9.0
+ *
+ * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
+ * @return bool True on success, false on failure.
+ */
+function wp_untrash_comment($comment_id) {
+       $comment = get_comment( $comment_id );
+       if ( ! $comment ) {
+               return false;
+       }
+
+       /**
+        * Fires immediately before a comment is restored from the Trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'untrash_comment', $comment->comment_ID );
+
+       $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
+       if ( empty($status) )
+               $status = '0';
+
+       if ( wp_set_comment_status( $comment, $status ) ) {
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
+               /**
+                * Fires immediately after a comment is restored from the Trash.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_id The comment ID.
+                */
+               do_action( 'untrashed_comment', $comment->comment_ID );
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Marks a comment as Spam
+ *
+ * @since 2.9.0
+ *
+ * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
+ * @return bool True on success, false on failure.
+ */
+function wp_spam_comment( $comment_id ) {
+       $comment = get_comment( $comment_id );
+       if ( ! $comment ) {
+               return false;
+       }
+
+       /**
+        * Fires immediately before a comment is marked as Spam.
+        *
+        * @since 2.9.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'spam_comment', $comment->comment_ID );
+
+       if ( wp_set_comment_status( $comment, 'spam' ) ) {
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
+               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
+               add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
+               /**
+                * Fires immediately after a comment is marked as Spam.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_id The comment ID.
+                */
+               do_action( 'spammed_comment', $comment->comment_ID );
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Removes a comment from the Spam
+ *
+ * @since 2.9.0
+ *
+ * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
+ * @return bool True on success, false on failure.
+ */
+function wp_unspam_comment( $comment_id ) {
+       $comment = get_comment( $comment_id );
+       if ( ! $comment ) {
+               return false;
+       }
+
+       /**
+        * Fires immediately before a comment is unmarked as Spam.
+        *
+        * @since 2.9.0
+        *
+        * @param int $comment_id The comment ID.
+        */
+       do_action( 'unspam_comment', $comment->comment_ID );
+
+       $status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
+       if ( empty($status) )
+               $status = '0';
+
+       if ( wp_set_comment_status( $comment, $status ) ) {
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
+               delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
+               /**
+                * Fires immediately after a comment is unmarked as Spam.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_id The comment ID.
+                */
+               do_action( 'unspammed_comment', $comment->comment_ID );
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * The status of a comment by ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int|WP_Comment $comment_id Comment ID or WP_Comment object
+ * @return false|string Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
+ */
+function wp_get_comment_status($comment_id) {
+       $comment = get_comment($comment_id);
+       if ( !$comment )
+               return false;
+
+       $approved = $comment->comment_approved;
+
+       if ( $approved == null )
+               return false;
+       elseif ( $approved == '1' )
+               return 'approved';
+       elseif ( $approved == '0' )
+               return 'unapproved';
+       elseif ( $approved == 'spam' )
+               return 'spam';
+       elseif ( $approved == 'trash' )
+               return 'trash';
+       else
+               return false;
+}
+
+/**
+ * Call hooks for when a comment status transition occurs.
+ *
+ * Calls hooks for comment status transitions. If the new comment status is not the same
+ * as the previous comment status, then two hooks will be ran, the first is
+ * 'transition_comment_status' with new status, old status, and comment data. The
+ * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
+ * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
+ * comment data.
+ *
+ * The final action will run whether or not the comment statuses are the same. The
+ * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
+ * parameter and COMMENTTYPE is comment_type comment data.
+ *
+ * @since 2.7.0
+ *
+ * @param string $new_status New comment status.
+ * @param string $old_status Previous comment status.
+ * @param object $comment Comment data.
+ */
+function wp_transition_comment_status($new_status, $old_status, $comment) {
+       /*
+        * Translate raw statuses to human readable formats for the hooks.
+        * This is not a complete list of comment status, it's only the ones
+        * that need to be renamed
+        */
+       $comment_statuses = array(
+               0         => 'unapproved',
+               'hold'    => 'unapproved', // wp_set_comment_status() uses "hold"
+               1         => 'approved',
+               'approve' => 'approved', // wp_set_comment_status() uses "approve"
+       );
+       if ( isset($comment_statuses[$new_status]) ) $new_status = $comment_statuses[$new_status];
+       if ( isset($comment_statuses[$old_status]) ) $old_status = $comment_statuses[$old_status];
+
+       // Call the hooks
+       if ( $new_status != $old_status ) {
+               /**
+                * Fires when the comment status is in transition.
+                *
+                * @since 2.7.0
+                *
+                * @param int|string $new_status The new comment status.
+                * @param int|string $old_status The old comment status.
+                * @param object     $comment    The comment data.
+                */
+               do_action( 'transition_comment_status', $new_status, $old_status, $comment );
+               /**
+                * Fires when the comment status is in transition from one specific status to another.
+                *
+                * The dynamic portions of the hook name, `$old_status`, and `$new_status`,
+                * refer to the old and new comment statuses, respectively.
+                *
+                * @since 2.7.0
+                *
+                * @param WP_Comment $comment Comment object.
+                */
+               do_action( "comment_{$old_status}_to_{$new_status}", $comment );
+       }
+       /**
+        * Fires when the status of a specific comment type is in transition.
+        *
+        * The dynamic portions of the hook name, `$new_status`, and `$comment->comment_type`,
+        * refer to the new comment status, and the type of comment, respectively.
+        *
+        * Typical comment types include an empty string (standard comment), 'pingback',
+        * or 'trackback'.
+        *
+        * @since 2.7.0
+        *
+        * @param int        $comment_ID The comment ID.
+        * @param WP_Comment $comment    Comment object.
+        */
+       do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
+}
+
+/**
+ * Get current commenter's name, email, and URL.
+ *
+ * Expects cookies content to already be sanitized. User of this function might
+ * wish to recheck the returned array for validity.
+ *
+ * @see sanitize_comment_cookies() Use to sanitize cookies
+ *
+ * @since 2.0.4
+ *
+ * @return array Comment author, email, url respectively.
+ */
+function wp_get_current_commenter() {
+       // Cookies should already be sanitized.
+
+       $comment_author = '';
+       if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) )
+               $comment_author = $_COOKIE['comment_author_'.COOKIEHASH];
+
+       $comment_author_email = '';
+       if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) )
+               $comment_author_email = $_COOKIE['comment_author_email_'.COOKIEHASH];
+
+       $comment_author_url = '';
+       if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
+               $comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
+
+       /**
+        * Filter the current commenter's name, email, and URL.
+        *
+        * @since 3.1.0
+        *
+        * @param array $comment_author_data {
+        *     An array of current commenter variables.
+        *
+        *     @type string $comment_author       The name of the author of the comment. Default empty.
+        *     @type string $comment_author_email The email address of the `$comment_author`. Default empty.
+        *     @type string $comment_author_url   The URL address of the `$comment_author`. Default empty.
+        * }
+        */
+       return apply_filters( 'wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url') );
+}
+
+/**
+ * Inserts a comment into the database.
+ *
+ * @since 2.0.0
+ * @since 4.4.0 Introduced `$comment_meta` argument.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $commentdata {
+ *     Array of arguments for inserting a new comment.
+ *
+ *     @type string     $comment_agent        The HTTP user agent of the `$comment_author` when
+ *                                            the comment was submitted. Default empty.
+ *     @type int|string $comment_approved     Whether the comment has been approved. Default 1.
+ *     @type string     $comment_author       The name of the author of the comment. Default empty.
+ *     @type string     $comment_author_email The email address of the `$comment_author`. Default empty.
+ *     @type string     $comment_author_IP    The IP address of the `$comment_author`. Default empty.
+ *     @type string     $comment_author_url   The URL address of the `$comment_author`. Default empty.
+ *     @type string     $comment_content      The content of the comment. Default empty.
+ *     @type string     $comment_date         The date the comment was submitted. To set the date
+ *                                            manually, `$comment_date_gmt` must also be specified.
+ *                                            Default is the current time.
+ *     @type string     $comment_date_gmt     The date the comment was submitted in the GMT timezone.
+ *                                            Default is `$comment_date` in the site's GMT timezone.
+ *     @type int        $comment_karma        The karma of the comment. Default 0.
+ *     @type int        $comment_parent       ID of this comment's parent, if any. Default 0.
+ *     @type int        $comment_post_ID      ID of the post that relates to the comment, if any.
+ *                                            Default empty.
+ *     @type string     $comment_type         Comment type. Default empty.
+ *     @type array      $comment_meta         Optional. Array of key/value pairs to be stored in commentmeta for the
+ *                                            new comment.
+ *     @type int        $user_id              ID of the user who submitted the comment. Default 0.
+ * }
+ * @return int|false The new comment's ID on success, false on failure.
+ */
+function wp_insert_comment( $commentdata ) {
+       global $wpdb;
+       $data = wp_unslash( $commentdata );
+
+       $comment_author       = ! isset( $data['comment_author'] )       ? '' : $data['comment_author'];
+       $comment_author_email = ! isset( $data['comment_author_email'] ) ? '' : $data['comment_author_email'];
+       $comment_author_url   = ! isset( $data['comment_author_url'] )   ? '' : $data['comment_author_url'];
+       $comment_author_IP    = ! isset( $data['comment_author_IP'] )    ? '' : $data['comment_author_IP'];
+
+       $comment_date     = ! isset( $data['comment_date'] )     ? current_time( 'mysql' )            : $data['comment_date'];
+       $comment_date_gmt = ! isset( $data['comment_date_gmt'] ) ? get_gmt_from_date( $comment_date ) : $data['comment_date_gmt'];
+
+       $comment_post_ID  = ! isset( $data['comment_post_ID'] )  ? '' : $data['comment_post_ID'];
+       $comment_content  = ! isset( $data['comment_content'] )  ? '' : $data['comment_content'];
+       $comment_karma    = ! isset( $data['comment_karma'] )    ? 0  : $data['comment_karma'];
+       $comment_approved = ! isset( $data['comment_approved'] ) ? 1  : $data['comment_approved'];
+       $comment_agent    = ! isset( $data['comment_agent'] )    ? '' : $data['comment_agent'];
+       $comment_type     = ! isset( $data['comment_type'] )     ? '' : $data['comment_type'];
+       $comment_parent   = ! isset( $data['comment_parent'] )   ? 0  : $data['comment_parent'];
+
+       $user_id  = ! isset( $data['user_id'] ) ? 0 : $data['user_id'];
+
+       $compacted = compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id' );
+       if ( ! $wpdb->insert( $wpdb->comments, $compacted ) ) {
+               return false;
+       }
+
+       $id = (int) $wpdb->insert_id;
+
+       if ( $comment_approved == 1 ) {
+               wp_update_comment_count( $comment_post_ID );
+       }
+       $comment = get_comment( $id );
+
+       // If metadata is provided, store it.
+       if ( isset( $commentdata['comment_meta'] ) && is_array( $commentdata['comment_meta'] ) ) {
+               foreach ( $commentdata['comment_meta'] as $meta_key => $meta_value ) {
+                       add_comment_meta( $comment->comment_ID, $meta_key, $meta_value, true );
+               }
+       }
+
+       /**
+        * Fires immediately after a comment is inserted into the database.
+        *
+        * @since 2.8.0
+        *
+        * @param int        $id      The comment ID.
+        * @param WP_Comment $comment Comment object.
+        */
+       do_action( 'wp_insert_comment', $id, $comment );
+
+       wp_cache_set( 'last_changed', microtime(), 'comment' );
+
+       return $id;
+}
+
+/**
+ * Filters and sanitizes comment data.
+ *
+ * Sets the comment data 'filtered' field to true when finished. This can be
+ * checked as to whether the comment should be filtered and to keep from
+ * filtering the same comment more than once.
+ *
+ * @since 2.0.0
+ *
+ * @param array $commentdata Contains information on the comment.
+ * @return array Parsed comment information.
+ */
+function wp_filter_comment($commentdata) {
+       if ( isset( $commentdata['user_ID'] ) ) {
+               /**
+                * Filter the comment author's user id before it is set.
+                *
+                * The first time this filter is evaluated, 'user_ID' is checked
+                * (for back-compat), followed by the standard 'user_id' value.
+                *
+                * @since 1.5.0
+                *
+                * @param int $user_ID The comment author's user ID.
+                */
+               $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_ID'] );
+       } elseif ( isset( $commentdata['user_id'] ) ) {
+               /** This filter is documented in wp-includes/comment-functions.php */
+               $commentdata['user_id'] = apply_filters( 'pre_user_id', $commentdata['user_id'] );
+       }
+
+       /**
+        * Filter the comment author's browser user agent before it is set.
+        *
+        * @since 1.5.0
+        *
+        * @param int $comment_agent The comment author's browser user agent.
+        */
+       $commentdata['comment_agent'] = apply_filters( 'pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
+       /** This filter is documented in wp-includes/comment-functions.php */
+       $commentdata['comment_author'] = apply_filters( 'pre_comment_author_name', $commentdata['comment_author'] );
+       /**
+        * Filter the comment content before it is set.
+        *
+        * @since 1.5.0
+        *
+        * @param int $comment_content The comment content.
+        */
+       $commentdata['comment_content'] = apply_filters( 'pre_comment_content', $commentdata['comment_content'] );
+       /**
+        * Filter the comment author's IP before it is set.
+        *
+        * @since 1.5.0
+        *
+        * @param int $comment_author_ip The comment author's IP.
+        */
+       $commentdata['comment_author_IP'] = apply_filters( 'pre_comment_user_ip', $commentdata['comment_author_IP'] );
+       /** This filter is documented in wp-includes/comment-functions.php */
+       $commentdata['comment_author_url'] = apply_filters( 'pre_comment_author_url', $commentdata['comment_author_url'] );
+       /** This filter is documented in wp-includes/comment-functions.php */
+       $commentdata['comment_author_email'] = apply_filters( 'pre_comment_author_email', $commentdata['comment_author_email'] );
+       $commentdata['filtered'] = true;
+       return $commentdata;
+}
+
+/**
+ * Whether a comment should be blocked because of comment flood.
+ *
+ * @since 2.1.0
+ *
+ * @param bool $block Whether plugin has already blocked comment.
+ * @param int $time_lastcomment Timestamp for last comment.
+ * @param int $time_newcomment Timestamp for new comment.
+ * @return bool Whether comment should be blocked.
+ */
+function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
+       if ( $block ) // a plugin has already blocked... we'll let that decision stand
+               return $block;
+       if ( ($time_newcomment - $time_lastcomment) < 15 )
+               return true;
+       return false;
+}
+
+/**
+ * Adds a new comment to the database.
+ *
+ * Filters new comment to ensure that the fields are sanitized and valid before
+ * inserting comment into database. Calls 'comment_post' action with comment ID
+ * and whether comment is approved by WordPress. Also has 'preprocess_comment'
+ * filter for processing the comment data before the function handles it.
+ *
+ * We use REMOTE_ADDR here directly. If you are behind a proxy, you should ensure
+ * that it is properly set, such as in wp-config.php, for your environment.
+ * See {@link https://core.trac.wordpress.org/ticket/9235}
+ *
+ * @since 1.5.0
+ * @since 4.3.0 'comment_agent' and 'comment_author_IP' can be set via `$commentdata`.
+ *
+ * @see wp_insert_comment()
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $commentdata {
+ *     Comment data.
+ *
+ *     @type string $comment_author       The name of the comment author.
+ *     @type string $comment_author_email The comment author email address.
+ *     @type string $comment_author_url   The comment author URL.
+ *     @type string $comment_content      The content of the comment.
+ *     @type string $comment_date         The date the comment was submitted. Default is the current time.
+ *     @type string $comment_date_gmt     The date the comment was submitted in the GMT timezone.
+ *                                        Default is `$comment_date` in the GMT timezone.
+ *     @type int    $comment_parent       The ID of this comment's parent, if any. Default 0.
+ *     @type int    $comment_post_ID      The ID of the post that relates to the comment.
+ *     @type int    $user_id              The ID of the user who submitted the comment. Default 0.
+ *     @type int    $user_ID              Kept for backward-compatibility. Use `$user_id` instead.
+ *     @type string $comment_agent        Comment author user agent. Default is the value of 'HTTP_USER_AGENT'
+ *                                        in the `$_SERVER` superglobal sent in the original request.
+ *     @type string $comment_author_IP    Comment author IP address in IPv4 format. Default is the value of
+ *                                        'REMOTE_ADDR' in the `$_SERVER` superglobal sent in the original request.
+ * }
+ * @return int|false The ID of the comment on success, false on failure.
+ */
+function wp_new_comment( $commentdata ) {
+       global $wpdb;
+
+       if ( isset( $commentdata['user_ID'] ) ) {
+               $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
+       }
+
+       $prefiltered_user_id = ( isset( $commentdata['user_id'] ) ) ? (int) $commentdata['user_id'] : 0;
+
+       /**
+        * Filter a comment's data before it is sanitized and inserted into the database.
+        *
+        * @since 1.5.0
+        *
+        * @param array $commentdata Comment data.
+        */
+       $commentdata = apply_filters( 'preprocess_comment', $commentdata );
+
+       $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
+       if ( isset( $commentdata['user_ID'] ) && $prefiltered_user_id !== (int) $commentdata['user_ID'] ) {
+               $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
+       } elseif ( isset( $commentdata['user_id'] ) ) {
+               $commentdata['user_id'] = (int) $commentdata['user_id'];
+       }
+
+       $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
+       $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
+       $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
+
+       if ( ! isset( $commentdata['comment_author_IP'] ) ) {
+               $commentdata['comment_author_IP'] = $_SERVER['REMOTE_ADDR'];
+       }
+       $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '', $commentdata['comment_author_IP'] );
+
+       if ( ! isset( $commentdata['comment_agent'] ) ) {
+               $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT']: '';
+       }
+       $commentdata['comment_agent'] = substr( $commentdata['comment_agent'], 0, 254 );
+
+       if ( empty( $commentdata['comment_date'] ) ) {
+               $commentdata['comment_date'] = current_time('mysql');
+       }
+
+       if ( empty( $commentdata['comment_date_gmt'] ) ) {
+               $commentdata['comment_date_gmt'] = current_time( 'mysql', 1 );
+       }
+
+       $commentdata = wp_filter_comment($commentdata);
+
+       $commentdata['comment_approved'] = wp_allow_comment($commentdata);
+
+       $comment_ID = wp_insert_comment($commentdata);
+       if ( ! $comment_ID ) {
+               $fields = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content' );
+
+               foreach ( $fields as $field ) {
+                       if ( isset( $commentdata[ $field ] ) ) {
+                               $commentdata[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->comments, $field, $commentdata[ $field ] );
+                       }
+               }
+
+               $commentdata = wp_filter_comment( $commentdata );
+
+               $commentdata['comment_approved'] = wp_allow_comment( $commentdata );
+
+               $comment_ID = wp_insert_comment( $commentdata );
+               if ( ! $comment_ID ) {
+                       return false;
+               }
+       }
+
+       /**
+        * Fires immediately after a comment is inserted into the database.
+        *
+        * @since 1.2.0
+        *
+        * @param int        $comment_ID       The comment ID.
+        * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
+        */
+       do_action( 'comment_post', $comment_ID, $commentdata['comment_approved'] );
+
+       return $comment_ID;
+}
+
+/**
+ * Send a comment moderation notification to the comment moderator.
+ *
+ * @since 4.4.0
+ *
+ * @param int $comment_ID ID of the comment.
+ * @return bool True on success, false on failure.
+ */
+function wp_new_comment_notify_moderator( $comment_ID ) {
+       $comment = get_comment( $comment_ID );
+
+       // Only send notifications for pending comments.
+       $maybe_notify = ( '0' == $comment->comment_approved );
+
+       /** This filter is documented in wp-includes/comment-functions.php */
+       $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_ID );
+
+       if ( ! $maybe_notify ) {
+               return false;
+       }
+
+       return wp_notify_moderator( $comment_ID );
+}
+
+/**
+ * Send a notification of a new comment to the post author.
+ *
+ * @since 4.4.0
+ *
+ * Uses the {@see 'notify_post_author'} filter to determine whether the post author
+ * should be notified when a new comment is added, overriding site setting.
+ *
+ * @param int $comment_ID Comment ID.
+ * @return bool True on success, false on failure.
+ */
+function wp_new_comment_notify_postauthor( $comment_ID ) {
+       $comment = get_comment( $comment_ID );
+
+       $maybe_notify = get_option( 'comments_notify' );
+
+       /**
+        * Filter whether to send the post author new comment notification emails,
+        * overriding the site setting.
+        *
+        * @since 4.4.0
+        *
+        * @param bool $maybe_notify Whether to notify the post author about the new comment.
+        * @param int  $comment_ID   The ID of the comment for the notification.
+        */
+       $maybe_notify = apply_filters( 'notify_post_author', $maybe_notify, $comment_ID );
+
+       /*
+        * wp_notify_postauthor() checks if notifying the author of their own comment.
+        * By default, it won't, but filters can override this.
+        */
+       if ( ! $maybe_notify ) {
+               return false;
+       }
+
+       // Only send notifications for approved comments.
+       if ( ! isset( $comment->comment_approved ) || 'spam' === $comment->comment_approved || ! $comment->comment_approved ) {
+               return false;
+       }
+
+       return wp_notify_postauthor( $comment_ID );
+}
+
+/**
+ * Sets the status of a comment.
+ *
+ * The 'wp_set_comment_status' action is called after the comment is handled.
+ * If the comment status is not in the list, then false is returned.
+ *
+ * @since 1.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|WP_Comment $comment_id     Comment ID or WP_Comment object.
+ * @param string         $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
+ * @param bool           $wp_error       Whether to return a WP_Error object if there is a failure. Default is false.
+ * @return bool|WP_Error True on success, false or WP_Error on failure.
+ */
+function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
+       global $wpdb;
+
+       switch ( $comment_status ) {
+               case 'hold':
+               case '0':
+                       $status = '0';
+                       break;
+               case 'approve':
+               case '1':
+                       $status = '1';
+                       add_action( 'wp_set_comment_status', 'wp_new_comment_notify_postauthor' );
+                       break;
+               case 'spam':
+                       $status = 'spam';
+                       break;
+               case 'trash':
+                       $status = 'trash';
+                       break;
+               default:
+                       return false;
+       }
+
+       $comment_old = clone get_comment($comment_id);
+
+       if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array( 'comment_ID' => $comment_old->comment_ID ) ) ) {
+               if ( $wp_error )
+                       return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
+               else
+                       return false;
+       }
+
+       clean_comment_cache( $comment_old->comment_ID );
+
+       $comment = get_comment( $comment_old->comment_ID );
+
+       /**
+        * Fires immediately before transitioning a comment's status from one to another
+        * in the database.
+        *
+        * @since 1.5.0
+        *
+        * @param int         $comment_id     Comment ID.
+        * @param string|bool $comment_status Current comment status. Possible values include
+        *                                    'hold', 'approve', 'spam', 'trash', or false.
+        */
+       do_action( 'wp_set_comment_status', $comment->comment_ID, $comment_status );
+
+       wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
+
+       wp_update_comment_count($comment->comment_post_ID);
+
+       return true;
+}
+
+/**
+ * Updates an existing comment in the database.
+ *
+ * Filters the comment and makes sure certain fields are valid before updating.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $commentarr Contains information on the comment.
+ * @return int Comment was updated if value is 1, or was not updated if value is 0.
+ */
+function wp_update_comment($commentarr) {
+       global $wpdb;
+
+       // First, get all of the original fields
+       $comment = get_comment($commentarr['comment_ID'], ARRAY_A);
+       if ( empty( $comment ) ) {
+               return 0;
+       }
+
+       // Make sure that the comment post ID is valid (if specified).
+       if ( isset( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
+               return 0;
+       }
+
+       // Escape data pulled from DB.
+       $comment = wp_slash($comment);
+
+       $old_status = $comment['comment_approved'];
+
+       // Merge old and new fields with new fields overwriting old ones.
+       $commentarr = array_merge($comment, $commentarr);
+
+       $commentarr = wp_filter_comment( $commentarr );
+
+       // Now extract the merged array.
+       $data = wp_unslash( $commentarr );
+
+       /**
+        * Filter the comment content before it is updated in the database.
+        *
+        * @since 1.5.0
+        *
+        * @param string $comment_content The comment data.
+        */
+       $data['comment_content'] = apply_filters( 'comment_save_pre', $data['comment_content'] );
+
+       $data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] );
+
+       if ( ! isset( $data['comment_approved'] ) ) {
+               $data['comment_approved'] = 1;
+       } elseif ( 'hold' == $data['comment_approved'] ) {
+               $data['comment_approved'] = 0;
+       } elseif ( 'approve' == $data['comment_approved'] ) {
+               $data['comment_approved'] = 1;
+       }
+
+       $comment_ID = $data['comment_ID'];
+       $comment_post_ID = $data['comment_post_ID'];
+       $keys = array( 'comment_post_ID', 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_type', 'comment_parent', 'user_id' );
+       $data = wp_array_slice_assoc( $data, $keys );
+       $rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
+
+       clean_comment_cache( $comment_ID );
+       wp_update_comment_count( $comment_post_ID );
+       /**
+        * Fires immediately after a comment is updated in the database.
+        *
+        * The hook also fires immediately before comment status transition hooks are fired.
+        *
+        * @since 1.2.0
+        *
+        * @param int $comment_ID The comment ID.
+        */
+       do_action( 'edit_comment', $comment_ID );
+       $comment = get_comment($comment_ID);
+       wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
+       return $rval;
+}
+
+/**
+ * Whether to defer comment counting.
+ *
+ * When setting $defer to true, all post comment counts will not be updated
+ * until $defer is set to false. When $defer is set to false, then all
+ * previously deferred updated post comment counts will then be automatically
+ * updated without having to call wp_update_comment_count() after.
+ *
+ * @since 2.5.0
+ * @staticvar bool $_defer
+ *
+ * @param bool $defer
+ * @return bool
+ */
+function wp_defer_comment_counting($defer=null) {
+       static $_defer = false;
+
+       if ( is_bool($defer) ) {
+               $_defer = $defer;
+               // flush any deferred counts
+               if ( !$defer )
+                       wp_update_comment_count( null, true );
+       }
+
+       return $_defer;
+}
+
+/**
+ * Updates the comment count for post(s).
+ *
+ * When $do_deferred is false (is by default) and the comments have been set to
+ * be deferred, the post_id will be added to a queue, which will be updated at a
+ * later date and only updated once per post ID.
+ *
+ * If the comments have not be set up to be deferred, then the post will be
+ * updated. When $do_deferred is set to true, then all previous deferred post
+ * IDs will be updated along with the current $post_id.
+ *
+ * @since 2.1.0
+ * @see wp_update_comment_count_now() For what could cause a false return value
+ *
+ * @staticvar array $_deferred
+ *
+ * @param int $post_id Post ID
+ * @param bool $do_deferred Whether to process previously deferred post comment counts
+ * @return bool|void True on success, false on failure
+ */
+function wp_update_comment_count($post_id, $do_deferred=false) {
+       static $_deferred = array();
+
+       if ( $do_deferred ) {
+               $_deferred = array_unique($_deferred);
+               foreach ( $_deferred as $i => $_post_id ) {
+                       wp_update_comment_count_now($_post_id);
+                       unset( $_deferred[$i] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */
+               }
+       }
+
+       if ( wp_defer_comment_counting() ) {
+               $_deferred[] = $post_id;
+               return true;
+       }
+       elseif ( $post_id ) {
+               return wp_update_comment_count_now($post_id);
+       }
+
+}
+
+/**
+ * Updates the comment count for the post.
+ *
+ * @since 2.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int $post_id Post ID
+ * @return bool True on success, false on '0' $post_id or if post with ID does not exist.
+ */
+function wp_update_comment_count_now($post_id) {
+       global $wpdb;
+       $post_id = (int) $post_id;
+       if ( !$post_id )
+               return false;
+
+       wp_cache_delete( 'comments-0', 'counts' );
+       wp_cache_delete( "comments-{$post_id}", 'counts' );
+
+       if ( !$post = get_post($post_id) )
+               return false;
+
+       $old = (int) $post->comment_count;
+       $new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
+       $wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
+
+       clean_post_cache( $post );
+
+       /**
+        * Fires immediately after a post's comment count is updated in the database.
+        *
+        * @since 2.3.0
+        *
+        * @param int $post_id Post ID.
+        * @param int $new     The new comment count.
+        * @param int $old     The old comment count.
+        */
+       do_action( 'wp_update_comment_count', $post_id, $new, $old );
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'edit_post', $post_id, $post );
+
+       return true;
+}
+
+//
+// Ping and trackback functions.
+//
+
+/**
+ * Finds a pingback server URI based on the given URL.
+ *
+ * Checks the HTML for the rel="pingback" link and x-pingback headers. It does
+ * a check for the x-pingback headers first and returns that, if available. The
+ * check for the rel="pingback" has more overhead than just the header.
+ *
+ * @since 1.5.0
+ *
+ * @param string $url URL to ping.
+ * @param int $deprecated Not Used.
+ * @return false|string False on failure, string containing URI on success.
+ */
+function discover_pingback_server_uri( $url, $deprecated = '' ) {
+       if ( !empty( $deprecated ) )
+               _deprecated_argument( __FUNCTION__, '2.7' );
+
+       $pingback_str_dquote = 'rel="pingback"';
+       $pingback_str_squote = 'rel=\'pingback\'';
+
+       /** @todo Should use Filter Extension or custom preg_match instead. */
+       $parsed_url = parse_url($url);
+
+       if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
+               return false;
+
+       //Do not search for a pingback server on our own uploads
+       $uploads_dir = wp_upload_dir();
+       if ( 0 === strpos($url, $uploads_dir['baseurl']) )
+               return false;
+
+       $response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
+
+       if ( is_wp_error( $response ) )
+               return false;
+
+       if ( wp_remote_retrieve_header( $response, 'x-pingback' ) )
+               return wp_remote_retrieve_header( $response, 'x-pingback' );
+
+       // Not an (x)html, sgml, or xml page, no use going further.
+       if ( preg_match('#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' )) )
+               return false;
+
+       // Now do a GET since we're going to look in the html headers (and we're sure it's not a binary file)
+       $response = wp_safe_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
+
+       if ( is_wp_error( $response ) )
+               return false;
+
+       $contents = wp_remote_retrieve_body( $response );
+
+       $pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
+       $pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
+       if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
+               $quote = ($pingback_link_offset_dquote) ? '"' : '\'';
+               $pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
+               $pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
+               $pingback_href_start = $pingback_href_pos+6;
+               $pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
+               $pingback_server_url_len = $pingback_href_end - $pingback_href_start;
+               $pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
+
+               // We may find rel="pingback" but an incomplete pingback URL
+               if ( $pingback_server_url_len > 0 ) { // We got it!
+                       return $pingback_server_url;
+               }
+       }
+
+       return false;
+}
+
+/**
+ * Perform all pingbacks, enclosures, trackbacks, and send to pingback services.
+ *
+ * @since 2.1.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ */
+function do_all_pings() {
+       global $wpdb;
+
+       // Do pingbacks
+       while ($ping = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1")) {
+               delete_metadata_by_mid( 'post', $ping->meta_id );
+               pingback( $ping->post_content, $ping->ID );
+       }
+
+       // Do Enclosures
+       while ($enclosure = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1")) {
+               delete_metadata_by_mid( 'post', $enclosure->meta_id );
+               do_enclose( $enclosure->post_content, $enclosure->ID );
+       }
+
+       // Do Trackbacks
+       $trackbacks = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'");
+       if ( is_array($trackbacks) )
+               foreach ( $trackbacks as $trackback )
+                       do_trackbacks($trackback);
+
+       //Do Update Services/Generic Pings
+       generic_ping();
+}
+
+/**
+ * Perform trackbacks.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int $post_id Post ID to do trackbacks on.
+ */
+function do_trackbacks($post_id) {
+       global $wpdb;
+
+       $post = get_post( $post_id );
+       $to_ping = get_to_ping($post_id);
+       $pinged  = get_pung($post_id);
+       if ( empty($to_ping) ) {
+               $wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
+               return;
+       }
+
+       if ( empty($post->post_excerpt) ) {
+               /** This filter is documented in wp-includes/post-template.php */
+               $excerpt = apply_filters( 'the_content', $post->post_content, $post->ID );
+       } else {
+               /** This filter is documented in wp-includes/post-template.php */
+               $excerpt = apply_filters( 'the_excerpt', $post->post_excerpt );
+       }
+
+       $excerpt = str_replace(']]>', ']]&gt;', $excerpt);
+       $excerpt = wp_html_excerpt($excerpt, 252, '&#8230;');
+
+       /** This filter is documented in wp-includes/post-template.php */
+       $post_title = apply_filters( 'the_title', $post->post_title, $post->ID );
+       $post_title = strip_tags($post_title);
+
+       if ( $to_ping ) {
+               foreach ( (array) $to_ping as $tb_ping ) {
+                       $tb_ping = trim($tb_ping);
+                       if ( !in_array($tb_ping, $pinged) ) {
+                               trackback($tb_ping, $post_title, $excerpt, $post_id);
+                               $pinged[] = $tb_ping;
+                       } else {
+                               $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
+                       }
+               }
+       }
+}
+
+/**
+ * Sends pings to all of the ping site services.
+ *
+ * @since 1.2.0
+ *
+ * @param int $post_id Post ID.
+ * @return int Same as Post ID from parameter
+ */
+function generic_ping( $post_id = 0 ) {
+       $services = get_option('ping_sites');
+
+       $services = explode("\n", $services);
+       foreach ( (array) $services as $service ) {
+               $service = trim($service);
+               if ( '' != $service )
+                       weblog_ping($service);
+       }
+
+       return $post_id;
+}
+
+/**
+ * Pings back the links found in a post.
+ *
+ * @since 0.71
+ *
+ * @global string $wp_version
+ *
+ * @param string $content Post content to check for links.
+ * @param int $post_ID Post ID.
+ */
+function pingback($content, $post_ID) {
+       global $wp_version;
+       include_once(ABSPATH . WPINC . '/class-IXR.php');
+       include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
+
+       // original code by Mort (http://mort.mine.nu:8080)
+       $post_links = array();
+
+       $pung = get_pung($post_ID);
+
+       // Step 1
+       // Parsing the post, external links (if any) are stored in the $post_links array
+       $post_links_temp = wp_extract_urls( $content );
+
+       // Step 2.
+       // Walking thru the links array
+       // first we get rid of links pointing to sites, not to specific files
+       // Example:
+       // http://dummy-weblog.org
+       // http://dummy-weblog.org/
+       // http://dummy-weblog.org/post.php
+       // We don't wanna ping first and second types, even if they have a valid <link/>
+
+       foreach ( (array) $post_links_temp as $link_test ) :
+               if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
+                               && !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
+                       if ( $test = @parse_url($link_test) ) {
+                               if ( isset($test['query']) )
+                                       $post_links[] = $link_test;
+                               elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
+                                       $post_links[] = $link_test;
+                       }
+               endif;
+       endforeach;
+
+       $post_links = array_unique( $post_links );
+       /**
+        * Fires just before pinging back links found in a post.
+        *
+        * @since 2.0.0
+        *
+        * @param array &$post_links An array of post links to be checked, passed by reference.
+        * @param array &$pung       Whether a link has already been pinged, passed by reference.
+        * @param int   $post_ID     The post ID.
+        */
+       do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post_ID ) );
+
+       foreach ( (array) $post_links as $pagelinkedto ) {
+               $pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
+
+               if ( $pingback_server_url ) {
+                       @ set_time_limit( 60 );
+                       // Now, the RPC call
+                       $pagelinkedfrom = get_permalink($post_ID);
+
+                       // using a timeout of 3 seconds should be enough to cover slow servers
+                       $client = new WP_HTTP_IXR_Client($pingback_server_url);
+                       $client->timeout = 3;
+                       /**
+                        * Filter the user agent sent when pinging-back a URL.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param string $concat_useragent    The user agent concatenated with ' -- WordPress/'
+                        *                                    and the WordPress version.
+                        * @param string $useragent           The useragent.
+                        * @param string $pingback_server_url The server URL being linked to.
+                        * @param string $pagelinkedto        URL of page linked to.
+                        * @param string $pagelinkedfrom      URL of page linked from.
+                        */
+                       $client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
+                       // when set to true, this outputs debug messages by itself
+                       $client->debug = false;
+
+                       if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
+                               add_ping( $post_ID, $pagelinkedto );
+               }
+       }
+}
+
+/**
+ * Check whether blog is public before returning sites.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $sites Will return if blog is public, will not return if not public.
+ * @return mixed Empty string if blog is not public, returns $sites, if site is public.
+ */
+function privacy_ping_filter($sites) {
+       if ( '0' != get_option('blog_public') )
+               return $sites;
+       else
+               return '';
+}
+
+/**
+ * Send a Trackback.
+ *
+ * Updates database when sending trackback to prevent duplicates.
+ *
+ * @since 0.71
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $trackback_url URL to send trackbacks.
+ * @param string $title Title of post.
+ * @param string $excerpt Excerpt of post.
+ * @param int $ID Post ID.
+ * @return int|false|void Database query from update.
+ */
+function trackback($trackback_url, $title, $excerpt, $ID) {
+       global $wpdb;
+
+       if ( empty($trackback_url) )
+               return;
+
+       $options = array();
+       $options['timeout'] = 10;
+       $options['body'] = array(
+               'title' => $title,
+               'url' => get_permalink($ID),
+               'blog_name' => get_option('blogname'),
+               'excerpt' => $excerpt
+       );
+
+       $response = wp_safe_remote_post( $trackback_url, $options );
+
+       if ( is_wp_error( $response ) )
+               return;
+
+       $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $ID) );
+       return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $ID) );
+}
+
+/**
+ * Send a pingback.
+ *
+ * @since 1.2.0
+ *
+ * @global string $wp_version
+ *
+ * @param string $server Host of blog to connect to.
+ * @param string $path Path to send the ping.
+ */
+function weblog_ping($server = '', $path = '') {
+       global $wp_version;
+       include_once(ABSPATH . WPINC . '/class-IXR.php');
+       include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
+
+       // using a timeout of 3 seconds should be enough to cover slow servers
+       $client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
+       $client->timeout = 3;
+       $client->useragent .= ' -- WordPress/'.$wp_version;
+
+       // when set to true, this outputs debug messages by itself
+       $client->debug = false;
+       $home = trailingslashit( home_url() );
+       if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
+               $client->query('weblogUpdates.ping', get_option('blogname'), $home);
+}
+
+/**
+ * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
+ *
+ * @since 3.5.1
+ * @see wp_http_validate_url()
+ *
+ * @param string $source_uri
+ * @return string
+ */
+function pingback_ping_source_uri( $source_uri ) {
+       return (string) wp_http_validate_url( $source_uri );
+}
+
+/**
+ * Default filter attached to xmlrpc_pingback_error.
+ *
+ * Returns a generic pingback error code unless the error code is 48,
+ * which reports that the pingback is already registered.
+ *
+ * @since 3.5.1
+ * @link http://www.hixie.ch/specs/pingback/pingback#TOC3
+ *
+ * @param IXR_Error $ixr_error
+ * @return IXR_Error
+ */
+function xmlrpc_pingback_error( $ixr_error ) {
+       if ( $ixr_error->code === 48 )
+               return $ixr_error;
+       return new IXR_Error( 0, '' );
+}
+
+//
+// Cache
+//
+
+/**
+ * Removes comment ID from the comment cache.
+ *
+ * @since 2.3.0
+ *
+ * @param int|array $ids Comment ID or array of comment IDs to remove from cache
+ */
+function clean_comment_cache($ids) {
+       foreach ( (array) $ids as $id ) {
+               wp_cache_delete( $id, 'comment' );
+       }
+
+       wp_cache_set( 'last_changed', microtime(), 'comment' );
+}
+
+/**
+ * Updates the comment cache of given comments.
+ *
+ * Will add the comments in $comments to the cache. If comment ID already exists
+ * in the comment cache then it will not be updated. The comment is added to the
+ * cache using the comment group with the key using the ID of the comments.
+ *
+ * @since 2.3.0
+ * @since 4.4.0 Introduced the `$update_meta_cache` parameter.
+ *
+ * @param array $comments          Array of comment row objects
+ * @param bool  $update_meta_cache Whether to update commentmeta cache. Default true.
+ */
+function update_comment_cache( $comments, $update_meta_cache = true ) {
+       foreach ( (array) $comments as $comment )
+               wp_cache_add($comment->comment_ID, $comment, 'comment');
+
+       if ( $update_meta_cache ) {
+               // Avoid `wp_list_pluck()` in case `$comments` is passed by reference.
+               $comment_ids = array();
+               foreach ( $comments as $comment ) {
+                       $comment_ids[] = $comment->comment_ID;
+               }
+               update_meta_cache( 'comment', $comment_ids );
+       }
+}
+
+/**
+ * Adds any comments from the given IDs to the cache that do not already exist in cache.
+ *
+ * @since 4.4.0
+ * @access private
+ *
+ * @see update_comment_cache()
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $comment_ids       Array of comment IDs.
+ * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
+ */
+function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
+       global $wpdb;
+
+       $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
+       if ( !empty( $non_cached_ids ) ) {
+               $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
+
+               update_comment_cache( $fresh_comments, $update_meta_cache );
+       }
+}
+
+//
+// Internal
+//
+
+/**
+ * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
+ *
+ * @access private
+ * @since 2.7.0
+ *
+ * @param WP_Post  $posts Post data object.
+ * @param WP_Query $query Query object.
+ * @return array
+ */
+function _close_comments_for_old_posts( $posts, $query ) {
+       if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
+               return $posts;
+
+       /**
+        * Filter the list of post types to automatically close comments for.
+        *
+        * @since 3.2.0
+        *
+        * @param array $post_types An array of registered post types. Default array with 'post'.
+        */
+       $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
+       if ( ! in_array( $posts[0]->post_type, $post_types ) )
+               return $posts;
+
+       $days_old = (int) get_option( 'close_comments_days_old' );
+       if ( ! $days_old )
+               return $posts;
+
+       if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) {
+               $posts[0]->comment_status = 'closed';
+               $posts[0]->ping_status = 'closed';
+       }
+
+       return $posts;
+}
+
+/**
+ * Close comments on an old post. Hooked to comments_open and pings_open.
+ *
+ * @access private
+ * @since 2.7.0
+ *
+ * @param bool $open Comments open or closed
+ * @param int $post_id Post ID
+ * @return bool $open
+ */
+function _close_comments_for_old_post( $open, $post_id ) {
+       if ( ! $open )
+               return $open;
+
+       if ( !get_option('close_comments_for_old_posts') )
+               return $open;
+
+       $days_old = (int) get_option('close_comments_days_old');
+       if ( !$days_old )
+               return $open;
+
+       $post = get_post($post_id);
+
+       /** This filter is documented in wp-includes/comment-functions.php */
+       $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
+       if ( ! in_array( $post->post_type, $post_types ) )
+               return $open;
+
+       // Undated drafts should not show up as comments closed.
+       if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {
+               return $open;
+       }
+
+       if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
+               return false;
+
+       return $open;
+}
+
+/**
+ * Handles the submission of a comment, usually posted to wp-comments-post.php via a comment form.
+ *
+ * This function expects unslashed data, as opposed to functions such as `wp_new_comment()` which
+ * expect slashed data.
+ *
+ * @since 4.4.0
+ *
+ * @param array $comment_data {
+ *     Comment data.
+ *
+ *     @type string|int $comment_post_ID             The ID of the post that relates to the comment.
+ *     @type string     $author                      The name of the comment author.
+ *     @type string     $email                       The comment author email address.
+ *     @type string     $url                         The comment author URL.
+ *     @type string     $comment                     The content of the comment.
+ *     @type string|int $comment_parent              The ID of this comment's parent, if any. Default 0.
+ *     @type string     $_wp_unfiltered_html_comment The nonce value for allowing unfiltered HTML.
+ * }
+ * @return WP_Comment|WP_Error A WP_Comment object on success, a WP_Error object on failure.
+ */
+function wp_handle_comment_submission( $comment_data ) {
+
+       $comment_post_ID = $comment_parent = 0;
+       $comment_author = $comment_author_email = $comment_author_url = $comment_content = $_wp_unfiltered_html_comment = null;
+
+       if ( isset( $comment_data['comment_post_ID'] ) ) {
+               $comment_post_ID = (int) $comment_data['comment_post_ID'];
+       }
+       if ( isset( $comment_data['author'] ) && is_string( $comment_data['author'] ) ) {
+               $comment_author = trim( strip_tags( $comment_data['author'] ) );
+       }
+       if ( isset( $comment_data['email'] ) && is_string( $comment_data['email'] ) ) {
+               $comment_author_email = trim( $comment_data['email'] );
+       }
+       if ( isset( $comment_data['url'] ) && is_string( $comment_data['url'] ) ) {
+               $comment_author_url = trim( $comment_data['url'] );
+       }
+       if ( isset( $comment_data['comment'] ) && is_string( $comment_data['comment'] ) ) {
+               $comment_content = trim( $comment_data['comment'] );
+       }
+       if ( isset( $comment_data['comment_parent'] ) ) {
+               $comment_parent = absint( $comment_data['comment_parent'] );
+       }
+       if ( isset( $comment_data['_wp_unfiltered_html_comment'] ) && is_string( $comment_data['_wp_unfiltered_html_comment'] ) ) {
+               $_wp_unfiltered_html_comment = trim( $comment_data['_wp_unfiltered_html_comment'] );
+       }
+
+       $post = get_post( $comment_post_ID );
+
+       if ( empty( $post->comment_status ) ) {
+
+               /**
+                * Fires when a comment is attempted on a post that does not exist.
+                *
+                * @since 1.5.0
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'comment_id_not_found', $comment_post_ID );
+
+               return new WP_Error( 'comment_id_not_found' );
+
+       }
+
+       // get_post_status() will get the parent status for attachments.
+       $status = get_post_status( $post );
+
+       $status_obj = get_post_status_object( $status );
+
+       if ( ! comments_open( $comment_post_ID ) ) {
+
+               /**
+                * Fires when a comment is attempted on a post that has comments closed.
+                *
+                * @since 1.5.0
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'comment_closed', $comment_post_ID );
+
+               return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );
+
+       } elseif ( 'trash' == $status ) {
+
+               /**
+                * Fires when a comment is attempted on a trashed post.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'comment_on_trash', $comment_post_ID );
+
+               return new WP_Error( 'comment_on_trash' );
+
+       } elseif ( ! $status_obj->public && ! $status_obj->private ) {
+
+               /**
+                * Fires when a comment is attempted on a post in draft mode.
+                *
+                * @since 1.5.1
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'comment_on_draft', $comment_post_ID );
+
+               return new WP_Error( 'comment_on_draft' );
+
+       } elseif ( post_password_required( $comment_post_ID ) ) {
+
+               /**
+                * Fires when a comment is attempted on a password-protected post.
+                *
+                * @since 2.9.0
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'comment_on_password_protected', $comment_post_ID );
+
+               return new WP_Error( 'comment_on_password_protected' );
+
+       } else {
+
+               /**
+                * Fires before a comment is posted.
+                *
+                * @since 2.8.0
+                *
+                * @param int $comment_post_ID Post ID.
+                */
+               do_action( 'pre_comment_on_post', $comment_post_ID );
+
+       }
+
+       // If the user is logged in
+       $user = wp_get_current_user();
+       if ( $user->exists() ) {
+               if ( empty( $user->display_name ) ) {
+                       $user->display_name=$user->user_login;
+               }
+               $comment_author       = $user->display_name;
+               $comment_author_email = $user->user_email;
+               $comment_author_url   = $user->user_url;
+               $user_id              = $user->ID;
+               if ( current_user_can( 'unfiltered_html' ) ) {
+                       if ( ! isset( $comment_data['_wp_unfiltered_html_comment'] )
+                               || ! wp_verify_nonce( $comment_data['_wp_unfiltered_html_comment'], 'unfiltered-html-comment_' . $comment_post_ID )
+                       ) {
+                               kses_remove_filters(); // start with a clean slate
+                               kses_init_filters(); // set up the filters
+                       }
+               }
+       } else {
+               if ( get_option( 'comment_registration' ) || 'private' == $status ) {
+                       return new WP_Error( 'not_logged_in', __( 'Sorry, you must be logged in to post a comment.' ), 403 );
+               }
+       }
+
+       $comment_type = '';
+
+       if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
+               if ( 6 > strlen( $comment_author_email ) || '' == $comment_author ) {
+                       return new WP_Error( 'require_name_email', __( '<strong>ERROR</strong>: please fill the required fields (name, email).' ), 200 );
+               } elseif ( ! is_email( $comment_author_email ) ) {
+                       return new WP_Error( 'require_valid_email', __( '<strong>ERROR</strong>: please enter a valid email address.' ), 200 );
+               }
+       }
+
+       if ( '' == $comment_content ) {
+               return new WP_Error( 'require_valid_comment', __( '<strong>ERROR</strong>: please type a comment.' ), 200 );
+       }
+
+       $commentdata = compact(
+               'comment_post_ID',
+               'comment_author',
+               'comment_author_email',
+               'comment_author_url',
+               'comment_content',
+               'comment_type',
+               'comment_parent',
+               'user_id'
+       );
+
+       $comment_id = wp_new_comment( wp_slash( $commentdata ) );
+       if ( ! $comment_id ) {
+               return new WP_Error( 'comment_save_error', __( '<strong>ERROR</strong>: The comment could not be saved. Please try again later.' ), 500 );
+       }
+
+       return get_comment( $comment_id );
+
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesembedfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/embed-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/embed-functions.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/embed-functions.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,1047 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * oEmbed API: Top-level oEmbed functionality
- *
- * @package WordPress
- * @subpackage oEmbed
- * @since 4.4.0
- */
-
-/**
- * Registers an embed handler.
- *
- * Should probably only be used for sites that do not support oEmbed.
- *
- * @since 2.9.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param string   $id       An internal ID/name for the handler. Needs to be unique.
- * @param string   $regex    The regex that will be used to see if this handler should be used for a URL.
- * @param callable $callback The callback function that will be called if the regex is matched.
- * @param int      $priority Optional. Used to specify the order in which the registered handlers will
- *                           be tested. Default 10.
- */
-function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
-       global $wp_embed;
-       $wp_embed->register_handler( $id, $regex, $callback, $priority );
-}
-
-/**
- * Unregisters a previously-registered embed handler.
- *
- * @since 2.9.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param string $id       The handler ID that should be removed.
- * @param int    $priority Optional. The priority of the handler to be removed. Default 10.
- */
-function wp_embed_unregister_handler( $id, $priority = 10 ) {
-       global $wp_embed;
-       $wp_embed->unregister_handler( $id, $priority );
-}
-
-/**
- * Creates default array of embed parameters.
- *
- * The width defaults to the content width as specified by the theme. If the
- * theme does not specify a content width, then 500px is used.
- *
- * The default height is 1.5 times the width, or 1000px, whichever is smaller.
- *
- * The 'embed_defaults' filter can be used to adjust either of these values.
- *
- * @since 2.9.0
- *
- * @global int $content_width
- *
- * @param string $url Optional. The URL that should be embedded. Default empty.
- *
- * @return array Default embed parameters.
- */
-function wp_embed_defaults( $url = '' ) {
-       if ( ! empty( $GLOBALS['content_width'] ) )
-               $width = (int) $GLOBALS['content_width'];
-
-       if ( empty( $width ) )
-               $width = 500;
-
-       $height = min( ceil( $width * 1.5 ), 1000 );
-
-       /**
-        * Filter the default array of embed dimensions.
-        *
-        * @since 2.9.0
-        *
-        * @param array  $size An array of embed width and height values
-        *                     in pixels (in that order).
-        * @param string $url  The URL that should be embedded.
-        */
-       return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url );
-}
-
-/**
- * Attempts to fetch the embed HTML for a provided URL using oEmbed.
- *
- * @since 2.9.0
- *
- * @see WP_oEmbed
- *
- * @param string $url  The URL that should be embedded.
- * @param array  $args Optional. Additional arguments and parameters for retrieving embed HTML.
- *                     Default empty.
- * @return false|string False on failure or the embed HTML on success.
- */
-function wp_oembed_get( $url, $args = '' ) {
-       require_once( ABSPATH . WPINC . '/class-oembed.php' );
-       $oembed = _wp_oembed_get_object();
-       return $oembed->get_html( $url, $args );
-}
-
-/**
- * Adds a URL format and oEmbed provider URL pair.
- *
- * @since 2.9.0
- *
- * @see WP_oEmbed
- *
- * @param string  $format   The format of URL that this provider can handle. You can use asterisks
- *                          as wildcards.
- * @param string  $provider The URL to the oEmbed provider.
- * @param boolean $regex    Optional. Whether the `$format` parameter is in a RegEx format. Default false.
- */
-function wp_oembed_add_provider( $format, $provider, $regex = false ) {
-       require_once( ABSPATH . WPINC . '/class-oembed.php' );
-
-       if ( did_action( 'plugins_loaded' ) ) {
-               $oembed = _wp_oembed_get_object();
-               $oembed->providers[$format] = array( $provider, $regex );
-       } else {
-               WP_oEmbed::_add_provider_early( $format, $provider, $regex );
-       }
-}
-
-/**
- * Removes an oEmbed provider.
- *
- * @since 3.5.0
- *
- * @see WP_oEmbed
- *
- * @param string $format The URL format for the oEmbed provider to remove.
- * @return bool Was the provider removed successfully?
- */
-function wp_oembed_remove_provider( $format ) {
-       require_once( ABSPATH . WPINC . '/class-oembed.php' );
-
-       if ( did_action( 'plugins_loaded' ) ) {
-               $oembed = _wp_oembed_get_object();
-
-               if ( isset( $oembed->providers[ $format ] ) ) {
-                       unset( $oembed->providers[ $format ] );
-                       return true;
-               }
-       } else {
-               WP_oEmbed::_remove_provider_early( $format );
-       }
-
-       return false;
-}
-
-/**
- * Determines if default embed handlers should be loaded.
- *
- * Checks to make sure that the embeds library hasn't already been loaded. If
- * it hasn't, then it will load the embeds library.
- *
- * @since 2.9.0
- *
- * @see wp_embed_register_handler()
- */
-function wp_maybe_load_embeds() {
-       /**
-        * Filter whether to load the default embed handlers.
-        *
-        * Returning a falsey value will prevent loading the default embed handlers.
-        *
-        * @since 2.9.0
-        *
-        * @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
-        */
-       if ( ! apply_filters( 'load_default_embeds', true ) ) {
-               return;
-       }
-
-       wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
-
-       wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
-
-       /**
-        * Filter the audio embed handler callback.
-        *
-        * @since 3.6.0
-        *
-        * @param callable $handler Audio embed handler callback function.
-        */
-       wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
-
-       /**
-        * Filter the video embed handler callback.
-        *
-        * @since 3.6.0
-        *
-        * @param callable $handler Video embed handler callback function.
-        */
-       wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
-}
-
-/**
- * The Google Video embed handler callback.
- *
- * Google Video does not support oEmbed.
- *
- * @see WP_Embed::register_handler()
- * @see WP_Embed::shortcode()
- *
- * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array  $attr    Embed attributes.
- * @param string $url     The original URL that was matched by the regex.
- * @param array  $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
-       // If the user supplied a fixed width AND height, use it
-       if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
-               $width  = (int) $rawattr['width'];
-               $height = (int) $rawattr['height'];
-       } else {
-               list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
-       }
-
-       /**
-        * Filter the Google Video embed output.
-        *
-        * @since 2.9.0
-        *
-        * @param string $html    Google Video HTML embed markup.
-        * @param array  $matches The RegEx matches from the provided regex.
-        * @param array  $attr    An array of embed attributes.
-        * @param string $url     The original URL that was matched by the regex.
-        * @param array  $rawattr The original unmodified attributes.
-        */
-       return apply_filters( 'embed_googlevideo', '<embed type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docid=' . esc_attr($matches[2]) . '&amp;hl=en&amp;fs=true" style="width:' . esc_attr($width) . 'px;height:' . esc_attr($height) . 'px" allowFullScreen="true" allowScriptAccess="always" />', $matches, $attr, $url, $rawattr );
-}
-
-/**
- * YouTube iframe embed handler callback.
- *
- * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is.
- *
- * @since 4.0.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param array  $matches The RegEx matches from the provided regex when calling
- *                        wp_embed_register_handler().
- * @param array  $attr    Embed attributes.
- * @param string $url     The original URL that was matched by the regex.
- * @param array  $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
-       global $wp_embed;
-       $embed = $wp_embed->autoembed( "https://youtube.com/watch?v={$matches[2]}" );
-
-       /**
-        * Filter the YoutTube embed output.
-        *
-        * @since 4.0.0
-        *
-        * @see wp_embed_handler_youtube()
-        *
-        * @param string $embed   YouTube embed output.
-        * @param array  $attr    An array of embed attributes.
-        * @param string $url     The original URL that was matched by the regex.
-        * @param array  $rawattr The original unmodified attributes.
-        */
-       return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr );
-}
-
-/**
- * Audio embed handler callback.
- *
- * @since 3.6.0
- *
- * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array  $attr Embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array  $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
-       $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
-
-       /**
-        * Filter the audio embed output.
-        *
-        * @since 3.6.0
-        *
-        * @param string $audio   Audio embed output.
-        * @param array  $attr    An array of embed attributes.
-        * @param string $url     The original URL that was matched by the regex.
-        * @param array  $rawattr The original unmodified attributes.
-        */
-       return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
-}
-
-/**
- * Video embed handler callback.
- *
- * @since 3.6.0
- *
- * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array  $attr    Embed attributes.
- * @param string $url     The original URL that was matched by the regex.
- * @param array  $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
-       $dimensions = '';
-       if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
-               $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
-               $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
-       }
-       $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
-
-       /**
-        * Filter the video embed output.
-        *
-        * @since 3.6.0
-        *
-        * @param string $video   Video embed output.
-        * @param array  $attr    An array of embed attributes.
-        * @param string $url     The original URL that was matched by the regex.
-        * @param array  $rawattr The original unmodified attributes.
-        */
-       return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
-}
-
-/**
- * Registers the oEmbed REST API route.
- *
- * @since 4.4.0
- */
-function wp_oembed_register_route() {
-       $controller = new WP_oEmbed_Controller();
-       $controller->register_routes();
-}
-
-/**
- * Adds oEmbed discovery links in the website <head>.
- *
- * @since 4.4.0
- */
-function wp_oembed_add_discovery_links() {
-       $output = '';
-
-       if ( is_singular() ) {
-               $output .= '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
-
-               if ( class_exists( 'SimpleXMLElement' ) ) {
-                       $output .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
-               }
-       }
-
-       /**
-        * Filter the oEmbed discovery links HTML.
-        *
-        * @since 4.4.0
-        *
-        * @param string $output HTML of the discovery links.
-        */
-       echo apply_filters( 'oembed_discovery_links', $output );
-}
-
-/**
- * Adds the necessary JavaScript to communicate with the embedded iframes.
- *
- * @since 4.4.0
- */
-function wp_oembed_add_host_js() {
-       wp_enqueue_script( 'wp-embed' );
-}
-
-/**
- * Retrieves the URL to embed a specific post in an iframe.
- *
- * @since 4.4.0
- *
- * @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post.
- * @return string|false The post embed URL on success, false if the post doesn't exist.
- */
-function get_post_embed_url( $post = null ) {
-       $post = get_post( $post );
-
-       if ( ! $post ) {
-               return false;
-       }
-
-       if ( get_option( 'permalink_structure' ) ) {
-               $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' );
-       } else {
-               $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) );
-       }
-
-       /**
-        * Filter the URL to embed a specific post.
-        *
-        * @since 4.4.0
-        *
-        * @param string  $embed_url The post embed URL.
-        * @param WP_Post $post      The corresponding post object.
-        */
-       return esc_url_raw( apply_filters( 'post_embed_url', $embed_url, $post ) );
-}
-
-/**
- * Retrieves the oEmbed endpoint URL for a given permalink.
- *
- * Pass an empty string as the first argument to get the endpoint base URL.
- *
- * @since 4.4.0
- *
- * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty.
- * @param string $format    Optional. The requested response format. Default 'json'.
- * @return string The oEmbed endpoint URL.
- */
-function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
-       $url = rest_url( 'oembed/1.0/embed' );
-
-       if ( 'json' === $format ) {
-               $format = false;
-       }
-
-       if ( '' !== $permalink ) {
-               $url = add_query_arg( array(
-                       'url'    => urlencode( $permalink ),
-                       'format' => $format,
-               ), $url );
-       }
-
-       /**
-        * Filter the oEmbed endpoint URL.
-        *
-        * @since 4.4.0
-        *
-        * @param string $url       The URL to the oEmbed endpoint.
-        * @param string $permalink The permalink used for the `url` query arg.
-        * @param string $format    The requested response format.
-        */
-       return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format );
-}
-
-/**
- * Retrieves the embed code for a specific post.
- *
- * @since 4.4.0
- *
- * @param int         $width  The width for the response.
- * @param int         $height The height for the response.
- * @param int|WP_Post $post   Optional. Post ID or object. Default is global `$post`.
- * @return string|false Embed code on success, false if post doesn't exist.
- */
-function get_post_embed_html( $width, $height, $post = null ) {
-       $post = get_post( $post );
-
-       if ( ! $post ) {
-               return false;
-       }
-
-       $embed_url = get_post_embed_url( $post );
-
-       $output = '<blockquote class="wp-embedded-content"><a href="' . esc_url( get_permalink( $post ) ) . '">' . get_the_title( $post ) . "</a></blockquote>\n";
-
-       $output .= "<script type='text/javascript'>\n";
-       $output .= "<!--//--><![CDATA[//><!--\n";
-       if ( SCRIPT_DEBUG ) {
-               $output .= file_get_contents( ABSPATH . WPINC . '/js/wp-embed.js' );
-       } else {
-               /*
-                * If you're looking at a src version of this file, you'll see an "include"
-                * statement below. This is used by the `grunt build` process to directly
-                * include a minified version of wp-embed.js, instead of using the
-                * file_get_contents() method from above.
-                *
-                * If you're looking at a build version of this file, you'll see a string of
-                * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
-                * and edit wp-embed.js directly.
-                */
-               $output .=<<<JS
-               include "js/wp-embed.min.js"
-JS;
-       }
-       $output .= "\n//--><!]]>";
-       $output .= "\n</script>";
-
-       $output .= sprintf(
-               '<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
-               esc_url( $embed_url ),
-               absint( $width ),
-               absint( $height ),
-               esc_attr__( 'Embedded WordPress Post' )
-       );
-
-       /**
-        * Filter the embed HTML output for a given post.
-        *
-        * @since 4.4.0
-        *
-        * @param string  $output The default HTML.
-        * @param WP_Post $post   Current post object.
-        * @param int     $width  Width of the response.
-        * @param int     $height Height of the response.
-        */
-       return apply_filters( 'embed_html', $output, $post, $width, $height );
-}
-
-/**
- * Retrieves the oEmbed response data for a given post.
- *
- * @since 4.4.0
- *
- * @param WP_Post|int $post  Post object or ID.
- * @param int         $width The requested width.
- * @return array|false Response data on success, false if post doesn't exist.
- */
-function get_oembed_response_data( $post, $width ) {
-       $post = get_post( $post );
-
-       if ( ! $post ) {
-               return false;
-       }
-
-       if ( 'publish' !== get_post_status( $post ) ) {
-               return false;
-       }
-
-       /**
-        * Filter the allowed minimum and maximum widths for the oEmbed response.
-        *
-        * @since 4.4.0
-        *
-        * @param array $min_max_width {
-        *     Minimum and maximum widths for the oEmbed response.
-        *
-        *     @type int $min Minimum width. Default 200.
-        *     @type int $max Maximum width. Default 600.
-        * }
-        */
-       $min_max_width = apply_filters( 'oembed_min_max_width', array(
-               'min' => 200,
-               'max' => 600
-       ) );
-
-       $width  = min( max( $min_max_width['min'], $width ), $min_max_width['max'] );
-       $height = max( ceil( $width / 16 * 9 ), 200 );
-
-       $data = array(
-               'version'       => '1.0',
-               'provider_name' => get_bloginfo( 'name' ),
-               'provider_url'  => get_home_url(),
-               'author_name'   => get_bloginfo( 'name' ),
-               'author_url'    => get_home_url(),
-               'title'         => $post->post_title,
-               'type'          => 'link',
-       );
-
-       $author = get_userdata( $post->post_author );
-
-       if ( $author ) {
-               $data['author_name'] = $author->display_name;
-               $data['author_url']  = get_author_posts_url( $author->ID );
-       }
-
-       /**
-        * Filter the oEmbed response data.
-        *
-        * @since 4.4.0
-        *
-        * @param array   $data   The response data.
-        * @param WP_Post $post   The post object.
-        * @param int     $width  The requested width.
-        * @param int     $height The calculated height.
-        */
-       return apply_filters( 'oembed_response_data', $data, $post, $width, $height );
-}
-
-/**
- * Filters the oEmbed response data to return an iframe embed code.
- *
- * @since 4.4.0
- *
- * @param array   $data   The response data.
- * @param WP_Post $post   The post object.
- * @param int     $width  The requested width.
- * @param int     $height The calculated height.
- * @return array The modified response data.
- */
-function get_oembed_response_data_rich( $data, $post, $width, $height ) {
-       $data['width']  = absint( $width );
-       $data['height'] = absint( $height );
-       $data['type']   = 'rich';
-       $data['html']   = get_post_embed_html( $width, $height, $post );
-
-       // Add post thumbnail to response if available.
-       $thumbnail_id = false;
-
-       if ( has_post_thumbnail( $post->ID ) ) {
-               $thumbnail_id = get_post_thumbnail_id( $post->ID );
-       }
-
-       if ( 'attachment' === get_post_type( $post ) ) {
-               if ( wp_attachment_is_image( $post ) ) {
-                       $thumbnail_id = $post->ID;
-               } else if ( wp_attachment_is( 'video', $post ) ) {
-                       $thumbnail_id = get_post_thumbnail_id( $post );
-                       $data['type'] = 'video';
-               }
-       }
-
-       if ( $thumbnail_id ) {
-               list( $thumbnail_url, $thumbnail_width, $thumbnail_height ) = wp_get_attachment_image_src( $thumbnail_id, array( $width, 99999 ) );
-               $data['thumbnail_url']    = $thumbnail_url;
-               $data['thumbnail_width']  = $thumbnail_width;
-               $data['thumbnail_height'] = $thumbnail_height;
-       }
-
-       return $data;
-}
-
-/**
- * Ensures that the specified format is either 'json' or 'xml'.
- *
- * @since 4.4.0
- *
- * @param string $format The oEmbed response format. Accepts 'json' or 'xml'.
- * @return string The format, either 'xml' or 'json'. Default 'json'.
- */
-function wp_oembed_ensure_format( $format ) {
-       if ( ! in_array( $format, array( 'json', 'xml' ), true ) ) {
-               return 'json';
-       }
-
-       return $format;
-}
-
-/**
- * Hooks into the REST API output to print XML instead of JSON.
- *
- * This is only done for the oEmbed API endpoint,
- * which supports both formats.
- *
- * @access private
- * @since 4.4.0
- *
- * @param bool                      $served  Whether the request has already been served.
- * @param WP_HTTP_ResponseInterface $result  Result to send to the client. Usually a WP_REST_Response.
- * @param WP_REST_Request           $request Request used to generate the response.
- * @param WP_REST_Server            $server  Server instance.
- * @return true
- */
-function _oembed_rest_pre_serve_request( $served, $result, $request, $server ) {
-       $params = $request->get_params();
-
-       if ( '/oembed/1.0/embed' !== $request->get_route() || 'GET' !== $request->get_method() ) {
-               return $served;
-       }
-
-       if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) {
-               return $served;
-       }
-
-       // Embed links inside the request.
-       $data = $server->response_to_data( $result, false );
-
-       if ( ! class_exists( 'SimpleXMLElement' ) ) {
-               status_header( 501 );
-               die( get_status_header_desc( 501 ) );
-       }
-
-       $result = _oembed_create_xml( $data );
-
-       // Bail if there's no XML.
-       if ( ! $result ) {
-               status_header( 501 );
-               return get_status_header_desc( 501 );
-       }
-
-       if ( ! headers_sent() ) {
-               $server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) );
-       }
-
-       echo $result;
-
-       return true;
-}
-
-/**
- * Creates an XML string from a given array.
- *
- * @since 4.4.0
- * @access private
- *
- * @param array            $data The original oEmbed response data.
- * @param SimpleXMLElement $node Optional. XML node to append the result to recursively.
- * @return string|false XML string on success, false on error.
- */
-function _oembed_create_xml( $data, $node = null ) {
-       if ( ! is_array( $data ) || empty( $data ) ) {
-               return false;
-       }
-
-       if ( null === $node ) {
-               $node = new SimpleXMLElement( '<oembed></oembed>' );
-       }
-
-       foreach ( $data as $key => $value ) {
-               if ( is_numeric( $key ) ) {
-                       $key = 'oembed';
-               }
-
-               if ( is_array( $value ) ) {
-                       $item = $node->addChild( $key );
-                       _oembed_create_xml( $value, $item );
-               } else {
-                       $node->addChild( $key, esc_html( $value ) );
-               }
-       }
-
-       return $node->asXML();
-}
-
-/**
- * Filters the given oEmbed HTML.
- *
- * If the `$url` isn't on the trusted providers list,
- * we need to filter the HTML heavily for security.
- *
- * Only filters 'rich' and 'html' response types.
- *
- * @since 4.4.0
- *
- * @param string $result The oEmbed HTML result.
- * @param object $data   A data object result from an oEmbed provider.
- * @param string $url    The URL of the content to be embedded.
- * @return string The filtered and sanitized oEmbed result.
- */
-function wp_filter_oembed_result( $result, $data, $url ) {
-       if ( false === $result || ! in_array( $data->type, array( 'rich', 'video' ) ) ) {
-               return $result;
-       }
-
-       require_once( ABSPATH . WPINC . '/class-oembed.php' );
-       $wp_oembed = _wp_oembed_get_object();
-
-       // Don't modify the HTML for trusted providers.
-       if ( false !== $wp_oembed->get_provider( $url, array( 'discover' => false ) ) ) {
-               return $result;
-       }
-
-       $allowed_html = array(
-               'a'          => array(
-                       'href'         => true,
-               ),
-               'blockquote' => array(),
-               'iframe'     => array(
-                       'src'          => true,
-                       'width'        => true,
-                       'height'       => true,
-                       'frameborder'  => true,
-                       'marginwidth'  => true,
-                       'marginheight' => true,
-                       'scrolling'    => true,
-                       'title'        => true,
-               ),
-       );
-
-       $html = wp_kses( $result, $allowed_html );
-
-       preg_match( '|(<blockquote>.*?</blockquote>)?.*(<iframe.*?></iframe>)|ms', $html, $content );
-       // We require at least the iframe to exist.
-       if ( empty( $content[2] ) ) {
-               return false;
-       }
-       $html = $content[1] . $content[2];
-
-       if ( ! empty( $content[1] ) ) {
-               // We have a blockquote to fall back on. Hide the iframe by default.
-               $html = str_replace( '<iframe', '<iframe style="display:none;"', $html );
-               $html = str_replace( '<blockquote', '<blockquote class="wp-embedded-content"', $html );
-       }
-
-       $html = str_replace( '<iframe', '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"', $html );
-
-       preg_match( '/ src=[\'"]([^\'"]*)[\'"]/', $html, $results );
-
-       if ( ! empty( $results ) ) {
-               $secret = wp_generate_password( 10, false );
-
-               $url = esc_url( "{$results[1]}#?secret=$secret" );
-
-               $html = str_replace( $results[0], " src=\"$url\" data-secret=\"$secret\"", $html );
-               $html = str_replace( '<blockquote', "<blockquote data-secret=\"$secret\"", $html );
-       }
-
-       return $html;
-}
-
-/**
- * Filters the string in the 'more' link displayed after a trimmed excerpt.
- *
- * Replaces '[...]' (appended to automatically generated excerpts) with an
- * ellipsis and a "Continue reading" link in the embed template.
- *
- * @since 4.4.0
- *
- * @param string $more_string Default 'more' string.
- * @return string 'Continue reading' link prepended with an ellipsis.
- */
-function wp_embed_excerpt_more( $more_string ) {
-       if ( ! is_embed() ) {
-               return $more_string;
-       }
-
-       $link = sprintf( '<a href="%1$s" class="wp-embed-more" target="_top">%2$s</a>',
-               esc_url( get_permalink() ),
-               /* translators: %s: Name of current post */
-               sprintf( __( 'Continue reading %s' ), '<span class="screen-reader-text">' . get_the_title() . '</span>' )
-       );
-       return ' &hellip; ' . $link;
-}
-
-/**
- * Displays the post excerpt for the embed template.
- *
- * Intended to be used in 'The Loop'.
- *
- * @since 4.4.0
- */
-function the_excerpt_embed() {
-       $output = get_the_excerpt();
-
-       /**
-        * Filter the post excerpt for the embed template.
-        *
-        * @since 4.4.0
-        *
-        * @param string $output The current post excerpt.
-        */
-       echo apply_filters( 'the_excerpt_embed', $output );
-}
-
-/**
- * Filters the post excerpt for the embed template.
- *
- * Shows players for video and audio attachments.
- *
- * @since 4.4.0
- *
- * @param string $content The current post excerpt.
- * @return string The modified post excerpt.
- */
-function wp_embed_excerpt_attachment( $content ) {
-       if ( is_attachment() ) {
-               return prepend_attachment( '' );
-       }
-
-       return $content;
-}
-
-/**
- * Enqueue embed iframe default CSS and JS & fire do_action('enqueue_embed_scripts')
- *
- * Enqueue PNG fallback CSS for embed iframe for legacy versions of IE.
- *
- * Allows plugins to queue scripts for the embed iframe end using wp_enqueue_script().
- * Runs first in oembed_head().
- *
- * @since 4.4.0
- */
-function enqueue_embed_scripts() {
-       wp_enqueue_style( 'open-sans' );
-       wp_enqueue_style( 'wp-embed-template-ie' );
-
-       /**
-        * Fires when scripts and styles are enqueued for the embed iframe.
-        *
-        * @since 4.4.0
-        */
-       do_action( 'enqueue_embed_scripts' );
-}
-
-/**
- * Prints the CSS in the embed iframe header.
- *
- * @since 4.4.0
- */
-function print_embed_styles() {
-       ?>
-       <style type="text/css">
-       <?php
-               if ( SCRIPT_DEBUG ) {
-                       readfile( ABSPATH . WPINC . "/css/wp-embed-template.css" );
-               } else {
-                       /*
-                        * If you're looking at a src version of this file, you'll see an "include"
-                        * statement below. This is used by the `grunt build` process to directly
-                        * include a minified version of wp-oembed-embed.css, instead of using the
-                        * readfile() method from above.
-                        *
-                        * If you're looking at a build version of this file, you'll see a string of
-                        * minified CSS. If you need to debug it, please turn on SCRIPT_DEBUG
-                        * and edit wp-embed-template.css directly.
-                        */
-                       ?>
-                       include "css/wp-embed-template.min.css"
-                       <?php
-               }
-       ?>
-       </style>
-       <?php
-}
-
-/**
- * Prints the JavaScript in the embed iframe header.
- *
- * @since 4.4.0
- */
-function print_embed_scripts() {
-       ?>
-       <script type="text/javascript">
-       <?php
-               if ( SCRIPT_DEBUG ) {
-                       readfile( ABSPATH . WPINC . "/js/wp-embed-template.js" );
-               } else {
-                       /*
-                        * If you're looking at a src version of this file, you'll see an "include"
-                        * statement below. This is used by the `grunt build` process to directly
-                        * include a minified version of wp-embed-template.js, instead of using the
-                        * readfile() method from above.
-                        *
-                        * If you're looking at a build version of this file, you'll see a string of
-                        * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
-                        * and edit wp-embed-template.js directly.
-                        */
-                       ?>
-                       include "js/wp-embed-template.min.js"
-                       <?php
-               }
-       ?>
-       </script>
-       <?php
-}
-
-/**
- * Prepare the oembed HTML to be displayed in an RSS feed.
- *
- * @since 4.4.0
- * @access private
- *
- * @param string $content The content to filter.
- * @return string The filtered content.
- */
-function _oembed_filter_feed_content( $content ) {
-       return str_replace( '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" style="display:none;"', '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"', $content );
-}
-
-/**
- * Prints the necessary markup for the embed comments button.
- *
- * @since 4.4.0
- */
-function print_embed_comments_button() {
-       if ( is_404() || ! ( get_comments_number() || comments_open() ) ) {
-               return;
-       }
-       ?>
-       <div class="wp-embed-comments">
-               <a href="<?php comments_link(); ?>" target="_top">
-                       <span class="dashicons dashicons-admin-comments"></span>
-                       <?php
-                       printf(
-                               _n(
-                                       '%s <span class="screen-reader-text">Comment</span>',
-                                       '%s <span class="screen-reader-text">Comments</span>',
-                                       get_comments_number()
-                               ),
-                               number_format_i18n( get_comments_number() )
-                       );
-                       ?>
-               </a>
-       </div>
-       <?php
-}
-
-/**
- * Prints the necessary markup for the embed sharing button.
- *
- * @since 4.4.0
- */
-function print_embed_sharing_button() {
-       if ( is_404() ) {
-               return;
-       }
-       ?>
-       <div class="wp-embed-share">
-               <button type="button" class="wp-embed-share-dialog-open" aria-label="<?php esc_attr_e( 'Open sharing dialog' ); ?>">
-                       <span class="dashicons dashicons-share"></span>
-               </button>
-       </div>
-       <?php
-}
-
-/**
- * Prints the necessary markup for the embed sharing dialog.
- *
- * @since 4.4.0
- */
-function print_embed_sharing_dialog() {
-       if ( is_404() ) {
-               return;
-       }
-       ?>
-       <div class="wp-embed-share-dialog hidden" role="dialog" aria-label="<?php esc_attr_e( 'Sharing options' ); ?>">
-               <div class="wp-embed-share-dialog-content">
-                       <div class="wp-embed-share-dialog-text">
-                               <ul class="wp-embed-share-tabs" role="tablist">
-                                       <li class="wp-embed-share-tab-button wp-embed-share-tab-button-wordpress" role="presentation">
-                                               <button type="button" role="tab" aria-controls="wp-embed-share-tab-wordpress" aria-selected="true" tabindex="0"><?php esc_html_e( 'WordPress Embed' ); ?></button>
-                                       </li>
-                                       <li class="wp-embed-share-tab-button wp-embed-share-tab-button-html" role="presentation">
-                                               <button type="button" role="tab" aria-controls="wp-embed-share-tab-html" aria-selected="false" tabindex="-1"><?php esc_html_e( 'HTML Embed' ); ?></button>
-                                       </li>
-                               </ul>
-                               <div id="wp-embed-share-tab-wordpress" class="wp-embed-share-tab" role="tabpanel" aria-hidden="false">
-                                       <input type="text" value="<?php the_permalink(); ?>" class="wp-embed-share-input" aria-describedby="wp-embed-share-description-wordpress" tabindex="0" readonly/>
-
-                                       <p class="wp-embed-share-description" id="wp-embed-share-description-wordpress">
-                                               <?php _e( 'Copy and paste this URL into your WordPress site to embed' ); ?>
-                                       </p>
-                               </div>
-                               <div id="wp-embed-share-tab-html" class="wp-embed-share-tab" role="tabpanel" aria-hidden="true">
-                                       <textarea class="wp-embed-share-input" aria-describedby="wp-embed-share-description-html" tabindex="0" readonly><?php echo esc_textarea( get_post_embed_html( 600, 400 ) ); ?></textarea>
-
-                                       <p class="wp-embed-share-description" id="wp-embed-share-description-html">
-                                               <?php _e( 'Copy and paste this code into your site to embed' ); ?>
-                                       </p>
-                               </div>
-                       </div>
-
-                       <button type="button" class="wp-embed-share-dialog-close" aria-label="<?php esc_attr_e( 'Close sharing dialog' ); ?>">
-                               <span class="dashicons dashicons-no"></span>
-                       </button>
-               </div>
-       </div>
-       <?php
-}
</del></span></pre></div>
<a id="trunksrcwpincludesembedphpfromrev35712trunksrcwpincludesembedfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/embed.php (from rev 35712, trunk/src/wp-includes/embed-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/embed.php                           (rev 0)
+++ trunk/src/wp-includes/embed.php     2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,1047 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * oEmbed API: Top-level oEmbed functionality
+ *
+ * @package WordPress
+ * @subpackage oEmbed
+ * @since 4.4.0
+ */
+
+/**
+ * Registers an embed handler.
+ *
+ * Should probably only be used for sites that do not support oEmbed.
+ *
+ * @since 2.9.0
+ *
+ * @global WP_Embed $wp_embed
+ *
+ * @param string   $id       An internal ID/name for the handler. Needs to be unique.
+ * @param string   $regex    The regex that will be used to see if this handler should be used for a URL.
+ * @param callable $callback The callback function that will be called if the regex is matched.
+ * @param int      $priority Optional. Used to specify the order in which the registered handlers will
+ *                           be tested. Default 10.
+ */
+function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
+       global $wp_embed;
+       $wp_embed->register_handler( $id, $regex, $callback, $priority );
+}
+
+/**
+ * Unregisters a previously-registered embed handler.
+ *
+ * @since 2.9.0
+ *
+ * @global WP_Embed $wp_embed
+ *
+ * @param string $id       The handler ID that should be removed.
+ * @param int    $priority Optional. The priority of the handler to be removed. Default 10.
+ */
+function wp_embed_unregister_handler( $id, $priority = 10 ) {
+       global $wp_embed;
+       $wp_embed->unregister_handler( $id, $priority );
+}
+
+/**
+ * Creates default array of embed parameters.
+ *
+ * The width defaults to the content width as specified by the theme. If the
+ * theme does not specify a content width, then 500px is used.
+ *
+ * The default height is 1.5 times the width, or 1000px, whichever is smaller.
+ *
+ * The 'embed_defaults' filter can be used to adjust either of these values.
+ *
+ * @since 2.9.0
+ *
+ * @global int $content_width
+ *
+ * @param string $url Optional. The URL that should be embedded. Default empty.
+ *
+ * @return array Default embed parameters.
+ */
+function wp_embed_defaults( $url = '' ) {
+       if ( ! empty( $GLOBALS['content_width'] ) )
+               $width = (int) $GLOBALS['content_width'];
+
+       if ( empty( $width ) )
+               $width = 500;
+
+       $height = min( ceil( $width * 1.5 ), 1000 );
+
+       /**
+        * Filter the default array of embed dimensions.
+        *
+        * @since 2.9.0
+        *
+        * @param array  $size An array of embed width and height values
+        *                     in pixels (in that order).
+        * @param string $url  The URL that should be embedded.
+        */
+       return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url );
+}
+
+/**
+ * Attempts to fetch the embed HTML for a provided URL using oEmbed.
+ *
+ * @since 2.9.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string $url  The URL that should be embedded.
+ * @param array  $args Optional. Additional arguments and parameters for retrieving embed HTML.
+ *                     Default empty.
+ * @return false|string False on failure or the embed HTML on success.
+ */
+function wp_oembed_get( $url, $args = '' ) {
+       require_once( ABSPATH . WPINC . '/class-oembed.php' );
+       $oembed = _wp_oembed_get_object();
+       return $oembed->get_html( $url, $args );
+}
+
+/**
+ * Adds a URL format and oEmbed provider URL pair.
+ *
+ * @since 2.9.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string  $format   The format of URL that this provider can handle. You can use asterisks
+ *                          as wildcards.
+ * @param string  $provider The URL to the oEmbed provider.
+ * @param boolean $regex    Optional. Whether the `$format` parameter is in a RegEx format. Default false.
+ */
+function wp_oembed_add_provider( $format, $provider, $regex = false ) {
+       require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+       if ( did_action( 'plugins_loaded' ) ) {
+               $oembed = _wp_oembed_get_object();
+               $oembed->providers[$format] = array( $provider, $regex );
+       } else {
+               WP_oEmbed::_add_provider_early( $format, $provider, $regex );
+       }
+}
+
+/**
+ * Removes an oEmbed provider.
+ *
+ * @since 3.5.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string $format The URL format for the oEmbed provider to remove.
+ * @return bool Was the provider removed successfully?
+ */
+function wp_oembed_remove_provider( $format ) {
+       require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+       if ( did_action( 'plugins_loaded' ) ) {
+               $oembed = _wp_oembed_get_object();
+
+               if ( isset( $oembed->providers[ $format ] ) ) {
+                       unset( $oembed->providers[ $format ] );
+                       return true;
+               }
+       } else {
+               WP_oEmbed::_remove_provider_early( $format );
+       }
+
+       return false;
+}
+
+/**
+ * Determines if default embed handlers should be loaded.
+ *
+ * Checks to make sure that the embeds library hasn't already been loaded. If
+ * it hasn't, then it will load the embeds library.
+ *
+ * @since 2.9.0
+ *
+ * @see wp_embed_register_handler()
+ */
+function wp_maybe_load_embeds() {
+       /**
+        * Filter whether to load the default embed handlers.
+        *
+        * Returning a falsey value will prevent loading the default embed handlers.
+        *
+        * @since 2.9.0
+        *
+        * @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
+        */
+       if ( ! apply_filters( 'load_default_embeds', true ) ) {
+               return;
+       }
+
+       wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
+
+       wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
+
+       /**
+        * Filter the audio embed handler callback.
+        *
+        * @since 3.6.0
+        *
+        * @param callable $handler Audio embed handler callback function.
+        */
+       wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
+
+       /**
+        * Filter the video embed handler callback.
+        *
+        * @since 3.6.0
+        *
+        * @param callable $handler Video embed handler callback function.
+        */
+       wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
+}
+
+/**
+ * The Google Video embed handler callback.
+ *
+ * Google Video does not support oEmbed.
+ *
+ * @see WP_Embed::register_handler()
+ * @see WP_Embed::shortcode()
+ *
+ * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array  $attr    Embed attributes.
+ * @param string $url     The original URL that was matched by the regex.
+ * @param array  $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
+       // If the user supplied a fixed width AND height, use it
+       if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
+               $width  = (int) $rawattr['width'];
+               $height = (int) $rawattr['height'];
+       } else {
+               list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
+       }
+
+       /**
+        * Filter the Google Video embed output.
+        *
+        * @since 2.9.0
+        *
+        * @param string $html    Google Video HTML embed markup.
+        * @param array  $matches The RegEx matches from the provided regex.
+        * @param array  $attr    An array of embed attributes.
+        * @param string $url     The original URL that was matched by the regex.
+        * @param array  $rawattr The original unmodified attributes.
+        */
+       return apply_filters( 'embed_googlevideo', '<embed type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docid=' . esc_attr($matches[2]) . '&amp;hl=en&amp;fs=true" style="width:' . esc_attr($width) . 'px;height:' . esc_attr($height) . 'px" allowFullScreen="true" allowScriptAccess="always" />', $matches, $attr, $url, $rawattr );
+}
+
+/**
+ * YouTube iframe embed handler callback.
+ *
+ * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is.
+ *
+ * @since 4.0.0
+ *
+ * @global WP_Embed $wp_embed
+ *
+ * @param array  $matches The RegEx matches from the provided regex when calling
+ *                        wp_embed_register_handler().
+ * @param array  $attr    Embed attributes.
+ * @param string $url     The original URL that was matched by the regex.
+ * @param array  $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
+       global $wp_embed;
+       $embed = $wp_embed->autoembed( "https://youtube.com/watch?v={$matches[2]}" );
+
+       /**
+        * Filter the YoutTube embed output.
+        *
+        * @since 4.0.0
+        *
+        * @see wp_embed_handler_youtube()
+        *
+        * @param string $embed   YouTube embed output.
+        * @param array  $attr    An array of embed attributes.
+        * @param string $url     The original URL that was matched by the regex.
+        * @param array  $rawattr The original unmodified attributes.
+        */
+       return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr );
+}
+
+/**
+ * Audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array  $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array  $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
+       $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
+
+       /**
+        * Filter the audio embed output.
+        *
+        * @since 3.6.0
+        *
+        * @param string $audio   Audio embed output.
+        * @param array  $attr    An array of embed attributes.
+        * @param string $url     The original URL that was matched by the regex.
+        * @param array  $rawattr The original unmodified attributes.
+        */
+       return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
+}
+
+/**
+ * Video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array  $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array  $attr    Embed attributes.
+ * @param string $url     The original URL that was matched by the regex.
+ * @param array  $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
+       $dimensions = '';
+       if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
+               $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
+               $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
+       }
+       $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
+
+       /**
+        * Filter the video embed output.
+        *
+        * @since 3.6.0
+        *
+        * @param string $video   Video embed output.
+        * @param array  $attr    An array of embed attributes.
+        * @param string $url     The original URL that was matched by the regex.
+        * @param array  $rawattr The original unmodified attributes.
+        */
+       return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
+}
+
+/**
+ * Registers the oEmbed REST API route.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_register_route() {
+       $controller = new WP_oEmbed_Controller();
+       $controller->register_routes();
+}
+
+/**
+ * Adds oEmbed discovery links in the website <head>.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_add_discovery_links() {
+       $output = '';
+
+       if ( is_singular() ) {
+               $output .= '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
+
+               if ( class_exists( 'SimpleXMLElement' ) ) {
+                       $output .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
+               }
+       }
+
+       /**
+        * Filter the oEmbed discovery links HTML.
+        *
+        * @since 4.4.0
+        *
+        * @param string $output HTML of the discovery links.
+        */
+       echo apply_filters( 'oembed_discovery_links', $output );
+}
+
+/**
+ * Adds the necessary JavaScript to communicate with the embedded iframes.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_add_host_js() {
+       wp_enqueue_script( 'wp-embed' );
+}
+
+/**
+ * Retrieves the URL to embed a specific post in an iframe.
+ *
+ * @since 4.4.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post.
+ * @return string|false The post embed URL on success, false if the post doesn't exist.
+ */
+function get_post_embed_url( $post = null ) {
+       $post = get_post( $post );
+
+       if ( ! $post ) {
+               return false;
+       }
+
+       if ( get_option( 'permalink_structure' ) ) {
+               $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' );
+       } else {
+               $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) );
+       }
+
+       /**
+        * Filter the URL to embed a specific post.
+        *
+        * @since 4.4.0
+        *
+        * @param string  $embed_url The post embed URL.
+        * @param WP_Post $post      The corresponding post object.
+        */
+       return esc_url_raw( apply_filters( 'post_embed_url', $embed_url, $post ) );
+}
+
+/**
+ * Retrieves the oEmbed endpoint URL for a given permalink.
+ *
+ * Pass an empty string as the first argument to get the endpoint base URL.
+ *
+ * @since 4.4.0
+ *
+ * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty.
+ * @param string $format    Optional. The requested response format. Default 'json'.
+ * @return string The oEmbed endpoint URL.
+ */
+function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
+       $url = rest_url( 'oembed/1.0/embed' );
+
+       if ( 'json' === $format ) {
+               $format = false;
+       }
+
+       if ( '' !== $permalink ) {
+               $url = add_query_arg( array(
+                       'url'    => urlencode( $permalink ),
+                       'format' => $format,
+               ), $url );
+       }
+
+       /**
+        * Filter the oEmbed endpoint URL.
+        *
+        * @since 4.4.0
+        *
+        * @param string $url       The URL to the oEmbed endpoint.
+        * @param string $permalink The permalink used for the `url` query arg.
+        * @param string $format    The requested response format.
+        */
+       return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format );
+}
+
+/**
+ * Retrieves the embed code for a specific post.
+ *
+ * @since 4.4.0
+ *
+ * @param int         $width  The width for the response.
+ * @param int         $height The height for the response.
+ * @param int|WP_Post $post   Optional. Post ID or object. Default is global `$post`.
+ * @return string|false Embed code on success, false if post doesn't exist.
+ */
+function get_post_embed_html( $width, $height, $post = null ) {
+       $post = get_post( $post );
+
+       if ( ! $post ) {
+               return false;
+       }
+
+       $embed_url = get_post_embed_url( $post );
+
+       $output = '<blockquote class="wp-embedded-content"><a href="' . esc_url( get_permalink( $post ) ) . '">' . get_the_title( $post ) . "</a></blockquote>\n";
+
+       $output .= "<script type='text/javascript'>\n";
+       $output .= "<!--//--><![CDATA[//><!--\n";
+       if ( SCRIPT_DEBUG ) {
+               $output .= file_get_contents( ABSPATH . WPINC . '/js/wp-embed.js' );
+       } else {
+               /*
+                * If you're looking at a src version of this file, you'll see an "include"
+                * statement below. This is used by the `grunt build` process to directly
+                * include a minified version of wp-embed.js, instead of using the
+                * file_get_contents() method from above.
+                *
+                * If you're looking at a build version of this file, you'll see a string of
+                * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
+                * and edit wp-embed.js directly.
+                */
+               $output .=<<<JS
+               include "js/wp-embed.min.js"
+JS;
+       }
+       $output .= "\n//--><!]]>";
+       $output .= "\n</script>";
+
+       $output .= sprintf(
+               '<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
+               esc_url( $embed_url ),
+               absint( $width ),
+               absint( $height ),
+               esc_attr__( 'Embedded WordPress Post' )
+       );
+
+       /**
+        * Filter the embed HTML output for a given post.
+        *
+        * @since 4.4.0
+        *
+        * @param string  $output The default HTML.
+        * @param WP_Post $post   Current post object.
+        * @param int     $width  Width of the response.
+        * @param int     $height Height of the response.
+        */
+       return apply_filters( 'embed_html', $output, $post, $width, $height );
+}
+
+/**
+ * Retrieves the oEmbed response data for a given post.
+ *
+ * @since 4.4.0
+ *
+ * @param WP_Post|int $post  Post object or ID.
+ * @param int         $width The requested width.
+ * @return array|false Response data on success, false if post doesn't exist.
+ */
+function get_oembed_response_data( $post, $width ) {
+       $post = get_post( $post );
+
+       if ( ! $post ) {
+               return false;
+       }
+
+       if ( 'publish' !== get_post_status( $post ) ) {
+               return false;
+       }
+
+       /**
+        * Filter the allowed minimum and maximum widths for the oEmbed response.
+        *
+        * @since 4.4.0
+        *
+        * @param array $min_max_width {
+        *     Minimum and maximum widths for the oEmbed response.
+        *
+        *     @type int $min Minimum width. Default 200.
+        *     @type int $max Maximum width. Default 600.
+        * }
+        */
+       $min_max_width = apply_filters( 'oembed_min_max_width', array(
+               'min' => 200,
+               'max' => 600
+       ) );
+
+       $width  = min( max( $min_max_width['min'], $width ), $min_max_width['max'] );
+       $height = max( ceil( $width / 16 * 9 ), 200 );
+
+       $data = array(
+               'version'       => '1.0',
+               'provider_name' => get_bloginfo( 'name' ),
+               'provider_url'  => get_home_url(),
+               'author_name'   => get_bloginfo( 'name' ),
+               'author_url'    => get_home_url(),
+               'title'         => $post->post_title,
+               'type'          => 'link',
+       );
+
+       $author = get_userdata( $post->post_author );
+
+       if ( $author ) {
+               $data['author_name'] = $author->display_name;
+               $data['author_url']  = get_author_posts_url( $author->ID );
+       }
+
+       /**
+        * Filter the oEmbed response data.
+        *
+        * @since 4.4.0
+        *
+        * @param array   $data   The response data.
+        * @param WP_Post $post   The post object.
+        * @param int     $width  The requested width.
+        * @param int     $height The calculated height.
+        */
+       return apply_filters( 'oembed_response_data', $data, $post, $width, $height );
+}
+
+/**
+ * Filters the oEmbed response data to return an iframe embed code.
+ *
+ * @since 4.4.0
+ *
+ * @param array   $data   The response data.
+ * @param WP_Post $post   The post object.
+ * @param int     $width  The requested width.
+ * @param int     $height The calculated height.
+ * @return array The modified response data.
+ */
+function get_oembed_response_data_rich( $data, $post, $width, $height ) {
+       $data['width']  = absint( $width );
+       $data['height'] = absint( $height );
+       $data['type']   = 'rich';
+       $data['html']   = get_post_embed_html( $width, $height, $post );
+
+       // Add post thumbnail to response if available.
+       $thumbnail_id = false;
+
+       if ( has_post_thumbnail( $post->ID ) ) {
+               $thumbnail_id = get_post_thumbnail_id( $post->ID );
+       }
+
+       if ( 'attachment' === get_post_type( $post ) ) {
+               if ( wp_attachment_is_image( $post ) ) {
+                       $thumbnail_id = $post->ID;
+               } else if ( wp_attachment_is( 'video', $post ) ) {
+                       $thumbnail_id = get_post_thumbnail_id( $post );
+                       $data['type'] = 'video';
+               }
+       }
+
+       if ( $thumbnail_id ) {
+               list( $thumbnail_url, $thumbnail_width, $thumbnail_height ) = wp_get_attachment_image_src( $thumbnail_id, array( $width, 99999 ) );
+               $data['thumbnail_url']    = $thumbnail_url;
+               $data['thumbnail_width']  = $thumbnail_width;
+               $data['thumbnail_height'] = $thumbnail_height;
+       }
+
+       return $data;
+}
+
+/**
+ * Ensures that the specified format is either 'json' or 'xml'.
+ *
+ * @since 4.4.0
+ *
+ * @param string $format The oEmbed response format. Accepts 'json' or 'xml'.
+ * @return string The format, either 'xml' or 'json'. Default 'json'.
+ */
+function wp_oembed_ensure_format( $format ) {
+       if ( ! in_array( $format, array( 'json', 'xml' ), true ) ) {
+               return 'json';
+       }
+
+       return $format;
+}
+
+/**
+ * Hooks into the REST API output to print XML instead of JSON.
+ *
+ * This is only done for the oEmbed API endpoint,
+ * which supports both formats.
+ *
+ * @access private
+ * @since 4.4.0
+ *
+ * @param bool                      $served  Whether the request has already been served.
+ * @param WP_HTTP_ResponseInterface $result  Result to send to the client. Usually a WP_REST_Response.
+ * @param WP_REST_Request           $request Request used to generate the response.
+ * @param WP_REST_Server            $server  Server instance.
+ * @return true
+ */
+function _oembed_rest_pre_serve_request( $served, $result, $request, $server ) {
+       $params = $request->get_params();
+
+       if ( '/oembed/1.0/embed' !== $request->get_route() || 'GET' !== $request->get_method() ) {
+               return $served;
+       }
+
+       if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) {
+               return $served;
+       }
+
+       // Embed links inside the request.
+       $data = $server->response_to_data( $result, false );
+
+       if ( ! class_exists( 'SimpleXMLElement' ) ) {
+               status_header( 501 );
+               die( get_status_header_desc( 501 ) );
+       }
+
+       $result = _oembed_create_xml( $data );
+
+       // Bail if there's no XML.
+       if ( ! $result ) {
+               status_header( 501 );
+               return get_status_header_desc( 501 );
+       }
+
+       if ( ! headers_sent() ) {
+               $server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) );
+       }
+
+       echo $result;
+
+       return true;
+}
+
+/**
+ * Creates an XML string from a given array.
+ *
+ * @since 4.4.0
+ * @access private
+ *
+ * @param array            $data The original oEmbed response data.
+ * @param SimpleXMLElement $node Optional. XML node to append the result to recursively.
+ * @return string|false XML string on success, false on error.
+ */
+function _oembed_create_xml( $data, $node = null ) {
+       if ( ! is_array( $data ) || empty( $data ) ) {
+               return false;
+       }
+
+       if ( null === $node ) {
+               $node = new SimpleXMLElement( '<oembed></oembed>' );
+       }
+
+       foreach ( $data as $key => $value ) {
+               if ( is_numeric( $key ) ) {
+                       $key = 'oembed';
+               }
+
+               if ( is_array( $value ) ) {
+                       $item = $node->addChild( $key );
+                       _oembed_create_xml( $value, $item );
+               } else {
+                       $node->addChild( $key, esc_html( $value ) );
+               }
+       }
+
+       return $node->asXML();
+}
+
+/**
+ * Filters the given oEmbed HTML.
+ *
+ * If the `$url` isn't on the trusted providers list,
+ * we need to filter the HTML heavily for security.
+ *
+ * Only filters 'rich' and 'html' response types.
+ *
+ * @since 4.4.0
+ *
+ * @param string $result The oEmbed HTML result.
+ * @param object $data   A data object result from an oEmbed provider.
+ * @param string $url    The URL of the content to be embedded.
+ * @return string The filtered and sanitized oEmbed result.
+ */
+function wp_filter_oembed_result( $result, $data, $url ) {
+       if ( false === $result || ! in_array( $data->type, array( 'rich', 'video' ) ) ) {
+               return $result;
+       }
+
+       require_once( ABSPATH . WPINC . '/class-oembed.php' );
+       $wp_oembed = _wp_oembed_get_object();
+
+       // Don't modify the HTML for trusted providers.
+       if ( false !== $wp_oembed->get_provider( $url, array( 'discover' => false ) ) ) {
+               return $result;
+       }
+
+       $allowed_html = array(
+               'a'          => array(
+                       'href'         => true,
+               ),
+               'blockquote' => array(),
+               'iframe'     => array(
+                       'src'          => true,
+                       'width'        => true,
+                       'height'       => true,
+                       'frameborder'  => true,
+                       'marginwidth'  => true,
+                       'marginheight' => true,
+                       'scrolling'    => true,
+                       'title'        => true,
+               ),
+       );
+
+       $html = wp_kses( $result, $allowed_html );
+
+       preg_match( '|(<blockquote>.*?</blockquote>)?.*(<iframe.*?></iframe>)|ms', $html, $content );
+       // We require at least the iframe to exist.
+       if ( empty( $content[2] ) ) {
+               return false;
+       }
+       $html = $content[1] . $content[2];
+
+       if ( ! empty( $content[1] ) ) {
+               // We have a blockquote to fall back on. Hide the iframe by default.
+               $html = str_replace( '<iframe', '<iframe style="display:none;"', $html );
+               $html = str_replace( '<blockquote', '<blockquote class="wp-embedded-content"', $html );
+       }
+
+       $html = str_replace( '<iframe', '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"', $html );
+
+       preg_match( '/ src=[\'"]([^\'"]*)[\'"]/', $html, $results );
+
+       if ( ! empty( $results ) ) {
+               $secret = wp_generate_password( 10, false );
+
+               $url = esc_url( "{$results[1]}#?secret=$secret" );
+
+               $html = str_replace( $results[0], " src=\"$url\" data-secret=\"$secret\"", $html );
+               $html = str_replace( '<blockquote', "<blockquote data-secret=\"$secret\"", $html );
+       }
+
+       return $html;
+}
+
+/**
+ * Filters the string in the 'more' link displayed after a trimmed excerpt.
+ *
+ * Replaces '[...]' (appended to automatically generated excerpts) with an
+ * ellipsis and a "Continue reading" link in the embed template.
+ *
+ * @since 4.4.0
+ *
+ * @param string $more_string Default 'more' string.
+ * @return string 'Continue reading' link prepended with an ellipsis.
+ */
+function wp_embed_excerpt_more( $more_string ) {
+       if ( ! is_embed() ) {
+               return $more_string;
+       }
+
+       $link = sprintf( '<a href="%1$s" class="wp-embed-more" target="_top">%2$s</a>',
+               esc_url( get_permalink() ),
+               /* translators: %s: Name of current post */
+               sprintf( __( 'Continue reading %s' ), '<span class="screen-reader-text">' . get_the_title() . '</span>' )
+       );
+       return ' &hellip; ' . $link;
+}
+
+/**
+ * Displays the post excerpt for the embed template.
+ *
+ * Intended to be used in 'The Loop'.
+ *
+ * @since 4.4.0
+ */
+function the_excerpt_embed() {
+       $output = get_the_excerpt();
+
+       /**
+        * Filter the post excerpt for the embed template.
+        *
+        * @since 4.4.0
+        *
+        * @param string $output The current post excerpt.
+        */
+       echo apply_filters( 'the_excerpt_embed', $output );
+}
+
+/**
+ * Filters the post excerpt for the embed template.
+ *
+ * Shows players for video and audio attachments.
+ *
+ * @since 4.4.0
+ *
+ * @param string $content The current post excerpt.
+ * @return string The modified post excerpt.
+ */
+function wp_embed_excerpt_attachment( $content ) {
+       if ( is_attachment() ) {
+               return prepend_attachment( '' );
+       }
+
+       return $content;
+}
+
+/**
+ * Enqueue embed iframe default CSS and JS & fire do_action('enqueue_embed_scripts')
+ *
+ * Enqueue PNG fallback CSS for embed iframe for legacy versions of IE.
+ *
+ * Allows plugins to queue scripts for the embed iframe end using wp_enqueue_script().
+ * Runs first in oembed_head().
+ *
+ * @since 4.4.0
+ */
+function enqueue_embed_scripts() {
+       wp_enqueue_style( 'open-sans' );
+       wp_enqueue_style( 'wp-embed-template-ie' );
+
+       /**
+        * Fires when scripts and styles are enqueued for the embed iframe.
+        *
+        * @since 4.4.0
+        */
+       do_action( 'enqueue_embed_scripts' );
+}
+
+/**
+ * Prints the CSS in the embed iframe header.
+ *
+ * @since 4.4.0
+ */
+function print_embed_styles() {
+       ?>
+       <style type="text/css">
+       <?php
+               if ( SCRIPT_DEBUG ) {
+                       readfile( ABSPATH . WPINC . "/css/wp-embed-template.css" );
+               } else {
+                       /*
+                        * If you're looking at a src version of this file, you'll see an "include"
+                        * statement below. This is used by the `grunt build` process to directly
+                        * include a minified version of wp-oembed-embed.css, instead of using the
+                        * readfile() method from above.
+                        *
+                        * If you're looking at a build version of this file, you'll see a string of
+                        * minified CSS. If you need to debug it, please turn on SCRIPT_DEBUG
+                        * and edit wp-embed-template.css directly.
+                        */
+                       ?>
+                       include "css/wp-embed-template.min.css"
+                       <?php
+               }
+       ?>
+       </style>
+       <?php
+}
+
+/**
+ * Prints the JavaScript in the embed iframe header.
+ *
+ * @since 4.4.0
+ */
+function print_embed_scripts() {
+       ?>
+       <script type="text/javascript">
+       <?php
+               if ( SCRIPT_DEBUG ) {
+                       readfile( ABSPATH . WPINC . "/js/wp-embed-template.js" );
+               } else {
+                       /*
+                        * If you're looking at a src version of this file, you'll see an "include"
+                        * statement below. This is used by the `grunt build` process to directly
+                        * include a minified version of wp-embed-template.js, instead of using the
+                        * readfile() method from above.
+                        *
+                        * If you're looking at a build version of this file, you'll see a string of
+                        * minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
+                        * and edit wp-embed-template.js directly.
+                        */
+                       ?>
+                       include "js/wp-embed-template.min.js"
+                       <?php
+               }
+       ?>
+       </script>
+       <?php
+}
+
+/**
+ * Prepare the oembed HTML to be displayed in an RSS feed.
+ *
+ * @since 4.4.0
+ * @access private
+ *
+ * @param string $content The content to filter.
+ * @return string The filtered content.
+ */
+function _oembed_filter_feed_content( $content ) {
+       return str_replace( '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" style="display:none;"', '<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"', $content );
+}
+
+/**
+ * Prints the necessary markup for the embed comments button.
+ *
+ * @since 4.4.0
+ */
+function print_embed_comments_button() {
+       if ( is_404() || ! ( get_comments_number() || comments_open() ) ) {
+               return;
+       }
+       ?>
+       <div class="wp-embed-comments">
+               <a href="<?php comments_link(); ?>" target="_top">
+                       <span class="dashicons dashicons-admin-comments"></span>
+                       <?php
+                       printf(
+                               _n(
+                                       '%s <span class="screen-reader-text">Comment</span>',
+                                       '%s <span class="screen-reader-text">Comments</span>',
+                                       get_comments_number()
+                               ),
+                               number_format_i18n( get_comments_number() )
+                       );
+                       ?>
+               </a>
+       </div>
+       <?php
+}
+
+/**
+ * Prints the necessary markup for the embed sharing button.
+ *
+ * @since 4.4.0
+ */
+function print_embed_sharing_button() {
+       if ( is_404() ) {
+               return;
+       }
+       ?>
+       <div class="wp-embed-share">
+               <button type="button" class="wp-embed-share-dialog-open" aria-label="<?php esc_attr_e( 'Open sharing dialog' ); ?>">
+                       <span class="dashicons dashicons-share"></span>
+               </button>
+       </div>
+       <?php
+}
+
+/**
+ * Prints the necessary markup for the embed sharing dialog.
+ *
+ * @since 4.4.0
+ */
+function print_embed_sharing_dialog() {
+       if ( is_404() ) {
+               return;
+       }
+       ?>
+       <div class="wp-embed-share-dialog hidden" role="dialog" aria-label="<?php esc_attr_e( 'Sharing options' ); ?>">
+               <div class="wp-embed-share-dialog-content">
+                       <div class="wp-embed-share-dialog-text">
+                               <ul class="wp-embed-share-tabs" role="tablist">
+                                       <li class="wp-embed-share-tab-button wp-embed-share-tab-button-wordpress" role="presentation">
+                                               <button type="button" role="tab" aria-controls="wp-embed-share-tab-wordpress" aria-selected="true" tabindex="0"><?php esc_html_e( 'WordPress Embed' ); ?></button>
+                                       </li>
+                                       <li class="wp-embed-share-tab-button wp-embed-share-tab-button-html" role="presentation">
+                                               <button type="button" role="tab" aria-controls="wp-embed-share-tab-html" aria-selected="false" tabindex="-1"><?php esc_html_e( 'HTML Embed' ); ?></button>
+                                       </li>
+                               </ul>
+                               <div id="wp-embed-share-tab-wordpress" class="wp-embed-share-tab" role="tabpanel" aria-hidden="false">
+                                       <input type="text" value="<?php the_permalink(); ?>" class="wp-embed-share-input" aria-describedby="wp-embed-share-description-wordpress" tabindex="0" readonly/>
+
+                                       <p class="wp-embed-share-description" id="wp-embed-share-description-wordpress">
+                                               <?php _e( 'Copy and paste this URL into your WordPress site to embed' ); ?>
+                                       </p>
+                               </div>
+                               <div id="wp-embed-share-tab-html" class="wp-embed-share-tab" role="tabpanel" aria-hidden="true">
+                                       <textarea class="wp-embed-share-input" aria-describedby="wp-embed-share-description-html" tabindex="0" readonly><?php echo esc_textarea( get_post_embed_html( 600, 400 ) ); ?></textarea>
+
+                                       <p class="wp-embed-share-description" id="wp-embed-share-description-html">
+                                               <?php _e( 'Copy and paste this code into your site to embed' ); ?>
+                                       </p>
+                               </div>
+                       </div>
+
+                       <button type="button" class="wp-embed-share-dialog-close" aria-label="<?php esc_attr_e( 'Close sharing dialog' ); ?>">
+                               <span class="dashicons dashicons-no"></span>
+                       </button>
+               </div>
+       </div>
+       <?php
+}
</ins></span></pre></div>
<a id="trunksrcwpincludeshttpfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/http-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/http-functions.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/http-functions.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,660 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * HTTP API: Top-level HTTP request API functionality
- *
- * @package WordPress
- * @subpackage HTTP
- * @since 4.4.0
- */
-
-/**
- * Returns the initialized WP_Http Object
- *
- * @since 2.7.0
- * @access private
- *
- * @staticvar WP_Http $http
- *
- * @return WP_Http HTTP Transport object.
- */
-function _wp_http_get_object() {
-       static $http = null;
-
-       if ( is_null( $http ) ) {
-               $http = new WP_Http();
-       }
-       return $http;
-}
-
-/**
- * Retrieve the raw response from a safe HTTP request.
- *
- * This function is ideal when the HTTP request is being made to an arbitrary
- * URL. The URL is validated to avoid redirection and request forgery attacks.
- *
- * @since 3.6.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_safe_remote_request( $url, $args = array() ) {
-       $args['reject_unsafe_urls'] = true;
-       $http = _wp_http_get_object();
-       return $http->request( $url, $args );
-}
-
-/**
- * Retrieve the raw response from a safe HTTP request using the GET method.
- *
- * This function is ideal when the HTTP request is being made to an arbitrary
- * URL. The URL is validated to avoid redirection and request forgery attacks.
- *
- * @since 3.6.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_safe_remote_get( $url, $args = array() ) {
-       $args['reject_unsafe_urls'] = true;
-       $http = _wp_http_get_object();
-       return $http->get( $url, $args );
-}
-
-/**
- * Retrieve the raw response from a safe HTTP request using the POST method.
- *
- * This function is ideal when the HTTP request is being made to an arbitrary
- * URL. The URL is validated to avoid redirection and request forgery attacks.
- *
- * @since 3.6.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_safe_remote_post( $url, $args = array() ) {
-       $args['reject_unsafe_urls'] = true;
-       $http = _wp_http_get_object();
-       return $http->post( $url, $args );
-}
-
-/**
- * Retrieve the raw response from a safe HTTP request using the HEAD method.
- *
- * This function is ideal when the HTTP request is being made to an arbitrary
- * URL. The URL is validated to avoid redirection and request forgery attacks.
- *
- * @since 3.6.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url Site URL to retrieve.
- * @param array $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_safe_remote_head( $url, $args = array() ) {
-       $args['reject_unsafe_urls'] = true;
-       $http = _wp_http_get_object();
-       return $http->head( $url, $args );
-}
-
-/**
- * Retrieve the raw response from the HTTP request.
- *
- * The array structure is a little complex:
- *
- *     $res = array(
- *         'headers'  => array(),
- *         'response' => array(
- *             'code'    => int,
- *             'message' => string
- *         )
- *     );
- *
- * All of the headers in $res['headers'] are with the name as the key and the
- * value as the value. So to get the User-Agent, you would do the following.
- *
- *     $user_agent = $res['headers']['user-agent'];
- *
- * The body is the raw response content and can be retrieved from $res['body'].
- *
- * This function is called first to make the request and there are other API
- * functions to abstract out the above convoluted setup.
- *
- * Request method defaults for helper functions:
- *  - Default 'GET'  for wp_remote_get()
- *  - Default 'POST' for wp_remote_post()
- *  - Default 'HEAD' for wp_remote_head()
- *
- * @since 2.7.0
- *
- * @see WP_Http::request() For additional information on default arguments.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_remote_request($url, $args = array()) {
-       $http = _wp_http_get_object();
-       return $http->request( $url, $args );
-}
-
-/**
- * Retrieve the raw response from the HTTP request using the GET method.
- *
- * @since 2.7.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_remote_get($url, $args = array()) {
-       $http = _wp_http_get_object();
-       return $http->get( $url, $args );
-}
-
-/**
- * Retrieve the raw response from the HTTP request using the POST method.
- *
- * @since 2.7.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_remote_post($url, $args = array()) {
-       $http = _wp_http_get_object();
-       return $http->post( $url, $args );
-}
-
-/**
- * Retrieve the raw response from the HTTP request using the HEAD method.
- *
- * @since 2.7.0
- *
- * @see wp_remote_request() For more information on the response array format.
- * @see WP_Http::request() For default arguments information.
- *
- * @param string $url  Site URL to retrieve.
- * @param array  $args Optional. Request arguments. Default empty array.
- * @return WP_Error|array The response or WP_Error on failure.
- */
-function wp_remote_head($url, $args = array()) {
-       $http = _wp_http_get_object();
-       return $http->head( $url, $args );
-}
-
-/**
- * Retrieve only the headers from the raw response.
- *
- * @since 2.7.0
- *
- * @param array $response HTTP response.
- * @return array The headers of the response. Empty array if incorrect parameter given.
- */
-function wp_remote_retrieve_headers( $response ) {
-       if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
-               return array();
-
-       return $response['headers'];
-}
-
-/**
- * Retrieve a single header by name from the raw response.
- *
- * @since 2.7.0
- *
- * @param array  $response
- * @param string $header Header name to retrieve value from.
- * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
- */
-function wp_remote_retrieve_header( $response, $header ) {
-       if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
-               return '';
-
-       if ( array_key_exists($header, $response['headers']) )
-               return $response['headers'][$header];
-
-       return '';
-}
-
-/**
- * Retrieve only the response code from the raw response.
- *
- * Will return an empty array if incorrect parameter value is given.
- *
- * @since 2.7.0
- *
- * @param array $response HTTP response.
- * @return int|string The response code as an integer. Empty string on incorrect parameter given.
- */
-function wp_remote_retrieve_response_code( $response ) {
-       if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
-               return '';
-
-       return $response['response']['code'];
-}
-
-/**
- * Retrieve only the response message from the raw response.
- *
- * Will return an empty array if incorrect parameter value is given.
- *
- * @since 2.7.0
- *
- * @param array $response HTTP response.
- * @return string The response message. Empty string on incorrect parameter given.
- */
-function wp_remote_retrieve_response_message( $response ) {
-       if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
-               return '';
-
-       return $response['response']['message'];
-}
-
-/**
- * Retrieve only the body from the raw response.
- *
- * @since 2.7.0
- *
- * @param array $response HTTP response.
- * @return string The body of the response. Empty string if no body or incorrect parameter given.
- */
-function wp_remote_retrieve_body( $response ) {
-       if ( is_wp_error($response) || ! isset($response['body']) )
-               return '';
-
-       return $response['body'];
-}
-
-/**
- * Retrieve only the body from the raw response.
- *
- * @since 4.4.0
- *
- * @param array $response HTTP response.
- * @return array An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error.
- */
-function wp_remote_retrieve_cookies( $response ) {
-       if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
-               return array();
-       }
-
-       return $response['cookies'];
-}
-
-/**
- * Retrieve a single cookie by name from the raw response.
- *
- * @since 4.4.0
- *
- * @param array  $response HTTP response.
- * @param string $name     The name of the cookie to retrieve.
- * @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response.
- */
-function wp_remote_retrieve_cookie( $response, $name ) {
-       $cookies = wp_remote_retrieve_cookies( $response );
-
-       if ( empty( $cookies ) ) {
-               return '';
-       }
-
-       foreach ( $cookies as $cookie ) {
-               if ( $cookie->name === $name ) {
-                       return $cookie;
-               }
-       }
-
-       return '';
-}
-
-/**
- * Retrieve a single cookie's value by name from the raw response.
- *
- * @since 4.4.0
- *
- * @param array  $response HTTP response.
- * @param string $name     The name of the cookie to retrieve.
- * @return string The value of the cookie. Empty string if the cookie isn't present in the response.
- */
-function wp_remote_retrieve_cookie_value( $response, $name ) {
-       $cookie = wp_remote_retrieve_cookie( $response, $name );
-
-       if ( ! is_a( $cookie, 'WP_Http_Cookie' ) ) {
-               return '';
-       }
-
-       return $cookie->value;
-}
-
-/**
- * Determines if there is an HTTP Transport that can process this request.
- *
- * @since 3.2.0
- *
- * @param array  $capabilities Array of capabilities to test or a wp_remote_request() $args array.
- * @param string $url          Optional. If given, will check if the URL requires SSL and adds
- *                             that requirement to the capabilities array.
- *
- * @return bool
- */
-function wp_http_supports( $capabilities = array(), $url = null ) {
-       $http = _wp_http_get_object();
-
-       $capabilities = wp_parse_args( $capabilities );
-
-       $count = count( $capabilities );
-
-       // If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
-       if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
-               $capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
-       }
-
-       if ( $url && !isset( $capabilities['ssl'] ) ) {
-               $scheme = parse_url( $url, PHP_URL_SCHEME );
-               if ( 'https' == $scheme || 'ssl' == $scheme ) {
-                       $capabilities['ssl'] = true;
-               }
-       }
-
-       return (bool) $http->_get_first_available_transport( $capabilities );
-}
-
-/**
- * Get the HTTP Origin of the current request.
- *
- * @since 3.4.0
- *
- * @return string URL of the origin. Empty string if no origin.
- */
-function get_http_origin() {
-       $origin = '';
-       if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
-               $origin = $_SERVER[ 'HTTP_ORIGIN' ];
-
-       /**
-        * Change the origin of an HTTP request.
-        *
-        * @since 3.4.0
-        *
-        * @param string $origin The original origin for the request.
-        */
-       return apply_filters( 'http_origin', $origin );
-}
-
-/**
- * Retrieve list of allowed HTTP origins.
- *
- * @since 3.4.0
- *
- * @return array Array of origin URLs.
- */
-function get_allowed_http_origins() {
-       $admin_origin = parse_url( admin_url() );
-       $home_origin = parse_url( home_url() );
-
-       // @todo preserve port?
-       $allowed_origins = array_unique( array(
-               'http://' . $admin_origin[ 'host' ],
-               'https://' . $admin_origin[ 'host' ],
-               'http://' . $home_origin[ 'host' ],
-               'https://' . $home_origin[ 'host' ],
-       ) );
-
-       /**
-        * Change the origin types allowed for HTTP requests.
-        *
-        * @since 3.4.0
-        *
-        * @param array $allowed_origins {
-        *     Default allowed HTTP origins.
-        *     @type string Non-secure URL for admin origin.
-        *     @type string Secure URL for admin origin.
-        *     @type string Non-secure URL for home origin.
-        *     @type string Secure URL for home origin.
-        * }
-        */
-       return apply_filters( 'allowed_http_origins' , $allowed_origins );
-}
-
-/**
- * Determines if the HTTP origin is an authorized one.
- *
- * @since 3.4.0
- *
- * @param null|string $origin Origin URL. If not provided, the value of get_http_origin() is used.
- * @return string True if the origin is allowed. False otherwise.
- */
-function is_allowed_http_origin( $origin = null ) {
-       $origin_arg = $origin;
-
-       if ( null === $origin )
-               $origin = get_http_origin();
-
-       if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
-               $origin = '';
-
-       /**
-        * Change the allowed HTTP origin result.
-        *
-        * @since 3.4.0
-        *
-        * @param string $origin     Result of check for allowed origin.
-        * @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
-        */
-       return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
-}
-
-/**
- * Send Access-Control-Allow-Origin and related headers if the current request
- * is from an allowed origin.
- *
- * If the request is an OPTIONS request, the script exits with either access
- * control headers sent, or a 403 response if the origin is not allowed. For
- * other request methods, you will receive a return value.
- *
- * @since 3.4.0
- *
- * @return string|false Returns the origin URL if headers are sent. Returns false
- *                      if headers are not sent.
- */
-function send_origin_headers() {
-       $origin = get_http_origin();
-
-       if ( is_allowed_http_origin( $origin ) ) {
-               @header( 'Access-Control-Allow-Origin: ' .  $origin );
-               @header( 'Access-Control-Allow-Credentials: true' );
-               if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
-                       exit;
-               return $origin;
-       }
-
-       if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
-               status_header( 403 );
-               exit;
-       }
-
-       return false;
-}
-
-/**
- * Validate a URL for safe use in the HTTP API.
- *
- * @since 3.5.2
- *
- * @param string $url
- * @return false|string URL or false on failure.
- */
-function wp_http_validate_url( $url ) {
-       $original_url = $url;
-       $url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
-       if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) )
-               return false;
-
-       $parsed_url = @parse_url( $url );
-       if ( ! $parsed_url || empty( $parsed_url['host'] ) )
-               return false;
-
-       if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
-               return false;
-
-       if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) )
-               return false;
-
-       $parsed_home = @parse_url( get_option( 'home' ) );
-
-       $same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
-
-       if ( ! $same_host ) {
-               $host = trim( $parsed_url['host'], '.' );
-               if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
-                       $ip = $host;
-               } else {
-                       $ip = gethostbyname( $host );
-                       if ( $ip === $host ) // Error condition for gethostbyname()
-                               $ip = false;
-               }
-               if ( $ip ) {
-                       $parts = array_map( 'intval', explode( '.', $ip ) );
-                       if ( 127 === $parts[0] || 10 === $parts[0]
-                               || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
-                               || ( 192 === $parts[0] && 168 === $parts[1] )
-                       ) {
-                               // If host appears local, reject unless specifically allowed.
-                               /**
-                                * Check if HTTP request is external or not.
-                                *
-                                * Allows to change and allow external requests for the HTTP request.
-                                *
-                                * @since 3.6.0
-                                *
-                                * @param bool   false Whether HTTP request is external or not.
-                                * @param string $host IP of the requested host.
-                                * @param string $url  URL of the requested host.
-                                */
-                               if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
-                                       return false;
-                       }
-               }
-       }
-
-       if ( empty( $parsed_url['port'] ) )
-               return $url;
-
-       $port = $parsed_url['port'];
-       if ( 80 === $port || 443 === $port || 8080 === $port )
-               return $url;
-
-       if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port )
-               return $url;
-
-       return false;
-}
-
-/**
- * Whitelists allowed redirect hosts for safe HTTP requests as well.
- *
- * Attached to the http_request_host_is_external filter.
- *
- * @since 3.6.0
- *
- * @param bool   $is_external
- * @param string $host
- * @return bool
- */
-function allowed_http_request_hosts( $is_external, $host ) {
-       if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
-               $is_external = true;
-       return $is_external;
-}
-
-/**
- * Whitelists any domain in a multisite installation for safe HTTP requests.
- *
- * Attached to the http_request_host_is_external filter.
- *
- * @since 3.6.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @staticvar array $queried
- *
- * @param bool   $is_external
- * @param string $host
- * @return bool
- */
-function ms_allowed_http_request_hosts( $is_external, $host ) {
-       global $wpdb;
-       static $queried = array();
-       if ( $is_external )
-               return $is_external;
-       if ( $host === get_current_site()->domain )
-               return true;
-       if ( isset( $queried[ $host ] ) )
-               return $queried[ $host ];
-       $queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
-       return $queried[ $host ];
-}
-
-/**
- * A wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7
- *
- * PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including
- * schemeless and relative url's with :// in the path, this works around those
- * limitations providing a standard output on PHP 5.2~5.4+.
- *
- * Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated
- * when URL parsing failed.
- *
- * @since 4.4.0
- *
- * @param string $url The URL to parse.
- * @return bool|array False on failure; Array of URL components on success;
- *                    See parse_url()'s return values.
- */
-function wp_parse_url( $url ) {
-       $parts = @parse_url( $url );
-       if ( ! $parts ) {
-               // < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
-               if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
-                       // Since we know it's a relative path, prefix with a scheme/host placeholder and try again
-                       if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
-                               return $parts;
-                       }
-                       // Remove the placeholder values
-                       unset( $parts['scheme'], $parts['host'] );
-               } else {
-                       return $parts;
-               }
-       }
-
-       // < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
-       if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
-               $path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
-               $parts['host'] = $path_parts[0];
-               if ( isset( $path_parts[1] ) ) {
-                       $parts['path'] = '/' . $path_parts[1];
-               } else {
-                       unset( $parts['path'] );
-               }
-       }
-
-       return $parts;
-}
</del></span></pre></div>
<a id="trunksrcwpincludeshttpphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/http.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/http.php    2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/http.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,35 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core HTTP Request API
- *
- * Standardizes the HTTP requests for WordPress. Handles cookies, gzip encoding and decoding, chunk
- * decoding, if HTTP 1.1 and various other difficult HTTP protocol implementations.
- *
- * @package WordPress
- * @subpackage HTTP
- * @since 2.7.0
- */
-
-/** Core HTTP API functionality */
-require_once( ABSPATH . WPINC . '/http-functions.php' );
-
-/** WP_Http class */
-require_once( ABSPATH . WPINC . '/class-http.php' );
-
-/** WP_Http_Streams class */
-require_once( ABSPATH . WPINC . '/class-wp-http-streams.php' );
-
-/** WP_Http_Curl transport class */
-require_once( ABSPATH . WPINC . '/class-wp-http-curl.php' );
-
-/** WP_HTTP_Proxy transport class */
-require_once( ABSPATH . WPINC . '/class-wp-http-proxy.php' );
-
-/** WP_Http_Cookie class */
-require_once( ABSPATH . WPINC . '/class-wp-http-cookie.php' );
-
-/** WP_Http_Encoding class */
-require_once( ABSPATH . WPINC . '/class-wp-http-encoding.php' );
-
-/** WP_HTTP_Response class */
-require_once( ABSPATH . WPINC . '/class-wp-http-response.php' );
</del></span></pre></div>
<a id="trunksrcwpincludeshttpphpfromrev35712trunksrcwpincludeshttpfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/http.php (from rev 35712, trunk/src/wp-includes/http-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/http.php                            (rev 0)
+++ trunk/src/wp-includes/http.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,662 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core HTTP Request API
+ *
+ * Standardizes the HTTP requests for WordPress. Handles cookies, gzip encoding and decoding, chunk
+ * decoding, if HTTP 1.1 and various other difficult HTTP protocol implementations.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ */
+
+/**
+ * Returns the initialized WP_Http Object
+ *
+ * @since 2.7.0
+ * @access private
+ *
+ * @staticvar WP_Http $http
+ *
+ * @return WP_Http HTTP Transport object.
+ */
+function _wp_http_get_object() {
+       static $http = null;
+
+       if ( is_null( $http ) ) {
+               $http = new WP_Http();
+       }
+       return $http;
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @since 3.6.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_request( $url, $args = array() ) {
+       $args['reject_unsafe_urls'] = true;
+       $http = _wp_http_get_object();
+       return $http->request( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the GET method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @since 3.6.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_get( $url, $args = array() ) {
+       $args['reject_unsafe_urls'] = true;
+       $http = _wp_http_get_object();
+       return $http->get( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the POST method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @since 3.6.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_post( $url, $args = array() ) {
+       $args['reject_unsafe_urls'] = true;
+       $http = _wp_http_get_object();
+       return $http->post( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the HEAD method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @since 3.6.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_head( $url, $args = array() ) {
+       $args['reject_unsafe_urls'] = true;
+       $http = _wp_http_get_object();
+       return $http->head( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from the HTTP request.
+ *
+ * The array structure is a little complex:
+ *
+ *     $res = array(
+ *         'headers'  => array(),
+ *         'response' => array(
+ *             'code'    => int,
+ *             'message' => string
+ *         )
+ *     );
+ *
+ * All of the headers in $res['headers'] are with the name as the key and the
+ * value as the value. So to get the User-Agent, you would do the following.
+ *
+ *     $user_agent = $res['headers']['user-agent'];
+ *
+ * The body is the raw response content and can be retrieved from $res['body'].
+ *
+ * This function is called first to make the request and there are other API
+ * functions to abstract out the above convoluted setup.
+ *
+ * Request method defaults for helper functions:
+ *  - Default 'GET'  for wp_remote_get()
+ *  - Default 'POST' for wp_remote_post()
+ *  - Default 'HEAD' for wp_remote_head()
+ *
+ * @since 2.7.0
+ *
+ * @see WP_Http::request() For additional information on default arguments.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_request($url, $args = array()) {
+       $http = _wp_http_get_object();
+       return $http->request( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the GET method.
+ *
+ * @since 2.7.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_get($url, $args = array()) {
+       $http = _wp_http_get_object();
+       return $http->get( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the POST method.
+ *
+ * @since 2.7.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_post($url, $args = array()) {
+       $http = _wp_http_get_object();
+       return $http->post( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the HEAD method.
+ *
+ * @since 2.7.0
+ *
+ * @see wp_remote_request() For more information on the response array format.
+ * @see WP_Http::request() For default arguments information.
+ *
+ * @param string $url  Site URL to retrieve.
+ * @param array  $args Optional. Request arguments. Default empty array.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_head($url, $args = array()) {
+       $http = _wp_http_get_object();
+       return $http->head( $url, $args );
+}
+
+/**
+ * Retrieve only the headers from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return array The headers of the response. Empty array if incorrect parameter given.
+ */
+function wp_remote_retrieve_headers( $response ) {
+       if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
+               return array();
+
+       return $response['headers'];
+}
+
+/**
+ * Retrieve a single header by name from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array  $response
+ * @param string $header Header name to retrieve value from.
+ * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
+ */
+function wp_remote_retrieve_header( $response, $header ) {
+       if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
+               return '';
+
+       if ( array_key_exists($header, $response['headers']) )
+               return $response['headers'][$header];
+
+       return '';
+}
+
+/**
+ * Retrieve only the response code from the raw response.
+ *
+ * Will return an empty array if incorrect parameter value is given.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return int|string The response code as an integer. Empty string on incorrect parameter given.
+ */
+function wp_remote_retrieve_response_code( $response ) {
+       if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
+               return '';
+
+       return $response['response']['code'];
+}
+
+/**
+ * Retrieve only the response message from the raw response.
+ *
+ * Will return an empty array if incorrect parameter value is given.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return string The response message. Empty string on incorrect parameter given.
+ */
+function wp_remote_retrieve_response_message( $response ) {
+       if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
+               return '';
+
+       return $response['response']['message'];
+}
+
+/**
+ * Retrieve only the body from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return string The body of the response. Empty string if no body or incorrect parameter given.
+ */
+function wp_remote_retrieve_body( $response ) {
+       if ( is_wp_error($response) || ! isset($response['body']) )
+               return '';
+
+       return $response['body'];
+}
+
+/**
+ * Retrieve only the body from the raw response.
+ *
+ * @since 4.4.0
+ *
+ * @param array $response HTTP response.
+ * @return array An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error.
+ */
+function wp_remote_retrieve_cookies( $response ) {
+       if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
+               return array();
+       }
+
+       return $response['cookies'];
+}
+
+/**
+ * Retrieve a single cookie by name from the raw response.
+ *
+ * @since 4.4.0
+ *
+ * @param array  $response HTTP response.
+ * @param string $name     The name of the cookie to retrieve.
+ * @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response.
+ */
+function wp_remote_retrieve_cookie( $response, $name ) {
+       $cookies = wp_remote_retrieve_cookies( $response );
+
+       if ( empty( $cookies ) ) {
+               return '';
+       }
+
+       foreach ( $cookies as $cookie ) {
+               if ( $cookie->name === $name ) {
+                       return $cookie;
+               }
+       }
+
+       return '';
+}
+
+/**
+ * Retrieve a single cookie's value by name from the raw response.
+ *
+ * @since 4.4.0
+ *
+ * @param array  $response HTTP response.
+ * @param string $name     The name of the cookie to retrieve.
+ * @return string The value of the cookie. Empty string if the cookie isn't present in the response.
+ */
+function wp_remote_retrieve_cookie_value( $response, $name ) {
+       $cookie = wp_remote_retrieve_cookie( $response, $name );
+
+       if ( ! is_a( $cookie, 'WP_Http_Cookie' ) ) {
+               return '';
+       }
+
+       return $cookie->value;
+}
+
+/**
+ * Determines if there is an HTTP Transport that can process this request.
+ *
+ * @since 3.2.0
+ *
+ * @param array  $capabilities Array of capabilities to test or a wp_remote_request() $args array.
+ * @param string $url          Optional. If given, will check if the URL requires SSL and adds
+ *                             that requirement to the capabilities array.
+ *
+ * @return bool
+ */
+function wp_http_supports( $capabilities = array(), $url = null ) {
+       $http = _wp_http_get_object();
+
+       $capabilities = wp_parse_args( $capabilities );
+
+       $count = count( $capabilities );
+
+       // If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
+       if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
+               $capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
+       }
+
+       if ( $url && !isset( $capabilities['ssl'] ) ) {
+               $scheme = parse_url( $url, PHP_URL_SCHEME );
+               if ( 'https' == $scheme || 'ssl' == $scheme ) {
+                       $capabilities['ssl'] = true;
+               }
+       }
+
+       return (bool) $http->_get_first_available_transport( $capabilities );
+}
+
+/**
+ * Get the HTTP Origin of the current request.
+ *
+ * @since 3.4.0
+ *
+ * @return string URL of the origin. Empty string if no origin.
+ */
+function get_http_origin() {
+       $origin = '';
+       if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
+               $origin = $_SERVER[ 'HTTP_ORIGIN' ];
+
+       /**
+        * Change the origin of an HTTP request.
+        *
+        * @since 3.4.0
+        *
+        * @param string $origin The original origin for the request.
+        */
+       return apply_filters( 'http_origin', $origin );
+}
+
+/**
+ * Retrieve list of allowed HTTP origins.
+ *
+ * @since 3.4.0
+ *
+ * @return array Array of origin URLs.
+ */
+function get_allowed_http_origins() {
+       $admin_origin = parse_url( admin_url() );
+       $home_origin = parse_url( home_url() );
+
+       // @todo preserve port?
+       $allowed_origins = array_unique( array(
+               'http://' . $admin_origin[ 'host' ],
+               'https://' . $admin_origin[ 'host' ],
+               'http://' . $home_origin[ 'host' ],
+               'https://' . $home_origin[ 'host' ],
+       ) );
+
+       /**
+        * Change the origin types allowed for HTTP requests.
+        *
+        * @since 3.4.0
+        *
+        * @param array $allowed_origins {
+        *     Default allowed HTTP origins.
+        *     @type string Non-secure URL for admin origin.
+        *     @type string Secure URL for admin origin.
+        *     @type string Non-secure URL for home origin.
+        *     @type string Secure URL for home origin.
+        * }
+        */
+       return apply_filters( 'allowed_http_origins' , $allowed_origins );
+}
+
+/**
+ * Determines if the HTTP origin is an authorized one.
+ *
+ * @since 3.4.0
+ *
+ * @param null|string $origin Origin URL. If not provided, the value of get_http_origin() is used.
+ * @return string True if the origin is allowed. False otherwise.
+ */
+function is_allowed_http_origin( $origin = null ) {
+       $origin_arg = $origin;
+
+       if ( null === $origin )
+               $origin = get_http_origin();
+
+       if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
+               $origin = '';
+
+       /**
+        * Change the allowed HTTP origin result.
+        *
+        * @since 3.4.0
+        *
+        * @param string $origin     Result of check for allowed origin.
+        * @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
+        */
+       return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
+}
+
+/**
+ * Send Access-Control-Allow-Origin and related headers if the current request
+ * is from an allowed origin.
+ *
+ * If the request is an OPTIONS request, the script exits with either access
+ * control headers sent, or a 403 response if the origin is not allowed. For
+ * other request methods, you will receive a return value.
+ *
+ * @since 3.4.0
+ *
+ * @return string|false Returns the origin URL if headers are sent. Returns false
+ *                      if headers are not sent.
+ */
+function send_origin_headers() {
+       $origin = get_http_origin();
+
+       if ( is_allowed_http_origin( $origin ) ) {
+               @header( 'Access-Control-Allow-Origin: ' .  $origin );
+               @header( 'Access-Control-Allow-Credentials: true' );
+               if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
+                       exit;
+               return $origin;
+       }
+
+       if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
+               status_header( 403 );
+               exit;
+       }
+
+       return false;
+}
+
+/**
+ * Validate a URL for safe use in the HTTP API.
+ *
+ * @since 3.5.2
+ *
+ * @param string $url
+ * @return false|string URL or false on failure.
+ */
+function wp_http_validate_url( $url ) {
+       $original_url = $url;
+       $url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
+       if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) )
+               return false;
+
+       $parsed_url = @parse_url( $url );
+       if ( ! $parsed_url || empty( $parsed_url['host'] ) )
+               return false;
+
+       if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
+               return false;
+
+       if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) )
+               return false;
+
+       $parsed_home = @parse_url( get_option( 'home' ) );
+
+       $same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
+
+       if ( ! $same_host ) {
+               $host = trim( $parsed_url['host'], '.' );
+               if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
+                       $ip = $host;
+               } else {
+                       $ip = gethostbyname( $host );
+                       if ( $ip === $host ) // Error condition for gethostbyname()
+                               $ip = false;
+               }
+               if ( $ip ) {
+                       $parts = array_map( 'intval', explode( '.', $ip ) );
+                       if ( 127 === $parts[0] || 10 === $parts[0]
+                               || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
+                               || ( 192 === $parts[0] && 168 === $parts[1] )
+                       ) {
+                               // If host appears local, reject unless specifically allowed.
+                               /**
+                                * Check if HTTP request is external or not.
+                                *
+                                * Allows to change and allow external requests for the HTTP request.
+                                *
+                                * @since 3.6.0
+                                *
+                                * @param bool   false Whether HTTP request is external or not.
+                                * @param string $host IP of the requested host.
+                                * @param string $url  URL of the requested host.
+                                */
+                               if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
+                                       return false;
+                       }
+               }
+       }
+
+       if ( empty( $parsed_url['port'] ) )
+               return $url;
+
+       $port = $parsed_url['port'];
+       if ( 80 === $port || 443 === $port || 8080 === $port )
+               return $url;
+
+       if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port )
+               return $url;
+
+       return false;
+}
+
+/**
+ * Whitelists allowed redirect hosts for safe HTTP requests as well.
+ *
+ * Attached to the http_request_host_is_external filter.
+ *
+ * @since 3.6.0
+ *
+ * @param bool   $is_external
+ * @param string $host
+ * @return bool
+ */
+function allowed_http_request_hosts( $is_external, $host ) {
+       if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
+               $is_external = true;
+       return $is_external;
+}
+
+/**
+ * Whitelists any domain in a multisite installation for safe HTTP requests.
+ *
+ * Attached to the http_request_host_is_external filter.
+ *
+ * @since 3.6.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @staticvar array $queried
+ *
+ * @param bool   $is_external
+ * @param string $host
+ * @return bool
+ */
+function ms_allowed_http_request_hosts( $is_external, $host ) {
+       global $wpdb;
+       static $queried = array();
+       if ( $is_external )
+               return $is_external;
+       if ( $host === get_current_site()->domain )
+               return true;
+       if ( isset( $queried[ $host ] ) )
+               return $queried[ $host ];
+       $queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
+       return $queried[ $host ];
+}
+
+/**
+ * A wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7
+ *
+ * PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including
+ * schemeless and relative url's with :// in the path, this works around those
+ * limitations providing a standard output on PHP 5.2~5.4+.
+ *
+ * Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated
+ * when URL parsing failed.
+ *
+ * @since 4.4.0
+ *
+ * @param string $url The URL to parse.
+ * @return bool|array False on failure; Array of URL components on success;
+ *                    See parse_url()'s return values.
+ */
+function wp_parse_url( $url ) {
+       $parts = @parse_url( $url );
+       if ( ! $parts ) {
+               // < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
+               if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
+                       // Since we know it's a relative path, prefix with a scheme/host placeholder and try again
+                       if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
+                               return $parts;
+                       }
+                       // Remove the placeholder values
+                       unset( $parts['scheme'], $parts['host'] );
+               } else {
+                       return $parts;
+               }
+       }
+
+       // < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
+       if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
+               $path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
+               $parts['host'] = $path_parts[0];
+               if ( isset( $path_parts[1] ) ) {
+                       $parts['path'] = '/' . $path_parts[1];
+               } else {
+                       unset( $parts['path'] );
+               }
+       }
+
+       return $parts;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesmetafunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/meta-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/meta-functions.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/meta-functions.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,968 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Meta API: Top-level metadata functionality
- *
- * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
- * for an object is a represented by a simple key-value pair. Objects may contain multiple
- * metadata entries that share the same key and differ only in their value.
- *
- * @package WordPress
- * @subpackage Meta
- * @since 4.4.0
- */
-
-/**
- * Add metadata for the specified object.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $object_id  ID of the object metadata is for
- * @param string $meta_key   Metadata key
- * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
- * @param bool   $unique     Optional, default is false.
- *                           Whether the specified metadata key should be unique for the object.
- *                           If true, and the object already has a value for the specified metadata key,
- *                           no change will be made.
- * @return int|false The meta ID on success, false on failure.
- */
-function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
-       global $wpdb;
-
-       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
-               return false;
-       }
-
-       $object_id = absint( $object_id );
-       if ( ! $object_id ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $column = sanitize_key($meta_type . '_id');
-
-       // expected_slashed ($meta_key)
-       $meta_key = wp_unslash($meta_key);
-       $meta_value = wp_unslash($meta_value);
-       $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
-
-       /**
-        * Filter whether to add metadata of a specific type.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user). Returning a non-null value
-        * will effectively short-circuit the function.
-        *
-        * @since 3.1.0
-        *
-        * @param null|bool $check      Whether to allow adding metadata for the given type.
-        * @param int       $object_id  Object ID.
-        * @param string    $meta_key   Meta key.
-        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
-        * @param bool      $unique     Whether the specified meta key should be unique
-        *                              for the object. Optional. Default false.
-        */
-       $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
-       if ( null !== $check )
-               return $check;
-
-       if ( $unique && $wpdb->get_var( $wpdb->prepare(
-               "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
-               $meta_key, $object_id ) ) )
-               return false;
-
-       $_meta_value = $meta_value;
-       $meta_value = maybe_serialize( $meta_value );
-
-       /**
-        * Fires immediately before meta of a specific type is added.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user).
-        *
-        * @since 3.1.0
-        *
-        * @param int    $object_id  Object ID.
-        * @param string $meta_key   Meta key.
-        * @param mixed  $meta_value Meta value.
-        */
-       do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
-
-       $result = $wpdb->insert( $table, array(
-               $column => $object_id,
-               'meta_key' => $meta_key,
-               'meta_value' => $meta_value
-       ) );
-
-       if ( ! $result )
-               return false;
-
-       $mid = (int) $wpdb->insert_id;
-
-       wp_cache_delete($object_id, $meta_type . '_meta');
-
-       /**
-        * Fires immediately after meta of a specific type is added.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user).
-        *
-        * @since 2.9.0
-        *
-        * @param int    $mid        The meta ID after successful update.
-        * @param int    $object_id  Object ID.
-        * @param string $meta_key   Meta key.
-        * @param mixed  $meta_value Meta value.
-        */
-       do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
-
-       return $mid;
-}
-
-/**
- * Update metadata for the specified object. If no value already exists for the specified object
- * ID and metadata key, the metadata will be added.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $object_id  ID of the object metadata is for
- * @param string $meta_key   Metadata key
- * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
- * @param mixed  $prev_value Optional. If specified, only update existing metadata entries with
- *                                  the specified value. Otherwise, update all entries.
- * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
- */
-function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
-       global $wpdb;
-
-       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
-               return false;
-       }
-
-       $object_id = absint( $object_id );
-       if ( ! $object_id ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $column = sanitize_key($meta_type . '_id');
-       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
-
-       // expected_slashed ($meta_key)
-       $meta_key = wp_unslash($meta_key);
-       $passed_value = $meta_value;
-       $meta_value = wp_unslash($meta_value);
-       $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
-
-       /**
-        * Filter whether to update metadata of a specific type.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user). Returning a non-null value
-        * will effectively short-circuit the function.
-        *
-        * @since 3.1.0
-        *
-        * @param null|bool $check      Whether to allow updating metadata for the given type.
-        * @param int       $object_id  Object ID.
-        * @param string    $meta_key   Meta key.
-        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
-        * @param mixed     $prev_value Optional. If specified, only update existing
-        *                              metadata entries with the specified value.
-        *                              Otherwise, update all entries.
-        */
-       $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
-       if ( null !== $check )
-               return (bool) $check;
-
-       // Compare existing value to new value if no prev value given and the key exists only once.
-       if ( empty($prev_value) ) {
-               $old_value = get_metadata($meta_type, $object_id, $meta_key);
-               if ( count($old_value) == 1 ) {
-                       if ( $old_value[0] === $meta_value )
-                               return false;
-               }
-       }
-
-       $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
-       if ( empty( $meta_ids ) ) {
-               return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
-       }
-
-       $_meta_value = $meta_value;
-       $meta_value = maybe_serialize( $meta_value );
-
-       $data  = compact( 'meta_value' );
-       $where = array( $column => $object_id, 'meta_key' => $meta_key );
-
-       if ( !empty( $prev_value ) ) {
-               $prev_value = maybe_serialize($prev_value);
-               $where['meta_value'] = $prev_value;
-       }
-
-       foreach ( $meta_ids as $meta_id ) {
-               /**
-                * Fires immediately before updating metadata of a specific type.
-                *
-                * The dynamic portion of the hook, `$meta_type`, refers to the meta
-                * object type (comment, post, or user).
-                *
-                * @since 2.9.0
-                *
-                * @param int    $meta_id    ID of the metadata entry to update.
-                * @param int    $object_id  Object ID.
-                * @param string $meta_key   Meta key.
-                * @param mixed  $meta_value Meta value.
-                */
-               do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
-       }
-
-       if ( 'post' == $meta_type ) {
-               foreach ( $meta_ids as $meta_id ) {
-                       /**
-                        * Fires immediately before updating a post's metadata.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param int    $meta_id    ID of metadata entry to update.
-                        * @param int    $object_id  Object ID.
-                        * @param string $meta_key   Meta key.
-                        * @param mixed  $meta_value Meta value.
-                        */
-                       do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
-               }
-       }
-
-       $result = $wpdb->update( $table, $data, $where );
-       if ( ! $result )
-               return false;
-
-       wp_cache_delete($object_id, $meta_type . '_meta');
-
-       foreach ( $meta_ids as $meta_id ) {
-               /**
-                * Fires immediately after updating metadata of a specific type.
-                *
-                * The dynamic portion of the hook, `$meta_type`, refers to the meta
-                * object type (comment, post, or user).
-                *
-                * @since 2.9.0
-                *
-                * @param int    $meta_id    ID of updated metadata entry.
-                * @param int    $object_id  Object ID.
-                * @param string $meta_key   Meta key.
-                * @param mixed  $meta_value Meta value.
-                */
-               do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
-       }
-
-       if ( 'post' == $meta_type ) {
-               foreach ( $meta_ids as $meta_id ) {
-                       /**
-                        * Fires immediately after updating a post's metadata.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param int    $meta_id    ID of updated metadata entry.
-                        * @param int    $object_id  Object ID.
-                        * @param string $meta_key   Meta key.
-                        * @param mixed  $meta_value Meta value.
-                        */
-                       do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
-               }
-       }
-
-       return true;
-}
-
-/**
- * Delete metadata for the specified object.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $object_id  ID of the object metadata is for
- * @param string $meta_key   Metadata key
- * @param mixed  $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
- *                           metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
- *                           Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,
- *                           it is not possible to pass an empty string to delete those entries with an empty string
- *                           for a value.)
- * @param bool   $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
- *                           ignoring the specified object_id. Otherwise, only delete matching metadata entries for
- *                           the specified object_id.
- * @return bool True on successful delete, false on failure.
- */
-function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
-       global $wpdb;
-
-       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
-               return false;
-       }
-
-       $object_id = absint( $object_id );
-       if ( ! $object_id && ! $delete_all ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $type_column = sanitize_key($meta_type . '_id');
-       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
-       // expected_slashed ($meta_key)
-       $meta_key = wp_unslash($meta_key);
-       $meta_value = wp_unslash($meta_value);
-
-       /**
-        * Filter whether to delete metadata of a specific type.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user). Returning a non-null value
-        * will effectively short-circuit the function.
-        *
-        * @since 3.1.0
-        *
-        * @param null|bool $delete     Whether to allow metadata deletion of the given type.
-        * @param int       $object_id  Object ID.
-        * @param string    $meta_key   Meta key.
-        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
-        * @param bool      $delete_all Whether to delete the matching metadata entries
-        *                              for all objects, ignoring the specified $object_id.
-        *                              Default false.
-        */
-       $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
-       if ( null !== $check )
-               return (bool) $check;
-
-       $_meta_value = $meta_value;
-       $meta_value = maybe_serialize( $meta_value );
-
-       $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
-
-       if ( !$delete_all )
-               $query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
-
-       if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value )
-               $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );
-
-       $meta_ids = $wpdb->get_col( $query );
-       if ( !count( $meta_ids ) )
-               return false;
-
-       if ( $delete_all )
-               $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
-
-       /**
-        * Fires immediately before deleting metadata of a specific type.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user).
-        *
-        * @since 3.1.0
-        *
-        * @param array  $meta_ids   An array of metadata entry IDs to delete.
-        * @param int    $object_id  Object ID.
-        * @param string $meta_key   Meta key.
-        * @param mixed  $meta_value Meta value.
-        */
-       do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
-
-       // Old-style action.
-       if ( 'post' == $meta_type ) {
-               /**
-                * Fires immediately before deleting metadata for a post.
-                *
-                * @since 2.9.0
-                *
-                * @param array $meta_ids An array of post metadata entry IDs to delete.
-                */
-               do_action( 'delete_postmeta', $meta_ids );
-       }
-
-       $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
-
-       $count = $wpdb->query($query);
-
-       if ( !$count )
-               return false;
-
-       if ( $delete_all ) {
-               foreach ( (array) $object_ids as $o_id ) {
-                       wp_cache_delete($o_id, $meta_type . '_meta');
-               }
-       } else {
-               wp_cache_delete($object_id, $meta_type . '_meta');
-       }
-
-       /**
-        * Fires immediately after deleting metadata of a specific type.
-        *
-        * The dynamic portion of the hook name, `$meta_type`, refers to the meta
-        * object type (comment, post, or user).
-        *
-        * @since 2.9.0
-        *
-        * @param array  $meta_ids   An array of deleted metadata entry IDs.
-        * @param int    $object_id  Object ID.
-        * @param string $meta_key   Meta key.
-        * @param mixed  $meta_value Meta value.
-        */
-       do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
-
-       // Old-style action.
-       if ( 'post' == $meta_type ) {
-               /**
-                * Fires immediately after deleting metadata for a post.
-                *
-                * @since 2.9.0
-                *
-                * @param array $meta_ids An array of deleted post metadata entry IDs.
-                */
-               do_action( 'deleted_postmeta', $meta_ids );
-       }
-
-       return true;
-}
-
-/**
- * Retrieve metadata for the specified object.
- *
- * @since 2.9.0
- *
- * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $object_id ID of the object metadata is for
- * @param string $meta_key  Optional. Metadata key. If not specified, retrieve all metadata for
- *                                 the specified object.
- * @param bool   $single    Optional, default is false.
- *                          If true, return only the first value of the specified meta_key.
- *                          This parameter has no effect if meta_key is not specified.
- * @return mixed Single metadata value, or array of values
- */
-function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
-       if ( ! $meta_type || ! is_numeric( $object_id ) ) {
-               return false;
-       }
-
-       $object_id = absint( $object_id );
-       if ( ! $object_id ) {
-               return false;
-       }
-
-       /**
-        * Filter whether to retrieve metadata of a specific type.
-        *
-        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-        * object type (comment, post, or user). Returning a non-null value
-        * will effectively short-circuit the function.
-        *
-        * @since 3.1.0
-        *
-        * @param null|array|string $value     The value get_metadata() should return - a single metadata value,
-        *                                     or an array of values.
-        * @param int               $object_id Object ID.
-        * @param string            $meta_key  Meta key.
-        * @param bool              $single    Whether to return only the first value of the specified $meta_key.
-        */
-       $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
-       if ( null !== $check ) {
-               if ( $single && is_array( $check ) )
-                       return $check[0];
-               else
-                       return $check;
-       }
-
-       $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
-
-       if ( !$meta_cache ) {
-               $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
-               $meta_cache = $meta_cache[$object_id];
-       }
-
-       if ( ! $meta_key ) {
-               return $meta_cache;
-       }
-
-       if ( isset($meta_cache[$meta_key]) ) {
-               if ( $single )
-                       return maybe_unserialize( $meta_cache[$meta_key][0] );
-               else
-                       return array_map('maybe_unserialize', $meta_cache[$meta_key]);
-       }
-
-       if ($single)
-               return '';
-       else
-               return array();
-}
-
-/**
- * Determine if a meta key is set for a given object
- *
- * @since 3.3.0
- *
- * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $object_id ID of the object metadata is for
- * @param string $meta_key  Metadata key.
- * @return bool True of the key is set, false if not.
- */
-function metadata_exists( $meta_type, $object_id, $meta_key ) {
-       if ( ! $meta_type || ! is_numeric( $object_id ) ) {
-               return false;
-       }
-
-       $object_id = absint( $object_id );
-       if ( ! $object_id ) {
-               return false;
-       }
-
-       /** This filter is documented in wp-includes/meta-functions.php */
-       $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
-       if ( null !== $check )
-               return (bool) $check;
-
-       $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
-
-       if ( !$meta_cache ) {
-               $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
-               $meta_cache = $meta_cache[$object_id];
-       }
-
-       if ( isset( $meta_cache[ $meta_key ] ) )
-               return true;
-
-       return false;
-}
-
-/**
- * Get meta data by meta ID
- *
- * @since 3.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
- * @param int    $meta_id   ID for a specific meta row
- * @return object|false Meta object or false.
- */
-function get_metadata_by_mid( $meta_type, $meta_id ) {
-       global $wpdb;
-
-       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
-               return false;
-       }
-
-       $meta_id = absint( $meta_id );
-       if ( ! $meta_id ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
-
-       $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
-
-       if ( empty( $meta ) )
-               return false;
-
-       if ( isset( $meta->meta_value ) )
-               $meta->meta_value = maybe_unserialize( $meta->meta_value );
-
-       return $meta;
-}
-
-/**
- * Update meta data by meta ID
- *
- * @since 3.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
- * @param int    $meta_id    ID for a specific meta row
- * @param string $meta_value Metadata value
- * @param string $meta_key   Optional, you can provide a meta key to update it
- * @return bool True on successful update, false on failure.
- */
-function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
-       global $wpdb;
-
-       // Make sure everything is valid.
-       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
-               return false;
-       }
-
-       $meta_id = absint( $meta_id );
-       if ( ! $meta_id ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $column = sanitize_key($meta_type . '_id');
-       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
-
-       // Fetch the meta and go on if it's found.
-       if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
-               $original_key = $meta->meta_key;
-               $object_id = $meta->{$column};
-
-               // If a new meta_key (last parameter) was specified, change the meta key,
-               // otherwise use the original key in the update statement.
-               if ( false === $meta_key ) {
-                       $meta_key = $original_key;
-               } elseif ( ! is_string( $meta_key ) ) {
-                       return false;
-               }
-
-               // Sanitize the meta
-               $_meta_value = $meta_value;
-               $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
-               $meta_value = maybe_serialize( $meta_value );
-
-               // Format the data query arguments.
-               $data = array(
-                       'meta_key' => $meta_key,
-                       'meta_value' => $meta_value
-               );
-
-               // Format the where query arguments.
-               $where = array();
-               $where[$id_column] = $meta_id;
-
-               /** This action is documented in wp-includes/meta-functions.php */
-               do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
-
-               if ( 'post' == $meta_type ) {
-                       /** This action is documented in wp-includes/meta-functions.php */
-                       do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
-               }
-
-               // Run the update query, all fields in $data are %s, $where is a %d.
-               $result = $wpdb->update( $table, $data, $where, '%s', '%d' );
-               if ( ! $result )
-                       return false;
-
-               // Clear the caches.
-               wp_cache_delete($object_id, $meta_type . '_meta');
-
-               /** This action is documented in wp-includes/meta-functions.php */
-               do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
-
-               if ( 'post' == $meta_type ) {
-                       /** This action is documented in wp-includes/meta-functions.php */
-                       do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
-               }
-
-               return true;
-       }
-
-       // And if the meta was not found.
-       return false;
-}
-
-/**
- * Delete meta data by meta ID
- *
- * @since 3.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
- * @param int    $meta_id   ID for a specific meta row
- * @return bool True on successful delete, false on failure.
- */
-function delete_metadata_by_mid( $meta_type, $meta_id ) {
-       global $wpdb;
-
-       // Make sure everything is valid.
-       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
-               return false;
-       }
-
-       $meta_id = absint( $meta_id );
-       if ( ! $meta_id ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       // object and id columns
-       $column = sanitize_key($meta_type . '_id');
-       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
-
-       // Fetch the meta and go on if it's found.
-       if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
-               $object_id = $meta->{$column};
-
-               /** This action is documented in wp-includes/meta-functions.php */
-               do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
-
-               // Old-style action.
-               if ( 'post' == $meta_type || 'comment' == $meta_type ) {
-                       /**
-                        * Fires immediately before deleting post or comment metadata of a specific type.
-                        *
-                        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-                        * object type (post or comment).
-                        *
-                        * @since 3.4.0
-                        *
-                        * @param int $meta_id ID of the metadata entry to delete.
-                        */
-                       do_action( "delete_{$meta_type}meta", $meta_id );
-               }
-
-               // Run the query, will return true if deleted, false otherwise
-               $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
-
-               // Clear the caches.
-               wp_cache_delete($object_id, $meta_type . '_meta');
-
-               /** This action is documented in wp-includes/meta-functions.php */
-               do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
-
-               // Old-style action.
-               if ( 'post' == $meta_type || 'comment' == $meta_type ) {
-                       /**
-                        * Fires immediately after deleting post or comment metadata of a specific type.
-                        *
-                        * The dynamic portion of the hook, `$meta_type`, refers to the meta
-                        * object type (post or comment).
-                        *
-                        * @since 3.4.0
-                        *
-                        * @param int $meta_ids Deleted metadata entry ID.
-                        */
-                       do_action( "deleted_{$meta_type}meta", $meta_id );
-               }
-
-               return $result;
-
-       }
-
-       // Meta id was not found.
-       return false;
-}
-
-/**
- * Update the metadata cache for the specified objects.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string    $meta_type  Type of object metadata is for (e.g., comment, post, or user)
- * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
- * @return array|false Metadata cache for the specified objects, or false on failure.
- */
-function update_meta_cache($meta_type, $object_ids) {
-       global $wpdb;
-
-       if ( ! $meta_type || ! $object_ids ) {
-               return false;
-       }
-
-       $table = _get_meta_table( $meta_type );
-       if ( ! $table ) {
-               return false;
-       }
-
-       $column = sanitize_key($meta_type . '_id');
-
-       if ( !is_array($object_ids) ) {
-               $object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
-               $object_ids = explode(',', $object_ids);
-       }
-
-       $object_ids = array_map('intval', $object_ids);
-
-       $cache_key = $meta_type . '_meta';
-       $ids = array();
-       $cache = array();
-       foreach ( $object_ids as $id ) {
-               $cached_object = wp_cache_get( $id, $cache_key );
-               if ( false === $cached_object )
-                       $ids[] = $id;
-               else
-                       $cache[$id] = $cached_object;
-       }
-
-       if ( empty( $ids ) )
-               return $cache;
-
-       // Get meta info
-       $id_list = join( ',', $ids );
-       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
-       $meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
-
-       if ( !empty($meta_list) ) {
-               foreach ( $meta_list as $metarow) {
-                       $mpid = intval($metarow[$column]);
-                       $mkey = $metarow['meta_key'];
-                       $mval = $metarow['meta_value'];
-
-                       // Force subkeys to be array type:
-                       if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
-                               $cache[$mpid] = array();
-                       if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
-                               $cache[$mpid][$mkey] = array();
-
-                       // Add a value to the current pid/key:
-                       $cache[$mpid][$mkey][] = $mval;
-               }
-       }
-
-       foreach ( $ids as $id ) {
-               if ( ! isset($cache[$id]) )
-                       $cache[$id] = array();
-               wp_cache_add( $id, $cache[$id], $cache_key );
-       }
-
-       return $cache;
-}
-
-/**
- * Given a meta query, generates SQL clauses to be appended to a main query.
- *
- * @since 3.2.0
- *
- * @see WP_Meta_Query
- *
- * @param array $meta_query         A meta query.
- * @param string $type              Type of meta.
- * @param string $primary_table     Primary database table name.
- * @param string $primary_id_column Primary ID column name.
- * @param object $context           Optional. The main query object
- * @return array Associative array of `JOIN` and `WHERE` SQL.
- */
-function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
-       $meta_query_obj = new WP_Meta_Query( $meta_query );
-       return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
-}
-
-/**
- * Retrieve the name of the metadata table for the specified object type.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
- * @return string|false Metadata table name, or false if no metadata table exists
- */
-function _get_meta_table($type) {
-       global $wpdb;
-
-       $table_name = $type . 'meta';
-
-       if ( empty($wpdb->$table_name) )
-               return false;
-
-       return $wpdb->$table_name;
-}
-
-/**
- * Determine whether a meta key is protected.
- *
- * @since 3.1.3
- *
- * @param string      $meta_key Meta key
- * @param string|null $meta_type
- * @return bool True if the key is protected, false otherwise.
- */
-function is_protected_meta( $meta_key, $meta_type = null ) {
-       $protected = ( '_' == $meta_key[0] );
-
-       /**
-        * Filter whether a meta key is protected.
-        *
-        * @since 3.2.0
-        *
-        * @param bool   $protected Whether the key is protected. Default false.
-        * @param string $meta_key  Meta key.
-        * @param string $meta_type Meta type.
-        */
-       return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
-}
-
-/**
- * Sanitize meta value.
- *
- * @since 3.1.3
- *
- * @param string $meta_key   Meta key
- * @param mixed  $meta_value Meta value to sanitize
- * @param string $meta_type  Type of meta
- * @return mixed Sanitized $meta_value
- */
-function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
-
-       /**
-        * Filter the sanitization of a specific meta key of a specific meta type.
-        *
-        * The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
-        * refer to the metadata object type (comment, post, or user) and the meta
-        * key value,
-        * respectively.
-        *
-        * @since 3.3.0
-        *
-        * @param mixed  $meta_value Meta value to sanitize.
-        * @param string $meta_key   Meta key.
-        * @param string $meta_type  Meta type.
-        */
-       return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
-}
-
-/**
- * Register meta key
- *
- * @since 3.3.0
- *
- * @param string       $meta_type         Type of meta
- * @param string       $meta_key          Meta key
- * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
- * @param string|array $auth_callback     Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
- */
-function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
-       if ( is_callable( $sanitize_callback ) )
-               add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
-
-       if ( empty( $auth_callback ) ) {
-               if ( is_protected_meta( $meta_key, $meta_type ) )
-                       $auth_callback = '__return_false';
-               else
-                       $auth_callback = '__return_true';
-       }
-
-       if ( is_callable( $auth_callback ) )
-               add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
-}
</del></span></pre></div>
<a id="trunksrcwpincludesmetaphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/meta.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/meta.php    2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/meta.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,18 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core Metadata API
- *
- * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
- * for an object is a represented by a simple key-value pair. Objects may contain multiple
- * metadata entries that share the same key and differ only in their value.
- *
- * @package WordPress
- * @subpackage Meta
- * @since 2.9.0
- */
-
-/** Core metdata functionality */
-require_once( ABSPATH . WPINC . '/meta-functions.php' );
-
-/** WP_Meta_Query class */
-require_once( ABSPATH . WPINC . '/class-wp-meta-query.php' );
</del></span></pre></div>
<a id="trunksrcwpincludesmetaphpfromrev35712trunksrcwpincludesmetafunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/meta.php (from rev 35712, trunk/src/wp-includes/meta-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/meta.php                            (rev 0)
+++ trunk/src/wp-includes/meta.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,967 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core Metadata API
+ *
+ * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
+ * for an object is a represented by a simple key-value pair. Objects may contain multiple
+ * metadata entries that share the same key and differ only in their value.
+ *
+ * @package WordPress
+ * @subpackage Meta
+ */
+
+/**
+ * Add metadata for the specified object.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $object_id  ID of the object metadata is for
+ * @param string $meta_key   Metadata key
+ * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
+ * @param bool   $unique     Optional, default is false.
+ *                           Whether the specified metadata key should be unique for the object.
+ *                           If true, and the object already has a value for the specified metadata key,
+ *                           no change will be made.
+ * @return int|false The meta ID on success, false on failure.
+ */
+function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
+       global $wpdb;
+
+       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
+               return false;
+       }
+
+       $object_id = absint( $object_id );
+       if ( ! $object_id ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $column = sanitize_key($meta_type . '_id');
+
+       // expected_slashed ($meta_key)
+       $meta_key = wp_unslash($meta_key);
+       $meta_value = wp_unslash($meta_value);
+       $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+
+       /**
+        * Filter whether to add metadata of a specific type.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user). Returning a non-null value
+        * will effectively short-circuit the function.
+        *
+        * @since 3.1.0
+        *
+        * @param null|bool $check      Whether to allow adding metadata for the given type.
+        * @param int       $object_id  Object ID.
+        * @param string    $meta_key   Meta key.
+        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
+        * @param bool      $unique     Whether the specified meta key should be unique
+        *                              for the object. Optional. Default false.
+        */
+       $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
+       if ( null !== $check )
+               return $check;
+
+       if ( $unique && $wpdb->get_var( $wpdb->prepare(
+               "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
+               $meta_key, $object_id ) ) )
+               return false;
+
+       $_meta_value = $meta_value;
+       $meta_value = maybe_serialize( $meta_value );
+
+       /**
+        * Fires immediately before meta of a specific type is added.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user).
+        *
+        * @since 3.1.0
+        *
+        * @param int    $object_id  Object ID.
+        * @param string $meta_key   Meta key.
+        * @param mixed  $meta_value Meta value.
+        */
+       do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
+
+       $result = $wpdb->insert( $table, array(
+               $column => $object_id,
+               'meta_key' => $meta_key,
+               'meta_value' => $meta_value
+       ) );
+
+       if ( ! $result )
+               return false;
+
+       $mid = (int) $wpdb->insert_id;
+
+       wp_cache_delete($object_id, $meta_type . '_meta');
+
+       /**
+        * Fires immediately after meta of a specific type is added.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user).
+        *
+        * @since 2.9.0
+        *
+        * @param int    $mid        The meta ID after successful update.
+        * @param int    $object_id  Object ID.
+        * @param string $meta_key   Meta key.
+        * @param mixed  $meta_value Meta value.
+        */
+       do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
+
+       return $mid;
+}
+
+/**
+ * Update metadata for the specified object. If no value already exists for the specified object
+ * ID and metadata key, the metadata will be added.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $object_id  ID of the object metadata is for
+ * @param string $meta_key   Metadata key
+ * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
+ * @param mixed  $prev_value Optional. If specified, only update existing metadata entries with
+ *                                  the specified value. Otherwise, update all entries.
+ * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
+ */
+function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
+       global $wpdb;
+
+       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
+               return false;
+       }
+
+       $object_id = absint( $object_id );
+       if ( ! $object_id ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $column = sanitize_key($meta_type . '_id');
+       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+       // expected_slashed ($meta_key)
+       $meta_key = wp_unslash($meta_key);
+       $passed_value = $meta_value;
+       $meta_value = wp_unslash($meta_value);
+       $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+
+       /**
+        * Filter whether to update metadata of a specific type.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user). Returning a non-null value
+        * will effectively short-circuit the function.
+        *
+        * @since 3.1.0
+        *
+        * @param null|bool $check      Whether to allow updating metadata for the given type.
+        * @param int       $object_id  Object ID.
+        * @param string    $meta_key   Meta key.
+        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
+        * @param mixed     $prev_value Optional. If specified, only update existing
+        *                              metadata entries with the specified value.
+        *                              Otherwise, update all entries.
+        */
+       $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
+       if ( null !== $check )
+               return (bool) $check;
+
+       // Compare existing value to new value if no prev value given and the key exists only once.
+       if ( empty($prev_value) ) {
+               $old_value = get_metadata($meta_type, $object_id, $meta_key);
+               if ( count($old_value) == 1 ) {
+                       if ( $old_value[0] === $meta_value )
+                               return false;
+               }
+       }
+
+       $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
+       if ( empty( $meta_ids ) ) {
+               return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
+       }
+
+       $_meta_value = $meta_value;
+       $meta_value = maybe_serialize( $meta_value );
+
+       $data  = compact( 'meta_value' );
+       $where = array( $column => $object_id, 'meta_key' => $meta_key );
+
+       if ( !empty( $prev_value ) ) {
+               $prev_value = maybe_serialize($prev_value);
+               $where['meta_value'] = $prev_value;
+       }
+
+       foreach ( $meta_ids as $meta_id ) {
+               /**
+                * Fires immediately before updating metadata of a specific type.
+                *
+                * The dynamic portion of the hook, `$meta_type`, refers to the meta
+                * object type (comment, post, or user).
+                *
+                * @since 2.9.0
+                *
+                * @param int    $meta_id    ID of the metadata entry to update.
+                * @param int    $object_id  Object ID.
+                * @param string $meta_key   Meta key.
+                * @param mixed  $meta_value Meta value.
+                */
+               do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+       }
+
+       if ( 'post' == $meta_type ) {
+               foreach ( $meta_ids as $meta_id ) {
+                       /**
+                        * Fires immediately before updating a post's metadata.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param int    $meta_id    ID of metadata entry to update.
+                        * @param int    $object_id  Object ID.
+                        * @param string $meta_key   Meta key.
+                        * @param mixed  $meta_value Meta value.
+                        */
+                       do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+               }
+       }
+
+       $result = $wpdb->update( $table, $data, $where );
+       if ( ! $result )
+               return false;
+
+       wp_cache_delete($object_id, $meta_type . '_meta');
+
+       foreach ( $meta_ids as $meta_id ) {
+               /**
+                * Fires immediately after updating metadata of a specific type.
+                *
+                * The dynamic portion of the hook, `$meta_type`, refers to the meta
+                * object type (comment, post, or user).
+                *
+                * @since 2.9.0
+                *
+                * @param int    $meta_id    ID of updated metadata entry.
+                * @param int    $object_id  Object ID.
+                * @param string $meta_key   Meta key.
+                * @param mixed  $meta_value Meta value.
+                */
+               do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+       }
+
+       if ( 'post' == $meta_type ) {
+               foreach ( $meta_ids as $meta_id ) {
+                       /**
+                        * Fires immediately after updating a post's metadata.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param int    $meta_id    ID of updated metadata entry.
+                        * @param int    $object_id  Object ID.
+                        * @param string $meta_key   Meta key.
+                        * @param mixed  $meta_value Meta value.
+                        */
+                       do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+               }
+       }
+
+       return true;
+}
+
+/**
+ * Delete metadata for the specified object.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $object_id  ID of the object metadata is for
+ * @param string $meta_key   Metadata key
+ * @param mixed  $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
+ *                           metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
+ *                           Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,
+ *                           it is not possible to pass an empty string to delete those entries with an empty string
+ *                           for a value.)
+ * @param bool   $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
+ *                           ignoring the specified object_id. Otherwise, only delete matching metadata entries for
+ *                           the specified object_id.
+ * @return bool True on successful delete, false on failure.
+ */
+function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
+       global $wpdb;
+
+       if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
+               return false;
+       }
+
+       $object_id = absint( $object_id );
+       if ( ! $object_id && ! $delete_all ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $type_column = sanitize_key($meta_type . '_id');
+       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+       // expected_slashed ($meta_key)
+       $meta_key = wp_unslash($meta_key);
+       $meta_value = wp_unslash($meta_value);
+
+       /**
+        * Filter whether to delete metadata of a specific type.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user). Returning a non-null value
+        * will effectively short-circuit the function.
+        *
+        * @since 3.1.0
+        *
+        * @param null|bool $delete     Whether to allow metadata deletion of the given type.
+        * @param int       $object_id  Object ID.
+        * @param string    $meta_key   Meta key.
+        * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
+        * @param bool      $delete_all Whether to delete the matching metadata entries
+        *                              for all objects, ignoring the specified $object_id.
+        *                              Default false.
+        */
+       $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
+       if ( null !== $check )
+               return (bool) $check;
+
+       $_meta_value = $meta_value;
+       $meta_value = maybe_serialize( $meta_value );
+
+       $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
+
+       if ( !$delete_all )
+               $query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
+
+       if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value )
+               $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );
+
+       $meta_ids = $wpdb->get_col( $query );
+       if ( !count( $meta_ids ) )
+               return false;
+
+       if ( $delete_all )
+               $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
+
+       /**
+        * Fires immediately before deleting metadata of a specific type.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user).
+        *
+        * @since 3.1.0
+        *
+        * @param array  $meta_ids   An array of metadata entry IDs to delete.
+        * @param int    $object_id  Object ID.
+        * @param string $meta_key   Meta key.
+        * @param mixed  $meta_value Meta value.
+        */
+       do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
+
+       // Old-style action.
+       if ( 'post' == $meta_type ) {
+               /**
+                * Fires immediately before deleting metadata for a post.
+                *
+                * @since 2.9.0
+                *
+                * @param array $meta_ids An array of post metadata entry IDs to delete.
+                */
+               do_action( 'delete_postmeta', $meta_ids );
+       }
+
+       $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
+
+       $count = $wpdb->query($query);
+
+       if ( !$count )
+               return false;
+
+       if ( $delete_all ) {
+               foreach ( (array) $object_ids as $o_id ) {
+                       wp_cache_delete($o_id, $meta_type . '_meta');
+               }
+       } else {
+               wp_cache_delete($object_id, $meta_type . '_meta');
+       }
+
+       /**
+        * Fires immediately after deleting metadata of a specific type.
+        *
+        * The dynamic portion of the hook name, `$meta_type`, refers to the meta
+        * object type (comment, post, or user).
+        *
+        * @since 2.9.0
+        *
+        * @param array  $meta_ids   An array of deleted metadata entry IDs.
+        * @param int    $object_id  Object ID.
+        * @param string $meta_key   Meta key.
+        * @param mixed  $meta_value Meta value.
+        */
+       do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
+
+       // Old-style action.
+       if ( 'post' == $meta_type ) {
+               /**
+                * Fires immediately after deleting metadata for a post.
+                *
+                * @since 2.9.0
+                *
+                * @param array $meta_ids An array of deleted post metadata entry IDs.
+                */
+               do_action( 'deleted_postmeta', $meta_ids );
+       }
+
+       return true;
+}
+
+/**
+ * Retrieve metadata for the specified object.
+ *
+ * @since 2.9.0
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $object_id ID of the object metadata is for
+ * @param string $meta_key  Optional. Metadata key. If not specified, retrieve all metadata for
+ *                                 the specified object.
+ * @param bool   $single    Optional, default is false.
+ *                          If true, return only the first value of the specified meta_key.
+ *                          This parameter has no effect if meta_key is not specified.
+ * @return mixed Single metadata value, or array of values
+ */
+function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
+       if ( ! $meta_type || ! is_numeric( $object_id ) ) {
+               return false;
+       }
+
+       $object_id = absint( $object_id );
+       if ( ! $object_id ) {
+               return false;
+       }
+
+       /**
+        * Filter whether to retrieve metadata of a specific type.
+        *
+        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+        * object type (comment, post, or user). Returning a non-null value
+        * will effectively short-circuit the function.
+        *
+        * @since 3.1.0
+        *
+        * @param null|array|string $value     The value get_metadata() should return - a single metadata value,
+        *                                     or an array of values.
+        * @param int               $object_id Object ID.
+        * @param string            $meta_key  Meta key.
+        * @param bool              $single    Whether to return only the first value of the specified $meta_key.
+        */
+       $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
+       if ( null !== $check ) {
+               if ( $single && is_array( $check ) )
+                       return $check[0];
+               else
+                       return $check;
+       }
+
+       $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
+
+       if ( !$meta_cache ) {
+               $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
+               $meta_cache = $meta_cache[$object_id];
+       }
+
+       if ( ! $meta_key ) {
+               return $meta_cache;
+       }
+
+       if ( isset($meta_cache[$meta_key]) ) {
+               if ( $single )
+                       return maybe_unserialize( $meta_cache[$meta_key][0] );
+               else
+                       return array_map('maybe_unserialize', $meta_cache[$meta_key]);
+       }
+
+       if ($single)
+               return '';
+       else
+               return array();
+}
+
+/**
+ * Determine if a meta key is set for a given object
+ *
+ * @since 3.3.0
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $object_id ID of the object metadata is for
+ * @param string $meta_key  Metadata key.
+ * @return bool True of the key is set, false if not.
+ */
+function metadata_exists( $meta_type, $object_id, $meta_key ) {
+       if ( ! $meta_type || ! is_numeric( $object_id ) ) {
+               return false;
+       }
+
+       $object_id = absint( $object_id );
+       if ( ! $object_id ) {
+               return false;
+       }
+
+       /** This filter is documented in wp-includes/meta-functions.php */
+       $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
+       if ( null !== $check )
+               return (bool) $check;
+
+       $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
+
+       if ( !$meta_cache ) {
+               $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
+               $meta_cache = $meta_cache[$object_id];
+       }
+
+       if ( isset( $meta_cache[ $meta_key ] ) )
+               return true;
+
+       return false;
+}
+
+/**
+ * Get meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
+ * @param int    $meta_id   ID for a specific meta row
+ * @return object|false Meta object or false.
+ */
+function get_metadata_by_mid( $meta_type, $meta_id ) {
+       global $wpdb;
+
+       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
+               return false;
+       }
+
+       $meta_id = absint( $meta_id );
+       if ( ! $meta_id ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
+
+       $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
+
+       if ( empty( $meta ) )
+               return false;
+
+       if ( isset( $meta->meta_value ) )
+               $meta->meta_value = maybe_unserialize( $meta->meta_value );
+
+       return $meta;
+}
+
+/**
+ * Update meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
+ * @param int    $meta_id    ID for a specific meta row
+ * @param string $meta_value Metadata value
+ * @param string $meta_key   Optional, you can provide a meta key to update it
+ * @return bool True on successful update, false on failure.
+ */
+function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
+       global $wpdb;
+
+       // Make sure everything is valid.
+       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
+               return false;
+       }
+
+       $meta_id = absint( $meta_id );
+       if ( ! $meta_id ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $column = sanitize_key($meta_type . '_id');
+       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+       // Fetch the meta and go on if it's found.
+       if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
+               $original_key = $meta->meta_key;
+               $object_id = $meta->{$column};
+
+               // If a new meta_key (last parameter) was specified, change the meta key,
+               // otherwise use the original key in the update statement.
+               if ( false === $meta_key ) {
+                       $meta_key = $original_key;
+               } elseif ( ! is_string( $meta_key ) ) {
+                       return false;
+               }
+
+               // Sanitize the meta
+               $_meta_value = $meta_value;
+               $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+               $meta_value = maybe_serialize( $meta_value );
+
+               // Format the data query arguments.
+               $data = array(
+                       'meta_key' => $meta_key,
+                       'meta_value' => $meta_value
+               );
+
+               // Format the where query arguments.
+               $where = array();
+               $where[$id_column] = $meta_id;
+
+               /** This action is documented in wp-includes/meta-functions.php */
+               do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+               if ( 'post' == $meta_type ) {
+                       /** This action is documented in wp-includes/meta-functions.php */
+                       do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+               }
+
+               // Run the update query, all fields in $data are %s, $where is a %d.
+               $result = $wpdb->update( $table, $data, $where, '%s', '%d' );
+               if ( ! $result )
+                       return false;
+
+               // Clear the caches.
+               wp_cache_delete($object_id, $meta_type . '_meta');
+
+               /** This action is documented in wp-includes/meta-functions.php */
+               do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+               if ( 'post' == $meta_type ) {
+                       /** This action is documented in wp-includes/meta-functions.php */
+                       do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+               }
+
+               return true;
+       }
+
+       // And if the meta was not found.
+       return false;
+}
+
+/**
+ * Delete meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
+ * @param int    $meta_id   ID for a specific meta row
+ * @return bool True on successful delete, false on failure.
+ */
+function delete_metadata_by_mid( $meta_type, $meta_id ) {
+       global $wpdb;
+
+       // Make sure everything is valid.
+       if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
+               return false;
+       }
+
+       $meta_id = absint( $meta_id );
+       if ( ! $meta_id ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       // object and id columns
+       $column = sanitize_key($meta_type . '_id');
+       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+       // Fetch the meta and go on if it's found.
+       if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
+               $object_id = $meta->{$column};
+
+               /** This action is documented in wp-includes/meta-functions.php */
+               do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
+
+               // Old-style action.
+               if ( 'post' == $meta_type || 'comment' == $meta_type ) {
+                       /**
+                        * Fires immediately before deleting post or comment metadata of a specific type.
+                        *
+                        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+                        * object type (post or comment).
+                        *
+                        * @since 3.4.0
+                        *
+                        * @param int $meta_id ID of the metadata entry to delete.
+                        */
+                       do_action( "delete_{$meta_type}meta", $meta_id );
+               }
+
+               // Run the query, will return true if deleted, false otherwise
+               $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
+
+               // Clear the caches.
+               wp_cache_delete($object_id, $meta_type . '_meta');
+
+               /** This action is documented in wp-includes/meta-functions.php */
+               do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
+
+               // Old-style action.
+               if ( 'post' == $meta_type || 'comment' == $meta_type ) {
+                       /**
+                        * Fires immediately after deleting post or comment metadata of a specific type.
+                        *
+                        * The dynamic portion of the hook, `$meta_type`, refers to the meta
+                        * object type (post or comment).
+                        *
+                        * @since 3.4.0
+                        *
+                        * @param int $meta_ids Deleted metadata entry ID.
+                        */
+                       do_action( "deleted_{$meta_type}meta", $meta_id );
+               }
+
+               return $result;
+
+       }
+
+       // Meta id was not found.
+       return false;
+}
+
+/**
+ * Update the metadata cache for the specified objects.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string    $meta_type  Type of object metadata is for (e.g., comment, post, or user)
+ * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
+ * @return array|false Metadata cache for the specified objects, or false on failure.
+ */
+function update_meta_cache($meta_type, $object_ids) {
+       global $wpdb;
+
+       if ( ! $meta_type || ! $object_ids ) {
+               return false;
+       }
+
+       $table = _get_meta_table( $meta_type );
+       if ( ! $table ) {
+               return false;
+       }
+
+       $column = sanitize_key($meta_type . '_id');
+
+       if ( !is_array($object_ids) ) {
+               $object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
+               $object_ids = explode(',', $object_ids);
+       }
+
+       $object_ids = array_map('intval', $object_ids);
+
+       $cache_key = $meta_type . '_meta';
+       $ids = array();
+       $cache = array();
+       foreach ( $object_ids as $id ) {
+               $cached_object = wp_cache_get( $id, $cache_key );
+               if ( false === $cached_object )
+                       $ids[] = $id;
+               else
+                       $cache[$id] = $cached_object;
+       }
+
+       if ( empty( $ids ) )
+               return $cache;
+
+       // Get meta info
+       $id_list = join( ',', $ids );
+       $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+       $meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
+
+       if ( !empty($meta_list) ) {
+               foreach ( $meta_list as $metarow) {
+                       $mpid = intval($metarow[$column]);
+                       $mkey = $metarow['meta_key'];
+                       $mval = $metarow['meta_value'];
+
+                       // Force subkeys to be array type:
+                       if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
+                               $cache[$mpid] = array();
+                       if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
+                               $cache[$mpid][$mkey] = array();
+
+                       // Add a value to the current pid/key:
+                       $cache[$mpid][$mkey][] = $mval;
+               }
+       }
+
+       foreach ( $ids as $id ) {
+               if ( ! isset($cache[$id]) )
+                       $cache[$id] = array();
+               wp_cache_add( $id, $cache[$id], $cache_key );
+       }
+
+       return $cache;
+}
+
+/**
+ * Given a meta query, generates SQL clauses to be appended to a main query.
+ *
+ * @since 3.2.0
+ *
+ * @see WP_Meta_Query
+ *
+ * @param array $meta_query         A meta query.
+ * @param string $type              Type of meta.
+ * @param string $primary_table     Primary database table name.
+ * @param string $primary_id_column Primary ID column name.
+ * @param object $context           Optional. The main query object
+ * @return array Associative array of `JOIN` and `WHERE` SQL.
+ */
+function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
+       $meta_query_obj = new WP_Meta_Query( $meta_query );
+       return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
+}
+
+/**
+ * Retrieve the name of the metadata table for the specified object type.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
+ * @return string|false Metadata table name, or false if no metadata table exists
+ */
+function _get_meta_table($type) {
+       global $wpdb;
+
+       $table_name = $type . 'meta';
+
+       if ( empty($wpdb->$table_name) )
+               return false;
+
+       return $wpdb->$table_name;
+}
+
+/**
+ * Determine whether a meta key is protected.
+ *
+ * @since 3.1.3
+ *
+ * @param string      $meta_key Meta key
+ * @param string|null $meta_type
+ * @return bool True if the key is protected, false otherwise.
+ */
+function is_protected_meta( $meta_key, $meta_type = null ) {
+       $protected = ( '_' == $meta_key[0] );
+
+       /**
+        * Filter whether a meta key is protected.
+        *
+        * @since 3.2.0
+        *
+        * @param bool   $protected Whether the key is protected. Default false.
+        * @param string $meta_key  Meta key.
+        * @param string $meta_type Meta type.
+        */
+       return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
+}
+
+/**
+ * Sanitize meta value.
+ *
+ * @since 3.1.3
+ *
+ * @param string $meta_key   Meta key
+ * @param mixed  $meta_value Meta value to sanitize
+ * @param string $meta_type  Type of meta
+ * @return mixed Sanitized $meta_value
+ */
+function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
+
+       /**
+        * Filter the sanitization of a specific meta key of a specific meta type.
+        *
+        * The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
+        * refer to the metadata object type (comment, post, or user) and the meta
+        * key value,
+        * respectively.
+        *
+        * @since 3.3.0
+        *
+        * @param mixed  $meta_value Meta value to sanitize.
+        * @param string $meta_key   Meta key.
+        * @param string $meta_type  Meta type.
+        */
+       return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
+}
+
+/**
+ * Register meta key
+ *
+ * @since 3.3.0
+ *
+ * @param string       $meta_type         Type of meta
+ * @param string       $meta_key          Meta key
+ * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
+ * @param string|array $auth_callback     Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
+ */
+function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
+       if ( is_callable( $sanitize_callback ) )
+               add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
+
+       if ( empty( $auth_callback ) ) {
+               if ( is_protected_meta( $meta_key, $meta_type ) )
+                       $auth_callback = '__return_false';
+               else
+                       $auth_callback = '__return_true';
+       }
+
+       if ( is_callable( $auth_callback ) )
+               add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
+}
</ins></span></pre></div>
<a id="trunksrcwpincludespostfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/post-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/post-functions.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/post-functions.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,5891 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Post API: Top-level post functionality
- *
- * @package WordPress
- * @subpackage Post
- * @since 4.4.0
- */
-
-//
-// Post Type Registration
-//
-
-/**
- * Creates the initial post types when 'init' action is fired.
- *
- * @since 2.9.0
- */
-function create_initial_post_types() {
-       register_post_type( 'post', array(
-               'labels' => array(
-                       'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
-               ),
-               'public'  => true,
-               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
-               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
-               'capability_type' => 'post',
-               'map_meta_cap' => true,
-               'menu_position' => 5,
-               'hierarchical' => false,
-               'rewrite' => false,
-               'query_var' => false,
-               'delete_with_user' => true,
-               'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
-       ) );
-
-       register_post_type( 'page', array(
-               'labels' => array(
-                       'name_admin_bar' => _x( 'Page', 'add new on admin bar' ),
-               ),
-               'public' => true,
-               'publicly_queryable' => false,
-               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
-               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
-               'capability_type' => 'page',
-               'map_meta_cap' => true,
-               'menu_position' => 20,
-               'hierarchical' => true,
-               'rewrite' => false,
-               'query_var' => false,
-               'delete_with_user' => true,
-               'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
-       ) );
-
-       register_post_type( 'attachment', array(
-               'labels' => array(
-                       'name' => _x('Media', 'post type general name'),
-                       'name_admin_bar' => _x( 'Media', 'add new from admin bar' ),
-                       'add_new' => _x( 'Add New', 'add new media' ),
-                       'edit_item' => __( 'Edit Media' ),
-                       'view_item' => __( 'View Attachment Page' ),
-               ),
-               'public' => true,
-               'show_ui' => true,
-               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
-               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
-               'capability_type' => 'post',
-               'capabilities' => array(
-                       'create_posts' => 'upload_files',
-               ),
-               'map_meta_cap' => true,
-               'hierarchical' => false,
-               'rewrite' => false,
-               'query_var' => false,
-               'show_in_nav_menus' => false,
-               'delete_with_user' => true,
-               'supports' => array( 'title', 'author', 'comments' ),
-       ) );
-       add_post_type_support( 'attachment:audio', 'thumbnail' );
-       add_post_type_support( 'attachment:video', 'thumbnail' );
-
-       register_post_type( 'revision', array(
-               'labels' => array(
-                       'name' => __( 'Revisions' ),
-                       'singular_name' => __( 'Revision' ),
-               ),
-               'public' => false,
-               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
-               '_edit_link' => 'revision.php?revision=%d', /* internal use only. don't use this when registering your own post type. */
-               'capability_type' => 'post',
-               'map_meta_cap' => true,
-               'hierarchical' => false,
-               'rewrite' => false,
-               'query_var' => false,
-               'can_export' => false,
-               'delete_with_user' => true,
-               'supports' => array( 'author' ),
-       ) );
-
-       register_post_type( 'nav_menu_item', array(
-               'labels' => array(
-                       'name' => __( 'Navigation Menu Items' ),
-                       'singular_name' => __( 'Navigation Menu Item' ),
-               ),
-               'public' => false,
-               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
-               'hierarchical' => false,
-               'rewrite' => false,
-               'delete_with_user' => false,
-               'query_var' => false,
-       ) );
-
-       register_post_status( 'publish', array(
-               'label'       => _x( 'Published', 'post' ),
-               'public'      => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
-       ) );
-
-       register_post_status( 'future', array(
-               'label'       => _x( 'Scheduled', 'post' ),
-               'protected'   => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
-       ) );
-
-       register_post_status( 'draft', array(
-               'label'       => _x( 'Draft', 'post' ),
-               'protected'   => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
-       ) );
-
-       register_post_status( 'pending', array(
-               'label'       => _x( 'Pending', 'post' ),
-               'protected'   => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
-       ) );
-
-       register_post_status( 'private', array(
-               'label'       => _x( 'Private', 'post' ),
-               'private'     => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
-       ) );
-
-       register_post_status( 'trash', array(
-               'label'       => _x( 'Trash', 'post' ),
-               'internal'    => true,
-               '_builtin'    => true, /* internal use only. */
-               'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
-               'show_in_admin_status_list' => true,
-       ) );
-
-       register_post_status( 'auto-draft', array(
-               'label'    => 'auto-draft',
-               'internal' => true,
-               '_builtin' => true, /* internal use only. */
-       ) );
-
-       register_post_status( 'inherit', array(
-               'label'    => 'inherit',
-               'internal' => true,
-               '_builtin' => true, /* internal use only. */
-               'exclude_from_search' => false,
-       ) );
-}
-
-/**
- * Retrieve attached file path based on attachment ID.
- *
- * By default the path will go through the 'get_attached_file' filter, but
- * passing a true to the $unfiltered argument of get_attached_file() will
- * return the file path unfiltered.
- *
- * The function works by getting the single post meta name, named
- * '_wp_attached_file' and returning it. This is a convenience function to
- * prevent looking up the meta name and provide a mechanism for sending the
- * attached filename through a filter.
- *
- * @since 2.0.0
- *
- * @param int  $attachment_id Attachment ID.
- * @param bool $unfiltered    Optional. Whether to apply filters. Default false.
- * @return string|false The file path to where the attached file should be, false otherwise.
- */
-function get_attached_file( $attachment_id, $unfiltered = false ) {
-       $file = get_post_meta( $attachment_id, '_wp_attached_file', true );
-       // If the file is relative, prepend upload dir.
-       if ( $file && 0 !== strpos($file, '/') && !preg_match('|^.:\\\|', $file) && ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) )
-               $file = $uploads['basedir'] . "/$file";
-       if ( $unfiltered )
-               return $file;
-
-       /**
-        * Filter the attached file based on the given ID.
-        *
-        * @since 2.1.0
-        *
-        * @param string $file          Path to attached file.
-        * @param int    $attachment_id Attachment ID.
-        */
-       return apply_filters( 'get_attached_file', $file, $attachment_id );
-}
-
-/**
- * Update attachment file path based on attachment ID.
- *
- * Used to update the file path of the attachment, which uses post meta name
- * '_wp_attached_file' to store the path of the attachment.
- *
- * @since 2.1.0
- *
- * @param int    $attachment_id Attachment ID.
- * @param string $file          File path for the attachment.
- * @return bool True on success, false on failure.
- */
-function update_attached_file( $attachment_id, $file ) {
-       if ( !get_post( $attachment_id ) )
-               return false;
-
-       /**
-        * Filter the path to the attached file to update.
-        *
-        * @since 2.1.0
-        *
-        * @param string $file          Path to the attached file to update.
-        * @param int    $attachment_id Attachment ID.
-        */
-       $file = apply_filters( 'update_attached_file', $file, $attachment_id );
-
-       if ( $file = _wp_relative_upload_path( $file ) )
-               return update_post_meta( $attachment_id, '_wp_attached_file', $file );
-       else
-               return delete_post_meta( $attachment_id, '_wp_attached_file' );
-}
-
-/**
- * Return relative path to an uploaded file.
- *
- * The path is relative to the current upload dir.
- *
- * @since 2.9.0
- *
- * @param string $path Full path to the file.
- * @return string Relative path on success, unchanged path on failure.
- */
-function _wp_relative_upload_path( $path ) {
-       $new_path = $path;
-
-       $uploads = wp_upload_dir();
-       if ( 0 === strpos( $new_path, $uploads['basedir'] ) ) {
-                       $new_path = str_replace( $uploads['basedir'], '', $new_path );
-                       $new_path = ltrim( $new_path, '/' );
-       }
-
-       /**
-        * Filter the relative path to an uploaded file.
-        *
-        * @since 2.9.0
-        *
-        * @param string $new_path Relative path to the file.
-        * @param string $path     Full path to the file.
-        */
-       return apply_filters( '_wp_relative_upload_path', $new_path, $path );
-}
-
-/**
- * Retrieve all children of the post parent ID.
- *
- * Normally, without any enhancements, the children would apply to pages. In the
- * context of the inner workings of WordPress, pages, posts, and attachments
- * share the same table, so therefore the functionality could apply to any one
- * of them. It is then noted that while this function does not work on posts, it
- * does not mean that it won't work on posts. It is recommended that you know
- * what context you wish to retrieve the children of.
- *
- * Attachments may also be made the child of a post, so if that is an accurate
- * statement (which needs to be verified), it would then be possible to get
- * all of the attachments for a post. Attachments have since changed since
- * version 2.5, so this is most likely inaccurate, but serves generally as an
- * example of what is possible.
- *
- * The arguments listed as defaults are for this function and also of the
- * {@link get_posts()} function. The arguments are combined with the
- * get_children defaults and are then passed to the {@link get_posts()}
- * function, which accepts additional arguments. You can replace the defaults in
- * this function, listed below and the additional arguments listed in the
- * {@link get_posts()} function.
- *
- * The 'post_parent' is the most important argument and important attention
- * needs to be paid to the $args parameter. If you pass either an object or an
- * integer (number), then just the 'post_parent' is grabbed and everything else
- * is lost. If you don't specify any arguments, then it is assumed that you are
- * in The Loop and the post parent will be grabbed for from the current post.
- *
- * The 'post_parent' argument is the ID to get the children. The 'numberposts'
- * is the amount of posts to retrieve that has a default of '-1', which is
- * used to get all of the posts. Giving a number higher than 0 will only
- * retrieve that amount of posts.
- *
- * The 'post_type' and 'post_status' arguments can be used to choose what
- * criteria of posts to retrieve. The 'post_type' can be anything, but WordPress
- * post types are 'post', 'pages', and 'attachments'. The 'post_status'
- * argument will accept any post status within the write administration panels.
- *
- * @since 2.0.0
- *
- * @see get_posts()
- * @todo Check validity of description.
- *
- * @global WP_Post $post
- *
- * @param mixed  $args   Optional. User defined arguments for replacing the defaults. Default empty.
- * @param string $output Optional. Constant for return type. Accepts OBJECT, ARRAY_A, ARRAY_N.
- *                       Default OBJECT.
- * @return array Array of children, where the type of each element is determined by $output parameter.
- *               Empty array on failure.
- */
-function get_children( $args = '', $output = OBJECT ) {
-       $kids = array();
-       if ( empty( $args ) ) {
-               if ( isset( $GLOBALS['post'] ) ) {
-                       $args = array('post_parent' => (int) $GLOBALS['post']->post_parent );
-               } else {
-                       return $kids;
-               }
-       } elseif ( is_object( $args ) ) {
-               $args = array('post_parent' => (int) $args->post_parent );
-       } elseif ( is_numeric( $args ) ) {
-               $args = array('post_parent' => (int) $args);
-       }
-
-       $defaults = array(
-               'numberposts' => -1, 'post_type' => 'any',
-               'post_status' => 'any', 'post_parent' => 0,
-       );
-
-       $r = wp_parse_args( $args, $defaults );
-
-       $children = get_posts( $r );
-
-       if ( ! $children )
-               return $kids;
-
-       if ( ! empty( $r['fields'] ) )
-               return $children;
-
-       update_post_cache($children);
-
-       foreach ( $children as $key => $child )
-               $kids[$child->ID] = $children[$key];
-
-       if ( $output == OBJECT ) {
-               return $kids;
-       } elseif ( $output == ARRAY_A ) {
-               $weeuns = array();
-               foreach ( (array) $kids as $kid ) {
-                       $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
-               }
-               return $weeuns;
-       } elseif ( $output == ARRAY_N ) {
-               $babes = array();
-               foreach ( (array) $kids as $kid ) {
-                       $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
-               }
-               return $babes;
-       } else {
-               return $kids;
-       }
-}
-
-/**
- * Get extended entry info (<!--more-->).
- *
- * There should not be any space after the second dash and before the word
- * 'more'. There can be text or space(s) after the word 'more', but won't be
- * referenced.
- *
- * The returned array has 'main', 'extended', and 'more_text' keys. Main has the text before
- * the `<!--more-->`. The 'extended' key has the content after the
- * `<!--more-->` comment. The 'more_text' key has the custom "Read More" text.
- *
- * @since 1.0.0
- *
- * @param string $post Post content.
- * @return array Post before ('main'), after ('extended'), and custom read more ('more_text').
- */
-function get_extended( $post ) {
-       //Match the new style more links.
-       if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
-               list($main, $extended) = explode($matches[0], $post, 2);
-               $more_text = $matches[1];
-       } else {
-               $main = $post;
-               $extended = '';
-               $more_text = '';
-       }
-
-       //  leading and trailing whitespace.
-       $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
-       $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
-       $more_text = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $more_text);
-
-       return array( 'main' => $main, 'extended' => $extended, 'more_text' => $more_text );
-}
-
-/**
- * Retrieves post data given a post ID or post object.
- *
- * See {@link sanitize_post()} for optional $filter values. Also, the parameter
- * $post, must be given as a variable, since it is passed by reference.
- *
- * @since 1.5.1
- *
- * @global WP_Post $post
- *
- * @param int|WP_Post|null $post   Optional. Post ID or post object. Defaults to global $post.
- * @param string           $output Optional, default is Object. Accepts OBJECT, ARRAY_A, or ARRAY_N.
- *                                 Default OBJECT.
- * @param string           $filter Optional. Type of filter to apply. Accepts 'raw', 'edit', 'db',
- *                                 or 'display'. Default 'raw'.
- * @return WP_Post|array|null Type corresponding to $output on success or null on failure.
- *                            When $output is OBJECT, a `WP_Post` instance is returned.
- */
-function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
-       if ( empty( $post ) && isset( $GLOBALS['post'] ) )
-               $post = $GLOBALS['post'];
-
-       if ( $post instanceof WP_Post ) {
-               $_post = $post;
-       } elseif ( is_object( $post ) ) {
-               if ( empty( $post->filter ) ) {
-                       $_post = sanitize_post( $post, 'raw' );
-                       $_post = new WP_Post( $_post );
-               } elseif ( 'raw' == $post->filter ) {
-                       $_post = new WP_Post( $post );
-               } else {
-                       $_post = WP_Post::get_instance( $post->ID );
-               }
-       } else {
-               $_post = WP_Post::get_instance( $post );
-       }
-
-       if ( ! $_post )
-               return null;
-
-       $_post = $_post->filter( $filter );
-
-       if ( $output == ARRAY_A )
-               return $_post->to_array();
-       elseif ( $output == ARRAY_N )
-               return array_values( $_post->to_array() );
-
-       return $_post;
-}
-
-/**
- * Retrieve ancestors of a post.
- *
- * @since 2.5.0
- *
- * @param int|WP_Post $post Post ID or post object.
- * @return array Ancestor IDs or empty array if none are found.
- */
-function get_post_ancestors( $post ) {
-       $post = get_post( $post );
-
-       if ( ! $post || empty( $post->post_parent ) || $post->post_parent == $post->ID )
-               return array();
-
-       $ancestors = array();
-
-       $id = $ancestors[] = $post->post_parent;
-
-       while ( $ancestor = get_post( $id ) ) {
-               // Loop detection: If the ancestor has been seen before, break.
-               if ( empty( $ancestor->post_parent ) || ( $ancestor->post_parent == $post->ID ) || in_array( $ancestor->post_parent, $ancestors ) )
-                       break;
-
-               $id = $ancestors[] = $ancestor->post_parent;
-       }
-
-       return $ancestors;
-}
-
-/**
- * Retrieve data from a post field based on Post ID.
- *
- * Examples of the post field will be, 'post_type', 'post_status', 'post_content',
- * etc and based off of the post object property or key names.
- *
- * The context values are based off of the taxonomy filter functions and
- * supported values are found within those functions.
- *
- * @since 2.3.0
- *
- * @see sanitize_post_field()
- *
- * @param string      $field   Post field name.
- * @param int|WP_Post $post    Post ID or post object.
- * @param string      $context Optional. How to filter the field. Accepts 'raw', 'edit', 'db',
- *                             or 'display'. Default 'display'.
- * @return string The value of the post field on success, empty string on failure.
- */
-function get_post_field( $field, $post, $context = 'display' ) {
-       $post = get_post( $post );
-
-       if ( !$post )
-               return '';
-
-       if ( !isset($post->$field) )
-               return '';
-
-       return sanitize_post_field($field, $post->$field, $post->ID, $context);
-}
-
-/**
- * Retrieve the mime type of an attachment based on the ID.
- *
- * This function can be used with any post type, but it makes more sense with
- * attachments.
- *
- * @since 2.0.0
- *
- * @param int|WP_Post $ID Optional. Post ID or post object. Default empty.
- * @return string|false The mime type on success, false on failure.
- */
-function get_post_mime_type( $ID = '' ) {
-       $post = get_post($ID);
-
-       if ( is_object($post) )
-               return $post->post_mime_type;
-
-       return false;
-}
-
-/**
- * Retrieve the post status based on the Post ID.
- *
- * If the post ID is of an attachment, then the parent post status will be given
- * instead.
- *
- * @since 2.0.0
- *
- * @param int|WP_Post $ID Optional. Post ID or post object. Default empty.
- * @return string|false Post status on success, false on failure.
- */
-function get_post_status( $ID = '' ) {
-       $post = get_post($ID);
-
-       if ( !is_object($post) )
-               return false;
-
-       if ( 'attachment' == $post->post_type ) {
-               if ( 'private' == $post->post_status )
-                       return 'private';
-
-               // Unattached attachments are assumed to be published.
-               if ( ( 'inherit' == $post->post_status ) && ( 0 == $post->post_parent) )
-                       return 'publish';
-
-               // Inherit status from the parent.
-               if ( $post->post_parent && ( $post->ID != $post->post_parent ) ) {
-                       $parent_post_status = get_post_status( $post->post_parent );
-                       if ( 'trash' == $parent_post_status ) {
-                               return get_post_meta( $post->post_parent, '_wp_trash_meta_status', true );
-                       } else {
-                               return $parent_post_status;
-                       }
-               }
-
-       }
-
-       /**
-        * Filter the post status.
-        *
-        * @since 4.4.0
-        *
-        * @param string  $post_status The post status.
-        * @param WP_Post $post        The post object.
-        */
-       return apply_filters( 'get_post_status', $post->post_status, $post );
-}
-
-/**
- * Retrieve all of the WordPress supported post statuses.
- *
- * Posts have a limited set of valid status values, this provides the
- * post_status values and descriptions.
- *
- * @since 2.5.0
- *
- * @return array List of post statuses.
- */
-function get_post_statuses() {
-       $status = array(
-               'draft'   => __( 'Draft' ),
-               'pending' => __( 'Pending Review' ),
-               'private' => __( 'Private' ),
-               'publish' => __( 'Published' )
-       );
-
-       return $status;
-}
-
-/**
- * Retrieve all of the WordPress support page statuses.
- *
- * Pages have a limited set of valid status values, this provides the
- * post_status values and descriptions.
- *
- * @since 2.5.0
- *
- * @return array List of page statuses.
- */
-function get_page_statuses() {
-       $status = array(
-               'draft'   => __( 'Draft' ),
-               'private' => __( 'Private' ),
-               'publish' => __( 'Published' )
-       );
-
-       return $status;
-}
-
-/**
- * Register a post status. Do not use before init.
- *
- * A simple function for creating or modifying a post status based on the
- * parameters given. The function will accept an array (second optional
- * parameter), along with a string for the post status name.
- *
- * Arguments prefixed with an _underscore shouldn't be used by plugins and themes.
- *
- * @since 3.0.0
- * @global array $wp_post_statuses Inserts new post status object into the list
- *
- * @param string $post_status Name of the post status.
- * @param array|string $args {
- *     Optional. Array or string of post status arguments.
- *
- *     @type bool|string $label                     A descriptive name for the post status marked
- *                                                  for translation. Defaults to value of $post_status.
- *     @type bool|array  $label_count               Descriptive text to use for nooped plurals.
- *                                                  Default array of $label, twice
- *     @type bool        $exclude_from_search       Whether to exclude posts with this post status
- *                                                  from search results. Default is value of $internal.
- *     @type bool        $_builtin                  Whether the status is built-in. Core-use only.
- *                                                  Default false.
- *     @type bool        $public                    Whether posts of this status should be shown
- *                                                  in the front end of the site. Default false.
- *     @type bool        $internal                  Whether the status is for internal use only.
- *                                                  Default false.
- *     @type bool        $protected                 Whether posts with this status should be protected.
- *                                                  Default false.
- *     @type bool        $private                   Whether posts with this status should be private.
- *                                                  Default false.
- *     @type bool        $publicly_queryable        Whether posts with this status should be publicly-
- *                                                  queryable. Default is value of $public.
- *     @type bool        $show_in_admin_all_list    Whether to include posts in the edit listing for
- *                                                  their post type. Default is value of $internal.
- *     @type bool        $show_in_admin_status_list Show in the list of statuses with post counts at
- *                                                  the top of the edit listings,
- *                                                  e.g. All (12) | Published (9) | My Custom Status (2)
- *                                                  Default is value of $internal.
- * }
- * @return object
- */
-function register_post_status( $post_status, $args = array() ) {
-       global $wp_post_statuses;
-
-       if (!is_array($wp_post_statuses))
-               $wp_post_statuses = array();
-
-       // Args prefixed with an underscore are reserved for internal use.
-       $defaults = array(
-               'label' => false,
-               'label_count' => false,
-               'exclude_from_search' => null,
-               '_builtin' => false,
-               'public' => null,
-               'internal' => null,
-               'protected' => null,
-               'private' => null,
-               'publicly_queryable' => null,
-               'show_in_admin_status_list' => null,
-               'show_in_admin_all_list' => null,
-       );
-       $args = wp_parse_args($args, $defaults);
-       $args = (object) $args;
-
-       $post_status = sanitize_key($post_status);
-       $args->name = $post_status;
-
-       // Set various defaults.
-       if ( null === $args->public && null === $args->internal && null === $args->protected && null === $args->private )
-               $args->internal = true;
-
-       if ( null === $args->public  )
-               $args->public = false;
-
-       if ( null === $args->private  )
-               $args->private = false;
-
-       if ( null === $args->protected  )
-               $args->protected = false;
-
-       if ( null === $args->internal  )
-               $args->internal = false;
-
-       if ( null === $args->publicly_queryable )
-               $args->publicly_queryable = $args->public;
-
-       if ( null === $args->exclude_from_search )
-               $args->exclude_from_search = $args->internal;
-
-       if ( null === $args->show_in_admin_all_list )
-               $args->show_in_admin_all_list = !$args->internal;
-
-       if ( null === $args->show_in_admin_status_list )
-               $args->show_in_admin_status_list = !$args->internal;
-
-       if ( false === $args->label )
-               $args->label = $post_status;
-
-       if ( false === $args->label_count )
-               $args->label_count = array( $args->label, $args->label );
-
-       $wp_post_statuses[$post_status] = $args;
-
-       return $args;
-}
-
-/**
- * Retrieve a post status object by name.
- *
- * @since 3.0.0
- *
- * @global array $wp_post_statuses List of post statuses.
- *
- * @see register_post_status()
- *
- * @param string $post_status The name of a registered post status.
- * @return object|null A post status object.
- */
-function get_post_status_object( $post_status ) {
-       global $wp_post_statuses;
-
-       if ( empty($wp_post_statuses[$post_status]) )
-               return null;
-
-       return $wp_post_statuses[$post_status];
-}
-
-/**
- * Get a list of post statuses.
- *
- * @since 3.0.0
- *
- * @global array $wp_post_statuses List of post statuses.
- *
- * @see register_post_status()
- *
- * @param array|string $args     Optional. Array or string of post status arguments to compare against
- *                               properties of the global `$wp_post_statuses objects`. Default empty array.
- * @param string       $output   Optional. The type of output to return, either 'names' or 'objects'. Default 'names'.
- * @param string       $operator Optional. The logical operation to perform. 'or' means only one element
- *                               from the array needs to match; 'and' means all elements must match.
- *                               Default 'and'.
- * @return array A list of post status names or objects.
- */
-function get_post_stati( $args = array(), $output = 'names', $operator = 'and' ) {
-       global $wp_post_statuses;
-
-       $field = ('names' == $output) ? 'name' : false;
-
-       return wp_filter_object_list($wp_post_statuses, $args, $operator, $field);
-}
-
-/**
- * Whether the post type is hierarchical.
- *
- * A false return value might also mean that the post type does not exist.
- *
- * @since 3.0.0
- *
- * @see get_post_type_object()
- *
- * @param string $post_type Post type name
- * @return bool Whether post type is hierarchical.
- */
-function is_post_type_hierarchical( $post_type ) {
-       if ( ! post_type_exists( $post_type ) )
-               return false;
-
-       $post_type = get_post_type_object( $post_type );
-       return $post_type->hierarchical;
-}
-
-/**
- * Check if a post type is registered.
- *
- * @since 3.0.0
- *
- * @see get_post_type_object()
- *
- * @param string $post_type Post type name.
- * @return bool Whether post type is registered.
- */
-function post_type_exists( $post_type ) {
-       return (bool) get_post_type_object( $post_type );
-}
-
-/**
- * Retrieve the post type of the current post or of a given post.
- *
- * @since 2.1.0
- *
- * @param int|WP_Post|null $post Optional. Post ID or post object. Default is global $post.
- * @return string|false          Post type on success, false on failure.
- */
-function get_post_type( $post = null ) {
-       if ( $post = get_post( $post ) )
-               return $post->post_type;
-
-       return false;
-}
-
-/**
- * Retrieve a post type object by name.
- *
- * @since 3.0.0
- *
- * @global array $wp_post_types List of post types.
- *
- * @see register_post_type()
- *
- * @param string $post_type The name of a registered post type.
- * @return object|null A post type object.
- */
-function get_post_type_object( $post_type ) {
-       global $wp_post_types;
-
-       if ( ! is_scalar( $post_type ) || empty( $wp_post_types[ $post_type ] ) ) {
-               return null;
-       }
-
-       return $wp_post_types[ $post_type ];
-}
-
-/**
- * Get a list of all registered post type objects.
- *
- * @since 2.9.0
- *
- * @global array $wp_post_types List of post types.
- *
- * @see register_post_type() for accepted arguments.
- *
- * @param array|string $args     Optional. An array of key => value arguments to match against
- *                               the post type objects. Default empty array.
- * @param string       $output   Optional. The type of output to return. Accepts post type 'names'
- *                               or 'objects'. Default 'names'.
- * @param string       $operator Optional. The logical operation to perform. 'or' means only one
- *                               element from the array needs to match; 'and' means all elements
- *                               must match. Accepts 'or' or 'and'. Default 'and'.
- * @return array A list of post type names or objects.
- */
-function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) {
-       global $wp_post_types;
-
-       $field = ('names' == $output) ? 'name' : false;
-
-       return wp_filter_object_list($wp_post_types, $args, $operator, $field);
-}
-
-/**
- * Register a post type. Do not use before init.
- *
- * A function for creating or modifying a post type based on the
- * parameters given. The function will accept an array (second optional
- * parameter), along with a string for the post type name.
- *
- * @since 2.9.0
- * @since 3.0.0 The `show_ui` argument is now enforced on the new post screen.
- * @since 4.4.0 The `show_ui` argument is now enforced on the post type listing screen and post editing screen.
- *
- * @global array      $wp_post_types List of post types.
- * @global WP_Rewrite $wp_rewrite    Used for default feeds.
- * @global WP         $wp            Used to add query vars.
- *
- * @param string $post_type Post type key, must not exceed 20 characters.
- * @param array|string $args {
- *     Array or string of arguments for registering a post type.
- *
- *     @type string      $label                Name of the post type shown in the menu. Usually plural.
- *                                             Default is value of $labels['name'].
- *     @type array       $labels               An array of labels for this post type. If not set, post
- *                                             labels are inherited for non-hierarchical types and page
- *                                             labels for hierarchical ones. {@see get_post_type_labels()}.
- *     @type string      $description          A short descriptive summary of what the post type is.
- *                                             Default empty.
- *     @type bool        $public               Whether a post type is intended for use publicly either via
- *                                             the admin interface or by front-end users. While the default
- *                                             settings of $exclude_from_search, $publicly_queryable, $show_ui,
- *                                             and $show_in_nav_menus are inherited from public, each does not
- *                                             rely on this relationship and controls a very specific intention.
- *                                             Default false.
- *     @type bool        $hierarchical         Whether the post type is hierarchical (e.g. page). Default false.
- *     @type bool        $exclude_from_search  Whether to exclude posts with this post type from front end search
- *                                             results. Default is the opposite value of $public.
- *     @type bool        $publicly_queryable   Whether queries can be performed on the front end for the post type
- *                                             as part of {@see parse_request()}. Endpoints would include:
- *                                             * ?post_type={post_type_key}
- *                                             * ?{post_type_key}={single_post_slug}
- *                                             * ?{post_type_query_var}={single_post_slug}
- *                                             If not set, the default is inherited from $public.
- *     @type bool        $show_ui              Whether to generate and allow a UI for managing this post type in the
- *                                             admin. Default is value of $public.
- *     @type bool        $show_in_menu         Where to show the post type in the admin menu. To work, $show_ui
- *                                             must be true. If true, the post type is shown in its own top level
- *                                             menu. If false, no menu is shown. If a string of an existing top
- *                                             level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post
- *                                             type will be placed as a sub-menu of that.
- *                                             Default is value of $show_ui.
- *     @type bool        $show_in_nav_menus    Makes this post type available for selection in navigation menus.
- *                                             Default is value $public.
- *     @type bool        $show_in_admin_bar    Makes this post type available via the admin bar. Default is value
- *                                             of $show_in_menu.
- *     @type int         $menu_position        The position in the menu order the post type should appear. To work,
- *                                             $show_in_menu must be true. Default null (at the bottom).
- *     @type string      $menu_icon            The url to the icon to be used for this menu. Pass a base64-encoded
- *                                             SVG using a data URI, which will be colored to match the color scheme
- *                                             -- this should begin with 'data:image/svg+xml;base64,'. Pass the name
- *                                             of a Dashicons helper class to use a font icon, e.g.
- *                                             'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty
- *                                             so an icon can be added via CSS. Defaults to use the posts icon.
- *     @type string      $capability_type      The string to use to build the read, edit, and delete capabilities.
- *                                             May be passed as an array to allow for alternative plurals when using
- *                                             this argument as a base to construct the capabilities, e.g.
- *                                             array('story', 'stories'). Default 'post'.
- *     @type array       $capabilities         Array of capabilities for this post type. $capability_type is used
- *                                             as a base to construct capabilities by default.
- *                                             {@see get_post_type_capabilities()}.
- *     @type bool        $map_meta_cap         Whether to use the internal default meta capability handling.
- *                                             Default false.
- *     @type array       $supports             An alias for calling {@see add_post_type_support()} directly.
- *                                             Defaults to array containing 'title' & 'editor'.
- *     @type callable    $register_meta_box_cb Provide a callback function that sets up the meta boxes for the
- *                                             edit form. Do remove_meta_box() and add_meta_box() calls in the
- *                                             callback. Default null.
- *     @type array       $taxonomies           An array of taxonomy identifiers that will be registered for the
- *                                             post type. Taxonomies can be registered later with
- *                                             {@see register_taxonomy()} or {@see register_taxonomy_for_object_type()}.
- *                                             Default empty array.
- *     @type bool|string $has_archive          Whether there should be post type archives, or if a string, the
- *                                             archive slug to use. Will generate the proper rewrite rules if
- *                                             $rewrite is enabled. Default false.
- *     @type bool|array  $rewrite              {
- *         Triggers the handling of rewrites for this post type. To prevent rewrite, set to false.
- *         Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be
- *         passed with any of these keys:
- *
- *         @type string $slug       Customize the permastruct slug. Defaults to $post_type key.
- *         @type bool   $with_front Whether the permastruct should be prepended with WP_Rewrite::$front.
- *                                  Default true.
- *         @type bool   $feeds      Whether the feed permastruct should be built for this post type.
- *                                  Default is value of $has_archive.
- *         @type bool   $pages      Whether the permastruct should provide for pagination. Default true.
- *         @type const  $ep_mask    Endpoint mask to assign. If not specified and permalink_epmask is set,
- *                                  inherits from $permalink_epmask. If not specified and permalink_epmask
- *                                  is not set, defaults to EP_PERMALINK.
- *     }
- *     @type string|bool $query_var            Sets the query_var key for this post type. Defaults to $post_type
- *                                             key. If false, a post type cannot be loaded at
- *                                             ?{query_var}={post_slug}. If specified as a string, the query
- *                                             ?{query_var_string}={post_slug} will be valid.
- *     @type bool        $can_export           Whether to allow this post type to be exported. Default true.
- *     @type bool        $delete_with_user     Whether to delete posts of this type when deleting a user. If true,
- *                                             posts of this type belonging to the user will be moved to trash
- *                                             when then user is deleted. If false, posts of this type belonging
- *                                             to the user will *not* be trashed or deleted. If not set (the default),
- *                                             posts are trashed if post_type_supports('author'). Otherwise posts
- *                                             are not trashed or deleted. Default null.
- *     @type bool        $_builtin             FOR INTERNAL USE ONLY! True if this post type is a native or
- *                                             "built-in" post_type. Default false.
- *     @type string      $_edit_link           FOR INTERNAL USE ONLY! URL segment to use for edit link of
- *                                             this post type. Default 'post.php?post=%d'.
- * }
- * @return object|WP_Error The registered post type object, or an error object.
- */
-function register_post_type( $post_type, $args = array() ) {
-       global $wp_post_types, $wp_rewrite, $wp;
-
-       if ( ! is_array( $wp_post_types ) ) {
-               $wp_post_types = array();
-       }
-
-       // Sanitize post type name
-       $post_type = sanitize_key( $post_type );
-       $args      = wp_parse_args( $args );
-
-       /**
-        * Filter the arguments for registering a post type.
-        *
-        * @since 4.4.0
-        *
-        * @param array  $args      Array of arguments for registering a post type.
-        * @param string $post_type Post type key.
-        */
-       $args = apply_filters( 'register_post_type_args', $args, $post_type );
-
-       $has_edit_link = ! empty( $args['_edit_link'] );
-
-       // Args prefixed with an underscore are reserved for internal use.
-       $defaults = array(
-               'labels'               => array(),
-               'description'          => '',
-               'public'               => false,
-               'hierarchical'         => false,
-               'exclude_from_search'  => null,
-               'publicly_queryable'   => null,
-               'show_ui'              => null,
-               'show_in_menu'         => null,
-               'show_in_nav_menus'    => null,
-               'show_in_admin_bar'    => null,
-               'menu_position'        => null,
-               'menu_icon'            => null,
-               'capability_type'      => 'post',
-               'capabilities'         => array(),
-               'map_meta_cap'         => null,
-               'supports'             => array(),
-               'register_meta_box_cb' => null,
-               'taxonomies'           => array(),
-               'has_archive'          => false,
-               'rewrite'              => true,
-               'query_var'            => true,
-               'can_export'           => true,
-               'delete_with_user'     => null,
-               '_builtin'             => false,
-               '_edit_link'           => 'post.php?post=%d',
-       );
-       $args = array_merge( $defaults, $args );
-       $args = (object) $args;
-
-       $args->name = $post_type;
-
-       if ( empty( $post_type ) || strlen( $post_type ) > 20 ) {
-               _doing_it_wrong( __FUNCTION__, __( 'Post type names must be between 1 and 20 characters in length.' ), '4.2' );
-               return new WP_Error( 'post_type_length_invalid', __( 'Post type names must be between 1 and 20 characters in length.' ) );
-       }
-
-       // If not set, default to the setting for public.
-       if ( null === $args->publicly_queryable )
-               $args->publicly_queryable = $args->public;
-
-       // If not set, default to the setting for public.
-       if ( null === $args->show_ui )
-               $args->show_ui = $args->public;
-
-       // If not set, default to the setting for show_ui.
-       if ( null === $args->show_in_menu || ! $args->show_ui )
-               $args->show_in_menu = $args->show_ui;
-
-       // If not set, default to the whether the full UI is shown.
-       if ( null === $args->show_in_admin_bar )
-               $args->show_in_admin_bar = (bool) $args->show_in_menu;
-
-       // If not set, default to the setting for public.
-       if ( null === $args->show_in_nav_menus )
-               $args->show_in_nav_menus = $args->public;
-
-       // If not set, default to true if not public, false if public.
-       if ( null === $args->exclude_from_search )
-               $args->exclude_from_search = !$args->public;
-
-       // Back compat with quirky handling in version 3.0. #14122.
-       if ( empty( $args->capabilities ) && null === $args->map_meta_cap && in_array( $args->capability_type, array( 'post', 'page' ) ) )
-               $args->map_meta_cap = true;
-
-       // If not set, default to false.
-       if ( null === $args->map_meta_cap )
-               $args->map_meta_cap = false;
-
-       // If there's no specified edit link and no UI, remove the edit link.
-       if ( ! $args->show_ui && ! $has_edit_link ) {
-               $args->_edit_link = '';
-       }
-
-       $args->cap = get_post_type_capabilities( $args );
-       unset( $args->capabilities );
-
-       if ( is_array( $args->capability_type ) )
-               $args->capability_type = $args->capability_type[0];
-
-       if ( ! empty( $args->supports ) ) {
-               add_post_type_support( $post_type, $args->supports );
-               unset( $args->supports );
-       } elseif ( false !== $args->supports ) {
-               // Add default features
-               add_post_type_support( $post_type, array( 'title', 'editor' ) );
-       }
-
-       if ( false !== $args->query_var ) {
-               if ( true === $args->query_var )
-                       $args->query_var = $post_type;
-               else
-                       $args->query_var = sanitize_title_with_dashes( $args->query_var );
-
-               if ( $wp && is_post_type_viewable( $args ) ) {
-                       $wp->add_query_var( $args->query_var );
-               }
-       }
-
-       if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
-               if ( ! is_array( $args->rewrite ) )
-                       $args->rewrite = array();
-               if ( empty( $args->rewrite['slug'] ) )
-                       $args->rewrite['slug'] = $post_type;
-               if ( ! isset( $args->rewrite['with_front'] ) )
-                       $args->rewrite['with_front'] = true;
-               if ( ! isset( $args->rewrite['pages'] ) )
-                       $args->rewrite['pages'] = true;
-               if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
-                       $args->rewrite['feeds'] = (bool) $args->has_archive;
-               if ( ! isset( $args->rewrite['ep_mask'] ) ) {
-                       if ( isset( $args->permalink_epmask ) )
-                               $args->rewrite['ep_mask'] = $args->permalink_epmask;
-                       else
-                               $args->rewrite['ep_mask'] = EP_PERMALINK;
-               }
-
-               if ( $args->hierarchical )
-                       add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
-               else
-                       add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );
-
-               if ( $args->has_archive ) {
-                       $archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
-                       if ( $args->rewrite['with_front'] )
-                               $archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
-                       else
-                               $archive_slug = $wp_rewrite->root . $archive_slug;
-
-                       add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
-                       if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
-                               $feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
-                               add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
-                               add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
-                       }
-                       if ( $args->rewrite['pages'] )
-                               add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
-               }
-
-               $permastruct_args = $args->rewrite;
-               $permastruct_args['feed'] = $permastruct_args['feeds'];
-               add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
-       }
-
-       // Register the post type meta box if a custom callback was specified.
-       if ( $args->register_meta_box_cb )
-               add_action( 'add_meta_boxes_' . $post_type, $args->register_meta_box_cb, 10, 1 );
-
-       $args->labels = get_post_type_labels( $args );
-       $args->label = $args->labels->name;
-
-       $wp_post_types[ $post_type ] = $args;
-
-       add_action( 'future_' . $post_type, '_future_post_hook', 5, 2 );
-
-       foreach ( $args->taxonomies as $taxonomy ) {
-               register_taxonomy_for_object_type( $taxonomy, $post_type );
-       }
-
-       /**
-        * Fires after a post type is registered.
-        *
-        * @since 3.3.0
-        *
-        * @param string $post_type Post type.
-        * @param object $args      Arguments used to register the post type.
-        */
-       do_action( 'registered_post_type', $post_type, $args );
-
-       return $args;
-}
-
-/**
- * Build an object with all post type capabilities out of a post type object
- *
- * Post type capabilities use the 'capability_type' argument as a base, if the
- * capability is not set in the 'capabilities' argument array or if the
- * 'capabilities' argument is not supplied.
- *
- * The capability_type argument can optionally be registered as an array, with
- * the first value being singular and the second plural, e.g. array('story, 'stories')
- * Otherwise, an 's' will be added to the value for the plural form. After
- * registration, capability_type will always be a string of the singular value.
- *
- * By default, seven keys are accepted as part of the capabilities array:
- *
- * - edit_post, read_post, and delete_post are meta capabilities, which are then
- *   generally mapped to corresponding primitive capabilities depending on the
- *   context, which would be the post being edited/read/deleted and the user or
- *   role being checked. Thus these capabilities would generally not be granted
- *   directly to users or roles.
- *
- * - edit_posts - Controls whether objects of this post type can be edited.
- * - edit_others_posts - Controls whether objects of this type owned by other users
- *   can be edited. If the post type does not support an author, then this will
- *   behave like edit_posts.
- * - publish_posts - Controls publishing objects of this post type.
- * - read_private_posts - Controls whether private objects can be read.
- *
- * These four primitive capabilities are checked in core in various locations.
- * There are also seven other primitive capabilities which are not referenced
- * directly in core, except in map_meta_cap(), which takes the three aforementioned
- * meta capabilities and translates them into one or more primitive capabilities
- * that must then be checked against the user or role, depending on the context.
- *
- * - read - Controls whether objects of this post type can be read.
- * - delete_posts - Controls whether objects of this post type can be deleted.
- * - delete_private_posts - Controls whether private objects can be deleted.
- * - delete_published_posts - Controls whether published objects can be deleted.
- * - delete_others_posts - Controls whether objects owned by other users can be
- *   can be deleted. If the post type does not support an author, then this will
- *   behave like delete_posts.
- * - edit_private_posts - Controls whether private objects can be edited.
- * - edit_published_posts - Controls whether published objects can be edited.
- *
- * These additional capabilities are only used in map_meta_cap(). Thus, they are
- * only assigned by default if the post type is registered with the 'map_meta_cap'
- * argument set to true (default is false).
- *
- * @since 3.0.0
- *
- * @see register_post_type()
- * @see map_meta_cap()
- *
- * @param object $args Post type registration arguments.
- * @return object object with all the capabilities as member variables.
- */
-function get_post_type_capabilities( $args ) {
-       if ( ! is_array( $args->capability_type ) )
-               $args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
-
-       // Singular base for meta capabilities, plural base for primitive capabilities.
-       list( $singular_base, $plural_base ) = $args->capability_type;
-
-       $default_capabilities = array(
-               // Meta capabilities
-               'edit_post'          => 'edit_'         . $singular_base,
-               'read_post'          => 'read_'         . $singular_base,
-               'delete_post'        => 'delete_'       . $singular_base,
-               // Primitive capabilities used outside of map_meta_cap():
-               'edit_posts'         => 'edit_'         . $plural_base,
-               'edit_others_posts'  => 'edit_others_'  . $plural_base,
-               'publish_posts'      => 'publish_'      . $plural_base,
-               'read_private_posts' => 'read_private_' . $plural_base,
-       );
-
-       // Primitive capabilities used within map_meta_cap():
-       if ( $args->map_meta_cap ) {
-               $default_capabilities_for_mapping = array(
-                       'read'                   => 'read',
-                       'delete_posts'           => 'delete_'           . $plural_base,
-                       'delete_private_posts'   => 'delete_private_'   . $plural_base,
-                       'delete_published_posts' => 'delete_published_' . $plural_base,
-                       'delete_others_posts'    => 'delete_others_'    . $plural_base,
-                       'edit_private_posts'     => 'edit_private_'     . $plural_base,
-                       'edit_published_posts'   => 'edit_published_'   . $plural_base,
-               );
-               $default_capabilities = array_merge( $default_capabilities, $default_capabilities_for_mapping );
-       }
-
-       $capabilities = array_merge( $default_capabilities, $args->capabilities );
-
-       // Post creation capability simply maps to edit_posts by default:
-       if ( ! isset( $capabilities['create_posts'] ) )
-               $capabilities['create_posts'] = $capabilities['edit_posts'];
-
-       // Remember meta capabilities for future reference.
-       if ( $args->map_meta_cap )
-               _post_type_meta_capabilities( $capabilities );
-
-       return (object) $capabilities;
-}
-
-/**
- * Store or return a list of post type meta caps for map_meta_cap().
- *
- * @since 3.1.0
- * @access private
- *
- * @staticvar array $meta_caps
- *
- * @param array|void $capabilities Post type meta capabilities.
- */
-function _post_type_meta_capabilities( $capabilities = null ) {
-       static $meta_caps = array();
-       if ( null === $capabilities )
-               return $meta_caps;
-       foreach ( $capabilities as $core => $custom ) {
-               if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
-                       $meta_caps[ $custom ] = $core;
-       }
-}
-
-/**
- * Build an object with all post type labels out of a post type object
- *
- * Accepted keys of the label array in the post type object:
- *
- * - name - general name for the post type, usually plural. The same and overridden
- *          by $post_type_object->label. Default is Posts/Pages
- * - singular_name - name for one object of this post type. Default is Post/Page
- * - add_new - Default is Add New for both hierarchical and non-hierarchical types.
- *             When internationalizing this string, please use a gettext context
- *             {@link https://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context}
- *             matching your post type. Example: `_x( 'Add New', 'product' );`.
- * - add_new_item - Default is Add New Post/Add New Page.
- * - edit_item - Default is Edit Post/Edit Page.
- * - new_item - Default is New Post/New Page.
- * - view_item - Default is View Post/View Page.
- * - search_items - Default is Search Posts/Search Pages.
- * - not_found - Default is No posts found/No pages found.
- * - not_found_in_trash - Default is No posts found in Trash/No pages found in Trash.
- * - parent_item_colon - This string isn't used on non-hierarchical types. In hierarchical
- *                       ones the default is 'Parent Page:'.
- * - all_items - String for the submenu. Default is All Posts/All Pages.
- * - archives - String for use with archives in nav menus. Default is Post Archives/Page Archives.
- * - insert_into_item - String for the media frame button. Default is Insert into post/Insert into page.
- * - uploaded_to_this_item - String for the media frame filter. Default is Uploaded to this post/Uploaded to this page.
- * - featured_image - Default is Featured Image.
- * - set_featured_image - Default is Set featured image.
- * - remove_featured_image - Default is Remove featured image.
- * - use_featured_image - Default is Use as featured image.
- * - menu_name - Default is the same as `name`.
- * - filter_items_list - String for the table views hidden heading.
- * - items_list_navigation - String for the table pagination hidden heading.
- * - items_list - String for the table hidden heading.
- *
- * Above, the first default value is for non-hierarchical post types (like posts)
- * and the second one is for hierarchical post types (like pages).
- *
- * @since 3.0.0
- * @since 4.3.0 Added the `featured_image`, `set_featured_image`, `remove_featured_image`,
- *              and `use_featured_image` labels.
- * @since 4.4.0 Added the `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`,
- *              `items_list_navigation`, and `items_list` labels.
- *
- * @access private
- *
- * @param object $post_type_object Post type object.
- * @return object object with all the labels as member variables.
- */
-function get_post_type_labels( $post_type_object ) {
-       $nohier_vs_hier_defaults = array(
-               'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
-               'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
-               'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
-               'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
-               'edit_item' => array( __('Edit Post'), __('Edit Page') ),
-               'new_item' => array( __('New Post'), __('New Page') ),
-               'view_item' => array( __('View Post'), __('View Page') ),
-               'search_items' => array( __('Search Posts'), __('Search Pages') ),
-               'not_found' => array( __('No posts found.'), __('No pages found.') ),
-               'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
-               'parent_item_colon' => array( null, __('Parent Page:') ),
-               'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ),
-               'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ),
-               'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ),
-               'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ),
-               'featured_image' => array( __( 'Featured Image' ), __( 'Featured Image' ) ),
-               'set_featured_image' => array( __( 'Set featured image' ), __( 'Set featured image' ) ),
-               'remove_featured_image' => array( __( 'Remove featured image' ), __( 'Remove featured image' ) ),
-               'use_featured_image' => array( __( 'Use as featured image' ), __( 'Use as featured image' ) ),
-               'filter_items_list' => array( __( 'Filter posts list' ), __( 'Filter pages list' ) ),
-               'items_list_navigation' => array( __( 'Posts list navigation' ), __( 'Pages list navigation' ) ),
-               'items_list' => array( __( 'Posts list' ), __( 'Pages list' ) ),
-       );
-       $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
-
-       $labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
-
-       $post_type = $post_type_object->name;
-
-       $default_labels = clone $labels;
-
-       /**
-        * Filter the labels of a specific post type.
-        *
-        * The dynamic portion of the hook name, `$post_type`, refers to
-        * the post type slug.
-        *
-        * @since 3.5.0
-        *
-        * @see get_post_type_labels() for the full list of labels.
-        *
-        * @param object $labels Object with labels for the post type as member variables.
-        */
-       $labels = apply_filters( "post_type_labels_{$post_type}", $labels );
-
-       // Ensure that the filtered labels contain all required default values.
-       $labels = (object) array_merge( (array) $default_labels, (array) $labels );
-
-       return $labels;
-}
-
-/**
- * Build an object with custom-something object (post type, taxonomy) labels
- * out of a custom-something object
- *
- * @since 3.0.0
- * @access private
- *
- * @param object $object                  A custom-something object.
- * @param array  $nohier_vs_hier_defaults Hierarchical vs non-hierarchical default labels.
- * @return object Object containing labels for the given custom-something object.
- */
-function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
-       $object->labels = (array) $object->labels;
-
-       if ( isset( $object->label ) && empty( $object->labels['name'] ) )
-               $object->labels['name'] = $object->label;
-
-       if ( !isset( $object->labels['singular_name'] ) && isset( $object->labels['name'] ) )
-               $object->labels['singular_name'] = $object->labels['name'];
-
-       if ( ! isset( $object->labels['name_admin_bar'] ) )
-               $object->labels['name_admin_bar'] = isset( $object->labels['singular_name'] ) ? $object->labels['singular_name'] : $object->name;
-
-       if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
-               $object->labels['menu_name'] = $object->labels['name'];
-
-       if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
-               $object->labels['all_items'] = $object->labels['menu_name'];
-
-       if ( !isset( $object->labels['archives'] ) && isset( $object->labels['all_items'] ) ) {
-               $object->labels['archives'] = $object->labels['all_items'];
-       }
-
-       $defaults = array();
-       foreach ( $nohier_vs_hier_defaults as $key => $value ) {
-               $defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
-       }
-       $labels = array_merge( $defaults, $object->labels );
-       $object->labels = (object) $object->labels;
-
-       return (object) $labels;
-}
-
-/**
- * Add submenus for post types.
- *
- * @access private
- * @since 3.1.0
- */
-function _add_post_type_submenus() {
-       foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) {
-               $ptype_obj = get_post_type_object( $ptype );
-               // Sub-menus only.
-               if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true )
-                       continue;
-               add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" );
-       }
-}
-
-/**
- * Register support of certain features for a post type.
- *
- * All core features are directly associated with a functional area of the edit
- * screen, such as the editor or a meta box. Features include: 'title', 'editor',
- * 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes',
- * 'thumbnail', 'custom-fields', and 'post-formats'.
- *
- * Additionally, the 'revisions' feature dictates whether the post type will
- * store revisions, and the 'comments' feature dictates whether the comments
- * count will show on the edit screen.
- *
- * @since 3.0.0
- *
- * @global array $_wp_post_type_features
- *
- * @param string       $post_type The post type for which to add the feature.
- * @param string|array $feature   The feature being added, accepts an array of
- *                                feature strings or a single string.
- */
-function add_post_type_support( $post_type, $feature ) {
-       global $_wp_post_type_features;
-
-       $features = (array) $feature;
-       foreach ($features as $feature) {
-               if ( func_num_args() == 2 )
-                       $_wp_post_type_features[$post_type][$feature] = true;
-               else
-                       $_wp_post_type_features[$post_type][$feature] = array_slice( func_get_args(), 2 );
-       }
-}
-
-/**
- * Remove support for a feature from a post type.
- *
- * @since 3.0.0
- *
- * @global array $_wp_post_type_features
- *
- * @param string $post_type The post type for which to remove the feature.
- * @param string $feature   The feature being removed.
- */
-function remove_post_type_support( $post_type, $feature ) {
-       global $_wp_post_type_features;
-
-       unset( $_wp_post_type_features[ $post_type ][ $feature ] );
-}
-
-/**
- * Get all the post type features
- *
- * @since 3.4.0
- *
- * @global array $_wp_post_type_features
- *
- * @param string $post_type The post type.
- * @return array Post type supports list.
- */
-function get_all_post_type_supports( $post_type ) {
-       global $_wp_post_type_features;
-
-       if ( isset( $_wp_post_type_features[$post_type] ) )
-               return $_wp_post_type_features[$post_type];
-
-       return array();
-}
-
-/**
- * Check a post type's support for a given feature.
- *
- * @since 3.0.0
- *
- * @global array $_wp_post_type_features
- *
- * @param string $post_type The post type being checked.
- * @param string $feature   The feature being checked.
- * @return bool Whether the post type supports the given feature.
- */
-function post_type_supports( $post_type, $feature ) {
-       global $_wp_post_type_features;
-
-       return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
-}
-
-/**
- * Update the post type for the post ID.
- *
- * The page or post cache will be cleaned for the post ID.
- *
- * @since 2.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int    $post_id   Optional. Post ID to change post type. Default 0.
- * @param string $post_type Optional. Post type. Accepts 'post' or 'page' to
- *                          name a few. Default 'post'.
- * @return int|false Amount of rows changed. Should be 1 for success and 0 for failure.
- */
-function set_post_type( $post_id = 0, $post_type = 'post' ) {
-       global $wpdb;
-
-       $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
-       $return = $wpdb->update( $wpdb->posts, array('post_type' => $post_type), array('ID' => $post_id) );
-
-       clean_post_cache( $post_id );
-
-       return $return;
-}
-
-/**
- * Determines whether a post type is considered "viewable".
- *
- * For built-in post types such as posts and pages, the 'public' value will be evaluated.
- * For all others, the 'publicly_queryable' value will be used.
- *
- * @since 4.4.0
- *
- * @param object $post_type_object Post type object.
- * @return bool Whether the post type should be considered viewable.
- */
-function is_post_type_viewable( $post_type_object ) {
-       return $post_type_object->publicly_queryable || ( $post_type_object->_builtin && $post_type_object->public );
-}
-
-/**
- * Retrieve list of latest posts or posts matching criteria.
- *
- * The defaults are as follows:
- *
- * @since 1.2.0
- *
- * @see WP_Query::parse_query()
- *
- * @param array $args {
- *     Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all
- *     available arguments.
- *
- *     @type int        $numberposts      Total number of posts to retrieve. Is an alias of $posts_per_page
- *                                        in WP_Query. Accepts -1 for all. Default 5.
- *     @type int|string $category         Category ID or comma-separated list of IDs (this or any children).
- *                                        Is an alias of $cat in WP_Query. Default 0.
- *     @type array      $include          An array of post IDs to retrieve, sticky posts will be included.
- *                                        Is an alias of $post__in in WP_Query. Default empty array.
- *     @type array      $exclude          An array of post IDs not to retrieve. Default empty array.
- *     @type bool       $suppress_filters Whether to suppress filters. Default true.
- * }
- * @return array List of posts.
- */
-function get_posts( $args = null ) {
-       $defaults = array(
-               'numberposts' => 5,
-               'category' => 0, 'orderby' => 'date',
-               'order' => 'DESC', 'include' => array(),
-               'exclude' => array(), 'meta_key' => '',
-               'meta_value' =>'', 'post_type' => 'post',
-               'suppress_filters' => true
-       );
-
-       $r = wp_parse_args( $args, $defaults );
-       if ( empty( $r['post_status'] ) )
-               $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
-       if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
-               $r['posts_per_page'] = $r['numberposts'];
-       if ( ! empty($r['category']) )
-               $r['cat'] = $r['category'];
-       if ( ! empty($r['include']) ) {
-               $incposts = wp_parse_id_list( $r['include'] );
-               $r['posts_per_page'] = count($incposts);  // only the number of posts included
-               $r['post__in'] = $incposts;
-       } elseif ( ! empty($r['exclude']) )
-               $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );
-
-       $r['ignore_sticky_posts'] = true;
-       $r['no_found_rows'] = true;
-
-       $get_posts = new WP_Query;
-       return $get_posts->query($r);
-
-}
-
-//
-// Post meta functions
-//
-
-/**
- * Add meta data field to a post.
- *
- * Post meta data is called "Custom Fields" on the Administration Screen.
- *
- * @since 1.5.0
- *
- * @param int    $post_id    Post ID.
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
- * @param bool   $unique     Optional. Whether the same key should not be added.
- *                           Default false.
- * @return int|false Meta ID on success, false on failure.
- */
-function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
-       // Make sure meta is added to the post, not a revision.
-       if ( $the_post = wp_is_post_revision($post_id) )
-               $post_id = $the_post;
-
-       return add_metadata('post', $post_id, $meta_key, $meta_value, $unique);
-}
-
-/**
- * Remove metadata matching criteria from a post.
- *
- * You can match based on the key, or key and value. Removing based on key and
- * value, will keep from removing duplicate metadata with the same key. It also
- * allows removing all metadata matching key, if needed.
- *
- * @since 1.5.0
- *
- * @param int    $post_id    Post ID.
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Optional. Metadata value. Must be serializable if
- *                           non-scalar. Default empty.
- * @return bool True on success, false on failure.
- */
-function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
-       // Make sure meta is added to the post, not a revision.
-       if ( $the_post = wp_is_post_revision($post_id) )
-               $post_id = $the_post;
-
-       return delete_metadata('post', $post_id, $meta_key, $meta_value);
-}
-
-/**
- * Retrieve post meta field for a post.
- *
- * @since 1.5.0
- *
- * @param int    $post_id Post ID.
- * @param string $key     Optional. The meta key to retrieve. By default, returns
- *                        data for all keys. Default empty.
- * @param bool   $single  Optional. Whether to return a single value. Default false.
- * @return mixed Will be an array if $single is false. Will be value of meta data
- *               field if $single is true.
- */
-function get_post_meta( $post_id, $key = '', $single = false ) {
-       return get_metadata('post', $post_id, $key, $single);
-}
-
-/**
- * Update post meta field based on post ID.
- *
- * Use the $prev_value parameter to differentiate between meta fields with the
- * same key and post ID.
- *
- * If the meta field for the post does not exist, it will be added.
- *
- * @since 1.5.0
- *
- * @param int    $post_id    Post ID.
- * @param string $meta_key   Metadata key.
- * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
- * @param mixed  $prev_value Optional. Previous value to check before removing.
- *                           Default empty.
- * @return int|bool Meta ID if the key didn't exist, true on successful update,
- *                  false on failure.
- */
-function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
-       // Make sure meta is added to the post, not a revision.
-       if ( $the_post = wp_is_post_revision($post_id) )
-               $post_id = $the_post;
-
-       return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
-}
-
-/**
- * Delete everything from post meta matching meta key.
- *
- * @since 2.3.0
- *
- * @param string $post_meta_key Key to search for when deleting.
- * @return bool Whether the post meta key was deleted from the database.
- */
-function delete_post_meta_by_key( $post_meta_key ) {
-       return delete_metadata( 'post', null, $post_meta_key, '', true );
-}
-
-/**
- * Retrieve post meta fields, based on post ID.
- *
- * The post meta fields are retrieved from the cache where possible,
- * so the function is optimized to be called more than once.
- *
- * @since 1.2.0
- *
- * @param int $post_id Optional. Post ID. Default is ID of the global $post.
- * @return array Post meta for the given post.
- */
-function get_post_custom( $post_id = 0 ) {
-       $post_id = absint( $post_id );
-       if ( ! $post_id )
-               $post_id = get_the_ID();
-
-       return get_post_meta( $post_id );
-}
-
-/**
- * Retrieve meta field names for a post.
- *
- * If there are no meta fields, then nothing (null) will be returned.
- *
- * @since 1.2.0
- *
- * @param int $post_id Optional. Post ID. Default is ID of the global $post.
- * @return array|void Array of the keys, if retrieved.
- */
-function get_post_custom_keys( $post_id = 0 ) {
-       $custom = get_post_custom( $post_id );
-
-       if ( !is_array($custom) )
-               return;
-
-       if ( $keys = array_keys($custom) )
-               return $keys;
-}
-
-/**
- * Retrieve values for a custom post field.
- *
- * The parameters must not be considered optional. All of the post meta fields
- * will be retrieved and only the meta field key values returned.
- *
- * @since 1.2.0
- *
- * @param string $key     Optional. Meta field key. Default empty.
- * @param int    $post_id Optional. Post ID. Default is ID of the global $post.
- * @return array|null Meta field values.
- */
-function get_post_custom_values( $key = '', $post_id = 0 ) {
-       if ( !$key )
-               return null;
-
-       $custom = get_post_custom($post_id);
-
-       return isset($custom[$key]) ? $custom[$key] : null;
-}
-
-/**
- * Check if post is sticky.
- *
- * Sticky posts should remain at the top of The Loop. If the post ID is not
- * given, then The Loop ID for the current post will be used.
- *
- * @since 2.7.0
- *
- * @param int $post_id Optional. Post ID. Default is ID of the global $post.
- * @return bool Whether post is sticky.
- */
-function is_sticky( $post_id = 0 ) {
-       $post_id = absint( $post_id );
-
-       if ( ! $post_id )
-               $post_id = get_the_ID();
-
-       $stickies = get_option( 'sticky_posts' );
-
-       if ( ! is_array( $stickies ) )
-               return false;
-
-       if ( in_array( $post_id, $stickies ) )
-               return true;
-
-       return false;
-}
-
-/**
- * Sanitize every post field.
- *
- * If the context is 'raw', then the post object or array will get minimal
- * sanitization of the integer fields.
- *
- * @since 2.3.0
- *
- * @see sanitize_post_field()
- *
- * @param object|WP_Post|array $post    The Post Object or Array
- * @param string               $context Optional. How to sanitize post fields.
- *                                      Accepts 'raw', 'edit', 'db', or 'display'.
- *                                      Default 'display'.
- * @return object|WP_Post|array The now sanitized Post Object or Array (will be the
- *                              same type as $post).
- */
-function sanitize_post( $post, $context = 'display' ) {
-       if ( is_object($post) ) {
-               // Check if post already filtered for this context.
-               if ( isset($post->filter) && $context == $post->filter )
-                       return $post;
-               if ( !isset($post->ID) )
-                       $post->ID = 0;
-               foreach ( array_keys(get_object_vars($post)) as $field )
-                       $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
-               $post->filter = $context;
-       } elseif ( is_array( $post ) ) {
-               // Check if post already filtered for this context.
-               if ( isset($post['filter']) && $context == $post['filter'] )
-                       return $post;
-               if ( !isset($post['ID']) )
-                       $post['ID'] = 0;
-               foreach ( array_keys($post) as $field )
-                       $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
-               $post['filter'] = $context;
-       }
-       return $post;
-}
-
-/**
- * Sanitize post field based on context.
- *
- * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and
- * 'js'. The 'display' context is used by default. 'attribute' and 'js' contexts
- * are treated like 'display' when calling filters.
- *
- * @since 2.3.0
- * @since 4.4.0 Like `sanitize_post()`, `$context` defaults to 'display'.
- *
- * @param string $field   The Post Object field name.
- * @param mixed  $value   The Post Object value.
- * @param int    $post_id Post ID.
- * @param string $context Optional. How to sanitize post fields. Looks for 'raw', 'edit',
- *                        'db', 'display', 'attribute' and 'js'. Default 'display'.
- * @return mixed Sanitized value.
- */
-function sanitize_post_field( $field, $value, $post_id, $context = 'display' ) {
-       $int_fields = array('ID', 'post_parent', 'menu_order');
-       if ( in_array($field, $int_fields) )
-               $value = (int) $value;
-
-       // Fields which contain arrays of integers.
-       $array_int_fields = array( 'ancestors' );
-       if ( in_array($field, $array_int_fields) ) {
-               $value = array_map( 'absint', $value);
-               return $value;
-       }
-
-       if ( 'raw' == $context )
-               return $value;
-
-       $prefixed = false;
-       if ( false !== strpos($field, 'post_') ) {
-               $prefixed = true;
-               $field_no_prefix = str_replace('post_', '', $field);
-       }
-
-       if ( 'edit' == $context ) {
-               $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
-
-               if ( $prefixed ) {
-
-                       /**
-                        * Filter the value of a specific post field to edit.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the post
-                        * field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed $value   Value of the post field.
-                        * @param int   $post_id Post ID.
-                        */
-                       $value = apply_filters( "edit_{$field}", $value, $post_id );
-
-                       /**
-                        * Filter the value of a specific post field to edit.
-                        *
-                        * The dynamic portion of the hook name, `$field_no_prefix`, refers to
-                        * the post field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed $value   Value of the post field.
-                        * @param int   $post_id Post ID.
-                        */
-                       $value = apply_filters( "{$field_no_prefix}_edit_pre", $value, $post_id );
-               } else {
-                       $value = apply_filters( "edit_post_{$field}", $value, $post_id );
-               }
-
-               if ( in_array($field, $format_to_edit) ) {
-                       if ( 'post_content' == $field )
-                               $value = format_to_edit($value, user_can_richedit());
-                       else
-                               $value = format_to_edit($value);
-               } else {
-                       $value = esc_attr($value);
-               }
-       } elseif ( 'db' == $context ) {
-               if ( $prefixed ) {
-
-                       /**
-                        * Filter the value of a specific post field before saving.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the post
-                        * field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed $value Value of the post field.
-                        */
-                       $value = apply_filters( "pre_{$field}", $value );
-
-                       /**
-                        * Filter the value of a specific field before saving.
-                        *
-                        * The dynamic portion of the hook name, `$field_no_prefix`, refers
-                        * to the post field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed $value Value of the post field.
-                        */
-                       $value = apply_filters( "{$field_no_prefix}_save_pre", $value );
-               } else {
-                       $value = apply_filters( "pre_post_{$field}", $value );
-
-                       /**
-                        * Filter the value of a specific post field before saving.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the post
-                        * field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed $value Value of the post field.
-                        */
-                       $value = apply_filters( "{$field}_pre", $value );
-               }
-       } else {
-
-               // Use display filters by default.
-               if ( $prefixed ) {
-
-                       /**
-                        * Filter the value of a specific post field for display.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the post
-                        * field name.
-                        *
-                        * @since 2.3.0
-                        *
-                        * @param mixed  $value   Value of the prefixed post field.
-                        * @param int    $post_id Post ID.
-                        * @param string $context Context for how to sanitize the field. Possible
-                        *                        values include 'raw', 'edit', 'db', 'display',
-                        *                        'attribute' and 'js'.
-                        */
-                       $value = apply_filters( $field, $value, $post_id, $context );
-               } else {
-                       $value = apply_filters( "post_{$field}", $value, $post_id, $context );
-               }
-       }
-
-       if ( 'attribute' == $context )
-               $value = esc_attr($value);
-       elseif ( 'js' == $context )
-               $value = esc_js($value);
-
-       return $value;
-}
-
-/**
- * Make a post sticky.
- *
- * Sticky posts should be displayed at the top of the front page.
- *
- * @since 2.7.0
- *
- * @param int $post_id Post ID.
- */
-function stick_post( $post_id ) {
-       $stickies = get_option('sticky_posts');
-
-       if ( !is_array($stickies) )
-               $stickies = array($post_id);
-
-       if ( ! in_array($post_id, $stickies) )
-               $stickies[] = $post_id;
-
-       update_option('sticky_posts', $stickies);
-}
-
-/**
- * Un-stick a post.
- *
- * Sticky posts should be displayed at the top of the front page.
- *
- * @since 2.7.0
- *
- * @param int $post_id Post ID.
- */
-function unstick_post( $post_id ) {
-       $stickies = get_option('sticky_posts');
-
-       if ( !is_array($stickies) )
-               return;
-
-       if ( ! in_array($post_id, $stickies) )
-               return;
-
-       $offset = array_search($post_id, $stickies);
-       if ( false === $offset )
-               return;
-
-       array_splice($stickies, $offset, 1);
-
-       update_option('sticky_posts', $stickies);
-}
-
-/**
- * Return the cache key for wp_count_posts() based on the passed arguments.
- *
- * @since 3.9.0
- *
- * @param string $type Optional. Post type to retrieve count Default 'post'.
- * @param string $perm Optional. 'readable' or empty. Default empty.
- * @return string The cache key.
- */
-function _count_posts_cache_key( $type = 'post', $perm = '' ) {
-       $cache_key = 'posts-' . $type;
-       if ( 'readable' == $perm && is_user_logged_in() ) {
-               $post_type_object = get_post_type_object( $type );
-               if ( $post_type_object && ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
-                       $cache_key .= '_' . $perm . '_' . get_current_user_id();
-               }
-       }
-       return $cache_key;
-}
-
-/**
- * Count number of posts of a post type and if user has permissions to view.
- *
- * This function provides an efficient method of finding the amount of post's
- * type a blog has. Another method is to count the amount of items in
- * get_posts(), but that method has a lot of overhead with doing so. Therefore,
- * when developing for 2.5+, use this function instead.
- *
- * The $perm parameter checks for 'readable' value and if the user can read
- * private posts, it will display that for the user that is signed in.
- *
- * @since 2.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $type Optional. Post type to retrieve count. Default 'post'.
- * @param string $perm Optional. 'readable' or empty. Default empty.
- * @return object Number of posts for each status.
- */
-function wp_count_posts( $type = 'post', $perm = '' ) {
-       global $wpdb;
-
-       if ( ! post_type_exists( $type ) )
-               return new stdClass;
-
-       $cache_key = _count_posts_cache_key( $type, $perm );
-
-       $counts = wp_cache_get( $cache_key, 'counts' );
-       if ( false !== $counts ) {
-               /** This filter is documented in wp-includes/post-functions.php */
-               return apply_filters( 'wp_count_posts', $counts, $type, $perm );
-       }
-
-       $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
-       if ( 'readable' == $perm && is_user_logged_in() ) {
-               $post_type_object = get_post_type_object($type);
-               if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
-                       $query .= $wpdb->prepare( " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
-                               get_current_user_id()
-                       );
-               }
-       }
-       $query .= ' GROUP BY post_status';
-
-       $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
-       $counts = array_fill_keys( get_post_stati(), 0 );
-
-       foreach ( $results as $row ) {
-               $counts[ $row['post_status'] ] = $row['num_posts'];
-       }
-
-       $counts = (object) $counts;
-       wp_cache_set( $cache_key, $counts, 'counts' );
-
-       /**
-        * Modify returned post counts by status for the current post type.
-        *
-        * @since 3.7.0
-        *
-        * @param object $counts An object containing the current post_type's post
-        *                       counts by status.
-        * @param string $type   Post type.
-        * @param string $perm   The permission to determine if the posts are 'readable'
-        *                       by the current user.
-        */
-       return apply_filters( 'wp_count_posts', $counts, $type, $perm );
-}
-
-/**
- * Count number of attachments for the mime type(s).
- *
- * If you set the optional mime_type parameter, then an array will still be
- * returned, but will only have the item you are looking for. It does not give
- * you the number of attachments that are children of a post. You can get that
- * by counting the number of children that post has.
- *
- * @since 2.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string|array $mime_type Optional. Array or comma-separated list of
- *                                MIME patterns. Default empty.
- * @return object An object containing the attachment counts by mime type.
- */
-function wp_count_attachments( $mime_type = '' ) {
-       global $wpdb;
-
-       $and = wp_post_mime_type_where( $mime_type );
-       $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' $and GROUP BY post_mime_type", ARRAY_A );
-
-       $counts = array();
-       foreach ( (array) $count as $row ) {
-               $counts[ $row['post_mime_type'] ] = $row['num_posts'];
-       }
-       $counts['trash'] = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and");
-
-       /**
-        * Modify returned attachment counts by mime type.
-        *
-        * @since 3.7.0
-        *
-        * @param object $counts    An object containing the attachment counts by
-        *                          mime type.
-        * @param string $mime_type The mime type pattern used to filter the attachments
-        *                          counted.
-        */
-       return apply_filters( 'wp_count_attachments', (object) $counts, $mime_type );
-}
-
-/**
- * Get default post mime types.
- *
- * @since 2.9.0
- *
- * @return array List of post mime types.
- */
-function get_post_mime_types() {
-       $post_mime_types = array(       //      array( adj, noun )
-               'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
-               'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
-               'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
-       );
-
-       /**
-        * Filter the default list of post mime types.
-        *
-        * @since 2.5.0
-        *
-        * @param array $post_mime_types Default list of post mime types.
-        */
-       return apply_filters( 'post_mime_types', $post_mime_types );
-}
-
-/**
- * Check a MIME-Type against a list.
- *
- * If the wildcard_mime_types parameter is a string, it must be comma separated
- * list. If the real_mime_types is a string, it is also comma separated to
- * create the list.
- *
- * @since 2.5.0
- *
- * @param string|array $wildcard_mime_types Mime types, e.g. audio/mpeg or image (same as image/*)
- *                                          or flash (same as *flash*).
- * @param string|array $real_mime_types     Real post mime type values.
- * @return array array(wildcard=>array(real types)).
- */
-function wp_match_mime_types( $wildcard_mime_types, $real_mime_types ) {
-       $matches = array();
-       if ( is_string( $wildcard_mime_types ) ) {
-               $wildcard_mime_types = array_map( 'trim', explode( ',', $wildcard_mime_types ) );
-       }
-       if ( is_string( $real_mime_types ) ) {
-               $real_mime_types = array_map( 'trim', explode( ',', $real_mime_types ) );
-       }
-
-       $patternses = array();
-       $wild = '[-._a-z0-9]*';
-
-       foreach ( (array) $wildcard_mime_types as $type ) {
-               $mimes = array_map( 'trim', explode( ',', $type ) );
-               foreach ( $mimes as $mime ) {
-                       $regex = str_replace( '__wildcard__', $wild, preg_quote( str_replace( '*', '__wildcard__', $mime ) ) );
-                       $patternses[][$type] = "^$regex$";
-                       if ( false === strpos( $mime, '/' ) ) {
-                               $patternses[][$type] = "^$regex/";
-                               $patternses[][$type] = $regex;
-                       }
-               }
-       }
-       asort( $patternses );
-
-       foreach ( $patternses as $patterns ) {
-               foreach ( $patterns as $type => $pattern ) {
-                       foreach ( (array) $real_mime_types as $real ) {
-                               if ( preg_match( "#$pattern#", $real ) && ( empty( $matches[$type] ) || false === array_search( $real, $matches[$type] ) ) ) {
-                                       $matches[$type][] = $real;
-                               }
-                       }
-               }
-       }
-       return $matches;
-}
-
-/**
- * Convert MIME types into SQL.
- *
- * @since 2.5.0
- *
- * @param string|array $post_mime_types List of mime types or comma separated string
- *                                      of mime types.
- * @param string       $table_alias     Optional. Specify a table alias, if needed.
- *                                      Default empty.
- * @return string The SQL AND clause for mime searching.
- */
-function wp_post_mime_type_where( $post_mime_types, $table_alias = '' ) {
-       $where = '';
-       $wildcards = array('', '%', '%/%');
-       if ( is_string($post_mime_types) )
-               $post_mime_types = array_map('trim', explode(',', $post_mime_types));
-
-       $wheres = array();
-
-       foreach ( (array) $post_mime_types as $mime_type ) {
-               $mime_type = preg_replace('/\s/', '', $mime_type);
-               $slashpos = strpos($mime_type, '/');
-               if ( false !== $slashpos ) {
-                       $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
-                       $mime_subgroup = preg_replace('/[^-*.+a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
-                       if ( empty($mime_subgroup) )
-                               $mime_subgroup = '*';
-                       else
-                               $mime_subgroup = str_replace('/', '', $mime_subgroup);
-                       $mime_pattern = "$mime_group/$mime_subgroup";
-               } else {
-                       $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
-                       if ( false === strpos($mime_pattern, '*') )
-                               $mime_pattern .= '/*';
-               }
-
-               $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
-
-               if ( in_array( $mime_type, $wildcards ) )
-                       return '';
-
-               if ( false !== strpos($mime_pattern, '%') )
-                       $wheres[] = empty($table_alias) ? "post_mime_type LIKE '$mime_pattern'" : "$table_alias.post_mime_type LIKE '$mime_pattern'";
-               else
-                       $wheres[] = empty($table_alias) ? "post_mime_type = '$mime_pattern'" : "$table_alias.post_mime_type = '$mime_pattern'";
-       }
-       if ( !empty($wheres) )
-               $where = ' AND (' . join(' OR ', $wheres) . ') ';
-       return $where;
-}
-
-/**
- * Trash or delete a post or page.
- *
- * When the post and page is permanently deleted, everything that is tied to
- * it is deleted also. This includes comments, post meta fields, and terms
- * associated with the post.
- *
- * The post or page is moved to trash instead of permanently deleted unless
- * trash is disabled, item is already in the trash, or $force_delete is true.
- *
- * @since 1.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @see wp_delete_attachment()
- * @see wp_trash_post()
- *
- * @param int  $postid       Optional. Post ID. Default 0.
- * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
- *                           Default false.
- * @return array|false|WP_Post False on failure.
- */
-function wp_delete_post( $postid = 0, $force_delete = false ) {
-       global $wpdb;
-
-       if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
-               return $post;
-
-       if ( !$force_delete && ( $post->post_type == 'post' || $post->post_type == 'page') && get_post_status( $postid ) != 'trash' && EMPTY_TRASH_DAYS )
-               return wp_trash_post( $postid );
-
-       if ( $post->post_type == 'attachment' )
-               return wp_delete_attachment( $postid, $force_delete );
-
-       /**
-        * Filter whether a post deletion should take place.
-        *
-        * @since 4.4.0
-        *
-        * @param bool    $delete       Whether to go forward with deletion.
-        * @param WP_Post $post         Post object.
-        * @param bool    $force_delete Whether to bypass the trash.
-        */
-       $check = apply_filters( 'pre_delete_post', null, $post, $force_delete );
-       if ( null !== $check ) {
-               return $check;
-       }
-
-       /**
-        * Fires before a post is deleted, at the start of wp_delete_post().
-        *
-        * @since 3.2.0
-        *
-        * @see wp_delete_post()
-        *
-        * @param int $postid Post ID.
-        */
-       do_action( 'before_delete_post', $postid );
-
-       delete_post_meta($postid,'_wp_trash_meta_status');
-       delete_post_meta($postid,'_wp_trash_meta_time');
-
-       wp_delete_object_term_relationships($postid, get_object_taxonomies($post->post_type));
-
-       $parent_data = array( 'post_parent' => $post->post_parent );
-       $parent_where = array( 'post_parent' => $postid );
-
-       if ( is_post_type_hierarchical( $post->post_type ) ) {
-               // Point children of this page to its parent, also clean the cache of affected children.
-               $children_query = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $postid, $post->post_type );
-               $children = $wpdb->get_results( $children_query );
-
-               $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
-       }
-
-       // Do raw query. wp_get_post_revisions() is filtered.
-       $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
-       // Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
-       foreach ( $revision_ids as $revision_id )
-               wp_delete_post_revision( $revision_id );
-
-       // Point all attachments to this post up one level.
-       $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
-
-       wp_defer_comment_counting( true );
-
-       $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
-       foreach ( $comment_ids as $comment_id ) {
-               wp_delete_comment( $comment_id, true );
-       }
-
-       wp_defer_comment_counting( false );
-
-       $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
-       foreach ( $post_meta_ids as $mid )
-               delete_metadata_by_mid( 'post', $mid );
-
-       /**
-        * Fires immediately before a post is deleted from the database.
-        *
-        * @since 1.2.0
-        *
-        * @param int $postid Post ID.
-        */
-       do_action( 'delete_post', $postid );
-       $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) );
-       if ( ! $result ) {
-               return false;
-       }
-
-       /**
-        * Fires immediately after a post is deleted from the database.
-        *
-        * @since 2.2.0
-        *
-        * @param int $postid Post ID.
-        */
-       do_action( 'deleted_post', $postid );
-
-       clean_post_cache( $post );
-
-       if ( is_post_type_hierarchical( $post->post_type ) && $children ) {
-               foreach ( $children as $child )
-                       clean_post_cache( $child );
-       }
-
-       wp_clear_scheduled_hook('publish_future_post', array( $postid ) );
-
-       /**
-        * Fires after a post is deleted, at the conclusion of wp_delete_post().
-        *
-        * @since 3.2.0
-        *
-        * @see wp_delete_post()
-        *
-        * @param int $postid Post ID.
-        */
-       do_action( 'after_delete_post', $postid );
-
-       return $post;
-}
-
-/**
- * Reset the page_on_front, show_on_front, and page_for_post settings when
- * a linked page is deleted or trashed.
- *
- * Also ensures the post is no longer sticky.
- *
- * @since 3.7.0
- * @access private
- *
- * @param int $post_id Post ID.
- */
-function _reset_front_page_settings_for_post( $post_id ) {
-       $post = get_post( $post_id );
-       if ( 'page' == $post->post_type ) {
-               /*
-                * If the page is defined in option page_on_front or post_for_posts,
-                * adjust the corresponding options.
-                */
-               if ( get_option( 'page_on_front' ) == $post->ID ) {
-                       update_option( 'show_on_front', 'posts' );
-                       update_option( 'page_on_front', 0 );
-               }
-               if ( get_option( 'page_for_posts' ) == $post->ID ) {
-                       delete_option( 'page_for_posts', 0 );
-               }
-       }
-       unstick_post( $post->ID );
-}
-
-/**
- * Move a post or page to the Trash
- *
- * If trash is disabled, the post or page is permanently deleted.
- *
- * @since 2.9.0
- *
- * @see wp_delete_post()
- *
- * @param int $post_id Optional. Post ID. Default is ID of the global $post
- *                     if EMPTY_TRASH_DAYS equals true.
- * @return false|array|WP_Post|null Post data array, otherwise false.
- */
-function wp_trash_post( $post_id = 0 ) {
-       if ( !EMPTY_TRASH_DAYS )
-               return wp_delete_post($post_id, true);
-
-       if ( !$post = get_post($post_id, ARRAY_A) )
-               return $post;
-
-       if ( $post['post_status'] == 'trash' )
-               return false;
-
-       /**
-        * Fires before a post is sent to the trash.
-        *
-        * @since 3.3.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'wp_trash_post', $post_id );
-
-       add_post_meta($post_id,'_wp_trash_meta_status', $post['post_status']);
-       add_post_meta($post_id,'_wp_trash_meta_time', time());
-
-       $post['post_status'] = 'trash';
-       wp_insert_post( wp_slash( $post ) );
-
-       wp_trash_post_comments($post_id);
-
-       /**
-        * Fires after a post is sent to the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'trashed_post', $post_id );
-
-       return $post;
-}
-
-/**
- * Restore a post or page from the Trash.
- *
- * @since 2.9.0
- *
- * @param int $post_id Optional. Post ID. Default is ID of the global $post.
- * @return WP_Post|false WP_Post object. False on failure.
- */
-function wp_untrash_post( $post_id = 0 ) {
-       if ( !$post = get_post($post_id, ARRAY_A) )
-               return $post;
-
-       if ( $post['post_status'] != 'trash' )
-               return false;
-
-       /**
-        * Fires before a post is restored from the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'untrash_post', $post_id );
-
-       $post_status = get_post_meta($post_id, '_wp_trash_meta_status', true);
-
-       $post['post_status'] = $post_status;
-
-       delete_post_meta($post_id, '_wp_trash_meta_status');
-       delete_post_meta($post_id, '_wp_trash_meta_time');
-
-       wp_insert_post( wp_slash( $post ) );
-
-       wp_untrash_post_comments($post_id);
-
-       /**
-        * Fires after a post is restored from the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'untrashed_post', $post_id );
-
-       return $post;
-}
-
-/**
- * Moves comments for a post to the trash.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
- * @return mixed|void False on failure.
- */
-function wp_trash_post_comments( $post = null ) {
-       global $wpdb;
-
-       $post = get_post($post);
-       if ( empty($post) )
-               return;
-
-       $post_id = $post->ID;
-
-       /**
-        * Fires before comments are sent to the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'trash_post_comments', $post_id );
-
-       $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id) );
-       if ( empty($comments) )
-               return;
-
-       // Cache current status for each comment.
-       $statuses = array();
-       foreach ( $comments as $comment )
-               $statuses[$comment->comment_ID] = $comment->comment_approved;
-       add_post_meta($post_id, '_wp_trash_meta_comments_status', $statuses);
-
-       // Set status for all comments to post-trashed.
-       $result = $wpdb->update($wpdb->comments, array('comment_approved' => 'post-trashed'), array('comment_post_ID' => $post_id));
-
-       clean_comment_cache( array_keys($statuses) );
-
-       /**
-        * Fires after comments are sent to the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int   $post_id  Post ID.
-        * @param array $statuses Array of comment statuses.
-        */
-       do_action( 'trashed_post_comments', $post_id, $statuses );
-
-       return $result;
-}
-
-/**
- * Restore comments for a post from the trash.
- *
- * @since 2.9.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
- * @return true|void
- */
-function wp_untrash_post_comments( $post = null ) {
-       global $wpdb;
-
-       $post = get_post($post);
-       if ( empty($post) )
-               return;
-
-       $post_id = $post->ID;
-
-       $statuses = get_post_meta($post_id, '_wp_trash_meta_comments_status', true);
-
-       if ( empty($statuses) )
-               return true;
-
-       /**
-        * Fires before comments are restored for a post from the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'untrash_post_comments', $post_id );
-
-       // Restore each comment to its original status.
-       $group_by_status = array();
-       foreach ( $statuses as $comment_id => $comment_status )
-               $group_by_status[$comment_status][] = $comment_id;
-
-       foreach ( $group_by_status as $status => $comments ) {
-               // Sanity check. This shouldn't happen.
-               if ( 'post-trashed' == $status ) {
-                       $status = '0';
-               }
-               $comments_in = implode( ', ', array_map( 'intval', $comments ) );
-               $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) );
-       }
-
-       clean_comment_cache( array_keys($statuses) );
-
-       delete_post_meta($post_id, '_wp_trash_meta_comments_status');
-
-       /**
-        * Fires after comments are restored for a post from the trash.
-        *
-        * @since 2.9.0
-        *
-        * @param int $post_id Post ID.
-        */
-       do_action( 'untrashed_post_comments', $post_id );
-}
-
-/**
- * Retrieve the list of categories for a post.
- *
- * Compatibility layer for themes and plugins. Also an easy layer of abstraction
- * away from the complexity of the taxonomy layer.
- *
- * @since 2.1.0
- *
- * @see wp_get_object_terms()
- *
- * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
- *                       global $post. Default 0.
- * @param array $args    Optional. Category arguments. Default empty.
- * @return array List of categories.
- */
-function wp_get_post_categories( $post_id = 0, $args = array() ) {
-       $post_id = (int) $post_id;
-
-       $defaults = array('fields' => 'ids');
-       $args = wp_parse_args( $args, $defaults );
-
-       $cats = wp_get_object_terms($post_id, 'category', $args);
-       return $cats;
-}
-
-/**
- * Retrieve the tags for a post.
- *
- * There is only one default for this function, called 'fields' and by default
- * is set to 'all'. There are other defaults that can be overridden in
- * {@link wp_get_object_terms()}.
- *
- * @since 2.3.0
- *
- * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
- *                       global $post. Default 0.
- * @param array $args Optional. Overwrite the defaults
- * @return array List of post tags.
- */
-function wp_get_post_tags( $post_id = 0, $args = array() ) {
-       return wp_get_post_terms( $post_id, 'post_tag', $args);
-}
-
-/**
- * Retrieve the terms for a post.
- *
- * There is only one default for this function, called 'fields' and by default
- * is set to 'all'. There are other defaults that can be overridden in
- * {@link wp_get_object_terms()}.
- *
- * @since 2.8.0
- *
- * @param int    $post_id  Optional. The Post ID. Does not default to the ID of the
- *                         global $post. Default 0.
- * @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
- * @param array  $args     Optional. {@link wp_get_object_terms()} arguments. Default empty array.
- * @return array|WP_Error  List of post terms or empty array if no terms were found. WP_Error object
- *                         if `$taxonomy` doesn't exist.
- */
-function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
-       $post_id = (int) $post_id;
-
-       $defaults = array('fields' => 'all');
-       $args = wp_parse_args( $args, $defaults );
-
-       $tags = wp_get_object_terms($post_id, $taxonomy, $args);
-
-       return $tags;
-}
-
-/**
- * Retrieve a number of recent posts.
- *
- * @since 1.0.0
- *
- * @see get_posts()
- *
- * @param array  $args       Optional. Arguments to retrieve posts. Default empty array.
- * @param string $output     Optional. Type of output. Accepts ARRAY_A or ''. Default ARRAY_A.
- * @return array|false Associative array if $output equals ARRAY_A, array or false if no results.
- */
-function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) {
-
-       if ( is_numeric( $args ) ) {
-               _deprecated_argument( __FUNCTION__, '3.1', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
-               $args = array( 'numberposts' => absint( $args ) );
-       }
-
-       // Set default arguments.
-       $defaults = array(
-               'numberposts' => 10, 'offset' => 0,
-               'category' => 0, 'orderby' => 'post_date',
-               'order' => 'DESC', 'include' => '',
-               'exclude' => '', 'meta_key' => '',
-               'meta_value' =>'', 'post_type' => 'post', 'post_status' => 'draft, publish, future, pending, private',
-               'suppress_filters' => true
-       );
-
-       $r = wp_parse_args( $args, $defaults );
-
-       $results = get_posts( $r );
-
-       // Backward compatibility. Prior to 3.1 expected posts to be returned in array.
-       if ( ARRAY_A == $output ){
-               foreach ( $results as $key => $result ) {
-                       $results[$key] = get_object_vars( $result );
-               }
-               return $results ? $results : array();
-       }
-
-       return $results ? $results : false;
-
-}
-
-/**
- * Insert or update a post.
- *
- * If the $postarr parameter has 'ID' set to a value, then post will be updated.
- *
- * You can set the post date manually, by 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.
- *
- * @since 1.0.0
- * @since 4.2.0 Support was added for encoding emoji in the post title, content, and excerpt.
- * @since 4.4.0 A 'meta_input' array can now be passed to `$postarr` to add post meta data.
- *
- * @see sanitize_post()
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $postarr {
- *     An array of elements that make up a post to update or insert.
- *
- *     @type int    $ID                    The post ID. If equal to something other than 0,
- *                                         the post with that ID will be updated. Default 0.
- *     @type int    $post_author           The ID of the user who added the post. Default is
- *                                         the current user ID.
- *     @type string $post_date             The date of the post. Default is the current time.
- *     @type string $post_date_gmt         The date of the post in the GMT timezone. Default is
- *                                         the value of `$post_date`.
- *     @type mixed  $post_content          The post content. Default empty.
- *     @type string $post_content_filtered The filtered post content. Default empty.
- *     @type string $post_title            The post title. Default empty.
- *     @type string $post_excerpt          The post excerpt. Default empty.
- *     @type string $post_status           The post status. Default 'draft'.
- *     @type string $post_type             The post type. Default 'post'.
- *     @type string $comment_status        Whether the post can accept comments. Accepts 'open' or 'closed'.
- *                                         Default is the value of 'default_comment_status' option.
- *     @type string $ping_status           Whether the post can accept pings. Accepts 'open' or 'closed'.
- *                                         Default is the value of 'default_ping_status' option.
- *     @type string $post_password         The password to access the post. Default empty.
- *     @type string $post_name             The post name. Default is the sanitized post title.
- *     @type string $to_ping               Space or carriage return-separated list of URLs to ping.
- *                                         Default empty.
- *     @type string $pinged                Space or carriage return-separated list of URLs that have
- *                                         been pinged. Default empty.
- *     @type string $post_modified         The date when the post was last modified. Default is
- *                                         the current time.
- *     @type string $post_modified_gmt     The date when the post was last modified in the GMT
- *                                         timezone. Default is the current time.
- *     @type int    $post_parent           Set this for the post it belongs to, if any. Default 0.
- *     @type int    $menu_order            The order the post should be displayed in. Default 0.
- *     @type string $post_mime_type        The mime type of the post. Default empty.
- *     @type string $guid                  Global Unique ID for referencing the post. Default empty.
- *     @type array  $tax_input             Array of taxonomy terms keyed by their taxonomy name. Default empty.
- *     @type array  $meta_input            Array of post meta values keyed by their post meta key. Default empty.
- * }
- * @param bool  $wp_error Optional. Whether to allow return of WP_Error on failure. Default false.
- * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure.
- */
-function wp_insert_post( $postarr, $wp_error = false ) {
-       global $wpdb;
-
-       $user_id = get_current_user_id();
-
-       $defaults = array(
-               'post_author' => $user_id,
-               'post_content' => '',
-               'post_content_filtered' => '',
-               'post_title' => '',
-               'post_excerpt' => '',
-               'post_status' => 'draft',
-               'post_type' => 'post',
-               'comment_status' => '',
-               'ping_status' => '',
-               'post_password' => '',
-               'to_ping' =>  '',
-               'pinged' => '',
-               'post_parent' => 0,
-               'menu_order' => 0,
-               'guid' => '',
-               'import_id' => 0,
-               'context' => '',
-       );
-
-       $postarr = wp_parse_args($postarr, $defaults);
-
-       unset( $postarr[ 'filter' ] );
-
-       $postarr = sanitize_post($postarr, 'db');
-
-       // Are we updating or creating?
-       $post_ID = 0;
-       $update = false;
-       $guid = $postarr['guid'];
-
-       if ( ! empty( $postarr['ID'] ) ) {
-               $update = true;
-
-               // Get the post ID and GUID.
-               $post_ID = $postarr['ID'];
-               $post_before = get_post( $post_ID );
-               if ( is_null( $post_before ) ) {
-                       if ( $wp_error ) {
-                               return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
-                       }
-                       return 0;
-               }
-
-               $guid = get_post_field( 'guid', $post_ID );
-               $previous_status = get_post_field('post_status', $post_ID );
-       } else {
-               $previous_status = 'new';
-       }
-
-       $post_type = empty( $postarr['post_type'] ) ? 'post' : $postarr['post_type'];
-
-       $post_title = $postarr['post_title'];
-       $post_content = $postarr['post_content'];
-       $post_excerpt = $postarr['post_excerpt'];
-       if ( isset( $postarr['post_name'] ) ) {
-               $post_name = $postarr['post_name'];
-       }
-
-       $maybe_empty = 'attachment' !== $post_type
-               && ! $post_content && ! $post_title && ! $post_excerpt
-               && post_type_supports( $post_type, 'editor' )
-               && post_type_supports( $post_type, 'title' )
-               && post_type_supports( $post_type, 'excerpt' );
-
-       /**
-        * Filter whether the post should be considered "empty".
-        *
-        * The post is considered "empty" if both:
-        * 1. The post type supports the title, editor, and excerpt fields
-        * 2. The title, editor, and excerpt fields are all empty
-        *
-        * Returning a truthy value to the filter will effectively short-circuit
-        * the new post being inserted, returning 0. If $wp_error is true, a WP_Error
-        * will be returned instead.
-        *
-        * @since 3.3.0
-        *
-        * @param bool  $maybe_empty Whether the post should be considered "empty".
-        * @param array $postarr     Array of post data.
-        */
-       if ( apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $postarr ) ) {
-               if ( $wp_error ) {
-                       return new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.' ) );
-               } else {
-                       return 0;
-               }
-       }
-
-       $post_status = empty( $postarr['post_status'] ) ? 'draft' : $postarr['post_status'];
-       if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash' ) ) ) {
-               $post_status = 'inherit';
-       }
-
-       if ( ! empty( $postarr['post_category'] ) ) {
-               // Filter out empty terms.
-               $post_category = array_filter( $postarr['post_category'] );
-       }
-
-       // 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();
-               }
-       }
-
-       // Don't allow contributors 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 {
-               // On updates, we need to check to see if it's using the old, fixed sanitization context.
-               $check_name = sanitize_title( $post_name, '', 'old-save' );
-               if ( $update && strtolower( urlencode( $post_name ) ) == $check_name && get_post_field( 'post_name', $post_ID ) == $check_name ) {
-                       $post_name = $check_name;
-               } else { // new post, or slug has changed.
-                       $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( $postarr['post_date'] ) || '0000-00-00 00:00:00' == $postarr['post_date'] ) {
-               if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['post_date_gmt'] ) {
-                       $post_date = current_time( 'mysql' );
-               } else {
-                       $post_date = get_date_from_gmt( $postarr['post_date_gmt'] );
-               }
-       } else {
-               $post_date = $postarr['post_date'];
-       }
-
-       // Validate the date.
-       $mm = substr( $post_date, 5, 2 );
-       $jj = substr( $post_date, 8, 2 );
-       $aa = substr( $post_date, 0, 4 );
-       $valid_date = wp_checkdate( $mm, $jj, $aa, $post_date );
-       if ( ! $valid_date ) {
-               if ( $wp_error ) {
-                       return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
-               } else {
-                       return 0;
-               }
-       }
-
-       if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['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';
-               }
-       } else {
-               $post_date_gmt = $postarr['post_date_gmt'];
-       }
-
-       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 ( 'attachment' !== $post_type ) {
-               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';
-                       }
-               }
-       }
-
-       // Comment status.
-       if ( empty( $postarr['comment_status'] ) ) {
-               if ( $update ) {
-                       $comment_status = 'closed';
-               } else {
-                       $comment_status = get_default_comment_status( $post_type );
-               }
-       } else {
-               $comment_status = $postarr['comment_status'];
-       }
-
-       // These variables are needed by compact() later.
-       $post_content_filtered = $postarr['post_content_filtered'];
-       $post_author = isset( $postarr['post_author'] ) ? $postarr['post_author'] : $user_id;
-       $ping_status = empty( $postarr['ping_status'] ) ? get_default_comment_status( $post_type, 'pingback' ) : $postarr['ping_status'];
-       $to_ping = isset( $postarr['to_ping'] ) ? sanitize_trackback_urls( $postarr['to_ping'] ) : '';
-       $pinged = isset( $postarr['pinged'] ) ? $postarr['pinged'] : '';
-       $import_id = isset( $postarr['import_id'] ) ? $postarr['import_id'] : 0;
-
-       /*
-        * The 'wp_insert_post_parent' filter expects all variables to be present.
-        * Previously, these variables would have already been extracted
-        */
-       if ( isset( $postarr['menu_order'] ) ) {
-               $menu_order = (int) $postarr['menu_order'];
-       } else {
-               $menu_order = 0;
-       }
-
-       $post_password = isset( $postarr['post_password'] ) ? $postarr['post_password'] : '';
-       if ( 'private' == $post_status ) {
-               $post_password = '';
-       }
-
-       if ( isset( $postarr['post_parent'] ) ) {
-               $post_parent = (int) $postarr['post_parent'];
-       } else {
-               $post_parent = 0;
-       }
-
-       /**
-        * Filter the post parent -- used to check for and prevent hierarchy loops.
-        *
-        * @since 3.1.0
-        *
-        * @param int   $post_parent Post parent ID.
-        * @param int   $post_ID     Post ID.
-        * @param array $new_postarr Array of parsed post data.
-        * @param array $postarr     Array of sanitized, but otherwise unmodified post data.
-        */
-       $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
-
-       $post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent );
-
-       // Don't unslash.
-       $post_mime_type = isset( $postarr['post_mime_type'] ) ? $postarr['post_mime_type'] : '';
-
-       // Expected_slashed (everything!).
-       $data = compact( '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' );
-
-       $emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' );
-
-       foreach ( $emoji_fields as $emoji_field ) {
-               if ( isset( $data[ $emoji_field ] ) ) {
-                       $charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field );
-                       if ( 'utf8' === $charset ) {
-                               $data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] );
-                       }
-               }
-       }
-
-       if ( 'attachment' === $post_type ) {
-               /**
-                * Filter attachment post data before it is updated in or added to the database.
-                *
-                * @since 3.9.0
-                *
-                * @param array $data    An array of sanitized attachment post data.
-                * @param array $postarr An array of unsanitized attachment post data.
-                */
-               $data = apply_filters( 'wp_insert_attachment_data', $data, $postarr );
-       } else {
-               /**
-                * Filter slashed post data just before it is inserted into the database.
-                *
-                * @since 2.7.0
-                *
-                * @param array $data    An array of slashed post data.
-                * @param array $postarr An array of sanitized, but otherwise unmodified post data.
-                */
-               $data = apply_filters( 'wp_insert_post_data', $data, $postarr );
-       }
-       $data = wp_unslash( $data );
-       $where = array( 'ID' => $post_ID );
-
-       if ( $update ) {
-               /**
-                * Fires immediately before an existing post is updated in the database.
-                *
-                * @since 2.5.0
-                *
-                * @param int   $post_ID Post ID.
-                * @param array $data    Array of unslashed post data.
-                */
-               do_action( 'pre_post_update', $post_ID, $data );
-               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 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'] = wp_unique_post_slug( sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data['post_status'], $post_type, $post_parent );
-               $wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
-               clean_post_cache( $post_ID );
-       }
-
-       if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
-               wp_set_post_categories( $post_ID, $post_category );
-       }
-
-       if ( isset( $postarr['tags_input'] ) && is_object_in_taxonomy( $post_type, 'post_tag' ) ) {
-               wp_set_post_tags( $post_ID, $postarr['tags_input'] );
-       }
-
-       // New-style support for all custom taxonomies.
-       if ( ! empty( $postarr['tax_input'] ) ) {
-               foreach ( $postarr['tax_input'] as $taxonomy => $tags ) {
-                       $taxonomy_obj = get_taxonomy($taxonomy);
-                       if ( ! $taxonomy_obj ) {
-                               /* translators: %s: taxonomy name */
-                               _doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid taxonomy: %s.' ), $taxonomy ), '4.4.0' );
-                               continue;
-                       }
-
-                       // array = hierarchical, string = non-hierarchical.
-                       if ( is_array( $tags ) ) {
-                               $tags = array_filter($tags);
-                       }
-                       if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
-                               wp_set_post_terms( $post_ID, $tags, $taxonomy );
-                       }
-               }
-       }
-
-       if ( ! empty( $postarr['meta_input'] ) ) {
-               foreach ( $postarr['meta_input'] as $field => $value ) {
-                       update_post_meta( $post_ID, $field, $value );
-               }
-       }
-
-       $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 );
-       }
-
-       if ( 'attachment' === $postarr['post_type'] ) {
-               if ( ! empty( $postarr['file'] ) ) {
-                       update_attached_file( $post_ID, $postarr['file'] );
-               }
-
-               if ( ! empty( $postarr['context'] ) ) {
-                       add_post_meta( $post_ID, '_wp_attachment_context', $postarr['context'], true );
-               }
-       }
-
-       clean_post_cache( $post_ID );
-
-       $post = get_post( $post_ID );
-
-       if ( ! empty( $postarr['page_template'] ) && 'page' == $data['post_type'] ) {
-               $post->page_template = $postarr['page_template'];
-               $page_templates = wp_get_theme()->get_page_templates( $post );
-               if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) {
-                       if ( $wp_error ) {
-                               return new WP_Error('invalid_page_template', __('The page template is invalid.'));
-                       }
-                       update_post_meta( $post_ID, '_wp_page_template', 'default' );
-               } else {
-                       update_post_meta( $post_ID, '_wp_page_template', $postarr['page_template'] );
-               }
-       }
-
-       if ( 'attachment' !== $postarr['post_type'] ) {
-               wp_transition_post_status( $data['post_status'], $previous_status, $post );
-       } else {
-               if ( $update ) {
-                       /**
-                        * Fires once an existing attachment has been updated.
-                        *
-                        * @since 2.0.0
-                        *
-                        * @param int $post_ID Attachment ID.
-                        */
-                       do_action( 'edit_attachment', $post_ID );
-                       $post_after = get_post( $post_ID );
-
-                       /**
-                        * Fires once an existing attachment has been updated.
-                        *
-                        * @since 4.4.0
-                        *
-                        * @param int     $post_ID      Post ID.
-                        * @param WP_Post $post_after   Post object following the update.
-                        * @param WP_Post $post_before  Post object before the update.
-                        */
-                       do_action( 'attachment_updated', $post_ID, $post_after, $post_before );
-               } else {
-
-                       /**
-                        * Fires once an attachment has been added.
-                        *
-                        * @since 2.0.0
-                        *
-                        * @param int $post_ID Attachment ID.
-                        */
-                       do_action( 'add_attachment', $post_ID );
-               }
-
-               return $post_ID;
-       }
-
-       if ( $update ) {
-               /**
-                * Fires once an existing post has been updated.
-                *
-                * @since 1.2.0
-                *
-                * @param int     $post_ID Post ID.
-                * @param WP_Post $post    Post object.
-                */
-               do_action( 'edit_post', $post_ID, $post );
-               $post_after = get_post($post_ID);
-
-               /**
-                * Fires once an existing post has been updated.
-                *
-                * @since 3.0.0
-                *
-                * @param int     $post_ID      Post ID.
-                * @param WP_Post $post_after   Post object following the update.
-                * @param WP_Post $post_before  Post object before the update.
-                */
-               do_action( 'post_updated', $post_ID, $post_after, $post_before);
-       }
-
-       /**
-        * Fires once a post has been saved.
-        *
-        * The dynamic portion of the hook name, `$post->post_type`, refers to
-        * the post type slug.
-        *
-        * @since 3.7.0
-        *
-        * @param int     $post_ID Post ID.
-        * @param WP_Post $post    Post object.
-        * @param bool    $update  Whether this is an existing post being updated or not.
-        */
-       do_action( "save_post_{$post->post_type}", $post_ID, $post, $update );
-
-       /**
-        * Fires once a post has been saved.
-        *
-        * @since 1.5.0
-        *
-        * @param int     $post_ID Post ID.
-        * @param WP_Post $post    Post object.
-        * @param bool    $update  Whether this is an existing post being updated or not.
-        */
-       do_action( 'save_post', $post_ID, $post, $update );
-
-       /**
-        * Fires once a post has been saved.
-        *
-        * @since 2.0.0
-        *
-        * @param int     $post_ID Post ID.
-        * @param WP_Post $post    Post object.
-        * @param bool    $update  Whether this is an existing post being updated or not.
-        */
-       do_action( 'wp_insert_post', $post_ID, $post, $update );
-
-       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  Optional. Post data. Arrays are expected to be escaped,
- *                               objects are not. Default array.
- * @param bool         $wp_error Optional. Allow return of WP_Error on failure. Default false.
- * @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 = wp_slash($postarr);
-       }
-
-       // First, get all of the original fields.
-       $post = get_post($postarr['ID'], ARRAY_A);
-
-       if ( is_null( $post ) ) {
-               if ( $wp_error )
-                       return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
-               return 0;
-       }
-
-       // Escape data pulled from DB.
-       $post = wp_slash($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
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|WP_Post $post Post ID or post object.
- */
-function wp_publish_post( $post ) {
-       global $wpdb;
-
-       if ( ! $post = get_post( $post ) )
-               return;
-
-       if ( 'publish' == $post->post_status )
-               return;
-
-       $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post->ID ) );
-
-       clean_post_cache( $post->ID );
-
-       $old_status = $post->post_status;
-       $post->post_status = 'publish';
-       wp_transition_post_status( 'publish', $old_status, $post );
-
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'edit_post', $post->ID, $post );
-
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( "save_post_{$post->post_type}", $post->ID, $post, true );
-
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'save_post', $post->ID, $post, true );
-
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'wp_insert_post', $post->ID, $post, true );
-}
-
-/**
- * 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|WP_Post $post_id Post ID or post object.
- */
-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' );
-
-       // Uh oh, someone jumped the gun!
-       if ( $time > time() ) {
-               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;
-       }
-
-       // wp_publish_post(_ returns no meaningful value.
-       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 WordPress database abstraction object.
- * @global WP_Rewrite $wp_rewrite
- *
- * @param string $slug        The desired slug (post_name).
- * @param int    $post_ID     Post ID.
- * @param string $post_status No uniqueness checks are made if the post is still draft or pending.
- * @param string $post_type   Post type.
- * @param int    $post_parent Post parent ID.
- * @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' ) ) || ( 'inherit' == $post_status && 'revision' == $post_type ) )
-               return $slug;
-
-       global $wpdb, $wp_rewrite;
-
-       $original_slug = $slug;
-
-       $feeds = $wp_rewrite->feeds;
-       if ( ! is_array( $feeds ) )
-               $feeds = array();
-
-       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 ) );
-
-               /**
-                * Filter whether the post slug would make a bad attachment slug.
-                *
-                * @since 3.1.0
-                *
-                * @param bool   $bad_slug Whether the slug would be bad as an attachment slug.
-                * @param string $slug     The post slug.
-                */
-               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 = _truncate_post_slug( $slug, 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 ( is_post_type_hierarchical( $post_type ) ) {
-               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 ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1";
-               $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );
-
-               /**
-                * Filter whether the post slug would make a bad hierarchical post slug.
-                *
-                * @since 3.1.0
-                *
-                * @param bool   $bad_slug    Whether the post slug would be bad in a hierarchical post context.
-                * @param string $slug        The post slug.
-                * @param string $post_type   Post type.
-                * @param int    $post_parent Post parent ID.
-                */
-               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 = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
-                               $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $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 ) );
-
-               // Prevent new post slugs that could result in URLs that conflict with date archives.
-               $post = get_post( $post_ID );
-               $conflicts_with_date_archive = false;
-               if ( 'post' === $post_type && ( ! $post || $post->post_name !== $slug ) && preg_match( '/^[0-9]+$/', $slug ) && $slug_num = intval( $slug ) ) {
-                       $permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
-                       $postname_index = array_search( '%postname%', $permastructs );
-
-                       /*
-                        * Potential date clashes are as follows:
-                        *
-                        * - Any integer in the first permastruct position could be a year.
-                        * - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum'.
-                        * - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day'.
-                        */
-                       if ( 0 === $postname_index ||
-                               ( $postname_index && '%year%' === $permastructs[ $postname_index - 1 ] && 13 > $slug_num ) ||
-                               ( $postname_index && '%monthnum%' === $permastructs[ $postname_index - 1 ] && 32 > $slug_num )
-                       ) {
-                               $conflicts_with_date_archive = true;
-                       }
-               }
-
-               /**
-                * Filter whether the post slug would be bad as a flat slug.
-                *
-                * @since 3.1.0
-                *
-                * @param bool   $bad_slug  Whether the post slug would be bad as a flat slug.
-                * @param string $slug      The post slug.
-                * @param string $post_type Post type.
-                */
-               if ( $post_name_check || in_array( $slug, $feeds ) || $conflicts_with_date_archive || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
-                       $suffix = 2;
-                       do {
-                               $alt_post_name = _truncate_post_slug( $slug, 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;
-               }
-       }
-
-       /**
-        * Filter the unique post slug.
-        *
-        * @since 3.3.0
-        *
-        * @param string $slug          The post slug.
-        * @param int    $post_ID       Post ID.
-        * @param string $post_status   The post status.
-        * @param string $post_type     Post type.
-        * @param int    $post_parent   Post parent ID
-        * @param string $original_slug The original post slug.
-        */
-       return apply_filters( 'wp_unique_post_slug', $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug );
-}
-
-/**
- * Truncate a post slug.
- *
- * @since 3.6.0
- * @access private
- *
- * @see utf8_uri_encode()
- *
- * @param string $slug   The slug to truncate.
- * @param int    $length Optional. Max length of the slug. Default 200 (characters).
- * @return string The truncated slug.
- */
-function _truncate_post_slug( $slug, $length = 200 ) {
-       if ( strlen( $slug ) > $length ) {
-               $decoded_slug = urldecode( $slug );
-               if ( $decoded_slug === $slug )
-                       $slug = substr( $slug, 0, $length );
-               else
-                       $slug = utf8_uri_encode( $decoded_slug, $length );
-       }
-
-       return rtrim( $slug, '-' );
-}
-
-/**
- * Add tags to a post.
- *
- * @see wp_set_post_tags()
- *
- * @since 2.3.0
- *
- * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
- * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
- *                              separated by commas. Default empty.
- * @return array|false|WP_Error Array of affected term IDs. WP_Error or false on failure.
- */
-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
- *
- * @see wp_set_object_terms()
- *
- * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
- * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
- *                              separated by commas. Default empty.
- * @param bool         $append  Optional. If true, don't delete existing tags, just add on. If false,
- *                              replace the tags with the new tags. Default false.
- * @return array|false|WP_Error 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
- *
- * @see wp_set_object_terms()
- *
- * @param int          $post_id  Optional. The Post ID. Does not default to the ID of the global $post.
- * @param string|array $tags     Optional. An array of terms to set for the post, or a string of terms
- *                               separated by commas. Default empty.
- * @param string       $taxonomy Optional. Taxonomy name. Default 'post_tag'.
- * @param bool         $append   Optional. If true, don't delete existing terms, just add on. If false,
- *                               replace the terms with the new terms. Default false.
- * @return array|false|WP_Error 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         Optional. The Post ID. Does not default to the ID
- *                                   of the global $post. Default 0.
- * @param array|int $post_categories Optional. List of categories or ID of category.
- *                                   Default empty array.
- * @param bool      $append         If true, don't delete existing categories, just add on.
- *                                  If false, replace the categories with the new categories.
- * @return array|bool|WP_Error
- */
-function wp_set_post_categories( $post_ID = 0, $post_categories = array(), $append = false ) {
-       $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:
-       $post_categories = (array) $post_categories;
-       if ( empty( $post_categories ) ) {
-               if ( 'post' == $post_type && 'auto-draft' != $post_status ) {
-                       $post_categories = array( get_option('default_category') );
-                       $append = false;
-               } else {
-                       $post_categories = array();
-               }
-       } elseif ( 1 == count( $post_categories ) && '' == reset( $post_categories ) ) {
-               return true;
-       }
-
-       return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
-}
-
-/**
- * Fires actions related to the transitioning of a post's status.
- *
- * When a post is saved, the post status is "transitioned" from one status to another,
- * though this does not always mean the status has actually changed before and after
- * the save. This function fires a number of action hooks related to that transition:
- * the generic 'transition_post_status' action, as well as the dynamic hooks
- * `"{$old_status}_to_{$new_status}"` and `"{$new_status}_{$post->post_type}"`. Note
- * that the function does not transition the post object in the database.
- *
- * For instance: When publishing a post for the first time, the post status may transition
- * from 'draft' â€“ or some other status â€“ to 'publish'. However, if a post is already
- * published and is simply being updated, the "old" and "new" statuses may both be 'publish'
- * before and after the transition.
- *
- * @since 2.3.0
- *
- * @param string  $new_status Transition to this post status.
- * @param string  $old_status Previous post status.
- * @param WP_Post $post Post data.
- */
-function wp_transition_post_status( $new_status, $old_status, $post ) {
-       /**
-        * Fires when a post is transitioned from one status to another.
-        *
-        * @since 2.3.0
-        *
-        * @param string  $new_status New post status.
-        * @param string  $old_status Old post status.
-        * @param WP_Post $post       Post object.
-        */
-       do_action( 'transition_post_status', $new_status, $old_status, $post );
-
-       /**
-        * Fires when a post is transitioned from one status to another.
-        *
-        * The dynamic portions of the hook name, `$new_status` and `$old status`,
-        * refer to the old and new post statuses, respectively.
-        *
-        * @since 2.3.0
-        *
-        * @param WP_Post $post Post object.
-        */
-       do_action( "{$old_status}_to_{$new_status}", $post );
-
-       /**
-        * Fires when a post is transitioned from one status to another.
-        *
-        * The dynamic portions of the hook name, `$new_status` and `$post->post_type`,
-        * refer to the new post status and post type, respectively.
-        *
-        * Please note: When this action is hooked using a particular post status (like
-        * 'publish', as `publish_{$post->post_type}`), it will fire both when a post is
-        * first transitioned to that status from something else, as well as upon
-        * subsequent post updates (old and new status are both the same).
-        *
-        * Therefore, if you are looking to only fire a callback when a post is first
-        * transitioned to a status, use the {@see 'transition_post_status'} hook instead.
-        *
-        * @since 2.3.0
-        *
-        * @param int     $post_id Post ID.
-        * @param WP_Post $post    Post object.
-        */
-       do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
-}
-
-//
-// Comment, trackback, and pingback functions.
-//
-
-/**
- * Add a URL to those already pinged.
- *
- * @since 1.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int    $post_id Post ID.
- * @param string $uri     Ping URI.
- * @return int|false 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);
-
-       /**
-        * Filter the new ping URL to add for the given post.
-        *
-        * @since 2.0.0
-        *
-        * @param string $new New ping URL to add.
-        */
-       $new = apply_filters( 'add_ping', $new );
-
-       // expected_slashed ($new).
-       $new = wp_unslash($new);
-       return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
-}
-
-/**
- * Retrieve enclosures already enclosed for a post.
- *
- * @since 1.5.0
- *
- * @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 ] );
-               }
-       }
-
-       /**
-        * Filter the list of enclosures already enclosed for the given post.
-        *
-        * @since 2.0.0
-        *
-        * @param array $pung    Array of enclosures for the given post.
-        * @param int   $post_id Post ID.
-        */
-       return apply_filters( 'get_enclosed', $pung, $post_id );
-}
-
-/**
- * Retrieve URLs already pinged for a post.
- *
- * @since 1.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @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);
-
-       /**
-        * Filter the list of already-pinged URLs for the given post.
-        *
-        * @since 2.0.0
-        *
-        * @param array $pung Array of URLs already pinged for the given post.
-        */
-       return apply_filters( 'get_pung', $pung );
-}
-
-/**
- * Retrieve URLs that need to be pinged.
- *
- * @since 1.5.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @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);
-
-       /**
-        * Filter the list of URLs yet to ping for the given post.
-        *
-        * @since 2.0.0
-        *
-        * @param array $to_ping List of URLs yet to ping.
-        */
-       return apply_filters( 'get_to_ping', $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 );
-
-               // Form an excerpt.
-               $excerpt = strip_tags( $postdata['post_excerpt'] ? $postdata['post_excerpt'] : $postdata['post_content'] );
-
-               if ( strlen( $excerpt ) > 255 ) {
-                       $excerpt = substr( $excerpt, 0, 252 ) . '&hellip;';
-               }
-
-               $trackback_urls = explode( ',', $tb_list );
-               foreach ( (array) $trackback_urls as $tb_url ) {
-                       $tb_url = trim( $tb_url );
-                       trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id );
-               }
-       }
-}
-
-//
-// Page functions
-//
-
-/**
- * Get a list of page IDs.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @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 Use get_post()
- *
- * @param mixed  $page   Page object or page ID. Passed by reference.
- * @param string $output Optional. What to output. Accepts OBJECT, ARRAY_A, or ARRAY_N.
- *                       Default OBJECT.
- * @param string $filter Optional. How the return value should be filtered. Accepts 'raw',
- *                       'edit', 'db', 'display'. Default 'raw'.
- * @return WP_Post|array|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
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string       $page_path Page path.
- * @param string       $output    Optional. Output type. Accepts OBJECT, ARRAY_N, or ARRAY_A.
- *                                Default OBJECT.
- * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
- * @return WP_Post|array|void WP_Post on success.
- */
-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 = esc_sql( $parts );
-       $parts = array_map( 'sanitize_title_for_query', $parts );
-
-       $in_string = "'" . implode( "','", $parts ) . "'";
-
-       if ( is_array( $post_type ) ) {
-               $post_types = $post_type;
-       } else {
-               $post_types = array( $post_type, 'attachment' );
-       }
-
-       $post_types = esc_sql( $post_types );
-       $post_type_in_string = "'" . implode( "','", $post_types ) . "'";
-       $sql = "
-               SELECT ID, post_name, post_parent, post_type
-               FROM $wpdb->posts
-               WHERE post_name IN ($in_string)
-               AND post_type IN ($post_type_in_string)
-       ";
-
-       $pages = $wpdb->get_results( $sql, 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 );
-       }
-}
-
-/**
- * Retrieve a page given its title.
- *
- * @since 2.1.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string       $page_title Page title
- * @param string       $output     Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A.
- *                                 Default OBJECT.
- * @param string|array $post_type  Optional. Post type or array of post types. Default 'page'.
- * @return WP_Post|array|void WP_Post on success or null on failure
- */
-function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
-       global $wpdb;
-
-       if ( is_array( $post_type ) ) {
-               $post_type = esc_sql( $post_type );
-               $post_type_in_string = "'" . implode( "','", $post_type ) . "'";
-               $sql = $wpdb->prepare( "
-                       SELECT ID
-                       FROM $wpdb->posts
-                       WHERE post_title = %s
-                       AND post_type IN ($post_type_in_string)
-               ", $page_title );
-       } else {
-               $sql = $wpdb->prepare( "
-                       SELECT ID
-                       FROM $wpdb->posts
-                       WHERE post_title = %s
-                       AND post_type = %s
-               ", $page_title, $post_type );
-       }
-
-       $page = $wpdb->get_var( $sql );
-
-       if ( $page ) {
-               return get_post( $page, $output );
-       }
-}
-
-/**
- * Identify descendants of a given page ID in a list of page objects.
- *
- * Descendants are identified from the `$pages` array passed to the function. No database queries are performed.
- *
- * @since 1.5.1
- *
- * @param int   $page_id Page ID.
- * @param array $pages   List of page objects from which descendants should be identified.
- * @return array List of page children.
- */
-function get_page_children( $page_id, $pages ) {
-       // Build a hash of ID -> children.
-       $children = array();
-       foreach ( (array) $pages as $page ) {
-               $children[ intval( $page->post_parent ) ][] = $page;
-       }
-
-       $page_list = array();
-
-       // Start the search by looking at immediate children.
-       if ( isset( $children[ $page_id ] ) ) {
-               // Always start at the end of the stack in order to preserve original `$pages` order.
-               $to_look = array_reverse( $children[ $page_id ] );
-
-               while ( $to_look ) {
-                       $p = array_pop( $to_look );
-                       $page_list[] = $p;
-                       if ( isset( $children[ $p->ID ] ) ) {
-                               foreach ( array_reverse( $children[ $p->ID ] ) as $child ) {
-                                       // Append to the `$to_look` stack to descend the tree.
-                                       $to_look[] = $child;
-                               }
-                       }
-               }
-       }
-
-       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, passed by reference.
- * @param int   $page_id Optional. Parent page ID. Default 0.
- * @return array A list arranged by hierarchy. Children immediately follow their parents.
- */
-function get_page_hierarchy( &$pages, $page_id = 0 ) {
-       if ( empty( $pages ) ) {
-               return array();
-       }
-
-       $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;
-}
-
-/**
- * Traverse and return all the nested children post names of a root page.
- *
- * $children contains parent-children relations
- *
- * @since 2.9.0
- *
- * @see _page_traverse_name()
- *
- * @param int   $page_id   Page ID.
- * @param array &$children Parent-children relations, passed by reference.
- * @param array &$result   Result, passed by reference.
- */
-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 );
-               }
-       }
-}
-
-/**
- * Build URI for a page.
- *
- * Sub pages will be in the "directory" under the parent page post name.
- *
- * @since 1.5.0
- *
- * @param WP_Post|object|int $page Page object or page ID.
- * @return string|false Page URI, false on error.
- */
-function get_page_uri( $page ) {
-       $page = get_post( $page );
-
-       if ( ! $page )
-               return false;
-
-       $uri = $page->post_name;
-
-       foreach ( $page->ancestors as $parent ) {
-               $parent = get_post( $parent );
-               if ( 'publish' === $parent->post_status ) {
-                       $uri = $parent->post_name . '/' . $uri;
-               }
-       }
-
-       /**
-        * Filter the URI for a page.
-        *
-        * @since 4.4.0
-        *
-        * @param string  $uri  Page URI.
-        * @param WP_Post $page Page object.
-        */
-       return apply_filters( 'get_page_uri', $uri, $page );
-}
-
-/**
- * Retrieve a list of pages.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @since 1.5.0
- *
- * @param array|string $args {
- *     Optional. Array or string of arguments to retrieve pages.
- *
- *     @type int          $child_of     Page ID to return child and grandchild pages of. Note: The value
- *                                      of `$hierarchical` has no bearing on whether `$child_of` returns
- *                                      hierarchical results. Default 0, or no restriction.
- *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
- *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
- *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
- *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
- *                                      'post_' can be omitted for any values that start with it.
- *                                      Default 'post_title'.
- *     @type bool         $hierarchical Whether to return pages hierarchically. If false in conjunction with
- *                                      `$child_of` also being false, both arguments will be disregarded.
- *                                      Default true.
- *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
- *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
- *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
- *                                      Default empty array.
- *     @type string       $meta_key     Only include pages with this meta key. Default empty.
- *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
- *                                      Default empty.
- *     @type string       $authors      A comma-separated list of author IDs. Default empty.
- *     @type int          $parent       Page ID to return direct children of. Default -1, or no restriction.
- *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
- *                                      Default empty array.
- *     @type int          $number       The number of pages to return. Default 0, or all pages.
- *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
- *                                      Default 0.
- *     @type string       $post_type    The post type to query. Default 'page'.
- *     @type string       $post_status  A comma-separated list of post status types to include.
- *                                      Default 'publish'.
- * }
- * @return array|false List of pages matching defaults or `$args`.
- */
-function get_pages( $args = array() ) {
-       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' => array(),
-               'number' => '', 'offset' => 0,
-               'post_type' => 'page', 'post_status' => 'publish',
-       );
-
-       $r = wp_parse_args( $args, $defaults );
-
-       $number = (int) $r['number'];
-       $offset = (int) $r['offset'];
-       $child_of = (int) $r['child_of'];
-       $hierarchical = $r['hierarchical'];
-       $exclude = $r['exclude'];
-       $meta_key = $r['meta_key'];
-       $meta_value = $r['meta_value'];
-       $parent = $r['parent'];
-       $post_status = $r['post_status'];
-
-       // Make sure the post type is hierarchical.
-       $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
-       if ( ! in_array( $r['post_type'], $hierarchical_post_types ) ) {
-               return false;
-       }
-
-       if ( $parent > 0 && ! $child_of ) {
-               $hierarchical = false;
-       }
-
-       // 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 false;
-       }
-
-       // $args can be whatever, only use the args defined in defaults to compute the key.
-       $key = md5( serialize( wp_array_slice_assoc( $r, array_keys( $defaults ) ) ) );
-       $last_changed = wp_cache_get( 'last_changed', 'posts' );
-       if ( ! $last_changed ) {
-               $last_changed = microtime();
-               wp_cache_set( 'last_changed', $last_changed, 'posts' );
-       }
-
-       $cache_key = "get_pages:$key:$last_changed";
-       if ( $cache = wp_cache_get( $cache_key, 'posts' ) ) {
-               // Convert to WP_Post instances.
-               $pages = array_map( 'get_post', $cache );
-               /** This filter is documented in wp-includes/post-functions.php */
-               $pages = apply_filters( 'get_pages', $pages, $r );
-               return $pages;
-       }
-
-       $inclusions = '';
-       if ( ! empty( $r['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( $r['include'] );
-               if ( ! empty( $incpages ) ) {
-                       $inclusions = ' AND ID IN (' . implode( ',', $incpages ) .  ')';
-               }
-       }
-
-       $exclusions = '';
-       if ( ! empty( $exclude ) ) {
-               $expages = wp_parse_id_list( $exclude );
-               if ( ! empty( $expages ) ) {
-                       $exclusions = ' AND ID NOT IN (' . implode( ',', $expages ) .  ')';
-               }
-       }
-
-       $author_query = '';
-       if ( ! empty( $r['authors'] ) ) {
-               $post_authors = preg_split( '/[\s,]+/', $r['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 ( '' !== $meta_key || '' !== $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 = wp_unslash($meta_key);
-               $meta_value = wp_unslash($meta_value);
-               if ( '' !== $meta_key ) {
-                       $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
-               }
-               if ( '' !== $meta_value ) {
-                       $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
-               }
-
-       }
-
-       if ( is_array( $parent ) ) {
-               $post_parent__in = implode( ',', array_map( 'absint', (array) $parent ) );
-               if ( ! empty( $post_parent__in ) ) {
-                       $where .= " AND post_parent IN ($post_parent__in)";
-               }
-       } elseif ( $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", $r['post_type'], reset( $post_status ) );
-       } else {
-               $post_status = implode( "', '", $post_status );
-               $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $r['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( ',', $r['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( $r['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) ) {
-               /** This filter is documented in wp-includes/post-functions.php */
-               $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( $r['exclude_tree'] ) ) {
-               $exclude = wp_parse_id_list( $r['exclude_tree'] );
-               foreach ( $exclude as $id ) {
-                       $children = get_page_children( $id, $pages );
-                       foreach ( $children as $child ) {
-                               $exclude[] = $child->ID;
-                       }
-               }
-
-               $num_pages = count( $pages );
-               for ( $i = 0; $i < $num_pages; $i++ ) {
-                       if ( in_array( $pages[$i]->ID, $exclude ) ) {
-                               unset( $pages[$i] );
-                       }
-               }
-       }
-
-       $page_structure = array();
-       foreach ( $pages as $page ) {
-               $page_structure[] = $page->ID;
-       }
-
-       wp_cache_set( $cache_key, $page_structure, 'posts' );
-
-       // Convert to WP_Post instances
-       $pages = array_map( 'get_post', $pages );
-
-       /**
-        * Filter the retrieved list of pages.
-        *
-        * @since 2.1.0
-        *
-        * @param array $pages List of pages to retrieve.
-        * @param array $r     Array of get_pages() arguments.
-        */
-       return apply_filters( 'get_pages', $pages, $r );
-}
-
-//
-// 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 $args 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.
- *
- * @since 2.0.0
- *
- * @see wp_insert_post()
- *
- * @param string|array $args   Arguments for inserting an attachment.
- * @param string       $file   Optional. Filename.
- * @param int          $parent Optional. Parent post ID.
- * @return int Attachment ID.
- */
-function wp_insert_attachment( $args, $file = false, $parent = 0 ) {
-       $defaults = array(
-               'file'        => $file,
-               'post_parent' => 0
-       );
-
-       $data = wp_parse_args( $args, $defaults );
-
-       if ( ! empty( $parent ) ) {
-               $data['post_parent'] = $parent;
-       }
-
-       $data['post_type'] = 'attachment';
-
-       return wp_insert_post( $data );
-}
-
-/**
- * Trash or delete an attachment.
- *
- * When an attachment is permanently deleted, the file will also be removed.
- * Deletion removes all post meta fields, taxonomy, comments, etc. associated
- * with the attachment (except the main post).
- *
- * The attachment is moved to the trash instead of permanently deleted unless trash
- * for media is disabled, item is already in the trash, or $force_delete is true.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int  $post_id      Attachment ID.
- * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
- *                           Default false.
- * @return mixed False on failure. Post data on success.
- */
-function wp_delete_attachment( $post_id, $force_delete = false ) {
-       global $wpdb;
-
-       if ( !$post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) ) )
-               return $post;
-
-       if ( 'attachment' != $post->post_type )
-               return false;
-
-       if ( !$force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' != $post->post_status )
-               return wp_trash_post( $post_id );
-
-       delete_post_meta($post_id, '_wp_trash_meta_status');
-       delete_post_meta($post_id, '_wp_trash_meta_time');
-
-       $meta = wp_get_attachment_metadata( $post_id );
-       $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
-       $file = get_attached_file( $post_id );
-
-       if ( is_multisite() )
-               delete_transient( 'dirsize_cache' );
-
-       /**
-        * Fires before an attachment is deleted, at the start of wp_delete_attachment().
-        *
-        * @since 2.0.0
-        *
-        * @param int $post_id Attachment ID.
-        */
-       do_action( 'delete_attachment', $post_id );
-
-       wp_delete_object_term_relationships($post_id, array('category', 'post_tag'));
-       wp_delete_object_term_relationships($post_id, get_object_taxonomies($post->post_type));
-
-       // Delete all for any posts.
-       delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );
-
-       wp_defer_comment_counting( true );
-
-       $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ));
-       foreach ( $comment_ids as $comment_id ) {
-               wp_delete_comment( $comment_id, true );
-       }
-
-       wp_defer_comment_counting( false );
-
-       $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ));
-       foreach ( $post_meta_ids as $mid )
-               delete_metadata_by_mid( 'post', $mid );
-
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'delete_post', $post_id );
-       $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
-       if ( ! $result ) {
-               return false;
-       }
-       /** This action is documented in wp-includes/post-functions.php */
-       do_action( 'deleted_post', $post_id );
-
-       $uploadpath = wp_upload_dir();
-
-       if ( ! empty($meta['thumb']) ) {
-               // Don't delete the thumb if another attachment uses it.
-               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", '%' . $wpdb->esc_like( $meta['thumb'] ) . '%', $post_id)) ) {
-                       $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
-                       /** This filter is documented in wp-includes/functions.php */
-                       $thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
-                       @ unlink( path_join($uploadpath['basedir'], $thumbfile) );
-               }
-       }
-
-       // Remove intermediate and backup images if there are any.
-       if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) {
-               foreach ( $meta['sizes'] as $size => $sizeinfo ) {
-                       $intermediate_file = str_replace( basename( $file ), $sizeinfo['file'], $file );
-                       /** This filter is documented in wp-includes/functions.php */
-                       $intermediate_file = apply_filters( 'wp_delete_file', $intermediate_file );
-                       @ unlink( path_join( $uploadpath['basedir'], $intermediate_file ) );
-               }
-       }
-
-       if ( is_array($backup_sizes) ) {
-               foreach ( $backup_sizes as $size ) {
-                       $del_file = path_join( dirname($meta['file']), $size['file'] );
-                       /** This filter is documented in wp-includes/functions.php */
-                       $del_file = apply_filters( 'wp_delete_file', $del_file );
-                       @ unlink( path_join($uploadpath['basedir'], $del_file) );
-               }
-       }
-
-       wp_delete_file( $file );
-
-       clean_post_cache( $post );
-
-       return $post;
-}
-
-/**
- * Retrieve attachment meta field for attachment ID.
- *
- * @since 2.1.0
- *
- * @param int  $post_id    Attachment ID. Default 0.
- * @param bool $unfiltered Optional. If true, filters are not run. Default false.
- * @return mixed Attachment meta field. False on failure.
- */
-function wp_get_attachment_metadata( $post_id = 0, $unfiltered = false ) {
-       $post_id = (int) $post_id;
-       if ( !$post = get_post( $post_id ) )
-               return false;
-
-       $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
-
-       if ( $unfiltered )
-               return $data;
-
-       /**
-        * Filter the attachment meta data.
-        *
-        * @since 2.1.0
-        *
-        * @param array|bool $data    Array of meta data for the given attachment, or false
-        *                            if the object does not exist.
-        * @param int        $post_id Attachment ID.
-        */
-       return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
-}
-
-/**
- * Update metadata for an attachment.
- *
- * @since 2.1.0
- *
- * @param int   $post_id Attachment ID.
- * @param array $data    Attachment data.
- * @return int|bool False if $post is invalid.
- */
-function wp_update_attachment_metadata( $post_id, $data ) {
-       $post_id = (int) $post_id;
-       if ( !$post = get_post( $post_id ) )
-               return false;
-
-       /**
-        * Filter the updated attachment meta data.
-        *
-        * @since 2.1.0
-        *
-        * @param array $data    Array of updated attachment meta data.
-        * @param int   $post_id Attachment ID.
-        */
-       if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
-               return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
-       else
-               return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
-}
-
-/**
- * Retrieve the URL for an attachment.
- *
- * @since 2.1.0
- *
- * @global string $pagenow
- *
- * @param int $post_id Optional. Attachment ID. Default 0.
- * @return string|false Attachment URL, otherwise false.
- */
-function wp_get_attachment_url( $post_id = 0 ) {
-       $post_id = (int) $post_id;
-       if ( !$post = get_post( $post_id ) )
-               return false;
-
-       if ( 'attachment' != $post->post_type )
-               return false;
-
-       $url = '';
-       // Get attached file.
-       if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true) ) {
-               // Get upload directory.
-               if ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) {
-                       // Check that the upload base exists in the file location.
-                       if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
-                               // Replace file location with url location.
-                               $url = str_replace($uploads['basedir'], $uploads['baseurl'], $file);
-                       } elseif ( false !== strpos($file, 'wp-content/uploads') ) {
-                               $url = $uploads['baseurl'] . substr( $file, strpos($file, 'wp-content/uploads') + 18 );
-                       } else {
-                               // It's a newly-uploaded file, therefore $file is relative to the basedir.
-                               $url = $uploads['baseurl'] . "/$file";
-                       }
-               }
-       }
-
-       /*
-        * If any of the above options failed, Fallback on the GUID as used pre-2.7,
-        * not recommended to rely upon this.
-        */
-       if ( empty($url) ) {
-               $url = get_the_guid( $post->ID );
-       }
-
-       // On SSL front-end, URLs should be HTTPS.
-       if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] ) {
-               $url = set_url_scheme( $url );
-       }
-
-       /**
-        * Filter the attachment URL.
-        *
-        * @since 2.1.0
-        *
-        * @param string $url     URL for the given attachment.
-        * @param int    $post_id Attachment ID.
-        */
-       $url = apply_filters( 'wp_get_attachment_url', $url, $post->ID );
-
-       if ( empty( $url ) )
-               return false;
-
-       return $url;
-}
-
-/**
- * Retrieve thumbnail for an attachment.
- *
- * @since 2.1.0
- *
- * @param int $post_id Optional. Attachment ID. Default 0.
- * @return string|false False on failure. Thumbnail file path on success.
- */
-function wp_get_attachment_thumb_file( $post_id = 0 ) {
-       $post_id = (int) $post_id;
-       if ( !$post = get_post( $post_id ) )
-               return false;
-       if ( !is_array( $imagedata = wp_get_attachment_metadata( $post->ID ) ) )
-               return false;
-
-       $file = get_attached_file( $post->ID );
-
-       if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) ) {
-               /**
-                * Filter the attachment thumbnail file path.
-                *
-                * @since 2.1.0
-                *
-                * @param string $thumbfile File path to the attachment thumbnail.
-                * @param int    $post_id   Attachment ID.
-                */
-               return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
-       }
-       return false;
-}
-
-/**
- * Retrieve URL for an attachment thumbnail.
- *
- * @since 2.1.0
- *
- * @param int $post_id Optional. Attachment ID. Default 0.
- * @return string|false False on failure. Thumbnail URL on success.
- */
-function wp_get_attachment_thumb_url( $post_id = 0 ) {
-       $post_id = (int) $post_id;
-       if ( !$post = get_post( $post_id ) )
-               return false;
-       if ( !$url = wp_get_attachment_url( $post->ID ) )
-               return false;
-
-       $sized = image_downsize( $post_id, 'thumbnail' );
-       if ( $sized )
-               return $sized[0];
-
-       if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
-               return false;
-
-       $url = str_replace(basename($url), basename($thumb), $url);
-
-       /**
-        * Filter the attachment thumbnail URL.
-        *
-        * @since 2.1.0
-        *
-        * @param string $url     URL for the attachment thumbnail.
-        * @param int    $post_id Attachment ID.
-        */
-       return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
-}
-
-/**
- * Verifies an attachment is of a given type.
- *
- * @since 4.2.0
- *
- * @param string      $type    Attachment type. Accepts 'image', 'audio', or 'video'.
- * @param int|WP_Post $post_id Optional. Attachment ID. Default 0.
- * @return bool True if one of the accepted types, false otherwise.
- */
-function wp_attachment_is( $type, $post_id = 0 ) {
-       if ( ! $post = get_post( $post_id ) ) {
-               return false;
-       }
-
-       if ( ! $file = get_attached_file( $post->ID ) ) {
-               return false;
-       }
-
-       if ( 0 === strpos( $post->post_mime_type, $type . '/' ) ) {
-               return true;
-       }
-
-       $check = wp_check_filetype( $file );
-       if ( empty( $check['ext'] ) ) {
-               return false;
-       }
-
-       $ext = $check['ext'];
-
-       if ( 'import' !== $post->post_mime_type ) {
-               return $type === $ext;
-       }
-
-       switch ( $type ) {
-       case 'image':
-               $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
-               return in_array( $ext, $image_exts );
-
-       case 'audio':
-               return in_array( $ext, wp_get_audio_extensions() );
-
-       case 'video':
-               return in_array( $ext, wp_get_video_extensions() );
-
-       default:
-               return $type === $ext;
-       }
-}
-
-/**
- * Checks if the attachment is an image.
- *
- * @since 2.1.0
- * @since 4.2.0 Modified into wrapper for wp_attachment_is() and
- *              allowed WP_Post object to be passed.
- *
- * @param int|WP_Post $post Optional. Attachment ID. Default 0.
- * @return bool Whether the attachment is an image.
- */
-function wp_attachment_is_image( $post = 0 ) {
-       return wp_attachment_is( 'image', $post );
-}
-
-/**
- * Retrieve the icon for a MIME type.
- *
- * @since 2.1.0
- *
- * @param string|int $mime MIME type or attachment ID.
- * @return string|false Icon, false otherwise.
- */
-function wp_mime_type_icon( $mime = 0 ) {
-       if ( !is_numeric($mime) )
-               $icon = wp_cache_get("mime_type_icon_$mime");
-
-       $post_id = 0;
-       if ( empty($icon) ) {
-               $post_mimes = array();
-               if ( is_numeric($mime) ) {
-                       $mime = (int) $mime;
-                       if ( $post = get_post( $mime ) ) {
-                               $post_id = (int) $post->ID;
-                               $file = get_attached_file( $post_id );
-                               $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $file);
-                               if ( !empty($ext) ) {
-                                       $post_mimes[] = $ext;
-                                       if ( $ext_type = wp_ext2type( $ext ) )
-                                               $post_mimes[] = $ext_type;
-                               }
-                               $mime = $post->post_mime_type;
-                       } else {
-                               $mime = 0;
-                       }
-               } else {
-                       $post_mimes[] = $mime;
-               }
-
-               $icon_files = wp_cache_get('icon_files');
-
-               if ( !is_array($icon_files) ) {
-                       /**
-                        * Filter the icon directory path.
-                        *
-                        * @since 2.0.0
-                        *
-                        * @param string $path Icon directory absolute path.
-                        */
-                       $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
-
-                       /**
-                        * Filter the icon directory URI.
-                        *
-                        * @since 2.0.0
-                        *
-                        * @param string $uri Icon directory URI.
-                        */
-                       $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url( 'images/media' ) );
-
-                       /**
-                        * Filter the list of icon directory URIs.
-                        *
-                        * @since 2.5.0
-                        *
-                        * @param array $uris List of icon directory URIs.
-                        */
-                       $dirs = apply_filters( 'icon_dirs', array( $icon_dir => $icon_dir_uri ) );
-                       $icon_files = array();
-                       while ( $dirs ) {
-                               $keys = array_keys( $dirs );
-                               $dir = array_shift( $keys );
-                               $uri = array_shift($dirs);
-                               if ( $dh = opendir($dir) ) {
-                                       while ( false !== $file = readdir($dh) ) {
-                                               $file = basename($file);
-                                               if ( substr($file, 0, 1) == '.' )
-                                                       continue;
-                                               if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
-                                                       if ( is_dir("$dir/$file") )
-                                                               $dirs["$dir/$file"] = "$uri/$file";
-                                                       continue;
-                                               }
-                                               $icon_files["$dir/$file"] = "$uri/$file";
-                                       }
-                                       closedir($dh);
-                               }
-                       }
-                       wp_cache_add( 'icon_files', $icon_files, 'default', 600 );
-               }
-
-               $types = array();
-               // Icon basename - extension = MIME wildcard.
-               foreach ( $icon_files as $file => $uri )
-                       $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
-
-               if ( ! empty($mime) ) {
-                       $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
-                       $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
-                       $post_mimes[] = str_replace('/', '_', $mime);
-               }
-
-               $matches = wp_match_mime_types(array_keys($types), $post_mimes);
-               $matches['default'] = array('default');
-
-               foreach ( $matches as $match => $wilds ) {
-                       foreach ( $wilds as $wild ) {
-                               if ( ! isset( $types[ $wild ] ) ) {
-                                       continue;
-                               }
-
-                               $icon = $types[ $wild ];
-                               if ( ! is_numeric( $mime ) ) {
-                                       wp_cache_add( "mime_type_icon_$mime", $icon );
-                               }
-                               break 2;
-                       }
-               }
-       }
-
-       /**
-        * Filter the mime type icon.
-        *
-        * @since 2.1.0
-        *
-        * @param string $icon    Path to the mime type icon.
-        * @param string $mime    Mime type.
-        * @param int    $post_id Attachment ID. Will equal 0 if the function passed
-        *                        the mime type.
-        */
-       return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id );
-}
-
-/**
- * Check for changed slugs for published post objects and save the old slug.
- *
- * The function is used when a post object of any type is updated,
- * by comparing the current and previous post objects.
- *
- * If the slug was changed and not already part of the old slugs then it will be
- * added to the post meta field ('_wp_old_slug') for storing old slugs for that
- * post.
- *
- * The most logically usage of this function is redirecting changed post objects, so
- * that those that linked to an changed post will be redirected to the new post.
- *
- * @since 2.1.0
- *
- * @param int     $post_id     Post ID.
- * @param WP_Post $post        The Post Object
- * @param WP_Post $post_before The Previous Post Object
- */
-function wp_check_for_changed_slugs( $post_id, $post, $post_before ) {
-       // Don't bother if it hasn't changed.
-       if ( $post->post_name == $post_before->post_name ) {
-               return;
-       }
-
-       // We're only concerned with published, non-hierarchical objects.
-       if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) {
-               return;
-       }
-
-       $old_slugs = (array) get_post_meta( $post_id, '_wp_old_slug' );
-
-       // If we haven't added this old slug before, add it now.
-       if ( ! empty( $post_before->post_name ) && ! in_array( $post_before->post_name, $old_slugs ) ) {
-               add_post_meta( $post_id, '_wp_old_slug', $post_before->post_name );
-       }
-
-       // If the new slug was used previously, delete it from the list.
-       if ( in_array( $post->post_name, $old_slugs ) ) {
-               delete_post_meta( $post_id, '_wp_old_slug', $post->post_name );
-       }
-}
-
-/**
- * Retrieve the private post SQL based on capability.
- *
- * This function provides a standardized way to appropriately select on the
- * post_status of a post type. The function will return a piece of SQL code
- * that can be added to a WHERE clause; this SQL is constructed to allow all
- * published posts, and all private posts to which the user has access.
- *
- * @since 2.2.0
- * @since 4.3.0 Added the ability to pass an array to `$post_type`.
- *
- * @param string|array $post_type Single post type or an array of post types. Currently only supports 'post' or 'page'.
- * @return string SQL code that can be added to a where clause.
- */
-function get_private_posts_cap_sql( $post_type ) {
-       return get_posts_by_author_sql( $post_type, false );
-}
-
-/**
- * Retrieve the post SQL based on capability, author, and type.
- *
- * @since 3.0.0
- * @since 4.3.0 Introduced the ability to pass an array of post types to `$post_type`.
- *
- * @see get_private_posts_cap_sql()
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array|string   $post_type   Single post type or an array of post types.
- * @param bool           $full        Optional. Returns a full WHERE statement instead of just
- *                                    an 'andalso' term. Default true.
- * @param int            $post_author Optional. Query posts having a single author ID. Default null.
- * @param bool           $public_only Optional. Only return public posts. Skips cap checks for
- *                                    $current_user.  Default false.
- * @return string SQL WHERE code that can be added to a query.
- */
-function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) {
-       global $wpdb;
-
-       if ( is_array( $post_type ) ) {
-               $post_types = $post_type;
-       } else {
-               $post_types = array( $post_type );
-       }
-
-       $post_type_clauses = array();
-       foreach ( $post_types as $post_type ) {
-               $post_type_obj = get_post_type_object( $post_type );
-               if ( ! $post_type_obj ) {
-                       continue;
-               }
-
-               /**
-                * Filter the capability to read private posts for a custom post type
-                * when generating SQL for getting posts by author.
-                *
-                * @since 2.2.0
-                * @deprecated 3.2.0 The hook transitioned from "somewhat useless" to "totally useless".
-                *
-                * @param string $cap Capability.
-                */
-               if ( ! $cap = apply_filters( 'pub_priv_sql_capability', '' ) ) {
-                       $cap = current_user_can( $post_type_obj->cap->read_private_posts );
-               }
-
-               // Only need to check the cap if $public_only is false.
-               $post_status_sql = "post_status = 'publish'";
-               if ( false === $public_only ) {
-                       if ( $cap ) {
-                               // Does the user have the capability to view private posts? Guess so.
-                               $post_status_sql .= " OR post_status = 'private'";
-                       } elseif ( is_user_logged_in() ) {
-                               // Users can view their own private posts.
-                               $id = get_current_user_id();
-                               if ( null === $post_author || ! $full ) {
-                                       $post_status_sql .= " OR post_status = 'private' AND post_author = $id";
-                               } elseif ( $id == (int) $post_author ) {
-                                       $post_status_sql .= " OR post_status = 'private'";
-                               } // else none
-                       } // else none
-               }
-
-               $post_type_clauses[] = "( post_type = '" . $post_type . "' AND ( $post_status_sql ) )";
-       }
-
-       if ( empty( $post_type_clauses ) ) {
-               return $full ? 'WHERE 1 = 0' : '1 = 0';
-       }
-
-       $sql = '( '. implode( ' OR ', $post_type_clauses ) . ' )';
-
-       if ( null !== $post_author ) {
-               $sql .= $wpdb->prepare( ' AND post_author = %d', $post_author );
-       }
-
-       if ( $full ) {
-               $sql = 'WHERE ' . $sql;
-       }
-
-       return $sql;
-}
-
-/**
- * Retrieve the date that the last post was published.
- *
- * The server timezone is the default and is the difference between GMT and
- * server time. The 'blog' value is the date when the last post was posted. The
- * 'gmt' is when the last post was posted in GMT formatted date.
- *
- * @since 0.71
- * @since 4.4.0 The `$post_type` argument was added.
- *
- * @param string $timezone  Optional. The timezone for the timestamp. Accepts 'server', 'blog', or 'gmt'.
- *                          'server' uses the server's internal timezone.
- *                          'blog' uses the `post_modified` field, which proxies to the timezone set for the site.
- *                          'gmt' uses the `post_modified_gmt` field.
- *                          Default 'server'.
- * @param string $post_type Optional. The post type to check. Default 'any'.
- * @return string The date of the last post.
- */
-function get_lastpostdate( $timezone = 'server', $post_type = 'any' ) {
-       /**
-        * Filter the date the last post was published.
-        *
-        * @since 2.3.0
-        *
-        * @param string $date     Date the last post was published.
-        * @param string $timezone Location to use for getting the post published date.
-        *                         See {@see get_lastpostdate()} for accepted `$timezone` values.
-        */
-       return apply_filters( 'get_lastpostdate', _get_last_post_time( $timezone, 'date', $post_type ), $timezone );
-}
-
-/**
- * Get the timestamp of the last time any post was modified.
- *
- * The server timezone is the default and is the difference between GMT and
- * server time. The 'blog' value is just when the last post was modified. The
- * 'gmt' is when the last post was modified in GMT time.
- *
- * @since 1.2.0
- * @since 4.4.0 The `$post_type` argument was added.
- *
- * @param string $timezone  Optional. The timezone for the timestamp. See {@see get_lastpostdate()}
- *                          for information on accepted values.
- *                          Default 'server'.
- * @param string $post_type Optional. The post type to check. Default 'any'.
- * @return string The timestamp.
- */
-function get_lastpostmodified( $timezone = 'server', $post_type = 'any' ) {
-       /**
-        * Pre-filter the return value of get_lastpostmodified() before the query is run.
-        *
-        * @since 4.4.0
-        *
-        * @param string $lastpostmodified Date the last post was modified.
-        *                                 Returning anything other than false will short-circuit the function.
-        * @param string $timezone         Location to use for getting the post modified date.
-        *                                 See {@see get_lastpostdate()} for accepted `$timezone` values.
-        * @param string $post_type        The post type to check.
-        */
-       $lastpostmodified = apply_filters( 'pre_get_lastpostmodified', false, $timezone, $post_type );
-       if ( false !== $lastpostmodified ) {
-               return $lastpostmodified;
-       }
-
-       $lastpostmodified = _get_last_post_time( $timezone, 'modified', $post_type );
-
-       $lastpostdate = get_lastpostdate($timezone);
-       if ( $lastpostdate > $lastpostmodified ) {
-               $lastpostmodified = $lastpostdate;
-       }
-
-       /**
-        * Filter the date the last post was modified.
-        *
-        * @since 2.3.0
-        *
-        * @param string $lastpostmodified Date the last post was modified.
-        * @param string $timezone         Location to use for getting the post modified date.
-        *                                 See {@see get_lastpostdate()} for accepted `$timezone` values.
-        */
-       return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
-}
-
-/**
- * Get the timestamp of the last time any post was modified or published.
- *
- * @since 3.1.0
- * @since 4.4.0 The `$post_type` argument was added.
- * @access private
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $timezone  The timezone for the timestamp. See get_lastpostdate().
- *                          for information on accepted values.
- * @param string $field     Post field to check. Accepts 'date' or 'modified'.
- * @param string $post_type Optional. The post type to check. Default 'any'.
- * @return string|false The timestamp.
- */
-function _get_last_post_time( $timezone, $field, $post_type = 'any' ) {
-       global $wpdb;
-
-       if ( ! in_array( $field, array( 'date', 'modified' ) ) ) {
-               return false;
-       }
-
-       $timezone = strtolower( $timezone );
-
-       $key = "lastpost{$field}:$timezone";
-       if ( 'any' !== $post_type ) {
-               $key .= ':' . sanitize_key( $post_type );
-       }
-
-       $date = wp_cache_get( $key, 'timeinfo' );
-
-       if ( ! $date ) {
-               if ( 'any' === $post_type ) {
-                       $post_types = get_post_types( array( 'public' => true ) );
-                       array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) );
-                       $post_types = "'" . implode( "', '", $post_types ) . "'";
-               } else {
-                       $post_types = "'" . sanitize_key( $post_type ) . "'";
-               }
-
-               switch ( $timezone ) {
-                       case 'gmt':
-                               $date = $wpdb->get_var("SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
-                               break;
-                       case 'blog':
-                               $date = $wpdb->get_var("SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
-                               break;
-                       case 'server':
-                               $add_seconds_server = date( 'Z' );
-                               $date = $wpdb->get_var("SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
-                               break;
-               }
-
-               if ( $date ) {
-                       wp_cache_set( $key, $date, 'timeinfo' );
-               }
-       }
-
-       return $date;
-}
-
-/**
- * Updates posts in cache.
- *
- * @since 1.5.1
- *
- * @param array $posts Array of post objects, passed by reference.
- */
-function update_post_cache( &$posts ) {
-       if ( ! $posts )
-               return;
-
-       foreach ( $posts as $post )
-               wp_cache_add( $post->ID, $post, 'posts' );
-}
-
-/**
- * Will clean the post in the cache.
- *
- * Cleaning means delete from the cache of the post. Will call to clean the term
- * object cache associated with the post ID.
- *
- * This function not run if $_wp_suspend_cache_invalidation is not empty. See
- * wp_suspend_cache_invalidation().
- *
- * @since 2.0.0
- *
- * @global bool $_wp_suspend_cache_invalidation
- *
- * @param int|WP_Post $post Post ID or post object to remove from the cache.
- */
-function clean_post_cache( $post ) {
-       global $_wp_suspend_cache_invalidation;
-
-       if ( ! empty( $_wp_suspend_cache_invalidation ) )
-               return;
-
-       $post = get_post( $post );
-       if ( empty( $post ) )
-               return;
-
-       wp_cache_delete( $post->ID, 'posts' );
-       wp_cache_delete( $post->ID, 'post_meta' );
-
-       clean_object_term_cache( $post->ID, $post->post_type );
-
-       wp_cache_delete( 'wp_get_archives', 'general' );
-
-       /**
-        * Fires immediately after the given post's cache is cleaned.
-        *
-        * @since 2.5.0
-        *
-        * @param int     $post_id Post ID.
-        * @param WP_Post $post    Post object.
-        */
-       do_action( 'clean_post_cache', $post->ID, $post );
-
-       if ( 'page' == $post->post_type ) {
-               wp_cache_delete( 'all_page_ids', 'posts' );
-
-               /**
-                * Fires immediately after the given page's cache is cleaned.
-                *
-                * @since 2.5.0
-                *
-                * @param int $post_id Post ID.
-                */
-               do_action( 'clean_page_cache', $post->ID );
-       }
-
-       wp_cache_set( 'last_changed', microtime(), 'posts' );
-}
-
-/**
- * Call major cache updating functions for list of Post objects.
- *
- * @since 1.5.0
- *
- * @param array  $posts             Array of Post objects
- * @param string $post_type         Optional. Post type. Default 'post'.
- * @param bool   $update_term_cache Optional. Whether to update the term cache. Default true.
- * @param bool   $update_meta_cache Optional. Whether to update the meta cache. Default true.
- */
-function update_post_caches( &$posts, $post_type = 'post', $update_term_cache = true, $update_meta_cache = true ) {
-       // No point in doing all this work if we didn't match any posts.
-       if ( !$posts )
-               return;
-
-       update_post_cache($posts);
-
-       $post_ids = array();
-       foreach ( $posts as $post )
-               $post_ids[] = $post->ID;
-
-       if ( ! $post_type )
-               $post_type = 'any';
-
-       if ( $update_term_cache ) {
-               if ( is_array($post_type) ) {
-                       $ptypes = $post_type;
-               } elseif ( 'any' == $post_type ) {
-                       $ptypes = array();
-                       // Just use the post_types in the supplied posts.
-                       foreach ( $posts as $post ) {
-                               $ptypes[] = $post->post_type;
-                       }
-                       $ptypes = array_unique($ptypes);
-               } else {
-                       $ptypes = array($post_type);
-               }
-
-               if ( ! empty($ptypes) )
-                       update_object_term_cache($post_ids, $ptypes);
-       }
-
-       if ( $update_meta_cache )
-               update_postmeta_cache($post_ids);
-}
-
-/**
- * Updates metadata cache for list of post IDs.
- *
- * Performs SQL query to retrieve the metadata for the post IDs and updates the
- * metadata cache for the posts. Therefore, the functions, which call this
- * function, do not need to perform SQL queries on their own.
- *
- * @since 2.1.0
- *
- * @param array $post_ids List of post IDs.
- * @return array|false Returns false if there is nothing to update or an array
- *                     of metadata.
- */
-function update_postmeta_cache( $post_ids ) {
-       return update_meta_cache('post', $post_ids);
-}
-
-/**
- * Will clean the attachment in the cache.
- *
- * Cleaning means delete from the cache. Optionally will clean the term
- * object cache associated with the attachment ID.
- *
- * This function will not run if $_wp_suspend_cache_invalidation is not empty.
- *
- * @since 3.0.0
- *
- * @global bool $_wp_suspend_cache_invalidation
- *
- * @param int  $id          The attachment ID in the cache to clean.
- * @param bool $clean_terms Optional. Whether to clean terms cache. Default false.
- */
-function clean_attachment_cache( $id, $clean_terms = false ) {
-       global $_wp_suspend_cache_invalidation;
-
-       if ( !empty($_wp_suspend_cache_invalidation) )
-               return;
-
-       $id = (int) $id;
-
-       wp_cache_delete($id, 'posts');
-       wp_cache_delete($id, 'post_meta');
-
-       if ( $clean_terms )
-               clean_object_term_cache($id, 'attachment');
-
-       /**
-        * Fires after the given attachment's cache is cleaned.
-        *
-        * @since 3.0.0
-        *
-        * @param int $id Attachment ID.
-        */
-       do_action( 'clean_attachment_cache', $id );
-}
-
-//
-// Hooks
-//
-
-/**
- * Hook for managing future post transitions to published.
- *
- * @since 2.3.0
- * @access private
- *
- * @see wp_clear_scheduled_hook()
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string  $new_status New post status.
- * @param string  $old_status Previous post status.
- * @param WP_Post $post       Post object.
- */
-function _transition_post_status( $new_status, $old_status, $post ) {
-       global $wpdb;
-
-       if ( $old_status != 'publish' && $new_status == 'publish' ) {
-               // Reset GUID if transitioning to publish and it is empty.
-               if ( '' == get_the_guid($post->ID) )
-                       $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
-
-               /**
-                * Fires when a post's status is transitioned from private to published.
-                *
-                * @since 1.5.0
-                * @deprecated 2.3.0 Use 'private_to_publish' instead.
-                *
-                * @param int $post_id Post ID.
-                */
-               do_action('private_to_published', $post->ID);
-       }
-
-       // If published posts changed clear the lastpostmodified cache.
-       if ( 'publish' == $new_status || 'publish' == $old_status) {
-               foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
-                       wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' );
-                       wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' );
-                       wp_cache_delete( "lastpostdate:$timezone:{$post->post_type}", 'timeinfo' );
-               }
-       }
-
-       if ( $new_status !== $old_status ) {
-               wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
-               wp_cache_delete( _count_posts_cache_key( $post->post_type, 'readable' ), 'counts' );
-       }
-
-       // Always clears the hook in case the post status bounced from future to draft.
-       wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
-}
-
-/**
- * Hook used to schedule publication for a post marked for the future.
- *
- * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
- *
- * @since 2.3.0
- * @access private
- *
- * @param int     $deprecated Not used. Can be set to null. Never implemented. Not marked
- *                            as deprecated with _deprecated_argument() as it conflicts with
- *                            wp_transition_post_status() and the default filter for
- *                            {@see _future_post_hook()}.
- * @param WP_Post $post       Post object.
- */
-function _future_post_hook( $deprecated, $post ) {
-       wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) );
-       wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT') , 'publish_future_post', array( $post->ID ) );
-}
-
-/**
- * Hook to schedule pings and enclosures when a post is published.
- *
- * Uses XMLRPC_REQUEST and WP_IMPORTING constants.
- *
- * @since 2.3.0
- * @access private
- *
- * @param int $post_id The ID in the database table of the post being published.
- */
-function _publish_post_hook( $post_id ) {
-       if ( defined( 'XMLRPC_REQUEST' ) ) {
-               /**
-                * Fires when _publish_post_hook() is called during an XML-RPC request.
-                *
-                * @since 2.1.0
-                *
-                * @param int $post_id Post ID.
-                */
-               do_action( 'xmlrpc_publish_post', $post_id );
-       }
-
-       if ( defined('WP_IMPORTING') )
-               return;
-
-       if ( get_option('default_pingback_flag') )
-               add_post_meta( $post_id, '_pingme', '1' );
-       add_post_meta( $post_id, '_encloseme', '1' );
-
-       wp_schedule_single_event(time(), 'do_pings');
-}
-
-/**
- * Return the post's parent's post_ID
- *
- * @since 3.1.0
- *
- * @param int $post_ID
- *
- * @return int|false Post parent ID, otherwise false.
- */
-function wp_get_post_parent_id( $post_ID ) {
-       $post = get_post( $post_ID );
-       if ( !$post || is_wp_error( $post ) )
-               return false;
-       return (int) $post->post_parent;
-}
-
-/**
- * Check the given subset of the post hierarchy for hierarchy loops.
- *
- * Prevents loops from forming and breaks those that it finds. Attached
- * to the 'wp_insert_post_parent' filter.
- *
- * @since 3.1.0
- *
- * @see wp_find_hierarchy_loop()
- *
- * @param int $post_parent ID of the parent for the post we're checking.
- * @param int $post_ID     ID of the post we're checking.
- * @return int The new post_parent for the post, 0 otherwise.
- */
-function wp_check_post_hierarchy_for_loops( $post_parent, $post_ID ) {
-       // Nothing fancy here - bail.
-       if ( !$post_parent )
-               return 0;
-
-       // New post can't cause a loop.
-       if ( empty( $post_ID ) )
-               return $post_parent;
-
-       // Can't be its own parent.
-       if ( $post_parent == $post_ID )
-               return 0;
-
-       // Now look for larger loops.
-       if ( !$loop = wp_find_hierarchy_loop( 'wp_get_post_parent_id', $post_ID, $post_parent ) )
-               return $post_parent; // No loop
-
-       // Setting $post_parent to the given value causes a loop.
-       if ( isset( $loop[$post_ID] ) )
-               return 0;
-
-       // There's a loop, but it doesn't contain $post_ID. Break the loop.
-       foreach ( array_keys( $loop ) as $loop_member )
-               wp_update_post( array( 'ID' => $loop_member, 'post_parent' => 0 ) );
-
-       return $post_parent;
-}
-
-/**
- * Set a post thumbnail.
- *
- * @since 3.1.0
- *
- * @param int|WP_Post $post         Post ID or post object where thumbnail should be attached.
- * @param int         $thumbnail_id Thumbnail to attach.
- * @return int|bool True on success, false on failure.
- */
-function set_post_thumbnail( $post, $thumbnail_id ) {
-       $post = get_post( $post );
-       $thumbnail_id = absint( $thumbnail_id );
-       if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) {
-               if ( wp_get_attachment_image( $thumbnail_id, 'thumbnail' ) )
-                       return update_post_meta( $post->ID, '_thumbnail_id', $thumbnail_id );
-               else
-                       return delete_post_meta( $post->ID, '_thumbnail_id' );
-       }
-       return false;
-}
-
-/**
- * Remove a post thumbnail.
- *
- * @since 3.3.0
- *
- * @param int|WP_Post $post Post ID or post object where thumbnail should be removed from.
- * @return bool True on success, false on failure.
- */
-function delete_post_thumbnail( $post ) {
-       $post = get_post( $post );
-       if ( $post )
-               return delete_post_meta( $post->ID, '_thumbnail_id' );
-       return false;
-}
-
-/**
- * Delete auto-drafts for new posts that are > 7 days old.
- *
- * @since 3.4.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- */
-function wp_delete_auto_drafts() {
-       global $wpdb;
-
-       // Cleanup old auto-drafts more than 7 days old.
-       $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
-       foreach ( (array) $old_posts as $delete ) {
-               // Force delete.
-               wp_delete_post( $delete, true );
-       }
-}
-
-/**
- * Update the custom taxonomies' term counts when a post's status is changed.
- *
- * For example, default posts term counts (for custom taxonomies) don't include
- * private / draft posts.
- *
- * @since 3.3.0
- * @access private
- *
- * @param string  $new_status New post status.
- * @param string  $old_status Old post status.
- * @param WP_Post $post       Post object.
- */
-function _update_term_count_on_transition_post_status( $new_status, $old_status, $post ) {
-       // Update counts for the post's terms.
-       foreach ( (array) get_object_taxonomies( $post->post_type ) as $taxonomy ) {
-               $tt_ids = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'tt_ids' ) );
-               wp_update_term_count( $tt_ids, $taxonomy );
-       }
-}
-
-/**
- * Adds any posts from the given ids to the cache that do not already exist in cache
- *
- * @since 3.4.0
- * @access private
- *
- * @see update_post_caches()
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array $ids               ID list.
- * @param bool  $update_term_cache Optional. Whether to update the term cache. Default true.
- * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
- */
-function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) {
-       global $wpdb;
-
-       $non_cached_ids = _get_non_cached_ids( $ids, 'posts' );
-       if ( !empty( $non_cached_ids ) ) {
-               $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) );
-
-               update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
-       }
-}
</del></span></pre></div>
<a id="trunksrcwpincludespostphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/post.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/post.php    2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/post.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,20 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core Post API
- *
- * @package WordPress
- * @subpackage Post
- * @since 1.5.0
- */
-
-/** Core posts functionality */
-require_once( ABSPATH . WPINC . '/post-functions.php' );
-
-/** Walker_Page class */
-require_once( ABSPATH . WPINC . '/class-walker-page.php' );
-
-/** Walker_PageDropdown class */
-require_once( ABSPATH . WPINC . '/class-walker-page-dropdown.php' );
-
-/** WP_Post class */
-require_once( ABSPATH . WPINC . '/class-wp-post.php' );
</del></span></pre></div>
<a id="trunksrcwpincludespostphpfromrev35712trunksrcwpincludespostfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/post.php (from rev 35712, trunk/src/wp-includes/post-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/post.php                            (rev 0)
+++ trunk/src/wp-includes/post.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,5890 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core Post API
+ *
+ * @package WordPress
+ * @subpackage Post
+ */
+
+//
+// Post Type Registration
+//
+
+/**
+ * Creates the initial post types when 'init' action is fired.
+ *
+ * @since 2.9.0
+ */
+function create_initial_post_types() {
+       register_post_type( 'post', array(
+               'labels' => array(
+                       'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
+               ),
+               'public'  => true,
+               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+               'capability_type' => 'post',
+               'map_meta_cap' => true,
+               'menu_position' => 5,
+               'hierarchical' => false,
+               'rewrite' => false,
+               'query_var' => false,
+               'delete_with_user' => true,
+               'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
+       ) );
+
+       register_post_type( 'page', array(
+               'labels' => array(
+                       'name_admin_bar' => _x( 'Page', 'add new on admin bar' ),
+               ),
+               'public' => true,
+               'publicly_queryable' => false,
+               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+               'capability_type' => 'page',
+               'map_meta_cap' => true,
+               'menu_position' => 20,
+               'hierarchical' => true,
+               'rewrite' => false,
+               'query_var' => false,
+               'delete_with_user' => true,
+               'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
+       ) );
+
+       register_post_type( 'attachment', array(
+               'labels' => array(
+                       'name' => _x('Media', 'post type general name'),
+                       'name_admin_bar' => _x( 'Media', 'add new from admin bar' ),
+                       'add_new' => _x( 'Add New', 'add new media' ),
+                       'edit_item' => __( 'Edit Media' ),
+                       'view_item' => __( 'View Attachment Page' ),
+               ),
+               'public' => true,
+               'show_ui' => true,
+               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+               '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+               'capability_type' => 'post',
+               'capabilities' => array(
+                       'create_posts' => 'upload_files',
+               ),
+               'map_meta_cap' => true,
+               'hierarchical' => false,
+               'rewrite' => false,
+               'query_var' => false,
+               'show_in_nav_menus' => false,
+               'delete_with_user' => true,
+               'supports' => array( 'title', 'author', 'comments' ),
+       ) );
+       add_post_type_support( 'attachment:audio', 'thumbnail' );
+       add_post_type_support( 'attachment:video', 'thumbnail' );
+
+       register_post_type( 'revision', array(
+               'labels' => array(
+                       'name' => __( 'Revisions' ),
+                       'singular_name' => __( 'Revision' ),
+               ),
+               'public' => false,
+               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+               '_edit_link' => 'revision.php?revision=%d', /* internal use only. don't use this when registering your own post type. */
+               'capability_type' => 'post',
+               'map_meta_cap' => true,
+               'hierarchical' => false,
+               'rewrite' => false,
+               'query_var' => false,
+               'can_export' => false,
+               'delete_with_user' => true,
+               'supports' => array( 'author' ),
+       ) );
+
+       register_post_type( 'nav_menu_item', array(
+               'labels' => array(
+                       'name' => __( 'Navigation Menu Items' ),
+                       'singular_name' => __( 'Navigation Menu Item' ),
+               ),
+               'public' => false,
+               '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+               'hierarchical' => false,
+               'rewrite' => false,
+               'delete_with_user' => false,
+               'query_var' => false,
+       ) );
+
+       register_post_status( 'publish', array(
+               'label'       => _x( 'Published', 'post' ),
+               'public'      => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
+       ) );
+
+       register_post_status( 'future', array(
+               'label'       => _x( 'Scheduled', 'post' ),
+               'protected'   => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
+       ) );
+
+       register_post_status( 'draft', array(
+               'label'       => _x( 'Draft', 'post' ),
+               'protected'   => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
+       ) );
+
+       register_post_status( 'pending', array(
+               'label'       => _x( 'Pending', 'post' ),
+               'protected'   => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
+       ) );
+
+       register_post_status( 'private', array(
+               'label'       => _x( 'Private', 'post' ),
+               'private'     => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
+       ) );
+
+       register_post_status( 'trash', array(
+               'label'       => _x( 'Trash', 'post' ),
+               'internal'    => true,
+               '_builtin'    => true, /* internal use only. */
+               'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
+               'show_in_admin_status_list' => true,
+       ) );
+
+       register_post_status( 'auto-draft', array(
+               'label'    => 'auto-draft',
+               'internal' => true,
+               '_builtin' => true, /* internal use only. */
+       ) );
+
+       register_post_status( 'inherit', array(
+               'label'    => 'inherit',
+               'internal' => true,
+               '_builtin' => true, /* internal use only. */
+               'exclude_from_search' => false,
+       ) );
+}
+
+/**
+ * Retrieve attached file path based on attachment ID.
+ *
+ * By default the path will go through the 'get_attached_file' filter, but
+ * passing a true to the $unfiltered argument of get_attached_file() will
+ * return the file path unfiltered.
+ *
+ * The function works by getting the single post meta name, named
+ * '_wp_attached_file' and returning it. This is a convenience function to
+ * prevent looking up the meta name and provide a mechanism for sending the
+ * attached filename through a filter.
+ *
+ * @since 2.0.0
+ *
+ * @param int  $attachment_id Attachment ID.
+ * @param bool $unfiltered    Optional. Whether to apply filters. Default false.
+ * @return string|false The file path to where the attached file should be, false otherwise.
+ */
+function get_attached_file( $attachment_id, $unfiltered = false ) {
+       $file = get_post_meta( $attachment_id, '_wp_attached_file', true );
+       // If the file is relative, prepend upload dir.
+       if ( $file && 0 !== strpos($file, '/') && !preg_match('|^.:\\\|', $file) && ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) )
+               $file = $uploads['basedir'] . "/$file";
+       if ( $unfiltered )
+               return $file;
+
+       /**
+        * Filter the attached file based on the given ID.
+        *
+        * @since 2.1.0
+        *
+        * @param string $file          Path to attached file.
+        * @param int    $attachment_id Attachment ID.
+        */
+       return apply_filters( 'get_attached_file', $file, $attachment_id );
+}
+
+/**
+ * Update attachment file path based on attachment ID.
+ *
+ * Used to update the file path of the attachment, which uses post meta name
+ * '_wp_attached_file' to store the path of the attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int    $attachment_id Attachment ID.
+ * @param string $file          File path for the attachment.
+ * @return bool True on success, false on failure.
+ */
+function update_attached_file( $attachment_id, $file ) {
+       if ( !get_post( $attachment_id ) )
+               return false;
+
+       /**
+        * Filter the path to the attached file to update.
+        *
+        * @since 2.1.0
+        *
+        * @param string $file          Path to the attached file to update.
+        * @param int    $attachment_id Attachment ID.
+        */
+       $file = apply_filters( 'update_attached_file', $file, $attachment_id );
+
+       if ( $file = _wp_relative_upload_path( $file ) )
+               return update_post_meta( $attachment_id, '_wp_attached_file', $file );
+       else
+               return delete_post_meta( $attachment_id, '_wp_attached_file' );
+}
+
+/**
+ * Return relative path to an uploaded file.
+ *
+ * The path is relative to the current upload dir.
+ *
+ * @since 2.9.0
+ *
+ * @param string $path Full path to the file.
+ * @return string Relative path on success, unchanged path on failure.
+ */
+function _wp_relative_upload_path( $path ) {
+       $new_path = $path;
+
+       $uploads = wp_upload_dir();
+       if ( 0 === strpos( $new_path, $uploads['basedir'] ) ) {
+                       $new_path = str_replace( $uploads['basedir'], '', $new_path );
+                       $new_path = ltrim( $new_path, '/' );
+       }
+
+       /**
+        * Filter the relative path to an uploaded file.
+        *
+        * @since 2.9.0
+        *
+        * @param string $new_path Relative path to the file.
+        * @param string $path     Full path to the file.
+        */
+       return apply_filters( '_wp_relative_upload_path', $new_path, $path );
+}
+
+/**
+ * Retrieve all children of the post parent ID.
+ *
+ * Normally, without any enhancements, the children would apply to pages. In the
+ * context of the inner workings of WordPress, pages, posts, and attachments
+ * share the same table, so therefore the functionality could apply to any one
+ * of them. It is then noted that while this function does not work on posts, it
+ * does not mean that it won't work on posts. It is recommended that you know
+ * what context you wish to retrieve the children of.
+ *
+ * Attachments may also be made the child of a post, so if that is an accurate
+ * statement (which needs to be verified), it would then be possible to get
+ * all of the attachments for a post. Attachments have since changed since
+ * version 2.5, so this is most likely inaccurate, but serves generally as an
+ * example of what is possible.
+ *
+ * The arguments listed as defaults are for this function and also of the
+ * {@link get_posts()} function. The arguments are combined with the
+ * get_children defaults and are then passed to the {@link get_posts()}
+ * function, which accepts additional arguments. You can replace the defaults in
+ * this function, listed below and the additional arguments listed in the
+ * {@link get_posts()} function.
+ *
+ * The 'post_parent' is the most important argument and important attention
+ * needs to be paid to the $args parameter. If you pass either an object or an
+ * integer (number), then just the 'post_parent' is grabbed and everything else
+ * is lost. If you don't specify any arguments, then it is assumed that you are
+ * in The Loop and the post parent will be grabbed for from the current post.
+ *
+ * The 'post_parent' argument is the ID to get the children. The 'numberposts'
+ * is the amount of posts to retrieve that has a default of '-1', which is
+ * used to get all of the posts. Giving a number higher than 0 will only
+ * retrieve that amount of posts.
+ *
+ * The 'post_type' and 'post_status' arguments can be used to choose what
+ * criteria of posts to retrieve. The 'post_type' can be anything, but WordPress
+ * post types are 'post', 'pages', and 'attachments'. The 'post_status'
+ * argument will accept any post status within the write administration panels.
+ *
+ * @since 2.0.0
+ *
+ * @see get_posts()
+ * @todo Check validity of description.
+ *
+ * @global WP_Post $post
+ *
+ * @param mixed  $args   Optional. User defined arguments for replacing the defaults. Default empty.
+ * @param string $output Optional. Constant for return type. Accepts OBJECT, ARRAY_A, ARRAY_N.
+ *                       Default OBJECT.
+ * @return array Array of children, where the type of each element is determined by $output parameter.
+ *               Empty array on failure.
+ */
+function get_children( $args = '', $output = OBJECT ) {
+       $kids = array();
+       if ( empty( $args ) ) {
+               if ( isset( $GLOBALS['post'] ) ) {
+                       $args = array('post_parent' => (int) $GLOBALS['post']->post_parent );
+               } else {
+                       return $kids;
+               }
+       } elseif ( is_object( $args ) ) {
+               $args = array('post_parent' => (int) $args->post_parent );
+       } elseif ( is_numeric( $args ) ) {
+               $args = array('post_parent' => (int) $args);
+       }
+
+       $defaults = array(
+               'numberposts' => -1, 'post_type' => 'any',
+               'post_status' => 'any', 'post_parent' => 0,
+       );
+
+       $r = wp_parse_args( $args, $defaults );
+
+       $children = get_posts( $r );
+
+       if ( ! $children )
+               return $kids;
+
+       if ( ! empty( $r['fields'] ) )
+               return $children;
+
+       update_post_cache($children);
+
+       foreach ( $children as $key => $child )
+               $kids[$child->ID] = $children[$key];
+
+       if ( $output == OBJECT ) {
+               return $kids;
+       } elseif ( $output == ARRAY_A ) {
+               $weeuns = array();
+               foreach ( (array) $kids as $kid ) {
+                       $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
+               }
+               return $weeuns;
+       } elseif ( $output == ARRAY_N ) {
+               $babes = array();
+               foreach ( (array) $kids as $kid ) {
+                       $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
+               }
+               return $babes;
+       } else {
+               return $kids;
+       }
+}
+
+/**
+ * Get extended entry info (<!--more-->).
+ *
+ * There should not be any space after the second dash and before the word
+ * 'more'. There can be text or space(s) after the word 'more', but won't be
+ * referenced.
+ *
+ * The returned array has 'main', 'extended', and 'more_text' keys. Main has the text before
+ * the `<!--more-->`. The 'extended' key has the content after the
+ * `<!--more-->` comment. The 'more_text' key has the custom "Read More" text.
+ *
+ * @since 1.0.0
+ *
+ * @param string $post Post content.
+ * @return array Post before ('main'), after ('extended'), and custom read more ('more_text').
+ */
+function get_extended( $post ) {
+       //Match the new style more links.
+       if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
+               list($main, $extended) = explode($matches[0], $post, 2);
+               $more_text = $matches[1];
+       } else {
+               $main = $post;
+               $extended = '';
+               $more_text = '';
+       }
+
+       //  leading and trailing whitespace.
+       $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
+       $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
+       $more_text = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $more_text);
+
+       return array( 'main' => $main, 'extended' => $extended, 'more_text' => $more_text );
+}
+
+/**
+ * Retrieves post data given a post ID or post object.
+ *
+ * See {@link sanitize_post()} for optional $filter values. Also, the parameter
+ * $post, must be given as a variable, since it is passed by reference.
+ *
+ * @since 1.5.1
+ *
+ * @global WP_Post $post
+ *
+ * @param int|WP_Post|null $post   Optional. Post ID or post object. Defaults to global $post.
+ * @param string           $output Optional, default is Object. Accepts OBJECT, ARRAY_A, or ARRAY_N.
+ *                                 Default OBJECT.
+ * @param string           $filter Optional. Type of filter to apply. Accepts 'raw', 'edit', 'db',
+ *                                 or 'display'. Default 'raw'.
+ * @return WP_Post|array|null Type corresponding to $output on success or null on failure.
+ *                            When $output is OBJECT, a `WP_Post` instance is returned.
+ */
+function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
+       if ( empty( $post ) && isset( $GLOBALS['post'] ) )
+               $post = $GLOBALS['post'];
+
+       if ( $post instanceof WP_Post ) {
+               $_post = $post;
+       } elseif ( is_object( $post ) ) {
+               if ( empty( $post->filter ) ) {
+                       $_post = sanitize_post( $post, 'raw' );
+                       $_post = new WP_Post( $_post );
+               } elseif ( 'raw' == $post->filter ) {
+                       $_post = new WP_Post( $post );
+               } else {
+                       $_post = WP_Post::get_instance( $post->ID );
+               }
+       } else {
+               $_post = WP_Post::get_instance( $post );
+       }
+
+       if ( ! $_post )
+               return null;
+
+       $_post = $_post->filter( $filter );
+
+       if ( $output == ARRAY_A )
+               return $_post->to_array();
+       elseif ( $output == ARRAY_N )
+               return array_values( $_post->to_array() );
+
+       return $_post;
+}
+
+/**
+ * Retrieve ancestors of a post.
+ *
+ * @since 2.5.0
+ *
+ * @param int|WP_Post $post Post ID or post object.
+ * @return array Ancestor IDs or empty array if none are found.
+ */
+function get_post_ancestors( $post ) {
+       $post = get_post( $post );
+
+       if ( ! $post || empty( $post->post_parent ) || $post->post_parent == $post->ID )
+               return array();
+
+       $ancestors = array();
+
+       $id = $ancestors[] = $post->post_parent;
+
+       while ( $ancestor = get_post( $id ) ) {
+               // Loop detection: If the ancestor has been seen before, break.
+               if ( empty( $ancestor->post_parent ) || ( $ancestor->post_parent == $post->ID ) || in_array( $ancestor->post_parent, $ancestors ) )
+                       break;
+
+               $id = $ancestors[] = $ancestor->post_parent;
+       }
+
+       return $ancestors;
+}
+
+/**
+ * Retrieve data from a post field based on Post ID.
+ *
+ * Examples of the post field will be, 'post_type', 'post_status', 'post_content',
+ * etc and based off of the post object property or key names.
+ *
+ * The context values are based off of the taxonomy filter functions and
+ * supported values are found within those functions.
+ *
+ * @since 2.3.0
+ *
+ * @see sanitize_post_field()
+ *
+ * @param string      $field   Post field name.
+ * @param int|WP_Post $post    Post ID or post object.
+ * @param string      $context Optional. How to filter the field. Accepts 'raw', 'edit', 'db',
+ *                             or 'display'. Default 'display'.
+ * @return string The value of the post field on success, empty string on failure.
+ */
+function get_post_field( $field, $post, $context = 'display' ) {
+       $post = get_post( $post );
+
+       if ( !$post )
+               return '';
+
+       if ( !isset($post->$field) )
+               return '';
+
+       return sanitize_post_field($field, $post->$field, $post->ID, $context);
+}
+
+/**
+ * Retrieve the mime type of an attachment based on the ID.
+ *
+ * This function can be used with any post type, but it makes more sense with
+ * attachments.
+ *
+ * @since 2.0.0
+ *
+ * @param int|WP_Post $ID Optional. Post ID or post object. Default empty.
+ * @return string|false The mime type on success, false on failure.
+ */
+function get_post_mime_type( $ID = '' ) {
+       $post = get_post($ID);
+
+       if ( is_object($post) )
+               return $post->post_mime_type;
+
+       return false;
+}
+
+/**
+ * Retrieve the post status based on the Post ID.
+ *
+ * If the post ID is of an attachment, then the parent post status will be given
+ * instead.
+ *
+ * @since 2.0.0
+ *
+ * @param int|WP_Post $ID Optional. Post ID or post object. Default empty.
+ * @return string|false Post status on success, false on failure.
+ */
+function get_post_status( $ID = '' ) {
+       $post = get_post($ID);
+
+       if ( !is_object($post) )
+               return false;
+
+       if ( 'attachment' == $post->post_type ) {
+               if ( 'private' == $post->post_status )
+                       return 'private';
+
+               // Unattached attachments are assumed to be published.
+               if ( ( 'inherit' == $post->post_status ) && ( 0 == $post->post_parent) )
+                       return 'publish';
+
+               // Inherit status from the parent.
+               if ( $post->post_parent && ( $post->ID != $post->post_parent ) ) {
+                       $parent_post_status = get_post_status( $post->post_parent );
+                       if ( 'trash' == $parent_post_status ) {
+                               return get_post_meta( $post->post_parent, '_wp_trash_meta_status', true );
+                       } else {
+                               return $parent_post_status;
+                       }
+               }
+
+       }
+
+       /**
+        * Filter the post status.
+        *
+        * @since 4.4.0
+        *
+        * @param string  $post_status The post status.
+        * @param WP_Post $post        The post object.
+        */
+       return apply_filters( 'get_post_status', $post->post_status, $post );
+}
+
+/**
+ * Retrieve all of the WordPress supported post statuses.
+ *
+ * Posts have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of post statuses.
+ */
+function get_post_statuses() {
+       $status = array(
+               'draft'   => __( 'Draft' ),
+               'pending' => __( 'Pending Review' ),
+               'private' => __( 'Private' ),
+               'publish' => __( 'Published' )
+       );
+
+       return $status;
+}
+
+/**
+ * Retrieve all of the WordPress support page statuses.
+ *
+ * Pages have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of page statuses.
+ */
+function get_page_statuses() {
+       $status = array(
+               'draft'   => __( 'Draft' ),
+               'private' => __( 'Private' ),
+               'publish' => __( 'Published' )
+       );
+
+       return $status;
+}
+
+/**
+ * Register a post status. Do not use before init.
+ *
+ * A simple function for creating or modifying a post status based on the
+ * parameters given. The function will accept an array (second optional
+ * parameter), along with a string for the post status name.
+ *
+ * Arguments prefixed with an _underscore shouldn't be used by plugins and themes.
+ *
+ * @since 3.0.0
+ * @global array $wp_post_statuses Inserts new post status object into the list
+ *
+ * @param string $post_status Name of the post status.
+ * @param array|string $args {
+ *     Optional. Array or string of post status arguments.
+ *
+ *     @type bool|string $label                     A descriptive name for the post status marked
+ *                                                  for translation. Defaults to value of $post_status.
+ *     @type bool|array  $label_count               Descriptive text to use for nooped plurals.
+ *                                                  Default array of $label, twice
+ *     @type bool        $exclude_from_search       Whether to exclude posts with this post status
+ *                                                  from search results. Default is value of $internal.
+ *     @type bool        $_builtin                  Whether the status is built-in. Core-use only.
+ *                                                  Default false.
+ *     @type bool        $public                    Whether posts of this status should be shown
+ *                                                  in the front end of the site. Default false.
+ *     @type bool        $internal                  Whether the status is for internal use only.
+ *                                                  Default false.
+ *     @type bool        $protected                 Whether posts with this status should be protected.
+ *                                                  Default false.
+ *     @type bool        $private                   Whether posts with this status should be private.
+ *                                                  Default false.
+ *     @type bool        $publicly_queryable        Whether posts with this status should be publicly-
+ *                                                  queryable. Default is value of $public.
+ *     @type bool        $show_in_admin_all_list    Whether to include posts in the edit listing for
+ *                                                  their post type. Default is value of $internal.
+ *     @type bool        $show_in_admin_status_list Show in the list of statuses with post counts at
+ *                                                  the top of the edit listings,
+ *                                                  e.g. All (12) | Published (9) | My Custom Status (2)
+ *                                                  Default is value of $internal.
+ * }
+ * @return object
+ */
+function register_post_status( $post_status, $args = array() ) {
+       global $wp_post_statuses;
+
+       if (!is_array($wp_post_statuses))
+               $wp_post_statuses = array();
+
+       // Args prefixed with an underscore are reserved for internal use.
+       $defaults = array(
+               'label' => false,
+               'label_count' => false,
+               'exclude_from_search' => null,
+               '_builtin' => false,
+               'public' => null,
+               'internal' => null,
+               'protected' => null,
+               'private' => null,
+               'publicly_queryable' => null,
+               'show_in_admin_status_list' => null,
+               'show_in_admin_all_list' => null,
+       );
+       $args = wp_parse_args($args, $defaults);
+       $args = (object) $args;
+
+       $post_status = sanitize_key($post_status);
+       $args->name = $post_status;
+
+       // Set various defaults.
+       if ( null === $args->public && null === $args->internal && null === $args->protected && null === $args->private )
+               $args->internal = true;
+
+       if ( null === $args->public  )
+               $args->public = false;
+
+       if ( null === $args->private  )
+               $args->private = false;
+
+       if ( null === $args->protected  )
+               $args->protected = false;
+
+       if ( null === $args->internal  )
+               $args->internal = false;
+
+       if ( null === $args->publicly_queryable )
+               $args->publicly_queryable = $args->public;
+
+       if ( null === $args->exclude_from_search )
+               $args->exclude_from_search = $args->internal;
+
+       if ( null === $args->show_in_admin_all_list )
+               $args->show_in_admin_all_list = !$args->internal;
+
+       if ( null === $args->show_in_admin_status_list )
+               $args->show_in_admin_status_list = !$args->internal;
+
+       if ( false === $args->label )
+               $args->label = $post_status;
+
+       if ( false === $args->label_count )
+               $args->label_count = array( $args->label, $args->label );
+
+       $wp_post_statuses[$post_status] = $args;
+
+       return $args;
+}
+
+/**
+ * Retrieve a post status object by name.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_post_statuses List of post statuses.
+ *
+ * @see register_post_status()
+ *
+ * @param string $post_status The name of a registered post status.
+ * @return object|null A post status object.
+ */
+function get_post_status_object( $post_status ) {
+       global $wp_post_statuses;
+
+       if ( empty($wp_post_statuses[$post_status]) )
+               return null;
+
+       return $wp_post_statuses[$post_status];
+}
+
+/**
+ * Get a list of post statuses.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_post_statuses List of post statuses.
+ *
+ * @see register_post_status()
+ *
+ * @param array|string $args     Optional. Array or string of post status arguments to compare against
+ *                               properties of the global `$wp_post_statuses objects`. Default empty array.
+ * @param string       $output   Optional. The type of output to return, either 'names' or 'objects'. Default 'names'.
+ * @param string       $operator Optional. The logical operation to perform. 'or' means only one element
+ *                               from the array needs to match; 'and' means all elements must match.
+ *                               Default 'and'.
+ * @return array A list of post status names or objects.
+ */
+function get_post_stati( $args = array(), $output = 'names', $operator = 'and' ) {
+       global $wp_post_statuses;
+
+       $field = ('names' == $output) ? 'name' : false;
+
+       return wp_filter_object_list($wp_post_statuses, $args, $operator, $field);
+}
+
+/**
+ * Whether the post type is hierarchical.
+ *
+ * A false return value might also mean that the post type does not exist.
+ *
+ * @since 3.0.0
+ *
+ * @see get_post_type_object()
+ *
+ * @param string $post_type Post type name
+ * @return bool Whether post type is hierarchical.
+ */
+function is_post_type_hierarchical( $post_type ) {
+       if ( ! post_type_exists( $post_type ) )
+               return false;
+
+       $post_type = get_post_type_object( $post_type );
+       return $post_type->hierarchical;
+}
+
+/**
+ * Check if a post type is registered.
+ *
+ * @since 3.0.0
+ *
+ * @see get_post_type_object()
+ *
+ * @param string $post_type Post type name.
+ * @return bool Whether post type is registered.
+ */
+function post_type_exists( $post_type ) {
+       return (bool) get_post_type_object( $post_type );
+}
+
+/**
+ * Retrieve the post type of the current post or of a given post.
+ *
+ * @since 2.1.0
+ *
+ * @param int|WP_Post|null $post Optional. Post ID or post object. Default is global $post.
+ * @return string|false          Post type on success, false on failure.
+ */
+function get_post_type( $post = null ) {
+       if ( $post = get_post( $post ) )
+               return $post->post_type;
+
+       return false;
+}
+
+/**
+ * Retrieve a post type object by name.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_post_types List of post types.
+ *
+ * @see register_post_type()
+ *
+ * @param string $post_type The name of a registered post type.
+ * @return object|null A post type object.
+ */
+function get_post_type_object( $post_type ) {
+       global $wp_post_types;
+
+       if ( ! is_scalar( $post_type ) || empty( $wp_post_types[ $post_type ] ) ) {
+               return null;
+       }
+
+       return $wp_post_types[ $post_type ];
+}
+
+/**
+ * Get a list of all registered post type objects.
+ *
+ * @since 2.9.0
+ *
+ * @global array $wp_post_types List of post types.
+ *
+ * @see register_post_type() for accepted arguments.
+ *
+ * @param array|string $args     Optional. An array of key => value arguments to match against
+ *                               the post type objects. Default empty array.
+ * @param string       $output   Optional. The type of output to return. Accepts post type 'names'
+ *                               or 'objects'. Default 'names'.
+ * @param string       $operator Optional. The logical operation to perform. 'or' means only one
+ *                               element from the array needs to match; 'and' means all elements
+ *                               must match. Accepts 'or' or 'and'. Default 'and'.
+ * @return array A list of post type names or objects.
+ */
+function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) {
+       global $wp_post_types;
+
+       $field = ('names' == $output) ? 'name' : false;
+
+       return wp_filter_object_list($wp_post_types, $args, $operator, $field);
+}
+
+/**
+ * Register a post type. Do not use before init.
+ *
+ * A function for creating or modifying a post type based on the
+ * parameters given. The function will accept an array (second optional
+ * parameter), along with a string for the post type name.
+ *
+ * @since 2.9.0
+ * @since 3.0.0 The `show_ui` argument is now enforced on the new post screen.
+ * @since 4.4.0 The `show_ui` argument is now enforced on the post type listing screen and post editing screen.
+ *
+ * @global array      $wp_post_types List of post types.
+ * @global WP_Rewrite $wp_rewrite    Used for default feeds.
+ * @global WP         $wp            Used to add query vars.
+ *
+ * @param string $post_type Post type key, must not exceed 20 characters.
+ * @param array|string $args {
+ *     Array or string of arguments for registering a post type.
+ *
+ *     @type string      $label                Name of the post type shown in the menu. Usually plural.
+ *                                             Default is value of $labels['name'].
+ *     @type array       $labels               An array of labels for this post type. If not set, post
+ *                                             labels are inherited for non-hierarchical types and page
+ *                                             labels for hierarchical ones. {@see get_post_type_labels()}.
+ *     @type string      $description          A short descriptive summary of what the post type is.
+ *                                             Default empty.
+ *     @type bool        $public               Whether a post type is intended for use publicly either via
+ *                                             the admin interface or by front-end users. While the default
+ *                                             settings of $exclude_from_search, $publicly_queryable, $show_ui,
+ *                                             and $show_in_nav_menus are inherited from public, each does not
+ *                                             rely on this relationship and controls a very specific intention.
+ *                                             Default false.
+ *     @type bool        $hierarchical         Whether the post type is hierarchical (e.g. page). Default false.
+ *     @type bool        $exclude_from_search  Whether to exclude posts with this post type from front end search
+ *                                             results. Default is the opposite value of $public.
+ *     @type bool        $publicly_queryable   Whether queries can be performed on the front end for the post type
+ *                                             as part of {@see parse_request()}. Endpoints would include:
+ *                                             * ?post_type={post_type_key}
+ *                                             * ?{post_type_key}={single_post_slug}
+ *                                             * ?{post_type_query_var}={single_post_slug}
+ *                                             If not set, the default is inherited from $public.
+ *     @type bool        $show_ui              Whether to generate and allow a UI for managing this post type in the
+ *                                             admin. Default is value of $public.
+ *     @type bool        $show_in_menu         Where to show the post type in the admin menu. To work, $show_ui
+ *                                             must be true. If true, the post type is shown in its own top level
+ *                                             menu. If false, no menu is shown. If a string of an existing top
+ *                                             level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post
+ *                                             type will be placed as a sub-menu of that.
+ *                                             Default is value of $show_ui.
+ *     @type bool        $show_in_nav_menus    Makes this post type available for selection in navigation menus.
+ *                                             Default is value $public.
+ *     @type bool        $show_in_admin_bar    Makes this post type available via the admin bar. Default is value
+ *                                             of $show_in_menu.
+ *     @type int         $menu_position        The position in the menu order the post type should appear. To work,
+ *                                             $show_in_menu must be true. Default null (at the bottom).
+ *     @type string      $menu_icon            The url to the icon to be used for this menu. Pass a base64-encoded
+ *                                             SVG using a data URI, which will be colored to match the color scheme
+ *                                             -- this should begin with 'data:image/svg+xml;base64,'. Pass the name
+ *                                             of a Dashicons helper class to use a font icon, e.g.
+ *                                             'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty
+ *                                             so an icon can be added via CSS. Defaults to use the posts icon.
+ *     @type string      $capability_type      The string to use to build the read, edit, and delete capabilities.
+ *                                             May be passed as an array to allow for alternative plurals when using
+ *                                             this argument as a base to construct the capabilities, e.g.
+ *                                             array('story', 'stories'). Default 'post'.
+ *     @type array       $capabilities         Array of capabilities for this post type. $capability_type is used
+ *                                             as a base to construct capabilities by default.
+ *                                             {@see get_post_type_capabilities()}.
+ *     @type bool        $map_meta_cap         Whether to use the internal default meta capability handling.
+ *                                             Default false.
+ *     @type array       $supports             An alias for calling {@see add_post_type_support()} directly.
+ *                                             Defaults to array containing 'title' & 'editor'.
+ *     @type callable    $register_meta_box_cb Provide a callback function that sets up the meta boxes for the
+ *                                             edit form. Do remove_meta_box() and add_meta_box() calls in the
+ *                                             callback. Default null.
+ *     @type array       $taxonomies           An array of taxonomy identifiers that will be registered for the
+ *                                             post type. Taxonomies can be registered later with
+ *                                             {@see register_taxonomy()} or {@see register_taxonomy_for_object_type()}.
+ *                                             Default empty array.
+ *     @type bool|string $has_archive          Whether there should be post type archives, or if a string, the
+ *                                             archive slug to use. Will generate the proper rewrite rules if
+ *                                             $rewrite is enabled. Default false.
+ *     @type bool|array  $rewrite              {
+ *         Triggers the handling of rewrites for this post type. To prevent rewrite, set to false.
+ *         Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be
+ *         passed with any of these keys:
+ *
+ *         @type string $slug       Customize the permastruct slug. Defaults to $post_type key.
+ *         @type bool   $with_front Whether the permastruct should be prepended with WP_Rewrite::$front.
+ *                                  Default true.
+ *         @type bool   $feeds      Whether the feed permastruct should be built for this post type.
+ *                                  Default is value of $has_archive.
+ *         @type bool   $pages      Whether the permastruct should provide for pagination. Default true.
+ *         @type const  $ep_mask    Endpoint mask to assign. If not specified and permalink_epmask is set,
+ *                                  inherits from $permalink_epmask. If not specified and permalink_epmask
+ *                                  is not set, defaults to EP_PERMALINK.
+ *     }
+ *     @type string|bool $query_var            Sets the query_var key for this post type. Defaults to $post_type
+ *                                             key. If false, a post type cannot be loaded at
+ *                                             ?{query_var}={post_slug}. If specified as a string, the query
+ *                                             ?{query_var_string}={post_slug} will be valid.
+ *     @type bool        $can_export           Whether to allow this post type to be exported. Default true.
+ *     @type bool        $delete_with_user     Whether to delete posts of this type when deleting a user. If true,
+ *                                             posts of this type belonging to the user will be moved to trash
+ *                                             when then user is deleted. If false, posts of this type belonging
+ *                                             to the user will *not* be trashed or deleted. If not set (the default),
+ *                                             posts are trashed if post_type_supports('author'). Otherwise posts
+ *                                             are not trashed or deleted. Default null.
+ *     @type bool        $_builtin             FOR INTERNAL USE ONLY! True if this post type is a native or
+ *                                             "built-in" post_type. Default false.
+ *     @type string      $_edit_link           FOR INTERNAL USE ONLY! URL segment to use for edit link of
+ *                                             this post type. Default 'post.php?post=%d'.
+ * }
+ * @return object|WP_Error The registered post type object, or an error object.
+ */
+function register_post_type( $post_type, $args = array() ) {
+       global $wp_post_types, $wp_rewrite, $wp;
+
+       if ( ! is_array( $wp_post_types ) ) {
+               $wp_post_types = array();
+       }
+
+       // Sanitize post type name
+       $post_type = sanitize_key( $post_type );
+       $args      = wp_parse_args( $args );
+
+       /**
+        * Filter the arguments for registering a post type.
+        *
+        * @since 4.4.0
+        *
+        * @param array  $args      Array of arguments for registering a post type.
+        * @param string $post_type Post type key.
+        */
+       $args = apply_filters( 'register_post_type_args', $args, $post_type );
+
+       $has_edit_link = ! empty( $args['_edit_link'] );
+
+       // Args prefixed with an underscore are reserved for internal use.
+       $defaults = array(
+               'labels'               => array(),
+               'description'          => '',
+               'public'               => false,
+               'hierarchical'         => false,
+               'exclude_from_search'  => null,
+               'publicly_queryable'   => null,
+               'show_ui'              => null,
+               'show_in_menu'         => null,
+               'show_in_nav_menus'    => null,
+               'show_in_admin_bar'    => null,
+               'menu_position'        => null,
+               'menu_icon'            => null,
+               'capability_type'      => 'post',
+               'capabilities'         => array(),
+               'map_meta_cap'         => null,
+               'supports'             => array(),
+               'register_meta_box_cb' => null,
+               'taxonomies'           => array(),
+               'has_archive'          => false,
+               'rewrite'              => true,
+               'query_var'            => true,
+               'can_export'           => true,
+               'delete_with_user'     => null,
+               '_builtin'             => false,
+               '_edit_link'           => 'post.php?post=%d',
+       );
+       $args = array_merge( $defaults, $args );
+       $args = (object) $args;
+
+       $args->name = $post_type;
+
+       if ( empty( $post_type ) || strlen( $post_type ) > 20 ) {
+               _doing_it_wrong( __FUNCTION__, __( 'Post type names must be between 1 and 20 characters in length.' ), '4.2' );
+               return new WP_Error( 'post_type_length_invalid', __( 'Post type names must be between 1 and 20 characters in length.' ) );
+       }
+
+       // If not set, default to the setting for public.
+       if ( null === $args->publicly_queryable )
+               $args->publicly_queryable = $args->public;
+
+       // If not set, default to the setting for public.
+       if ( null === $args->show_ui )
+               $args->show_ui = $args->public;
+
+       // If not set, default to the setting for show_ui.
+       if ( null === $args->show_in_menu || ! $args->show_ui )
+               $args->show_in_menu = $args->show_ui;
+
+       // If not set, default to the whether the full UI is shown.
+       if ( null === $args->show_in_admin_bar )
+               $args->show_in_admin_bar = (bool) $args->show_in_menu;
+
+       // If not set, default to the setting for public.
+       if ( null === $args->show_in_nav_menus )
+               $args->show_in_nav_menus = $args->public;
+
+       // If not set, default to true if not public, false if public.
+       if ( null === $args->exclude_from_search )
+               $args->exclude_from_search = !$args->public;
+
+       // Back compat with quirky handling in version 3.0. #14122.
+       if ( empty( $args->capabilities ) && null === $args->map_meta_cap && in_array( $args->capability_type, array( 'post', 'page' ) ) )
+               $args->map_meta_cap = true;
+
+       // If not set, default to false.
+       if ( null === $args->map_meta_cap )
+               $args->map_meta_cap = false;
+
+       // If there's no specified edit link and no UI, remove the edit link.
+       if ( ! $args->show_ui && ! $has_edit_link ) {
+               $args->_edit_link = '';
+       }
+
+       $args->cap = get_post_type_capabilities( $args );
+       unset( $args->capabilities );
+
+       if ( is_array( $args->capability_type ) )
+               $args->capability_type = $args->capability_type[0];
+
+       if ( ! empty( $args->supports ) ) {
+               add_post_type_support( $post_type, $args->supports );
+               unset( $args->supports );
+       } elseif ( false !== $args->supports ) {
+               // Add default features
+               add_post_type_support( $post_type, array( 'title', 'editor' ) );
+       }
+
+       if ( false !== $args->query_var ) {
+               if ( true === $args->query_var )
+                       $args->query_var = $post_type;
+               else
+                       $args->query_var = sanitize_title_with_dashes( $args->query_var );
+
+               if ( $wp && is_post_type_viewable( $args ) ) {
+                       $wp->add_query_var( $args->query_var );
+               }
+       }
+
+       if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
+               if ( ! is_array( $args->rewrite ) )
+                       $args->rewrite = array();
+               if ( empty( $args->rewrite['slug'] ) )
+                       $args->rewrite['slug'] = $post_type;
+               if ( ! isset( $args->rewrite['with_front'] ) )
+                       $args->rewrite['with_front'] = true;
+               if ( ! isset( $args->rewrite['pages'] ) )
+                       $args->rewrite['pages'] = true;
+               if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
+                       $args->rewrite['feeds'] = (bool) $args->has_archive;
+               if ( ! isset( $args->rewrite['ep_mask'] ) ) {
+                       if ( isset( $args->permalink_epmask ) )
+                               $args->rewrite['ep_mask'] = $args->permalink_epmask;
+                       else
+                               $args->rewrite['ep_mask'] = EP_PERMALINK;
+               }
+
+               if ( $args->hierarchical )
+                       add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
+               else
+                       add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );
+
+               if ( $args->has_archive ) {
+                       $archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
+                       if ( $args->rewrite['with_front'] )
+                               $archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
+                       else
+                               $archive_slug = $wp_rewrite->root . $archive_slug;
+
+                       add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
+                       if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
+                               $feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
+                               add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
+                               add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
+                       }
+                       if ( $args->rewrite['pages'] )
+                               add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
+               }
+
+               $permastruct_args = $args->rewrite;
+               $permastruct_args['feed'] = $permastruct_args['feeds'];
+               add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
+       }
+
+       // Register the post type meta box if a custom callback was specified.
+       if ( $args->register_meta_box_cb )
+               add_action( 'add_meta_boxes_' . $post_type, $args->register_meta_box_cb, 10, 1 );
+
+       $args->labels = get_post_type_labels( $args );
+       $args->label = $args->labels->name;
+
+       $wp_post_types[ $post_type ] = $args;
+
+       add_action( 'future_' . $post_type, '_future_post_hook', 5, 2 );
+
+       foreach ( $args->taxonomies as $taxonomy ) {
+               register_taxonomy_for_object_type( $taxonomy, $post_type );
+       }
+
+       /**
+        * Fires after a post type is registered.
+        *
+        * @since 3.3.0
+        *
+        * @param string $post_type Post type.
+        * @param object $args      Arguments used to register the post type.
+        */
+       do_action( 'registered_post_type', $post_type, $args );
+
+       return $args;
+}
+
+/**
+ * Build an object with all post type capabilities out of a post type object
+ *
+ * Post type capabilities use the 'capability_type' argument as a base, if the
+ * capability is not set in the 'capabilities' argument array or if the
+ * 'capabilities' argument is not supplied.
+ *
+ * The capability_type argument can optionally be registered as an array, with
+ * the first value being singular and the second plural, e.g. array('story, 'stories')
+ * Otherwise, an 's' will be added to the value for the plural form. After
+ * registration, capability_type will always be a string of the singular value.
+ *
+ * By default, seven keys are accepted as part of the capabilities array:
+ *
+ * - edit_post, read_post, and delete_post are meta capabilities, which are then
+ *   generally mapped to corresponding primitive capabilities depending on the
+ *   context, which would be the post being edited/read/deleted and the user or
+ *   role being checked. Thus these capabilities would generally not be granted
+ *   directly to users or roles.
+ *
+ * - edit_posts - Controls whether objects of this post type can be edited.
+ * - edit_others_posts - Controls whether objects of this type owned by other users
+ *   can be edited. If the post type does not support an author, then this will
+ *   behave like edit_posts.
+ * - publish_posts - Controls publishing objects of this post type.
+ * - read_private_posts - Controls whether private objects can be read.
+ *
+ * These four primitive capabilities are checked in core in various locations.
+ * There are also seven other primitive capabilities which are not referenced
+ * directly in core, except in map_meta_cap(), which takes the three aforementioned
+ * meta capabilities and translates them into one or more primitive capabilities
+ * that must then be checked against the user or role, depending on the context.
+ *
+ * - read - Controls whether objects of this post type can be read.
+ * - delete_posts - Controls whether objects of this post type can be deleted.
+ * - delete_private_posts - Controls whether private objects can be deleted.
+ * - delete_published_posts - Controls whether published objects can be deleted.
+ * - delete_others_posts - Controls whether objects owned by other users can be
+ *   can be deleted. If the post type does not support an author, then this will
+ *   behave like delete_posts.
+ * - edit_private_posts - Controls whether private objects can be edited.
+ * - edit_published_posts - Controls whether published objects can be edited.
+ *
+ * These additional capabilities are only used in map_meta_cap(). Thus, they are
+ * only assigned by default if the post type is registered with the 'map_meta_cap'
+ * argument set to true (default is false).
+ *
+ * @since 3.0.0
+ *
+ * @see register_post_type()
+ * @see map_meta_cap()
+ *
+ * @param object $args Post type registration arguments.
+ * @return object object with all the capabilities as member variables.
+ */
+function get_post_type_capabilities( $args ) {
+       if ( ! is_array( $args->capability_type ) )
+               $args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
+
+       // Singular base for meta capabilities, plural base for primitive capabilities.
+       list( $singular_base, $plural_base ) = $args->capability_type;
+
+       $default_capabilities = array(
+               // Meta capabilities
+               'edit_post'          => 'edit_'         . $singular_base,
+               'read_post'          => 'read_'         . $singular_base,
+               'delete_post'        => 'delete_'       . $singular_base,
+               // Primitive capabilities used outside of map_meta_cap():
+               'edit_posts'         => 'edit_'         . $plural_base,
+               'edit_others_posts'  => 'edit_others_'  . $plural_base,
+               'publish_posts'      => 'publish_'      . $plural_base,
+               'read_private_posts' => 'read_private_' . $plural_base,
+       );
+
+       // Primitive capabilities used within map_meta_cap():
+       if ( $args->map_meta_cap ) {
+               $default_capabilities_for_mapping = array(
+                       'read'                   => 'read',
+                       'delete_posts'           => 'delete_'           . $plural_base,
+                       'delete_private_posts'   => 'delete_private_'   . $plural_base,
+                       'delete_published_posts' => 'delete_published_' . $plural_base,
+                       'delete_others_posts'    => 'delete_others_'    . $plural_base,
+                       'edit_private_posts'     => 'edit_private_'     . $plural_base,
+                       'edit_published_posts'   => 'edit_published_'   . $plural_base,
+               );
+               $default_capabilities = array_merge( $default_capabilities, $default_capabilities_for_mapping );
+       }
+
+       $capabilities = array_merge( $default_capabilities, $args->capabilities );
+
+       // Post creation capability simply maps to edit_posts by default:
+       if ( ! isset( $capabilities['create_posts'] ) )
+               $capabilities['create_posts'] = $capabilities['edit_posts'];
+
+       // Remember meta capabilities for future reference.
+       if ( $args->map_meta_cap )
+               _post_type_meta_capabilities( $capabilities );
+
+       return (object) $capabilities;
+}
+
+/**
+ * Store or return a list of post type meta caps for map_meta_cap().
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @staticvar array $meta_caps
+ *
+ * @param array|void $capabilities Post type meta capabilities.
+ */
+function _post_type_meta_capabilities( $capabilities = null ) {
+       static $meta_caps = array();
+       if ( null === $capabilities )
+               return $meta_caps;
+       foreach ( $capabilities as $core => $custom ) {
+               if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
+                       $meta_caps[ $custom ] = $core;
+       }
+}
+
+/**
+ * Build an object with all post type labels out of a post type object
+ *
+ * Accepted keys of the label array in the post type object:
+ *
+ * - name - general name for the post type, usually plural. The same and overridden
+ *          by $post_type_object->label. Default is Posts/Pages
+ * - singular_name - name for one object of this post type. Default is Post/Page
+ * - add_new - Default is Add New for both hierarchical and non-hierarchical types.
+ *             When internationalizing this string, please use a gettext context
+ *             {@link https://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context}
+ *             matching your post type. Example: `_x( 'Add New', 'product' );`.
+ * - add_new_item - Default is Add New Post/Add New Page.
+ * - edit_item - Default is Edit Post/Edit Page.
+ * - new_item - Default is New Post/New Page.
+ * - view_item - Default is View Post/View Page.
+ * - search_items - Default is Search Posts/Search Pages.
+ * - not_found - Default is No posts found/No pages found.
+ * - not_found_in_trash - Default is No posts found in Trash/No pages found in Trash.
+ * - parent_item_colon - This string isn't used on non-hierarchical types. In hierarchical
+ *                       ones the default is 'Parent Page:'.
+ * - all_items - String for the submenu. Default is All Posts/All Pages.
+ * - archives - String for use with archives in nav menus. Default is Post Archives/Page Archives.
+ * - insert_into_item - String for the media frame button. Default is Insert into post/Insert into page.
+ * - uploaded_to_this_item - String for the media frame filter. Default is Uploaded to this post/Uploaded to this page.
+ * - featured_image - Default is Featured Image.
+ * - set_featured_image - Default is Set featured image.
+ * - remove_featured_image - Default is Remove featured image.
+ * - use_featured_image - Default is Use as featured image.
+ * - menu_name - Default is the same as `name`.
+ * - filter_items_list - String for the table views hidden heading.
+ * - items_list_navigation - String for the table pagination hidden heading.
+ * - items_list - String for the table hidden heading.
+ *
+ * Above, the first default value is for non-hierarchical post types (like posts)
+ * and the second one is for hierarchical post types (like pages).
+ *
+ * @since 3.0.0
+ * @since 4.3.0 Added the `featured_image`, `set_featured_image`, `remove_featured_image`,
+ *              and `use_featured_image` labels.
+ * @since 4.4.0 Added the `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`,
+ *              `items_list_navigation`, and `items_list` labels.
+ *
+ * @access private
+ *
+ * @param object $post_type_object Post type object.
+ * @return object object with all the labels as member variables.
+ */
+function get_post_type_labels( $post_type_object ) {
+       $nohier_vs_hier_defaults = array(
+               'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
+               'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
+               'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
+               'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
+               'edit_item' => array( __('Edit Post'), __('Edit Page') ),
+               'new_item' => array( __('New Post'), __('New Page') ),
+               'view_item' => array( __('View Post'), __('View Page') ),
+               'search_items' => array( __('Search Posts'), __('Search Pages') ),
+               'not_found' => array( __('No posts found.'), __('No pages found.') ),
+               'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
+               'parent_item_colon' => array( null, __('Parent Page:') ),
+               'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ),
+               'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ),
+               'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ),
+               'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ),
+               'featured_image' => array( __( 'Featured Image' ), __( 'Featured Image' ) ),
+               'set_featured_image' => array( __( 'Set featured image' ), __( 'Set featured image' ) ),
+               'remove_featured_image' => array( __( 'Remove featured image' ), __( 'Remove featured image' ) ),
+               'use_featured_image' => array( __( 'Use as featured image' ), __( 'Use as featured image' ) ),
+               'filter_items_list' => array( __( 'Filter posts list' ), __( 'Filter pages list' ) ),
+               'items_list_navigation' => array( __( 'Posts list navigation' ), __( 'Pages list navigation' ) ),
+               'items_list' => array( __( 'Posts list' ), __( 'Pages list' ) ),
+       );
+       $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
+
+       $labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
+
+       $post_type = $post_type_object->name;
+
+       $default_labels = clone $labels;
+
+       /**
+        * Filter the labels of a specific post type.
+        *
+        * The dynamic portion of the hook name, `$post_type`, refers to
+        * the post type slug.
+        *
+        * @since 3.5.0
+        *
+        * @see get_post_type_labels() for the full list of labels.
+        *
+        * @param object $labels Object with labels for the post type as member variables.
+        */
+       $labels = apply_filters( "post_type_labels_{$post_type}", $labels );
+
+       // Ensure that the filtered labels contain all required default values.
+       $labels = (object) array_merge( (array) $default_labels, (array) $labels );
+
+       return $labels;
+}
+
+/**
+ * Build an object with custom-something object (post type, taxonomy) labels
+ * out of a custom-something object
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param object $object                  A custom-something object.
+ * @param array  $nohier_vs_hier_defaults Hierarchical vs non-hierarchical default labels.
+ * @return object Object containing labels for the given custom-something object.
+ */
+function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
+       $object->labels = (array) $object->labels;
+
+       if ( isset( $object->label ) && empty( $object->labels['name'] ) )
+               $object->labels['name'] = $object->label;
+
+       if ( !isset( $object->labels['singular_name'] ) && isset( $object->labels['name'] ) )
+               $object->labels['singular_name'] = $object->labels['name'];
+
+       if ( ! isset( $object->labels['name_admin_bar'] ) )
+               $object->labels['name_admin_bar'] = isset( $object->labels['singular_name'] ) ? $object->labels['singular_name'] : $object->name;
+
+       if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
+               $object->labels['menu_name'] = $object->labels['name'];
+
+       if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
+               $object->labels['all_items'] = $object->labels['menu_name'];
+
+       if ( !isset( $object->labels['archives'] ) && isset( $object->labels['all_items'] ) ) {
+               $object->labels['archives'] = $object->labels['all_items'];
+       }
+
+       $defaults = array();
+       foreach ( $nohier_vs_hier_defaults as $key => $value ) {
+               $defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
+       }
+       $labels = array_merge( $defaults, $object->labels );
+       $object->labels = (object) $object->labels;
+
+       return (object) $labels;
+}
+
+/**
+ * Add submenus for post types.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _add_post_type_submenus() {
+       foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) {
+               $ptype_obj = get_post_type_object( $ptype );
+               // Sub-menus only.
+               if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true )
+                       continue;
+               add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" );
+       }
+}
+
+/**
+ * Register support of certain features for a post type.
+ *
+ * All core features are directly associated with a functional area of the edit
+ * screen, such as the editor or a meta box. Features include: 'title', 'editor',
+ * 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes',
+ * 'thumbnail', 'custom-fields', and 'post-formats'.
+ *
+ * Additionally, the 'revisions' feature dictates whether the post type will
+ * store revisions, and the 'comments' feature dictates whether the comments
+ * count will show on the edit screen.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string       $post_type The post type for which to add the feature.
+ * @param string|array $feature   The feature being added, accepts an array of
+ *                                feature strings or a single string.
+ */
+function add_post_type_support( $post_type, $feature ) {
+       global $_wp_post_type_features;
+
+       $features = (array) $feature;
+       foreach ($features as $feature) {
+               if ( func_num_args() == 2 )
+                       $_wp_post_type_features[$post_type][$feature] = true;
+               else
+                       $_wp_post_type_features[$post_type][$feature] = array_slice( func_get_args(), 2 );
+       }
+}
+
+/**
+ * Remove support for a feature from a post type.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type for which to remove the feature.
+ * @param string $feature   The feature being removed.
+ */
+function remove_post_type_support( $post_type, $feature ) {
+       global $_wp_post_type_features;
+
+       unset( $_wp_post_type_features[ $post_type ][ $feature ] );
+}
+
+/**
+ * Get all the post type features
+ *
+ * @since 3.4.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type.
+ * @return array Post type supports list.
+ */
+function get_all_post_type_supports( $post_type ) {
+       global $_wp_post_type_features;
+
+       if ( isset( $_wp_post_type_features[$post_type] ) )
+               return $_wp_post_type_features[$post_type];
+
+       return array();
+}
+
+/**
+ * Check a post type's support for a given feature.
+ *
+ * @since 3.0.0
+ *
+ * @global array $_wp_post_type_features
+ *
+ * @param string $post_type The post type being checked.
+ * @param string $feature   The feature being checked.
+ * @return bool Whether the post type supports the given feature.
+ */
+function post_type_supports( $post_type, $feature ) {
+       global $_wp_post_type_features;
+
+       return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
+}
+
+/**
+ * Update the post type for the post ID.
+ *
+ * The page or post cache will be cleaned for the post ID.
+ *
+ * @since 2.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int    $post_id   Optional. Post ID to change post type. Default 0.
+ * @param string $post_type Optional. Post type. Accepts 'post' or 'page' to
+ *                          name a few. Default 'post'.
+ * @return int|false Amount of rows changed. Should be 1 for success and 0 for failure.
+ */
+function set_post_type( $post_id = 0, $post_type = 'post' ) {
+       global $wpdb;
+
+       $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
+       $return = $wpdb->update( $wpdb->posts, array('post_type' => $post_type), array('ID' => $post_id) );
+
+       clean_post_cache( $post_id );
+
+       return $return;
+}
+
+/**
+ * Determines whether a post type is considered "viewable".
+ *
+ * For built-in post types such as posts and pages, the 'public' value will be evaluated.
+ * For all others, the 'publicly_queryable' value will be used.
+ *
+ * @since 4.4.0
+ *
+ * @param object $post_type_object Post type object.
+ * @return bool Whether the post type should be considered viewable.
+ */
+function is_post_type_viewable( $post_type_object ) {
+       return $post_type_object->publicly_queryable || ( $post_type_object->_builtin && $post_type_object->public );
+}
+
+/**
+ * Retrieve list of latest posts or posts matching criteria.
+ *
+ * The defaults are as follows:
+ *
+ * @since 1.2.0
+ *
+ * @see WP_Query::parse_query()
+ *
+ * @param array $args {
+ *     Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all
+ *     available arguments.
+ *
+ *     @type int        $numberposts      Total number of posts to retrieve. Is an alias of $posts_per_page
+ *                                        in WP_Query. Accepts -1 for all. Default 5.
+ *     @type int|string $category         Category ID or comma-separated list of IDs (this or any children).
+ *                                        Is an alias of $cat in WP_Query. Default 0.
+ *     @type array      $include          An array of post IDs to retrieve, sticky posts will be included.
+ *                                        Is an alias of $post__in in WP_Query. Default empty array.
+ *     @type array      $exclude          An array of post IDs not to retrieve. Default empty array.
+ *     @type bool       $suppress_filters Whether to suppress filters. Default true.
+ * }
+ * @return array List of posts.
+ */
+function get_posts( $args = null ) {
+       $defaults = array(
+               'numberposts' => 5,
+               'category' => 0, 'orderby' => 'date',
+               'order' => 'DESC', 'include' => array(),
+               'exclude' => array(), 'meta_key' => '',
+               'meta_value' =>'', 'post_type' => 'post',
+               'suppress_filters' => true
+       );
+
+       $r = wp_parse_args( $args, $defaults );
+       if ( empty( $r['post_status'] ) )
+               $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
+       if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
+               $r['posts_per_page'] = $r['numberposts'];
+       if ( ! empty($r['category']) )
+               $r['cat'] = $r['category'];
+       if ( ! empty($r['include']) ) {
+               $incposts = wp_parse_id_list( $r['include'] );
+               $r['posts_per_page'] = count($incposts);  // only the number of posts included
+               $r['post__in'] = $incposts;
+       } elseif ( ! empty($r['exclude']) )
+               $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );
+
+       $r['ignore_sticky_posts'] = true;
+       $r['no_found_rows'] = true;
+
+       $get_posts = new WP_Query;
+       return $get_posts->query($r);
+
+}
+
+//
+// Post meta functions
+//
+
+/**
+ * Add meta data field to a post.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Screen.
+ *
+ * @since 1.5.0
+ *
+ * @param int    $post_id    Post ID.
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
+ * @param bool   $unique     Optional. Whether the same key should not be added.
+ *                           Default false.
+ * @return int|false Meta ID on success, false on failure.
+ */
+function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
+       // Make sure meta is added to the post, not a revision.
+       if ( $the_post = wp_is_post_revision($post_id) )
+               $post_id = $the_post;
+
+       return add_metadata('post', $post_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a post.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 1.5.0
+ *
+ * @param int    $post_id    Post ID.
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Optional. Metadata value. Must be serializable if
+ *                           non-scalar. Default empty.
+ * @return bool True on success, false on failure.
+ */
+function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
+       // Make sure meta is added to the post, not a revision.
+       if ( $the_post = wp_is_post_revision($post_id) )
+               $post_id = $the_post;
+
+       return delete_metadata('post', $post_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve post meta field for a post.
+ *
+ * @since 1.5.0
+ *
+ * @param int    $post_id Post ID.
+ * @param string $key     Optional. The meta key to retrieve. By default, returns
+ *                        data for all keys. Default empty.
+ * @param bool   $single  Optional. Whether to return a single value. Default false.
+ * @return mixed Will be an array if $single is false. Will be value of meta data
+ *               field if $single is true.
+ */
+function get_post_meta( $post_id, $key = '', $single = false ) {
+       return get_metadata('post', $post_id, $key, $single);
+}
+
+/**
+ * Update post meta field based on post ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and post ID.
+ *
+ * If the meta field for the post does not exist, it will be added.
+ *
+ * @since 1.5.0
+ *
+ * @param int    $post_id    Post ID.
+ * @param string $meta_key   Metadata key.
+ * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
+ * @param mixed  $prev_value Optional. Previous value to check before removing.
+ *                           Default empty.
+ * @return int|bool Meta ID if the key didn't exist, true on successful update,
+ *                  false on failure.
+ */
+function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
+       // Make sure meta is added to the post, not a revision.
+       if ( $the_post = wp_is_post_revision($post_id) )
+               $post_id = $the_post;
+
+       return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Delete everything from post meta matching meta key.
+ *
+ * @since 2.3.0
+ *
+ * @param string $post_meta_key Key to search for when deleting.
+ * @return bool Whether the post meta key was deleted from the database.
+ */
+function delete_post_meta_by_key( $post_meta_key ) {
+       return delete_metadata( 'post', null, $post_meta_key, '', true );
+}
+
+/**
+ * Retrieve post meta fields, based on post ID.
+ *
+ * The post meta fields are retrieved from the cache where possible,
+ * so the function is optimized to be called more than once.
+ *
+ * @since 1.2.0
+ *
+ * @param int $post_id Optional. Post ID. Default is ID of the global $post.
+ * @return array Post meta for the given post.
+ */
+function get_post_custom( $post_id = 0 ) {
+       $post_id = absint( $post_id );
+       if ( ! $post_id )
+               $post_id = get_the_ID();
+
+       return get_post_meta( $post_id );
+}
+
+/**
+ * Retrieve meta field names for a post.
+ *
+ * If there are no meta fields, then nothing (null) will be returned.
+ *
+ * @since 1.2.0
+ *
+ * @param int $post_id Optional. Post ID. Default is ID of the global $post.
+ * @return array|void Array of the keys, if retrieved.
+ */
+function get_post_custom_keys( $post_id = 0 ) {
+       $custom = get_post_custom( $post_id );
+
+       if ( !is_array($custom) )
+               return;
+
+       if ( $keys = array_keys($custom) )
+               return $keys;
+}
+
+/**
+ * Retrieve values for a custom post field.
+ *
+ * The parameters must not be considered optional. All of the post meta fields
+ * will be retrieved and only the meta field key values returned.
+ *
+ * @since 1.2.0
+ *
+ * @param string $key     Optional. Meta field key. Default empty.
+ * @param int    $post_id Optional. Post ID. Default is ID of the global $post.
+ * @return array|null Meta field values.
+ */
+function get_post_custom_values( $key = '', $post_id = 0 ) {
+       if ( !$key )
+               return null;
+
+       $custom = get_post_custom($post_id);
+
+       return isset($custom[$key]) ? $custom[$key] : null;
+}
+
+/**
+ * Check if post is sticky.
+ *
+ * Sticky posts should remain at the top of The Loop. If the post ID is not
+ * given, then The Loop ID for the current post will be used.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Optional. Post ID. Default is ID of the global $post.
+ * @return bool Whether post is sticky.
+ */
+function is_sticky( $post_id = 0 ) {
+       $post_id = absint( $post_id );
+
+       if ( ! $post_id )
+               $post_id = get_the_ID();
+
+       $stickies = get_option( 'sticky_posts' );
+
+       if ( ! is_array( $stickies ) )
+               return false;
+
+       if ( in_array( $post_id, $stickies ) )
+               return true;
+
+       return false;
+}
+
+/**
+ * Sanitize every post field.
+ *
+ * If the context is 'raw', then the post object or array will get minimal
+ * sanitization of the integer fields.
+ *
+ * @since 2.3.0
+ *
+ * @see sanitize_post_field()
+ *
+ * @param object|WP_Post|array $post    The Post Object or Array
+ * @param string               $context Optional. How to sanitize post fields.
+ *                                      Accepts 'raw', 'edit', 'db', or 'display'.
+ *                                      Default 'display'.
+ * @return object|WP_Post|array The now sanitized Post Object or Array (will be the
+ *                              same type as $post).
+ */
+function sanitize_post( $post, $context = 'display' ) {
+       if ( is_object($post) ) {
+               // Check if post already filtered for this context.
+               if ( isset($post->filter) && $context == $post->filter )
+                       return $post;
+               if ( !isset($post->ID) )
+                       $post->ID = 0;
+               foreach ( array_keys(get_object_vars($post)) as $field )
+                       $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
+               $post->filter = $context;
+       } elseif ( is_array( $post ) ) {
+               // Check if post already filtered for this context.
+               if ( isset($post['filter']) && $context == $post['filter'] )
+                       return $post;
+               if ( !isset($post['ID']) )
+                       $post['ID'] = 0;
+               foreach ( array_keys($post) as $field )
+                       $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
+               $post['filter'] = $context;
+       }
+       return $post;
+}
+
+/**
+ * Sanitize post field based on context.
+ *
+ * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and
+ * 'js'. The 'display' context is used by default. 'attribute' and 'js' contexts
+ * are treated like 'display' when calling filters.
+ *
+ * @since 2.3.0
+ * @since 4.4.0 Like `sanitize_post()`, `$context` defaults to 'display'.
+ *
+ * @param string $field   The Post Object field name.
+ * @param mixed  $value   The Post Object value.
+ * @param int    $post_id Post ID.
+ * @param string $context Optional. How to sanitize post fields. Looks for 'raw', 'edit',
+ *                        'db', 'display', 'attribute' and 'js'. Default 'display'.
+ * @return mixed Sanitized value.
+ */
+function sanitize_post_field( $field, $value, $post_id, $context = 'display' ) {
+       $int_fields = array('ID', 'post_parent', 'menu_order');
+       if ( in_array($field, $int_fields) )
+               $value = (int) $value;
+
+       // Fields which contain arrays of integers.
+       $array_int_fields = array( 'ancestors' );
+       if ( in_array($field, $array_int_fields) ) {
+               $value = array_map( 'absint', $value);
+               return $value;
+       }
+
+       if ( 'raw' == $context )
+               return $value;
+
+       $prefixed = false;
+       if ( false !== strpos($field, 'post_') ) {
+               $prefixed = true;
+               $field_no_prefix = str_replace('post_', '', $field);
+       }
+
+       if ( 'edit' == $context ) {
+               $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
+
+               if ( $prefixed ) {
+
+                       /**
+                        * Filter the value of a specific post field to edit.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the post
+                        * field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed $value   Value of the post field.
+                        * @param int   $post_id Post ID.
+                        */
+                       $value = apply_filters( "edit_{$field}", $value, $post_id );
+
+                       /**
+                        * Filter the value of a specific post field to edit.
+                        *
+                        * The dynamic portion of the hook name, `$field_no_prefix`, refers to
+                        * the post field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed $value   Value of the post field.
+                        * @param int   $post_id Post ID.
+                        */
+                       $value = apply_filters( "{$field_no_prefix}_edit_pre", $value, $post_id );
+               } else {
+                       $value = apply_filters( "edit_post_{$field}", $value, $post_id );
+               }
+
+               if ( in_array($field, $format_to_edit) ) {
+                       if ( 'post_content' == $field )
+                               $value = format_to_edit($value, user_can_richedit());
+                       else
+                               $value = format_to_edit($value);
+               } else {
+                       $value = esc_attr($value);
+               }
+       } elseif ( 'db' == $context ) {
+               if ( $prefixed ) {
+
+                       /**
+                        * Filter the value of a specific post field before saving.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the post
+                        * field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed $value Value of the post field.
+                        */
+                       $value = apply_filters( "pre_{$field}", $value );
+
+                       /**
+                        * Filter the value of a specific field before saving.
+                        *
+                        * The dynamic portion of the hook name, `$field_no_prefix`, refers
+                        * to the post field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed $value Value of the post field.
+                        */
+                       $value = apply_filters( "{$field_no_prefix}_save_pre", $value );
+               } else {
+                       $value = apply_filters( "pre_post_{$field}", $value );
+
+                       /**
+                        * Filter the value of a specific post field before saving.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the post
+                        * field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed $value Value of the post field.
+                        */
+                       $value = apply_filters( "{$field}_pre", $value );
+               }
+       } else {
+
+               // Use display filters by default.
+               if ( $prefixed ) {
+
+                       /**
+                        * Filter the value of a specific post field for display.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the post
+                        * field name.
+                        *
+                        * @since 2.3.0
+                        *
+                        * @param mixed  $value   Value of the prefixed post field.
+                        * @param int    $post_id Post ID.
+                        * @param string $context Context for how to sanitize the field. Possible
+                        *                        values include 'raw', 'edit', 'db', 'display',
+                        *                        'attribute' and 'js'.
+                        */
+                       $value = apply_filters( $field, $value, $post_id, $context );
+               } else {
+                       $value = apply_filters( "post_{$field}", $value, $post_id, $context );
+               }
+       }
+
+       if ( 'attribute' == $context )
+               $value = esc_attr($value);
+       elseif ( 'js' == $context )
+               $value = esc_js($value);
+
+       return $value;
+}
+
+/**
+ * Make a post sticky.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function stick_post( $post_id ) {
+       $stickies = get_option('sticky_posts');
+
+       if ( !is_array($stickies) )
+               $stickies = array($post_id);
+
+       if ( ! in_array($post_id, $stickies) )
+               $stickies[] = $post_id;
+
+       update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Un-stick a post.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function unstick_post( $post_id ) {
+       $stickies = get_option('sticky_posts');
+
+       if ( !is_array($stickies) )
+               return;
+
+       if ( ! in_array($post_id, $stickies) )
+               return;
+
+       $offset = array_search($post_id, $stickies);
+       if ( false === $offset )
+               return;
+
+       array_splice($stickies, $offset, 1);
+
+       update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Return the cache key for wp_count_posts() based on the passed arguments.
+ *
+ * @since 3.9.0
+ *
+ * @param string $type Optional. Post type to retrieve count Default 'post'.
+ * @param string $perm Optional. 'readable' or empty. Default empty.
+ * @return string The cache key.
+ */
+function _count_posts_cache_key( $type = 'post', $perm = '' ) {
+       $cache_key = 'posts-' . $type;
+       if ( 'readable' == $perm && is_user_logged_in() ) {
+               $post_type_object = get_post_type_object( $type );
+               if ( $post_type_object && ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
+                       $cache_key .= '_' . $perm . '_' . get_current_user_id();
+               }
+       }
+       return $cache_key;
+}
+
+/**
+ * Count number of posts of a post type and if user has permissions to view.
+ *
+ * This function provides an efficient method of finding the amount of post's
+ * type a blog has. Another method is to count the amount of items in
+ * get_posts(), but that method has a lot of overhead with doing so. Therefore,
+ * when developing for 2.5+, use this function instead.
+ *
+ * The $perm parameter checks for 'readable' value and if the user can read
+ * private posts, it will display that for the user that is signed in.
+ *
+ * @since 2.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $type Optional. Post type to retrieve count. Default 'post'.
+ * @param string $perm Optional. 'readable' or empty. Default empty.
+ * @return object Number of posts for each status.
+ */
+function wp_count_posts( $type = 'post', $perm = '' ) {
+       global $wpdb;
+
+       if ( ! post_type_exists( $type ) )
+               return new stdClass;
+
+       $cache_key = _count_posts_cache_key( $type, $perm );
+
+       $counts = wp_cache_get( $cache_key, 'counts' );
+       if ( false !== $counts ) {
+               /** This filter is documented in wp-includes/post-functions.php */
+               return apply_filters( 'wp_count_posts', $counts, $type, $perm );
+       }
+
+       $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
+       if ( 'readable' == $perm && is_user_logged_in() ) {
+               $post_type_object = get_post_type_object($type);
+               if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
+                       $query .= $wpdb->prepare( " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
+                               get_current_user_id()
+                       );
+               }
+       }
+       $query .= ' GROUP BY post_status';
+
+       $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
+       $counts = array_fill_keys( get_post_stati(), 0 );
+
+       foreach ( $results as $row ) {
+               $counts[ $row['post_status'] ] = $row['num_posts'];
+       }
+
+       $counts = (object) $counts;
+       wp_cache_set( $cache_key, $counts, 'counts' );
+
+       /**
+        * Modify returned post counts by status for the current post type.
+        *
+        * @since 3.7.0
+        *
+        * @param object $counts An object containing the current post_type's post
+        *                       counts by status.
+        * @param string $type   Post type.
+        * @param string $perm   The permission to determine if the posts are 'readable'
+        *                       by the current user.
+        */
+       return apply_filters( 'wp_count_posts', $counts, $type, $perm );
+}
+
+/**
+ * Count number of attachments for the mime type(s).
+ *
+ * If you set the optional mime_type parameter, then an array will still be
+ * returned, but will only have the item you are looking for. It does not give
+ * you the number of attachments that are children of a post. You can get that
+ * by counting the number of children that post has.
+ *
+ * @since 2.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string|array $mime_type Optional. Array or comma-separated list of
+ *                                MIME patterns. Default empty.
+ * @return object An object containing the attachment counts by mime type.
+ */
+function wp_count_attachments( $mime_type = '' ) {
+       global $wpdb;
+
+       $and = wp_post_mime_type_where( $mime_type );
+       $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' $and GROUP BY post_mime_type", ARRAY_A );
+
+       $counts = array();
+       foreach ( (array) $count as $row ) {
+               $counts[ $row['post_mime_type'] ] = $row['num_posts'];
+       }
+       $counts['trash'] = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and");
+
+       /**
+        * Modify returned attachment counts by mime type.
+        *
+        * @since 3.7.0
+        *
+        * @param object $counts    An object containing the attachment counts by
+        *                          mime type.
+        * @param string $mime_type The mime type pattern used to filter the attachments
+        *                          counted.
+        */
+       return apply_filters( 'wp_count_attachments', (object) $counts, $mime_type );
+}
+
+/**
+ * Get default post mime types.
+ *
+ * @since 2.9.0
+ *
+ * @return array List of post mime types.
+ */
+function get_post_mime_types() {
+       $post_mime_types = array(       //      array( adj, noun )
+               'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
+               'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
+               'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
+       );
+
+       /**
+        * Filter the default list of post mime types.
+        *
+        * @since 2.5.0
+        *
+        * @param array $post_mime_types Default list of post mime types.
+        */
+       return apply_filters( 'post_mime_types', $post_mime_types );
+}
+
+/**
+ * Check a MIME-Type against a list.
+ *
+ * If the wildcard_mime_types parameter is a string, it must be comma separated
+ * list. If the real_mime_types is a string, it is also comma separated to
+ * create the list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $wildcard_mime_types Mime types, e.g. audio/mpeg or image (same as image/*)
+ *                                          or flash (same as *flash*).
+ * @param string|array $real_mime_types     Real post mime type values.
+ * @return array array(wildcard=>array(real types)).
+ */
+function wp_match_mime_types( $wildcard_mime_types, $real_mime_types ) {
+       $matches = array();
+       if ( is_string( $wildcard_mime_types ) ) {
+               $wildcard_mime_types = array_map( 'trim', explode( ',', $wildcard_mime_types ) );
+       }
+       if ( is_string( $real_mime_types ) ) {
+               $real_mime_types = array_map( 'trim', explode( ',', $real_mime_types ) );
+       }
+
+       $patternses = array();
+       $wild = '[-._a-z0-9]*';
+
+       foreach ( (array) $wildcard_mime_types as $type ) {
+               $mimes = array_map( 'trim', explode( ',', $type ) );
+               foreach ( $mimes as $mime ) {
+                       $regex = str_replace( '__wildcard__', $wild, preg_quote( str_replace( '*', '__wildcard__', $mime ) ) );
+                       $patternses[][$type] = "^$regex$";
+                       if ( false === strpos( $mime, '/' ) ) {
+                               $patternses[][$type] = "^$regex/";
+                               $patternses[][$type] = $regex;
+                       }
+               }
+       }
+       asort( $patternses );
+
+       foreach ( $patternses as $patterns ) {
+               foreach ( $patterns as $type => $pattern ) {
+                       foreach ( (array) $real_mime_types as $real ) {
+                               if ( preg_match( "#$pattern#", $real ) && ( empty( $matches[$type] ) || false === array_search( $real, $matches[$type] ) ) ) {
+                                       $matches[$type][] = $real;
+                               }
+                       }
+               }
+       }
+       return $matches;
+}
+
+/**
+ * Convert MIME types into SQL.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $post_mime_types List of mime types or comma separated string
+ *                                      of mime types.
+ * @param string       $table_alias     Optional. Specify a table alias, if needed.
+ *                                      Default empty.
+ * @return string The SQL AND clause for mime searching.
+ */
+function wp_post_mime_type_where( $post_mime_types, $table_alias = '' ) {
+       $where = '';
+       $wildcards = array('', '%', '%/%');
+       if ( is_string($post_mime_types) )
+               $post_mime_types = array_map('trim', explode(',', $post_mime_types));
+
+       $wheres = array();
+
+       foreach ( (array) $post_mime_types as $mime_type ) {
+               $mime_type = preg_replace('/\s/', '', $mime_type);
+               $slashpos = strpos($mime_type, '/');
+               if ( false !== $slashpos ) {
+                       $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
+                       $mime_subgroup = preg_replace('/[^-*.+a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
+                       if ( empty($mime_subgroup) )
+                               $mime_subgroup = '*';
+                       else
+                               $mime_subgroup = str_replace('/', '', $mime_subgroup);
+                       $mime_pattern = "$mime_group/$mime_subgroup";
+               } else {
+                       $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
+                       if ( false === strpos($mime_pattern, '*') )
+                               $mime_pattern .= '/*';
+               }
+
+               $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
+
+               if ( in_array( $mime_type, $wildcards ) )
+                       return '';
+
+               if ( false !== strpos($mime_pattern, '%') )
+                       $wheres[] = empty($table_alias) ? "post_mime_type LIKE '$mime_pattern'" : "$table_alias.post_mime_type LIKE '$mime_pattern'";
+               else
+                       $wheres[] = empty($table_alias) ? "post_mime_type = '$mime_pattern'" : "$table_alias.post_mime_type = '$mime_pattern'";
+       }
+       if ( !empty($wheres) )
+               $where = ' AND (' . join(' OR ', $wheres) . ') ';
+       return $where;
+}
+
+/**
+ * Trash or delete a post or page.
+ *
+ * When the post and page is permanently deleted, everything that is tied to
+ * it is deleted also. This includes comments, post meta fields, and terms
+ * associated with the post.
+ *
+ * The post or page is moved to trash instead of permanently deleted unless
+ * trash is disabled, item is already in the trash, or $force_delete is true.
+ *
+ * @since 1.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @see wp_delete_attachment()
+ * @see wp_trash_post()
+ *
+ * @param int  $postid       Optional. Post ID. Default 0.
+ * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
+ *                           Default false.
+ * @return array|false|WP_Post False on failure.
+ */
+function wp_delete_post( $postid = 0, $force_delete = false ) {
+       global $wpdb;
+
+       if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
+               return $post;
+
+       if ( !$force_delete && ( $post->post_type == 'post' || $post->post_type == 'page') && get_post_status( $postid ) != 'trash' && EMPTY_TRASH_DAYS )
+               return wp_trash_post( $postid );
+
+       if ( $post->post_type == 'attachment' )
+               return wp_delete_attachment( $postid, $force_delete );
+
+       /**
+        * Filter whether a post deletion should take place.
+        *
+        * @since 4.4.0
+        *
+        * @param bool    $delete       Whether to go forward with deletion.
+        * @param WP_Post $post         Post object.
+        * @param bool    $force_delete Whether to bypass the trash.
+        */
+       $check = apply_filters( 'pre_delete_post', null, $post, $force_delete );
+       if ( null !== $check ) {
+               return $check;
+       }
+
+       /**
+        * Fires before a post is deleted, at the start of wp_delete_post().
+        *
+        * @since 3.2.0
+        *
+        * @see wp_delete_post()
+        *
+        * @param int $postid Post ID.
+        */
+       do_action( 'before_delete_post', $postid );
+
+       delete_post_meta($postid,'_wp_trash_meta_status');
+       delete_post_meta($postid,'_wp_trash_meta_time');
+
+       wp_delete_object_term_relationships($postid, get_object_taxonomies($post->post_type));
+
+       $parent_data = array( 'post_parent' => $post->post_parent );
+       $parent_where = array( 'post_parent' => $postid );
+
+       if ( is_post_type_hierarchical( $post->post_type ) ) {
+               // Point children of this page to its parent, also clean the cache of affected children.
+               $children_query = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $postid, $post->post_type );
+               $children = $wpdb->get_results( $children_query );
+
+               $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
+       }
+
+       // Do raw query. wp_get_post_revisions() is filtered.
+       $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
+       // Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
+       foreach ( $revision_ids as $revision_id )
+               wp_delete_post_revision( $revision_id );
+
+       // Point all attachments to this post up one level.
+       $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
+
+       wp_defer_comment_counting( true );
+
+       $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
+       foreach ( $comment_ids as $comment_id ) {
+               wp_delete_comment( $comment_id, true );
+       }
+
+       wp_defer_comment_counting( false );
+
+       $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
+       foreach ( $post_meta_ids as $mid )
+               delete_metadata_by_mid( 'post', $mid );
+
+       /**
+        * Fires immediately before a post is deleted from the database.
+        *
+        * @since 1.2.0
+        *
+        * @param int $postid Post ID.
+        */
+       do_action( 'delete_post', $postid );
+       $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) );
+       if ( ! $result ) {
+               return false;
+       }
+
+       /**
+        * Fires immediately after a post is deleted from the database.
+        *
+        * @since 2.2.0
+        *
+        * @param int $postid Post ID.
+        */
+       do_action( 'deleted_post', $postid );
+
+       clean_post_cache( $post );
+
+       if ( is_post_type_hierarchical( $post->post_type ) && $children ) {
+               foreach ( $children as $child )
+                       clean_post_cache( $child );
+       }
+
+       wp_clear_scheduled_hook('publish_future_post', array( $postid ) );
+
+       /**
+        * Fires after a post is deleted, at the conclusion of wp_delete_post().
+        *
+        * @since 3.2.0
+        *
+        * @see wp_delete_post()
+        *
+        * @param int $postid Post ID.
+        */
+       do_action( 'after_delete_post', $postid );
+
+       return $post;
+}
+
+/**
+ * Reset the page_on_front, show_on_front, and page_for_post settings when
+ * a linked page is deleted or trashed.
+ *
+ * Also ensures the post is no longer sticky.
+ *
+ * @since 3.7.0
+ * @access private
+ *
+ * @param int $post_id Post ID.
+ */
+function _reset_front_page_settings_for_post( $post_id ) {
+       $post = get_post( $post_id );
+       if ( 'page' == $post->post_type ) {
+               /*
+                * If the page is defined in option page_on_front or post_for_posts,
+                * adjust the corresponding options.
+                */
+               if ( get_option( 'page_on_front' ) == $post->ID ) {
+                       update_option( 'show_on_front', 'posts' );
+                       update_option( 'page_on_front', 0 );
+               }
+               if ( get_option( 'page_for_posts' ) == $post->ID ) {
+                       delete_option( 'page_for_posts', 0 );
+               }
+       }
+       unstick_post( $post->ID );
+}
+
+/**
+ * Move a post or page to the Trash
+ *
+ * If trash is disabled, the post or page is permanently deleted.
+ *
+ * @since 2.9.0
+ *
+ * @see wp_delete_post()
+ *
+ * @param int $post_id Optional. Post ID. Default is ID of the global $post
+ *                     if EMPTY_TRASH_DAYS equals true.
+ * @return false|array|WP_Post|null Post data array, otherwise false.
+ */
+function wp_trash_post( $post_id = 0 ) {
+       if ( !EMPTY_TRASH_DAYS )
+               return wp_delete_post($post_id, true);
+
+       if ( !$post = get_post($post_id, ARRAY_A) )
+               return $post;
+
+       if ( $post['post_status'] == 'trash' )
+               return false;
+
+       /**
+        * Fires before a post is sent to the trash.
+        *
+        * @since 3.3.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'wp_trash_post', $post_id );
+
+       add_post_meta($post_id,'_wp_trash_meta_status', $post['post_status']);
+       add_post_meta($post_id,'_wp_trash_meta_time', time());
+
+       $post['post_status'] = 'trash';
+       wp_insert_post( wp_slash( $post ) );
+
+       wp_trash_post_comments($post_id);
+
+       /**
+        * Fires after a post is sent to the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'trashed_post', $post_id );
+
+       return $post;
+}
+
+/**
+ * Restore a post or page from the Trash.
+ *
+ * @since 2.9.0
+ *
+ * @param int $post_id Optional. Post ID. Default is ID of the global $post.
+ * @return WP_Post|false WP_Post object. False on failure.
+ */
+function wp_untrash_post( $post_id = 0 ) {
+       if ( !$post = get_post($post_id, ARRAY_A) )
+               return $post;
+
+       if ( $post['post_status'] != 'trash' )
+               return false;
+
+       /**
+        * Fires before a post is restored from the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'untrash_post', $post_id );
+
+       $post_status = get_post_meta($post_id, '_wp_trash_meta_status', true);
+
+       $post['post_status'] = $post_status;
+
+       delete_post_meta($post_id, '_wp_trash_meta_status');
+       delete_post_meta($post_id, '_wp_trash_meta_time');
+
+       wp_insert_post( wp_slash( $post ) );
+
+       wp_untrash_post_comments($post_id);
+
+       /**
+        * Fires after a post is restored from the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'untrashed_post', $post_id );
+
+       return $post;
+}
+
+/**
+ * Moves comments for a post to the trash.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
+ * @return mixed|void False on failure.
+ */
+function wp_trash_post_comments( $post = null ) {
+       global $wpdb;
+
+       $post = get_post($post);
+       if ( empty($post) )
+               return;
+
+       $post_id = $post->ID;
+
+       /**
+        * Fires before comments are sent to the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'trash_post_comments', $post_id );
+
+       $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id) );
+       if ( empty($comments) )
+               return;
+
+       // Cache current status for each comment.
+       $statuses = array();
+       foreach ( $comments as $comment )
+               $statuses[$comment->comment_ID] = $comment->comment_approved;
+       add_post_meta($post_id, '_wp_trash_meta_comments_status', $statuses);
+
+       // Set status for all comments to post-trashed.
+       $result = $wpdb->update($wpdb->comments, array('comment_approved' => 'post-trashed'), array('comment_post_ID' => $post_id));
+
+       clean_comment_cache( array_keys($statuses) );
+
+       /**
+        * Fires after comments are sent to the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int   $post_id  Post ID.
+        * @param array $statuses Array of comment statuses.
+        */
+       do_action( 'trashed_post_comments', $post_id, $statuses );
+
+       return $result;
+}
+
+/**
+ * Restore comments for a post from the trash.
+ *
+ * @since 2.9.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
+ * @return true|void
+ */
+function wp_untrash_post_comments( $post = null ) {
+       global $wpdb;
+
+       $post = get_post($post);
+       if ( empty($post) )
+               return;
+
+       $post_id = $post->ID;
+
+       $statuses = get_post_meta($post_id, '_wp_trash_meta_comments_status', true);
+
+       if ( empty($statuses) )
+               return true;
+
+       /**
+        * Fires before comments are restored for a post from the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'untrash_post_comments', $post_id );
+
+       // Restore each comment to its original status.
+       $group_by_status = array();
+       foreach ( $statuses as $comment_id => $comment_status )
+               $group_by_status[$comment_status][] = $comment_id;
+
+       foreach ( $group_by_status as $status => $comments ) {
+               // Sanity check. This shouldn't happen.
+               if ( 'post-trashed' == $status ) {
+                       $status = '0';
+               }
+               $comments_in = implode( ', ', array_map( 'intval', $comments ) );
+               $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) );
+       }
+
+       clean_comment_cache( array_keys($statuses) );
+
+       delete_post_meta($post_id, '_wp_trash_meta_comments_status');
+
+       /**
+        * Fires after comments are restored for a post from the trash.
+        *
+        * @since 2.9.0
+        *
+        * @param int $post_id Post ID.
+        */
+       do_action( 'untrashed_post_comments', $post_id );
+}
+
+/**
+ * Retrieve the list of categories for a post.
+ *
+ * Compatibility layer for themes and plugins. Also an easy layer of abstraction
+ * away from the complexity of the taxonomy layer.
+ *
+ * @since 2.1.0
+ *
+ * @see wp_get_object_terms()
+ *
+ * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
+ *                       global $post. Default 0.
+ * @param array $args    Optional. Category arguments. Default empty.
+ * @return array List of categories.
+ */
+function wp_get_post_categories( $post_id = 0, $args = array() ) {
+       $post_id = (int) $post_id;
+
+       $defaults = array('fields' => 'ids');
+       $args = wp_parse_args( $args, $defaults );
+
+       $cats = wp_get_object_terms($post_id, 'category', $args);
+       return $cats;
+}
+
+/**
+ * Retrieve the tags for a post.
+ *
+ * There is only one default for this function, called 'fields' and by default
+ * is set to 'all'. There are other defaults that can be overridden in
+ * {@link wp_get_object_terms()}.
+ *
+ * @since 2.3.0
+ *
+ * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
+ *                       global $post. Default 0.
+ * @param array $args Optional. Overwrite the defaults
+ * @return array List of post tags.
+ */
+function wp_get_post_tags( $post_id = 0, $args = array() ) {
+       return wp_get_post_terms( $post_id, 'post_tag', $args);
+}
+
+/**
+ * Retrieve the terms for a post.
+ *
+ * There is only one default for this function, called 'fields' and by default
+ * is set to 'all'. There are other defaults that can be overridden in
+ * {@link wp_get_object_terms()}.
+ *
+ * @since 2.8.0
+ *
+ * @param int    $post_id  Optional. The Post ID. Does not default to the ID of the
+ *                         global $post. Default 0.
+ * @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
+ * @param array  $args     Optional. {@link wp_get_object_terms()} arguments. Default empty array.
+ * @return array|WP_Error  List of post terms or empty array if no terms were found. WP_Error object
+ *                         if `$taxonomy` doesn't exist.
+ */
+function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
+       $post_id = (int) $post_id;
+
+       $defaults = array('fields' => 'all');
+       $args = wp_parse_args( $args, $defaults );
+
+       $tags = wp_get_object_terms($post_id, $taxonomy, $args);
+
+       return $tags;
+}
+
+/**
+ * Retrieve a number of recent posts.
+ *
+ * @since 1.0.0
+ *
+ * @see get_posts()
+ *
+ * @param array  $args       Optional. Arguments to retrieve posts. Default empty array.
+ * @param string $output     Optional. Type of output. Accepts ARRAY_A or ''. Default ARRAY_A.
+ * @return array|false Associative array if $output equals ARRAY_A, array or false if no results.
+ */
+function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) {
+
+       if ( is_numeric( $args ) ) {
+               _deprecated_argument( __FUNCTION__, '3.1', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
+               $args = array( 'numberposts' => absint( $args ) );
+       }
+
+       // Set default arguments.
+       $defaults = array(
+               'numberposts' => 10, 'offset' => 0,
+               'category' => 0, 'orderby' => 'post_date',
+               'order' => 'DESC', 'include' => '',
+               'exclude' => '', 'meta_key' => '',
+               'meta_value' =>'', 'post_type' => 'post', 'post_status' => 'draft, publish, future, pending, private',
+               'suppress_filters' => true
+       );
+
+       $r = wp_parse_args( $args, $defaults );
+
+       $results = get_posts( $r );
+
+       // Backward compatibility. Prior to 3.1 expected posts to be returned in array.
+       if ( ARRAY_A == $output ){
+               foreach ( $results as $key => $result ) {
+                       $results[$key] = get_object_vars( $result );
+               }
+               return $results ? $results : array();
+       }
+
+       return $results ? $results : false;
+
+}
+
+/**
+ * Insert or update a post.
+ *
+ * If the $postarr parameter has 'ID' set to a value, then post will be updated.
+ *
+ * You can set the post date manually, by 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.
+ *
+ * @since 1.0.0
+ * @since 4.2.0 Support was added for encoding emoji in the post title, content, and excerpt.
+ * @since 4.4.0 A 'meta_input' array can now be passed to `$postarr` to add post meta data.
+ *
+ * @see sanitize_post()
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $postarr {
+ *     An array of elements that make up a post to update or insert.
+ *
+ *     @type int    $ID                    The post ID. If equal to something other than 0,
+ *                                         the post with that ID will be updated. Default 0.
+ *     @type int    $post_author           The ID of the user who added the post. Default is
+ *                                         the current user ID.
+ *     @type string $post_date             The date of the post. Default is the current time.
+ *     @type string $post_date_gmt         The date of the post in the GMT timezone. Default is
+ *                                         the value of `$post_date`.
+ *     @type mixed  $post_content          The post content. Default empty.
+ *     @type string $post_content_filtered The filtered post content. Default empty.
+ *     @type string $post_title            The post title. Default empty.
+ *     @type string $post_excerpt          The post excerpt. Default empty.
+ *     @type string $post_status           The post status. Default 'draft'.
+ *     @type string $post_type             The post type. Default 'post'.
+ *     @type string $comment_status        Whether the post can accept comments. Accepts 'open' or 'closed'.
+ *                                         Default is the value of 'default_comment_status' option.
+ *     @type string $ping_status           Whether the post can accept pings. Accepts 'open' or 'closed'.
+ *                                         Default is the value of 'default_ping_status' option.
+ *     @type string $post_password         The password to access the post. Default empty.
+ *     @type string $post_name             The post name. Default is the sanitized post title.
+ *     @type string $to_ping               Space or carriage return-separated list of URLs to ping.
+ *                                         Default empty.
+ *     @type string $pinged                Space or carriage return-separated list of URLs that have
+ *                                         been pinged. Default empty.
+ *     @type string $post_modified         The date when the post was last modified. Default is
+ *                                         the current time.
+ *     @type string $post_modified_gmt     The date when the post was last modified in the GMT
+ *                                         timezone. Default is the current time.
+ *     @type int    $post_parent           Set this for the post it belongs to, if any. Default 0.
+ *     @type int    $menu_order            The order the post should be displayed in. Default 0.
+ *     @type string $post_mime_type        The mime type of the post. Default empty.
+ *     @type string $guid                  Global Unique ID for referencing the post. Default empty.
+ *     @type array  $tax_input             Array of taxonomy terms keyed by their taxonomy name. Default empty.
+ *     @type array  $meta_input            Array of post meta values keyed by their post meta key. Default empty.
+ * }
+ * @param bool  $wp_error Optional. Whether to allow return of WP_Error on failure. Default false.
+ * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure.
+ */
+function wp_insert_post( $postarr, $wp_error = false ) {
+       global $wpdb;
+
+       $user_id = get_current_user_id();
+
+       $defaults = array(
+               'post_author' => $user_id,
+               'post_content' => '',
+               'post_content_filtered' => '',
+               'post_title' => '',
+               'post_excerpt' => '',
+               'post_status' => 'draft',
+               'post_type' => 'post',
+               'comment_status' => '',
+               'ping_status' => '',
+               'post_password' => '',
+               'to_ping' =>  '',
+               'pinged' => '',
+               'post_parent' => 0,
+               'menu_order' => 0,
+               'guid' => '',
+               'import_id' => 0,
+               'context' => '',
+       );
+
+       $postarr = wp_parse_args($postarr, $defaults);
+
+       unset( $postarr[ 'filter' ] );
+
+       $postarr = sanitize_post($postarr, 'db');
+
+       // Are we updating or creating?
+       $post_ID = 0;
+       $update = false;
+       $guid = $postarr['guid'];
+
+       if ( ! empty( $postarr['ID'] ) ) {
+               $update = true;
+
+               // Get the post ID and GUID.
+               $post_ID = $postarr['ID'];
+               $post_before = get_post( $post_ID );
+               if ( is_null( $post_before ) ) {
+                       if ( $wp_error ) {
+                               return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
+                       }
+                       return 0;
+               }
+
+               $guid = get_post_field( 'guid', $post_ID );
+               $previous_status = get_post_field('post_status', $post_ID );
+       } else {
+               $previous_status = 'new';
+       }
+
+       $post_type = empty( $postarr['post_type'] ) ? 'post' : $postarr['post_type'];
+
+       $post_title = $postarr['post_title'];
+       $post_content = $postarr['post_content'];
+       $post_excerpt = $postarr['post_excerpt'];
+       if ( isset( $postarr['post_name'] ) ) {
+               $post_name = $postarr['post_name'];
+       }
+
+       $maybe_empty = 'attachment' !== $post_type
+               && ! $post_content && ! $post_title && ! $post_excerpt
+               && post_type_supports( $post_type, 'editor' )
+               && post_type_supports( $post_type, 'title' )
+               && post_type_supports( $post_type, 'excerpt' );
+
+       /**
+        * Filter whether the post should be considered "empty".
+        *
+        * The post is considered "empty" if both:
+        * 1. The post type supports the title, editor, and excerpt fields
+        * 2. The title, editor, and excerpt fields are all empty
+        *
+        * Returning a truthy value to the filter will effectively short-circuit
+        * the new post being inserted, returning 0. If $wp_error is true, a WP_Error
+        * will be returned instead.
+        *
+        * @since 3.3.0
+        *
+        * @param bool  $maybe_empty Whether the post should be considered "empty".
+        * @param array $postarr     Array of post data.
+        */
+       if ( apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $postarr ) ) {
+               if ( $wp_error ) {
+                       return new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.' ) );
+               } else {
+                       return 0;
+               }
+       }
+
+       $post_status = empty( $postarr['post_status'] ) ? 'draft' : $postarr['post_status'];
+       if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash' ) ) ) {
+               $post_status = 'inherit';
+       }
+
+       if ( ! empty( $postarr['post_category'] ) ) {
+               // Filter out empty terms.
+               $post_category = array_filter( $postarr['post_category'] );
+       }
+
+       // 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();
+               }
+       }
+
+       // Don't allow contributors 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 {
+               // On updates, we need to check to see if it's using the old, fixed sanitization context.
+               $check_name = sanitize_title( $post_name, '', 'old-save' );
+               if ( $update && strtolower( urlencode( $post_name ) ) == $check_name && get_post_field( 'post_name', $post_ID ) == $check_name ) {
+                       $post_name = $check_name;
+               } else { // new post, or slug has changed.
+                       $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( $postarr['post_date'] ) || '0000-00-00 00:00:00' == $postarr['post_date'] ) {
+               if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['post_date_gmt'] ) {
+                       $post_date = current_time( 'mysql' );
+               } else {
+                       $post_date = get_date_from_gmt( $postarr['post_date_gmt'] );
+               }
+       } else {
+               $post_date = $postarr['post_date'];
+       }
+
+       // Validate the date.
+       $mm = substr( $post_date, 5, 2 );
+       $jj = substr( $post_date, 8, 2 );
+       $aa = substr( $post_date, 0, 4 );
+       $valid_date = wp_checkdate( $mm, $jj, $aa, $post_date );
+       if ( ! $valid_date ) {
+               if ( $wp_error ) {
+                       return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
+               } else {
+                       return 0;
+               }
+       }
+
+       if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['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';
+               }
+       } else {
+               $post_date_gmt = $postarr['post_date_gmt'];
+       }
+
+       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 ( 'attachment' !== $post_type ) {
+               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';
+                       }
+               }
+       }
+
+       // Comment status.
+       if ( empty( $postarr['comment_status'] ) ) {
+               if ( $update ) {
+                       $comment_status = 'closed';
+               } else {
+                       $comment_status = get_default_comment_status( $post_type );
+               }
+       } else {
+               $comment_status = $postarr['comment_status'];
+       }
+
+       // These variables are needed by compact() later.
+       $post_content_filtered = $postarr['post_content_filtered'];
+       $post_author = isset( $postarr['post_author'] ) ? $postarr['post_author'] : $user_id;
+       $ping_status = empty( $postarr['ping_status'] ) ? get_default_comment_status( $post_type, 'pingback' ) : $postarr['ping_status'];
+       $to_ping = isset( $postarr['to_ping'] ) ? sanitize_trackback_urls( $postarr['to_ping'] ) : '';
+       $pinged = isset( $postarr['pinged'] ) ? $postarr['pinged'] : '';
+       $import_id = isset( $postarr['import_id'] ) ? $postarr['import_id'] : 0;
+
+       /*
+        * The 'wp_insert_post_parent' filter expects all variables to be present.
+        * Previously, these variables would have already been extracted
+        */
+       if ( isset( $postarr['menu_order'] ) ) {
+               $menu_order = (int) $postarr['menu_order'];
+       } else {
+               $menu_order = 0;
+       }
+
+       $post_password = isset( $postarr['post_password'] ) ? $postarr['post_password'] : '';
+       if ( 'private' == $post_status ) {
+               $post_password = '';
+       }
+
+       if ( isset( $postarr['post_parent'] ) ) {
+               $post_parent = (int) $postarr['post_parent'];
+       } else {
+               $post_parent = 0;
+       }
+
+       /**
+        * Filter the post parent -- used to check for and prevent hierarchy loops.
+        *
+        * @since 3.1.0
+        *
+        * @param int   $post_parent Post parent ID.
+        * @param int   $post_ID     Post ID.
+        * @param array $new_postarr Array of parsed post data.
+        * @param array $postarr     Array of sanitized, but otherwise unmodified post data.
+        */
+       $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
+
+       $post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent );
+
+       // Don't unslash.
+       $post_mime_type = isset( $postarr['post_mime_type'] ) ? $postarr['post_mime_type'] : '';
+
+       // Expected_slashed (everything!).
+       $data = compact( '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' );
+
+       $emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' );
+
+       foreach ( $emoji_fields as $emoji_field ) {
+               if ( isset( $data[ $emoji_field ] ) ) {
+                       $charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field );
+                       if ( 'utf8' === $charset ) {
+                               $data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] );
+                       }
+               }
+       }
+
+       if ( 'attachment' === $post_type ) {
+               /**
+                * Filter attachment post data before it is updated in or added to the database.
+                *
+                * @since 3.9.0
+                *
+                * @param array $data    An array of sanitized attachment post data.
+                * @param array $postarr An array of unsanitized attachment post data.
+                */
+               $data = apply_filters( 'wp_insert_attachment_data', $data, $postarr );
+       } else {
+               /**
+                * Filter slashed post data just before it is inserted into the database.
+                *
+                * @since 2.7.0
+                *
+                * @param array $data    An array of slashed post data.
+                * @param array $postarr An array of sanitized, but otherwise unmodified post data.
+                */
+               $data = apply_filters( 'wp_insert_post_data', $data, $postarr );
+       }
+       $data = wp_unslash( $data );
+       $where = array( 'ID' => $post_ID );
+
+       if ( $update ) {
+               /**
+                * Fires immediately before an existing post is updated in the database.
+                *
+                * @since 2.5.0
+                *
+                * @param int   $post_ID Post ID.
+                * @param array $data    Array of unslashed post data.
+                */
+               do_action( 'pre_post_update', $post_ID, $data );
+               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 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'] = wp_unique_post_slug( sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data['post_status'], $post_type, $post_parent );
+               $wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
+               clean_post_cache( $post_ID );
+       }
+
+       if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
+               wp_set_post_categories( $post_ID, $post_category );
+       }
+
+       if ( isset( $postarr['tags_input'] ) && is_object_in_taxonomy( $post_type, 'post_tag' ) ) {
+               wp_set_post_tags( $post_ID, $postarr['tags_input'] );
+       }
+
+       // New-style support for all custom taxonomies.
+       if ( ! empty( $postarr['tax_input'] ) ) {
+               foreach ( $postarr['tax_input'] as $taxonomy => $tags ) {
+                       $taxonomy_obj = get_taxonomy($taxonomy);
+                       if ( ! $taxonomy_obj ) {
+                               /* translators: %s: taxonomy name */
+                               _doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid taxonomy: %s.' ), $taxonomy ), '4.4.0' );
+                               continue;
+                       }
+
+                       // array = hierarchical, string = non-hierarchical.
+                       if ( is_array( $tags ) ) {
+                               $tags = array_filter($tags);
+                       }
+                       if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
+                               wp_set_post_terms( $post_ID, $tags, $taxonomy );
+                       }
+               }
+       }
+
+       if ( ! empty( $postarr['meta_input'] ) ) {
+               foreach ( $postarr['meta_input'] as $field => $value ) {
+                       update_post_meta( $post_ID, $field, $value );
+               }
+       }
+
+       $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 );
+       }
+
+       if ( 'attachment' === $postarr['post_type'] ) {
+               if ( ! empty( $postarr['file'] ) ) {
+                       update_attached_file( $post_ID, $postarr['file'] );
+               }
+
+               if ( ! empty( $postarr['context'] ) ) {
+                       add_post_meta( $post_ID, '_wp_attachment_context', $postarr['context'], true );
+               }
+       }
+
+       clean_post_cache( $post_ID );
+
+       $post = get_post( $post_ID );
+
+       if ( ! empty( $postarr['page_template'] ) && 'page' == $data['post_type'] ) {
+               $post->page_template = $postarr['page_template'];
+               $page_templates = wp_get_theme()->get_page_templates( $post );
+               if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) {
+                       if ( $wp_error ) {
+                               return new WP_Error('invalid_page_template', __('The page template is invalid.'));
+                       }
+                       update_post_meta( $post_ID, '_wp_page_template', 'default' );
+               } else {
+                       update_post_meta( $post_ID, '_wp_page_template', $postarr['page_template'] );
+               }
+       }
+
+       if ( 'attachment' !== $postarr['post_type'] ) {
+               wp_transition_post_status( $data['post_status'], $previous_status, $post );
+       } else {
+               if ( $update ) {
+                       /**
+                        * Fires once an existing attachment has been updated.
+                        *
+                        * @since 2.0.0
+                        *
+                        * @param int $post_ID Attachment ID.
+                        */
+                       do_action( 'edit_attachment', $post_ID );
+                       $post_after = get_post( $post_ID );
+
+                       /**
+                        * Fires once an existing attachment has been updated.
+                        *
+                        * @since 4.4.0
+                        *
+                        * @param int     $post_ID      Post ID.
+                        * @param WP_Post $post_after   Post object following the update.
+                        * @param WP_Post $post_before  Post object before the update.
+                        */
+                       do_action( 'attachment_updated', $post_ID, $post_after, $post_before );
+               } else {
+
+                       /**
+                        * Fires once an attachment has been added.
+                        *
+                        * @since 2.0.0
+                        *
+                        * @param int $post_ID Attachment ID.
+                        */
+                       do_action( 'add_attachment', $post_ID );
+               }
+
+               return $post_ID;
+       }
+
+       if ( $update ) {
+               /**
+                * Fires once an existing post has been updated.
+                *
+                * @since 1.2.0
+                *
+                * @param int     $post_ID Post ID.
+                * @param WP_Post $post    Post object.
+                */
+               do_action( 'edit_post', $post_ID, $post );
+               $post_after = get_post($post_ID);
+
+               /**
+                * Fires once an existing post has been updated.
+                *
+                * @since 3.0.0
+                *
+                * @param int     $post_ID      Post ID.
+                * @param WP_Post $post_after   Post object following the update.
+                * @param WP_Post $post_before  Post object before the update.
+                */
+               do_action( 'post_updated', $post_ID, $post_after, $post_before);
+       }
+
+       /**
+        * Fires once a post has been saved.
+        *
+        * The dynamic portion of the hook name, `$post->post_type`, refers to
+        * the post type slug.
+        *
+        * @since 3.7.0
+        *
+        * @param int     $post_ID Post ID.
+        * @param WP_Post $post    Post object.
+        * @param bool    $update  Whether this is an existing post being updated or not.
+        */
+       do_action( "save_post_{$post->post_type}", $post_ID, $post, $update );
+
+       /**
+        * Fires once a post has been saved.
+        *
+        * @since 1.5.0
+        *
+        * @param int     $post_ID Post ID.
+        * @param WP_Post $post    Post object.
+        * @param bool    $update  Whether this is an existing post being updated or not.
+        */
+       do_action( 'save_post', $post_ID, $post, $update );
+
+       /**
+        * Fires once a post has been saved.
+        *
+        * @since 2.0.0
+        *
+        * @param int     $post_ID Post ID.
+        * @param WP_Post $post    Post object.
+        * @param bool    $update  Whether this is an existing post being updated or not.
+        */
+       do_action( 'wp_insert_post', $post_ID, $post, $update );
+
+       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  Optional. Post data. Arrays are expected to be escaped,
+ *                               objects are not. Default array.
+ * @param bool         $wp_error Optional. Allow return of WP_Error on failure. Default false.
+ * @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 = wp_slash($postarr);
+       }
+
+       // First, get all of the original fields.
+       $post = get_post($postarr['ID'], ARRAY_A);
+
+       if ( is_null( $post ) ) {
+               if ( $wp_error )
+                       return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
+               return 0;
+       }
+
+       // Escape data pulled from DB.
+       $post = wp_slash($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
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|WP_Post $post Post ID or post object.
+ */
+function wp_publish_post( $post ) {
+       global $wpdb;
+
+       if ( ! $post = get_post( $post ) )
+               return;
+
+       if ( 'publish' == $post->post_status )
+               return;
+
+       $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post->ID ) );
+
+       clean_post_cache( $post->ID );
+
+       $old_status = $post->post_status;
+       $post->post_status = 'publish';
+       wp_transition_post_status( 'publish', $old_status, $post );
+
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'edit_post', $post->ID, $post );
+
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( "save_post_{$post->post_type}", $post->ID, $post, true );
+
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'save_post', $post->ID, $post, true );
+
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'wp_insert_post', $post->ID, $post, true );
+}
+
+/**
+ * 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|WP_Post $post_id Post ID or post object.
+ */
+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' );
+
+       // Uh oh, someone jumped the gun!
+       if ( $time > time() ) {
+               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;
+       }
+
+       // wp_publish_post(_ returns no meaningful value.
+       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 WordPress database abstraction object.
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param string $slug        The desired slug (post_name).
+ * @param int    $post_ID     Post ID.
+ * @param string $post_status No uniqueness checks are made if the post is still draft or pending.
+ * @param string $post_type   Post type.
+ * @param int    $post_parent Post parent ID.
+ * @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' ) ) || ( 'inherit' == $post_status && 'revision' == $post_type ) )
+               return $slug;
+
+       global $wpdb, $wp_rewrite;
+
+       $original_slug = $slug;
+
+       $feeds = $wp_rewrite->feeds;
+       if ( ! is_array( $feeds ) )
+               $feeds = array();
+
+       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 ) );
+
+               /**
+                * Filter whether the post slug would make a bad attachment slug.
+                *
+                * @since 3.1.0
+                *
+                * @param bool   $bad_slug Whether the slug would be bad as an attachment slug.
+                * @param string $slug     The post slug.
+                */
+               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 = _truncate_post_slug( $slug, 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 ( is_post_type_hierarchical( $post_type ) ) {
+               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 ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1";
+               $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );
+
+               /**
+                * Filter whether the post slug would make a bad hierarchical post slug.
+                *
+                * @since 3.1.0
+                *
+                * @param bool   $bad_slug    Whether the post slug would be bad in a hierarchical post context.
+                * @param string $slug        The post slug.
+                * @param string $post_type   Post type.
+                * @param int    $post_parent Post parent ID.
+                */
+               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 = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+                               $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $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 ) );
+
+               // Prevent new post slugs that could result in URLs that conflict with date archives.
+               $post = get_post( $post_ID );
+               $conflicts_with_date_archive = false;
+               if ( 'post' === $post_type && ( ! $post || $post->post_name !== $slug ) && preg_match( '/^[0-9]+$/', $slug ) && $slug_num = intval( $slug ) ) {
+                       $permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
+                       $postname_index = array_search( '%postname%', $permastructs );
+
+                       /*
+                        * Potential date clashes are as follows:
+                        *
+                        * - Any integer in the first permastruct position could be a year.
+                        * - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum'.
+                        * - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day'.
+                        */
+                       if ( 0 === $postname_index ||
+                               ( $postname_index && '%year%' === $permastructs[ $postname_index - 1 ] && 13 > $slug_num ) ||
+                               ( $postname_index && '%monthnum%' === $permastructs[ $postname_index - 1 ] && 32 > $slug_num )
+                       ) {
+                               $conflicts_with_date_archive = true;
+                       }
+               }
+
+               /**
+                * Filter whether the post slug would be bad as a flat slug.
+                *
+                * @since 3.1.0
+                *
+                * @param bool   $bad_slug  Whether the post slug would be bad as a flat slug.
+                * @param string $slug      The post slug.
+                * @param string $post_type Post type.
+                */
+               if ( $post_name_check || in_array( $slug, $feeds ) || $conflicts_with_date_archive || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
+                       $suffix = 2;
+                       do {
+                               $alt_post_name = _truncate_post_slug( $slug, 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;
+               }
+       }
+
+       /**
+        * Filter the unique post slug.
+        *
+        * @since 3.3.0
+        *
+        * @param string $slug          The post slug.
+        * @param int    $post_ID       Post ID.
+        * @param string $post_status   The post status.
+        * @param string $post_type     Post type.
+        * @param int    $post_parent   Post parent ID
+        * @param string $original_slug The original post slug.
+        */
+       return apply_filters( 'wp_unique_post_slug', $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug );
+}
+
+/**
+ * Truncate a post slug.
+ *
+ * @since 3.6.0
+ * @access private
+ *
+ * @see utf8_uri_encode()
+ *
+ * @param string $slug   The slug to truncate.
+ * @param int    $length Optional. Max length of the slug. Default 200 (characters).
+ * @return string The truncated slug.
+ */
+function _truncate_post_slug( $slug, $length = 200 ) {
+       if ( strlen( $slug ) > $length ) {
+               $decoded_slug = urldecode( $slug );
+               if ( $decoded_slug === $slug )
+                       $slug = substr( $slug, 0, $length );
+               else
+                       $slug = utf8_uri_encode( $decoded_slug, $length );
+       }
+
+       return rtrim( $slug, '-' );
+}
+
+/**
+ * Add tags to a post.
+ *
+ * @see wp_set_post_tags()
+ *
+ * @since 2.3.0
+ *
+ * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
+ * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
+ *                              separated by commas. Default empty.
+ * @return array|false|WP_Error Array of affected term IDs. WP_Error or false on failure.
+ */
+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
+ *
+ * @see wp_set_object_terms()
+ *
+ * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
+ * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
+ *                              separated by commas. Default empty.
+ * @param bool         $append  Optional. If true, don't delete existing tags, just add on. If false,
+ *                              replace the tags with the new tags. Default false.
+ * @return array|false|WP_Error 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
+ *
+ * @see wp_set_object_terms()
+ *
+ * @param int          $post_id  Optional. The Post ID. Does not default to the ID of the global $post.
+ * @param string|array $tags     Optional. An array of terms to set for the post, or a string of terms
+ *                               separated by commas. Default empty.
+ * @param string       $taxonomy Optional. Taxonomy name. Default 'post_tag'.
+ * @param bool         $append   Optional. If true, don't delete existing terms, just add on. If false,
+ *                               replace the terms with the new terms. Default false.
+ * @return array|false|WP_Error 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         Optional. The Post ID. Does not default to the ID
+ *                                   of the global $post. Default 0.
+ * @param array|int $post_categories Optional. List of categories or ID of category.
+ *                                   Default empty array.
+ * @param bool      $append         If true, don't delete existing categories, just add on.
+ *                                  If false, replace the categories with the new categories.
+ * @return array|bool|WP_Error
+ */
+function wp_set_post_categories( $post_ID = 0, $post_categories = array(), $append = false ) {
+       $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:
+       $post_categories = (array) $post_categories;
+       if ( empty( $post_categories ) ) {
+               if ( 'post' == $post_type && 'auto-draft' != $post_status ) {
+                       $post_categories = array( get_option('default_category') );
+                       $append = false;
+               } else {
+                       $post_categories = array();
+               }
+       } elseif ( 1 == count( $post_categories ) && '' == reset( $post_categories ) ) {
+               return true;
+       }
+
+       return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
+}
+
+/**
+ * Fires actions related to the transitioning of a post's status.
+ *
+ * When a post is saved, the post status is "transitioned" from one status to another,
+ * though this does not always mean the status has actually changed before and after
+ * the save. This function fires a number of action hooks related to that transition:
+ * the generic 'transition_post_status' action, as well as the dynamic hooks
+ * `"{$old_status}_to_{$new_status}"` and `"{$new_status}_{$post->post_type}"`. Note
+ * that the function does not transition the post object in the database.
+ *
+ * For instance: When publishing a post for the first time, the post status may transition
+ * from 'draft' â€“ or some other status â€“ to 'publish'. However, if a post is already
+ * published and is simply being updated, the "old" and "new" statuses may both be 'publish'
+ * before and after the transition.
+ *
+ * @since 2.3.0
+ *
+ * @param string  $new_status Transition to this post status.
+ * @param string  $old_status Previous post status.
+ * @param WP_Post $post Post data.
+ */
+function wp_transition_post_status( $new_status, $old_status, $post ) {
+       /**
+        * Fires when a post is transitioned from one status to another.
+        *
+        * @since 2.3.0
+        *
+        * @param string  $new_status New post status.
+        * @param string  $old_status Old post status.
+        * @param WP_Post $post       Post object.
+        */
+       do_action( 'transition_post_status', $new_status, $old_status, $post );
+
+       /**
+        * Fires when a post is transitioned from one status to another.
+        *
+        * The dynamic portions of the hook name, `$new_status` and `$old status`,
+        * refer to the old and new post statuses, respectively.
+        *
+        * @since 2.3.0
+        *
+        * @param WP_Post $post Post object.
+        */
+       do_action( "{$old_status}_to_{$new_status}", $post );
+
+       /**
+        * Fires when a post is transitioned from one status to another.
+        *
+        * The dynamic portions of the hook name, `$new_status` and `$post->post_type`,
+        * refer to the new post status and post type, respectively.
+        *
+        * Please note: When this action is hooked using a particular post status (like
+        * 'publish', as `publish_{$post->post_type}`), it will fire both when a post is
+        * first transitioned to that status from something else, as well as upon
+        * subsequent post updates (old and new status are both the same).
+        *
+        * Therefore, if you are looking to only fire a callback when a post is first
+        * transitioned to a status, use the {@see 'transition_post_status'} hook instead.
+        *
+        * @since 2.3.0
+        *
+        * @param int     $post_id Post ID.
+        * @param WP_Post $post    Post object.
+        */
+       do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
+}
+
+//
+// Comment, trackback, and pingback functions.
+//
+
+/**
+ * Add a URL to those already pinged.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int    $post_id Post ID.
+ * @param string $uri     Ping URI.
+ * @return int|false 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);
+
+       /**
+        * Filter the new ping URL to add for the given post.
+        *
+        * @since 2.0.0
+        *
+        * @param string $new New ping URL to add.
+        */
+       $new = apply_filters( 'add_ping', $new );
+
+       // expected_slashed ($new).
+       $new = wp_unslash($new);
+       return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
+}
+
+/**
+ * Retrieve enclosures already enclosed for a post.
+ *
+ * @since 1.5.0
+ *
+ * @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 ] );
+               }
+       }
+
+       /**
+        * Filter the list of enclosures already enclosed for the given post.
+        *
+        * @since 2.0.0
+        *
+        * @param array $pung    Array of enclosures for the given post.
+        * @param int   $post_id Post ID.
+        */
+       return apply_filters( 'get_enclosed', $pung, $post_id );
+}
+
+/**
+ * Retrieve URLs already pinged for a post.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @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);
+
+       /**
+        * Filter the list of already-pinged URLs for the given post.
+        *
+        * @since 2.0.0
+        *
+        * @param array $pung Array of URLs already pinged for the given post.
+        */
+       return apply_filters( 'get_pung', $pung );
+}
+
+/**
+ * Retrieve URLs that need to be pinged.
+ *
+ * @since 1.5.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @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);
+
+       /**
+        * Filter the list of URLs yet to ping for the given post.
+        *
+        * @since 2.0.0
+        *
+        * @param array $to_ping List of URLs yet to ping.
+        */
+       return apply_filters( 'get_to_ping', $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 );
+
+               // Form an excerpt.
+               $excerpt = strip_tags( $postdata['post_excerpt'] ? $postdata['post_excerpt'] : $postdata['post_content'] );
+
+               if ( strlen( $excerpt ) > 255 ) {
+                       $excerpt = substr( $excerpt, 0, 252 ) . '&hellip;';
+               }
+
+               $trackback_urls = explode( ',', $tb_list );
+               foreach ( (array) $trackback_urls as $tb_url ) {
+                       $tb_url = trim( $tb_url );
+                       trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id );
+               }
+       }
+}
+
+//
+// Page functions
+//
+
+/**
+ * Get a list of page IDs.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @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 Use get_post()
+ *
+ * @param mixed  $page   Page object or page ID. Passed by reference.
+ * @param string $output Optional. What to output. Accepts OBJECT, ARRAY_A, or ARRAY_N.
+ *                       Default OBJECT.
+ * @param string $filter Optional. How the return value should be filtered. Accepts 'raw',
+ *                       'edit', 'db', 'display'. Default 'raw'.
+ * @return WP_Post|array|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
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string       $page_path Page path.
+ * @param string       $output    Optional. Output type. Accepts OBJECT, ARRAY_N, or ARRAY_A.
+ *                                Default OBJECT.
+ * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
+ * @return WP_Post|array|void WP_Post on success.
+ */
+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 = esc_sql( $parts );
+       $parts = array_map( 'sanitize_title_for_query', $parts );
+
+       $in_string = "'" . implode( "','", $parts ) . "'";
+
+       if ( is_array( $post_type ) ) {
+               $post_types = $post_type;
+       } else {
+               $post_types = array( $post_type, 'attachment' );
+       }
+
+       $post_types = esc_sql( $post_types );
+       $post_type_in_string = "'" . implode( "','", $post_types ) . "'";
+       $sql = "
+               SELECT ID, post_name, post_parent, post_type
+               FROM $wpdb->posts
+               WHERE post_name IN ($in_string)
+               AND post_type IN ($post_type_in_string)
+       ";
+
+       $pages = $wpdb->get_results( $sql, 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 );
+       }
+}
+
+/**
+ * Retrieve a page given its title.
+ *
+ * @since 2.1.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string       $page_title Page title
+ * @param string       $output     Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A.
+ *                                 Default OBJECT.
+ * @param string|array $post_type  Optional. Post type or array of post types. Default 'page'.
+ * @return WP_Post|array|void WP_Post on success or null on failure
+ */
+function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
+       global $wpdb;
+
+       if ( is_array( $post_type ) ) {
+               $post_type = esc_sql( $post_type );
+               $post_type_in_string = "'" . implode( "','", $post_type ) . "'";
+               $sql = $wpdb->prepare( "
+                       SELECT ID
+                       FROM $wpdb->posts
+                       WHERE post_title = %s
+                       AND post_type IN ($post_type_in_string)
+               ", $page_title );
+       } else {
+               $sql = $wpdb->prepare( "
+                       SELECT ID
+                       FROM $wpdb->posts
+                       WHERE post_title = %s
+                       AND post_type = %s
+               ", $page_title, $post_type );
+       }
+
+       $page = $wpdb->get_var( $sql );
+
+       if ( $page ) {
+               return get_post( $page, $output );
+       }
+}
+
+/**
+ * Identify descendants of a given page ID in a list of page objects.
+ *
+ * Descendants are identified from the `$pages` array passed to the function. No database queries are performed.
+ *
+ * @since 1.5.1
+ *
+ * @param int   $page_id Page ID.
+ * @param array $pages   List of page objects from which descendants should be identified.
+ * @return array List of page children.
+ */
+function get_page_children( $page_id, $pages ) {
+       // Build a hash of ID -> children.
+       $children = array();
+       foreach ( (array) $pages as $page ) {
+               $children[ intval( $page->post_parent ) ][] = $page;
+       }
+
+       $page_list = array();
+
+       // Start the search by looking at immediate children.
+       if ( isset( $children[ $page_id ] ) ) {
+               // Always start at the end of the stack in order to preserve original `$pages` order.
+               $to_look = array_reverse( $children[ $page_id ] );
+
+               while ( $to_look ) {
+                       $p = array_pop( $to_look );
+                       $page_list[] = $p;
+                       if ( isset( $children[ $p->ID ] ) ) {
+                               foreach ( array_reverse( $children[ $p->ID ] ) as $child ) {
+                                       // Append to the `$to_look` stack to descend the tree.
+                                       $to_look[] = $child;
+                               }
+                       }
+               }
+       }
+
+       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, passed by reference.
+ * @param int   $page_id Optional. Parent page ID. Default 0.
+ * @return array A list arranged by hierarchy. Children immediately follow their parents.
+ */
+function get_page_hierarchy( &$pages, $page_id = 0 ) {
+       if ( empty( $pages ) ) {
+               return array();
+       }
+
+       $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;
+}
+
+/**
+ * Traverse and return all the nested children post names of a root page.
+ *
+ * $children contains parent-children relations
+ *
+ * @since 2.9.0
+ *
+ * @see _page_traverse_name()
+ *
+ * @param int   $page_id   Page ID.
+ * @param array &$children Parent-children relations, passed by reference.
+ * @param array &$result   Result, passed by reference.
+ */
+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 );
+               }
+       }
+}
+
+/**
+ * Build URI for a page.
+ *
+ * Sub pages will be in the "directory" under the parent page post name.
+ *
+ * @since 1.5.0
+ *
+ * @param WP_Post|object|int $page Page object or page ID.
+ * @return string|false Page URI, false on error.
+ */
+function get_page_uri( $page ) {
+       $page = get_post( $page );
+
+       if ( ! $page )
+               return false;
+
+       $uri = $page->post_name;
+
+       foreach ( $page->ancestors as $parent ) {
+               $parent = get_post( $parent );
+               if ( 'publish' === $parent->post_status ) {
+                       $uri = $parent->post_name . '/' . $uri;
+               }
+       }
+
+       /**
+        * Filter the URI for a page.
+        *
+        * @since 4.4.0
+        *
+        * @param string  $uri  Page URI.
+        * @param WP_Post $page Page object.
+        */
+       return apply_filters( 'get_page_uri', $uri, $page );
+}
+
+/**
+ * Retrieve a list of pages.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @since 1.5.0
+ *
+ * @param array|string $args {
+ *     Optional. Array or string of arguments to retrieve pages.
+ *
+ *     @type int          $child_of     Page ID to return child and grandchild pages of. Note: The value
+ *                                      of `$hierarchical` has no bearing on whether `$child_of` returns
+ *                                      hierarchical results. Default 0, or no restriction.
+ *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
+ *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
+ *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
+ *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
+ *                                      'post_' can be omitted for any values that start with it.
+ *                                      Default 'post_title'.
+ *     @type bool         $hierarchical Whether to return pages hierarchically. If false in conjunction with
+ *                                      `$child_of` also being false, both arguments will be disregarded.
+ *                                      Default true.
+ *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
+ *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
+ *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
+ *                                      Default empty array.
+ *     @type string       $meta_key     Only include pages with this meta key. Default empty.
+ *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
+ *                                      Default empty.
+ *     @type string       $authors      A comma-separated list of author IDs. Default empty.
+ *     @type int          $parent       Page ID to return direct children of. Default -1, or no restriction.
+ *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
+ *                                      Default empty array.
+ *     @type int          $number       The number of pages to return. Default 0, or all pages.
+ *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
+ *                                      Default 0.
+ *     @type string       $post_type    The post type to query. Default 'page'.
+ *     @type string       $post_status  A comma-separated list of post status types to include.
+ *                                      Default 'publish'.
+ * }
+ * @return array|false List of pages matching defaults or `$args`.
+ */
+function get_pages( $args = array() ) {
+       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' => array(),
+               'number' => '', 'offset' => 0,
+               'post_type' => 'page', 'post_status' => 'publish',
+       );
+
+       $r = wp_parse_args( $args, $defaults );
+
+       $number = (int) $r['number'];
+       $offset = (int) $r['offset'];
+       $child_of = (int) $r['child_of'];
+       $hierarchical = $r['hierarchical'];
+       $exclude = $r['exclude'];
+       $meta_key = $r['meta_key'];
+       $meta_value = $r['meta_value'];
+       $parent = $r['parent'];
+       $post_status = $r['post_status'];
+
+       // Make sure the post type is hierarchical.
+       $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
+       if ( ! in_array( $r['post_type'], $hierarchical_post_types ) ) {
+               return false;
+       }
+
+       if ( $parent > 0 && ! $child_of ) {
+               $hierarchical = false;
+       }
+
+       // 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 false;
+       }
+
+       // $args can be whatever, only use the args defined in defaults to compute the key.
+       $key = md5( serialize( wp_array_slice_assoc( $r, array_keys( $defaults ) ) ) );
+       $last_changed = wp_cache_get( 'last_changed', 'posts' );
+       if ( ! $last_changed ) {
+               $last_changed = microtime();
+               wp_cache_set( 'last_changed', $last_changed, 'posts' );
+       }
+
+       $cache_key = "get_pages:$key:$last_changed";
+       if ( $cache = wp_cache_get( $cache_key, 'posts' ) ) {
+               // Convert to WP_Post instances.
+               $pages = array_map( 'get_post', $cache );
+               /** This filter is documented in wp-includes/post-functions.php */
+               $pages = apply_filters( 'get_pages', $pages, $r );
+               return $pages;
+       }
+
+       $inclusions = '';
+       if ( ! empty( $r['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( $r['include'] );
+               if ( ! empty( $incpages ) ) {
+                       $inclusions = ' AND ID IN (' . implode( ',', $incpages ) .  ')';
+               }
+       }
+
+       $exclusions = '';
+       if ( ! empty( $exclude ) ) {
+               $expages = wp_parse_id_list( $exclude );
+               if ( ! empty( $expages ) ) {
+                       $exclusions = ' AND ID NOT IN (' . implode( ',', $expages ) .  ')';
+               }
+       }
+
+       $author_query = '';
+       if ( ! empty( $r['authors'] ) ) {
+               $post_authors = preg_split( '/[\s,]+/', $r['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 ( '' !== $meta_key || '' !== $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 = wp_unslash($meta_key);
+               $meta_value = wp_unslash($meta_value);
+               if ( '' !== $meta_key ) {
+                       $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
+               }
+               if ( '' !== $meta_value ) {
+                       $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
+               }
+
+       }
+
+       if ( is_array( $parent ) ) {
+               $post_parent__in = implode( ',', array_map( 'absint', (array) $parent ) );
+               if ( ! empty( $post_parent__in ) ) {
+                       $where .= " AND post_parent IN ($post_parent__in)";
+               }
+       } elseif ( $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", $r['post_type'], reset( $post_status ) );
+       } else {
+               $post_status = implode( "', '", $post_status );
+               $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $r['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( ',', $r['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( $r['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) ) {
+               /** This filter is documented in wp-includes/post-functions.php */
+               $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( $r['exclude_tree'] ) ) {
+               $exclude = wp_parse_id_list( $r['exclude_tree'] );
+               foreach ( $exclude as $id ) {
+                       $children = get_page_children( $id, $pages );
+                       foreach ( $children as $child ) {
+                               $exclude[] = $child->ID;
+                       }
+               }
+
+               $num_pages = count( $pages );
+               for ( $i = 0; $i < $num_pages; $i++ ) {
+                       if ( in_array( $pages[$i]->ID, $exclude ) ) {
+                               unset( $pages[$i] );
+                       }
+               }
+       }
+
+       $page_structure = array();
+       foreach ( $pages as $page ) {
+               $page_structure[] = $page->ID;
+       }
+
+       wp_cache_set( $cache_key, $page_structure, 'posts' );
+
+       // Convert to WP_Post instances
+       $pages = array_map( 'get_post', $pages );
+
+       /**
+        * Filter the retrieved list of pages.
+        *
+        * @since 2.1.0
+        *
+        * @param array $pages List of pages to retrieve.
+        * @param array $r     Array of get_pages() arguments.
+        */
+       return apply_filters( 'get_pages', $pages, $r );
+}
+
+//
+// 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 $args 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.
+ *
+ * @since 2.0.0
+ *
+ * @see wp_insert_post()
+ *
+ * @param string|array $args   Arguments for inserting an attachment.
+ * @param string       $file   Optional. Filename.
+ * @param int          $parent Optional. Parent post ID.
+ * @return int Attachment ID.
+ */
+function wp_insert_attachment( $args, $file = false, $parent = 0 ) {
+       $defaults = array(
+               'file'        => $file,
+               'post_parent' => 0
+       );
+
+       $data = wp_parse_args( $args, $defaults );
+
+       if ( ! empty( $parent ) ) {
+               $data['post_parent'] = $parent;
+       }
+
+       $data['post_type'] = 'attachment';
+
+       return wp_insert_post( $data );
+}
+
+/**
+ * Trash or delete an attachment.
+ *
+ * When an attachment is permanently deleted, the file will also be removed.
+ * Deletion removes all post meta fields, taxonomy, comments, etc. associated
+ * with the attachment (except the main post).
+ *
+ * The attachment is moved to the trash instead of permanently deleted unless trash
+ * for media is disabled, item is already in the trash, or $force_delete is true.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int  $post_id      Attachment ID.
+ * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
+ *                           Default false.
+ * @return mixed False on failure. Post data on success.
+ */
+function wp_delete_attachment( $post_id, $force_delete = false ) {
+       global $wpdb;
+
+       if ( !$post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) ) )
+               return $post;
+
+       if ( 'attachment' != $post->post_type )
+               return false;
+
+       if ( !$force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' != $post->post_status )
+               return wp_trash_post( $post_id );
+
+       delete_post_meta($post_id, '_wp_trash_meta_status');
+       delete_post_meta($post_id, '_wp_trash_meta_time');
+
+       $meta = wp_get_attachment_metadata( $post_id );
+       $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
+       $file = get_attached_file( $post_id );
+
+       if ( is_multisite() )
+               delete_transient( 'dirsize_cache' );
+
+       /**
+        * Fires before an attachment is deleted, at the start of wp_delete_attachment().
+        *
+        * @since 2.0.0
+        *
+        * @param int $post_id Attachment ID.
+        */
+       do_action( 'delete_attachment', $post_id );
+
+       wp_delete_object_term_relationships($post_id, array('category', 'post_tag'));
+       wp_delete_object_term_relationships($post_id, get_object_taxonomies($post->post_type));
+
+       // Delete all for any posts.
+       delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );
+
+       wp_defer_comment_counting( true );
+
+       $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ));
+       foreach ( $comment_ids as $comment_id ) {
+               wp_delete_comment( $comment_id, true );
+       }
+
+       wp_defer_comment_counting( false );
+
+       $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ));
+       foreach ( $post_meta_ids as $mid )
+               delete_metadata_by_mid( 'post', $mid );
+
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'delete_post', $post_id );
+       $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
+       if ( ! $result ) {
+               return false;
+       }
+       /** This action is documented in wp-includes/post-functions.php */
+       do_action( 'deleted_post', $post_id );
+
+       $uploadpath = wp_upload_dir();
+
+       if ( ! empty($meta['thumb']) ) {
+               // Don't delete the thumb if another attachment uses it.
+               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", '%' . $wpdb->esc_like( $meta['thumb'] ) . '%', $post_id)) ) {
+                       $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
+                       /** This filter is documented in wp-includes/functions.php */
+                       $thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
+                       @ unlink( path_join($uploadpath['basedir'], $thumbfile) );
+               }
+       }
+
+       // Remove intermediate and backup images if there are any.
+       if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) {
+               foreach ( $meta['sizes'] as $size => $sizeinfo ) {
+                       $intermediate_file = str_replace( basename( $file ), $sizeinfo['file'], $file );
+                       /** This filter is documented in wp-includes/functions.php */
+                       $intermediate_file = apply_filters( 'wp_delete_file', $intermediate_file );
+                       @ unlink( path_join( $uploadpath['basedir'], $intermediate_file ) );
+               }
+       }
+
+       if ( is_array($backup_sizes) ) {
+               foreach ( $backup_sizes as $size ) {
+                       $del_file = path_join( dirname($meta['file']), $size['file'] );
+                       /** This filter is documented in wp-includes/functions.php */
+                       $del_file = apply_filters( 'wp_delete_file', $del_file );
+                       @ unlink( path_join($uploadpath['basedir'], $del_file) );
+               }
+       }
+
+       wp_delete_file( $file );
+
+       clean_post_cache( $post );
+
+       return $post;
+}
+
+/**
+ * Retrieve attachment meta field for attachment ID.
+ *
+ * @since 2.1.0
+ *
+ * @param int  $post_id    Attachment ID. Default 0.
+ * @param bool $unfiltered Optional. If true, filters are not run. Default false.
+ * @return mixed Attachment meta field. False on failure.
+ */
+function wp_get_attachment_metadata( $post_id = 0, $unfiltered = false ) {
+       $post_id = (int) $post_id;
+       if ( !$post = get_post( $post_id ) )
+               return false;
+
+       $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
+
+       if ( $unfiltered )
+               return $data;
+
+       /**
+        * Filter the attachment meta data.
+        *
+        * @since 2.1.0
+        *
+        * @param array|bool $data    Array of meta data for the given attachment, or false
+        *                            if the object does not exist.
+        * @param int        $post_id Attachment ID.
+        */
+       return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
+}
+
+/**
+ * Update metadata for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int   $post_id Attachment ID.
+ * @param array $data    Attachment data.
+ * @return int|bool False if $post is invalid.
+ */
+function wp_update_attachment_metadata( $post_id, $data ) {
+       $post_id = (int) $post_id;
+       if ( !$post = get_post( $post_id ) )
+               return false;
+
+       /**
+        * Filter the updated attachment meta data.
+        *
+        * @since 2.1.0
+        *
+        * @param array $data    Array of updated attachment meta data.
+        * @param int   $post_id Attachment ID.
+        */
+       if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
+               return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
+       else
+               return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
+}
+
+/**
+ * Retrieve the URL for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @global string $pagenow
+ *
+ * @param int $post_id Optional. Attachment ID. Default 0.
+ * @return string|false Attachment URL, otherwise false.
+ */
+function wp_get_attachment_url( $post_id = 0 ) {
+       $post_id = (int) $post_id;
+       if ( !$post = get_post( $post_id ) )
+               return false;
+
+       if ( 'attachment' != $post->post_type )
+               return false;
+
+       $url = '';
+       // Get attached file.
+       if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true) ) {
+               // Get upload directory.
+               if ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) {
+                       // Check that the upload base exists in the file location.
+                       if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
+                               // Replace file location with url location.
+                               $url = str_replace($uploads['basedir'], $uploads['baseurl'], $file);
+                       } elseif ( false !== strpos($file, 'wp-content/uploads') ) {
+                               $url = $uploads['baseurl'] . substr( $file, strpos($file, 'wp-content/uploads') + 18 );
+                       } else {
+                               // It's a newly-uploaded file, therefore $file is relative to the basedir.
+                               $url = $uploads['baseurl'] . "/$file";
+                       }
+               }
+       }
+
+       /*
+        * If any of the above options failed, Fallback on the GUID as used pre-2.7,
+        * not recommended to rely upon this.
+        */
+       if ( empty($url) ) {
+               $url = get_the_guid( $post->ID );
+       }
+
+       // On SSL front-end, URLs should be HTTPS.
+       if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] ) {
+               $url = set_url_scheme( $url );
+       }
+
+       /**
+        * Filter the attachment URL.
+        *
+        * @since 2.1.0
+        *
+        * @param string $url     URL for the given attachment.
+        * @param int    $post_id Attachment ID.
+        */
+       $url = apply_filters( 'wp_get_attachment_url', $url, $post->ID );
+
+       if ( empty( $url ) )
+               return false;
+
+       return $url;
+}
+
+/**
+ * Retrieve thumbnail for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Optional. Attachment ID. Default 0.
+ * @return string|false False on failure. Thumbnail file path on success.
+ */
+function wp_get_attachment_thumb_file( $post_id = 0 ) {
+       $post_id = (int) $post_id;
+       if ( !$post = get_post( $post_id ) )
+               return false;
+       if ( !is_array( $imagedata = wp_get_attachment_metadata( $post->ID ) ) )
+               return false;
+
+       $file = get_attached_file( $post->ID );
+
+       if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) ) {
+               /**
+                * Filter the attachment thumbnail file path.
+                *
+                * @since 2.1.0
+                *
+                * @param string $thumbfile File path to the attachment thumbnail.
+                * @param int    $post_id   Attachment ID.
+                */
+               return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
+       }
+       return false;
+}
+
+/**
+ * Retrieve URL for an attachment thumbnail.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Optional. Attachment ID. Default 0.
+ * @return string|false False on failure. Thumbnail URL on success.
+ */
+function wp_get_attachment_thumb_url( $post_id = 0 ) {
+       $post_id = (int) $post_id;
+       if ( !$post = get_post( $post_id ) )
+               return false;
+       if ( !$url = wp_get_attachment_url( $post->ID ) )
+               return false;
+
+       $sized = image_downsize( $post_id, 'thumbnail' );
+       if ( $sized )
+               return $sized[0];
+
+       if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
+               return false;
+
+       $url = str_replace(basename($url), basename($thumb), $url);
+
+       /**
+        * Filter the attachment thumbnail URL.
+        *
+        * @since 2.1.0
+        *
+        * @param string $url     URL for the attachment thumbnail.
+        * @param int    $post_id Attachment ID.
+        */
+       return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
+}
+
+/**
+ * Verifies an attachment is of a given type.
+ *
+ * @since 4.2.0
+ *
+ * @param string      $type    Attachment type. Accepts 'image', 'audio', or 'video'.
+ * @param int|WP_Post $post_id Optional. Attachment ID. Default 0.
+ * @return bool True if one of the accepted types, false otherwise.
+ */
+function wp_attachment_is( $type, $post_id = 0 ) {
+       if ( ! $post = get_post( $post_id ) ) {
+               return false;
+       }
+
+       if ( ! $file = get_attached_file( $post->ID ) ) {
+               return false;
+       }
+
+       if ( 0 === strpos( $post->post_mime_type, $type . '/' ) ) {
+               return true;
+       }
+
+       $check = wp_check_filetype( $file );
+       if ( empty( $check['ext'] ) ) {
+               return false;
+       }
+
+       $ext = $check['ext'];
+
+       if ( 'import' !== $post->post_mime_type ) {
+               return $type === $ext;
+       }
+
+       switch ( $type ) {
+       case 'image':
+               $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
+               return in_array( $ext, $image_exts );
+
+       case 'audio':
+               return in_array( $ext, wp_get_audio_extensions() );
+
+       case 'video':
+               return in_array( $ext, wp_get_video_extensions() );
+
+       default:
+               return $type === $ext;
+       }
+}
+
+/**
+ * Checks if the attachment is an image.
+ *
+ * @since 2.1.0
+ * @since 4.2.0 Modified into wrapper for wp_attachment_is() and
+ *              allowed WP_Post object to be passed.
+ *
+ * @param int|WP_Post $post Optional. Attachment ID. Default 0.
+ * @return bool Whether the attachment is an image.
+ */
+function wp_attachment_is_image( $post = 0 ) {
+       return wp_attachment_is( 'image', $post );
+}
+
+/**
+ * Retrieve the icon for a MIME type.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $mime MIME type or attachment ID.
+ * @return string|false Icon, false otherwise.
+ */
+function wp_mime_type_icon( $mime = 0 ) {
+       if ( !is_numeric($mime) )
+               $icon = wp_cache_get("mime_type_icon_$mime");
+
+       $post_id = 0;
+       if ( empty($icon) ) {
+               $post_mimes = array();
+               if ( is_numeric($mime) ) {
+                       $mime = (int) $mime;
+                       if ( $post = get_post( $mime ) ) {
+                               $post_id = (int) $post->ID;
+                               $file = get_attached_file( $post_id );
+                               $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $file);
+                               if ( !empty($ext) ) {
+                                       $post_mimes[] = $ext;
+                                       if ( $ext_type = wp_ext2type( $ext ) )
+                                               $post_mimes[] = $ext_type;
+                               }
+                               $mime = $post->post_mime_type;
+                       } else {
+                               $mime = 0;
+                       }
+               } else {
+                       $post_mimes[] = $mime;
+               }
+
+               $icon_files = wp_cache_get('icon_files');
+
+               if ( !is_array($icon_files) ) {
+                       /**
+                        * Filter the icon directory path.
+                        *
+                        * @since 2.0.0
+                        *
+                        * @param string $path Icon directory absolute path.
+                        */
+                       $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
+
+                       /**
+                        * Filter the icon directory URI.
+                        *
+                        * @since 2.0.0
+                        *
+                        * @param string $uri Icon directory URI.
+                        */
+                       $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url( 'images/media' ) );
+
+                       /**
+                        * Filter the list of icon directory URIs.
+                        *
+                        * @since 2.5.0
+                        *
+                        * @param array $uris List of icon directory URIs.
+                        */
+                       $dirs = apply_filters( 'icon_dirs', array( $icon_dir => $icon_dir_uri ) );
+                       $icon_files = array();
+                       while ( $dirs ) {
+                               $keys = array_keys( $dirs );
+                               $dir = array_shift( $keys );
+                               $uri = array_shift($dirs);
+                               if ( $dh = opendir($dir) ) {
+                                       while ( false !== $file = readdir($dh) ) {
+                                               $file = basename($file);
+                                               if ( substr($file, 0, 1) == '.' )
+                                                       continue;
+                                               if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
+                                                       if ( is_dir("$dir/$file") )
+                                                               $dirs["$dir/$file"] = "$uri/$file";
+                                                       continue;
+                                               }
+                                               $icon_files["$dir/$file"] = "$uri/$file";
+                                       }
+                                       closedir($dh);
+                               }
+                       }
+                       wp_cache_add( 'icon_files', $icon_files, 'default', 600 );
+               }
+
+               $types = array();
+               // Icon basename - extension = MIME wildcard.
+               foreach ( $icon_files as $file => $uri )
+                       $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
+
+               if ( ! empty($mime) ) {
+                       $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
+                       $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
+                       $post_mimes[] = str_replace('/', '_', $mime);
+               }
+
+               $matches = wp_match_mime_types(array_keys($types), $post_mimes);
+               $matches['default'] = array('default');
+
+               foreach ( $matches as $match => $wilds ) {
+                       foreach ( $wilds as $wild ) {
+                               if ( ! isset( $types[ $wild ] ) ) {
+                                       continue;
+                               }
+
+                               $icon = $types[ $wild ];
+                               if ( ! is_numeric( $mime ) ) {
+                                       wp_cache_add( "mime_type_icon_$mime", $icon );
+                               }
+                               break 2;
+                       }
+               }
+       }
+
+       /**
+        * Filter the mime type icon.
+        *
+        * @since 2.1.0
+        *
+        * @param string $icon    Path to the mime type icon.
+        * @param string $mime    Mime type.
+        * @param int    $post_id Attachment ID. Will equal 0 if the function passed
+        *                        the mime type.
+        */
+       return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id );
+}
+
+/**
+ * Check for changed slugs for published post objects and save the old slug.
+ *
+ * The function is used when a post object of any type is updated,
+ * by comparing the current and previous post objects.
+ *
+ * If the slug was changed and not already part of the old slugs then it will be
+ * added to the post meta field ('_wp_old_slug') for storing old slugs for that
+ * post.
+ *
+ * The most logically usage of this function is redirecting changed post objects, so
+ * that those that linked to an changed post will be redirected to the new post.
+ *
+ * @since 2.1.0
+ *
+ * @param int     $post_id     Post ID.
+ * @param WP_Post $post        The Post Object
+ * @param WP_Post $post_before The Previous Post Object
+ */
+function wp_check_for_changed_slugs( $post_id, $post, $post_before ) {
+       // Don't bother if it hasn't changed.
+       if ( $post->post_name == $post_before->post_name ) {
+               return;
+       }
+
+       // We're only concerned with published, non-hierarchical objects.
+       if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) {
+               return;
+       }
+
+       $old_slugs = (array) get_post_meta( $post_id, '_wp_old_slug' );
+
+       // If we haven't added this old slug before, add it now.
+       if ( ! empty( $post_before->post_name ) && ! in_array( $post_before->post_name, $old_slugs ) ) {
+               add_post_meta( $post_id, '_wp_old_slug', $post_before->post_name );
+       }
+
+       // If the new slug was used previously, delete it from the list.
+       if ( in_array( $post->post_name, $old_slugs ) ) {
+               delete_post_meta( $post_id, '_wp_old_slug', $post->post_name );
+       }
+}
+
+/**
+ * Retrieve the private post SQL based on capability.
+ *
+ * This function provides a standardized way to appropriately select on the
+ * post_status of a post type. The function will return a piece of SQL code
+ * that can be added to a WHERE clause; this SQL is constructed to allow all
+ * published posts, and all private posts to which the user has access.
+ *
+ * @since 2.2.0
+ * @since 4.3.0 Added the ability to pass an array to `$post_type`.
+ *
+ * @param string|array $post_type Single post type or an array of post types. Currently only supports 'post' or 'page'.
+ * @return string SQL code that can be added to a where clause.
+ */
+function get_private_posts_cap_sql( $post_type ) {
+       return get_posts_by_author_sql( $post_type, false );
+}
+
+/**
+ * Retrieve the post SQL based on capability, author, and type.
+ *
+ * @since 3.0.0
+ * @since 4.3.0 Introduced the ability to pass an array of post types to `$post_type`.
+ *
+ * @see get_private_posts_cap_sql()
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array|string   $post_type   Single post type or an array of post types.
+ * @param bool           $full        Optional. Returns a full WHERE statement instead of just
+ *                                    an 'andalso' term. Default true.
+ * @param int            $post_author Optional. Query posts having a single author ID. Default null.
+ * @param bool           $public_only Optional. Only return public posts. Skips cap checks for
+ *                                    $current_user.  Default false.
+ * @return string SQL WHERE code that can be added to a query.
+ */
+function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) {
+       global $wpdb;
+
+       if ( is_array( $post_type ) ) {
+               $post_types = $post_type;
+       } else {
+               $post_types = array( $post_type );
+       }
+
+       $post_type_clauses = array();
+       foreach ( $post_types as $post_type ) {
+               $post_type_obj = get_post_type_object( $post_type );
+               if ( ! $post_type_obj ) {
+                       continue;
+               }
+
+               /**
+                * Filter the capability to read private posts for a custom post type
+                * when generating SQL for getting posts by author.
+                *
+                * @since 2.2.0
+                * @deprecated 3.2.0 The hook transitioned from "somewhat useless" to "totally useless".
+                *
+                * @param string $cap Capability.
+                */
+               if ( ! $cap = apply_filters( 'pub_priv_sql_capability', '' ) ) {
+                       $cap = current_user_can( $post_type_obj->cap->read_private_posts );
+               }
+
+               // Only need to check the cap if $public_only is false.
+               $post_status_sql = "post_status = 'publish'";
+               if ( false === $public_only ) {
+                       if ( $cap ) {
+                               // Does the user have the capability to view private posts? Guess so.
+                               $post_status_sql .= " OR post_status = 'private'";
+                       } elseif ( is_user_logged_in() ) {
+                               // Users can view their own private posts.
+                               $id = get_current_user_id();
+                               if ( null === $post_author || ! $full ) {
+                                       $post_status_sql .= " OR post_status = 'private' AND post_author = $id";
+                               } elseif ( $id == (int) $post_author ) {
+                                       $post_status_sql .= " OR post_status = 'private'";
+                               } // else none
+                       } // else none
+               }
+
+               $post_type_clauses[] = "( post_type = '" . $post_type . "' AND ( $post_status_sql ) )";
+       }
+
+       if ( empty( $post_type_clauses ) ) {
+               return $full ? 'WHERE 1 = 0' : '1 = 0';
+       }
+
+       $sql = '( '. implode( ' OR ', $post_type_clauses ) . ' )';
+
+       if ( null !== $post_author ) {
+               $sql .= $wpdb->prepare( ' AND post_author = %d', $post_author );
+       }
+
+       if ( $full ) {
+               $sql = 'WHERE ' . $sql;
+       }
+
+       return $sql;
+}
+
+/**
+ * Retrieve the date that the last post was published.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is the date when the last post was posted. The
+ * 'gmt' is when the last post was posted in GMT formatted date.
+ *
+ * @since 0.71
+ * @since 4.4.0 The `$post_type` argument was added.
+ *
+ * @param string $timezone  Optional. The timezone for the timestamp. Accepts 'server', 'blog', or 'gmt'.
+ *                          'server' uses the server's internal timezone.
+ *                          'blog' uses the `post_modified` field, which proxies to the timezone set for the site.
+ *                          'gmt' uses the `post_modified_gmt` field.
+ *                          Default 'server'.
+ * @param string $post_type Optional. The post type to check. Default 'any'.
+ * @return string The date of the last post.
+ */
+function get_lastpostdate( $timezone = 'server', $post_type = 'any' ) {
+       /**
+        * Filter the date the last post was published.
+        *
+        * @since 2.3.0
+        *
+        * @param string $date     Date the last post was published.
+        * @param string $timezone Location to use for getting the post published date.
+        *                         See {@see get_lastpostdate()} for accepted `$timezone` values.
+        */
+       return apply_filters( 'get_lastpostdate', _get_last_post_time( $timezone, 'date', $post_type ), $timezone );
+}
+
+/**
+ * Get the timestamp of the last time any post was modified.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is just when the last post was modified. The
+ * 'gmt' is when the last post was modified in GMT time.
+ *
+ * @since 1.2.0
+ * @since 4.4.0 The `$post_type` argument was added.
+ *
+ * @param string $timezone  Optional. The timezone for the timestamp. See {@see get_lastpostdate()}
+ *                          for information on accepted values.
+ *                          Default 'server'.
+ * @param string $post_type Optional. The post type to check. Default 'any'.
+ * @return string The timestamp.
+ */
+function get_lastpostmodified( $timezone = 'server', $post_type = 'any' ) {
+       /**
+        * Pre-filter the return value of get_lastpostmodified() before the query is run.
+        *
+        * @since 4.4.0
+        *
+        * @param string $lastpostmodified Date the last post was modified.
+        *                                 Returning anything other than false will short-circuit the function.
+        * @param string $timezone         Location to use for getting the post modified date.
+        *                                 See {@see get_lastpostdate()} for accepted `$timezone` values.
+        * @param string $post_type        The post type to check.
+        */
+       $lastpostmodified = apply_filters( 'pre_get_lastpostmodified', false, $timezone, $post_type );
+       if ( false !== $lastpostmodified ) {
+               return $lastpostmodified;
+       }
+
+       $lastpostmodified = _get_last_post_time( $timezone, 'modified', $post_type );
+
+       $lastpostdate = get_lastpostdate($timezone);
+       if ( $lastpostdate > $lastpostmodified ) {
+               $lastpostmodified = $lastpostdate;
+       }
+
+       /**
+        * Filter the date the last post was modified.
+        *
+        * @since 2.3.0
+        *
+        * @param string $lastpostmodified Date the last post was modified.
+        * @param string $timezone         Location to use for getting the post modified date.
+        *                                 See {@see get_lastpostdate()} for accepted `$timezone` values.
+        */
+       return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
+}
+
+/**
+ * Get the timestamp of the last time any post was modified or published.
+ *
+ * @since 3.1.0
+ * @since 4.4.0 The `$post_type` argument was added.
+ * @access private
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $timezone  The timezone for the timestamp. See get_lastpostdate().
+ *                          for information on accepted values.
+ * @param string $field     Post field to check. Accepts 'date' or 'modified'.
+ * @param string $post_type Optional. The post type to check. Default 'any'.
+ * @return string|false The timestamp.
+ */
+function _get_last_post_time( $timezone, $field, $post_type = 'any' ) {
+       global $wpdb;
+
+       if ( ! in_array( $field, array( 'date', 'modified' ) ) ) {
+               return false;
+       }
+
+       $timezone = strtolower( $timezone );
+
+       $key = "lastpost{$field}:$timezone";
+       if ( 'any' !== $post_type ) {
+               $key .= ':' . sanitize_key( $post_type );
+       }
+
+       $date = wp_cache_get( $key, 'timeinfo' );
+
+       if ( ! $date ) {
+               if ( 'any' === $post_type ) {
+                       $post_types = get_post_types( array( 'public' => true ) );
+                       array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) );
+                       $post_types = "'" . implode( "', '", $post_types ) . "'";
+               } else {
+                       $post_types = "'" . sanitize_key( $post_type ) . "'";
+               }
+
+               switch ( $timezone ) {
+                       case 'gmt':
+                               $date = $wpdb->get_var("SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+                               break;
+                       case 'blog':
+                               $date = $wpdb->get_var("SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+                               break;
+                       case 'server':
+                               $add_seconds_server = date( 'Z' );
+                               $date = $wpdb->get_var("SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+                               break;
+               }
+
+               if ( $date ) {
+                       wp_cache_set( $key, $date, 'timeinfo' );
+               }
+       }
+
+       return $date;
+}
+
+/**
+ * Updates posts in cache.
+ *
+ * @since 1.5.1
+ *
+ * @param array $posts Array of post objects, passed by reference.
+ */
+function update_post_cache( &$posts ) {
+       if ( ! $posts )
+               return;
+
+       foreach ( $posts as $post )
+               wp_cache_add( $post->ID, $post, 'posts' );
+}
+
+/**
+ * Will clean the post in the cache.
+ *
+ * Cleaning means delete from the cache of the post. Will call to clean the term
+ * object cache associated with the post ID.
+ *
+ * This function not run if $_wp_suspend_cache_invalidation is not empty. See
+ * wp_suspend_cache_invalidation().
+ *
+ * @since 2.0.0
+ *
+ * @global bool $_wp_suspend_cache_invalidation
+ *
+ * @param int|WP_Post $post Post ID or post object to remove from the cache.
+ */
+function clean_post_cache( $post ) {
+       global $_wp_suspend_cache_invalidation;
+
+       if ( ! empty( $_wp_suspend_cache_invalidation ) )
+               return;
+
+       $post = get_post( $post );
+       if ( empty( $post ) )
+               return;
+
+       wp_cache_delete( $post->ID, 'posts' );
+       wp_cache_delete( $post->ID, 'post_meta' );
+
+       clean_object_term_cache( $post->ID, $post->post_type );
+
+       wp_cache_delete( 'wp_get_archives', 'general' );
+
+       /**
+        * Fires immediately after the given post's cache is cleaned.
+        *
+        * @since 2.5.0
+        *
+        * @param int     $post_id Post ID.
+        * @param WP_Post $post    Post object.
+        */
+       do_action( 'clean_post_cache', $post->ID, $post );
+
+       if ( 'page' == $post->post_type ) {
+               wp_cache_delete( 'all_page_ids', 'posts' );
+
+               /**
+                * Fires immediately after the given page's cache is cleaned.
+                *
+                * @since 2.5.0
+                *
+                * @param int $post_id Post ID.
+                */
+               do_action( 'clean_page_cache', $post->ID );
+       }
+
+       wp_cache_set( 'last_changed', microtime(), 'posts' );
+}
+
+/**
+ * Call major cache updating functions for list of Post objects.
+ *
+ * @since 1.5.0
+ *
+ * @param array  $posts             Array of Post objects
+ * @param string $post_type         Optional. Post type. Default 'post'.
+ * @param bool   $update_term_cache Optional. Whether to update the term cache. Default true.
+ * @param bool   $update_meta_cache Optional. Whether to update the meta cache. Default true.
+ */
+function update_post_caches( &$posts, $post_type = 'post', $update_term_cache = true, $update_meta_cache = true ) {
+       // No point in doing all this work if we didn't match any posts.
+       if ( !$posts )
+               return;
+
+       update_post_cache($posts);
+
+       $post_ids = array();
+       foreach ( $posts as $post )
+               $post_ids[] = $post->ID;
+
+       if ( ! $post_type )
+               $post_type = 'any';
+
+       if ( $update_term_cache ) {
+               if ( is_array($post_type) ) {
+                       $ptypes = $post_type;
+               } elseif ( 'any' == $post_type ) {
+                       $ptypes = array();
+                       // Just use the post_types in the supplied posts.
+                       foreach ( $posts as $post ) {
+                               $ptypes[] = $post->post_type;
+                       }
+                       $ptypes = array_unique($ptypes);
+               } else {
+                       $ptypes = array($post_type);
+               }
+
+               if ( ! empty($ptypes) )
+                       update_object_term_cache($post_ids, $ptypes);
+       }
+
+       if ( $update_meta_cache )
+               update_postmeta_cache($post_ids);
+}
+
+/**
+ * Updates metadata cache for list of post IDs.
+ *
+ * Performs SQL query to retrieve the metadata for the post IDs and updates the
+ * metadata cache for the posts. Therefore, the functions, which call this
+ * function, do not need to perform SQL queries on their own.
+ *
+ * @since 2.1.0
+ *
+ * @param array $post_ids List of post IDs.
+ * @return array|false Returns false if there is nothing to update or an array
+ *                     of metadata.
+ */
+function update_postmeta_cache( $post_ids ) {
+       return update_meta_cache('post', $post_ids);
+}
+
+/**
+ * Will clean the attachment in the cache.
+ *
+ * Cleaning means delete from the cache. Optionally will clean the term
+ * object cache associated with the attachment ID.
+ *
+ * This function will not run if $_wp_suspend_cache_invalidation is not empty.
+ *
+ * @since 3.0.0
+ *
+ * @global bool $_wp_suspend_cache_invalidation
+ *
+ * @param int  $id          The attachment ID in the cache to clean.
+ * @param bool $clean_terms Optional. Whether to clean terms cache. Default false.
+ */
+function clean_attachment_cache( $id, $clean_terms = false ) {
+       global $_wp_suspend_cache_invalidation;
+
+       if ( !empty($_wp_suspend_cache_invalidation) )
+               return;
+
+       $id = (int) $id;
+
+       wp_cache_delete($id, 'posts');
+       wp_cache_delete($id, 'post_meta');
+
+       if ( $clean_terms )
+               clean_object_term_cache($id, 'attachment');
+
+       /**
+        * Fires after the given attachment's cache is cleaned.
+        *
+        * @since 3.0.0
+        *
+        * @param int $id Attachment ID.
+        */
+       do_action( 'clean_attachment_cache', $id );
+}
+
+//
+// Hooks
+//
+
+/**
+ * Hook for managing future post transitions to published.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @see wp_clear_scheduled_hook()
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string  $new_status New post status.
+ * @param string  $old_status Previous post status.
+ * @param WP_Post $post       Post object.
+ */
+function _transition_post_status( $new_status, $old_status, $post ) {
+       global $wpdb;
+
+       if ( $old_status != 'publish' && $new_status == 'publish' ) {
+               // Reset GUID if transitioning to publish and it is empty.
+               if ( '' == get_the_guid($post->ID) )
+                       $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
+
+               /**
+                * Fires when a post's status is transitioned from private to published.
+                *
+                * @since 1.5.0
+                * @deprecated 2.3.0 Use 'private_to_publish' instead.
+                *
+                * @param int $post_id Post ID.
+                */
+               do_action('private_to_published', $post->ID);
+       }
+
+       // If published posts changed clear the lastpostmodified cache.
+       if ( 'publish' == $new_status || 'publish' == $old_status) {
+               foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
+                       wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' );
+                       wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' );
+                       wp_cache_delete( "lastpostdate:$timezone:{$post->post_type}", 'timeinfo' );
+               }
+       }
+
+       if ( $new_status !== $old_status ) {
+               wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
+               wp_cache_delete( _count_posts_cache_key( $post->post_type, 'readable' ), 'counts' );
+       }
+
+       // Always clears the hook in case the post status bounced from future to draft.
+       wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
+}
+
+/**
+ * Hook used to schedule publication for a post marked for the future.
+ *
+ * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param int     $deprecated Not used. Can be set to null. Never implemented. Not marked
+ *                            as deprecated with _deprecated_argument() as it conflicts with
+ *                            wp_transition_post_status() and the default filter for
+ *                            {@see _future_post_hook()}.
+ * @param WP_Post $post       Post object.
+ */
+function _future_post_hook( $deprecated, $post ) {
+       wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) );
+       wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT') , 'publish_future_post', array( $post->ID ) );
+}
+
+/**
+ * Hook to schedule pings and enclosures when a post is published.
+ *
+ * Uses XMLRPC_REQUEST and WP_IMPORTING constants.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param int $post_id The ID in the database table of the post being published.
+ */
+function _publish_post_hook( $post_id ) {
+       if ( defined( 'XMLRPC_REQUEST' ) ) {
+               /**
+                * Fires when _publish_post_hook() is called during an XML-RPC request.
+                *
+                * @since 2.1.0
+                *
+                * @param int $post_id Post ID.
+                */
+               do_action( 'xmlrpc_publish_post', $post_id );
+       }
+
+       if ( defined('WP_IMPORTING') )
+               return;
+
+       if ( get_option('default_pingback_flag') )
+               add_post_meta( $post_id, '_pingme', '1' );
+       add_post_meta( $post_id, '_encloseme', '1' );
+
+       wp_schedule_single_event(time(), 'do_pings');
+}
+
+/**
+ * Return the post's parent's post_ID
+ *
+ * @since 3.1.0
+ *
+ * @param int $post_ID
+ *
+ * @return int|false Post parent ID, otherwise false.
+ */
+function wp_get_post_parent_id( $post_ID ) {
+       $post = get_post( $post_ID );
+       if ( !$post || is_wp_error( $post ) )
+               return false;
+       return (int) $post->post_parent;
+}
+
+/**
+ * Check the given subset of the post hierarchy for hierarchy loops.
+ *
+ * Prevents loops from forming and breaks those that it finds. Attached
+ * to the 'wp_insert_post_parent' filter.
+ *
+ * @since 3.1.0
+ *
+ * @see wp_find_hierarchy_loop()
+ *
+ * @param int $post_parent ID of the parent for the post we're checking.
+ * @param int $post_ID     ID of the post we're checking.
+ * @return int The new post_parent for the post, 0 otherwise.
+ */
+function wp_check_post_hierarchy_for_loops( $post_parent, $post_ID ) {
+       // Nothing fancy here - bail.
+       if ( !$post_parent )
+               return 0;
+
+       // New post can't cause a loop.
+       if ( empty( $post_ID ) )
+               return $post_parent;
+
+       // Can't be its own parent.
+       if ( $post_parent == $post_ID )
+               return 0;
+
+       // Now look for larger loops.
+       if ( !$loop = wp_find_hierarchy_loop( 'wp_get_post_parent_id', $post_ID, $post_parent ) )
+               return $post_parent; // No loop
+
+       // Setting $post_parent to the given value causes a loop.
+       if ( isset( $loop[$post_ID] ) )
+               return 0;
+
+       // There's a loop, but it doesn't contain $post_ID. Break the loop.
+       foreach ( array_keys( $loop ) as $loop_member )
+               wp_update_post( array( 'ID' => $loop_member, 'post_parent' => 0 ) );
+
+       return $post_parent;
+}
+
+/**
+ * Set a post thumbnail.
+ *
+ * @since 3.1.0
+ *
+ * @param int|WP_Post $post         Post ID or post object where thumbnail should be attached.
+ * @param int         $thumbnail_id Thumbnail to attach.
+ * @return int|bool True on success, false on failure.
+ */
+function set_post_thumbnail( $post, $thumbnail_id ) {
+       $post = get_post( $post );
+       $thumbnail_id = absint( $thumbnail_id );
+       if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) {
+               if ( wp_get_attachment_image( $thumbnail_id, 'thumbnail' ) )
+                       return update_post_meta( $post->ID, '_thumbnail_id', $thumbnail_id );
+               else
+                       return delete_post_meta( $post->ID, '_thumbnail_id' );
+       }
+       return false;
+}
+
+/**
+ * Remove a post thumbnail.
+ *
+ * @since 3.3.0
+ *
+ * @param int|WP_Post $post Post ID or post object where thumbnail should be removed from.
+ * @return bool True on success, false on failure.
+ */
+function delete_post_thumbnail( $post ) {
+       $post = get_post( $post );
+       if ( $post )
+               return delete_post_meta( $post->ID, '_thumbnail_id' );
+       return false;
+}
+
+/**
+ * Delete auto-drafts for new posts that are > 7 days old.
+ *
+ * @since 3.4.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ */
+function wp_delete_auto_drafts() {
+       global $wpdb;
+
+       // Cleanup old auto-drafts more than 7 days old.
+       $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
+       foreach ( (array) $old_posts as $delete ) {
+               // Force delete.
+               wp_delete_post( $delete, true );
+       }
+}
+
+/**
+ * Update the custom taxonomies' term counts when a post's status is changed.
+ *
+ * For example, default posts term counts (for custom taxonomies) don't include
+ * private / draft posts.
+ *
+ * @since 3.3.0
+ * @access private
+ *
+ * @param string  $new_status New post status.
+ * @param string  $old_status Old post status.
+ * @param WP_Post $post       Post object.
+ */
+function _update_term_count_on_transition_post_status( $new_status, $old_status, $post ) {
+       // Update counts for the post's terms.
+       foreach ( (array) get_object_taxonomies( $post->post_type ) as $taxonomy ) {
+               $tt_ids = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'tt_ids' ) );
+               wp_update_term_count( $tt_ids, $taxonomy );
+       }
+}
+
+/**
+ * Adds any posts from the given ids to the cache that do not already exist in cache
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @see update_post_caches()
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array $ids               ID list.
+ * @param bool  $update_term_cache Optional. Whether to update the term cache. Default true.
+ * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
+ */
+function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) {
+       global $wpdb;
+
+       $non_cached_ids = _get_non_cached_ids( $ids, 'posts' );
+       if ( !empty( $non_cached_ids ) ) {
+               $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) );
+
+               update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
+       }
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesrestapirestfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/rest-api/rest-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api/rest-functions.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/rest-api/rest-functions.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,643 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * REST API functions.
- *
- * @package WordPress
- * @subpackage REST_API
- * @since 4.4.0
- */
-
-/**
- * Registers a REST API route.
- *
- * @since 4.4.0
- *
- * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
- *
- * @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
- * @param string $route     The base URL for route you are adding.
- * @param array  $args      Optional. Either an array of options for the endpoint, or an array of arrays for
- *                          multiple methods. Default empty array.
- * @param bool   $override  Optional. If the route already exists, should we override it? True overrides,
- *                          false merges (with newer overriding if duplicate keys exist). Default false.
- * @return bool True on success, false on error.
- */
-function register_rest_route( $namespace, $route, $args = array(), $override = false ) {
-       /** @var WP_REST_Server $wp_rest_server */
-       global $wp_rest_server;
-
-       if ( empty( $namespace ) ) {
-               /*
-                * Non-namespaced routes are not allowed, with the exception of the main
-                * and namespace indexes. If you really need to register a
-                * non-namespaced route, call `WP_REST_Server::register_route` directly.
-                */
-               _doing_it_wrong( 'register_rest_route', 'Routes must be namespaced with plugin or theme name and version.', '4.4.0' );
-               return false;
-       } else if ( empty( $route ) ) {
-               _doing_it_wrong( 'register_rest_route', 'Route must be specified.', '4.4.0' );
-               return false;
-       }
-
-       if ( isset( $args['callback'] ) ) {
-               // Upgrade a single set to multiple.
-               $args = array( $args );
-       }
-
-       $defaults = array(
-               'methods'         => 'GET',
-               'callback'        => null,
-               'args'            => array(),
-       );
-       foreach ( $args as $key => &$arg_group ) {
-               if ( ! is_numeric( $arg_group ) ) {
-                       // Route option, skip here.
-                       continue;
-               }
-
-               $arg_group = array_merge( $defaults, $arg_group );
-       }
-
-       $full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
-       $wp_rest_server->register_route( $namespace, $full_route, $args, $override );
-       return true;
-}
-
-/**
- * Registers rewrite rules for the API.
- *
- * @since 4.4.0
- *
- * @see rest_api_register_rewrites()
- * @global WP $wp Current WordPress environment instance.
- */
-function rest_api_init() {
-       rest_api_register_rewrites();
-
-       global $wp;
-       $wp->add_query_var( 'rest_route' );
-}
-
-/**
- * Adds REST rewrite rules.
- *
- * @since 4.4.0
- *
- * @see add_rewrite_rule()
- */
-function rest_api_register_rewrites() {
-       add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
-       add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
-}
-
-/**
- * Registers the default REST API filters.
- *
- * Attached to the {@see 'rest_api_init'} action
- * to make testing and disabling these filters easier.
- *
- * @since 4.4.0
- */
-function rest_api_default_filters() {
-       // Deprecated reporting.
-       add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
-       add_filter( 'deprecated_function_trigger_error', '__return_false' );
-       add_action( 'deprecated_argument_run', 'rest_handle_deprecated_argument', 10, 3 );
-       add_filter( 'deprecated_argument_trigger_error', '__return_false' );
-
-       // Default serving.
-       add_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
-       add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
-
-       add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
-}
-
-/**
- * Loads the REST API.
- *
- * @since 4.4.0
- *
- * @global WP             $wp             Current WordPress environment instance.
- * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
- */
-function rest_api_loaded() {
-       if ( empty( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
-               return;
-       }
-
-       /**
-        * Whether this is a REST Request.
-        *
-        * @since 4.4.0
-        * @var bool
-        */
-       define( 'REST_REQUEST', true );
-
-       /** @var WP_REST_Server $wp_rest_server */
-       global $wp_rest_server;
-
-       /**
-        * Filter the REST Server Class.
-        *
-        * This filter allows you to adjust the server class used by the API, using a
-        * different class to handle requests.
-        *
-        * @since 4.4.0
-        *
-        * @param string $class_name The name of the server class. Default 'WP_REST_Server'.
-        */
-       $wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
-       $wp_rest_server = new $wp_rest_server_class;
-
-       /**
-        * Fires when preparing to serve an API request.
-        *
-        * Endpoint objects should be created and register their hooks on this action rather
-        * than another action to ensure they're only loaded when needed.
-        *
-        * @since 4.4.0
-        *
-        * @param WP_REST_Server $wp_rest_server Server object.
-        */
-       do_action( 'rest_api_init', $wp_rest_server );
-
-       // Fire off the request.
-       $wp_rest_server->serve_request( $GLOBALS['wp']->query_vars['rest_route'] );
-
-       // We're done.
-       die();
-}
-
-/**
- * Retrieves the URL prefix for any API resource.
- *
- * @since 4.4.0
- *
- * @return string Prefix.
- */
-function rest_get_url_prefix() {
-       /**
-        * Filter the REST URL prefix.
-        *
-        * @since 4.4.0
-        *
-        * @param string $prefix URL prefix. Default 'wp-json'.
-        */
-       return apply_filters( 'rest_url_prefix', 'wp-json' );
-}
-
-/**
- * Retrieves the URL to a REST endpoint on a site.
- *
- * Note: The returned URL is NOT escaped.
- *
- * @since 4.4.0
- *
- * @todo Check if this is even necessary
- *
- * @param int    $blog_id Optional. Blog ID. Default of null returns URL for current blog.
- * @param string $path    Optional. REST route. Default '/'.
- * @param string $scheme  Optional. Sanitization scheme. Default 'rest'.
- * @return string Full URL to the endpoint.
- */
-function get_rest_url( $blog_id = null, $path = '/', $scheme = 'rest' ) {
-       if ( empty( $path ) ) {
-               $path = '/';
-       }
-
-       if ( is_multisite() && get_blog_option( $blog_id, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) {
-               $url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
-               $url .= '/' . ltrim( $path, '/' );
-       } else {
-               $url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
-
-               $path = '/' . ltrim( $path, '/' );
-
-               $url = add_query_arg( 'rest_route', $path, $url );
-       }
-
-       if ( is_ssl() ) {
-               // If the current host is the same as the REST URL host, force the REST URL scheme to HTTPS.
-               if ( $_SERVER['SERVER_NAME'] === parse_url( get_home_url( $blog_id ), PHP_URL_HOST ) ) {
-                       $url = set_url_scheme( $url, 'https' );
-               }
-       }
-
-       /**
-        * Filter the REST URL.
-        *
-        * Use this filter to adjust the url returned by the `get_rest_url` function.
-        *
-        * @since 4.4.0
-        *
-        * @param string $url     REST URL.
-        * @param string $path    REST route.
-        * @param int    $blog_id Blog ID.
-        * @param string $scheme  Sanitization scheme.
-        */
-       return apply_filters( 'rest_url', $url, $path, $blog_id, $scheme );
-}
-
-/**
- * Retrieves the URL to a REST endpoint.
- *
- * Note: The returned URL is NOT escaped.
- *
- * @since 4.4.0
- *
- * @param string $path   Optional. REST route. Default empty.
- * @param string $scheme Optional. Sanitization scheme. Default 'json'.
- * @return string Full URL to the endpoint.
- */
-function rest_url( $path = '', $scheme = 'json' ) {
-       return get_rest_url( null, $path, $scheme );
-}
-
-/**
- * Do a REST request.
- *
- * Used primarily to route internal requests through WP_REST_Server.
- *
- * @since 4.4.0
- *
- * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
- *
- * @param WP_REST_Request|string $request Request.
- * @return WP_REST_Response REST response.
- */
-function rest_do_request( $request ) {
-       global $wp_rest_server;
-       $request = rest_ensure_request( $request );
-       return $wp_rest_server->dispatch( $request );
-}
-
-/**
- * Ensures request arguments are a request object (for consistency).
- *
- * @since 4.4.0
- *
- * @param array|WP_REST_Request $request Request to check.
- * @return WP_REST_Request REST request instance.
- */
-function rest_ensure_request( $request ) {
-       if ( $request instanceof WP_REST_Request ) {
-               return $request;
-       }
-
-       return new WP_REST_Request( 'GET', '', $request );
-}
-
-/**
- * Ensures a REST response is a response object (for consistency).
- *
- * This implements WP_HTTP_Response, allowing usage of `set_status`/`header`/etc
- * without needing to double-check the object. Will also allow WP_Error to indicate error
- * responses, so users should immediately check for this value.
- *
- * @since 4.4.0
- *
- * @param WP_Error|WP_HTTP_Response|mixed $response Response to check.
- * @return mixed WP_Error if response generated an error, WP_HTTP_Response if response
- *               is a already an instance, otherwise returns a new WP_REST_Response instance.
- */
-function rest_ensure_response( $response ) {
-       if ( is_wp_error( $response ) ) {
-               return $response;
-       }
-
-       if ( $response instanceof WP_HTTP_Response ) {
-               return $response;
-       }
-
-       return new WP_REST_Response( $response );
-}
-
-/**
- * Handles _deprecated_function() errors.
- *
- * @since 4.4.0
- *
- * @param string $function    Function name.
- * @param string $replacement Replacement function name.
- * @param string $version     Version.
- */
-function rest_handle_deprecated_function( $function, $replacement, $version ) {
-       if ( ! empty( $replacement ) ) {
-               /* translators: 1: function name, 2: WordPress version number, 3: new function name */
-               $string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function, $version, $replacement );
-       } else {
-               /* translators: 1: function name, 2: WordPress version number */
-               $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
-       }
-
-       header( sprintf( 'X-WP-DeprecatedFunction: %s', $string ) );
-}
-
-/**
- * Handles _deprecated_argument() errors.
- *
- * @since 4.4.0
- *
- * @param string $function    Function name.
- * @param string $replacement Replacement function name.
- * @param string $version     Version.
- */
-function rest_handle_deprecated_argument( $function, $replacement, $version ) {
-       if ( ! empty( $replacement ) ) {
-               /* translators: 1: function name, 2: WordPress version number, 3: new argument name */
-               $string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function, $version, $replacement );
-       } else {
-               /* translators: 1: function name, 2: WordPress version number */
-               $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
-       }
-
-       header( sprintf( 'X-WP-DeprecatedParam: %s', $string ) );
-}
-
-/**
- * Sends Cross-Origin Resource Sharing headers with API requests.
- *
- * @since 4.4.0
- *
- * @param mixed $value Response data.
- * @return mixed Response data.
- */
-function rest_send_cors_headers( $value ) {
-       $origin = get_http_origin();
-
-       if ( $origin ) {
-               header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
-               header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
-               header( 'Access-Control-Allow-Credentials: true' );
-       }
-
-       return $value;
-}
-
-/**
- * Handles OPTIONS requests for the server.
- *
- * This is handled outside of the server code, as it doesn't obey normal route
- * mapping.
- *
- * @since 4.4.0
- *
- * @param mixed           $response Current response, either response or `null` to indicate pass-through.
- * @param WP_REST_Server  $handler  ResponseHandler instance (usually WP_REST_Server).
- * @param WP_REST_Request $request  The request that was used to make current response.
- * @return WP_REST_Response Modified response, either response or `null` to indicate pass-through.
- */
-function rest_handle_options_request( $response, $handler, $request ) {
-       if ( ! empty( $response ) || $request->get_method() !== 'OPTIONS' ) {
-               return $response;
-       }
-
-       $response = new WP_REST_Response();
-       $data = array();
-
-       $accept = array();
-
-       foreach ( $handler->get_routes() as $route => $endpoints ) {
-               $match = preg_match( '@^' . $route . '$@i', $request->get_route(), $args );
-
-               if ( ! $match ) {
-                       continue;
-               }
-
-               $data = $handler->get_data_for_route( $route, $endpoints, 'help' );
-               $accept = array_merge( $accept, $data['methods'] );
-               break;
-       }
-       $response->header( 'Accept', implode( ', ', $accept ) );
-
-       $response->set_data( $data );
-       return $response;
-}
-
-/**
- * Sends the "Allow" header to state all methods that can be sent to the current route.
- *
- * @since 4.4.0
- *
- * @param WP_REST_Response $response Current response being served.
- * @param WP_REST_Server   $server   ResponseHandler instance (usually WP_REST_Server).
- * @param WP_REST_Request  $request  The request that was used to make current response.
- * @return WP_REST_Response Response to be served, with "Allow" header if route has allowed methods.
- */
-function rest_send_allow_header( $response, $server, $request ) {
-       $matched_route = $response->get_matched_route();
-
-       if ( ! $matched_route ) {
-               return $response;
-       }
-
-       $routes = $server->get_routes();
-
-       $allowed_methods = array();
-
-       // Get the allowed methods across the routes.
-       foreach ( $routes[ $matched_route ] as $_handler ) {
-               foreach ( $_handler['methods'] as $handler_method => $value ) {
-
-                       if ( ! empty( $_handler['permission_callback'] ) ) {
-
-                               $permission = call_user_func( $_handler['permission_callback'], $request );
-
-                               $allowed_methods[ $handler_method ] = true === $permission;
-                       } else {
-                               $allowed_methods[ $handler_method ] = true;
-                       }
-               }
-       }
-
-       // Strip out all the methods that are not allowed (false values).
-       $allowed_methods = array_filter( $allowed_methods );
-
-       if ( $allowed_methods ) {
-               $response->header( 'Allow', implode( ', ', array_map( 'strtoupper', array_keys( $allowed_methods ) ) ) );
-       }
-
-       return $response;
-}
-
-/**
- * Adds the REST API URL to the WP RSD endpoint.
- *
- * @since 4.4.0
- *
- * @see get_rest_url()
- */
-function rest_output_rsd() {
-       $api_root = get_rest_url();
-
-       if ( empty( $api_root ) ) {
-               return;
-       }
-       ?>
-       <api name="WP-API" blogID="1" preferred="false" apiLink="<?php echo esc_url( $api_root ); ?>" />
-       <?php
-}
-
-/**
- * Outputs the REST API link tag into page header.
- *
- * @since 4.4.0
- *
- * @see get_rest_url()
- */
-function rest_output_link_wp_head() {
-       $api_root = get_rest_url();
-
-       if ( empty( $api_root ) ) {
-               return;
-       }
-
-       echo "<link rel='https://api.w.org/' href='" . esc_url( $api_root ) . "' />\n";
-}
-
-/**
- * Sends a Link header for the REST API.
- *
- * @since 4.4.0
- */
-function rest_output_link_header() {
-       if ( headers_sent() ) {
-               return;
-       }
-
-       $api_root = get_rest_url();
-
-       if ( empty( $api_root ) ) {
-               return;
-       }
-
-       header( 'Link: <' . esc_url_raw( $api_root ) . '>; rel="https://api.w.org/"', false );
-}
-
-/**
- * Checks for errors when using cookie-based authentication.
- *
- * WordPress' built-in cookie authentication is always active
- * for logged in users. However, the API has to check nonces
- * for each request to ensure users are not vulnerable to CSRF.
- *
- * @since 4.4.0
- *
- * @global mixed $wp_rest_auth_cookie
- *
- * @param WP_Error|mixed $result Error from another authentication handler, null if we should handle it,
- *                               or another value if not.
- * @return WP_Error|mixed|bool WP_Error if the cookie is invalid, the $result, otherwise true.
- */
-function rest_cookie_check_errors( $result ) {
-       if ( ! empty( $result ) ) {
-               return $result;
-       }
-
-       global $wp_rest_auth_cookie;
-
-       /*
-        * Is cookie authentication being used? (If we get an auth
-        * error, but we're still logged in, another authentication
-        * must have been used).
-        */
-       if ( true !== $wp_rest_auth_cookie && is_user_logged_in() ) {
-               return $result;
-       }
-
-       // Determine if there is a nonce.
-       $nonce = null;
-
-       if ( isset( $_REQUEST['_wpnonce'] ) ) {
-               $nonce = $_REQUEST['_wpnonce'];
-       } elseif ( isset( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
-               $nonce = $_SERVER['HTTP_X_WP_NONCE'];
-       }
-
-       if ( null === $nonce ) {
-               // No nonce at all, so act as if it's an unauthenticated request.
-               wp_set_current_user( 0 );
-               return true;
-       }
-
-       // Check the nonce.
-       $result = wp_verify_nonce( $nonce, 'wp_rest' );
-
-       if ( ! $result ) {
-               return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie nonce is invalid' ), array( 'status' => 403 ) );
-       }
-
-       return true;
-}
-
-/**
- * Collects cookie authentication status.
- *
- * Collects errors from wp_validate_auth_cookie for use by rest_cookie_check_errors.
- *
- * @since 4.4.0
- *
- * @see current_action()
- * @global mixed $wp_rest_auth_cookie
- */
-function rest_cookie_collect_status() {
-       global $wp_rest_auth_cookie;
-
-       $status_type = current_action();
-
-       if ( 'auth_cookie_valid' !== $status_type ) {
-               $wp_rest_auth_cookie = substr( $status_type, 12 );
-               return;
-       }
-
-       $wp_rest_auth_cookie = true;
-}
-
-/**
- * Parses an RFC3339 timestamp into a DateTime.
- *
- * @since 4.4.0
- *
- * @param string $date      RFC3339 timestamp.
- * @param bool   $force_utc Optional. Whether to force UTC timezone instead of using
- *                          the timestamp's timezone. Default false.
- * @return DateTime DateTime instance.
- */
-function rest_parse_date( $date, $force_utc = false ) {
-       if ( $force_utc ) {
-               $date = preg_replace( '/[+-]\d+:?\d+$/', '+00:00', $date );
-       }
-
-       $regex = '#^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::\d{2})?)?$#';
-
-       if ( ! preg_match( $regex, $date, $matches ) ) {
-               return false;
-       }
-
-       return strtotime( $date );
-}
-
-/**
- * Retrieves a local date with its GMT equivalent, in MySQL datetime format.
- *
- * @since 4.4.0
- *
- * @see rest_parse_date()
- *
- * @param string $date      RFC3339 timestamp.
- * @param bool   $force_utc Whether a UTC timestamp should be forced. Default false.
- * @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
- *                    null on failure.
- */
-function rest_get_date_with_gmt( $date, $force_utc = false ) {
-       $date = rest_parse_date( $date, $force_utc );
-
-       if ( empty( $date ) ) {
-               return null;
-       }
-
-       $utc = date( 'Y-m-d H:i:s', $date );
-       $local = get_date_from_gmt( $utc );
-
-       return array( $local, $utc );
-}
</del></span></pre></div>
<a id="trunksrcwpincludesrestapiphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/rest-api.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api.php        2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/rest-api.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,26 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * REST API functions.
- *
- * @package WordPress
- * @subpackage REST_API
- */
-
-/**
- * Version number for our API.
- *
- * @var string
- */
-define( 'REST_API_VERSION', '2.0' );
-
-/** WP_REST_Server class */
-require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
-
-/** WP_REST_Response class */
-require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
-
-/** WP_REST_Request class */
-require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
-
-/** REST functions */
-require_once( ABSPATH . WPINC . '/rest-api/rest-functions.php' );
</del></span></pre></div>
<a id="trunksrcwpincludesrestapiphpfromrev35712trunksrcwpincludesrestapirestfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/rest-api.php (from rev 35712, trunk/src/wp-includes/rest-api/rest-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rest-api.php                                (rev 0)
+++ trunk/src/wp-includes/rest-api.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,650 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * REST API functions.
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 4.4.0
+ */
+
+/**
+ * Version number for our API.
+ *
+ * @var string
+ */
+define( 'REST_API_VERSION', '2.0' );
+
+/**
+ * Registers a REST API route.
+ *
+ * @since 4.4.0
+ *
+ * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
+ *
+ * @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
+ * @param string $route     The base URL for route you are adding.
+ * @param array  $args      Optional. Either an array of options for the endpoint, or an array of arrays for
+ *                          multiple methods. Default empty array.
+ * @param bool   $override  Optional. If the route already exists, should we override it? True overrides,
+ *                          false merges (with newer overriding if duplicate keys exist). Default false.
+ * @return bool True on success, false on error.
+ */
+function register_rest_route( $namespace, $route, $args = array(), $override = false ) {
+       /** @var WP_REST_Server $wp_rest_server */
+       global $wp_rest_server;
+
+       if ( empty( $namespace ) ) {
+               /*
+                * Non-namespaced routes are not allowed, with the exception of the main
+                * and namespace indexes. If you really need to register a
+                * non-namespaced route, call `WP_REST_Server::register_route` directly.
+                */
+               _doing_it_wrong( 'register_rest_route', 'Routes must be namespaced with plugin or theme name and version.', '4.4.0' );
+               return false;
+       } else if ( empty( $route ) ) {
+               _doing_it_wrong( 'register_rest_route', 'Route must be specified.', '4.4.0' );
+               return false;
+       }
+
+       if ( isset( $args['callback'] ) ) {
+               // Upgrade a single set to multiple.
+               $args = array( $args );
+       }
+
+       $defaults = array(
+               'methods'         => 'GET',
+               'callback'        => null,
+               'args'            => array(),
+       );
+       foreach ( $args as $key => &$arg_group ) {
+               if ( ! is_numeric( $arg_group ) ) {
+                       // Route option, skip here.
+                       continue;
+               }
+
+               $arg_group = array_merge( $defaults, $arg_group );
+       }
+
+       $full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
+       $wp_rest_server->register_route( $namespace, $full_route, $args, $override );
+       return true;
+}
+
+/**
+ * Registers rewrite rules for the API.
+ *
+ * @since 4.4.0
+ *
+ * @see rest_api_register_rewrites()
+ * @global WP $wp Current WordPress environment instance.
+ */
+function rest_api_init() {
+       rest_api_register_rewrites();
+
+       global $wp;
+       $wp->add_query_var( 'rest_route' );
+}
+
+/**
+ * Adds REST rewrite rules.
+ *
+ * @since 4.4.0
+ *
+ * @see add_rewrite_rule()
+ */
+function rest_api_register_rewrites() {
+       add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
+       add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
+}
+
+/**
+ * Registers the default REST API filters.
+ *
+ * Attached to the {@see 'rest_api_init'} action
+ * to make testing and disabling these filters easier.
+ *
+ * @since 4.4.0
+ */
+function rest_api_default_filters() {
+       // Deprecated reporting.
+       add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
+       add_filter( 'deprecated_function_trigger_error', '__return_false' );
+       add_action( 'deprecated_argument_run', 'rest_handle_deprecated_argument', 10, 3 );
+       add_filter( 'deprecated_argument_trigger_error', '__return_false' );
+
+       // Default serving.
+       add_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
+       add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
+
+       add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
+}
+
+/**
+ * Loads the REST API.
+ *
+ * @since 4.4.0
+ *
+ * @global WP             $wp             Current WordPress environment instance.
+ * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
+ */
+function rest_api_loaded() {
+       if ( empty( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
+               return;
+       }
+
+       /**
+        * Whether this is a REST Request.
+        *
+        * @since 4.4.0
+        * @var bool
+        */
+       define( 'REST_REQUEST', true );
+
+       /** @var WP_REST_Server $wp_rest_server */
+       global $wp_rest_server;
+
+       /**
+        * Filter the REST Server Class.
+        *
+        * This filter allows you to adjust the server class used by the API, using a
+        * different class to handle requests.
+        *
+        * @since 4.4.0
+        *
+        * @param string $class_name The name of the server class. Default 'WP_REST_Server'.
+        */
+       $wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
+       $wp_rest_server = new $wp_rest_server_class;
+
+       /**
+        * Fires when preparing to serve an API request.
+        *
+        * Endpoint objects should be created and register their hooks on this action rather
+        * than another action to ensure they're only loaded when needed.
+        *
+        * @since 4.4.0
+        *
+        * @param WP_REST_Server $wp_rest_server Server object.
+        */
+       do_action( 'rest_api_init', $wp_rest_server );
+
+       // Fire off the request.
+       $wp_rest_server->serve_request( $GLOBALS['wp']->query_vars['rest_route'] );
+
+       // We're done.
+       die();
+}
+
+/**
+ * Retrieves the URL prefix for any API resource.
+ *
+ * @since 4.4.0
+ *
+ * @return string Prefix.
+ */
+function rest_get_url_prefix() {
+       /**
+        * Filter the REST URL prefix.
+        *
+        * @since 4.4.0
+        *
+        * @param string $prefix URL prefix. Default 'wp-json'.
+        */
+       return apply_filters( 'rest_url_prefix', 'wp-json' );
+}
+
+/**
+ * Retrieves the URL to a REST endpoint on a site.
+ *
+ * Note: The returned URL is NOT escaped.
+ *
+ * @since 4.4.0
+ *
+ * @todo Check if this is even necessary
+ *
+ * @param int    $blog_id Optional. Blog ID. Default of null returns URL for current blog.
+ * @param string $path    Optional. REST route. Default '/'.
+ * @param string $scheme  Optional. Sanitization scheme. Default 'rest'.
+ * @return string Full URL to the endpoint.
+ */
+function get_rest_url( $blog_id = null, $path = '/', $scheme = 'rest' ) {
+       if ( empty( $path ) ) {
+               $path = '/';
+       }
+
+       if ( is_multisite() && get_blog_option( $blog_id, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) {
+               $url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
+               $url .= '/' . ltrim( $path, '/' );
+       } else {
+               $url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
+
+               $path = '/' . ltrim( $path, '/' );
+
+               $url = add_query_arg( 'rest_route', $path, $url );
+       }
+
+       if ( is_ssl() ) {
+               // If the current host is the same as the REST URL host, force the REST URL scheme to HTTPS.
+               if ( $_SERVER['SERVER_NAME'] === parse_url( get_home_url( $blog_id ), PHP_URL_HOST ) ) {
+                       $url = set_url_scheme( $url, 'https' );
+               }
+       }
+
+       /**
+        * Filter the REST URL.
+        *
+        * Use this filter to adjust the url returned by the `get_rest_url` function.
+        *
+        * @since 4.4.0
+        *
+        * @param string $url     REST URL.
+        * @param string $path    REST route.
+        * @param int    $blog_id Blog ID.
+        * @param string $scheme  Sanitization scheme.
+        */
+       return apply_filters( 'rest_url', $url, $path, $blog_id, $scheme );
+}
+
+/**
+ * Retrieves the URL to a REST endpoint.
+ *
+ * Note: The returned URL is NOT escaped.
+ *
+ * @since 4.4.0
+ *
+ * @param string $path   Optional. REST route. Default empty.
+ * @param string $scheme Optional. Sanitization scheme. Default 'json'.
+ * @return string Full URL to the endpoint.
+ */
+function rest_url( $path = '', $scheme = 'json' ) {
+       return get_rest_url( null, $path, $scheme );
+}
+
+/**
+ * Do a REST request.
+ *
+ * Used primarily to route internal requests through WP_REST_Server.
+ *
+ * @since 4.4.0
+ *
+ * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
+ *
+ * @param WP_REST_Request|string $request Request.
+ * @return WP_REST_Response REST response.
+ */
+function rest_do_request( $request ) {
+       global $wp_rest_server;
+       $request = rest_ensure_request( $request );
+       return $wp_rest_server->dispatch( $request );
+}
+
+/**
+ * Ensures request arguments are a request object (for consistency).
+ *
+ * @since 4.4.0
+ *
+ * @param array|WP_REST_Request $request Request to check.
+ * @return WP_REST_Request REST request instance.
+ */
+function rest_ensure_request( $request ) {
+       if ( $request instanceof WP_REST_Request ) {
+               return $request;
+       }
+
+       return new WP_REST_Request( 'GET', '', $request );
+}
+
+/**
+ * Ensures a REST response is a response object (for consistency).
+ *
+ * This implements WP_HTTP_Response, allowing usage of `set_status`/`header`/etc
+ * without needing to double-check the object. Will also allow WP_Error to indicate error
+ * responses, so users should immediately check for this value.
+ *
+ * @since 4.4.0
+ *
+ * @param WP_Error|WP_HTTP_Response|mixed $response Response to check.
+ * @return mixed WP_Error if response generated an error, WP_HTTP_Response if response
+ *               is a already an instance, otherwise returns a new WP_REST_Response instance.
+ */
+function rest_ensure_response( $response ) {
+       if ( is_wp_error( $response ) ) {
+               return $response;
+       }
+
+       if ( $response instanceof WP_HTTP_Response ) {
+               return $response;
+       }
+
+       return new WP_REST_Response( $response );
+}
+
+/**
+ * Handles _deprecated_function() errors.
+ *
+ * @since 4.4.0
+ *
+ * @param string $function    Function name.
+ * @param string $replacement Replacement function name.
+ * @param string $version     Version.
+ */
+function rest_handle_deprecated_function( $function, $replacement, $version ) {
+       if ( ! empty( $replacement ) ) {
+               /* translators: 1: function name, 2: WordPress version number, 3: new function name */
+               $string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function, $version, $replacement );
+       } else {
+               /* translators: 1: function name, 2: WordPress version number */
+               $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
+       }
+
+       header( sprintf( 'X-WP-DeprecatedFunction: %s', $string ) );
+}
+
+/**
+ * Handles _deprecated_argument() errors.
+ *
+ * @since 4.4.0
+ *
+ * @param string $function    Function name.
+ * @param string $replacement Replacement function name.
+ * @param string $version     Version.
+ */
+function rest_handle_deprecated_argument( $function, $replacement, $version ) {
+       if ( ! empty( $replacement ) ) {
+               /* translators: 1: function name, 2: WordPress version number, 3: new argument name */
+               $string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function, $version, $replacement );
+       } else {
+               /* translators: 1: function name, 2: WordPress version number */
+               $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
+       }
+
+       header( sprintf( 'X-WP-DeprecatedParam: %s', $string ) );
+}
+
+/**
+ * Sends Cross-Origin Resource Sharing headers with API requests.
+ *
+ * @since 4.4.0
+ *
+ * @param mixed $value Response data.
+ * @return mixed Response data.
+ */
+function rest_send_cors_headers( $value ) {
+       $origin = get_http_origin();
+
+       if ( $origin ) {
+               header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
+               header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
+               header( 'Access-Control-Allow-Credentials: true' );
+       }
+
+       return $value;
+}
+
+/**
+ * Handles OPTIONS requests for the server.
+ *
+ * This is handled outside of the server code, as it doesn't obey normal route
+ * mapping.
+ *
+ * @since 4.4.0
+ *
+ * @param mixed           $response Current response, either response or `null` to indicate pass-through.
+ * @param WP_REST_Server  $handler  ResponseHandler instance (usually WP_REST_Server).
+ * @param WP_REST_Request $request  The request that was used to make current response.
+ * @return WP_REST_Response Modified response, either response or `null` to indicate pass-through.
+ */
+function rest_handle_options_request( $response, $handler, $request ) {
+       if ( ! empty( $response ) || $request->get_method() !== 'OPTIONS' ) {
+               return $response;
+       }
+
+       $response = new WP_REST_Response();
+       $data = array();
+
+       $accept = array();
+
+       foreach ( $handler->get_routes() as $route => $endpoints ) {
+               $match = preg_match( '@^' . $route . '$@i', $request->get_route(), $args );
+
+               if ( ! $match ) {
+                       continue;
+               }
+
+               $data = $handler->get_data_for_route( $route, $endpoints, 'help' );
+               $accept = array_merge( $accept, $data['methods'] );
+               break;
+       }
+       $response->header( 'Accept', implode( ', ', $accept ) );
+
+       $response->set_data( $data );
+       return $response;
+}
+
+/**
+ * Sends the "Allow" header to state all methods that can be sent to the current route.
+ *
+ * @since 4.4.0
+ *
+ * @param WP_REST_Response $response Current response being served.
+ * @param WP_REST_Server   $server   ResponseHandler instance (usually WP_REST_Server).
+ * @param WP_REST_Request  $request  The request that was used to make current response.
+ * @return WP_REST_Response Response to be served, with "Allow" header if route has allowed methods.
+ */
+function rest_send_allow_header( $response, $server, $request ) {
+       $matched_route = $response->get_matched_route();
+
+       if ( ! $matched_route ) {
+               return $response;
+       }
+
+       $routes = $server->get_routes();
+
+       $allowed_methods = array();
+
+       // Get the allowed methods across the routes.
+       foreach ( $routes[ $matched_route ] as $_handler ) {
+               foreach ( $_handler['methods'] as $handler_method => $value ) {
+
+                       if ( ! empty( $_handler['permission_callback'] ) ) {
+
+                               $permission = call_user_func( $_handler['permission_callback'], $request );
+
+                               $allowed_methods[ $handler_method ] = true === $permission;
+                       } else {
+                               $allowed_methods[ $handler_method ] = true;
+                       }
+               }
+       }
+
+       // Strip out all the methods that are not allowed (false values).
+       $allowed_methods = array_filter( $allowed_methods );
+
+       if ( $allowed_methods ) {
+               $response->header( 'Allow', implode( ', ', array_map( 'strtoupper', array_keys( $allowed_methods ) ) ) );
+       }
+
+       return $response;
+}
+
+/**
+ * Adds the REST API URL to the WP RSD endpoint.
+ *
+ * @since 4.4.0
+ *
+ * @see get_rest_url()
+ */
+function rest_output_rsd() {
+       $api_root = get_rest_url();
+
+       if ( empty( $api_root ) ) {
+               return;
+       }
+       ?>
+       <api name="WP-API" blogID="1" preferred="false" apiLink="<?php echo esc_url( $api_root ); ?>" />
+       <?php
+}
+
+/**
+ * Outputs the REST API link tag into page header.
+ *
+ * @since 4.4.0
+ *
+ * @see get_rest_url()
+ */
+function rest_output_link_wp_head() {
+       $api_root = get_rest_url();
+
+       if ( empty( $api_root ) ) {
+               return;
+       }
+
+       echo "<link rel='https://api.w.org/' href='" . esc_url( $api_root ) . "' />\n";
+}
+
+/**
+ * Sends a Link header for the REST API.
+ *
+ * @since 4.4.0
+ */
+function rest_output_link_header() {
+       if ( headers_sent() ) {
+               return;
+       }
+
+       $api_root = get_rest_url();
+
+       if ( empty( $api_root ) ) {
+               return;
+       }
+
+       header( 'Link: <' . esc_url_raw( $api_root ) . '>; rel="https://api.w.org/"', false );
+}
+
+/**
+ * Checks for errors when using cookie-based authentication.
+ *
+ * WordPress' built-in cookie authentication is always active
+ * for logged in users. However, the API has to check nonces
+ * for each request to ensure users are not vulnerable to CSRF.
+ *
+ * @since 4.4.0
+ *
+ * @global mixed $wp_rest_auth_cookie
+ *
+ * @param WP_Error|mixed $result Error from another authentication handler, null if we should handle it,
+ *                               or another value if not.
+ * @return WP_Error|mixed|bool WP_Error if the cookie is invalid, the $result, otherwise true.
+ */
+function rest_cookie_check_errors( $result ) {
+       if ( ! empty( $result ) ) {
+               return $result;
+       }
+
+       global $wp_rest_auth_cookie;
+
+       /*
+        * Is cookie authentication being used? (If we get an auth
+        * error, but we're still logged in, another authentication
+        * must have been used).
+        */
+       if ( true !== $wp_rest_auth_cookie && is_user_logged_in() ) {
+               return $result;
+       }
+
+       // Determine if there is a nonce.
+       $nonce = null;
+
+       if ( isset( $_REQUEST['_wpnonce'] ) ) {
+               $nonce = $_REQUEST['_wpnonce'];
+       } elseif ( isset( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
+               $nonce = $_SERVER['HTTP_X_WP_NONCE'];
+       }
+
+       if ( null === $nonce ) {
+               // No nonce at all, so act as if it's an unauthenticated request.
+               wp_set_current_user( 0 );
+               return true;
+       }
+
+       // Check the nonce.
+       $result = wp_verify_nonce( $nonce, 'wp_rest' );
+
+       if ( ! $result ) {
+               return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie nonce is invalid' ), array( 'status' => 403 ) );
+       }
+
+       return true;
+}
+
+/**
+ * Collects cookie authentication status.
+ *
+ * Collects errors from wp_validate_auth_cookie for use by rest_cookie_check_errors.
+ *
+ * @since 4.4.0
+ *
+ * @see current_action()
+ * @global mixed $wp_rest_auth_cookie
+ */
+function rest_cookie_collect_status() {
+       global $wp_rest_auth_cookie;
+
+       $status_type = current_action();
+
+       if ( 'auth_cookie_valid' !== $status_type ) {
+               $wp_rest_auth_cookie = substr( $status_type, 12 );
+               return;
+       }
+
+       $wp_rest_auth_cookie = true;
+}
+
+/**
+ * Parses an RFC3339 timestamp into a DateTime.
+ *
+ * @since 4.4.0
+ *
+ * @param string $date      RFC3339 timestamp.
+ * @param bool   $force_utc Optional. Whether to force UTC timezone instead of using
+ *                          the timestamp's timezone. Default false.
+ * @return DateTime DateTime instance.
+ */
+function rest_parse_date( $date, $force_utc = false ) {
+       if ( $force_utc ) {
+               $date = preg_replace( '/[+-]\d+:?\d+$/', '+00:00', $date );
+       }
+
+       $regex = '#^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::\d{2})?)?$#';
+
+       if ( ! preg_match( $regex, $date, $matches ) ) {
+               return false;
+       }
+
+       return strtotime( $date );
+}
+
+/**
+ * Retrieves a local date with its GMT equivalent, in MySQL datetime format.
+ *
+ * @since 4.4.0
+ *
+ * @see rest_parse_date()
+ *
+ * @param string $date      RFC3339 timestamp.
+ * @param bool   $force_utc Whether a UTC timestamp should be forced. Default false.
+ * @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
+ *                    null on failure.
+ */
+function rest_get_date_with_gmt( $date, $force_utc = false ) {
+       $date = rest_parse_date( $date, $force_utc );
+
+       if ( empty( $date ) ) {
+               return null;
+       }
+
+       $utc = date( 'Y-m-d H:i:s', $date );
+       $local = get_date_from_gmt( $utc );
+
+       return array( $local, $utc );
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesrewriteconstantsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/rewrite-constants.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rewrite-constants.php       2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/rewrite-constants.php 2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,120 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Rewrite API: Constants
- *
- * @package WordPress
- * @subpackage Rewrite
- * @since 4.4.0
- */
-
-/**
- * Endpoint Mask for default, which is nothing.
- *
- * @since 2.1.0
- */
-define('EP_NONE', 0);
-
-/**
- * Endpoint Mask for Permalink.
- *
- * @since 2.1.0
- */
-define('EP_PERMALINK', 1);
-
-/**
- * Endpoint Mask for Attachment.
- *
- * @since 2.1.0
- */
-define('EP_ATTACHMENT', 2);
-
-/**
- * Endpoint Mask for date.
- *
- * @since 2.1.0
- */
-define('EP_DATE', 4);
-
-/**
- * Endpoint Mask for year
- *
- * @since 2.1.0
- */
-define('EP_YEAR', 8);
-
-/**
- * Endpoint Mask for month.
- *
- * @since 2.1.0
- */
-define('EP_MONTH', 16);
-
-/**
- * Endpoint Mask for day.
- *
- * @since 2.1.0
- */
-define('EP_DAY', 32);
-
-/**
- * Endpoint Mask for root.
- *
- * @since 2.1.0
- */
-define('EP_ROOT', 64);
-
-/**
- * Endpoint Mask for comments.
- *
- * @since 2.1.0
- */
-define('EP_COMMENTS', 128);
-
-/**
- * Endpoint Mask for searches.
- *
- * @since 2.1.0
- */
-define('EP_SEARCH', 256);
-
-/**
- * Endpoint Mask for categories.
- *
- * @since 2.1.0
- */
-define('EP_CATEGORIES', 512);
-
-/**
- * Endpoint Mask for tags.
- *
- * @since 2.3.0
- */
-define('EP_TAGS', 1024);
-
-/**
- * Endpoint Mask for authors.
- *
- * @since 2.1.0
- */
-define('EP_AUTHORS', 2048);
-
-/**
- * Endpoint Mask for pages.
- *
- * @since 2.1.0
- */
-define('EP_PAGES', 4096);
-
-/**
- * Endpoint Mask for all archive views.
- *
- * @since 3.7.0
- */
-define( 'EP_ALL_ARCHIVES', EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS );
-
-/**
- * Endpoint Mask for everything.
- *
- * @since 2.1.0
- */
-define( 'EP_ALL', EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES );
</del></span></pre></div>
<a id="trunksrcwpincludesrewritefunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/rewrite-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rewrite-functions.php       2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/rewrite-functions.php 2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,445 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * WordPress Rewrite API
- *
- * @package WordPress
- * @subpackage Rewrite
- */
-
-/**
- * Adds a rewrite rule that transforms a URL structure to a set of query vars.
- *
- * Any value in the $after parameter that isn't 'bottom' will result in the rule
- * being placed at the top of the rewrite rules.
- *
- * @since 2.1.0
- * @since 4.4.0 Array support was added to the `$query` parameter.
- *
- * @global WP_Rewrite $wp_rewrite WordPress Rewrite Component.
- *
- * @param string       $regex Regular expression to match request against.
- * @param string|array $query The corresponding query vars for this rewrite rule.
- * @param string       $after Optional. Priority of the new rule. Accepts 'top'
- *                            or 'bottom'. Default 'bottom'.
- */
-function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
-       global $wp_rewrite;
-
-       $wp_rewrite->add_rule( $regex, $query, $after );
-}
-
-/**
- * Add a new rewrite tag (like %postname%).
- *
- * The $query parameter is optional. If it is omitted you must ensure that
- * you call this on, or before, the 'init' hook. This is because $query defaults
- * to "$tag=", and for this to work a new query var has to be added.
- *
- * @since 2.1.0
- *
- * @global WP_Rewrite $wp_rewrite
- * @global WP         $wp
- *
- * @param string $tag   Name of the new rewrite tag.
- * @param string $regex Regular expression to substitute the tag for in rewrite rules.
- * @param string $query Optional. String to append to the rewritten query. Must end in '='. Default empty.
- */
-function add_rewrite_tag( $tag, $regex, $query = '' ) {
-       // validate the tag's name
-       if ( strlen( $tag ) < 3 || $tag[0] != '%' || $tag[ strlen($tag) - 1 ] != '%' )
-               return;
-
-       global $wp_rewrite, $wp;
-
-       if ( empty( $query ) ) {
-               $qv = trim( $tag, '%' );
-               $wp->add_query_var( $qv );
-               $query = $qv . '=';
-       }
-
-       $wp_rewrite->add_rewrite_tag( $tag, $regex, $query );
-}
-
-/**
- * Add permalink structure.
- *
- * @since 3.0.0
- *
- * @see WP_Rewrite::add_permastruct()
- * @global WP_Rewrite $wp_rewrite
- *
- * @param string $name   Name for permalink structure.
- * @param string $struct Permalink structure.
- * @param array  $args   Optional. Arguments for building the rules from the permalink structure,
- *                       see WP_Rewrite::add_permastruct() for full details. Default empty array.
- */
-function add_permastruct( $name, $struct, $args = array() ) {
-       global $wp_rewrite;
-
-       // backwards compatibility for the old parameters: $with_front and $ep_mask
-       if ( ! is_array( $args ) )
-               $args = array( 'with_front' => $args );
-       if ( func_num_args() == 4 )
-               $args['ep_mask'] = func_get_arg( 3 );
-
-       $wp_rewrite->add_permastruct( $name, $struct, $args );
-}
-
-/**
- * Add a new feed type like /atom1/.
- *
- * @since 2.1.0
- *
- * @global WP_Rewrite $wp_rewrite
- *
- * @param string   $feedname Feed name.
- * @param callable $function Callback to run on feed display.
- * @return string Feed action name.
- */
-function add_feed( $feedname, $function ) {
-       global $wp_rewrite;
-
-       if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
-               $wp_rewrite->feeds[] = $feedname;
-       }
-
-       $hook = 'do_feed_' . $feedname;
-
-       // Remove default function hook
-       remove_action( $hook, $hook );
-
-       add_action( $hook, $function, 10, 2 );
-
-       return $hook;
-}
-
-/**
- * Remove rewrite rules and then recreate rewrite rules.
- *
- * @since 3.0.0
- *
- * @global WP_Rewrite $wp_rewrite
- *
- * @param bool $hard Whether to update .htaccess (hard flush) or just update
- *                      rewrite_rules transient (soft flush). Default is true (hard).
- */
-function flush_rewrite_rules( $hard = true ) {
-       global $wp_rewrite;
-       $wp_rewrite->flush_rules( $hard );
-}
-
-/**
- * Add an endpoint, like /trackback/.
- *
- * Adding an endpoint creates extra rewrite rules for each of the matching
- * places specified by the provided bitmask. For example:
- *
- *     add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );
- *
- * will add a new rewrite rule ending with "json(/(.*))?/?$" for every permastruct
- * that describes a permalink (post) or page. This is rewritten to "json=$match"
- * where $match is the part of the URL matched by the endpoint regex (e.g. "foo" in
- * "[permalink]/json/foo/").
- *
- * A new query var with the same name as the endpoint will also be created.
- *
- * When specifying $places ensure that you are using the EP_* constants (or a
- * combination of them using the bitwise OR operator) as their values are not
- * guaranteed to remain static (especially `EP_ALL`).
- *
- * Be sure to flush the rewrite rules - see flush_rewrite_rules() - when your plugin gets
- * activated and deactivated.
- *
- * @since 2.1.0
- * @since 4.3.0 Added support for skipping query var registration by passing `false` to `$query_var`.
- *
- * @global WP_Rewrite $wp_rewrite
- *
- * @param string      $name      Name of the endpoint.
- * @param int         $places    Endpoint mask describing the places the endpoint should be added.
- * @param string|bool $query_var Name of the corresponding query variable. Pass `false` to skip registering a query_var
- *                               for this endpoint. Defaults to the value of `$name`.
- */
-function add_rewrite_endpoint( $name, $places, $query_var = true ) {
-       global $wp_rewrite;
-       $wp_rewrite->add_endpoint( $name, $places, $query_var );
-}
-
-/**
- * Filter the URL base for taxonomies.
- *
- * To remove any manually prepended /index.php/.
- *
- * @access private
- * @since 2.6.0
- *
- * @param string $base The taxonomy base that we're going to filter
- * @return string
- */
-function _wp_filter_taxonomy_base( $base ) {
-       if ( !empty( $base ) ) {
-               $base = preg_replace( '|^/index\.php/|', '', $base );
-               $base = trim( $base, '/' );
-       }
-       return $base;
-}
-
-
-/**
- * Resolve numeric slugs that collide with date permalinks.
- *
- * Permalinks of posts with numeric slugs can sometimes look to WP_Query::parse_query()
- * like a date archive, as when your permalink structure is `/%year%/%postname%/` and
- * a post with post_name '05' has the URL `/2015/05/`.
- *
- * This function detects conflicts of this type and resolves them in favor of the
- * post permalink.
- *
- * Note that, since 4.3.0, wp_unique_post_slug() prevents the creation of post slugs
- * that would result in a date archive conflict. The resolution performed in this
- * function is primarily for legacy content, as well as cases when the admin has changed
- * the site's permalink structure in a way that introduces URL conflicts.
- *
- * @since 4.3.0
- *
- * @param array $query_vars Optional. Query variables for setting up the loop, as determined in
- *                          WP::parse_request(). Default empty array.
- * @return array Returns the original array of query vars, with date/post conflicts resolved.
- */
-function wp_resolve_numeric_slug_conflicts( $query_vars = array() ) {
-       if ( ! isset( $query_vars['year'] ) && ! isset( $query_vars['monthnum'] ) && ! isset( $query_vars['day'] ) ) {
-               return $query_vars;
-       }
-
-       // Identify the 'postname' position in the permastruct array.
-       $permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
-       $postname_index = array_search( '%postname%', $permastructs );
-
-       if ( false === $postname_index ) {
-               return $query_vars;
-       }
-
-       /*
-        * A numeric slug could be confused with a year, month, or day, depending on position. To account for
-        * the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our
-        * `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check
-        * for month-slug clashes when `is_month` *or* `is_day`.
-        */
-       $compare = '';
-       if ( 0 === $postname_index && ( isset( $query_vars['year'] ) || isset( $query_vars['monthnum'] ) ) ) {
-               $compare = 'year';
-       } elseif ( '%year%' === $permastructs[ $postname_index - 1 ] && ( isset( $query_vars['monthnum'] ) || isset( $query_vars['day'] ) ) ) {
-               $compare = 'monthnum';
-       } elseif ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && isset( $query_vars['day'] ) ) {
-               $compare = 'day';
-       }
-
-       if ( ! $compare ) {
-               return $query_vars;
-       }
-
-       // This is the potentially clashing slug.
-       $value = $query_vars[ $compare ];
-
-       $post = get_page_by_path( $value, OBJECT, 'post' );
-       if ( ! ( $post instanceof WP_Post ) ) {
-               return $query_vars;
-       }
-
-       // If the date of the post doesn't match the date specified in the URL, resolve to the date archive.
-       if ( preg_match( '/^([0-9]{4})\-([0-9]{2})/', $post->post_date, $matches ) && isset( $query_vars['year'] ) && ( 'monthnum' === $compare || 'day' === $compare ) ) {
-               // $matches[1] is the year the post was published.
-               if ( intval( $query_vars['year'] ) !== intval( $matches[1] ) ) {
-                       return $query_vars;
-               }
-
-               // $matches[2] is the month the post was published.
-               if ( 'day' === $compare && isset( $query_vars['monthnum'] ) && intval( $query_vars['monthnum'] ) !== intval( $matches[2] ) ) {
-                       return $query_vars;
-               }
-       }
-
-       /*
-        * If the located post contains nextpage pagination, then the URL chunk following postname may be
-        * intended as the page number. Verify that it's a valid page before resolving to it.
-        */
-       $maybe_page = '';
-       if ( 'year' === $compare && isset( $query_vars['monthnum'] ) ) {
-               $maybe_page = $query_vars['monthnum'];
-       } elseif ( 'monthnum' === $compare && isset( $query_vars['day'] ) ) {
-               $maybe_page = $query_vars['day'];
-       }
-       // Bug found in #11694 - 'page' was returning '/4'
-       $maybe_page = (int) trim( $maybe_page, '/' );
-
-       $post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1;
-
-       // If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive.
-       if ( 1 === $post_page_count && $maybe_page ) {
-               return $query_vars;
-       }
-
-       // If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive.
-       if ( $post_page_count > 1 && $maybe_page > $post_page_count ) {
-               return $query_vars;
-       }
-
-       // If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage.
-       if ( '' !== $maybe_page ) {
-               $query_vars['page'] = intval( $maybe_page );
-       }
-
-       // Next, unset autodetected date-related query vars.
-       unset( $query_vars['year'] );
-       unset( $query_vars['monthnum'] );
-       unset( $query_vars['day'] );
-
-       // Then, set the identified post.
-       $query_vars['name'] = $post->post_name;
-
-       // Finally, return the modified query vars.
-       return $query_vars;
-}
-
-/**
- * Examine a url and try to determine the post ID it represents.
- *
- * Checks are supposedly from the hosted site blog.
- *
- * @since 1.0.0
- *
- * @global WP_Rewrite $wp_rewrite
- * @global WP         $wp
- *
- * @param string $url Permalink to check.
- * @return int Post ID, or 0 on failure.
- */
-function url_to_postid( $url ) {
-       global $wp_rewrite;
-
-       /**
-        * Filter the URL to derive the post ID from.
-        *
-        * @since 2.2.0
-        *
-        * @param string $url The URL to derive the post ID from.
-        */
-       $url = apply_filters( 'url_to_postid', $url );
-
-       // First, check to see if there is a 'p=N' or 'page_id=N' to match against
-       if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) )   {
-               $id = absint($values[2]);
-               if ( $id )
-                       return $id;
-       }
-
-       // Check to see if we are using rewrite rules
-       $rewrite = $wp_rewrite->wp_rewrite_rules();
-
-       // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
-       if ( empty($rewrite) )
-               return 0;
-
-       // Get rid of the #anchor
-       $url_split = explode('#', $url);
-       $url = $url_split[0];
-
-       // Get rid of URL ?query=string
-       $url_split = explode('?', $url);
-       $url = $url_split[0];
-
-       // Set the correct URL scheme.
-       $url = set_url_scheme( $url );
-
-       // Add 'www.' if it is absent and should be there
-       if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
-               $url = str_replace('://', '://www.', $url);
-
-       // Strip 'www.' if it is present and shouldn't be
-       if ( false === strpos(home_url(), '://www.') )
-               $url = str_replace('://www.', '://', $url);
-
-       // Strip 'index.php/' if we're not using path info permalinks
-       if ( !$wp_rewrite->using_index_permalinks() )
-               $url = str_replace( $wp_rewrite->index . '/', '', $url );
-
-       if ( false !== strpos( trailingslashit( $url ), home_url( '/' ) ) ) {
-               // Chop off http://domain.com/[path]
-               $url = str_replace(home_url(), '', $url);
-       } else {
-               // Chop off /path/to/blog
-               $home_path = parse_url( home_url( '/' ) );
-               $home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
-               $url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( $url ) );
-       }
-
-       // Trim leading and lagging slashes
-       $url = trim($url, '/');
-
-       $request = $url;
-       $post_type_query_vars = array();
-
-       foreach ( get_post_types( array() , 'objects' ) as $post_type => $t ) {
-               if ( ! empty( $t->query_var ) )
-                       $post_type_query_vars[ $t->query_var ] = $post_type;
-       }
-
-       // Look for matches.
-       $request_match = $request;
-       foreach ( (array)$rewrite as $match => $query) {
-
-               // If the requesting file is the anchor of the match, prepend it
-               // to the path info.
-               if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
-                       $request_match = $url . '/' . $request;
-
-               if ( preg_match("#^$match#", $request_match, $matches) ) {
-
-                       if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
-                               // This is a verbose page match, let's check to be sure about it.
-                               $page = get_page_by_path( $matches[ $varmatch[1] ] );
-                               if ( ! $page ) {
-                                       continue;
-                               }
-
-                               $post_status_obj = get_post_status_object( $page->post_status );
-                               if ( ! $post_status_obj->public && ! $post_status_obj->protected
-                                       && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
-                                       continue;
-                               }
-                       }
-
-                       // Got a match.
-                       // Trim the query of everything up to the '?'.
-                       $query = preg_replace("!^.+\?!", '', $query);
-
-                       // Substitute the substring matches into the query.
-                       $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
-
-                       // Filter out non-public query vars
-                       global $wp;
-                       parse_str( $query, $query_vars );
-                       $query = array();
-                       foreach ( (array) $query_vars as $key => $value ) {
-                               if ( in_array( $key, $wp->public_query_vars ) ){
-                                       $query[$key] = $value;
-                                       if ( isset( $post_type_query_vars[$key] ) ) {
-                                               $query['post_type'] = $post_type_query_vars[$key];
-                                               $query['name'] = $value;
-                                       }
-                               }
-                       }
-
-                       // Resolve conflicts between posts with numeric slugs and date archive queries.
-                       $query = wp_resolve_numeric_slug_conflicts( $query );
-
-                       // Do the query
-                       $query = new WP_Query( $query );
-                       if ( ! empty( $query->posts ) && $query->is_singular )
-                               return $query->post->ID;
-                       else
-                               return 0;
-               }
-       }
-       return 0;
-}
</del></span></pre></div>
<a id="trunksrcwpincludesrewritephp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/rewrite.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rewrite.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/rewrite.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,11 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * WordPress Rewrite API
- *
- * @package WordPress
- * @subpackage Rewrite
- */
-
-require_once( ABSPATH . WPINC . '/rewrite-constants.php' );
-require_once( ABSPATH . WPINC . '/rewrite-functions.php' );
-require_once( ABSPATH . WPINC . '/class-wp-rewrite.php' );
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesrewritephpfromrev35712trunksrcwpincludesrewritefunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/rewrite.php (from rev 35712, trunk/src/wp-includes/rewrite-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/rewrite.php                         (rev 0)
+++ trunk/src/wp-includes/rewrite.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,557 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * WordPress Rewrite API
+ *
+ * @package WordPress
+ * @subpackage Rewrite
+ */
+
+/**
+ * Endpoint Mask for default, which is nothing.
+ *
+ * @since 2.1.0
+ */
+define('EP_NONE', 0);
+
+/**
+ * Endpoint Mask for Permalink.
+ *
+ * @since 2.1.0
+ */
+define('EP_PERMALINK', 1);
+
+/**
+ * Endpoint Mask for Attachment.
+ *
+ * @since 2.1.0
+ */
+define('EP_ATTACHMENT', 2);
+
+/**
+ * Endpoint Mask for date.
+ *
+ * @since 2.1.0
+ */
+define('EP_DATE', 4);
+
+/**
+ * Endpoint Mask for year
+ *
+ * @since 2.1.0
+ */
+define('EP_YEAR', 8);
+
+/**
+ * Endpoint Mask for month.
+ *
+ * @since 2.1.0
+ */
+define('EP_MONTH', 16);
+
+/**
+ * Endpoint Mask for day.
+ *
+ * @since 2.1.0
+ */
+define('EP_DAY', 32);
+
+/**
+ * Endpoint Mask for root.
+ *
+ * @since 2.1.0
+ */
+define('EP_ROOT', 64);
+
+/**
+ * Endpoint Mask for comments.
+ *
+ * @since 2.1.0
+ */
+define('EP_COMMENTS', 128);
+
+/**
+ * Endpoint Mask for searches.
+ *
+ * @since 2.1.0
+ */
+define('EP_SEARCH', 256);
+
+/**
+ * Endpoint Mask for categories.
+ *
+ * @since 2.1.0
+ */
+define('EP_CATEGORIES', 512);
+
+/**
+ * Endpoint Mask for tags.
+ *
+ * @since 2.3.0
+ */
+define('EP_TAGS', 1024);
+
+/**
+ * Endpoint Mask for authors.
+ *
+ * @since 2.1.0
+ */
+define('EP_AUTHORS', 2048);
+
+/**
+ * Endpoint Mask for pages.
+ *
+ * @since 2.1.0
+ */
+define('EP_PAGES', 4096);
+
+/**
+ * Endpoint Mask for all archive views.
+ *
+ * @since 3.7.0
+ */
+define( 'EP_ALL_ARCHIVES', EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS );
+
+/**
+ * Endpoint Mask for everything.
+ *
+ * @since 2.1.0
+ */
+define( 'EP_ALL', EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES );
+
+/**
+ * Adds a rewrite rule that transforms a URL structure to a set of query vars.
+ *
+ * Any value in the $after parameter that isn't 'bottom' will result in the rule
+ * being placed at the top of the rewrite rules.
+ *
+ * @since 2.1.0
+ * @since 4.4.0 Array support was added to the `$query` parameter.
+ *
+ * @global WP_Rewrite $wp_rewrite WordPress Rewrite Component.
+ *
+ * @param string       $regex Regular expression to match request against.
+ * @param string|array $query The corresponding query vars for this rewrite rule.
+ * @param string       $after Optional. Priority of the new rule. Accepts 'top'
+ *                            or 'bottom'. Default 'bottom'.
+ */
+function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
+       global $wp_rewrite;
+
+       $wp_rewrite->add_rule( $regex, $query, $after );
+}
+
+/**
+ * Add a new rewrite tag (like %postname%).
+ *
+ * The $query parameter is optional. If it is omitted you must ensure that
+ * you call this on, or before, the 'init' hook. This is because $query defaults
+ * to "$tag=", and for this to work a new query var has to be added.
+ *
+ * @since 2.1.0
+ *
+ * @global WP_Rewrite $wp_rewrite
+ * @global WP         $wp
+ *
+ * @param string $tag   Name of the new rewrite tag.
+ * @param string $regex Regular expression to substitute the tag for in rewrite rules.
+ * @param string $query Optional. String to append to the rewritten query. Must end in '='. Default empty.
+ */
+function add_rewrite_tag( $tag, $regex, $query = '' ) {
+       // validate the tag's name
+       if ( strlen( $tag ) < 3 || $tag[0] != '%' || $tag[ strlen($tag) - 1 ] != '%' )
+               return;
+
+       global $wp_rewrite, $wp;
+
+       if ( empty( $query ) ) {
+               $qv = trim( $tag, '%' );
+               $wp->add_query_var( $qv );
+               $query = $qv . '=';
+       }
+
+       $wp_rewrite->add_rewrite_tag( $tag, $regex, $query );
+}
+
+/**
+ * Add permalink structure.
+ *
+ * @since 3.0.0
+ *
+ * @see WP_Rewrite::add_permastruct()
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param string $name   Name for permalink structure.
+ * @param string $struct Permalink structure.
+ * @param array  $args   Optional. Arguments for building the rules from the permalink structure,
+ *                       see WP_Rewrite::add_permastruct() for full details. Default empty array.
+ */
+function add_permastruct( $name, $struct, $args = array() ) {
+       global $wp_rewrite;
+
+       // backwards compatibility for the old parameters: $with_front and $ep_mask
+       if ( ! is_array( $args ) )
+               $args = array( 'with_front' => $args );
+       if ( func_num_args() == 4 )
+               $args['ep_mask'] = func_get_arg( 3 );
+
+       $wp_rewrite->add_permastruct( $name, $struct, $args );
+}
+
+/**
+ * Add a new feed type like /atom1/.
+ *
+ * @since 2.1.0
+ *
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param string   $feedname Feed name.
+ * @param callable $function Callback to run on feed display.
+ * @return string Feed action name.
+ */
+function add_feed( $feedname, $function ) {
+       global $wp_rewrite;
+
+       if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
+               $wp_rewrite->feeds[] = $feedname;
+       }
+
+       $hook = 'do_feed_' . $feedname;
+
+       // Remove default function hook
+       remove_action( $hook, $hook );
+
+       add_action( $hook, $function, 10, 2 );
+
+       return $hook;
+}
+
+/**
+ * Remove rewrite rules and then recreate rewrite rules.
+ *
+ * @since 3.0.0
+ *
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param bool $hard Whether to update .htaccess (hard flush) or just update
+ *                      rewrite_rules transient (soft flush). Default is true (hard).
+ */
+function flush_rewrite_rules( $hard = true ) {
+       global $wp_rewrite;
+       $wp_rewrite->flush_rules( $hard );
+}
+
+/**
+ * Add an endpoint, like /trackback/.
+ *
+ * Adding an endpoint creates extra rewrite rules for each of the matching
+ * places specified by the provided bitmask. For example:
+ *
+ *     add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );
+ *
+ * will add a new rewrite rule ending with "json(/(.*))?/?$" for every permastruct
+ * that describes a permalink (post) or page. This is rewritten to "json=$match"
+ * where $match is the part of the URL matched by the endpoint regex (e.g. "foo" in
+ * "[permalink]/json/foo/").
+ *
+ * A new query var with the same name as the endpoint will also be created.
+ *
+ * When specifying $places ensure that you are using the EP_* constants (or a
+ * combination of them using the bitwise OR operator) as their values are not
+ * guaranteed to remain static (especially `EP_ALL`).
+ *
+ * Be sure to flush the rewrite rules - see flush_rewrite_rules() - when your plugin gets
+ * activated and deactivated.
+ *
+ * @since 2.1.0
+ * @since 4.3.0 Added support for skipping query var registration by passing `false` to `$query_var`.
+ *
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param string      $name      Name of the endpoint.
+ * @param int         $places    Endpoint mask describing the places the endpoint should be added.
+ * @param string|bool $query_var Name of the corresponding query variable. Pass `false` to skip registering a query_var
+ *                               for this endpoint. Defaults to the value of `$name`.
+ */
+function add_rewrite_endpoint( $name, $places, $query_var = true ) {
+       global $wp_rewrite;
+       $wp_rewrite->add_endpoint( $name, $places, $query_var );
+}
+
+/**
+ * Filter the URL base for taxonomies.
+ *
+ * To remove any manually prepended /index.php/.
+ *
+ * @access private
+ * @since 2.6.0
+ *
+ * @param string $base The taxonomy base that we're going to filter
+ * @return string
+ */
+function _wp_filter_taxonomy_base( $base ) {
+       if ( !empty( $base ) ) {
+               $base = preg_replace( '|^/index\.php/|', '', $base );
+               $base = trim( $base, '/' );
+       }
+       return $base;
+}
+
+
+/**
+ * Resolve numeric slugs that collide with date permalinks.
+ *
+ * Permalinks of posts with numeric slugs can sometimes look to WP_Query::parse_query()
+ * like a date archive, as when your permalink structure is `/%year%/%postname%/` and
+ * a post with post_name '05' has the URL `/2015/05/`.
+ *
+ * This function detects conflicts of this type and resolves them in favor of the
+ * post permalink.
+ *
+ * Note that, since 4.3.0, wp_unique_post_slug() prevents the creation of post slugs
+ * that would result in a date archive conflict. The resolution performed in this
+ * function is primarily for legacy content, as well as cases when the admin has changed
+ * the site's permalink structure in a way that introduces URL conflicts.
+ *
+ * @since 4.3.0
+ *
+ * @param array $query_vars Optional. Query variables for setting up the loop, as determined in
+ *                          WP::parse_request(). Default empty array.
+ * @return array Returns the original array of query vars, with date/post conflicts resolved.
+ */
+function wp_resolve_numeric_slug_conflicts( $query_vars = array() ) {
+       if ( ! isset( $query_vars['year'] ) && ! isset( $query_vars['monthnum'] ) && ! isset( $query_vars['day'] ) ) {
+               return $query_vars;
+       }
+
+       // Identify the 'postname' position in the permastruct array.
+       $permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
+       $postname_index = array_search( '%postname%', $permastructs );
+
+       if ( false === $postname_index ) {
+               return $query_vars;
+       }
+
+       /*
+        * A numeric slug could be confused with a year, month, or day, depending on position. To account for
+        * the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our
+        * `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check
+        * for month-slug clashes when `is_month` *or* `is_day`.
+        */
+       $compare = '';
+       if ( 0 === $postname_index && ( isset( $query_vars['year'] ) || isset( $query_vars['monthnum'] ) ) ) {
+               $compare = 'year';
+       } elseif ( '%year%' === $permastructs[ $postname_index - 1 ] && ( isset( $query_vars['monthnum'] ) || isset( $query_vars['day'] ) ) ) {
+               $compare = 'monthnum';
+       } elseif ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && isset( $query_vars['day'] ) ) {
+               $compare = 'day';
+       }
+
+       if ( ! $compare ) {
+               return $query_vars;
+       }
+
+       // This is the potentially clashing slug.
+       $value = $query_vars[ $compare ];
+
+       $post = get_page_by_path( $value, OBJECT, 'post' );
+       if ( ! ( $post instanceof WP_Post ) ) {
+               return $query_vars;
+       }
+
+       // If the date of the post doesn't match the date specified in the URL, resolve to the date archive.
+       if ( preg_match( '/^([0-9]{4})\-([0-9]{2})/', $post->post_date, $matches ) && isset( $query_vars['year'] ) && ( 'monthnum' === $compare || 'day' === $compare ) ) {
+               // $matches[1] is the year the post was published.
+               if ( intval( $query_vars['year'] ) !== intval( $matches[1] ) ) {
+                       return $query_vars;
+               }
+
+               // $matches[2] is the month the post was published.
+               if ( 'day' === $compare && isset( $query_vars['monthnum'] ) && intval( $query_vars['monthnum'] ) !== intval( $matches[2] ) ) {
+                       return $query_vars;
+               }
+       }
+
+       /*
+        * If the located post contains nextpage pagination, then the URL chunk following postname may be
+        * intended as the page number. Verify that it's a valid page before resolving to it.
+        */
+       $maybe_page = '';
+       if ( 'year' === $compare && isset( $query_vars['monthnum'] ) ) {
+               $maybe_page = $query_vars['monthnum'];
+       } elseif ( 'monthnum' === $compare && isset( $query_vars['day'] ) ) {
+               $maybe_page = $query_vars['day'];
+       }
+       // Bug found in #11694 - 'page' was returning '/4'
+       $maybe_page = (int) trim( $maybe_page, '/' );
+
+       $post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1;
+
+       // If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive.
+       if ( 1 === $post_page_count && $maybe_page ) {
+               return $query_vars;
+       }
+
+       // If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive.
+       if ( $post_page_count > 1 && $maybe_page > $post_page_count ) {
+               return $query_vars;
+       }
+
+       // If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage.
+       if ( '' !== $maybe_page ) {
+               $query_vars['page'] = intval( $maybe_page );
+       }
+
+       // Next, unset autodetected date-related query vars.
+       unset( $query_vars['year'] );
+       unset( $query_vars['monthnum'] );
+       unset( $query_vars['day'] );
+
+       // Then, set the identified post.
+       $query_vars['name'] = $post->post_name;
+
+       // Finally, return the modified query vars.
+       return $query_vars;
+}
+
+/**
+ * Examine a url and try to determine the post ID it represents.
+ *
+ * Checks are supposedly from the hosted site blog.
+ *
+ * @since 1.0.0
+ *
+ * @global WP_Rewrite $wp_rewrite
+ * @global WP         $wp
+ *
+ * @param string $url Permalink to check.
+ * @return int Post ID, or 0 on failure.
+ */
+function url_to_postid( $url ) {
+       global $wp_rewrite;
+
+       /**
+        * Filter the URL to derive the post ID from.
+        *
+        * @since 2.2.0
+        *
+        * @param string $url The URL to derive the post ID from.
+        */
+       $url = apply_filters( 'url_to_postid', $url );
+
+       // First, check to see if there is a 'p=N' or 'page_id=N' to match against
+       if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) )   {
+               $id = absint($values[2]);
+               if ( $id )
+                       return $id;
+       }
+
+       // Check to see if we are using rewrite rules
+       $rewrite = $wp_rewrite->wp_rewrite_rules();
+
+       // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
+       if ( empty($rewrite) )
+               return 0;
+
+       // Get rid of the #anchor
+       $url_split = explode('#', $url);
+       $url = $url_split[0];
+
+       // Get rid of URL ?query=string
+       $url_split = explode('?', $url);
+       $url = $url_split[0];
+
+       // Set the correct URL scheme.
+       $url = set_url_scheme( $url );
+
+       // Add 'www.' if it is absent and should be there
+       if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
+               $url = str_replace('://', '://www.', $url);
+
+       // Strip 'www.' if it is present and shouldn't be
+       if ( false === strpos(home_url(), '://www.') )
+               $url = str_replace('://www.', '://', $url);
+
+       // Strip 'index.php/' if we're not using path info permalinks
+       if ( !$wp_rewrite->using_index_permalinks() )
+               $url = str_replace( $wp_rewrite->index . '/', '', $url );
+
+       if ( false !== strpos( trailingslashit( $url ), home_url( '/' ) ) ) {
+               // Chop off http://domain.com/[path]
+               $url = str_replace(home_url(), '', $url);
+       } else {
+               // Chop off /path/to/blog
+               $home_path = parse_url( home_url( '/' ) );
+               $home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
+               $url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( $url ) );
+       }
+
+       // Trim leading and lagging slashes
+       $url = trim($url, '/');
+
+       $request = $url;
+       $post_type_query_vars = array();
+
+       foreach ( get_post_types( array() , 'objects' ) as $post_type => $t ) {
+               if ( ! empty( $t->query_var ) )
+                       $post_type_query_vars[ $t->query_var ] = $post_type;
+       }
+
+       // Look for matches.
+       $request_match = $request;
+       foreach ( (array)$rewrite as $match => $query) {
+
+               // If the requesting file is the anchor of the match, prepend it
+               // to the path info.
+               if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
+                       $request_match = $url . '/' . $request;
+
+               if ( preg_match("#^$match#", $request_match, $matches) ) {
+
+                       if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
+                               // This is a verbose page match, let's check to be sure about it.
+                               $page = get_page_by_path( $matches[ $varmatch[1] ] );
+                               if ( ! $page ) {
+                                       continue;
+                               }
+
+                               $post_status_obj = get_post_status_object( $page->post_status );
+                               if ( ! $post_status_obj->public && ! $post_status_obj->protected
+                                       && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
+                                       continue;
+                               }
+                       }
+
+                       // Got a match.
+                       // Trim the query of everything up to the '?'.
+                       $query = preg_replace("!^.+\?!", '', $query);
+
+                       // Substitute the substring matches into the query.
+                       $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
+
+                       // Filter out non-public query vars
+                       global $wp;
+                       parse_str( $query, $query_vars );
+                       $query = array();
+                       foreach ( (array) $query_vars as $key => $value ) {
+                               if ( in_array( $key, $wp->public_query_vars ) ){
+                                       $query[$key] = $value;
+                                       if ( isset( $post_type_query_vars[$key] ) ) {
+                                               $query['post_type'] = $post_type_query_vars[$key];
+                                               $query['name'] = $value;
+                                       }
+                               }
+                       }
+
+                       // Resolve conflicts between posts with numeric slugs and date archive queries.
+                       $query = wp_resolve_numeric_slug_conflicts( $query );
+
+                       // Do the query
+                       $query = new WP_Query( $query );
+                       if ( ! empty( $query->posts ) && $query->is_singular )
+                               return $query->post->ID;
+                       else
+                               return 0;
+               }
+       }
+       return 0;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludestaxonomyfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/taxonomy-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/taxonomy-functions.php      2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/taxonomy-functions.php        2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,4692 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Taxonomy API: Top-level taxonomy functionality
- *
- * @package WordPress
- * @subpackage Taxonomy
- * @since 4.4.0
- */
-
-//
-// Taxonomy Registration
-//
-
-/**
- * Creates the initial taxonomies.
- *
- * This function fires twice: in wp-settings.php before plugins are loaded (for
- * backwards compatibility reasons), and again on the {@see 'init'} action. We must
- * avoid registering rewrite rules before the {@see 'init'} action.
- *
- * @since 2.8.0
- *
- * @global WP_Rewrite $wp_rewrite The WordPress rewrite class.
- */
-function create_initial_taxonomies() {
-       global $wp_rewrite;
-
-       if ( ! did_action( 'init' ) ) {
-               $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
-       } else {
-
-               /**
-                * Filter the post formats rewrite base.
-                *
-                * @since 3.1.0
-                *
-                * @param string $context Context of the rewrite base. Default 'type'.
-                */
-               $post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
-               $rewrite = array(
-                       'category' => array(
-                               'hierarchical' => true,
-                               'slug' => get_option('category_base') ? get_option('category_base') : 'category',
-                               'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
-                               'ep_mask' => EP_CATEGORIES,
-                       ),
-                       'post_tag' => array(
-                               'hierarchical' => false,
-                               'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
-                               'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
-                               'ep_mask' => EP_TAGS,
-                       ),
-                       'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
-               );
-       }
-
-       register_taxonomy( 'category', 'post', array(
-               'hierarchical' => true,
-               'query_var' => 'category_name',
-               'rewrite' => $rewrite['category'],
-               'public' => true,
-               'show_ui' => true,
-               'show_admin_column' => true,
-               '_builtin' => true,
-       ) );
-
-       register_taxonomy( 'post_tag', 'post', array(
-               'hierarchical' => false,
-               'query_var' => 'tag',
-               'rewrite' => $rewrite['post_tag'],
-               'public' => true,
-               'show_ui' => true,
-               'show_admin_column' => true,
-               '_builtin' => true,
-       ) );
-
-       register_taxonomy( 'nav_menu', 'nav_menu_item', array(
-               'public' => false,
-               'hierarchical' => false,
-               'labels' => array(
-                       'name' => __( 'Navigation Menus' ),
-                       'singular_name' => __( 'Navigation Menu' ),
-               ),
-               'query_var' => false,
-               'rewrite' => false,
-               'show_ui' => false,
-               '_builtin' => true,
-               'show_in_nav_menus' => false,
-       ) );
-
-       register_taxonomy( 'link_category', 'link', array(
-               'hierarchical' => false,
-               'labels' => array(
-                       'name' => __( 'Link Categories' ),
-                       'singular_name' => __( 'Link Category' ),
-                       'search_items' => __( 'Search Link Categories' ),
-                       'popular_items' => null,
-                       'all_items' => __( 'All Link Categories' ),
-                       'edit_item' => __( 'Edit Link Category' ),
-                       'update_item' => __( 'Update Link Category' ),
-                       'add_new_item' => __( 'Add New Link Category' ),
-                       'new_item_name' => __( 'New Link Category Name' ),
-                       'separate_items_with_commas' => null,
-                       'add_or_remove_items' => null,
-                       'choose_from_most_used' => null,
-               ),
-               'capabilities' => array(
-                       'manage_terms' => 'manage_links',
-                       'edit_terms'   => 'manage_links',
-                       'delete_terms' => 'manage_links',
-                       'assign_terms' => 'manage_links',
-               ),
-               'query_var' => false,
-               'rewrite' => false,
-               'public' => false,
-               'show_ui' => true,
-               '_builtin' => true,
-       ) );
-
-       register_taxonomy( 'post_format', 'post', array(
-               'public' => true,
-               'hierarchical' => false,
-               'labels' => array(
-                       'name' => _x( 'Format', 'post format' ),
-                       'singular_name' => _x( 'Format', 'post format' ),
-               ),
-               'query_var' => true,
-               'rewrite' => $rewrite['post_format'],
-               'show_ui' => false,
-               '_builtin' => true,
-               'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
-       ) );
-}
-
-/**
- * Retrieves a list of registered taxonomy names or objects.
- *
- * @since 3.0.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param array  $args     Optional. An array of `key => value` arguments to match against the taxonomy objects.
- *                         Default empty array.
- * @param string $output   Optional. The type of output to return in the array. Accepts either taxonomy 'names'
- *                         or 'objects'. Default 'names'.
- * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only
- *                         one element from the array needs to match; 'and' means all elements must match.
- *                         Default 'and'.
- * @return array A list of taxonomy names or objects.
- */
-function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
-       global $wp_taxonomies;
-
-       $field = ('names' == $output) ? 'name' : false;
-
-       return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
-}
-
-/**
- * Return all of the taxonomy names that are of $object_type.
- *
- * It appears that this function can be used to find all of the names inside of
- * $wp_taxonomies global variable.
- *
- * `<?php $taxonomies = get_object_taxonomies('post'); ?>` Should
- * result in `Array( 'category', 'post_tag' )`
- *
- * @since 2.3.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts)
- * @param string               $output Optional. The type of output to return in the array. Accepts either
- *                                     taxonomy 'names' or 'objects'. Default 'names'.
- * @return array The names of all taxonomy of $object_type.
- */
-function get_object_taxonomies( $object, $output = 'names' ) {
-       global $wp_taxonomies;
-
-       if ( is_object($object) ) {
-               if ( $object->post_type == 'attachment' )
-                       return get_attachment_taxonomies($object);
-               $object = $object->post_type;
-       }
-
-       $object = (array) $object;
-
-       $taxonomies = array();
-       foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
-               if ( array_intersect($object, (array) $tax_obj->object_type) ) {
-                       if ( 'names' == $output )
-                               $taxonomies[] = $tax_name;
-                       else
-                               $taxonomies[ $tax_name ] = $tax_obj;
-               }
-       }
-
-       return $taxonomies;
-}
-
-/**
- * Retrieves the taxonomy object of $taxonomy.
- *
- * The get_taxonomy function will first check that the parameter string given
- * is a taxonomy object and if it is, it will return it.
- *
- * @since 2.3.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param string $taxonomy Name of taxonomy object to return.
- * @return object|false The Taxonomy Object or false if $taxonomy doesn't exist.
- */
-function get_taxonomy( $taxonomy ) {
-       global $wp_taxonomies;
-
-       if ( ! taxonomy_exists( $taxonomy ) )
-               return false;
-
-       return $wp_taxonomies[$taxonomy];
-}
-
-/**
- * Checks that the taxonomy name exists.
- *
- * Formerly is_taxonomy(), introduced in 2.3.0.
- *
- * @since 3.0.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param string $taxonomy Name of taxonomy object.
- * @return bool Whether the taxonomy exists.
- */
-function taxonomy_exists( $taxonomy ) {
-       global $wp_taxonomies;
-
-       return isset( $wp_taxonomies[$taxonomy] );
-}
-
-/**
- * Whether the taxonomy object is hierarchical.
- *
- * Checks to make sure that the taxonomy is an object first. Then Gets the
- * object, and finally returns the hierarchical value in the object.
- *
- * A false return value might also mean that the taxonomy does not exist.
- *
- * @since 2.3.0
- *
- * @param string $taxonomy Name of taxonomy object.
- * @return bool Whether the taxonomy is hierarchical.
- */
-function is_taxonomy_hierarchical($taxonomy) {
-       if ( ! taxonomy_exists($taxonomy) )
-               return false;
-
-       $taxonomy = get_taxonomy($taxonomy);
-       return $taxonomy->hierarchical;
-}
-
-/**
- * Creates or modifies a taxonomy object.
- *
- * Note: Do not use before the {@see 'init'} hook.
- *
- * A simple function for creating or modifying a taxonomy object based on the
- * parameters given. The function will accept an array (third optional
- * parameter), along with strings for the taxonomy name and another string for
- * the object type.
- *
- * @since 2.3.0
- * @since 4.2.0 Introduced `show_in_quick_edit` argument.
- * @since 4.4.0 The `show_ui` argument is now enforced on the term editing screen.
- * @since 4.4.0 The `public` argument now controls whether the taxonomy can be queried on the front-end.
- *
- * @global array $wp_taxonomies Registered taxonomies.
- * @global WP    $wp            WP instance.
- *
- * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
- * @param array|string $object_type Name of the object type for the taxonomy object.
- * @param array|string $args        {
- *     Optional. Array or query string of arguments for registering a taxonomy.
- *
- *     @type string        $label                 Name of the taxonomy shown in the menu. Usually plural. If not set,
- *                                                `$labels['name']` will be used.
- *     @type array         $labels                An array of labels for this taxonomy. By default, Tag labels are used for
- *                                                non-hierarchical taxonmies, and Category labels are used for hierarchical
- *                                                taxonomies. See accepted values in get_taxonomy_labels().
- *                                                Default empty array.
- *     @type string        $description           A short descriptive summary of what the taxonomy is for. Default empty.
- *     @type bool          $public                Whether the taxonomy is publicly queryable. Default true.
- *     @type bool          $hierarchical          Whether the taxonomy is hierarchical. Default false.
- *     @type bool          $show_ui               Whether to generate and allow a UI for managing terms in this taxonomy in
- *                                                the admin. If not set, the default is inherited from `$public`
- *                                                (default true).
- *     @type bool          $show_in_menu          Whether to show the taxonomy in the admin menu. If true, the taxonomy is
- *                                                shown as a submenu of the object type menu. If false, no menu is shown.
- *                                                `$show_ui` must be true. If not set, default is inherited from `$show_ui`
- *                                                (default true).
- *     @type bool          $show_in_nav_menus     Makes this taxonomy available for selection in navigation menus. If not
- *                                                set, the default is inherited from `$public` (default true).
- *     @type bool          $show_tagcloud         Whether to list the taxonomy in the Tag Cloud Widget controls. If not set,
- *                                                the default is inherited from `$show_ui` (default true).
- *     @type bool          $show_in_quick_edit    Whether to show the taxonomy in the quick/bulk edit panel. It not set,
- *                                                the default is inherited from `$show_ui` (default true).
- *     @type bool          $show_admin_column     Whether to display a column for the taxonomy on its post type listing
- *                                                screens. Default false.
- *     @type bool|callable $meta_box_cb           Provide a callback function for the meta box display. If not set,
- *                                                post_categories_meta_box() is used for hierarchical taxonomies, and
- *                                                post_tags_meta_box() is used for non-hierarchical. If false, no meta
- *                                                box is shown.
- *     @type array         $capabilities {
- *         Array of capabilities for this taxonomy.
- *
- *         @type string $manage_terms Default 'manage_categories'.
- *         @type string $edit_terms   Default 'manage_categories'.
- *         @type string $delete_terms Default 'manage_categories'.
- *         @type string $assign_terms Default 'edit_posts'.
- *     }
- *     @type bool|array    $rewrite {
- *         Triggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent
- *         rewrite, set to false. To specify rewrite rules, an array can be passed with any of these keys:
- *
- *         @type string $slug         Customize the permastruct slug. Default `$taxonomy` key.
- *         @type bool   $with_front   Should the permastruct be prepended with WP_Rewrite::$front. Default true.
- *         @type bool   $hierarchical Either hierarchical rewrite tag or not. Default false.
- *         @type int    $ep_mask      Assign an endpoint mask. Default `EP_NONE`.
- *     }
- *     @type string        $query_var             Sets the query var key for this taxonomy. Default `$taxonomy` key. If
- *                                                false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a
- *                                                string, the query `?{query_var}={term_slug}` will be valid.
- *     @type callable      $update_count_callback Works much like a hook, in that it will be called when the count is
- *                                                updated. Default _update_post_term_count() for taxonomies attached
- *                                                to post types, which confirms that the objects are published before
- *                                                counting them. Default _update_generic_term_count() for taxonomies
- *                                                attached to other object types, such as users.
- *     @type bool          $_builtin              This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY!
- *                                                Default false.
- * }
- * @return WP_Error|void WP_Error, if errors.
- */
-function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
-       global $wp_taxonomies, $wp;
-
-       if ( ! is_array( $wp_taxonomies ) )
-               $wp_taxonomies = array();
-
-       $args = wp_parse_args( $args );
-
-       /**
-        * Filter the arguments for registering a taxonomy.
-        *
-        * @since 4.4.0
-        *
-        * @param array  $args        Array of arguments for registering a taxonomy.
-        * @param array  $object_type Array of names of object types for the taxonomy.
-        * @param string $taxonomy    Taxonomy key.
-        */
-       $args = apply_filters( 'register_taxonomy_args', $args, $taxonomy, (array) $object_type );
-
-       $defaults = array(
-               'labels'                => array(),
-               'description'           => '',
-               'public'                => true,
-               'hierarchical'          => false,
-               'show_ui'               => null,
-               'show_in_menu'          => null,
-               'show_in_nav_menus'     => null,
-               'show_tagcloud'         => null,
-               'show_in_quick_edit'    => null,
-               'show_admin_column'     => false,
-               'meta_box_cb'           => null,
-               'capabilities'          => array(),
-               'rewrite'               => true,
-               'query_var'             => $taxonomy,
-               'update_count_callback' => '',
-               '_builtin'              => false,
-       );
-       $args = array_merge( $defaults, $args );
-
-       if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
-               _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2' );
-               return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) );
-       }
-
-       // Non-public taxonomies should not register query vars, except in the admin.
-       if ( false !== $args['query_var'] && ( is_admin() || false !== $args['public'] ) && ! empty( $wp ) ) {
-               if ( true === $args['query_var'] )
-                       $args['query_var'] = $taxonomy;
-               else
-                       $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] );
-               $wp->add_query_var( $args['query_var'] );
-       }
-
-       if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
-               $args['rewrite'] = wp_parse_args( $args['rewrite'], array(
-                       'with_front' => true,
-                       'hierarchical' => false,
-                       'ep_mask' => EP_NONE,
-               ) );
-
-               if ( empty( $args['rewrite']['slug'] ) )
-                       $args['rewrite']['slug'] = sanitize_title_with_dashes( $taxonomy );
-
-               if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] )
-                       $tag = '(.+?)';
-               else
-                       $tag = '([^/]+)';
-
-               add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" );
-               add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] );
-       }
-
-       // If not set, default to the setting for public.
-       if ( null === $args['show_ui'] )
-               $args['show_ui'] = $args['public'];
-
-       // If not set, default to the setting for show_ui.
-       if ( null === $args['show_in_menu' ] || ! $args['show_ui'] )
-               $args['show_in_menu' ] = $args['show_ui'];
-
-       // If not set, default to the setting for public.
-       if ( null === $args['show_in_nav_menus'] )
-               $args['show_in_nav_menus'] = $args['public'];
-
-       // If not set, default to the setting for show_ui.
-       if ( null === $args['show_tagcloud'] )
-               $args['show_tagcloud'] = $args['show_ui'];
-
-       // If not set, default to the setting for show_ui.
-       if ( null === $args['show_in_quick_edit'] ) {
-               $args['show_in_quick_edit'] = $args['show_ui'];
-       }
-
-       $default_caps = array(
-               'manage_terms' => 'manage_categories',
-               'edit_terms'   => 'manage_categories',
-               'delete_terms' => 'manage_categories',
-               'assign_terms' => 'edit_posts',
-       );
-       $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
-       unset( $args['capabilities'] );
-
-       $args['name'] = $taxonomy;
-       $args['object_type'] = array_unique( (array) $object_type );
-
-       $args['labels'] = get_taxonomy_labels( (object) $args );
-       $args['label'] = $args['labels']->name;
-
-       // If not set, use the default meta box
-       if ( null === $args['meta_box_cb'] ) {
-               if ( $args['hierarchical'] )
-                       $args['meta_box_cb'] = 'post_categories_meta_box';
-               else
-                       $args['meta_box_cb'] = 'post_tags_meta_box';
-       }
-
-       $wp_taxonomies[ $taxonomy ] = (object) $args;
-
-       // register callback handling for metabox
-       add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' );
-
-       /**
-        * Fires after a taxonomy is registered.
-        *
-        * @since 3.3.0
-        *
-        * @param string       $taxonomy    Taxonomy slug.
-        * @param array|string $object_type Object type or array of object types.
-        * @param array        $args        Array of taxonomy registration arguments.
-        */
-       do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
-}
-
-/**
- * Builds an object with all taxonomy labels out of a taxonomy object
- *
- * Accepted keys of the label array in the taxonomy object:
- *
- * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
- * - singular_name - name for one object of this taxonomy. Default is Tag/Category
- * - search_items - Default is Search Tags/Search Categories
- * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
- * - all_items - Default is All Tags/All Categories
- * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
- * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end
- * - edit_item - Default is Edit Tag/Edit Category
- * - view_item - Default is View Tag/View Category
- * - update_item - Default is Update Tag/Update Category
- * - add_new_item - Default is Add New Tag/Add New Category
- * - new_item_name - Default is New Tag Name/New Category Name
- * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
- * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled.
- * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box.
- * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table.
- * - no_terms - Default is "No tags"/"No categories", used in the posts and media list tables.
- * - items_list_navigation - String for the table pagination hidden heading.
- * - items_list - String for the table hidden heading.
- *
- * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
- *
- * @todo Better documentation for the labels array.
- *
- * @since 3.0.0
- * @since 4.3.0 Added the `no_terms` label.
- * @since 4.4.0 Added the `items_list_navigation` and `items_list` labels.
- *
- * @param object $tax Taxonomy object.
- * @return object object with all the labels as member variables.
- */
-function get_taxonomy_labels( $tax ) {
-       $tax->labels = (array) $tax->labels;
-
-       if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
-               $tax->labels['separate_items_with_commas'] = $tax->helps;
-
-       if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) )
-               $tax->labels['not_found'] = $tax->no_tagcloud;
-
-       $nohier_vs_hier_defaults = array(
-               'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
-               'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
-               'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
-               'popular_items' => array( __( 'Popular Tags' ), null ),
-               'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
-               'parent_item' => array( null, __( 'Parent Category' ) ),
-               'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
-               'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
-               'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
-               'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
-               'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
-               'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
-               'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
-               'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
-               'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
-               'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
-               'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ),
-               'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
-               'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ),
-       );
-       $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
-
-       $labels = _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
-
-       $taxonomy = $tax->name;
-
-       $default_labels = clone $labels;
-
-       /**
-        * Filter the labels of a specific taxonomy.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
-        *
-        * @since 4.4.0
-        *
-        * @see get_taxonomy_labels() for the full list of taxonomy labels.
-        *
-        * @param object $labels Object with labels for the taxonomy as member variables.
-        */
-       $labels = apply_filters( "taxonomy_labels_{$taxonomy}", $labels );
-
-       // Ensure that the filtered labels contain all required default values.
-       $labels = (object) array_merge( (array) $default_labels, (array) $labels );
-
-       return $labels;
-}
-
-/**
- * Add an already registered taxonomy to an object type.
- *
- * @since 3.0.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param string $taxonomy    Name of taxonomy object.
- * @param string $object_type Name of the object type.
- * @return bool True if successful, false if not.
- */
-function register_taxonomy_for_object_type( $taxonomy, $object_type) {
-       global $wp_taxonomies;
-
-       if ( !isset($wp_taxonomies[$taxonomy]) )
-               return false;
-
-       if ( ! get_post_type_object($object_type) )
-               return false;
-
-       if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
-               $wp_taxonomies[$taxonomy]->object_type[] = $object_type;
-
-       // Filter out empties.
-       $wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
-
-       return true;
-}
-
-/**
- * Remove an already registered taxonomy from an object type.
- *
- * @since 3.7.0
- *
- * @global array $wp_taxonomies The registered taxonomies.
- *
- * @param string $taxonomy    Name of taxonomy object.
- * @param string $object_type Name of the object type.
- * @return bool True if successful, false if not.
- */
-function unregister_taxonomy_for_object_type( $taxonomy, $object_type ) {
-       global $wp_taxonomies;
-
-       if ( ! isset( $wp_taxonomies[ $taxonomy ] ) )
-               return false;
-
-       if ( ! get_post_type_object( $object_type ) )
-               return false;
-
-       $key = array_search( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true );
-       if ( false === $key )
-               return false;
-
-       unset( $wp_taxonomies[ $taxonomy ]->object_type[ $key ] );
-       return true;
-}
-
-//
-// Term API
-//
-
-/**
- * Retrieve object_ids of valid taxonomy and term.
- *
- * The strings of $taxonomies must exist before this function will continue. On
- * failure of finding a valid taxonomy, it will return an WP_Error class, kind
- * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
- * still test for the WP_Error class and get the error message.
- *
- * The $terms aren't checked the same as $taxonomies, but still need to exist
- * for $object_ids to be returned.
- *
- * It is possible to change the order that object_ids is returned by either
- * using PHP sort family functions or using the database by using $args with
- * either ASC or DESC array. The value should be in the key named 'order'.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
- * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
- * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
- * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
- *     the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
- */
-function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
-       global $wpdb;
-
-       if ( ! is_array( $term_ids ) ) {
-               $term_ids = array( $term_ids );
-       }
-       if ( ! is_array( $taxonomies ) ) {
-               $taxonomies = array( $taxonomies );
-       }
-       foreach ( (array) $taxonomies as $taxonomy ) {
-               if ( ! taxonomy_exists( $taxonomy ) ) {
-                       return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
-               }
-       }
-
-       $defaults = array( 'order' => 'ASC' );
-       $args = wp_parse_args( $args, $defaults );
-
-       $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
-
-       $term_ids = array_map('intval', $term_ids );
-
-       $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
-       $term_ids = "'" . implode( "', '", $term_ids ) . "'";
-
-       $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
-
-       if ( ! $object_ids ){
-               return array();
-       }
-       return $object_ids;
-}
-
-/**
- * Given a taxonomy query, generates SQL to be appended to a main query.
- *
- * @since 3.1.0
- *
- * @see WP_Tax_Query
- *
- * @param array  $tax_query         A compact tax query
- * @param string $primary_table
- * @param string $primary_id_column
- * @return array
- */
-function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
-       $tax_query_obj = new WP_Tax_Query( $tax_query );
-       return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
-}
-
-/**
- * Get all Term data from database by Term ID.
- *
- * The usage of the get_term function is to apply filters to a term object. It
- * is possible to get a term object from the database before applying the
- * filters.
- *
- * $term ID must be part of $taxonomy, to get from the database. Failure, might
- * be able to be captured by the hooks. Failure would be the same value as $wpdb
- * returns for the get_row method.
- *
- * There are two hooks, one is specifically for each term, named 'get_term', and
- * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
- * term object, and the taxonomy name as parameters. Both hooks are expected to
- * return a Term object.
- *
- * {@see 'get_term'} hook - Takes two parameters the term Object and the taxonomy name.
- * Must return term object. Used in get_term() as a catch-all filter for every
- * $term.
- *
- * {@see 'get_$taxonomy'} hook - Takes two parameters the term Object and the taxonomy
- * name. Must return term object. $taxonomy will be the taxonomy name, so for
- * example, if 'category', it would be 'get_category' as the filter name. Useful
- * for custom taxonomies or plugging into default taxonomies.
- *
- * @todo Better formatting for DocBlock
- *
- * @since 2.3.0
- * @since 4.4.0 Converted to return a WP_Term object if `$output` is `OBJECT`.
- *              The `$taxonomy` parameter was made optional.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
- *
- * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if
- *                                 available. If stdClass object (as in the results of a database query), will apply
- *                                 filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`,
- *                                 will return `$term`.
- * @param string     $taxonomy Optional. Taxonomy name that $term is part of.
- * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
- * @return mixed Type corresponding to `$output` on success or null on failure. When `$output` is `OBJECT`,
- *               a WP_Term instance is returned. If taxonomy does not exist then WP_Error will be returned.
- */
-function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
-       if ( empty( $term ) ) {
-               return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
-       }
-
-       if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) {
-               return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
-       }
-
-       if ( $term instanceof WP_Term ) {
-               $_term = $term;
-       } elseif ( is_object( $term ) ) {
-               if ( empty( $term->filter ) || 'raw' === $term->filter ) {
-                       $_term = sanitize_term( $term, $taxonomy, 'raw' );
-                       $_term = new WP_Term( $_term );
-               } else {
-                       $_term = WP_Term::get_instance( $term->term_id );
-               }
-       } else {
-               $_term = WP_Term::get_instance( $term, $taxonomy );
-       }
-
-       if ( is_wp_error( $_term ) ) {
-               return $_term;
-       } elseif ( ! $_term ) {
-               return null;
-       }
-
-       /**
-        * Filter a term.
-        *
-        * @since 2.3.0
-        * @since 4.4.0 `$_term` can now also be a WP_Term object.
-        *
-        * @param int|WP_Term $_term    Term object or ID.
-        * @param string      $taxonomy The taxonomy slug.
-        */
-       $_term = apply_filters( 'get_term', $_term, $taxonomy );
-
-       /**
-        * Filter a taxonomy.
-        *
-        * The dynamic portion of the filter name, `$taxonomy`, refers
-        * to the taxonomy slug.
-        *
-        * @since 2.3.0
-        * @since 4.4.0 `$_term` can now also be a WP_Term object.
-        *
-        * @param int|WP_Term $_term    Term object or ID.
-        * @param string      $taxonomy The taxonomy slug.
-        */
-       $_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
-
-       // Sanitize term, according to the specified filter.
-       $_term->filter( $filter );
-
-       if ( $output == ARRAY_A ) {
-               return $_term->to_array();
-       } elseif ( $output == ARRAY_N ) {
-               return array_values( $_term->to_array() );
-       }
-
-       return $_term;
-}
-
-/**
- * Get all Term data from database by Term field and data.
- *
- * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
- * required.
- *
- * The default $field is 'id', therefore it is possible to also use null for
- * field, but not recommended that you do so.
- *
- * If $value does not exist, the return value will be false. If $taxonomy exists
- * and $field and $value combinations exist, the Term will be returned.
- *
- * @todo Better formatting for DocBlock.
- *
- * @since 2.3.0
- * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return
- *              a WP_Term object if `$output` is `OBJECT`.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
- *
- * @param string     $field    Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
- * @param string|int $value    Search for this term value
- * @param string     $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
- * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
- * @return WP_Term|bool WP_Term instance on success. Will return false if `$taxonomy` does not exist
- *                      or `$term` was not found.
- */
-function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
-       global $wpdb;
-
-       // 'term_taxonomy_id' lookups don't require taxonomy checks.
-       if ( 'term_taxonomy_id' !== $field && ! taxonomy_exists( $taxonomy ) ) {
-               return false;
-       }
-
-       $tax_clause = $wpdb->prepare( "AND tt.taxonomy = %s", $taxonomy );
-
-       if ( 'slug' == $field ) {
-               $_field = 't.slug';
-               $value = sanitize_title($value);
-               if ( empty($value) )
-                       return false;
-       } elseif ( 'name' == $field ) {
-               // Assume already escaped
-               $value = wp_unslash($value);
-               $_field = 't.name';
-       } elseif ( 'term_taxonomy_id' == $field ) {
-               $value = (int) $value;
-               $_field = 'tt.term_taxonomy_id';
-
-               // No `taxonomy` clause when searching by 'term_taxonomy_id'.
-               $tax_clause = '';
-       } else {
-               $term = get_term( (int) $value, $taxonomy, $output, $filter );
-               if ( is_wp_error( $term ) || is_null( $term ) ) {
-                       $term = false;
-               }
-               return $term;
-       }
-
-       $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE $_field = %s $tax_clause LIMIT 1", $value ) );
-       if ( ! $term )
-               return false;
-
-       // In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the db.
-       if ( 'term_taxonomy_id' === $field ) {
-               $taxonomy = $term->taxonomy;
-       }
-
-       wp_cache_add( $term->term_id, $term, 'terms' );
-
-       return get_term( $term, $taxonomy, $output, $filter );
-}
-
-/**
- * Merge all term children into a single array of their IDs.
- *
- * This recursive function will merge all of the children of $term into the same
- * array of term IDs. Only useful for taxonomies which are hierarchical.
- *
- * Will return an empty array if $term does not exist in $taxonomy.
- *
- * @since 2.3.0
- *
- * @param string $term_id  ID of Term to get children.
- * @param string $taxonomy Taxonomy Name.
- * @return array|WP_Error List of Term IDs. WP_Error returned if `$taxonomy` does not exist.
- */
-function get_term_children( $term_id, $taxonomy ) {
-       if ( ! taxonomy_exists($taxonomy) )
-               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
-
-       $term_id = intval( $term_id );
-
-       $terms = _get_term_hierarchy($taxonomy);
-
-       if ( ! isset($terms[$term_id]) )
-               return array();
-
-       $children = $terms[$term_id];
-
-       foreach ( (array) $terms[$term_id] as $child ) {
-               if ( $term_id == $child ) {
-                       continue;
-               }
-
-               if ( isset($terms[$child]) )
-                       $children = array_merge($children, get_term_children($child, $taxonomy));
-       }
-
-       return $children;
-}
-
-/**
- * Get sanitized Term field.
- *
- * The function is for contextual reasons and for simplicity of usage.
- *
- * @since 2.3.0
- * @since 4.4.0 The `$taxonomy` parameter was made optional. `$term` can also now accept a WP_Term object.
- *
- * @see sanitize_term_field()
- *
- * @param string      $field    Term field to fetch.
- * @param int|WP_Term $term     Term ID or object.
- * @param string      $taxonomy Optional. Taxonomy Name. Default empty.
- * @param string      $context  Optional, default is display. Look at sanitize_term_field() for available options.
- * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term.
- */
-function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
-       $term = get_term( $term, $taxonomy );
-       if ( is_wp_error($term) )
-               return $term;
-
-       if ( !is_object($term) )
-               return '';
-
-       if ( !isset($term->$field) )
-               return '';
-
-       return sanitize_term_field( $field, $term->$field, $term->term_id, $term->taxonomy, $context );
-}
-
-/**
- * Sanitizes Term for editing.
- *
- * Return value is sanitize_term() and usage is for sanitizing the term for
- * editing. Function is for contextual and simplicity.
- *
- * @since 2.3.0
- *
- * @param int|object $id       Term ID or object.
- * @param string     $taxonomy Taxonomy name.
- * @return string|int|null|WP_Error Will return empty string if $term is not an object.
- */
-function get_term_to_edit( $id, $taxonomy ) {
-       $term = get_term( $id, $taxonomy );
-
-       if ( is_wp_error($term) )
-               return $term;
-
-       if ( !is_object($term) )
-               return '';
-
-       return sanitize_term($term, $taxonomy, 'edit');
-}
-
-/**
- * Retrieve the terms in a given taxonomy or list of taxonomies.
- *
- * You can fully inject any customizations to the query before it is sent, as
- * well as control the output with a filter.
- *
- * The {@see 'get_terms'} filter will be called when the cache has the term and will
- * pass the found term along with the array of $taxonomies and array of $args.
- * This filter is also called before the array of terms is passed and will pass
- * the array of terms, along with the $taxonomies and $args.
- *
- * The {@see 'list_terms_exclusions'} filter passes the compiled exclusions along with
- * the $args.
- *
- * The {@see 'get_terms_orderby'} filter passes the `ORDER BY` clause for the query
- * along with the $args array.
- *
- * @since 2.3.0
- * @since 4.2.0 Introduced 'name' and 'childless' parameters.
- * @since 4.4.0 Introduced the ability to pass 'term_id' as an alias of 'id' for the `orderby` parameter.
- *              Introduced the 'meta_query' and 'update_term_meta_cache' parameters. Converted to return
- *              a list of WP_Term objects.
- *
- * @global wpdb  $wpdb WordPress database abstraction object.
- * @global array $wp_filter
- *
- * @param string|array $taxonomies Taxonomy name or list of Taxonomy names.
- * @param array|string $args {
- *     Optional. Array or string of arguments to get terms.
- *
- *     @type string       $orderby                Field(s) to order terms by. Accepts term fields ('name', 'slug',
- *                                                'term_group', 'term_id', 'id', 'description'), 'count' for term
- *                                                taxonomy count, 'include' to match the 'order' of the $include param,
- *                                                or 'none' to skip ORDER BY. Defaults to 'name'.
- *     @type string       $order                  Whether to order terms in ascending or descending order.
- *                                                Accepts 'ASC' (ascending) or 'DESC' (descending).
- *                                                Default 'ASC'.
- *     @type bool|int     $hide_empty             Whether to hide terms not assigned to any posts. Accepts
- *                                                1|true or 0|false. Default 1|true.
- *     @type array|string $include                Array or comma/space-separated string of term ids to include.
- *                                                Default empty array.
- *     @type array|string $exclude                Array or comma/space-separated string of term ids to exclude.
- *                                                If $include is non-empty, $exclude is ignored.
- *                                                Default empty array.
- *     @type array|string $exclude_tree           Array or comma/space-separated string of term ids to exclude
- *                                                along with all of their descendant terms. If $include is
- *                                                non-empty, $exclude_tree is ignored. Default empty array.
- *     @type int|string   $number                 Maximum number of terms to return. Accepts ''|0 (all) or any
- *                                                positive number. Default ''|0 (all).
- *     @type int          $offset                 The number by which to offset the terms query. Default empty.
- *     @type string       $fields                 Term fields to query for. Accepts 'all' (returns an array of complete
- *                                                term objects), 'ids' (returns an array of ids), 'id=>parent' (returns
- *                                                an associative array with ids as keys, parent term IDs as values),
- *                                                'names' (returns an array of term names), 'count' (returns the number
- *                                                of matching terms), 'id=>name' (returns an associative array with ids
- *                                                as keys, term names as values), or 'id=>slug' (returns an associative
- *                                                array with ids as keys, term slugs as values). Default 'all'.
- *     @type string|array $name                   Optional. Name or array of names to return term(s) for. Default empty.
- *     @type string|array $slug                   Optional. Slug or array of slugs to return term(s) for. Default empty.
- *     @type bool         $hierarchical           Whether to include terms that have non-empty descendants (even
- *                                                if $hide_empty is set to true). Default true.
- *     @type string       $search                 Search criteria to match terms. Will be SQL-formatted with
- *                                                wildcards before and after. Default empty.
- *     @type string       $name__like             Retrieve terms with criteria by which a term is LIKE $name__like.
- *                                                Default empty.
- *     @type string       $description__like      Retrieve terms where the description is LIKE $description__like.
- *                                                Default empty.
- *     @type bool         $pad_counts             Whether to pad the quantity of a term's children in the quantity
- *                                                of each term's "count" object variable. Default false.
- *     @type string       $get                    Whether to return terms regardless of ancestry or whether the terms
- *                                                are empty. Accepts 'all' or empty (disabled). Default empty.
- *     @type int          $child_of               Term ID to retrieve child terms of. If multiple taxonomies
- *                                                are passed, $child_of is ignored. Default 0.
- *     @type int|string   $parent                 Parent term ID to retrieve direct-child terms of. Default empty.
- *     @type bool         $childless              True to limit results to terms that have no children. This parameter
- *                                                has no effect on non-hierarchical taxonomies. Default false.
- *     @type string       $cache_domain           Unique cache key to be produced when this query is stored in an
- *                                                object cache. Default is 'core'.
- *     @type bool         $update_term_meta_cache Whether to prime meta caches for matched terms. Default true.
- *     @type array        $meta_query             Meta query clauses to limit retrieved terms by.
- *                                                See `WP_Meta_Query`. Default empty.
- * }
- * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
- *                            do not exist.
- */
-function get_terms( $taxonomies, $args = '' ) {
-       global $wpdb;
-       $empty_array = array();
-
-       $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies );
-       if ( ! is_array( $taxonomies ) ) {
-               $taxonomies = array( $taxonomies );
-       }
-
-       foreach ( $taxonomies as $taxonomy ) {
-               if ( ! taxonomy_exists($taxonomy) ) {
-                       return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
-               }
-       }
-
-       $defaults = array(
-               'orderby'                => 'name',
-               'order'                  => 'ASC',
-               'hide_empty'             => true,
-               'include'                => array(),
-               'exclude'                => array(),
-               'exclude_tree'           => array(),
-               'number'                 => '',
-               'offset'                 => '',
-               'fields'                 => 'all',
-               'name'                   => '',
-               'slug'                   => '',
-               'hierarchical'           => true,
-               'search'                 => '',
-               'name__like'             => '',
-               'description__like'      => '',
-               'pad_counts'             => false,
-               'get'                    => '',
-               'child_of'               => 0,
-               'parent'                 => '',
-               'childless'              => false,
-               'cache_domain'           => 'core',
-               'update_term_meta_cache' => true,
-               'meta_query'             => ''
-       );
-
-       /**
-        * Filter the terms query default arguments.
-        *
-        * Use 'get_terms_args' to filter the passed arguments.
-        *
-        * @since 4.4.0
-        *
-        * @param array $defaults   An array of default get_terms() arguments.
-        * @param array $taxonomies An array of taxonomies.
-        */
-       $args = wp_parse_args( $args, apply_filters( 'get_terms_defaults', $defaults, $taxonomies ) );
-
-       $args['number'] = absint( $args['number'] );
-       $args['offset'] = absint( $args['offset'] );
-
-       // Save queries by not crawling the tree in the case of multiple taxes or a flat tax.
-       $has_hierarchical_tax = false;
-       foreach ( $taxonomies as $_tax ) {
-               if ( is_taxonomy_hierarchical( $_tax ) ) {
-                       $has_hierarchical_tax = true;
-               }
-       }
-
-       if ( ! $has_hierarchical_tax ) {
-               $args['hierarchical'] = false;
-               $args['pad_counts'] = false;
-       }
-
-       // 'parent' overrides 'child_of'.
-       if ( 0 < intval( $args['parent'] ) ) {
-               $args['child_of'] = false;
-       }
-
-       if ( 'all' == $args['get'] ) {
-               $args['childless'] = false;
-               $args['child_of'] = 0;
-               $args['hide_empty'] = 0;
-               $args['hierarchical'] = false;
-               $args['pad_counts'] = false;
-       }
-
-       /**
-        * Filter the terms query arguments.
-        *
-        * @since 3.1.0
-        *
-        * @param array $args       An array of get_terms() arguments.
-        * @param array $taxonomies An array of taxonomies.
-        */
-       $args = apply_filters( 'get_terms_args', $args, $taxonomies );
-
-       // Avoid the query if the queried parent/child_of term has no descendants.
-       $child_of = $args['child_of'];
-       $parent   = $args['parent'];
-
-       if ( $child_of ) {
-               $_parent = $child_of;
-       } elseif ( $parent ) {
-               $_parent = $parent;
-       } else {
-               $_parent = false;
-       }
-
-       if ( $_parent ) {
-               $in_hierarchy = false;
-               foreach ( $taxonomies as $_tax ) {
-                       $hierarchy = _get_term_hierarchy( $_tax );
-
-                       if ( isset( $hierarchy[ $_parent ] ) ) {
-                               $in_hierarchy = true;
-                       }
-               }
-
-               if ( ! $in_hierarchy ) {
-                       return $empty_array;
-               }
-       }
-
-       $_orderby = strtolower( $args['orderby'] );
-       if ( 'count' == $_orderby ) {
-               $orderby = 'tt.count';
-       } elseif ( 'name' == $_orderby ) {
-               $orderby = 't.name';
-       } elseif ( 'slug' == $_orderby ) {
-               $orderby = 't.slug';
-       } elseif ( 'include' == $_orderby && ! empty( $args['include'] ) ) {
-               $include = implode( ',', array_map( 'absint', $args['include'] ) );
-               $orderby = "FIELD( t.term_id, $include )";
-       } elseif ( 'term_group' == $_orderby ) {
-               $orderby = 't.term_group';
-       } elseif ( 'description' == $_orderby ) {
-               $orderby = 'tt.description';
-       } elseif ( 'none' == $_orderby ) {
-               $orderby = '';
-       } elseif ( empty( $_orderby ) || 'id' == $_orderby || 'term_id' === $_orderby ) {
-               $orderby = 't.term_id';
-       } else {
-               $orderby = 't.name';
-       }
-
-       /**
-        * Filter the ORDERBY clause of the terms query.
-        *
-        * @since 2.8.0
-        *
-        * @param string $orderby    `ORDERBY` clause of the terms query.
-        * @param array  $args       An array of terms query arguments.
-        * @param array  $taxonomies An array of taxonomies.
-        */
-       $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies );
-
-       $order = strtoupper( $args['order'] );
-       if ( ! empty( $orderby ) ) {
-               $orderby = "ORDER BY $orderby";
-       } else {
-               $order = '';
-       }
-
-       if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) {
-               $order = 'ASC';
-       }
-
-       $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
-
-       $exclude = $args['exclude'];
-       $exclude_tree = $args['exclude_tree'];
-       $include = $args['include'];
-
-       $inclusions = '';
-       if ( ! empty( $include ) ) {
-               $exclude = '';
-               $exclude_tree = '';
-               $inclusions = implode( ',', wp_parse_id_list( $include ) );
-       }
-
-       if ( ! empty( $inclusions ) ) {
-               $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )';
-               $where .= $inclusions;
-       }
-
-       $exclusions = array();
-       if ( ! empty( $exclude_tree ) ) {
-               $exclude_tree = wp_parse_id_list( $exclude_tree );
-               $excluded_children = $exclude_tree;
-               foreach ( $exclude_tree as $extrunk ) {
-                       $excluded_children = array_merge(
-                               $excluded_children,
-                               (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
-                       );
-               }
-               $exclusions = array_merge( $excluded_children, $exclusions );
-       }
-
-       if ( ! empty( $exclude ) ) {
-               $exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions );
-       }
-
-       // 'childless' terms are those without an entry in the flattened term hierarchy.
-       $childless = (bool) $args['childless'];
-       if ( $childless ) {
-               foreach ( $taxonomies as $_tax ) {
-                       $term_hierarchy = _get_term_hierarchy( $_tax );
-                       $exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions );
-               }
-       }
-
-       if ( ! empty( $exclusions ) ) {
-               $exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')';
-       } else {
-               $exclusions = '';
-       }
-
-       /**
-        * Filter the terms to exclude from the terms query.
-        *
-        * @since 2.3.0
-        *
-        * @param string $exclusions `NOT IN` clause of the terms query.
-        * @param array  $args       An array of terms query arguments.
-        * @param array  $taxonomies An array of taxonomies.
-        */
-       $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies );
-
-       if ( ! empty( $exclusions ) ) {
-               $where .= $exclusions;
-       }
-
-       if ( ! empty( $args['name'] ) ) {
-               $names = (array) $args['name'];
-               foreach ( $names as &$_name ) {
-                       $_name = sanitize_term_field( 'name', $_name, 0, reset( $taxonomies ), 'db' );
-               }
-
-               $where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $names ) ) . "')";
-       }
-
-       if ( ! empty( $args['slug'] ) ) {
-               if ( is_array( $args['slug'] ) ) {
-                       $slug = array_map( 'sanitize_title', $args['slug'] );
-                       $where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')";
-               } else {
-                       $slug = sanitize_title( $args['slug'] );
-                       $where .= " AND t.slug = '$slug'";
-               }
-       }
-
-       if ( ! empty( $args['name__like'] ) ) {
-               $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' );
-       }
-
-       if ( ! empty( $args['description__like'] ) ) {
-               $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' );
-       }
-
-       if ( '' !== $parent ) {
-               $parent = (int) $parent;
-               $where .= " AND tt.parent = '$parent'";
-       }
-
-       $hierarchical = $args['hierarchical'];
-       if ( 'count' == $args['fields'] ) {
-               $hierarchical = false;
-       }
-       if ( $args['hide_empty'] && !$hierarchical ) {
-               $where .= ' AND tt.count > 0';
-       }
-
-       $number = $args['number'];
-       $offset = $args['offset'];
-
-       // Don't limit the query results when we have to descend the family tree.
-       if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
-               if ( $offset ) {
-                       $limits = 'LIMIT ' . $offset . ',' . $number;
-               } else {
-                       $limits = 'LIMIT ' . $number;
-               }
-       } else {
-               $limits = '';
-       }
-
-       if ( ! empty( $args['search'] ) ) {
-               $like = '%' . $wpdb->esc_like( $args['search'] ) . '%';
-               $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like );
-       }
-
-       // Meta query support.
-       $join = '';
-       if ( ! empty( $args['meta_query'] ) ) {
-               $mquery = new WP_Meta_Query( $args['meta_query'] );
-               $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
-
-               $join  .= $mq_sql['join'];
-               $where .= $mq_sql['where'];
-       }
-
-       $selects = array();
-       switch ( $args['fields'] ) {
-               case 'all':
-                       $selects = array( 't.*', 'tt.*' );
-                       break;
-               case 'ids':
-               case 'id=>parent':
-                       $selects = array( 't.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy' );
-                       break;
-               case 'names':
-                       $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy' );
-                       break;
-               case 'count':
-                       $orderby = '';
-                       $order = '';
-                       $selects = array( 'COUNT(*)' );
-                       break;
-               case 'id=>name':
-                       $selects = array( 't.term_id', 't.name', 'tt.count', 'tt.taxonomy' );
-                       break;
-               case 'id=>slug':
-                       $selects = array( 't.term_id', 't.slug', 'tt.count', 'tt.taxonomy' );
-                       break;
-       }
-
-       $_fields = $args['fields'];
-
-       /**
-        * Filter the fields to select in the terms query.
-        *
-        * Field lists modified using this filter will only modify the term fields returned
-        * by the function when the `$fields` parameter set to 'count' or 'all'. In all other
-        * cases, the term fields in the results array will be determined by the `$fields`
-        * parameter alone.
-        *
-        * Use of this filter can result in unpredictable behavior, and is not recommended.
-        *
-        * @since 2.8.0
-        *
-        * @param array $selects    An array of fields to select for the terms query.
-        * @param array $args       An array of term query arguments.
-        * @param array $taxonomies An array of taxonomies.
-        */
-       $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) );
-
-       $join .= " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
-
-       $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
-
-       /**
-        * Filter the terms query SQL clauses.
-        *
-        * @since 3.1.0
-        *
-        * @param array $pieces     Terms query SQL clauses.
-        * @param array $taxonomies An array of taxonomies.
-        * @param array $args       An array of terms query arguments.
-        */
-       $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
-
-       $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
-       $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
-       $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
-       $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
-       $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : '';
-       $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
-
-       $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
-
-       // $args can be anything. Only use the args defined in defaults to compute the key.
-       $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $query );
-       $last_changed = wp_cache_get( 'last_changed', 'terms' );
-       if ( ! $last_changed ) {
-               $last_changed = microtime();
-               wp_cache_set( 'last_changed', $last_changed, 'terms' );
-       }
-       $cache_key = "get_terms:$key:$last_changed";
-       $cache = wp_cache_get( $cache_key, 'terms' );
-       if ( false !== $cache ) {
-               if ( 'all' === $_fields ) {
-                       $cache = array_map( 'get_term', $cache );
-               }
-
-               /**
-                * Filter the given taxonomy's terms cache.
-                *
-                * @since 2.3.0
-                *
-                * @param array $cache      Cached array of terms for the given taxonomy.
-                * @param array $taxonomies An array of taxonomies.
-                * @param array $args       An array of get_terms() arguments.
-                */
-               return apply_filters( 'get_terms', $cache, $taxonomies, $args );
-       }
-
-       if ( 'count' == $_fields ) {
-               return $wpdb->get_var( $query );
-       }
-
-       $terms = $wpdb->get_results($query);
-       if ( 'all' == $_fields ) {
-               update_term_cache( $terms );
-       }
-
-       // Prime termmeta cache.
-       if ( $args['update_term_meta_cache'] ) {
-               $term_ids = wp_list_pluck( $terms, 'term_id' );
-               update_termmeta_cache( $term_ids );
-       }
-
-       if ( empty($terms) ) {
-               wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
-
-               /** This filter is documented in wp-includes/taxonomy-functions.php */
-               return apply_filters( 'get_terms', array(), $taxonomies, $args );
-       }
-
-       if ( $child_of ) {
-               foreach ( $taxonomies as $_tax ) {
-                       $children = _get_term_hierarchy( $_tax );
-                       if ( ! empty( $children ) ) {
-                               $terms = _get_term_children( $child_of, $terms, $_tax );
-                       }
-               }
-       }
-
-       // Update term counts to include children.
-       if ( $args['pad_counts'] && 'all' == $_fields ) {
-               foreach ( $taxonomies as $_tax ) {
-                       _pad_term_counts( $terms, $_tax );
-               }
-       }
-
-       // Make sure we show empty categories that have children.
-       if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) {
-               foreach ( $terms as $k => $term ) {
-                       if ( ! $term->count ) {
-                               $children = get_term_children( $term->term_id, $term->taxonomy );
-                               if ( is_array( $children ) ) {
-                                       foreach ( $children as $child_id ) {
-                                               $child = get_term( $child_id, $term->taxonomy );
-                                               if ( $child->count ) {
-                                                       continue 2;
-                                               }
-                                       }
-                               }
-
-                               // It really is empty.
-                               unset($terms[$k]);
-                       }
-               }
-       }
-
-       $_terms = array();
-       if ( 'id=>parent' == $_fields ) {
-               foreach ( $terms as $term ) {
-                       $_terms[ $term->term_id ] = $term->parent;
-               }
-       } elseif ( 'ids' == $_fields ) {
-               foreach ( $terms as $term ) {
-                       $_terms[] = $term->term_id;
-               }
-       } elseif ( 'names' == $_fields ) {
-               foreach ( $terms as $term ) {
-                       $_terms[] = $term->name;
-               }
-       } elseif ( 'id=>name' == $_fields ) {
-               foreach ( $terms as $term ) {
-                       $_terms[ $term->term_id ] = $term->name;
-               }
-       } elseif ( 'id=>slug' == $_fields ) {
-               foreach ( $terms as $term ) {
-                       $_terms[ $term->term_id ] = $term->slug;
-               }
-       }
-
-       if ( ! empty( $_terms ) ) {
-               $terms = $_terms;
-       }
-
-       if ( $number && is_array( $terms ) && count( $terms ) > $number ) {
-               $terms = array_slice( $terms, $offset, $number );
-       }
-
-       wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
-
-       if ( 'all' === $_fields ) {
-               $terms = array_map( 'get_term', $terms );
-       }
-
-       /** This filter is documented in wp-includes/taxonomy-functions.php */
-       return apply_filters( 'get_terms', $terms, $taxonomies, $args );
-}
-
-/**
- * Adds metadata to a term.
- *
- * @since 4.4.0
- *
- * @param int    $term_id    Term ID.
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Metadata value.
- * @param bool   $unique     Optional. Whether to bail if an entry with the same key is found for the term.
- *                           Default false.
- * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies.
- *                           False on failure.
- */
-function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
-       // Bail if term meta table is not installed.
-       if ( get_option( 'db_version' ) < 34370 ) {
-               return false;
-       }
-
-       if ( wp_term_is_shared( $term_id ) ) {
-               return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
-       }
-
-       $added = add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique );
-
-       // Bust term query cache.
-       if ( $added ) {
-               wp_cache_set( 'last_changed', microtime(), 'terms' );
-       }
-
-       return $added;
-}
-
-/**
- * Removes metadata matching criteria from a term.
- *
- * @since 4.4.0
- *
- * @param int    $term_id    Term ID.
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
- * @return bool True on success, false on failure.
- */
-function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
-       // Bail if term meta table is not installed.
-       if ( get_option( 'db_version' ) < 34370 ) {
-               return false;
-       }
-
-       $deleted = delete_metadata( 'term', $term_id, $meta_key, $meta_value );
-
-       // Bust term query cache.
-       if ( $deleted ) {
-               wp_cache_set( 'last_changed', microtime(), 'terms' );
-       }
-
-       return $deleted;
-}
-
-/**
- * Retrieves metadata for a term.
- *
- * @since 4.4.0
- *
- * @param int    $term_id Term ID.
- * @param string $key     Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term.
- * @param bool   $single  Whether to return a single value. If false, an array of all values matching the
- *                        `$term_id`/`$key` pair will be returned. Default: false.
- * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
- */
-function get_term_meta( $term_id, $key = '', $single = false ) {
-       // Bail if term meta table is not installed.
-       if ( get_option( 'db_version' ) < 34370 ) {
-               return false;
-       }
-
-       return get_metadata( 'term', $term_id, $key, $single );
-}
-
-/**
- * Updates term metadata.
- *
- * Use the `$prev_value` parameter to differentiate between meta fields with the same key and term ID.
- *
- * If the meta field for the term does not exist, it will be added.
- *
- * @since 4.4.0
- *
- * @param int    $term_id    Term ID.
- * @param string $meta_key   Metadata key.
- * @param mixed  $meta_value Metadata value.
- * @param mixed  $prev_value Optional. Previous value to check before removing.
- * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update.
- *                           WP_Error when term_id is ambiguous between taxonomies. False on failure.
- */
-function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
-       // Bail if term meta table is not installed.
-       if ( get_option( 'db_version' ) < 34370 ) {
-               return false;
-       }
-
-       if ( wp_term_is_shared( $term_id ) ) {
-               return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
-       }
-
-       $updated = update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value );
-
-       // Bust term query cache.
-       if ( $updated ) {
-               wp_cache_set( 'last_changed', microtime(), 'terms' );
-       }
-
-       return $updated;
-}
-
-/**
- * Updates metadata cache for list of term IDs.
- *
- * Performs SQL query to retrieve all metadata for the terms matching `$term_ids` and stores them in the cache.
- * Subsequent calls to `get_term_meta()` will not need to query the database.
- *
- * @since 4.4.0
- *
- * @param array $term_ids List of term IDs.
- * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
- */
-function update_termmeta_cache( $term_ids ) {
-       // Bail if term meta table is not installed.
-       if ( get_option( 'db_version' ) < 34370 ) {
-               return;
-       }
-
-       return update_meta_cache( 'term', $term_ids );
-}
-
-/**
- * Check if Term exists.
- *
- * Formerly is_term(), introduced in 2.3.0.
- *
- * @since 3.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|string $term     The term to check
- * @param string     $taxonomy The taxonomy name to use
- * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
- * @return mixed Returns null if the term does not exist. Returns the term ID
- *               if no taxonomy is specified and the term ID exists. Returns
- *               an array of the term ID and the term taxonomy ID the taxonomy
- *               is specified and the pairing exists.
- */
-function term_exists( $term, $taxonomy = '', $parent = null ) {
-       global $wpdb;
-
-       $select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
-       $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
-
-       if ( is_int($term) ) {
-               if ( 0 == $term )
-                       return 0;
-               $where = 't.term_id = %d';
-               if ( !empty($taxonomy) )
-                       return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
-               else
-                       return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
-       }
-
-       $term = trim( wp_unslash( $term ) );
-       $slug = sanitize_title( $term );
-
-       $where = 't.slug = %s';
-       $else_where = 't.name = %s';
-       $where_fields = array($slug);
-       $else_where_fields = array($term);
-       $orderby = 'ORDER BY t.term_id ASC';
-       $limit = 'LIMIT 1';
-       if ( !empty($taxonomy) ) {
-               if ( is_numeric( $parent ) ) {
-                       $parent = (int) $parent;
-                       $where_fields[] = $parent;
-                       $else_where_fields[] = $parent;
-                       $where .= ' AND tt.parent = %d';
-                       $else_where .= ' AND tt.parent = %d';
-               }
-
-               $where_fields[] = $taxonomy;
-               $else_where_fields[] = $taxonomy;
-
-               if ( $result = $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s $orderby $limit", $where_fields), ARRAY_A) )
-                       return $result;
-
-               return $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s $orderby $limit", $else_where_fields), ARRAY_A);
-       }
-
-       if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields) ) )
-               return $result;
-
-       return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields) );
-}
-
-/**
- * Check if a term is an ancestor of another term.
- *
- * You can use either an id or the term object for both parameters.
- *
- * @since 3.4.0
- *
- * @param int|object $term1    ID or object to check if this is the parent term.
- * @param int|object $term2    The child term.
- * @param string     $taxonomy Taxonomy name that $term1 and `$term2` belong to.
- * @return bool Whether `$term2` is a child of `$term1`.
- */
-function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
-       if ( ! isset( $term1->term_id ) )
-               $term1 = get_term( $term1, $taxonomy );
-       if ( ! isset( $term2->parent ) )
-               $term2 = get_term( $term2, $taxonomy );
-
-       if ( empty( $term1->term_id ) || empty( $term2->parent ) )
-               return false;
-       if ( $term2->parent == $term1->term_id )
-               return true;
-
-       return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
-}
-
-/**
- * Sanitize Term all fields.
- *
- * Relies on sanitize_term_field() to sanitize the term. The difference is that
- * this function will sanitize <strong>all</strong> fields. The context is based
- * on sanitize_term_field().
- *
- * The $term is expected to be either an array or an object.
- *
- * @since 2.3.0
- *
- * @param array|object $term     The term to check.
- * @param string       $taxonomy The taxonomy name to use.
- * @param string       $context  Optional. Context in which to sanitize the term. Accepts 'edit', 'db',
- *                               'display', 'attribute', or 'js'. Default 'display'.
- * @return array|object Term with all fields sanitized.
- */
-function sanitize_term($term, $taxonomy, $context = 'display') {
-       $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
-
-       $do_object = is_object( $term );
-
-       $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
-
-       foreach ( (array) $fields as $field ) {
-               if ( $do_object ) {
-                       if ( isset($term->$field) )
-                               $term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
-               } else {
-                       if ( isset($term[$field]) )
-                               $term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
-               }
-       }
-
-       if ( $do_object )
-               $term->filter = $context;
-       else
-               $term['filter'] = $context;
-
-       return $term;
-}
-
-/**
- * Cleanse the field value in the term based on the context.
- *
- * Passing a term field value through the function should be assumed to have
- * cleansed the value for whatever context the term field is going to be used.
- *
- * If no context or an unsupported context is given, then default filters will
- * be applied.
- *
- * There are enough filters for each context to support a custom filtering
- * without creating your own filter function. Simply create a function that
- * hooks into the filter you need.
- *
- * @since 2.3.0
- *
- * @param string $field    Term field to sanitize.
- * @param string $value    Search for this term value.
- * @param int    $term_id  Term ID.
- * @param string $taxonomy Taxonomy Name.
- * @param string $context  Context in which to sanitize the term field. Accepts 'edit', 'db', 'display',
- *                         'attribute', or 'js'.
- * @return mixed Sanitized field.
- */
-function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
-       $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
-       if ( in_array( $field, $int_fields ) ) {
-               $value = (int) $value;
-               if ( $value < 0 )
-                       $value = 0;
-       }
-
-       if ( 'raw' == $context )
-               return $value;
-
-       if ( 'edit' == $context ) {
-
-               /**
-                * Filter a term field to edit before it is sanitized.
-                *
-                * The dynamic portion of the filter name, `$field`, refers to the term field.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed $value     Value of the term field.
-                * @param int   $term_id   Term ID.
-                * @param string $taxonomy Taxonomy slug.
-                */
-               $value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy );
-
-               /**
-                * Filter the taxonomy field to edit before it is sanitized.
-                *
-                * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
-                * to the taxonomy slug and taxonomy field, respectively.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed $value   Value of the taxonomy field to edit.
-                * @param int   $term_id Term ID.
-                */
-               $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
-
-               if ( 'description' == $field )
-                       $value = esc_html($value); // textarea_escaped
-               else
-                       $value = esc_attr($value);
-       } elseif ( 'db' == $context ) {
-
-               /**
-                * Filter a term field value before it is sanitized.
-                *
-                * The dynamic portion of the filter name, `$field`, refers to the term field.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed  $value    Value of the term field.
-                * @param string $taxonomy Taxonomy slug.
-                */
-               $value = apply_filters( "pre_term_{$field}", $value, $taxonomy );
-
-               /**
-                * Filter a taxonomy field before it is sanitized.
-                *
-                * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
-                * to the taxonomy slug and field name, respectively.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed $value Value of the taxonomy field.
-                */
-               $value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
-
-               // Back compat filters
-               if ( 'slug' == $field ) {
-                       /**
-                        * Filter the category nicename before it is sanitized.
-                        *
-                        * Use the pre_{$taxonomy}_{$field} hook instead.
-                        *
-                        * @since 2.0.3
-                        *
-                        * @param string $value The category nicename.
-                        */
-                       $value = apply_filters( 'pre_category_nicename', $value );
-               }
-
-       } elseif ( 'rss' == $context ) {
-
-               /**
-                * Filter the term field for use in RSS.
-                *
-                * The dynamic portion of the filter name, `$field`, refers to the term field.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed  $value    Value of the term field.
-                * @param string $taxonomy Taxonomy slug.
-                */
-               $value = apply_filters( "term_{$field}_rss", $value, $taxonomy );
-
-               /**
-                * Filter the taxonomy field for use in RSS.
-                *
-                * The dynamic portions of the hook name, `$taxonomy`, and `$field`, refer
-                * to the taxonomy slug and field name, respectively.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed $value Value of the taxonomy field.
-                */
-               $value = apply_filters( "{$taxonomy}_{$field}_rss", $value );
-       } else {
-               // Use display filters by default.
-
-               /**
-                * Filter the term field sanitized for display.
-                *
-                * The dynamic portion of the filter name, `$field`, refers to the term field name.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed  $value    Value of the term field.
-                * @param int    $term_id  Term ID.
-                * @param string $taxonomy Taxonomy slug.
-                * @param string $context  Context to retrieve the term field value.
-                */
-               $value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context );
-
-               /**
-                * Filter the taxonomy field sanitized for display.
-                *
-                * The dynamic portions of the filter name, `$taxonomy`, and `$field`, refer
-                * to the taxonomy slug and taxonomy field, respectively.
-                *
-                * @since 2.3.0
-                *
-                * @param mixed  $value   Value of the taxonomy field.
-                * @param int    $term_id Term ID.
-                * @param string $context Context to retrieve the taxonomy field value.
-                */
-               $value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
-       }
-
-       if ( 'attribute' == $context ) {
-               $value = esc_attr($value);
-       } elseif ( 'js' == $context ) {
-               $value = esc_js($value);
-       }
-       return $value;
-}
-
-/**
- * Count how many terms are in Taxonomy.
- *
- * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
- *
- * @todo Document $args as a hash notation.
- *
- * @since 2.3.0
- *
- * @param string       $taxonomy Taxonomy name
- * @param array|string $args     Overwrite defaults. See get_terms()
- * @return array|int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
- */
-function wp_count_terms( $taxonomy, $args = array() ) {
-       $defaults = array('hide_empty' => false);
-       $args = wp_parse_args($args, $defaults);
-
-       // backwards compatibility
-       if ( isset($args['ignore_empty']) ) {
-               $args['hide_empty'] = $args['ignore_empty'];
-               unset($args['ignore_empty']);
-       }
-
-       $args['fields'] = 'count';
-
-       return get_terms($taxonomy, $args);
-}
-
-/**
- * Will unlink the object from the taxonomy or taxonomies.
- *
- * Will remove all relationships between the object and any terms in
- * a particular taxonomy or taxonomies. Does not remove the term or
- * taxonomy itself.
- *
- * @since 2.3.0
- *
- * @param int          $object_id  The term Object Id that refers to the term.
- * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
- */
-function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
-       $object_id = (int) $object_id;
-
-       if ( !is_array($taxonomies) )
-               $taxonomies = array($taxonomies);
-
-       foreach ( (array) $taxonomies as $taxonomy ) {
-               $term_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids' ) );
-               $term_ids = array_map( 'intval', $term_ids );
-               wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
-       }
-}
-
-/**
- * Removes a term from the database.
- *
- * If the term is a parent of other terms, then the children will be updated to
- * that term's parent.
- *
- * Metadata associated with the term will be deleted.
- *
- * The `$args` 'default' will only override the terms found, if there is only one
- * term found. Any other and the found terms are used.
- *
- * The $args 'force_default' will force the term supplied as default to be
- * assigned even if the object was not going to be termless
- *
- * @todo Document $args as a hash notation.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int          $term     Term ID.
- * @param string       $taxonomy Taxonomy Name.
- * @param array|string $args     Optional. Change 'default' term id and override found term ids.
- * @return bool|int|WP_Error Returns false if not term; true if completes delete action.
- */
-function wp_delete_term( $term, $taxonomy, $args = array() ) {
-       global $wpdb;
-
-       $term = (int) $term;
-
-       if ( ! $ids = term_exists($term, $taxonomy) )
-               return false;
-       if ( is_wp_error( $ids ) )
-               return $ids;
-
-       $tt_id = $ids['term_taxonomy_id'];
-
-       $defaults = array();
-
-       if ( 'category' == $taxonomy ) {
-               $defaults['default'] = get_option( 'default_category' );
-               if ( $defaults['default'] == $term )
-                       return 0; // Don't delete the default category
-       }
-
-       $args = wp_parse_args($args, $defaults);
-
-       if ( isset( $args['default'] ) ) {
-               $default = (int) $args['default'];
-               if ( ! term_exists( $default, $taxonomy ) ) {
-                       unset( $default );
-               }
-       }
-
-       if ( isset( $args['force_default'] ) ) {
-               $force_default = $args['force_default'];
-       }
-
-       /**
-        * Fires when deleting a term, before any modifications are made to posts or terms.
-        *
-        * @since 4.1.0
-        *
-        * @param int    $term     Term ID.
-        * @param string $taxonomy Taxonomy Name.
-        */
-       do_action( 'pre_delete_term', $term, $taxonomy );
-
-       // Update children to point to new parent
-       if ( is_taxonomy_hierarchical($taxonomy) ) {
-               $term_obj = get_term($term, $taxonomy);
-               if ( is_wp_error( $term_obj ) )
-                       return $term_obj;
-               $parent = $term_obj->parent;
-
-               $edit_ids = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
-               $edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
-
-               /**
-                * Fires immediately before a term to delete's children are reassigned a parent.
-                *
-                * @since 2.9.0
-                *
-                * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
-                */
-               do_action( 'edit_term_taxonomies', $edit_tt_ids );
-
-               $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
-
-               // Clean the cache for all child terms.
-               $edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
-               clean_term_cache( $edit_term_ids, $taxonomy );
-
-               /**
-                * Fires immediately after a term to delete's children are reassigned a parent.
-                *
-                * @since 2.9.0
-                *
-                * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
-                */
-               do_action( 'edited_term_taxonomies', $edit_tt_ids );
-       }
-
-       // Get the term before deleting it or its term relationships so we can pass to actions below.
-       $deleted_term = get_term( $term, $taxonomy );
-
-       $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
-
-       foreach ( (array) $objects as $object ) {
-               $terms = wp_get_object_terms($object, $taxonomy, array('fields' => 'ids', 'orderby' => 'none'));
-               if ( 1 == count($terms) && isset($default) ) {
-                       $terms = array($default);
-               } else {
-                       $terms = array_diff($terms, array($term));
-                       if (isset($default) && isset($force_default) && $force_default)
-                               $terms = array_merge($terms, array($default));
-               }
-               $terms = array_map('intval', $terms);
-               wp_set_object_terms($object, $terms, $taxonomy);
-       }
-
-       // Clean the relationship caches for all object types using this term.
-       $tax_object = get_taxonomy( $taxonomy );
-       foreach ( $tax_object->object_type as $object_type )
-               clean_object_term_cache( $objects, $object_type );
-
-       $term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) );
-       foreach ( $term_meta_ids as $mid ) {
-               delete_metadata_by_mid( 'term', $mid );
-       }
-
-       /**
-        * Fires immediately before a term taxonomy ID is deleted.
-        *
-        * @since 2.9.0
-        *
-        * @param int $tt_id Term taxonomy ID.
-        */
-       do_action( 'delete_term_taxonomy', $tt_id );
-       $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
-
-       /**
-        * Fires immediately after a term taxonomy ID is deleted.
-        *
-        * @since 2.9.0
-        *
-        * @param int $tt_id Term taxonomy ID.
-        */
-       do_action( 'deleted_term_taxonomy', $tt_id );
-
-       // Delete the term if no taxonomies use it.
-       if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
-               $wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
-
-       clean_term_cache($term, $taxonomy);
-
-       /**
-        * Fires after a term is deleted from the database and the cache is cleaned.
-        *
-        * @since 2.5.0
-        *
-        * @param int     $term         Term ID.
-        * @param int     $tt_id        Term taxonomy ID.
-        * @param string  $taxonomy     Taxonomy slug.
-        * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
-        *                              by the parent function. WP_Error otherwise.
-        */
-       do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term );
-
-       /**
-        * Fires after a term in a specific taxonomy is deleted.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers to the specific
-        * taxonomy the term belonged to.
-        *
-        * @since 2.3.0
-        *
-        * @param int     $term         Term ID.
-        * @param int     $tt_id        Term taxonomy ID.
-        * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
-        *                              by the parent function. WP_Error otherwise.
-        */
-       do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
-
-       return true;
-}
-
-/**
- * Deletes one existing category.
- *
- * @since 2.0.0
- *
- * @param int $cat_ID
- * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
- *     Zero on attempted deletion of default Category; WP_Error object is also a possibility.
- */
-function wp_delete_category( $cat_ID ) {
-       return wp_delete_term( $cat_ID, 'category' );
-}
-
-/**
- * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
- *
- * @since 2.3.0
- * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`.
- *              Introduced `$parent` argument.
- * @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or
- *              'all_with_object_id', an array of `WP_Term` objects will be returned.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|array    $object_ids The ID(s) of the object(s) to retrieve.
- * @param string|array $taxonomies The taxonomies to retrieve terms from.
- * @param array|string $args {
- *     Array of arguments.
- *     @type string $orderby                Field by which results should be sorted. Accepts 'name', 'count', 'slug',
- *                                          'term_group', 'term_order', 'taxonomy', 'parent', or 'term_taxonomy_id'.
- *                                          Default 'name'.
- *     @type string $order                  Sort order. Accepts 'ASC' or 'DESC'. Default 'ASC'.
- *     @type string $fields                 Fields to return for matched terms. Accepts 'all', 'ids', 'names', and
- *                                          'all_with_object_id'. Note that 'all' or 'all_with_object_id' will result
- *                                          in an array of term objects being returned, 'ids' will return an array of
- *                                          integers, and 'names' an array of strings.
- *     @type int    $parent                 Optional. Limit results to the direct children of a given term ID.
- *     @type bool   $update_term_meta_cache Whether to prime termmeta cache for matched terms. Only applies when
- *                                          `$fields` is 'all', 'all_with_object_id', or 'term_id'. Default true.
- *     @type array  $meta_query             Meta query clauses to limit retrieved terms by. See `WP_Meta_Query`.
- *                                          Default empty.
- * }
- * @return array|WP_Error The requested term data or empty array if no terms found.
- *                        WP_Error if any of the $taxonomies don't exist.
- */
-function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
-       global $wpdb;
-
-       if ( empty( $object_ids ) || empty( $taxonomies ) )
-               return array();
-
-       if ( !is_array($taxonomies) )
-               $taxonomies = array($taxonomies);
-
-       foreach ( $taxonomies as $taxonomy ) {
-               if ( ! taxonomy_exists($taxonomy) )
-                       return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
-       }
-
-       if ( !is_array($object_ids) )
-               $object_ids = array($object_ids);
-       $object_ids = array_map('intval', $object_ids);
-
-       $defaults = array(
-               'orderby' => 'name',
-               'order'   => 'ASC',
-               'fields'  => 'all',
-               'parent'  => '',
-               'update_term_meta_cache' => true,
-               'meta_query' => '',
-       );
-       $args = wp_parse_args( $args, $defaults );
-
-       $terms = array();
-       if ( count($taxonomies) > 1 ) {
-               foreach ( $taxonomies as $index => $taxonomy ) {
-                       $t = get_taxonomy($taxonomy);
-                       if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) {
-                               unset($taxonomies[$index]);
-                               $terms = array_merge($terms, wp_get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args)));
-                       }
-               }
-       } else {
-               $t = get_taxonomy($taxonomies[0]);
-               if ( isset($t->args) && is_array($t->args) )
-                       $args = array_merge($args, $t->args);
-       }
-
-       $orderby = $args['orderby'];
-       $order = $args['order'];
-       $fields = $args['fields'];
-
-       if ( in_array( $orderby, array( 'term_id', 'name', 'slug', 'term_group' ) ) ) {
-               $orderby = "t.$orderby";
-       } elseif ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) {
-               $orderby = "tt.$orderby";
-       } elseif ( 'term_order' === $orderby ) {
-               $orderby = 'tr.term_order';
-       } elseif ( 'none' === $orderby ) {
-               $orderby = '';
-               $order = '';
-       } else {
-               $orderby = 't.term_id';
-       }
-
-       // tt_ids queries can only be none or tr.term_taxonomy_id
-       if ( ('tt_ids' == $fields) && !empty($orderby) )
-               $orderby = 'tr.term_taxonomy_id';
-
-       if ( !empty($orderby) )
-               $orderby = "ORDER BY $orderby";
-
-       $order = strtoupper( $order );
-       if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) )
-               $order = 'ASC';
-
-       $taxonomy_array = $taxonomies;
-       $object_id_array = $object_ids;
-       $taxonomies = "'" . implode("', '", $taxonomies) . "'";
-       $object_ids = implode(', ', $object_ids);
-
-       $select_this = '';
-       if ( 'all' == $fields ) {
-               $select_this = 't.*, tt.*';
-       } elseif ( 'ids' == $fields ) {
-               $select_this = 't.term_id';
-       } elseif ( 'names' == $fields ) {
-               $select_this = 't.name';
-       } elseif ( 'slugs' == $fields ) {
-               $select_this = 't.slug';
-       } elseif ( 'all_with_object_id' == $fields ) {
-               $select_this = 't.*, tt.*, tr.object_id';
-       }
-
-       $where = array(
-               "tt.taxonomy IN ($taxonomies)",
-               "tr.object_id IN ($object_ids)",
-       );
-
-       if ( '' !== $args['parent'] ) {
-               $where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] );
-       }
-
-       // Meta query support.
-       $meta_query_join = '';
-       if ( ! empty( $args['meta_query'] ) ) {
-               $mquery = new WP_Meta_Query( $args['meta_query'] );
-               $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
-
-               $meta_query_join .= $mq_sql['join'];
-
-               // Strip leading AND.
-               $where[] = preg_replace( '/^\s*AND/', '', $mq_sql['where'] );
-       }
-
-       $where = implode( ' AND ', $where );
-
-       $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id $meta_query_join WHERE $where $orderby $order";
-
-       $objects = false;
-       if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
-               $_terms = $wpdb->get_results( $query );
-               $object_id_index = array();
-               foreach ( $_terms as $key => $term ) {
-                       $term = sanitize_term( $term, $taxonomy, 'raw' );
-                       $_terms[ $key ] = $term;
-
-                       if ( isset( $term->object_id ) ) {
-                               $object_id_index[ $key ] = $term->object_id;
-                       }
-               }
-
-               update_term_cache( $_terms );
-               $_terms = array_map( 'get_term', $_terms );
-
-               // Re-add the object_id data, which is lost when fetching terms from cache.
-               if ( 'all_with_object_id' === $fields ) {
-                       foreach ( $_terms as $key => $_term ) {
-                               if ( isset( $object_id_index[ $key ] ) ) {
-                                       $_term->object_id = $object_id_index[ $key ];
-                               }
-                       }
-               }
-
-               $terms = array_merge( $terms, $_terms );
-               $objects = true;
-
-       } elseif ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) {
-               $_terms = $wpdb->get_col( $query );
-               $_field = ( 'ids' == $fields ) ? 'term_id' : 'name';
-               foreach ( $_terms as $key => $term ) {
-                       $_terms[$key] = sanitize_term_field( $_field, $term, $term, $taxonomy, 'raw' );
-               }
-               $terms = array_merge( $terms, $_terms );
-       } elseif ( 'tt_ids' == $fields ) {
-               $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
-               foreach ( $terms as $key => $tt_id ) {
-                       $terms[$key] = sanitize_term_field( 'term_taxonomy_id', $tt_id, 0, $taxonomy, 'raw' ); // 0 should be the term id, however is not needed when using raw context.
-               }
-       }
-
-       // Update termmeta cache, if necessary.
-       if ( $args['update_term_meta_cache'] && ( 'all' === $fields || 'all_with_object_ids' === $fields || 'term_id' === $fields ) ) {
-               if ( 'term_id' === $fields ) {
-                       $term_ids = $fields;
-               } else {
-                       $term_ids = wp_list_pluck( $terms, 'term_id' );
-               }
-
-               update_termmeta_cache( $term_ids );
-       }
-
-       if ( ! $terms ) {
-               $terms = array();
-       } elseif ( $objects && 'all_with_object_id' !== $fields ) {
-               $_tt_ids = array();
-               $_terms = array();
-               foreach ( $terms as $term ) {
-                       if ( in_array( $term->term_taxonomy_id, $_tt_ids ) ) {
-                               continue;
-                       }
-
-                       $_tt_ids[] = $term->term_taxonomy_id;
-                       $_terms[] = $term;
-               }
-               $terms = $_terms;
-       } elseif ( ! $objects ) {
-               $terms = array_values( array_unique( $terms ) );
-       }
-
-       /**
-        * Filter the terms for a given object or objects.
-        *
-        * @since 4.2.0
-        *
-        * @param array $terms           An array of terms for the given object or objects.
-        * @param array $object_id_array Array of object IDs for which `$terms` were retrieved.
-        * @param array $taxonomy_array  Array of taxonomies from which `$terms` were retrieved.
-        * @param array $args            An array of arguments for retrieving terms for the given
-        *                               object(s). See wp_get_object_terms() for details.
-        */
-       $terms = apply_filters( 'get_object_terms', $terms, $object_id_array, $taxonomy_array, $args );
-
-       /**
-        * Filter the terms for a given object or objects.
-        *
-        * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
-        * {@see 'get_object_terms'} filter is recommended as an alternative.
-        *
-        * @since 2.8.0
-        *
-        * @param array     $terms      An array of terms for the given object or objects.
-        * @param int|array $object_ids Object ID or array of IDs.
-        * @param string    $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names.
-        * @param array     $args       An array of arguments for retrieving terms for the given object(s).
-        *                              See {@see wp_get_object_terms()} for details.
-        */
-       return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
-}
-
-/**
- * Add a new term to the database.
- *
- * A non-existent term is inserted in the following sequence:
- * 1. The term is added to the term table, then related to the taxonomy.
- * 2. If everything is correct, several actions are fired.
- * 3. The 'term_id_filter' is evaluated.
- * 4. The term cache is cleaned.
- * 5. Several more actions are fired.
- * 6. An array is returned containing the term_id and term_taxonomy_id.
- *
- * If the 'slug' argument is not empty, then it is checked to see if the term
- * is invalid. If it is not a valid, existing term, it is added and the term_id
- * is given.
- *
- * If the taxonomy is hierarchical, and the 'parent' argument is not empty,
- * the term is inserted and the term_id will be given.
- *
- * Error handling:
- * If $taxonomy does not exist or $term is empty,
- * a WP_Error object will be returned.
- *
- * If the term already exists on the same hierarchical level,
- * or the term slug and name are not unique, a WP_Error object will be returned.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @since 2.3.0
- *
- * @param string       $term     The term to add or update.
- * @param string       $taxonomy The taxonomy to which to add the term.
- * @param array|string $args {
- *     Optional. Array or string of arguments for inserting a term.
- *
- *     @type string $alias_of    Slug of the term to make this term an alias of.
- *                               Default empty string. Accepts a term slug.
- *     @type string $description The term description. Default empty string.
- *     @type int    $parent      The id of the parent term. Default 0.
- *     @type string $slug        The term slug to use. Default empty string.
- * }
- * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`,
- *                        {@see WP_Error} otherwise.
- */
-function wp_insert_term( $term, $taxonomy, $args = array() ) {
-       global $wpdb;
-
-       if ( ! taxonomy_exists($taxonomy) ) {
-               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
-       }
-       /**
-        * Filter a term before it is sanitized and inserted into the database.
-        *
-        * @since 3.0.0
-        *
-        * @param string $term     The term to add or update.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       $term = apply_filters( 'pre_insert_term', $term, $taxonomy );
-       if ( is_wp_error( $term ) ) {
-               return $term;
-       }
-       if ( is_int($term) && 0 == $term ) {
-               return new WP_Error('invalid_term_id', __('Invalid term ID'));
-       }
-       if ( '' == trim($term) ) {
-               return new WP_Error('empty_term_name', __('A name is required for this term'));
-       }
-       $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
-       $args = wp_parse_args( $args, $defaults );
-
-       if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
-               return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
-       }
-       $args['name'] = $term;
-       $args['taxonomy'] = $taxonomy;
-       $args = sanitize_term($args, $taxonomy, 'db');
-
-       // expected_slashed ($name)
-       $name = wp_unslash( $args['name'] );
-       $description = wp_unslash( $args['description'] );
-       $parent = (int) $args['parent'];
-
-       $slug_provided = ! empty( $args['slug'] );
-       if ( ! $slug_provided ) {
-               $slug = sanitize_title( $name );
-       } else {
-               $slug = $args['slug'];
-       }
-
-       $term_group = 0;
-       if ( $args['alias_of'] ) {
-               $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
-               if ( ! empty( $alias->term_group ) ) {
-                       // The alias we want is already in a group, so let's use that one.
-                       $term_group = $alias->term_group;
-               } elseif ( ! empty( $alias->term_id ) ) {
-                       /*
-                        * The alias is not in a group, so we create a new one
-                        * and add the alias to it.
-                        */
-                       $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
-
-                       wp_update_term( $alias->term_id, $taxonomy, array(
-                               'term_group' => $term_group,
-                       ) );
-               }
-       }
-
-       /*
-        * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
-        * unless a unique slug has been explicitly provided.
-        */
-       $name_matches = get_terms( $taxonomy, array(
-               'name' => $name,
-               'hide_empty' => false,
-       ) );
-
-       /*
-        * The `name` match in `get_terms()` doesn't differentiate accented characters,
-        * so we do a stricter comparison here.
-        */
-       $name_match = null;
-       if ( $name_matches ) {
-               foreach ( $name_matches as $_match ) {
-                       if ( strtolower( $name ) === strtolower( $_match->name ) ) {
-                               $name_match = $_match;
-                               break;
-                       }
-               }
-       }
-
-       if ( $name_match ) {
-               $slug_match = get_term_by( 'slug', $slug, $taxonomy );
-               if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
-                       if ( is_taxonomy_hierarchical( $taxonomy ) ) {
-                               $siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) );
-
-                               $existing_term = null;
-                               if ( $name_match->slug === $slug && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
-                                       $existing_term = $name_match;
-                               } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
-                                       $existing_term = $slug_match;
-                               }
-
-                               if ( $existing_term ) {
-                                       return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id );
-                               }
-                       } else {
-                               return new WP_Error( 'term_exists', __( 'A term with the name provided already exists in this taxonomy.' ), $name_match->term_id );
-                       }
-               }
-       }
-
-       $slug = wp_unique_term_slug( $slug, (object) $args );
-
-       if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) {
-               return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error );
-       }
-
-       $term_id = (int) $wpdb->insert_id;
-
-       // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
-       if ( empty($slug) ) {
-               $slug = sanitize_title($slug, $term_id);
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edit_terms', $term_id, $taxonomy );
-               $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edited_terms', $term_id, $taxonomy );
-       }
-
-       $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
-
-       if ( !empty($tt_id) ) {
-               return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
-       }
-       $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
-       $tt_id = (int) $wpdb->insert_id;
-
-       /*
-        * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
-        * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
-        * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
-        * are not fired.
-        */
-       $duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) );
-       if ( $duplicate_term ) {
-               $wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
-               $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
-
-               $term_id = (int) $duplicate_term->term_id;
-               $tt_id   = (int) $duplicate_term->term_taxonomy_id;
-
-               clean_term_cache( $term_id, $taxonomy );
-               return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id );
-       }
-
-       /**
-        * Fires immediately after a new term is created, before the term cache is cleaned.
-        *
-        * @since 2.3.0
-        *
-        * @param int    $term_id  Term ID.
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( "create_term", $term_id, $tt_id, $taxonomy );
-
-       /**
-        * Fires after a new term is created for a specific taxonomy.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers
-        * to the slug of the taxonomy the term was created for.
-        *
-        * @since 2.3.0
-        *
-        * @param int $term_id Term ID.
-        * @param int $tt_id   Term taxonomy ID.
-        */
-       do_action( "create_$taxonomy", $term_id, $tt_id );
-
-       /**
-        * Filter the term ID after a new term is created.
-        *
-        * @since 2.3.0
-        *
-        * @param int $term_id Term ID.
-        * @param int $tt_id   Taxonomy term ID.
-        */
-       $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
-
-       clean_term_cache($term_id, $taxonomy);
-
-       /**
-        * Fires after a new term is created, and after the term cache has been cleaned.
-        *
-        * @since 2.3.0
-        *
-        * @param int    $term_id  Term ID.
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( 'created_term', $term_id, $tt_id, $taxonomy );
-
-       /**
-        * Fires after a new term in a specific taxonomy is created, and after the term
-        * cache has been cleaned.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
-        *
-        * @since 2.3.0
-        *
-        * @param int $term_id Term ID.
-        * @param int $tt_id   Term taxonomy ID.
-        */
-       do_action( "created_$taxonomy", $term_id, $tt_id );
-
-       return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
-}
-
-/**
- * Create Term and Taxonomy Relationships.
- *
- * Relates an object (post, link etc) to a term and taxonomy type. Creates the
- * term and taxonomy relationship if it doesn't already exist. Creates a term if
- * it doesn't exist (using the slug).
- *
- * A relationship means that the term is grouped in or belongs to the taxonomy.
- * A term has no meaning until it is given context by defining which taxonomy it
- * exists under.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb The WordPress database abstraction object.
- *
- * @param int              $object_id The object to relate to.
- * @param array|int|string $terms     A single term slug, single term id, or array of either term slugs or ids.
- *                                    Will replace all existing related terms in this taxonomy.
- * @param string           $taxonomy  The context in which to relate the term to the object.
- * @param bool             $append    Optional. If false will delete difference of terms. Default false.
- * @return array|WP_Error Affected Term IDs.
- */
-function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
-       global $wpdb;
-
-       $object_id = (int) $object_id;
-
-       if ( ! taxonomy_exists($taxonomy) )
-               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
-
-       if ( !is_array($terms) )
-               $terms = array($terms);
-
-       if ( ! $append )
-               $old_tt_ids =  wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'orderby' => 'none'));
-       else
-               $old_tt_ids = array();
-
-       $tt_ids = array();
-       $term_ids = array();
-       $new_tt_ids = array();
-
-       foreach ( (array) $terms as $term) {
-               if ( !strlen(trim($term)) )
-                       continue;
-
-               if ( !$term_info = term_exists($term, $taxonomy) ) {
-                       // Skip if a non-existent term ID is passed.
-                       if ( is_int($term) )
-                               continue;
-                       $term_info = wp_insert_term($term, $taxonomy);
-               }
-               if ( is_wp_error($term_info) )
-                       return $term_info;
-               $term_ids[] = $term_info['term_id'];
-               $tt_id = $term_info['term_taxonomy_id'];
-               $tt_ids[] = $tt_id;
-
-               if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) )
-                       continue;
-
-               /**
-                * Fires immediately before an object-term relationship is added.
-                *
-                * @since 2.9.0
-                *
-                * @param int $object_id Object ID.
-                * @param int $tt_id     Term taxonomy ID.
-                */
-               do_action( 'add_term_relationship', $object_id, $tt_id );
-               $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
-
-               /**
-                * Fires immediately after an object-term relationship is added.
-                *
-                * @since 2.9.0
-                *
-                * @param int $object_id Object ID.
-                * @param int $tt_id     Term taxonomy ID.
-                */
-               do_action( 'added_term_relationship', $object_id, $tt_id );
-               $new_tt_ids[] = $tt_id;
-       }
-
-       if ( $new_tt_ids )
-               wp_update_term_count( $new_tt_ids, $taxonomy );
-
-       if ( ! $append ) {
-               $delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
-
-               if ( $delete_tt_ids ) {
-                       $in_delete_tt_ids = "'" . implode( "', '", $delete_tt_ids ) . "'";
-                       $delete_term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT tt.term_id FROM $wpdb->term_taxonomy AS tt WHERE tt.taxonomy = %s AND tt.term_taxonomy_id IN ($in_delete_tt_ids)", $taxonomy ) );
-                       $delete_term_ids = array_map( 'intval', $delete_term_ids );
-
-                       $remove = wp_remove_object_terms( $object_id, $delete_term_ids, $taxonomy );
-                       if ( is_wp_error( $remove ) ) {
-                               return $remove;
-                       }
-               }
-       }
-
-       $t = get_taxonomy($taxonomy);
-       if ( ! $append && isset($t->sort) && $t->sort ) {
-               $values = array();
-               $term_order = 0;
-               $final_tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
-               foreach ( $tt_ids as $tt_id )
-                       if ( in_array($tt_id, $final_tt_ids) )
-                               $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
-               if ( $values )
-                       if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)" ) )
-                               return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error );
-       }
-
-       wp_cache_delete( $object_id, $taxonomy . '_relationships' );
-
-       /**
-        * Fires after an object's terms have been set.
-        *
-        * @since 2.8.0
-        *
-        * @param int    $object_id  Object ID.
-        * @param array  $terms      An array of object terms.
-        * @param array  $tt_ids     An array of term taxonomy IDs.
-        * @param string $taxonomy   Taxonomy slug.
-        * @param bool   $append     Whether to append new terms to the old terms.
-        * @param array  $old_tt_ids Old array of term taxonomy IDs.
-        */
-       do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids );
-       return $tt_ids;
-}
-
-/**
- * Add term(s) associated with a given object.
- *
- * @since 3.6.0
- *
- * @param int              $object_id The ID of the object to which the terms will be added.
- * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to add.
- * @param array|string     $taxonomy  Taxonomy name.
- * @return array|WP_Error Affected Term IDs
- */
-function wp_add_object_terms( $object_id, $terms, $taxonomy ) {
-       return wp_set_object_terms( $object_id, $terms, $taxonomy, true );
-}
-
-/**
- * Remove term(s) associated with a given object.
- *
- * @since 3.6.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int              $object_id The ID of the object from which the terms will be removed.
- * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to remove.
- * @param array|string     $taxonomy  Taxonomy name.
- * @return bool|WP_Error True on success, false or WP_Error on failure.
- */
-function wp_remove_object_terms( $object_id, $terms, $taxonomy ) {
-       global $wpdb;
-
-       $object_id = (int) $object_id;
-
-       if ( ! taxonomy_exists( $taxonomy ) ) {
-               return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
-       }
-
-       if ( ! is_array( $terms ) ) {
-               $terms = array( $terms );
-       }
-
-       $tt_ids = array();
-
-       foreach ( (array) $terms as $term ) {
-               if ( ! strlen( trim( $term ) ) ) {
-                       continue;
-               }
-
-               if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
-                       // Skip if a non-existent term ID is passed.
-                       if ( is_int( $term ) ) {
-                               continue;
-                       }
-               }
-
-               if ( is_wp_error( $term_info ) ) {
-                       return $term_info;
-               }
-
-               $tt_ids[] = $term_info['term_taxonomy_id'];
-       }
-
-       if ( $tt_ids ) {
-               $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
-
-               /**
-                * Fires immediately before an object-term relationship is deleted.
-                *
-                * @since 2.9.0
-                *
-                * @param int   $object_id Object ID.
-                * @param array $tt_ids    An array of term taxonomy IDs.
-                */
-               do_action( 'delete_term_relationships', $object_id, $tt_ids );
-               $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
-
-               wp_cache_delete( $object_id, $taxonomy . '_relationships' );
-
-               /**
-                * Fires immediately after an object-term relationship is deleted.
-                *
-                * @since 2.9.0
-                *
-                * @param int   $object_id Object ID.
-                * @param array $tt_ids    An array of term taxonomy IDs.
-                */
-               do_action( 'deleted_term_relationships', $object_id, $tt_ids );
-
-               wp_update_term_count( $tt_ids, $taxonomy );
-
-               return (bool) $deleted;
-       }
-
-       return false;
-}
-
-/**
- * Will make slug unique, if it isn't already.
- *
- * The `$slug` has to be unique global to every taxonomy, meaning that one
- * taxonomy term can't have a matching slug with another taxonomy term. Each
- * slug has to be globally unique for every taxonomy.
- *
- * The way this works is that if the taxonomy that the term belongs to is
- * hierarchical and has a parent, it will append that parent to the $slug.
- *
- * If that still doesn't return an unique slug, then it try to append a number
- * until it finds a number that is truly unique.
- *
- * The only purpose for `$term` is for appending a parent, if one exists.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $slug The string that will be tried for a unique slug.
- * @param object $term The term object that the `$slug` will belong to.
- * @return string Will return a true unique slug.
- */
-function wp_unique_term_slug( $slug, $term ) {
-       global $wpdb;
-
-       $needs_suffix = true;
-       $original_slug = $slug;
-
-       // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies.
-       if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
-               $needs_suffix = false;
-       }
-
-       /*
-        * If the taxonomy supports hierarchy and the term has a parent, make the slug unique
-        * by incorporating parent slugs.
-        */
-       $parent_suffix = '';
-       if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) {
-               $the_parent = $term->parent;
-               while ( ! empty($the_parent) ) {
-                       $parent_term = get_term($the_parent, $term->taxonomy);
-                       if ( is_wp_error($parent_term) || empty($parent_term) )
-                               break;
-                       $parent_suffix .= '-' . $parent_term->slug;
-                       if ( ! term_exists( $slug . $parent_suffix ) ) {
-                               break;
-                       }
-
-                       if ( empty($parent_term->parent) )
-                               break;
-                       $the_parent = $parent_term->parent;
-               }
-       }
-
-       // If we didn't get a unique slug, try appending a number to make it unique.
-
-       /**
-        * Filter whether the proposed unique term slug is bad.
-        *
-        * @since 4.3.0
-        *
-        * @param bool   $needs_suffix Whether the slug needs to be made unique with a suffix.
-        * @param string $slug         The slug.
-        * @param object $term         Term object.
-        */
-       if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
-               if ( $parent_suffix ) {
-                       $slug .= $parent_suffix;
-               } else {
-                       if ( ! empty( $term->term_id ) )
-                               $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
-                       else
-                               $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
-
-                       if ( $wpdb->get_var( $query ) ) {
-                               $num = 2;
-                               do {
-                                       $alt_slug = $slug . "-$num";
-                                       $num++;
-                                       $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
-                               } while ( $slug_check );
-                               $slug = $alt_slug;
-                       }
-               }
-       }
-
-       /**
-        * Filter the unique term slug.
-        *
-        * @since 4.3.0
-        *
-        * @param string $slug          Unique term slug.
-        * @param object $term          Term object.
-        * @param string $original_slug Slug originally passed to the function for testing.
-        */
-       return apply_filters( 'wp_unique_term_slug', $slug, $term, $original_slug );
-}
-
-/**
- * Update term based on arguments provided.
- *
- * The $args will indiscriminately override all values with the same field name.
- * Care must be taken to not override important information need to update or
- * update will fail (or perhaps create a new term, neither would be acceptable).
- *
- * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
- * defined in $args already.
- *
- * 'alias_of' will create a term group, if it doesn't already exist, and update
- * it for the $term.
- *
- * If the 'slug' argument in $args is missing, then the 'name' in $args will be
- * used. It should also be noted that if you set 'slug' and it isn't unique then
- * a WP_Error will be passed back. If you don't pass any slug, then a unique one
- * will be created for you.
- *
- * For what can be overrode in `$args`, check the term scheme can contain and stay
- * away from the term keys.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int          $term_id  The ID of the term
- * @param string       $taxonomy The context in which to relate the term to the object.
- * @param array|string $args     Optional. Array of get_terms() arguments. Default empty array.
- * @return array|WP_Error Returns Term ID and Taxonomy Term ID
- */
-function wp_update_term( $term_id, $taxonomy, $args = array() ) {
-       global $wpdb;
-
-       if ( ! taxonomy_exists( $taxonomy ) ) {
-               return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
-       }
-
-       $term_id = (int) $term_id;
-
-       // First, get all of the original args
-       $term = get_term( $term_id, $taxonomy );
-
-       if ( is_wp_error( $term ) ) {
-               return $term;
-       }
-
-       if ( ! $term ) {
-               return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
-       }
-
-       $term = (array) $term->data;
-
-       // Escape data pulled from DB.
-       $term = wp_slash( $term );
-
-       // Merge old and new args with new args overwriting old ones.
-       $args = array_merge($term, $args);
-
-       $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
-       $args = wp_parse_args($args, $defaults);
-       $args = sanitize_term($args, $taxonomy, 'db');
-       $parsed_args = $args;
-
-       // expected_slashed ($name)
-       $name = wp_unslash( $args['name'] );
-       $description = wp_unslash( $args['description'] );
-
-       $parsed_args['name'] = $name;
-       $parsed_args['description'] = $description;
-
-       if ( '' == trim($name) )
-               return new WP_Error('empty_term_name', __('A name is required for this term'));
-
-       if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) {
-               return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
-       }
-
-       $empty_slug = false;
-       if ( empty( $args['slug'] ) ) {
-               $empty_slug = true;
-               $slug = sanitize_title($name);
-       } else {
-               $slug = $args['slug'];
-       }
-
-       $parsed_args['slug'] = $slug;
-
-       $term_group = isset( $parsed_args['term_group'] ) ? $parsed_args['term_group'] : 0;
-       if ( $args['alias_of'] ) {
-               $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
-               if ( ! empty( $alias->term_group ) ) {
-                       // The alias we want is already in a group, so let's use that one.
-                       $term_group = $alias->term_group;
-               } elseif ( ! empty( $alias->term_id ) ) {
-                       /*
-                        * The alias is not in a group, so we create a new one
-                        * and add the alias to it.
-                        */
-                       $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
-
-                       wp_update_term( $alias->term_id, $taxonomy, array(
-                               'term_group' => $term_group,
-                       ) );
-               }
-
-               $parsed_args['term_group'] = $term_group;
-       }
-
-       /**
-        * Filter the term parent.
-        *
-        * Hook to this filter to see if it will cause a hierarchy loop.
-        *
-        * @since 3.1.0
-        *
-        * @param int    $parent      ID of the parent term.
-        * @param int    $term_id     Term ID.
-        * @param string $taxonomy    Taxonomy slug.
-        * @param array  $parsed_args An array of potentially altered update arguments for the given term.
-        * @param array  $args        An array of update arguments for the given term.
-        */
-       $parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args );
-
-       // Check for duplicate slug
-       $duplicate = get_term_by( 'slug', $slug, $taxonomy );
-       if ( $duplicate && $duplicate->term_id != $term_id ) {
-               // If an empty slug was passed or the parent changed, reset the slug to something unique.
-               // Otherwise, bail.
-               if ( $empty_slug || ( $parent != $term['parent']) )
-                       $slug = wp_unique_term_slug($slug, (object) $args);
-               else
-                       return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
-       }
-
-       $tt_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );
-
-       // Check whether this is a shared term that needs splitting.
-       $_term_id = _split_shared_term( $term_id, $tt_id );
-       if ( ! is_wp_error( $_term_id ) ) {
-               $term_id = $_term_id;
-       }
-
-       /**
-        * Fires immediately before the given terms are edited.
-        *
-        * @since 2.9.0
-        *
-        * @param int    $term_id  Term ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( 'edit_terms', $term_id, $taxonomy );
-       $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
-       if ( empty($slug) ) {
-               $slug = sanitize_title($name, $term_id);
-               $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
-       }
-
-       /**
-        * Fires immediately after the given terms are edited.
-        *
-        * @since 2.9.0
-        *
-        * @param int    $term_id  Term ID
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( 'edited_terms', $term_id, $taxonomy );
-
-       /**
-        * Fires immediate before a term-taxonomy relationship is updated.
-        *
-        * @since 2.9.0
-        *
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
-
-       $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
-
-       /**
-        * Fires immediately after a term-taxonomy relationship is updated.
-        *
-        * @since 2.9.0
-        *
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
-
-       // Clean the relationship caches for all object types using this term.
-       $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
-       $tax_object = get_taxonomy( $taxonomy );
-       foreach ( $tax_object->object_type as $object_type ) {
-               clean_object_term_cache( $objects, $object_type );
-       }
-
-       /**
-        * Fires after a term has been updated, but before the term cache has been cleaned.
-        *
-        * @since 2.3.0
-        *
-        * @param int    $term_id  Term ID.
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( "edit_term", $term_id, $tt_id, $taxonomy );
-
-       /**
-        * Fires after a term in a specific taxonomy has been updated, but before the term
-        * cache has been cleaned.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
-        *
-        * @since 2.3.0
-        *
-        * @param int $term_id Term ID.
-        * @param int $tt_id   Term taxonomy ID.
-        */
-       do_action( "edit_$taxonomy", $term_id, $tt_id );
-
-       /** This filter is documented in wp-includes/taxonomy-functions.php */
-       $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
-
-       clean_term_cache($term_id, $taxonomy);
-
-       /**
-        * Fires after a term has been updated, and the term cache has been cleaned.
-        *
-        * @since 2.3.0
-        *
-        * @param int    $term_id  Term ID.
-        * @param int    $tt_id    Term taxonomy ID.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       do_action( "edited_term", $term_id, $tt_id, $taxonomy );
-
-       /**
-        * Fires after a term for a specific taxonomy has been updated, and the term
-        * cache has been cleaned.
-        *
-        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
-        *
-        * @since 2.3.0
-        *
-        * @param int $term_id Term ID.
-        * @param int $tt_id   Term taxonomy ID.
-        */
-       do_action( "edited_$taxonomy", $term_id, $tt_id );
-
-       return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
-}
-
-/**
- * Enable or disable term counting.
- *
- * @since 2.5.0
- *
- * @staticvar bool $_defer
- *
- * @param bool $defer Optional. Enable if true, disable if false.
- * @return bool Whether term counting is enabled or disabled.
- */
-function wp_defer_term_counting($defer=null) {
-       static $_defer = false;
-
-       if ( is_bool($defer) ) {
-               $_defer = $defer;
-               // flush any deferred counts
-               if ( !$defer )
-                       wp_update_term_count( null, null, true );
-       }
-
-       return $_defer;
-}
-
-/**
- * Updates the amount of terms in taxonomy.
- *
- * If there is a taxonomy callback applied, then it will be called for updating
- * the count.
- *
- * The default action is to count what the amount of terms have the relationship
- * of term ID. Once that is done, then update the database.
- *
- * @since 2.3.0
- *
- * @staticvar array $_deferred
- *
- * @param int|array $terms    The term_taxonomy_id of the terms.
- * @param string    $taxonomy The context of the term.
- * @return bool If no terms will return false, and if successful will return true.
- */
-function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) {
-       static $_deferred = array();
-
-       if ( $do_deferred ) {
-               foreach ( (array) array_keys($_deferred) as $tax ) {
-                       wp_update_term_count_now( $_deferred[$tax], $tax );
-                       unset( $_deferred[$tax] );
-               }
-       }
-
-       if ( empty($terms) )
-               return false;
-
-       if ( !is_array($terms) )
-               $terms = array($terms);
-
-       if ( wp_defer_term_counting() ) {
-               if ( !isset($_deferred[$taxonomy]) )
-                       $_deferred[$taxonomy] = array();
-               $_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
-               return true;
-       }
-
-       return wp_update_term_count_now( $terms, $taxonomy );
-}
-
-/**
- * Perform term count update immediately.
- *
- * @since 2.5.0
- *
- * @param array  $terms    The term_taxonomy_id of terms to update.
- * @param string $taxonomy The context of the term.
- * @return true Always true when complete.
- */
-function wp_update_term_count_now( $terms, $taxonomy ) {
-       $terms = array_map('intval', $terms);
-
-       $taxonomy = get_taxonomy($taxonomy);
-       if ( !empty($taxonomy->update_count_callback) ) {
-               call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
-       } else {
-               $object_types = (array) $taxonomy->object_type;
-               foreach ( $object_types as &$object_type ) {
-                       if ( 0 === strpos( $object_type, 'attachment:' ) )
-                               list( $object_type ) = explode( ':', $object_type );
-               }
-
-               if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
-                       // Only post types are attached to this taxonomy
-                       _update_post_term_count( $terms, $taxonomy );
-               } else {
-                       // Default count updater
-                       _update_generic_term_count( $terms, $taxonomy );
-               }
-       }
-
-       clean_term_cache($terms, '', false);
-
-       return true;
-}
-
-//
-// Cache
-//
-
-/**
- * Removes the taxonomy relationship to terms from the cache.
- *
- * Will remove the entire taxonomy relationship containing term `$object_id`. The
- * term IDs have to exist within the taxonomy `$object_type` for the deletion to
- * take place.
- *
- * @since 2.3.0
- *
- * @see get_object_taxonomies() for more on $object_type.
- *
- * @param int|array    $object_ids  Single or list of term object ID(s).
- * @param array|string $object_type The taxonomy object type.
- */
-function clean_object_term_cache($object_ids, $object_type) {
-       if ( !is_array($object_ids) )
-               $object_ids = array($object_ids);
-
-       $taxonomies = get_object_taxonomies( $object_type );
-
-       foreach ( $object_ids as $id ) {
-               foreach ( $taxonomies as $taxonomy ) {
-                       wp_cache_delete($id, "{$taxonomy}_relationships");
-               }
-       }
-
-       /**
-        * Fires after the object term cache has been cleaned.
-        *
-        * @since 2.5.0
-        *
-        * @param array  $object_ids An array of object IDs.
-        * @param string $objet_type Object type.
-        */
-       do_action( 'clean_object_term_cache', $object_ids, $object_type );
-}
-
-/**
- * Will remove all of the term ids from the cache.
- *
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- * @global bool $_wp_suspend_cache_invalidation
- *
- * @param int|array $ids            Single or list of Term IDs.
- * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
- *                                  Default empty.
- * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
- *                                  term object caches (false). Default true.
- */
-function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
-       global $wpdb, $_wp_suspend_cache_invalidation;
-
-       if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
-               return;
-       }
-
-       if ( !is_array($ids) )
-               $ids = array($ids);
-
-       $taxonomies = array();
-       // If no taxonomy, assume tt_ids.
-       if ( empty($taxonomy) ) {
-               $tt_ids = array_map('intval', $ids);
-               $tt_ids = implode(', ', $tt_ids);
-               $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
-               $ids = array();
-               foreach ( (array) $terms as $term ) {
-                       $taxonomies[] = $term->taxonomy;
-                       $ids[] = $term->term_id;
-                       wp_cache_delete( $term->term_id, 'terms' );
-               }
-               $taxonomies = array_unique($taxonomies);
-       } else {
-               $taxonomies = array($taxonomy);
-               foreach ( $taxonomies as $taxonomy ) {
-                       foreach ( $ids as $id ) {
-                               wp_cache_delete( $id, 'terms' );
-                       }
-               }
-       }
-
-       foreach ( $taxonomies as $taxonomy ) {
-               if ( $clean_taxonomy ) {
-                       wp_cache_delete('all_ids', $taxonomy);
-                       wp_cache_delete('get', $taxonomy);
-                       delete_option("{$taxonomy}_children");
-                       // Regenerate {$taxonomy}_children
-                       _get_term_hierarchy($taxonomy);
-               }
-
-               /**
-                * Fires once after each taxonomy's term cache has been cleaned.
-                *
-                * @since 2.5.0
-                *
-                * @param array  $ids      An array of term IDs.
-                * @param string $taxonomy Taxonomy slug.
-                */
-               do_action( 'clean_term_cache', $ids, $taxonomy );
-       }
-
-       wp_cache_set( 'last_changed', microtime(), 'terms' );
-}
-
-/**
- * Retrieves the taxonomy relationship to the term object id.
- *
- * @since 2.3.0
- *
- * @param int    $id       Term object ID.
- * @param string $taxonomy Taxonomy name.
- * @return bool|mixed Empty array if $terms found, but not `$taxonomy`. False if nothing is in cache
- *                    for `$taxonomy` and `$id`.
- */
-function get_object_term_cache( $id, $taxonomy ) {
-       return wp_cache_get( $id, "{$taxonomy}_relationships" );
-}
-
-/**
- * Updates the cache for the given term object ID(s).
- *
- * Note: Due to performance concerns, great care should be taken to only update
- * term caches when necessary. Processing time can increase exponentially depending
- * on both the number of passed term IDs and the number of taxonomies those terms
- * belong to.
- *
- * Caches will only be updated for terms not already cached.
- *
- * @since 2.3.0
- *
- * @param string|array $object_ids  Comma-separated list or array of term object IDs.
- * @param array|string $object_type The taxonomy object type.
- * @return void|false False if all of the terms in `$object_ids` are already cached.
- */
-function update_object_term_cache($object_ids, $object_type) {
-       if ( empty($object_ids) )
-               return;
-
-       if ( !is_array($object_ids) )
-               $object_ids = explode(',', $object_ids);
-
-       $object_ids = array_map('intval', $object_ids);
-
-       $taxonomies = get_object_taxonomies($object_type);
-
-       $ids = array();
-       foreach ( (array) $object_ids as $id ) {
-               foreach ( $taxonomies as $taxonomy ) {
-                       if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
-                               $ids[] = $id;
-                               break;
-                       }
-               }
-       }
-
-       if ( empty( $ids ) )
-               return false;
-
-       $terms = wp_get_object_terms( $ids, $taxonomies, array(
-               'fields' => 'all_with_object_id',
-               'orderby' => 'none',
-               'update_term_meta_cache' => false,
-       ) );
-
-       $object_terms = array();
-       foreach ( (array) $terms as $term )
-               $object_terms[$term->object_id][$term->taxonomy][] = $term;
-
-       foreach ( $ids as $id ) {
-               foreach ( $taxonomies as $taxonomy ) {
-                       if ( ! isset($object_terms[$id][$taxonomy]) ) {
-                               if ( !isset($object_terms[$id]) )
-                                       $object_terms[$id] = array();
-                               $object_terms[$id][$taxonomy] = array();
-                       }
-               }
-       }
-
-       foreach ( $object_terms as $id => $value ) {
-               foreach ( $value as $taxonomy => $terms ) {
-                       wp_cache_add( $id, $terms, "{$taxonomy}_relationships" );
-               }
-       }
-}
-
-/**
- * Updates Terms to Taxonomy in cache.
- *
- * @since 2.3.0
- *
- * @param array  $terms    List of term objects to change.
- * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty.
- */
-function update_term_cache( $terms, $taxonomy = '' ) {
-       foreach ( (array) $terms as $term ) {
-               // Create a copy in case the array was passed by reference.
-               $_term = $term;
-
-               // Object ID should not be cached.
-               unset( $_term->object_id );
-
-               wp_cache_add( $term->term_id, $_term, 'terms' );
-       }
-}
-
-//
-// Private
-//
-
-/**
- * Retrieves children of taxonomy as Term IDs.
- *
- * @ignore
- * @since 2.3.0
- *
- * @param string $taxonomy Taxonomy name.
- * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
- */
-function _get_term_hierarchy( $taxonomy ) {
-       if ( !is_taxonomy_hierarchical($taxonomy) )
-               return array();
-       $children = get_option("{$taxonomy}_children");
-
-       if ( is_array($children) )
-               return $children;
-       $children = array();
-       $terms = get_terms($taxonomy, array('get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent'));
-       foreach ( $terms as $term_id => $parent ) {
-               if ( $parent > 0 )
-                       $children[$parent][] = $term_id;
-       }
-       update_option("{$taxonomy}_children", $children);
-
-       return $children;
-}
-
-/**
- * Get the subset of $terms that are descendants of $term_id.
- *
- * If `$terms` is an array of objects, then _get_term_children() returns an array of objects.
- * If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs.
- *
- * @access private
- * @since 2.3.0
- *
- * @param int    $term_id   The ancestor term: all returned terms should be descendants of `$term_id`.
- * @param array  $terms     The set of terms - either an array of term objects or term IDs - from which those that
- *                          are descendants of $term_id will be chosen.
- * @param string $taxonomy  The taxonomy which determines the hierarchy of the terms.
- * @param array  $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep
- *                          track of found terms when recursing the hierarchy. The array of located ancestors is used
- *                          to prevent infinite recursion loops. For performance, `term_ids` are used as array keys,
- *                          with 1 as value. Default empty array.
- * @return array|WP_Error The subset of $terms that are descendants of $term_id.
- */
-function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
-       $empty_array = array();
-       if ( empty($terms) )
-               return $empty_array;
-
-       $term_list = array();
-       $has_children = _get_term_hierarchy($taxonomy);
-
-       if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
-               return $empty_array;
-
-       // Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
-       if ( empty( $ancestors ) ) {
-               $ancestors[ $term_id ] = 1;
-       }
-
-       foreach ( (array) $terms as $term ) {
-               $use_id = false;
-               if ( !is_object($term) ) {
-                       $term = get_term($term, $taxonomy);
-                       if ( is_wp_error( $term ) )
-                               return $term;
-                       $use_id = true;
-               }
-
-               // Don't recurse if we've already identified the term as a child - this indicates a loop.
-               if ( isset( $ancestors[ $term->term_id ] ) ) {
-                       continue;
-               }
-
-               if ( $term->parent == $term_id ) {
-                       if ( $use_id )
-                               $term_list[] = $term->term_id;
-                       else
-                               $term_list[] = $term;
-
-                       if ( !isset($has_children[$term->term_id]) )
-                               continue;
-
-                       $ancestors[ $term->term_id ] = 1;
-
-                       if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors) )
-                               $term_list = array_merge($term_list, $children);
-               }
-       }
-
-       return $term_list;
-}
-
-/**
- * Add count of children to parent count.
- *
- * Recalculates term counts by including items from child terms. Assumes all
- * relevant children are already in the $terms argument.
- *
- * @access private
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array  $terms    List of term objects, passed by reference.
- * @param string $taxonomy Term context.
- */
-function _pad_term_counts( &$terms, $taxonomy ) {
-       global $wpdb;
-
-       // This function only works for hierarchical taxonomies like post categories.
-       if ( !is_taxonomy_hierarchical( $taxonomy ) )
-               return;
-
-       $term_hier = _get_term_hierarchy($taxonomy);
-
-       if ( empty($term_hier) )
-               return;
-
-       $term_items = array();
-       $terms_by_id = array();
-       $term_ids = array();
-
-       foreach ( (array) $terms as $key => $term ) {
-               $terms_by_id[$term->term_id] = & $terms[$key];
-               $term_ids[$term->term_taxonomy_id] = $term->term_id;
-       }
-
-       // Get the object and term ids and stick them in a lookup table.
-       $tax_obj = get_taxonomy($taxonomy);
-       $object_types = esc_sql($tax_obj->object_type);
-       $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
-       foreach ( $results as $row ) {
-               $id = $term_ids[$row->term_taxonomy_id];
-               $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
-       }
-
-       // Touch every ancestor's lookup row for each post in each term.
-       foreach ( $term_ids as $term_id ) {
-               $child = $term_id;
-               $ancestors = array();
-               while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
-                       $ancestors[] = $child;
-                       if ( !empty( $term_items[$term_id] ) )
-                               foreach ( $term_items[$term_id] as $item_id => $touches ) {
-                                       $term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
-                               }
-                       $child = $parent;
-
-                       if ( in_array( $parent, $ancestors ) ) {
-                               break;
-                       }
-               }
-       }
-
-       // Transfer the touched cells.
-       foreach ( (array) $term_items as $id => $items )
-               if ( isset($terms_by_id[$id]) )
-                       $terms_by_id[$id]->count = count($items);
-}
-
-//
-// Default callbacks
-//
-
-/**
- * Will update term count based on object types of the current taxonomy.
- *
- * Private function for the default callback for post_tag and category
- * taxonomies.
- *
- * @access private
- * @since 2.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array  $terms    List of Term taxonomy IDs.
- * @param object $taxonomy Current taxonomy object of terms.
- */
-function _update_post_term_count( $terms, $taxonomy ) {
-       global $wpdb;
-
-       $object_types = (array) $taxonomy->object_type;
-
-       foreach ( $object_types as &$object_type )
-               list( $object_type ) = explode( ':', $object_type );
-
-       $object_types = array_unique( $object_types );
-
-       if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
-               unset( $object_types[ $check_attachments ] );
-               $check_attachments = true;
-       }
-
-       if ( $object_types )
-               $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
-
-       foreach ( (array) $terms as $term ) {
-               $count = 0;
-
-               // Attachments can be 'inherit' status, we need to base count off the parent's status if so.
-               if ( $check_attachments )
-                       $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
-
-               if ( $object_types )
-                       $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
-               $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
-       }
-}
-
-/**
- * Will update term count based on number of objects.
- *
- * Default callback for the 'link_category' taxonomy.
- *
- * @since 3.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array  $terms    List of term taxonomy IDs.
- * @param object $taxonomy Current taxonomy object of terms.
- */
-function _update_generic_term_count( $terms, $taxonomy ) {
-       global $wpdb;
-
-       foreach ( (array) $terms as $term ) {
-               $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
-               $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
-
-               /** This action is documented in wp-includes/taxonomy-functions.php */
-               do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
-       }
-}
-
-/**
- * Create a new term for a term_taxonomy item that currently shares its term
- * with another term_taxonomy.
- *
- * @ignore
- * @since 4.2.0
- * @since 4.3.0 Introduced `$record` parameter. Also, `$term_id` and
- *              `$term_taxonomy_id` can now accept objects.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int|object $term_id          ID of the shared term, or the shared term object.
- * @param int|object $term_taxonomy_id ID of the term_taxonomy item to receive a new term, or the term_taxonomy object
- *                                     (corresponding to a row from the term_taxonomy table).
- * @param bool       $record           Whether to record data about the split term in the options table. The recording
- *                                     process has the potential to be resource-intensive, so during batch operations
- *                                     it can be beneficial to skip inline recording and do it just once, after the
- *                                     batch is processed. Only set this to `false` if you know what you are doing.
- *                                     Default: true.
- * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current
- *                      database schema), `$term_id` is returned. When the term is successfully split, the
- *                      new term_id is returned. A WP_Error is returned for miscellaneous errors.
- */
-function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) {
-       global $wpdb;
-
-       if ( is_object( $term_id ) ) {
-               $shared_term = $term_id;
-               $term_id = intval( $shared_term->term_id );
-       }
-
-       if ( is_object( $term_taxonomy_id ) ) {
-               $term_taxonomy = $term_taxonomy_id;
-               $term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
-       }
-
-       // If there are no shared term_taxonomy rows, there's nothing to do here.
-       $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) );
-
-       if ( ! $shared_tt_count ) {
-               return $term_id;
-       }
-
-       /*
-        * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id.
-        * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db.
-        */
-       $check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
-       if ( $check_term_id != $term_id ) {
-               return $check_term_id;
-       }
-
-       // Pull up data about the currently shared slug, which we'll use to populate the new one.
-       if ( empty( $shared_term ) ) {
-               $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
-       }
-
-       $new_term_data = array(
-               'name' => $shared_term->name,
-               'slug' => $shared_term->slug,
-               'term_group' => $shared_term->term_group,
-       );
-
-       if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) {
-               return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error );
-       }
-
-       $new_term_id = (int) $wpdb->insert_id;
-
-       // Update the existing term_taxonomy to point to the newly created term.
-       $wpdb->update( $wpdb->term_taxonomy,
-               array( 'term_id' => $new_term_id ),
-               array( 'term_taxonomy_id' => $term_taxonomy_id )
-       );
-
-       // Reassign child terms to the new parent.
-       if ( empty( $term_taxonomy ) ) {
-               $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
-       }
-
-       $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) );
-       if ( ! empty( $children_tt_ids ) ) {
-               foreach ( $children_tt_ids as $child_tt_id ) {
-                       $wpdb->update( $wpdb->term_taxonomy,
-                               array( 'parent' => $new_term_id ),
-                               array( 'term_taxonomy_id' => $child_tt_id )
-                       );
-                       clean_term_cache( $term_id, $term_taxonomy->taxonomy );
-               }
-       } else {
-               // If the term has no children, we must force its taxonomy cache to be rebuilt separately.
-               clean_term_cache( $new_term_id, $term_taxonomy->taxonomy );
-       }
-
-       // Clean the cache for term taxonomies formerly shared with the current term.
-       $shared_term_taxonomies = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
-       if ( $shared_term_taxonomies ) {
-               foreach ( $shared_term_taxonomies as $shared_term_taxonomy ) {
-                       clean_term_cache( $term_id, $shared_term_taxonomy );
-               }
-       }
-
-       // Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}.
-       if ( $record ) {
-               $split_term_data = get_option( '_split_terms', array() );
-               if ( ! isset( $split_term_data[ $term_id ] ) ) {
-                       $split_term_data[ $term_id ] = array();
-               }
-
-               $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id;
-               update_option( '_split_terms', $split_term_data );
-       }
-
-       // If we've just split the final shared term, set the "finished" flag.
-       $shared_terms_exist = $wpdb->get_results(
-               "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
-                LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
-                GROUP BY t.term_id
-                HAVING term_tt_count > 1
-                LIMIT 1"
-       );
-       if ( ! $shared_terms_exist ) {
-               update_option( 'finished_splitting_shared_terms', true );
-       }
-
-       /**
-        * Fires after a previously shared taxonomy term is split into two separate terms.
-        *
-        * @since 4.2.0
-        *
-        * @param int    $term_id          ID of the formerly shared term.
-        * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
-        * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
-        * @param string $taxonomy         Taxonomy for the split term.
-        */
-       do_action( 'split_shared_term', $term_id, $new_term_id, $term_taxonomy_id, $term_taxonomy->taxonomy );
-
-       return $new_term_id;
-}
-
-/**
- * Splits a batch of shared taxonomy terms.
- *
- * @since 4.3.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- */
-function _wp_batch_split_terms() {
-       global $wpdb;
-
-       $lock_name = 'term_split.lock';
-
-       // Try to lock.
-       $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
-
-       if ( ! $lock_result ) {
-               $lock_result = get_option( $lock_name );
-
-               // Bail if we were unable to create a lock, or if the existing lock is still valid.
-               if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) {
-                       wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
-                       return;
-               }
-       }
-
-       // Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
-       update_option( $lock_name, time() );
-
-       // Get a list of shared terms (those with more than one associated row in term_taxonomy).
-       $shared_terms = $wpdb->get_results(
-               "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
-                LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
-                GROUP BY t.term_id
-                HAVING term_tt_count > 1
-                LIMIT 10"
-       );
-
-       // No more terms, we're done here.
-       if ( ! $shared_terms ) {
-               update_option( 'finished_splitting_shared_terms', true );
-               delete_option( $lock_name );
-               return;
-       }
-
-       // Shared terms found? We'll need to run this script again.
-       wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
-
-       // Rekey shared term array for faster lookups.
-       $_shared_terms = array();
-       foreach ( $shared_terms as $shared_term ) {
-               $term_id = intval( $shared_term->term_id );
-               $_shared_terms[ $term_id ] = $shared_term;
-       }
-       $shared_terms = $_shared_terms;
-
-       // Get term taxonomy data for all shared terms.
-       $shared_term_ids = implode( ',', array_keys( $shared_terms ) );
-       $shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
-
-       // Split term data recording is slow, so we do it just once, outside the loop.
-       $split_term_data = get_option( '_split_terms', array() );
-       $skipped_first_term = $taxonomies = array();
-       foreach ( $shared_tts as $shared_tt ) {
-               $term_id = intval( $shared_tt->term_id );
-
-               // Don't split the first tt belonging to a given term_id.
-               if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
-                       $skipped_first_term[ $term_id ] = 1;
-                       continue;
-               }
-
-               if ( ! isset( $split_term_data[ $term_id ] ) ) {
-                       $split_term_data[ $term_id ] = array();
-               }
-
-               // Keep track of taxonomies whose hierarchies need flushing.
-               if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) {
-                       $taxonomies[ $shared_tt->taxonomy ] = 1;
-               }
-
-               // Split the term.
-               $split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false );
-       }
-
-       // Rebuild the cached hierarchy for each affected taxonomy.
-       foreach ( array_keys( $taxonomies ) as $tax ) {
-               delete_option( "{$tax}_children" );
-               _get_term_hierarchy( $tax );
-       }
-
-       update_option( '_split_terms', $split_term_data );
-
-       delete_option( $lock_name );
-}
-
-/**
- * In order to avoid the _wp_batch_split_terms() job being accidentally removed,
- * check that it's still scheduled while we haven't finished splitting terms.
- *
- * @ignore
- * @since 4.3.0
- */
-function _wp_check_for_scheduled_split_terms() {
-       if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_split_shared_term_batch' ) ) {
-               wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_split_shared_term_batch' );
-       }
-}
-
-/**
- * Check default categories when a term gets split to see if any of them need to be updated.
- *
- * @ignore
- * @since 4.2.0
- *
- * @param int    $term_id          ID of the formerly shared term.
- * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
- * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
- * @param string $taxonomy         Taxonomy for the split term.
- */
-function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
-       if ( 'category' != $taxonomy ) {
-               return;
-       }
-
-       foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) {
-               if ( $term_id == get_option( $option, -1 ) ) {
-                       update_option( $option, $new_term_id );
-               }
-       }
-}
-
-/**
- * Check menu items when a term gets split to see if any of them need to be updated.
- *
- * @ignore
- * @since 4.2.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int    $term_id          ID of the formerly shared term.
- * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
- * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
- * @param string $taxonomy         Taxonomy for the split term.
- */
-function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
-       global $wpdb;
-       $post_ids = $wpdb->get_col( $wpdb->prepare(
-               "SELECT m1.post_id
-               FROM {$wpdb->postmeta} AS m1
-                       INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id )
-                       INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id )
-               WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' )
-                       AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = '%s' )
-                       AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )",
-               $taxonomy,
-               $term_id
-       ) );
-
-       if ( $post_ids ) {
-               foreach ( $post_ids as $post_id ) {
-                       update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id );
-               }
-       }
-}
-
-/**
- * If the term being split is a nav_menu, change associations.
- *
- * @ignore
- * @since 4.3.0
- *
- * @param int    $term_id          ID of the formerly shared term.
- * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
- * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
- * @param string $taxonomy         Taxonomy for the split term.
- */
-function _wp_check_split_nav_menu_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
-       if ( 'nav_menu' !== $taxonomy ) {
-               return;
-       }
-
-       // Update menu locations.
-       $locations = get_nav_menu_locations();
-       foreach ( $locations as $location => $menu_id ) {
-               if ( $term_id == $menu_id ) {
-                       $locations[ $location ] = $new_term_id;
-               }
-       }
-       set_theme_mod( 'nav_menu_locations', $locations );
-}
-
-/**
- * Get data about terms that previously shared a single term_id, but have since been split.
- *
- * @since 4.2.0
- *
- * @param int $old_term_id Term ID. This is the old, pre-split term ID.
- * @return array Array of new term IDs, keyed by taxonomy.
- */
-function wp_get_split_terms( $old_term_id ) {
-       $split_terms = get_option( '_split_terms', array() );
-
-       $terms = array();
-       if ( isset( $split_terms[ $old_term_id ] ) ) {
-               $terms = $split_terms[ $old_term_id ];
-       }
-
-       return $terms;
-}
-
-/**
- * Get the new term ID corresponding to a previously split term.
- *
- * @since 4.2.0
- *
- * @param int    $old_term_id Term ID. This is the old, pre-split term ID.
- * @param string $taxonomy    Taxonomy that the term belongs to.
- * @return int|false If a previously split term is found corresponding to the old term_id and taxonomy,
- *                   the new term_id will be returned. If no previously split term is found matching
- *                   the parameters, returns false.
- */
-function wp_get_split_term( $old_term_id, $taxonomy ) {
-       $split_terms = wp_get_split_terms( $old_term_id );
-
-       $term_id = false;
-       if ( isset( $split_terms[ $taxonomy ] ) ) {
-               $term_id = (int) $split_terms[ $taxonomy ];
-       }
-
-       return $term_id;
-}
-
-/**
- * Determine whether a term is shared between multiple taxonomies.
- *
- * Shared taxonomy terms began to be split in 4.3, but failed cron tasks or other delays in upgrade routines may cause
- * shared terms to remain.
- *
- * @since 4.4.0
- *
- * @param int $term_id
- * @return bool
- */
-function wp_term_is_shared( $term_id ) {
-       global $wpdb;
-
-       if ( get_option( 'finished_splitting_shared_terms' ) ) {
-               return false;
-       }
-
-       $tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
-
-       return $tt_count > 1;
-}
-
-/**
- * Generate a permalink for a taxonomy term archive.
- *
- * @since 2.5.0
- *
- * @global WP_Rewrite $wp_rewrite
- *
- * @param object|int|string $term     The term object, ID, or slug whose link will be retrieved.
- * @param string            $taxonomy Optional. Taxonomy. Default empty.
- * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
- */
-function get_term_link( $term, $taxonomy = '' ) {
-       global $wp_rewrite;
-
-       if ( !is_object($term) ) {
-               if ( is_int( $term ) ) {
-                       $term = get_term( $term, $taxonomy );
-               } else {
-                       $term = get_term_by( 'slug', $term, $taxonomy );
-               }
-       }
-
-       if ( !is_object($term) )
-               $term = new WP_Error('invalid_term', __('Empty Term'));
-
-       if ( is_wp_error( $term ) )
-               return $term;
-
-       $taxonomy = $term->taxonomy;
-
-       $termlink = $wp_rewrite->get_extra_permastruct($taxonomy);
-
-       $slug = $term->slug;
-       $t = get_taxonomy($taxonomy);
-
-       if ( empty($termlink) ) {
-               if ( 'category' == $taxonomy )
-                       $termlink = '?cat=' . $term->term_id;
-               elseif ( $t->query_var )
-                       $termlink = "?$t->query_var=$slug";
-               else
-                       $termlink = "?taxonomy=$taxonomy&term=$slug";
-               $termlink = home_url($termlink);
-       } else {
-               if ( $t->rewrite['hierarchical'] ) {
-                       $hierarchical_slugs = array();
-                       $ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
-                       foreach ( (array)$ancestors as $ancestor ) {
-                               $ancestor_term = get_term($ancestor, $taxonomy);
-                               $hierarchical_slugs[] = $ancestor_term->slug;
-                       }
-                       $hierarchical_slugs = array_reverse($hierarchical_slugs);
-                       $hierarchical_slugs[] = $slug;
-                       $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
-               } else {
-                       $termlink = str_replace("%$taxonomy%", $slug, $termlink);
-               }
-               $termlink = home_url( user_trailingslashit($termlink, 'category') );
-       }
-       // Back Compat filters.
-       if ( 'post_tag' == $taxonomy ) {
-
-               /**
-                * Filter the tag link.
-                *
-                * @since 2.3.0
-                * @deprecated 2.5.0 Use 'term_link' instead.
-                *
-                * @param string $termlink Tag link URL.
-                * @param int    $term_id  Term ID.
-                */
-               $termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
-       } elseif ( 'category' == $taxonomy ) {
-
-               /**
-                * Filter the category link.
-                *
-                * @since 1.5.0
-                * @deprecated 2.5.0 Use 'term_link' instead.
-                *
-                * @param string $termlink Category link URL.
-                * @param int    $term_id  Term ID.
-                */
-               $termlink = apply_filters( 'category_link', $termlink, $term->term_id );
-       }
-
-       /**
-        * Filter the term link.
-        *
-        * @since 2.5.0
-        *
-        * @param string $termlink Term link URL.
-        * @param object $term     Term object.
-        * @param string $taxonomy Taxonomy slug.
-        */
-       return apply_filters( 'term_link', $termlink, $term, $taxonomy );
-}
-
-/**
- * Display the taxonomies of a post with available options.
- *
- * This function can be used within the loop to display the taxonomies for a
- * post without specifying the Post ID. You can also use it outside the Loop to
- * display the taxonomies for a specific post.
- *
- * @since 2.5.0
- *
- * @param array $args {
- *     Arguments about which post to use and how to format the output. Shares all of the arguments
- *     supported by get_the_taxonomies(), in addition to the following.
- *
- *     @type  int|WP_Post $post   Post ID or object to get taxonomies of. Default current post.
- *     @type  string      $before Displays before the taxonomies. Default empty string.
- *     @type  string      $sep    Separates each taxonomy. Default is a space.
- *     @type  string      $after  Displays after the taxonomies. Default empty string.
- * }
- * @param array $args See {@link get_the_taxonomies()} for a description of arguments and their defaults.
- */
-function the_taxonomies( $args = array() ) {
-       $defaults = array(
-               'post' => 0,
-               'before' => '',
-               'sep' => ' ',
-               'after' => '',
-       );
-
-       $r = wp_parse_args( $args, $defaults );
-
-       echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
-}
-
-/**
- * Retrieve all taxonomies associated with a post.
- *
- * This function can be used within the loop. It will also return an array of
- * the taxonomies with links to the taxonomy and name.
- *
- * @since 2.5.0
- *
- * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
- * @param array $args {
- *     Optional. Arguments about how to format the list of taxonomies. Default empty array.
- *
- *     @type string $template      Template for displaying a taxonomy label and list of terms.
- *                                 Default is "Label: Terms."
- *     @type string $term_template Template for displaying a single term in the list. Default is the term name
- *                                 linked to its archive.
- * }
- * @return array List of taxonomies.
- */
-function get_the_taxonomies( $post = 0, $args = array() ) {
-       $post = get_post( $post );
-
-       $args = wp_parse_args( $args, array(
-               /* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
-               'template' => __( '%s: %l.' ),
-               'term_template' => '<a href="%1$s">%2$s</a>',
-       ) );
-
-       $taxonomies = array();
-
-       if ( ! $post ) {
-               return $taxonomies;
-       }
-
-       foreach ( get_object_taxonomies( $post ) as $taxonomy ) {
-               $t = (array) get_taxonomy( $taxonomy );
-               if ( empty( $t['label'] ) ) {
-                       $t['label'] = $taxonomy;
-               }
-               if ( empty( $t['args'] ) ) {
-                       $t['args'] = array();
-               }
-               if ( empty( $t['template'] ) ) {
-                       $t['template'] = $args['template'];
-               }
-               if ( empty( $t['term_template'] ) ) {
-                       $t['term_template'] = $args['term_template'];
-               }
-
-               $terms = get_object_term_cache( $post->ID, $taxonomy );
-               if ( false === $terms ) {
-                       $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
-               }
-               $links = array();
-
-               foreach ( $terms as $term ) {
-                       $links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name );
-               }
-               if ( $links ) {
-                       $taxonomies[$taxonomy] = wp_sprintf( $t['template'], $t['label'], $links, $terms );
-               }
-       }
-       return $taxonomies;
-}
-
-/**
- * Retrieve all taxonomies of a post with just the names.
- *
- * @since 2.5.0
- *
- * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
- * @return array
- */
-function get_post_taxonomies( $post = 0 ) {
-       $post = get_post( $post );
-
-       return get_object_taxonomies($post);
-}
-
-/**
- * Determine if the given object is associated with any of the given terms.
- *
- * The given terms are checked against the object's terms' term_ids, names and slugs.
- * Terms given as integers will only be checked against the object's terms' term_ids.
- * If no terms are given, determines if object is associated with any terms in the given taxonomy.
- *
- * @since 2.7.0
- *
- * @param int              $object_id ID of the object (post ID, link ID, ...).
- * @param string           $taxonomy  Single taxonomy name.
- * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
- * @return bool|WP_Error WP_Error on input error.
- */
-function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
-       if ( !$object_id = (int) $object_id )
-               return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
-
-       $object_terms = get_object_term_cache( $object_id, $taxonomy );
-       if ( false === $object_terms ) {
-               $object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) );
-               wp_cache_set( $object_id, $object_terms, "{$taxonomy}_relationships" );
-       }
-
-       if ( is_wp_error( $object_terms ) )
-               return $object_terms;
-       if ( empty( $object_terms ) )
-               return false;
-       if ( empty( $terms ) )
-               return ( !empty( $object_terms ) );
-
-       $terms = (array) $terms;
-
-       if ( $ints = array_filter( $terms, 'is_int' ) )
-               $strs = array_diff( $terms, $ints );
-       else
-               $strs =& $terms;
-
-       foreach ( $object_terms as $object_term ) {
-               // If term is an int, check against term_ids only.
-               if ( $ints && in_array( $object_term->term_id, $ints ) ) {
-                       return true;
-               }
-
-               if ( $strs ) {
-                       // Only check numeric strings against term_id, to avoid false matches due to type juggling.
-                       $numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
-                       if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
-                               return true;
-                       }
-
-                       if ( in_array( $object_term->name, $strs ) ) return true;
-                       if ( in_array( $object_term->slug, $strs ) ) return true;
-               }
-       }
-
-       return false;
-}
-
-/**
- * Determine if the given object type is associated with the given taxonomy.
- *
- * @since 3.0.0
- *
- * @param string $object_type Object type string.
- * @param string $taxonomy    Single taxonomy name.
- * @return bool True if object is associated with the taxonomy, otherwise false.
- */
-function is_object_in_taxonomy( $object_type, $taxonomy ) {
-       $taxonomies = get_object_taxonomies( $object_type );
-       if ( empty( $taxonomies ) ) {
-               return false;
-       }
-       return in_array( $taxonomy, $taxonomies );
-}
-
-/**
- * Get an array of ancestor IDs for a given object.
- *
- * @since 3.1.0
- * @since 4.1.0 Introduced the `$resource_type` argument.
- *
- * @param int    $object_id     Optional. The ID of the object. Default 0.
- * @param string $object_type   Optional. The type of object for which we'll be retrieving
- *                              ancestors. Accepts a post type or a taxonomy name. Default empty.
- * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type'
- *                              or 'taxonomy'. Default empty.
- * @return array An array of ancestors from lowest to highest in the hierarchy.
- */
-function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) {
-       $object_id = (int) $object_id;
-
-       $ancestors = array();
-
-       if ( empty( $object_id ) ) {
-
-               /** This filter is documented in wp-includes/taxonomy-functions.php */
-               return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
-       }
-
-       if ( ! $resource_type ) {
-               if ( is_taxonomy_hierarchical( $object_type ) ) {
-                       $resource_type = 'taxonomy';
-               } elseif ( post_type_exists( $object_type ) ) {
-                       $resource_type = 'post_type';
-               }
-       }
-
-       if ( 'taxonomy' === $resource_type ) {
-               $term = get_term($object_id, $object_type);
-               while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
-                       $ancestors[] = (int) $term->parent;
-                       $term = get_term($term->parent, $object_type);
-               }
-       } elseif ( 'post_type' === $resource_type ) {
-               $ancestors = get_post_ancestors($object_id);
-       }
-
-       /**
-        * Filter a given object's ancestors.
-        *
-        * @since 3.1.0
-        * @since 4.1.1 Introduced the `$resource_type` parameter.
-        *
-        * @param array  $ancestors     An array of object ancestors.
-        * @param int    $object_id     Object ID.
-        * @param string $object_type   Type of object.
-        * @param string $resource_type Type of resource $object_type is.
-        */
-       return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
-}
-
-/**
- * Returns the term's parent's term_ID.
- *
- * @since 3.1.0
- *
- * @param int    $term_id  Term ID.
- * @param string $taxonomy Taxonomy name.
- * @return int|false False on error.
- */
-function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) {
-       $term = get_term( $term_id, $taxonomy );
-       if ( ! $term || is_wp_error( $term ) ) {
-               return false;
-       }
-       return (int) $term->parent;
-}
-
-/**
- * Checks the given subset of the term hierarchy for hierarchy loops.
- * Prevents loops from forming and breaks those that it finds.
- *
- * Attached to the {@see 'wp_update_term_parent'} filter.
- *
- * @since 3.1.0
- *
- * @param int    $parent   `term_id` of the parent for the term we're checking.
- * @param int    $term_id  The term we're checking.
- * @param string $taxonomy The taxonomy of the term we're checking.
- *
- * @return int The new parent for the term.
- */
-function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
-       // Nothing fancy here - bail
-       if ( !$parent )
-               return 0;
-
-       // Can't be its own parent.
-       if ( $parent == $term_id )
-               return 0;
-
-       // Now look for larger loops.
-       if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) )
-               return $parent; // No loop
-
-       // Setting $parent to the given value causes a loop.
-       if ( isset( $loop[$term_id] ) )
-               return 0;
-
-       // There's a loop, but it doesn't contain $term_id. Break the loop.
-       foreach ( array_keys( $loop ) as $loop_member )
-               wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) );
-
-       return $parent;
-}
</del></span></pre></div>
<a id="trunksrcwpincludestaxonomyphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/taxonomy.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/taxonomy.php        2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/taxonomy.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,17 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core Taxonomy API
- *
- * @package WordPress
- * @subpackage Taxonomy
- * @since 2.3.0
- */
-
-/** Core taxonomy functionality */
-require_once( ABSPATH . WPINC . '/taxonomy-functions.php' );
-
-/** WP_Term class */
-require_once( ABSPATH . WPINC . '/class-wp-term.php' );
-
-/** WP_Tax_Query class */
-require_once( ABSPATH . WPINC . '/class-wp-tax-query.php' );
</del></span></pre></div>
<a id="trunksrcwpincludestaxonomyphpfromrev35712trunksrcwpincludestaxonomyfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/taxonomy.php (from rev 35712, trunk/src/wp-includes/taxonomy-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/taxonomy.php                                (rev 0)
+++ trunk/src/wp-includes/taxonomy.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,4691 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core Taxonomy API
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ */
+
+//
+// Taxonomy Registration
+//
+
+/**
+ * Creates the initial taxonomies.
+ *
+ * This function fires twice: in wp-settings.php before plugins are loaded (for
+ * backwards compatibility reasons), and again on the {@see 'init'} action. We must
+ * avoid registering rewrite rules before the {@see 'init'} action.
+ *
+ * @since 2.8.0
+ *
+ * @global WP_Rewrite $wp_rewrite The WordPress rewrite class.
+ */
+function create_initial_taxonomies() {
+       global $wp_rewrite;
+
+       if ( ! did_action( 'init' ) ) {
+               $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
+       } else {
+
+               /**
+                * Filter the post formats rewrite base.
+                *
+                * @since 3.1.0
+                *
+                * @param string $context Context of the rewrite base. Default 'type'.
+                */
+               $post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
+               $rewrite = array(
+                       'category' => array(
+                               'hierarchical' => true,
+                               'slug' => get_option('category_base') ? get_option('category_base') : 'category',
+                               'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
+                               'ep_mask' => EP_CATEGORIES,
+                       ),
+                       'post_tag' => array(
+                               'hierarchical' => false,
+                               'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
+                               'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
+                               'ep_mask' => EP_TAGS,
+                       ),
+                       'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
+               );
+       }
+
+       register_taxonomy( 'category', 'post', array(
+               'hierarchical' => true,
+               'query_var' => 'category_name',
+               'rewrite' => $rewrite['category'],
+               'public' => true,
+               'show_ui' => true,
+               'show_admin_column' => true,
+               '_builtin' => true,
+       ) );
+
+       register_taxonomy( 'post_tag', 'post', array(
+               'hierarchical' => false,
+               'query_var' => 'tag',
+               'rewrite' => $rewrite['post_tag'],
+               'public' => true,
+               'show_ui' => true,
+               'show_admin_column' => true,
+               '_builtin' => true,
+       ) );
+
+       register_taxonomy( 'nav_menu', 'nav_menu_item', array(
+               'public' => false,
+               'hierarchical' => false,
+               'labels' => array(
+                       'name' => __( 'Navigation Menus' ),
+                       'singular_name' => __( 'Navigation Menu' ),
+               ),
+               'query_var' => false,
+               'rewrite' => false,
+               'show_ui' => false,
+               '_builtin' => true,
+               'show_in_nav_menus' => false,
+       ) );
+
+       register_taxonomy( 'link_category', 'link', array(
+               'hierarchical' => false,
+               'labels' => array(
+                       'name' => __( 'Link Categories' ),
+                       'singular_name' => __( 'Link Category' ),
+                       'search_items' => __( 'Search Link Categories' ),
+                       'popular_items' => null,
+                       'all_items' => __( 'All Link Categories' ),
+                       'edit_item' => __( 'Edit Link Category' ),
+                       'update_item' => __( 'Update Link Category' ),
+                       'add_new_item' => __( 'Add New Link Category' ),
+                       'new_item_name' => __( 'New Link Category Name' ),
+                       'separate_items_with_commas' => null,
+                       'add_or_remove_items' => null,
+                       'choose_from_most_used' => null,
+               ),
+               'capabilities' => array(
+                       'manage_terms' => 'manage_links',
+                       'edit_terms'   => 'manage_links',
+                       'delete_terms' => 'manage_links',
+                       'assign_terms' => 'manage_links',
+               ),
+               'query_var' => false,
+               'rewrite' => false,
+               'public' => false,
+               'show_ui' => true,
+               '_builtin' => true,
+       ) );
+
+       register_taxonomy( 'post_format', 'post', array(
+               'public' => true,
+               'hierarchical' => false,
+               'labels' => array(
+                       'name' => _x( 'Format', 'post format' ),
+                       'singular_name' => _x( 'Format', 'post format' ),
+               ),
+               'query_var' => true,
+               'rewrite' => $rewrite['post_format'],
+               'show_ui' => false,
+               '_builtin' => true,
+               'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
+       ) );
+}
+
+/**
+ * Retrieves a list of registered taxonomy names or objects.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param array  $args     Optional. An array of `key => value` arguments to match against the taxonomy objects.
+ *                         Default empty array.
+ * @param string $output   Optional. The type of output to return in the array. Accepts either taxonomy 'names'
+ *                         or 'objects'. Default 'names'.
+ * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only
+ *                         one element from the array needs to match; 'and' means all elements must match.
+ *                         Default 'and'.
+ * @return array A list of taxonomy names or objects.
+ */
+function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
+       global $wp_taxonomies;
+
+       $field = ('names' == $output) ? 'name' : false;
+
+       return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
+}
+
+/**
+ * Return all of the taxonomy names that are of $object_type.
+ *
+ * It appears that this function can be used to find all of the names inside of
+ * $wp_taxonomies global variable.
+ *
+ * `<?php $taxonomies = get_object_taxonomies('post'); ?>` Should
+ * result in `Array( 'category', 'post_tag' )`
+ *
+ * @since 2.3.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts)
+ * @param string               $output Optional. The type of output to return in the array. Accepts either
+ *                                     taxonomy 'names' or 'objects'. Default 'names'.
+ * @return array The names of all taxonomy of $object_type.
+ */
+function get_object_taxonomies( $object, $output = 'names' ) {
+       global $wp_taxonomies;
+
+       if ( is_object($object) ) {
+               if ( $object->post_type == 'attachment' )
+                       return get_attachment_taxonomies($object);
+               $object = $object->post_type;
+       }
+
+       $object = (array) $object;
+
+       $taxonomies = array();
+       foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
+               if ( array_intersect($object, (array) $tax_obj->object_type) ) {
+                       if ( 'names' == $output )
+                               $taxonomies[] = $tax_name;
+                       else
+                               $taxonomies[ $tax_name ] = $tax_obj;
+               }
+       }
+
+       return $taxonomies;
+}
+
+/**
+ * Retrieves the taxonomy object of $taxonomy.
+ *
+ * The get_taxonomy function will first check that the parameter string given
+ * is a taxonomy object and if it is, it will return it.
+ *
+ * @since 2.3.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param string $taxonomy Name of taxonomy object to return.
+ * @return object|false The Taxonomy Object or false if $taxonomy doesn't exist.
+ */
+function get_taxonomy( $taxonomy ) {
+       global $wp_taxonomies;
+
+       if ( ! taxonomy_exists( $taxonomy ) )
+               return false;
+
+       return $wp_taxonomies[$taxonomy];
+}
+
+/**
+ * Checks that the taxonomy name exists.
+ *
+ * Formerly is_taxonomy(), introduced in 2.3.0.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param string $taxonomy Name of taxonomy object.
+ * @return bool Whether the taxonomy exists.
+ */
+function taxonomy_exists( $taxonomy ) {
+       global $wp_taxonomies;
+
+       return isset( $wp_taxonomies[$taxonomy] );
+}
+
+/**
+ * Whether the taxonomy object is hierarchical.
+ *
+ * Checks to make sure that the taxonomy is an object first. Then Gets the
+ * object, and finally returns the hierarchical value in the object.
+ *
+ * A false return value might also mean that the taxonomy does not exist.
+ *
+ * @since 2.3.0
+ *
+ * @param string $taxonomy Name of taxonomy object.
+ * @return bool Whether the taxonomy is hierarchical.
+ */
+function is_taxonomy_hierarchical($taxonomy) {
+       if ( ! taxonomy_exists($taxonomy) )
+               return false;
+
+       $taxonomy = get_taxonomy($taxonomy);
+       return $taxonomy->hierarchical;
+}
+
+/**
+ * Creates or modifies a taxonomy object.
+ *
+ * Note: Do not use before the {@see 'init'} hook.
+ *
+ * A simple function for creating or modifying a taxonomy object based on the
+ * parameters given. The function will accept an array (third optional
+ * parameter), along with strings for the taxonomy name and another string for
+ * the object type.
+ *
+ * @since 2.3.0
+ * @since 4.2.0 Introduced `show_in_quick_edit` argument.
+ * @since 4.4.0 The `show_ui` argument is now enforced on the term editing screen.
+ * @since 4.4.0 The `public` argument now controls whether the taxonomy can be queried on the front-end.
+ *
+ * @global array $wp_taxonomies Registered taxonomies.
+ * @global WP    $wp            WP instance.
+ *
+ * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
+ * @param array|string $object_type Name of the object type for the taxonomy object.
+ * @param array|string $args        {
+ *     Optional. Array or query string of arguments for registering a taxonomy.
+ *
+ *     @type string        $label                 Name of the taxonomy shown in the menu. Usually plural. If not set,
+ *                                                `$labels['name']` will be used.
+ *     @type array         $labels                An array of labels for this taxonomy. By default, Tag labels are used for
+ *                                                non-hierarchical taxonmies, and Category labels are used for hierarchical
+ *                                                taxonomies. See accepted values in get_taxonomy_labels().
+ *                                                Default empty array.
+ *     @type string        $description           A short descriptive summary of what the taxonomy is for. Default empty.
+ *     @type bool          $public                Whether the taxonomy is publicly queryable. Default true.
+ *     @type bool          $hierarchical          Whether the taxonomy is hierarchical. Default false.
+ *     @type bool          $show_ui               Whether to generate and allow a UI for managing terms in this taxonomy in
+ *                                                the admin. If not set, the default is inherited from `$public`
+ *                                                (default true).
+ *     @type bool          $show_in_menu          Whether to show the taxonomy in the admin menu. If true, the taxonomy is
+ *                                                shown as a submenu of the object type menu. If false, no menu is shown.
+ *                                                `$show_ui` must be true. If not set, default is inherited from `$show_ui`
+ *                                                (default true).
+ *     @type bool          $show_in_nav_menus     Makes this taxonomy available for selection in navigation menus. If not
+ *                                                set, the default is inherited from `$public` (default true).
+ *     @type bool          $show_tagcloud         Whether to list the taxonomy in the Tag Cloud Widget controls. If not set,
+ *                                                the default is inherited from `$show_ui` (default true).
+ *     @type bool          $show_in_quick_edit    Whether to show the taxonomy in the quick/bulk edit panel. It not set,
+ *                                                the default is inherited from `$show_ui` (default true).
+ *     @type bool          $show_admin_column     Whether to display a column for the taxonomy on its post type listing
+ *                                                screens. Default false.
+ *     @type bool|callable $meta_box_cb           Provide a callback function for the meta box display. If not set,
+ *                                                post_categories_meta_box() is used for hierarchical taxonomies, and
+ *                                                post_tags_meta_box() is used for non-hierarchical. If false, no meta
+ *                                                box is shown.
+ *     @type array         $capabilities {
+ *         Array of capabilities for this taxonomy.
+ *
+ *         @type string $manage_terms Default 'manage_categories'.
+ *         @type string $edit_terms   Default 'manage_categories'.
+ *         @type string $delete_terms Default 'manage_categories'.
+ *         @type string $assign_terms Default 'edit_posts'.
+ *     }
+ *     @type bool|array    $rewrite {
+ *         Triggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent
+ *         rewrite, set to false. To specify rewrite rules, an array can be passed with any of these keys:
+ *
+ *         @type string $slug         Customize the permastruct slug. Default `$taxonomy` key.
+ *         @type bool   $with_front   Should the permastruct be prepended with WP_Rewrite::$front. Default true.
+ *         @type bool   $hierarchical Either hierarchical rewrite tag or not. Default false.
+ *         @type int    $ep_mask      Assign an endpoint mask. Default `EP_NONE`.
+ *     }
+ *     @type string        $query_var             Sets the query var key for this taxonomy. Default `$taxonomy` key. If
+ *                                                false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a
+ *                                                string, the query `?{query_var}={term_slug}` will be valid.
+ *     @type callable      $update_count_callback Works much like a hook, in that it will be called when the count is
+ *                                                updated. Default _update_post_term_count() for taxonomies attached
+ *                                                to post types, which confirms that the objects are published before
+ *                                                counting them. Default _update_generic_term_count() for taxonomies
+ *                                                attached to other object types, such as users.
+ *     @type bool          $_builtin              This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY!
+ *                                                Default false.
+ * }
+ * @return WP_Error|void WP_Error, if errors.
+ */
+function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
+       global $wp_taxonomies, $wp;
+
+       if ( ! is_array( $wp_taxonomies ) )
+               $wp_taxonomies = array();
+
+       $args = wp_parse_args( $args );
+
+       /**
+        * Filter the arguments for registering a taxonomy.
+        *
+        * @since 4.4.0
+        *
+        * @param array  $args        Array of arguments for registering a taxonomy.
+        * @param array  $object_type Array of names of object types for the taxonomy.
+        * @param string $taxonomy    Taxonomy key.
+        */
+       $args = apply_filters( 'register_taxonomy_args', $args, $taxonomy, (array) $object_type );
+
+       $defaults = array(
+               'labels'                => array(),
+               'description'           => '',
+               'public'                => true,
+               'hierarchical'          => false,
+               'show_ui'               => null,
+               'show_in_menu'          => null,
+               'show_in_nav_menus'     => null,
+               'show_tagcloud'         => null,
+               'show_in_quick_edit'    => null,
+               'show_admin_column'     => false,
+               'meta_box_cb'           => null,
+               'capabilities'          => array(),
+               'rewrite'               => true,
+               'query_var'             => $taxonomy,
+               'update_count_callback' => '',
+               '_builtin'              => false,
+       );
+       $args = array_merge( $defaults, $args );
+
+       if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
+               _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2' );
+               return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) );
+       }
+
+       // Non-public taxonomies should not register query vars, except in the admin.
+       if ( false !== $args['query_var'] && ( is_admin() || false !== $args['public'] ) && ! empty( $wp ) ) {
+               if ( true === $args['query_var'] )
+                       $args['query_var'] = $taxonomy;
+               else
+                       $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] );
+               $wp->add_query_var( $args['query_var'] );
+       }
+
+       if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
+               $args['rewrite'] = wp_parse_args( $args['rewrite'], array(
+                       'with_front' => true,
+                       'hierarchical' => false,
+                       'ep_mask' => EP_NONE,
+               ) );
+
+               if ( empty( $args['rewrite']['slug'] ) )
+                       $args['rewrite']['slug'] = sanitize_title_with_dashes( $taxonomy );
+
+               if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] )
+                       $tag = '(.+?)';
+               else
+                       $tag = '([^/]+)';
+
+               add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" );
+               add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] );
+       }
+
+       // If not set, default to the setting for public.
+       if ( null === $args['show_ui'] )
+               $args['show_ui'] = $args['public'];
+
+       // If not set, default to the setting for show_ui.
+       if ( null === $args['show_in_menu' ] || ! $args['show_ui'] )
+               $args['show_in_menu' ] = $args['show_ui'];
+
+       // If not set, default to the setting for public.
+       if ( null === $args['show_in_nav_menus'] )
+               $args['show_in_nav_menus'] = $args['public'];
+
+       // If not set, default to the setting for show_ui.
+       if ( null === $args['show_tagcloud'] )
+               $args['show_tagcloud'] = $args['show_ui'];
+
+       // If not set, default to the setting for show_ui.
+       if ( null === $args['show_in_quick_edit'] ) {
+               $args['show_in_quick_edit'] = $args['show_ui'];
+       }
+
+       $default_caps = array(
+               'manage_terms' => 'manage_categories',
+               'edit_terms'   => 'manage_categories',
+               'delete_terms' => 'manage_categories',
+               'assign_terms' => 'edit_posts',
+       );
+       $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
+       unset( $args['capabilities'] );
+
+       $args['name'] = $taxonomy;
+       $args['object_type'] = array_unique( (array) $object_type );
+
+       $args['labels'] = get_taxonomy_labels( (object) $args );
+       $args['label'] = $args['labels']->name;
+
+       // If not set, use the default meta box
+       if ( null === $args['meta_box_cb'] ) {
+               if ( $args['hierarchical'] )
+                       $args['meta_box_cb'] = 'post_categories_meta_box';
+               else
+                       $args['meta_box_cb'] = 'post_tags_meta_box';
+       }
+
+       $wp_taxonomies[ $taxonomy ] = (object) $args;
+
+       // register callback handling for metabox
+       add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' );
+
+       /**
+        * Fires after a taxonomy is registered.
+        *
+        * @since 3.3.0
+        *
+        * @param string       $taxonomy    Taxonomy slug.
+        * @param array|string $object_type Object type or array of object types.
+        * @param array        $args        Array of taxonomy registration arguments.
+        */
+       do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
+}
+
+/**
+ * Builds an object with all taxonomy labels out of a taxonomy object
+ *
+ * Accepted keys of the label array in the taxonomy object:
+ *
+ * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
+ * - singular_name - name for one object of this taxonomy. Default is Tag/Category
+ * - search_items - Default is Search Tags/Search Categories
+ * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
+ * - all_items - Default is All Tags/All Categories
+ * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
+ * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end
+ * - edit_item - Default is Edit Tag/Edit Category
+ * - view_item - Default is View Tag/View Category
+ * - update_item - Default is Update Tag/Update Category
+ * - add_new_item - Default is Add New Tag/Add New Category
+ * - new_item_name - Default is New Tag Name/New Category Name
+ * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
+ * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled.
+ * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box.
+ * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table.
+ * - no_terms - Default is "No tags"/"No categories", used in the posts and media list tables.
+ * - items_list_navigation - String for the table pagination hidden heading.
+ * - items_list - String for the table hidden heading.
+ *
+ * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
+ *
+ * @todo Better documentation for the labels array.
+ *
+ * @since 3.0.0
+ * @since 4.3.0 Added the `no_terms` label.
+ * @since 4.4.0 Added the `items_list_navigation` and `items_list` labels.
+ *
+ * @param object $tax Taxonomy object.
+ * @return object object with all the labels as member variables.
+ */
+function get_taxonomy_labels( $tax ) {
+       $tax->labels = (array) $tax->labels;
+
+       if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
+               $tax->labels['separate_items_with_commas'] = $tax->helps;
+
+       if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) )
+               $tax->labels['not_found'] = $tax->no_tagcloud;
+
+       $nohier_vs_hier_defaults = array(
+               'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
+               'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
+               'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
+               'popular_items' => array( __( 'Popular Tags' ), null ),
+               'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
+               'parent_item' => array( null, __( 'Parent Category' ) ),
+               'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
+               'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
+               'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
+               'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
+               'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
+               'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
+               'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
+               'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
+               'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
+               'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
+               'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ),
+               'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
+               'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ),
+       );
+       $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
+
+       $labels = _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
+
+       $taxonomy = $tax->name;
+
+       $default_labels = clone $labels;
+
+       /**
+        * Filter the labels of a specific taxonomy.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
+        *
+        * @since 4.4.0
+        *
+        * @see get_taxonomy_labels() for the full list of taxonomy labels.
+        *
+        * @param object $labels Object with labels for the taxonomy as member variables.
+        */
+       $labels = apply_filters( "taxonomy_labels_{$taxonomy}", $labels );
+
+       // Ensure that the filtered labels contain all required default values.
+       $labels = (object) array_merge( (array) $default_labels, (array) $labels );
+
+       return $labels;
+}
+
+/**
+ * Add an already registered taxonomy to an object type.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param string $taxonomy    Name of taxonomy object.
+ * @param string $object_type Name of the object type.
+ * @return bool True if successful, false if not.
+ */
+function register_taxonomy_for_object_type( $taxonomy, $object_type) {
+       global $wp_taxonomies;
+
+       if ( !isset($wp_taxonomies[$taxonomy]) )
+               return false;
+
+       if ( ! get_post_type_object($object_type) )
+               return false;
+
+       if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
+               $wp_taxonomies[$taxonomy]->object_type[] = $object_type;
+
+       // Filter out empties.
+       $wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
+
+       return true;
+}
+
+/**
+ * Remove an already registered taxonomy from an object type.
+ *
+ * @since 3.7.0
+ *
+ * @global array $wp_taxonomies The registered taxonomies.
+ *
+ * @param string $taxonomy    Name of taxonomy object.
+ * @param string $object_type Name of the object type.
+ * @return bool True if successful, false if not.
+ */
+function unregister_taxonomy_for_object_type( $taxonomy, $object_type ) {
+       global $wp_taxonomies;
+
+       if ( ! isset( $wp_taxonomies[ $taxonomy ] ) )
+               return false;
+
+       if ( ! get_post_type_object( $object_type ) )
+               return false;
+
+       $key = array_search( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true );
+       if ( false === $key )
+               return false;
+
+       unset( $wp_taxonomies[ $taxonomy ]->object_type[ $key ] );
+       return true;
+}
+
+//
+// Term API
+//
+
+/**
+ * Retrieve object_ids of valid taxonomy and term.
+ *
+ * The strings of $taxonomies must exist before this function will continue. On
+ * failure of finding a valid taxonomy, it will return an WP_Error class, kind
+ * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
+ * still test for the WP_Error class and get the error message.
+ *
+ * The $terms aren't checked the same as $taxonomies, but still need to exist
+ * for $object_ids to be returned.
+ *
+ * It is possible to change the order that object_ids is returned by either
+ * using PHP sort family functions or using the database by using $args with
+ * either ASC or DESC array. The value should be in the key named 'order'.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
+ * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
+ * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
+ * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
+ *     the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
+ */
+function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
+       global $wpdb;
+
+       if ( ! is_array( $term_ids ) ) {
+               $term_ids = array( $term_ids );
+       }
+       if ( ! is_array( $taxonomies ) ) {
+               $taxonomies = array( $taxonomies );
+       }
+       foreach ( (array) $taxonomies as $taxonomy ) {
+               if ( ! taxonomy_exists( $taxonomy ) ) {
+                       return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+               }
+       }
+
+       $defaults = array( 'order' => 'ASC' );
+       $args = wp_parse_args( $args, $defaults );
+
+       $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
+
+       $term_ids = array_map('intval', $term_ids );
+
+       $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
+       $term_ids = "'" . implode( "', '", $term_ids ) . "'";
+
+       $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
+
+       if ( ! $object_ids ){
+               return array();
+       }
+       return $object_ids;
+}
+
+/**
+ * Given a taxonomy query, generates SQL to be appended to a main query.
+ *
+ * @since 3.1.0
+ *
+ * @see WP_Tax_Query
+ *
+ * @param array  $tax_query         A compact tax query
+ * @param string $primary_table
+ * @param string $primary_id_column
+ * @return array
+ */
+function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
+       $tax_query_obj = new WP_Tax_Query( $tax_query );
+       return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
+}
+
+/**
+ * Get all Term data from database by Term ID.
+ *
+ * The usage of the get_term function is to apply filters to a term object. It
+ * is possible to get a term object from the database before applying the
+ * filters.
+ *
+ * $term ID must be part of $taxonomy, to get from the database. Failure, might
+ * be able to be captured by the hooks. Failure would be the same value as $wpdb
+ * returns for the get_row method.
+ *
+ * There are two hooks, one is specifically for each term, named 'get_term', and
+ * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
+ * term object, and the taxonomy name as parameters. Both hooks are expected to
+ * return a Term object.
+ *
+ * {@see 'get_term'} hook - Takes two parameters the term Object and the taxonomy name.
+ * Must return term object. Used in get_term() as a catch-all filter for every
+ * $term.
+ *
+ * {@see 'get_$taxonomy'} hook - Takes two parameters the term Object and the taxonomy
+ * name. Must return term object. $taxonomy will be the taxonomy name, so for
+ * example, if 'category', it would be 'get_category' as the filter name. Useful
+ * for custom taxonomies or plugging into default taxonomies.
+ *
+ * @todo Better formatting for DocBlock
+ *
+ * @since 2.3.0
+ * @since 4.4.0 Converted to return a WP_Term object if `$output` is `OBJECT`.
+ *              The `$taxonomy` parameter was made optional.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if
+ *                                 available. If stdClass object (as in the results of a database query), will apply
+ *                                 filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`,
+ *                                 will return `$term`.
+ * @param string     $taxonomy Optional. Taxonomy name that $term is part of.
+ * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
+ * @return mixed Type corresponding to `$output` on success or null on failure. When `$output` is `OBJECT`,
+ *               a WP_Term instance is returned. If taxonomy does not exist then WP_Error will be returned.
+ */
+function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
+       if ( empty( $term ) ) {
+               return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
+       }
+
+       if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) {
+               return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+       }
+
+       if ( $term instanceof WP_Term ) {
+               $_term = $term;
+       } elseif ( is_object( $term ) ) {
+               if ( empty( $term->filter ) || 'raw' === $term->filter ) {
+                       $_term = sanitize_term( $term, $taxonomy, 'raw' );
+                       $_term = new WP_Term( $_term );
+               } else {
+                       $_term = WP_Term::get_instance( $term->term_id );
+               }
+       } else {
+               $_term = WP_Term::get_instance( $term, $taxonomy );
+       }
+
+       if ( is_wp_error( $_term ) ) {
+               return $_term;
+       } elseif ( ! $_term ) {
+               return null;
+       }
+
+       /**
+        * Filter a term.
+        *
+        * @since 2.3.0
+        * @since 4.4.0 `$_term` can now also be a WP_Term object.
+        *
+        * @param int|WP_Term $_term    Term object or ID.
+        * @param string      $taxonomy The taxonomy slug.
+        */
+       $_term = apply_filters( 'get_term', $_term, $taxonomy );
+
+       /**
+        * Filter a taxonomy.
+        *
+        * The dynamic portion of the filter name, `$taxonomy`, refers
+        * to the taxonomy slug.
+        *
+        * @since 2.3.0
+        * @since 4.4.0 `$_term` can now also be a WP_Term object.
+        *
+        * @param int|WP_Term $_term    Term object or ID.
+        * @param string      $taxonomy The taxonomy slug.
+        */
+       $_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
+
+       // Sanitize term, according to the specified filter.
+       $_term->filter( $filter );
+
+       if ( $output == ARRAY_A ) {
+               return $_term->to_array();
+       } elseif ( $output == ARRAY_N ) {
+               return array_values( $_term->to_array() );
+       }
+
+       return $_term;
+}
+
+/**
+ * Get all Term data from database by Term field and data.
+ *
+ * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
+ * required.
+ *
+ * The default $field is 'id', therefore it is possible to also use null for
+ * field, but not recommended that you do so.
+ *
+ * If $value does not exist, the return value will be false. If $taxonomy exists
+ * and $field and $value combinations exist, the Term will be returned.
+ *
+ * @todo Better formatting for DocBlock.
+ *
+ * @since 2.3.0
+ * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return
+ *              a WP_Term object if `$output` is `OBJECT`.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param string     $field    Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
+ * @param string|int $value    Search for this term value
+ * @param string     $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
+ * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
+ * @return WP_Term|bool WP_Term instance on success. Will return false if `$taxonomy` does not exist
+ *                      or `$term` was not found.
+ */
+function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
+       global $wpdb;
+
+       // 'term_taxonomy_id' lookups don't require taxonomy checks.
+       if ( 'term_taxonomy_id' !== $field && ! taxonomy_exists( $taxonomy ) ) {
+               return false;
+       }
+
+       $tax_clause = $wpdb->prepare( "AND tt.taxonomy = %s", $taxonomy );
+
+       if ( 'slug' == $field ) {
+               $_field = 't.slug';
+               $value = sanitize_title($value);
+               if ( empty($value) )
+                       return false;
+       } elseif ( 'name' == $field ) {
+               // Assume already escaped
+               $value = wp_unslash($value);
+               $_field = 't.name';
+       } elseif ( 'term_taxonomy_id' == $field ) {
+               $value = (int) $value;
+               $_field = 'tt.term_taxonomy_id';
+
+               // No `taxonomy` clause when searching by 'term_taxonomy_id'.
+               $tax_clause = '';
+       } else {
+               $term = get_term( (int) $value, $taxonomy, $output, $filter );
+               if ( is_wp_error( $term ) || is_null( $term ) ) {
+                       $term = false;
+               }
+               return $term;
+       }
+
+       $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE $_field = %s $tax_clause LIMIT 1", $value ) );
+       if ( ! $term )
+               return false;
+
+       // In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the db.
+       if ( 'term_taxonomy_id' === $field ) {
+               $taxonomy = $term->taxonomy;
+       }
+
+       wp_cache_add( $term->term_id, $term, 'terms' );
+
+       return get_term( $term, $taxonomy, $output, $filter );
+}
+
+/**
+ * Merge all term children into a single array of their IDs.
+ *
+ * This recursive function will merge all of the children of $term into the same
+ * array of term IDs. Only useful for taxonomies which are hierarchical.
+ *
+ * Will return an empty array if $term does not exist in $taxonomy.
+ *
+ * @since 2.3.0
+ *
+ * @param string $term_id  ID of Term to get children.
+ * @param string $taxonomy Taxonomy Name.
+ * @return array|WP_Error List of Term IDs. WP_Error returned if `$taxonomy` does not exist.
+ */
+function get_term_children( $term_id, $taxonomy ) {
+       if ( ! taxonomy_exists($taxonomy) )
+               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+       $term_id = intval( $term_id );
+
+       $terms = _get_term_hierarchy($taxonomy);
+
+       if ( ! isset($terms[$term_id]) )
+               return array();
+
+       $children = $terms[$term_id];
+
+       foreach ( (array) $terms[$term_id] as $child ) {
+               if ( $term_id == $child ) {
+                       continue;
+               }
+
+               if ( isset($terms[$child]) )
+                       $children = array_merge($children, get_term_children($child, $taxonomy));
+       }
+
+       return $children;
+}
+
+/**
+ * Get sanitized Term field.
+ *
+ * The function is for contextual reasons and for simplicity of usage.
+ *
+ * @since 2.3.0
+ * @since 4.4.0 The `$taxonomy` parameter was made optional. `$term` can also now accept a WP_Term object.
+ *
+ * @see sanitize_term_field()
+ *
+ * @param string      $field    Term field to fetch.
+ * @param int|WP_Term $term     Term ID or object.
+ * @param string      $taxonomy Optional. Taxonomy Name. Default empty.
+ * @param string      $context  Optional, default is display. Look at sanitize_term_field() for available options.
+ * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term.
+ */
+function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
+       $term = get_term( $term, $taxonomy );
+       if ( is_wp_error($term) )
+               return $term;
+
+       if ( !is_object($term) )
+               return '';
+
+       if ( !isset($term->$field) )
+               return '';
+
+       return sanitize_term_field( $field, $term->$field, $term->term_id, $term->taxonomy, $context );
+}
+
+/**
+ * Sanitizes Term for editing.
+ *
+ * Return value is sanitize_term() and usage is for sanitizing the term for
+ * editing. Function is for contextual and simplicity.
+ *
+ * @since 2.3.0
+ *
+ * @param int|object $id       Term ID or object.
+ * @param string     $taxonomy Taxonomy name.
+ * @return string|int|null|WP_Error Will return empty string if $term is not an object.
+ */
+function get_term_to_edit( $id, $taxonomy ) {
+       $term = get_term( $id, $taxonomy );
+
+       if ( is_wp_error($term) )
+               return $term;
+
+       if ( !is_object($term) )
+               return '';
+
+       return sanitize_term($term, $taxonomy, 'edit');
+}
+
+/**
+ * Retrieve the terms in a given taxonomy or list of taxonomies.
+ *
+ * You can fully inject any customizations to the query before it is sent, as
+ * well as control the output with a filter.
+ *
+ * The {@see 'get_terms'} filter will be called when the cache has the term and will
+ * pass the found term along with the array of $taxonomies and array of $args.
+ * This filter is also called before the array of terms is passed and will pass
+ * the array of terms, along with the $taxonomies and $args.
+ *
+ * The {@see 'list_terms_exclusions'} filter passes the compiled exclusions along with
+ * the $args.
+ *
+ * The {@see 'get_terms_orderby'} filter passes the `ORDER BY` clause for the query
+ * along with the $args array.
+ *
+ * @since 2.3.0
+ * @since 4.2.0 Introduced 'name' and 'childless' parameters.
+ * @since 4.4.0 Introduced the ability to pass 'term_id' as an alias of 'id' for the `orderby` parameter.
+ *              Introduced the 'meta_query' and 'update_term_meta_cache' parameters. Converted to return
+ *              a list of WP_Term objects.
+ *
+ * @global wpdb  $wpdb WordPress database abstraction object.
+ * @global array $wp_filter
+ *
+ * @param string|array $taxonomies Taxonomy name or list of Taxonomy names.
+ * @param array|string $args {
+ *     Optional. Array or string of arguments to get terms.
+ *
+ *     @type string       $orderby                Field(s) to order terms by. Accepts term fields ('name', 'slug',
+ *                                                'term_group', 'term_id', 'id', 'description'), 'count' for term
+ *                                                taxonomy count, 'include' to match the 'order' of the $include param,
+ *                                                or 'none' to skip ORDER BY. Defaults to 'name'.
+ *     @type string       $order                  Whether to order terms in ascending or descending order.
+ *                                                Accepts 'ASC' (ascending) or 'DESC' (descending).
+ *                                                Default 'ASC'.
+ *     @type bool|int     $hide_empty             Whether to hide terms not assigned to any posts. Accepts
+ *                                                1|true or 0|false. Default 1|true.
+ *     @type array|string $include                Array or comma/space-separated string of term ids to include.
+ *                                                Default empty array.
+ *     @type array|string $exclude                Array or comma/space-separated string of term ids to exclude.
+ *                                                If $include is non-empty, $exclude is ignored.
+ *                                                Default empty array.
+ *     @type array|string $exclude_tree           Array or comma/space-separated string of term ids to exclude
+ *                                                along with all of their descendant terms. If $include is
+ *                                                non-empty, $exclude_tree is ignored. Default empty array.
+ *     @type int|string   $number                 Maximum number of terms to return. Accepts ''|0 (all) or any
+ *                                                positive number. Default ''|0 (all).
+ *     @type int          $offset                 The number by which to offset the terms query. Default empty.
+ *     @type string       $fields                 Term fields to query for. Accepts 'all' (returns an array of complete
+ *                                                term objects), 'ids' (returns an array of ids), 'id=>parent' (returns
+ *                                                an associative array with ids as keys, parent term IDs as values),
+ *                                                'names' (returns an array of term names), 'count' (returns the number
+ *                                                of matching terms), 'id=>name' (returns an associative array with ids
+ *                                                as keys, term names as values), or 'id=>slug' (returns an associative
+ *                                                array with ids as keys, term slugs as values). Default 'all'.
+ *     @type string|array $name                   Optional. Name or array of names to return term(s) for. Default empty.
+ *     @type string|array $slug                   Optional. Slug or array of slugs to return term(s) for. Default empty.
+ *     @type bool         $hierarchical           Whether to include terms that have non-empty descendants (even
+ *                                                if $hide_empty is set to true). Default true.
+ *     @type string       $search                 Search criteria to match terms. Will be SQL-formatted with
+ *                                                wildcards before and after. Default empty.
+ *     @type string       $name__like             Retrieve terms with criteria by which a term is LIKE $name__like.
+ *                                                Default empty.
+ *     @type string       $description__like      Retrieve terms where the description is LIKE $description__like.
+ *                                                Default empty.
+ *     @type bool         $pad_counts             Whether to pad the quantity of a term's children in the quantity
+ *                                                of each term's "count" object variable. Default false.
+ *     @type string       $get                    Whether to return terms regardless of ancestry or whether the terms
+ *                                                are empty. Accepts 'all' or empty (disabled). Default empty.
+ *     @type int          $child_of               Term ID to retrieve child terms of. If multiple taxonomies
+ *                                                are passed, $child_of is ignored. Default 0.
+ *     @type int|string   $parent                 Parent term ID to retrieve direct-child terms of. Default empty.
+ *     @type bool         $childless              True to limit results to terms that have no children. This parameter
+ *                                                has no effect on non-hierarchical taxonomies. Default false.
+ *     @type string       $cache_domain           Unique cache key to be produced when this query is stored in an
+ *                                                object cache. Default is 'core'.
+ *     @type bool         $update_term_meta_cache Whether to prime meta caches for matched terms. Default true.
+ *     @type array        $meta_query             Meta query clauses to limit retrieved terms by.
+ *                                                See `WP_Meta_Query`. Default empty.
+ * }
+ * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
+ *                            do not exist.
+ */
+function get_terms( $taxonomies, $args = '' ) {
+       global $wpdb;
+       $empty_array = array();
+
+       $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies );
+       if ( ! is_array( $taxonomies ) ) {
+               $taxonomies = array( $taxonomies );
+       }
+
+       foreach ( $taxonomies as $taxonomy ) {
+               if ( ! taxonomy_exists($taxonomy) ) {
+                       return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+               }
+       }
+
+       $defaults = array(
+               'orderby'                => 'name',
+               'order'                  => 'ASC',
+               'hide_empty'             => true,
+               'include'                => array(),
+               'exclude'                => array(),
+               'exclude_tree'           => array(),
+               'number'                 => '',
+               'offset'                 => '',
+               'fields'                 => 'all',
+               'name'                   => '',
+               'slug'                   => '',
+               'hierarchical'           => true,
+               'search'                 => '',
+               'name__like'             => '',
+               'description__like'      => '',
+               'pad_counts'             => false,
+               'get'                    => '',
+               'child_of'               => 0,
+               'parent'                 => '',
+               'childless'              => false,
+               'cache_domain'           => 'core',
+               'update_term_meta_cache' => true,
+               'meta_query'             => ''
+       );
+
+       /**
+        * Filter the terms query default arguments.
+        *
+        * Use 'get_terms_args' to filter the passed arguments.
+        *
+        * @since 4.4.0
+        *
+        * @param array $defaults   An array of default get_terms() arguments.
+        * @param array $taxonomies An array of taxonomies.
+        */
+       $args = wp_parse_args( $args, apply_filters( 'get_terms_defaults', $defaults, $taxonomies ) );
+
+       $args['number'] = absint( $args['number'] );
+       $args['offset'] = absint( $args['offset'] );
+
+       // Save queries by not crawling the tree in the case of multiple taxes or a flat tax.
+       $has_hierarchical_tax = false;
+       foreach ( $taxonomies as $_tax ) {
+               if ( is_taxonomy_hierarchical( $_tax ) ) {
+                       $has_hierarchical_tax = true;
+               }
+       }
+
+       if ( ! $has_hierarchical_tax ) {
+               $args['hierarchical'] = false;
+               $args['pad_counts'] = false;
+       }
+
+       // 'parent' overrides 'child_of'.
+       if ( 0 < intval( $args['parent'] ) ) {
+               $args['child_of'] = false;
+       }
+
+       if ( 'all' == $args['get'] ) {
+               $args['childless'] = false;
+               $args['child_of'] = 0;
+               $args['hide_empty'] = 0;
+               $args['hierarchical'] = false;
+               $args['pad_counts'] = false;
+       }
+
+       /**
+        * Filter the terms query arguments.
+        *
+        * @since 3.1.0
+        *
+        * @param array $args       An array of get_terms() arguments.
+        * @param array $taxonomies An array of taxonomies.
+        */
+       $args = apply_filters( 'get_terms_args', $args, $taxonomies );
+
+       // Avoid the query if the queried parent/child_of term has no descendants.
+       $child_of = $args['child_of'];
+       $parent   = $args['parent'];
+
+       if ( $child_of ) {
+               $_parent = $child_of;
+       } elseif ( $parent ) {
+               $_parent = $parent;
+       } else {
+               $_parent = false;
+       }
+
+       if ( $_parent ) {
+               $in_hierarchy = false;
+               foreach ( $taxonomies as $_tax ) {
+                       $hierarchy = _get_term_hierarchy( $_tax );
+
+                       if ( isset( $hierarchy[ $_parent ] ) ) {
+                               $in_hierarchy = true;
+                       }
+               }
+
+               if ( ! $in_hierarchy ) {
+                       return $empty_array;
+               }
+       }
+
+       $_orderby = strtolower( $args['orderby'] );
+       if ( 'count' == $_orderby ) {
+               $orderby = 'tt.count';
+       } elseif ( 'name' == $_orderby ) {
+               $orderby = 't.name';
+       } elseif ( 'slug' == $_orderby ) {
+               $orderby = 't.slug';
+       } elseif ( 'include' == $_orderby && ! empty( $args['include'] ) ) {
+               $include = implode( ',', array_map( 'absint', $args['include'] ) );
+               $orderby = "FIELD( t.term_id, $include )";
+       } elseif ( 'term_group' == $_orderby ) {
+               $orderby = 't.term_group';
+       } elseif ( 'description' == $_orderby ) {
+               $orderby = 'tt.description';
+       } elseif ( 'none' == $_orderby ) {
+               $orderby = '';
+       } elseif ( empty( $_orderby ) || 'id' == $_orderby || 'term_id' === $_orderby ) {
+               $orderby = 't.term_id';
+       } else {
+               $orderby = 't.name';
+       }
+
+       /**
+        * Filter the ORDERBY clause of the terms query.
+        *
+        * @since 2.8.0
+        *
+        * @param string $orderby    `ORDERBY` clause of the terms query.
+        * @param array  $args       An array of terms query arguments.
+        * @param array  $taxonomies An array of taxonomies.
+        */
+       $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies );
+
+       $order = strtoupper( $args['order'] );
+       if ( ! empty( $orderby ) ) {
+               $orderby = "ORDER BY $orderby";
+       } else {
+               $order = '';
+       }
+
+       if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) {
+               $order = 'ASC';
+       }
+
+       $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
+
+       $exclude = $args['exclude'];
+       $exclude_tree = $args['exclude_tree'];
+       $include = $args['include'];
+
+       $inclusions = '';
+       if ( ! empty( $include ) ) {
+               $exclude = '';
+               $exclude_tree = '';
+               $inclusions = implode( ',', wp_parse_id_list( $include ) );
+       }
+
+       if ( ! empty( $inclusions ) ) {
+               $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )';
+               $where .= $inclusions;
+       }
+
+       $exclusions = array();
+       if ( ! empty( $exclude_tree ) ) {
+               $exclude_tree = wp_parse_id_list( $exclude_tree );
+               $excluded_children = $exclude_tree;
+               foreach ( $exclude_tree as $extrunk ) {
+                       $excluded_children = array_merge(
+                               $excluded_children,
+                               (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
+                       );
+               }
+               $exclusions = array_merge( $excluded_children, $exclusions );
+       }
+
+       if ( ! empty( $exclude ) ) {
+               $exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions );
+       }
+
+       // 'childless' terms are those without an entry in the flattened term hierarchy.
+       $childless = (bool) $args['childless'];
+       if ( $childless ) {
+               foreach ( $taxonomies as $_tax ) {
+                       $term_hierarchy = _get_term_hierarchy( $_tax );
+                       $exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions );
+               }
+       }
+
+       if ( ! empty( $exclusions ) ) {
+               $exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')';
+       } else {
+               $exclusions = '';
+       }
+
+       /**
+        * Filter the terms to exclude from the terms query.
+        *
+        * @since 2.3.0
+        *
+        * @param string $exclusions `NOT IN` clause of the terms query.
+        * @param array  $args       An array of terms query arguments.
+        * @param array  $taxonomies An array of taxonomies.
+        */
+       $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies );
+
+       if ( ! empty( $exclusions ) ) {
+               $where .= $exclusions;
+       }
+
+       if ( ! empty( $args['name'] ) ) {
+               $names = (array) $args['name'];
+               foreach ( $names as &$_name ) {
+                       $_name = sanitize_term_field( 'name', $_name, 0, reset( $taxonomies ), 'db' );
+               }
+
+               $where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $names ) ) . "')";
+       }
+
+       if ( ! empty( $args['slug'] ) ) {
+               if ( is_array( $args['slug'] ) ) {
+                       $slug = array_map( 'sanitize_title', $args['slug'] );
+                       $where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')";
+               } else {
+                       $slug = sanitize_title( $args['slug'] );
+                       $where .= " AND t.slug = '$slug'";
+               }
+       }
+
+       if ( ! empty( $args['name__like'] ) ) {
+               $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' );
+       }
+
+       if ( ! empty( $args['description__like'] ) ) {
+               $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' );
+       }
+
+       if ( '' !== $parent ) {
+               $parent = (int) $parent;
+               $where .= " AND tt.parent = '$parent'";
+       }
+
+       $hierarchical = $args['hierarchical'];
+       if ( 'count' == $args['fields'] ) {
+               $hierarchical = false;
+       }
+       if ( $args['hide_empty'] && !$hierarchical ) {
+               $where .= ' AND tt.count > 0';
+       }
+
+       $number = $args['number'];
+       $offset = $args['offset'];
+
+       // Don't limit the query results when we have to descend the family tree.
+       if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
+               if ( $offset ) {
+                       $limits = 'LIMIT ' . $offset . ',' . $number;
+               } else {
+                       $limits = 'LIMIT ' . $number;
+               }
+       } else {
+               $limits = '';
+       }
+
+       if ( ! empty( $args['search'] ) ) {
+               $like = '%' . $wpdb->esc_like( $args['search'] ) . '%';
+               $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like );
+       }
+
+       // Meta query support.
+       $join = '';
+       if ( ! empty( $args['meta_query'] ) ) {
+               $mquery = new WP_Meta_Query( $args['meta_query'] );
+               $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
+
+               $join  .= $mq_sql['join'];
+               $where .= $mq_sql['where'];
+       }
+
+       $selects = array();
+       switch ( $args['fields'] ) {
+               case 'all':
+                       $selects = array( 't.*', 'tt.*' );
+                       break;
+               case 'ids':
+               case 'id=>parent':
+                       $selects = array( 't.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy' );
+                       break;
+               case 'names':
+                       $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy' );
+                       break;
+               case 'count':
+                       $orderby = '';
+                       $order = '';
+                       $selects = array( 'COUNT(*)' );
+                       break;
+               case 'id=>name':
+                       $selects = array( 't.term_id', 't.name', 'tt.count', 'tt.taxonomy' );
+                       break;
+               case 'id=>slug':
+                       $selects = array( 't.term_id', 't.slug', 'tt.count', 'tt.taxonomy' );
+                       break;
+       }
+
+       $_fields = $args['fields'];
+
+       /**
+        * Filter the fields to select in the terms query.
+        *
+        * Field lists modified using this filter will only modify the term fields returned
+        * by the function when the `$fields` parameter set to 'count' or 'all'. In all other
+        * cases, the term fields in the results array will be determined by the `$fields`
+        * parameter alone.
+        *
+        * Use of this filter can result in unpredictable behavior, and is not recommended.
+        *
+        * @since 2.8.0
+        *
+        * @param array $selects    An array of fields to select for the terms query.
+        * @param array $args       An array of term query arguments.
+        * @param array $taxonomies An array of taxonomies.
+        */
+       $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) );
+
+       $join .= " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
+
+       $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
+
+       /**
+        * Filter the terms query SQL clauses.
+        *
+        * @since 3.1.0
+        *
+        * @param array $pieces     Terms query SQL clauses.
+        * @param array $taxonomies An array of taxonomies.
+        * @param array $args       An array of terms query arguments.
+        */
+       $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
+
+       $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
+       $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
+       $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
+       $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
+       $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : '';
+       $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
+
+       $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
+
+       // $args can be anything. Only use the args defined in defaults to compute the key.
+       $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $query );
+       $last_changed = wp_cache_get( 'last_changed', 'terms' );
+       if ( ! $last_changed ) {
+               $last_changed = microtime();
+               wp_cache_set( 'last_changed', $last_changed, 'terms' );
+       }
+       $cache_key = "get_terms:$key:$last_changed";
+       $cache = wp_cache_get( $cache_key, 'terms' );
+       if ( false !== $cache ) {
+               if ( 'all' === $_fields ) {
+                       $cache = array_map( 'get_term', $cache );
+               }
+
+               /**
+                * Filter the given taxonomy's terms cache.
+                *
+                * @since 2.3.0
+                *
+                * @param array $cache      Cached array of terms for the given taxonomy.
+                * @param array $taxonomies An array of taxonomies.
+                * @param array $args       An array of get_terms() arguments.
+                */
+               return apply_filters( 'get_terms', $cache, $taxonomies, $args );
+       }
+
+       if ( 'count' == $_fields ) {
+               return $wpdb->get_var( $query );
+       }
+
+       $terms = $wpdb->get_results($query);
+       if ( 'all' == $_fields ) {
+               update_term_cache( $terms );
+       }
+
+       // Prime termmeta cache.
+       if ( $args['update_term_meta_cache'] ) {
+               $term_ids = wp_list_pluck( $terms, 'term_id' );
+               update_termmeta_cache( $term_ids );
+       }
+
+       if ( empty($terms) ) {
+               wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
+
+               /** This filter is documented in wp-includes/taxonomy-functions.php */
+               return apply_filters( 'get_terms', array(), $taxonomies, $args );
+       }
+
+       if ( $child_of ) {
+               foreach ( $taxonomies as $_tax ) {
+                       $children = _get_term_hierarchy( $_tax );
+                       if ( ! empty( $children ) ) {
+                               $terms = _get_term_children( $child_of, $terms, $_tax );
+                       }
+               }
+       }
+
+       // Update term counts to include children.
+       if ( $args['pad_counts'] && 'all' == $_fields ) {
+               foreach ( $taxonomies as $_tax ) {
+                       _pad_term_counts( $terms, $_tax );
+               }
+       }
+
+       // Make sure we show empty categories that have children.
+       if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) {
+               foreach ( $terms as $k => $term ) {
+                       if ( ! $term->count ) {
+                               $children = get_term_children( $term->term_id, $term->taxonomy );
+                               if ( is_array( $children ) ) {
+                                       foreach ( $children as $child_id ) {
+                                               $child = get_term( $child_id, $term->taxonomy );
+                                               if ( $child->count ) {
+                                                       continue 2;
+                                               }
+                                       }
+                               }
+
+                               // It really is empty.
+                               unset($terms[$k]);
+                       }
+               }
+       }
+
+       $_terms = array();
+       if ( 'id=>parent' == $_fields ) {
+               foreach ( $terms as $term ) {
+                       $_terms[ $term->term_id ] = $term->parent;
+               }
+       } elseif ( 'ids' == $_fields ) {
+               foreach ( $terms as $term ) {
+                       $_terms[] = $term->term_id;
+               }
+       } elseif ( 'names' == $_fields ) {
+               foreach ( $terms as $term ) {
+                       $_terms[] = $term->name;
+               }
+       } elseif ( 'id=>name' == $_fields ) {
+               foreach ( $terms as $term ) {
+                       $_terms[ $term->term_id ] = $term->name;
+               }
+       } elseif ( 'id=>slug' == $_fields ) {
+               foreach ( $terms as $term ) {
+                       $_terms[ $term->term_id ] = $term->slug;
+               }
+       }
+
+       if ( ! empty( $_terms ) ) {
+               $terms = $_terms;
+       }
+
+       if ( $number && is_array( $terms ) && count( $terms ) > $number ) {
+               $terms = array_slice( $terms, $offset, $number );
+       }
+
+       wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
+
+       if ( 'all' === $_fields ) {
+               $terms = array_map( 'get_term', $terms );
+       }
+
+       /** This filter is documented in wp-includes/taxonomy-functions.php */
+       return apply_filters( 'get_terms', $terms, $taxonomies, $args );
+}
+
+/**
+ * Adds metadata to a term.
+ *
+ * @since 4.4.0
+ *
+ * @param int    $term_id    Term ID.
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Metadata value.
+ * @param bool   $unique     Optional. Whether to bail if an entry with the same key is found for the term.
+ *                           Default false.
+ * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies.
+ *                           False on failure.
+ */
+function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
+       // Bail if term meta table is not installed.
+       if ( get_option( 'db_version' ) < 34370 ) {
+               return false;
+       }
+
+       if ( wp_term_is_shared( $term_id ) ) {
+               return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
+       }
+
+       $added = add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique );
+
+       // Bust term query cache.
+       if ( $added ) {
+               wp_cache_set( 'last_changed', microtime(), 'terms' );
+       }
+
+       return $added;
+}
+
+/**
+ * Removes metadata matching criteria from a term.
+ *
+ * @since 4.4.0
+ *
+ * @param int    $term_id    Term ID.
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
+ * @return bool True on success, false on failure.
+ */
+function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
+       // Bail if term meta table is not installed.
+       if ( get_option( 'db_version' ) < 34370 ) {
+               return false;
+       }
+
+       $deleted = delete_metadata( 'term', $term_id, $meta_key, $meta_value );
+
+       // Bust term query cache.
+       if ( $deleted ) {
+               wp_cache_set( 'last_changed', microtime(), 'terms' );
+       }
+
+       return $deleted;
+}
+
+/**
+ * Retrieves metadata for a term.
+ *
+ * @since 4.4.0
+ *
+ * @param int    $term_id Term ID.
+ * @param string $key     Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term.
+ * @param bool   $single  Whether to return a single value. If false, an array of all values matching the
+ *                        `$term_id`/`$key` pair will be returned. Default: false.
+ * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
+ */
+function get_term_meta( $term_id, $key = '', $single = false ) {
+       // Bail if term meta table is not installed.
+       if ( get_option( 'db_version' ) < 34370 ) {
+               return false;
+       }
+
+       return get_metadata( 'term', $term_id, $key, $single );
+}
+
+/**
+ * Updates term metadata.
+ *
+ * Use the `$prev_value` parameter to differentiate between meta fields with the same key and term ID.
+ *
+ * If the meta field for the term does not exist, it will be added.
+ *
+ * @since 4.4.0
+ *
+ * @param int    $term_id    Term ID.
+ * @param string $meta_key   Metadata key.
+ * @param mixed  $meta_value Metadata value.
+ * @param mixed  $prev_value Optional. Previous value to check before removing.
+ * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update.
+ *                           WP_Error when term_id is ambiguous between taxonomies. False on failure.
+ */
+function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
+       // Bail if term meta table is not installed.
+       if ( get_option( 'db_version' ) < 34370 ) {
+               return false;
+       }
+
+       if ( wp_term_is_shared( $term_id ) ) {
+               return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
+       }
+
+       $updated = update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value );
+
+       // Bust term query cache.
+       if ( $updated ) {
+               wp_cache_set( 'last_changed', microtime(), 'terms' );
+       }
+
+       return $updated;
+}
+
+/**
+ * Updates metadata cache for list of term IDs.
+ *
+ * Performs SQL query to retrieve all metadata for the terms matching `$term_ids` and stores them in the cache.
+ * Subsequent calls to `get_term_meta()` will not need to query the database.
+ *
+ * @since 4.4.0
+ *
+ * @param array $term_ids List of term IDs.
+ * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
+ */
+function update_termmeta_cache( $term_ids ) {
+       // Bail if term meta table is not installed.
+       if ( get_option( 'db_version' ) < 34370 ) {
+               return;
+       }
+
+       return update_meta_cache( 'term', $term_ids );
+}
+
+/**
+ * Check if Term exists.
+ *
+ * Formerly is_term(), introduced in 2.3.0.
+ *
+ * @since 3.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|string $term     The term to check
+ * @param string     $taxonomy The taxonomy name to use
+ * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
+ * @return mixed Returns null if the term does not exist. Returns the term ID
+ *               if no taxonomy is specified and the term ID exists. Returns
+ *               an array of the term ID and the term taxonomy ID the taxonomy
+ *               is specified and the pairing exists.
+ */
+function term_exists( $term, $taxonomy = '', $parent = null ) {
+       global $wpdb;
+
+       $select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
+       $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
+
+       if ( is_int($term) ) {
+               if ( 0 == $term )
+                       return 0;
+               $where = 't.term_id = %d';
+               if ( !empty($taxonomy) )
+                       return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
+               else
+                       return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
+       }
+
+       $term = trim( wp_unslash( $term ) );
+       $slug = sanitize_title( $term );
+
+       $where = 't.slug = %s';
+       $else_where = 't.name = %s';
+       $where_fields = array($slug);
+       $else_where_fields = array($term);
+       $orderby = 'ORDER BY t.term_id ASC';
+       $limit = 'LIMIT 1';
+       if ( !empty($taxonomy) ) {
+               if ( is_numeric( $parent ) ) {
+                       $parent = (int) $parent;
+                       $where_fields[] = $parent;
+                       $else_where_fields[] = $parent;
+                       $where .= ' AND tt.parent = %d';
+                       $else_where .= ' AND tt.parent = %d';
+               }
+
+               $where_fields[] = $taxonomy;
+               $else_where_fields[] = $taxonomy;
+
+               if ( $result = $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s $orderby $limit", $where_fields), ARRAY_A) )
+                       return $result;
+
+               return $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s $orderby $limit", $else_where_fields), ARRAY_A);
+       }
+
+       if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields) ) )
+               return $result;
+
+       return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields) );
+}
+
+/**
+ * Check if a term is an ancestor of another term.
+ *
+ * You can use either an id or the term object for both parameters.
+ *
+ * @since 3.4.0
+ *
+ * @param int|object $term1    ID or object to check if this is the parent term.
+ * @param int|object $term2    The child term.
+ * @param string     $taxonomy Taxonomy name that $term1 and `$term2` belong to.
+ * @return bool Whether `$term2` is a child of `$term1`.
+ */
+function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
+       if ( ! isset( $term1->term_id ) )
+               $term1 = get_term( $term1, $taxonomy );
+       if ( ! isset( $term2->parent ) )
+               $term2 = get_term( $term2, $taxonomy );
+
+       if ( empty( $term1->term_id ) || empty( $term2->parent ) )
+               return false;
+       if ( $term2->parent == $term1->term_id )
+               return true;
+
+       return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
+}
+
+/**
+ * Sanitize Term all fields.
+ *
+ * Relies on sanitize_term_field() to sanitize the term. The difference is that
+ * this function will sanitize <strong>all</strong> fields. The context is based
+ * on sanitize_term_field().
+ *
+ * The $term is expected to be either an array or an object.
+ *
+ * @since 2.3.0
+ *
+ * @param array|object $term     The term to check.
+ * @param string       $taxonomy The taxonomy name to use.
+ * @param string       $context  Optional. Context in which to sanitize the term. Accepts 'edit', 'db',
+ *                               'display', 'attribute', or 'js'. Default 'display'.
+ * @return array|object Term with all fields sanitized.
+ */
+function sanitize_term($term, $taxonomy, $context = 'display') {
+       $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
+
+       $do_object = is_object( $term );
+
+       $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
+
+       foreach ( (array) $fields as $field ) {
+               if ( $do_object ) {
+                       if ( isset($term->$field) )
+                               $term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
+               } else {
+                       if ( isset($term[$field]) )
+                               $term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
+               }
+       }
+
+       if ( $do_object )
+               $term->filter = $context;
+       else
+               $term['filter'] = $context;
+
+       return $term;
+}
+
+/**
+ * Cleanse the field value in the term based on the context.
+ *
+ * Passing a term field value through the function should be assumed to have
+ * cleansed the value for whatever context the term field is going to be used.
+ *
+ * If no context or an unsupported context is given, then default filters will
+ * be applied.
+ *
+ * There are enough filters for each context to support a custom filtering
+ * without creating your own filter function. Simply create a function that
+ * hooks into the filter you need.
+ *
+ * @since 2.3.0
+ *
+ * @param string $field    Term field to sanitize.
+ * @param string $value    Search for this term value.
+ * @param int    $term_id  Term ID.
+ * @param string $taxonomy Taxonomy Name.
+ * @param string $context  Context in which to sanitize the term field. Accepts 'edit', 'db', 'display',
+ *                         'attribute', or 'js'.
+ * @return mixed Sanitized field.
+ */
+function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
+       $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
+       if ( in_array( $field, $int_fields ) ) {
+               $value = (int) $value;
+               if ( $value < 0 )
+                       $value = 0;
+       }
+
+       if ( 'raw' == $context )
+               return $value;
+
+       if ( 'edit' == $context ) {
+
+               /**
+                * Filter a term field to edit before it is sanitized.
+                *
+                * The dynamic portion of the filter name, `$field`, refers to the term field.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed $value     Value of the term field.
+                * @param int   $term_id   Term ID.
+                * @param string $taxonomy Taxonomy slug.
+                */
+               $value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy );
+
+               /**
+                * Filter the taxonomy field to edit before it is sanitized.
+                *
+                * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
+                * to the taxonomy slug and taxonomy field, respectively.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed $value   Value of the taxonomy field to edit.
+                * @param int   $term_id Term ID.
+                */
+               $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
+
+               if ( 'description' == $field )
+                       $value = esc_html($value); // textarea_escaped
+               else
+                       $value = esc_attr($value);
+       } elseif ( 'db' == $context ) {
+
+               /**
+                * Filter a term field value before it is sanitized.
+                *
+                * The dynamic portion of the filter name, `$field`, refers to the term field.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed  $value    Value of the term field.
+                * @param string $taxonomy Taxonomy slug.
+                */
+               $value = apply_filters( "pre_term_{$field}", $value, $taxonomy );
+
+               /**
+                * Filter a taxonomy field before it is sanitized.
+                *
+                * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
+                * to the taxonomy slug and field name, respectively.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed $value Value of the taxonomy field.
+                */
+               $value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
+
+               // Back compat filters
+               if ( 'slug' == $field ) {
+                       /**
+                        * Filter the category nicename before it is sanitized.
+                        *
+                        * Use the pre_{$taxonomy}_{$field} hook instead.
+                        *
+                        * @since 2.0.3
+                        *
+                        * @param string $value The category nicename.
+                        */
+                       $value = apply_filters( 'pre_category_nicename', $value );
+               }
+
+       } elseif ( 'rss' == $context ) {
+
+               /**
+                * Filter the term field for use in RSS.
+                *
+                * The dynamic portion of the filter name, `$field`, refers to the term field.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed  $value    Value of the term field.
+                * @param string $taxonomy Taxonomy slug.
+                */
+               $value = apply_filters( "term_{$field}_rss", $value, $taxonomy );
+
+               /**
+                * Filter the taxonomy field for use in RSS.
+                *
+                * The dynamic portions of the hook name, `$taxonomy`, and `$field`, refer
+                * to the taxonomy slug and field name, respectively.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed $value Value of the taxonomy field.
+                */
+               $value = apply_filters( "{$taxonomy}_{$field}_rss", $value );
+       } else {
+               // Use display filters by default.
+
+               /**
+                * Filter the term field sanitized for display.
+                *
+                * The dynamic portion of the filter name, `$field`, refers to the term field name.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed  $value    Value of the term field.
+                * @param int    $term_id  Term ID.
+                * @param string $taxonomy Taxonomy slug.
+                * @param string $context  Context to retrieve the term field value.
+                */
+               $value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context );
+
+               /**
+                * Filter the taxonomy field sanitized for display.
+                *
+                * The dynamic portions of the filter name, `$taxonomy`, and `$field`, refer
+                * to the taxonomy slug and taxonomy field, respectively.
+                *
+                * @since 2.3.0
+                *
+                * @param mixed  $value   Value of the taxonomy field.
+                * @param int    $term_id Term ID.
+                * @param string $context Context to retrieve the taxonomy field value.
+                */
+               $value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
+       }
+
+       if ( 'attribute' == $context ) {
+               $value = esc_attr($value);
+       } elseif ( 'js' == $context ) {
+               $value = esc_js($value);
+       }
+       return $value;
+}
+
+/**
+ * Count how many terms are in Taxonomy.
+ *
+ * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
+ *
+ * @todo Document $args as a hash notation.
+ *
+ * @since 2.3.0
+ *
+ * @param string       $taxonomy Taxonomy name
+ * @param array|string $args     Overwrite defaults. See get_terms()
+ * @return array|int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
+ */
+function wp_count_terms( $taxonomy, $args = array() ) {
+       $defaults = array('hide_empty' => false);
+       $args = wp_parse_args($args, $defaults);
+
+       // backwards compatibility
+       if ( isset($args['ignore_empty']) ) {
+               $args['hide_empty'] = $args['ignore_empty'];
+               unset($args['ignore_empty']);
+       }
+
+       $args['fields'] = 'count';
+
+       return get_terms($taxonomy, $args);
+}
+
+/**
+ * Will unlink the object from the taxonomy or taxonomies.
+ *
+ * Will remove all relationships between the object and any terms in
+ * a particular taxonomy or taxonomies. Does not remove the term or
+ * taxonomy itself.
+ *
+ * @since 2.3.0
+ *
+ * @param int          $object_id  The term Object Id that refers to the term.
+ * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
+ */
+function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
+       $object_id = (int) $object_id;
+
+       if ( !is_array($taxonomies) )
+               $taxonomies = array($taxonomies);
+
+       foreach ( (array) $taxonomies as $taxonomy ) {
+               $term_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids' ) );
+               $term_ids = array_map( 'intval', $term_ids );
+               wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
+       }
+}
+
+/**
+ * Removes a term from the database.
+ *
+ * If the term is a parent of other terms, then the children will be updated to
+ * that term's parent.
+ *
+ * Metadata associated with the term will be deleted.
+ *
+ * The `$args` 'default' will only override the terms found, if there is only one
+ * term found. Any other and the found terms are used.
+ *
+ * The $args 'force_default' will force the term supplied as default to be
+ * assigned even if the object was not going to be termless
+ *
+ * @todo Document $args as a hash notation.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int          $term     Term ID.
+ * @param string       $taxonomy Taxonomy Name.
+ * @param array|string $args     Optional. Change 'default' term id and override found term ids.
+ * @return bool|int|WP_Error Returns false if not term; true if completes delete action.
+ */
+function wp_delete_term( $term, $taxonomy, $args = array() ) {
+       global $wpdb;
+
+       $term = (int) $term;
+
+       if ( ! $ids = term_exists($term, $taxonomy) )
+               return false;
+       if ( is_wp_error( $ids ) )
+               return $ids;
+
+       $tt_id = $ids['term_taxonomy_id'];
+
+       $defaults = array();
+
+       if ( 'category' == $taxonomy ) {
+               $defaults['default'] = get_option( 'default_category' );
+               if ( $defaults['default'] == $term )
+                       return 0; // Don't delete the default category
+       }
+
+       $args = wp_parse_args($args, $defaults);
+
+       if ( isset( $args['default'] ) ) {
+               $default = (int) $args['default'];
+               if ( ! term_exists( $default, $taxonomy ) ) {
+                       unset( $default );
+               }
+       }
+
+       if ( isset( $args['force_default'] ) ) {
+               $force_default = $args['force_default'];
+       }
+
+       /**
+        * Fires when deleting a term, before any modifications are made to posts or terms.
+        *
+        * @since 4.1.0
+        *
+        * @param int    $term     Term ID.
+        * @param string $taxonomy Taxonomy Name.
+        */
+       do_action( 'pre_delete_term', $term, $taxonomy );
+
+       // Update children to point to new parent
+       if ( is_taxonomy_hierarchical($taxonomy) ) {
+               $term_obj = get_term($term, $taxonomy);
+               if ( is_wp_error( $term_obj ) )
+                       return $term_obj;
+               $parent = $term_obj->parent;
+
+               $edit_ids = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
+               $edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
+
+               /**
+                * Fires immediately before a term to delete's children are reassigned a parent.
+                *
+                * @since 2.9.0
+                *
+                * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
+                */
+               do_action( 'edit_term_taxonomies', $edit_tt_ids );
+
+               $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
+
+               // Clean the cache for all child terms.
+               $edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
+               clean_term_cache( $edit_term_ids, $taxonomy );
+
+               /**
+                * Fires immediately after a term to delete's children are reassigned a parent.
+                *
+                * @since 2.9.0
+                *
+                * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
+                */
+               do_action( 'edited_term_taxonomies', $edit_tt_ids );
+       }
+
+       // Get the term before deleting it or its term relationships so we can pass to actions below.
+       $deleted_term = get_term( $term, $taxonomy );
+
+       $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
+
+       foreach ( (array) $objects as $object ) {
+               $terms = wp_get_object_terms($object, $taxonomy, array('fields' => 'ids', 'orderby' => 'none'));
+               if ( 1 == count($terms) && isset($default) ) {
+                       $terms = array($default);
+               } else {
+                       $terms = array_diff($terms, array($term));
+                       if (isset($default) && isset($force_default) && $force_default)
+                               $terms = array_merge($terms, array($default));
+               }
+               $terms = array_map('intval', $terms);
+               wp_set_object_terms($object, $terms, $taxonomy);
+       }
+
+       // Clean the relationship caches for all object types using this term.
+       $tax_object = get_taxonomy( $taxonomy );
+       foreach ( $tax_object->object_type as $object_type )
+               clean_object_term_cache( $objects, $object_type );
+
+       $term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) );
+       foreach ( $term_meta_ids as $mid ) {
+               delete_metadata_by_mid( 'term', $mid );
+       }
+
+       /**
+        * Fires immediately before a term taxonomy ID is deleted.
+        *
+        * @since 2.9.0
+        *
+        * @param int $tt_id Term taxonomy ID.
+        */
+       do_action( 'delete_term_taxonomy', $tt_id );
+       $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
+
+       /**
+        * Fires immediately after a term taxonomy ID is deleted.
+        *
+        * @since 2.9.0
+        *
+        * @param int $tt_id Term taxonomy ID.
+        */
+       do_action( 'deleted_term_taxonomy', $tt_id );
+
+       // Delete the term if no taxonomies use it.
+       if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
+               $wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
+
+       clean_term_cache($term, $taxonomy);
+
+       /**
+        * Fires after a term is deleted from the database and the cache is cleaned.
+        *
+        * @since 2.5.0
+        *
+        * @param int     $term         Term ID.
+        * @param int     $tt_id        Term taxonomy ID.
+        * @param string  $taxonomy     Taxonomy slug.
+        * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
+        *                              by the parent function. WP_Error otherwise.
+        */
+       do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term );
+
+       /**
+        * Fires after a term in a specific taxonomy is deleted.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers to the specific
+        * taxonomy the term belonged to.
+        *
+        * @since 2.3.0
+        *
+        * @param int     $term         Term ID.
+        * @param int     $tt_id        Term taxonomy ID.
+        * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
+        *                              by the parent function. WP_Error otherwise.
+        */
+       do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
+
+       return true;
+}
+
+/**
+ * Deletes one existing category.
+ *
+ * @since 2.0.0
+ *
+ * @param int $cat_ID
+ * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
+ *     Zero on attempted deletion of default Category; WP_Error object is also a possibility.
+ */
+function wp_delete_category( $cat_ID ) {
+       return wp_delete_term( $cat_ID, 'category' );
+}
+
+/**
+ * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
+ *
+ * @since 2.3.0
+ * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`.
+ *              Introduced `$parent` argument.
+ * @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or
+ *              'all_with_object_id', an array of `WP_Term` objects will be returned.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|array    $object_ids The ID(s) of the object(s) to retrieve.
+ * @param string|array $taxonomies The taxonomies to retrieve terms from.
+ * @param array|string $args {
+ *     Array of arguments.
+ *     @type string $orderby                Field by which results should be sorted. Accepts 'name', 'count', 'slug',
+ *                                          'term_group', 'term_order', 'taxonomy', 'parent', or 'term_taxonomy_id'.
+ *                                          Default 'name'.
+ *     @type string $order                  Sort order. Accepts 'ASC' or 'DESC'. Default 'ASC'.
+ *     @type string $fields                 Fields to return for matched terms. Accepts 'all', 'ids', 'names', and
+ *                                          'all_with_object_id'. Note that 'all' or 'all_with_object_id' will result
+ *                                          in an array of term objects being returned, 'ids' will return an array of
+ *                                          integers, and 'names' an array of strings.
+ *     @type int    $parent                 Optional. Limit results to the direct children of a given term ID.
+ *     @type bool   $update_term_meta_cache Whether to prime termmeta cache for matched terms. Only applies when
+ *                                          `$fields` is 'all', 'all_with_object_id', or 'term_id'. Default true.
+ *     @type array  $meta_query             Meta query clauses to limit retrieved terms by. See `WP_Meta_Query`.
+ *                                          Default empty.
+ * }
+ * @return array|WP_Error The requested term data or empty array if no terms found.
+ *                        WP_Error if any of the $taxonomies don't exist.
+ */
+function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
+       global $wpdb;
+
+       if ( empty( $object_ids ) || empty( $taxonomies ) )
+               return array();
+
+       if ( !is_array($taxonomies) )
+               $taxonomies = array($taxonomies);
+
+       foreach ( $taxonomies as $taxonomy ) {
+               if ( ! taxonomy_exists($taxonomy) )
+                       return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+       }
+
+       if ( !is_array($object_ids) )
+               $object_ids = array($object_ids);
+       $object_ids = array_map('intval', $object_ids);
+
+       $defaults = array(
+               'orderby' => 'name',
+               'order'   => 'ASC',
+               'fields'  => 'all',
+               'parent'  => '',
+               'update_term_meta_cache' => true,
+               'meta_query' => '',
+       );
+       $args = wp_parse_args( $args, $defaults );
+
+       $terms = array();
+       if ( count($taxonomies) > 1 ) {
+               foreach ( $taxonomies as $index => $taxonomy ) {
+                       $t = get_taxonomy($taxonomy);
+                       if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) {
+                               unset($taxonomies[$index]);
+                               $terms = array_merge($terms, wp_get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args)));
+                       }
+               }
+       } else {
+               $t = get_taxonomy($taxonomies[0]);
+               if ( isset($t->args) && is_array($t->args) )
+                       $args = array_merge($args, $t->args);
+       }
+
+       $orderby = $args['orderby'];
+       $order = $args['order'];
+       $fields = $args['fields'];
+
+       if ( in_array( $orderby, array( 'term_id', 'name', 'slug', 'term_group' ) ) ) {
+               $orderby = "t.$orderby";
+       } elseif ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) {
+               $orderby = "tt.$orderby";
+       } elseif ( 'term_order' === $orderby ) {
+               $orderby = 'tr.term_order';
+       } elseif ( 'none' === $orderby ) {
+               $orderby = '';
+               $order = '';
+       } else {
+               $orderby = 't.term_id';
+       }
+
+       // tt_ids queries can only be none or tr.term_taxonomy_id
+       if ( ('tt_ids' == $fields) && !empty($orderby) )
+               $orderby = 'tr.term_taxonomy_id';
+
+       if ( !empty($orderby) )
+               $orderby = "ORDER BY $orderby";
+
+       $order = strtoupper( $order );
+       if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) )
+               $order = 'ASC';
+
+       $taxonomy_array = $taxonomies;
+       $object_id_array = $object_ids;
+       $taxonomies = "'" . implode("', '", $taxonomies) . "'";
+       $object_ids = implode(', ', $object_ids);
+
+       $select_this = '';
+       if ( 'all' == $fields ) {
+               $select_this = 't.*, tt.*';
+       } elseif ( 'ids' == $fields ) {
+               $select_this = 't.term_id';
+       } elseif ( 'names' == $fields ) {
+               $select_this = 't.name';
+       } elseif ( 'slugs' == $fields ) {
+               $select_this = 't.slug';
+       } elseif ( 'all_with_object_id' == $fields ) {
+               $select_this = 't.*, tt.*, tr.object_id';
+       }
+
+       $where = array(
+               "tt.taxonomy IN ($taxonomies)",
+               "tr.object_id IN ($object_ids)",
+       );
+
+       if ( '' !== $args['parent'] ) {
+               $where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] );
+       }
+
+       // Meta query support.
+       $meta_query_join = '';
+       if ( ! empty( $args['meta_query'] ) ) {
+               $mquery = new WP_Meta_Query( $args['meta_query'] );
+               $mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
+
+               $meta_query_join .= $mq_sql['join'];
+
+               // Strip leading AND.
+               $where[] = preg_replace( '/^\s*AND/', '', $mq_sql['where'] );
+       }
+
+       $where = implode( ' AND ', $where );
+
+       $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id $meta_query_join WHERE $where $orderby $order";
+
+       $objects = false;
+       if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
+               $_terms = $wpdb->get_results( $query );
+               $object_id_index = array();
+               foreach ( $_terms as $key => $term ) {
+                       $term = sanitize_term( $term, $taxonomy, 'raw' );
+                       $_terms[ $key ] = $term;
+
+                       if ( isset( $term->object_id ) ) {
+                               $object_id_index[ $key ] = $term->object_id;
+                       }
+               }
+
+               update_term_cache( $_terms );
+               $_terms = array_map( 'get_term', $_terms );
+
+               // Re-add the object_id data, which is lost when fetching terms from cache.
+               if ( 'all_with_object_id' === $fields ) {
+                       foreach ( $_terms as $key => $_term ) {
+                               if ( isset( $object_id_index[ $key ] ) ) {
+                                       $_term->object_id = $object_id_index[ $key ];
+                               }
+                       }
+               }
+
+               $terms = array_merge( $terms, $_terms );
+               $objects = true;
+
+       } elseif ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) {
+               $_terms = $wpdb->get_col( $query );
+               $_field = ( 'ids' == $fields ) ? 'term_id' : 'name';
+               foreach ( $_terms as $key => $term ) {
+                       $_terms[$key] = sanitize_term_field( $_field, $term, $term, $taxonomy, 'raw' );
+               }
+               $terms = array_merge( $terms, $_terms );
+       } elseif ( 'tt_ids' == $fields ) {
+               $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
+               foreach ( $terms as $key => $tt_id ) {
+                       $terms[$key] = sanitize_term_field( 'term_taxonomy_id', $tt_id, 0, $taxonomy, 'raw' ); // 0 should be the term id, however is not needed when using raw context.
+               }
+       }
+
+       // Update termmeta cache, if necessary.
+       if ( $args['update_term_meta_cache'] && ( 'all' === $fields || 'all_with_object_ids' === $fields || 'term_id' === $fields ) ) {
+               if ( 'term_id' === $fields ) {
+                       $term_ids = $fields;
+               } else {
+                       $term_ids = wp_list_pluck( $terms, 'term_id' );
+               }
+
+               update_termmeta_cache( $term_ids );
+       }
+
+       if ( ! $terms ) {
+               $terms = array();
+       } elseif ( $objects && 'all_with_object_id' !== $fields ) {
+               $_tt_ids = array();
+               $_terms = array();
+               foreach ( $terms as $term ) {
+                       if ( in_array( $term->term_taxonomy_id, $_tt_ids ) ) {
+                               continue;
+                       }
+
+                       $_tt_ids[] = $term->term_taxonomy_id;
+                       $_terms[] = $term;
+               }
+               $terms = $_terms;
+       } elseif ( ! $objects ) {
+               $terms = array_values( array_unique( $terms ) );
+       }
+
+       /**
+        * Filter the terms for a given object or objects.
+        *
+        * @since 4.2.0
+        *
+        * @param array $terms           An array of terms for the given object or objects.
+        * @param array $object_id_array Array of object IDs for which `$terms` were retrieved.
+        * @param array $taxonomy_array  Array of taxonomies from which `$terms` were retrieved.
+        * @param array $args            An array of arguments for retrieving terms for the given
+        *                               object(s). See wp_get_object_terms() for details.
+        */
+       $terms = apply_filters( 'get_object_terms', $terms, $object_id_array, $taxonomy_array, $args );
+
+       /**
+        * Filter the terms for a given object or objects.
+        *
+        * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
+        * {@see 'get_object_terms'} filter is recommended as an alternative.
+        *
+        * @since 2.8.0
+        *
+        * @param array     $terms      An array of terms for the given object or objects.
+        * @param int|array $object_ids Object ID or array of IDs.
+        * @param string    $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names.
+        * @param array     $args       An array of arguments for retrieving terms for the given object(s).
+        *                              See {@see wp_get_object_terms()} for details.
+        */
+       return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
+}
+
+/**
+ * Add a new term to the database.
+ *
+ * A non-existent term is inserted in the following sequence:
+ * 1. The term is added to the term table, then related to the taxonomy.
+ * 2. If everything is correct, several actions are fired.
+ * 3. The 'term_id_filter' is evaluated.
+ * 4. The term cache is cleaned.
+ * 5. Several more actions are fired.
+ * 6. An array is returned containing the term_id and term_taxonomy_id.
+ *
+ * If the 'slug' argument is not empty, then it is checked to see if the term
+ * is invalid. If it is not a valid, existing term, it is added and the term_id
+ * is given.
+ *
+ * If the taxonomy is hierarchical, and the 'parent' argument is not empty,
+ * the term is inserted and the term_id will be given.
+ *
+ * Error handling:
+ * If $taxonomy does not exist or $term is empty,
+ * a WP_Error object will be returned.
+ *
+ * If the term already exists on the same hierarchical level,
+ * or the term slug and name are not unique, a WP_Error object will be returned.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @since 2.3.0
+ *
+ * @param string       $term     The term to add or update.
+ * @param string       $taxonomy The taxonomy to which to add the term.
+ * @param array|string $args {
+ *     Optional. Array or string of arguments for inserting a term.
+ *
+ *     @type string $alias_of    Slug of the term to make this term an alias of.
+ *                               Default empty string. Accepts a term slug.
+ *     @type string $description The term description. Default empty string.
+ *     @type int    $parent      The id of the parent term. Default 0.
+ *     @type string $slug        The term slug to use. Default empty string.
+ * }
+ * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`,
+ *                        {@see WP_Error} otherwise.
+ */
+function wp_insert_term( $term, $taxonomy, $args = array() ) {
+       global $wpdb;
+
+       if ( ! taxonomy_exists($taxonomy) ) {
+               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+       }
+       /**
+        * Filter a term before it is sanitized and inserted into the database.
+        *
+        * @since 3.0.0
+        *
+        * @param string $term     The term to add or update.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       $term = apply_filters( 'pre_insert_term', $term, $taxonomy );
+       if ( is_wp_error( $term ) ) {
+               return $term;
+       }
+       if ( is_int($term) && 0 == $term ) {
+               return new WP_Error('invalid_term_id', __('Invalid term ID'));
+       }
+       if ( '' == trim($term) ) {
+               return new WP_Error('empty_term_name', __('A name is required for this term'));
+       }
+       $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+       $args = wp_parse_args( $args, $defaults );
+
+       if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
+               return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
+       }
+       $args['name'] = $term;
+       $args['taxonomy'] = $taxonomy;
+       $args = sanitize_term($args, $taxonomy, 'db');
+
+       // expected_slashed ($name)
+       $name = wp_unslash( $args['name'] );
+       $description = wp_unslash( $args['description'] );
+       $parent = (int) $args['parent'];
+
+       $slug_provided = ! empty( $args['slug'] );
+       if ( ! $slug_provided ) {
+               $slug = sanitize_title( $name );
+       } else {
+               $slug = $args['slug'];
+       }
+
+       $term_group = 0;
+       if ( $args['alias_of'] ) {
+               $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
+               if ( ! empty( $alias->term_group ) ) {
+                       // The alias we want is already in a group, so let's use that one.
+                       $term_group = $alias->term_group;
+               } elseif ( ! empty( $alias->term_id ) ) {
+                       /*
+                        * The alias is not in a group, so we create a new one
+                        * and add the alias to it.
+                        */
+                       $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+
+                       wp_update_term( $alias->term_id, $taxonomy, array(
+                               'term_group' => $term_group,
+                       ) );
+               }
+       }
+
+       /*
+        * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
+        * unless a unique slug has been explicitly provided.
+        */
+       $name_matches = get_terms( $taxonomy, array(
+               'name' => $name,
+               'hide_empty' => false,
+       ) );
+
+       /*
+        * The `name` match in `get_terms()` doesn't differentiate accented characters,
+        * so we do a stricter comparison here.
+        */
+       $name_match = null;
+       if ( $name_matches ) {
+               foreach ( $name_matches as $_match ) {
+                       if ( strtolower( $name ) === strtolower( $_match->name ) ) {
+                               $name_match = $_match;
+                               break;
+                       }
+               }
+       }
+
+       if ( $name_match ) {
+               $slug_match = get_term_by( 'slug', $slug, $taxonomy );
+               if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
+                       if ( is_taxonomy_hierarchical( $taxonomy ) ) {
+                               $siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) );
+
+                               $existing_term = null;
+                               if ( $name_match->slug === $slug && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
+                                       $existing_term = $name_match;
+                               } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
+                                       $existing_term = $slug_match;
+                               }
+
+                               if ( $existing_term ) {
+                                       return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id );
+                               }
+                       } else {
+                               return new WP_Error( 'term_exists', __( 'A term with the name provided already exists in this taxonomy.' ), $name_match->term_id );
+                       }
+               }
+       }
+
+       $slug = wp_unique_term_slug( $slug, (object) $args );
+
+       if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) {
+               return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error );
+       }
+
+       $term_id = (int) $wpdb->insert_id;
+
+       // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
+       if ( empty($slug) ) {
+               $slug = sanitize_title($slug, $term_id);
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edit_terms', $term_id, $taxonomy );
+               $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edited_terms', $term_id, $taxonomy );
+       }
+
+       $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
+
+       if ( !empty($tt_id) ) {
+               return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+       }
+       $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
+       $tt_id = (int) $wpdb->insert_id;
+
+       /*
+        * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
+        * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
+        * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
+        * are not fired.
+        */
+       $duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) );
+       if ( $duplicate_term ) {
+               $wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
+               $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
+
+               $term_id = (int) $duplicate_term->term_id;
+               $tt_id   = (int) $duplicate_term->term_taxonomy_id;
+
+               clean_term_cache( $term_id, $taxonomy );
+               return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id );
+       }
+
+       /**
+        * Fires immediately after a new term is created, before the term cache is cleaned.
+        *
+        * @since 2.3.0
+        *
+        * @param int    $term_id  Term ID.
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( "create_term", $term_id, $tt_id, $taxonomy );
+
+       /**
+        * Fires after a new term is created for a specific taxonomy.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers
+        * to the slug of the taxonomy the term was created for.
+        *
+        * @since 2.3.0
+        *
+        * @param int $term_id Term ID.
+        * @param int $tt_id   Term taxonomy ID.
+        */
+       do_action( "create_$taxonomy", $term_id, $tt_id );
+
+       /**
+        * Filter the term ID after a new term is created.
+        *
+        * @since 2.3.0
+        *
+        * @param int $term_id Term ID.
+        * @param int $tt_id   Taxonomy term ID.
+        */
+       $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
+
+       clean_term_cache($term_id, $taxonomy);
+
+       /**
+        * Fires after a new term is created, and after the term cache has been cleaned.
+        *
+        * @since 2.3.0
+        *
+        * @param int    $term_id  Term ID.
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( 'created_term', $term_id, $tt_id, $taxonomy );
+
+       /**
+        * Fires after a new term in a specific taxonomy is created, and after the term
+        * cache has been cleaned.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
+        *
+        * @since 2.3.0
+        *
+        * @param int $term_id Term ID.
+        * @param int $tt_id   Term taxonomy ID.
+        */
+       do_action( "created_$taxonomy", $term_id, $tt_id );
+
+       return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Create Term and Taxonomy Relationships.
+ *
+ * Relates an object (post, link etc) to a term and taxonomy type. Creates the
+ * term and taxonomy relationship if it doesn't already exist. Creates a term if
+ * it doesn't exist (using the slug).
+ *
+ * A relationship means that the term is grouped in or belongs to the taxonomy.
+ * A term has no meaning until it is given context by defining which taxonomy it
+ * exists under.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb The WordPress database abstraction object.
+ *
+ * @param int              $object_id The object to relate to.
+ * @param array|int|string $terms     A single term slug, single term id, or array of either term slugs or ids.
+ *                                    Will replace all existing related terms in this taxonomy.
+ * @param string           $taxonomy  The context in which to relate the term to the object.
+ * @param bool             $append    Optional. If false will delete difference of terms. Default false.
+ * @return array|WP_Error Affected Term IDs.
+ */
+function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
+       global $wpdb;
+
+       $object_id = (int) $object_id;
+
+       if ( ! taxonomy_exists($taxonomy) )
+               return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+       if ( !is_array($terms) )
+               $terms = array($terms);
+
+       if ( ! $append )
+               $old_tt_ids =  wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'orderby' => 'none'));
+       else
+               $old_tt_ids = array();
+
+       $tt_ids = array();
+       $term_ids = array();
+       $new_tt_ids = array();
+
+       foreach ( (array) $terms as $term) {
+               if ( !strlen(trim($term)) )
+                       continue;
+
+               if ( !$term_info = term_exists($term, $taxonomy) ) {
+                       // Skip if a non-existent term ID is passed.
+                       if ( is_int($term) )
+                               continue;
+                       $term_info = wp_insert_term($term, $taxonomy);
+               }
+               if ( is_wp_error($term_info) )
+                       return $term_info;
+               $term_ids[] = $term_info['term_id'];
+               $tt_id = $term_info['term_taxonomy_id'];
+               $tt_ids[] = $tt_id;
+
+               if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) )
+                       continue;
+
+               /**
+                * Fires immediately before an object-term relationship is added.
+                *
+                * @since 2.9.0
+                *
+                * @param int $object_id Object ID.
+                * @param int $tt_id     Term taxonomy ID.
+                */
+               do_action( 'add_term_relationship', $object_id, $tt_id );
+               $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
+
+               /**
+                * Fires immediately after an object-term relationship is added.
+                *
+                * @since 2.9.0
+                *
+                * @param int $object_id Object ID.
+                * @param int $tt_id     Term taxonomy ID.
+                */
+               do_action( 'added_term_relationship', $object_id, $tt_id );
+               $new_tt_ids[] = $tt_id;
+       }
+
+       if ( $new_tt_ids )
+               wp_update_term_count( $new_tt_ids, $taxonomy );
+
+       if ( ! $append ) {
+               $delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
+
+               if ( $delete_tt_ids ) {
+                       $in_delete_tt_ids = "'" . implode( "', '", $delete_tt_ids ) . "'";
+                       $delete_term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT tt.term_id FROM $wpdb->term_taxonomy AS tt WHERE tt.taxonomy = %s AND tt.term_taxonomy_id IN ($in_delete_tt_ids)", $taxonomy ) );
+                       $delete_term_ids = array_map( 'intval', $delete_term_ids );
+
+                       $remove = wp_remove_object_terms( $object_id, $delete_term_ids, $taxonomy );
+                       if ( is_wp_error( $remove ) ) {
+                               return $remove;
+                       }
+               }
+       }
+
+       $t = get_taxonomy($taxonomy);
+       if ( ! $append && isset($t->sort) && $t->sort ) {
+               $values = array();
+               $term_order = 0;
+               $final_tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
+               foreach ( $tt_ids as $tt_id )
+                       if ( in_array($tt_id, $final_tt_ids) )
+                               $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
+               if ( $values )
+                       if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)" ) )
+                               return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error );
+       }
+
+       wp_cache_delete( $object_id, $taxonomy . '_relationships' );
+
+       /**
+        * Fires after an object's terms have been set.
+        *
+        * @since 2.8.0
+        *
+        * @param int    $object_id  Object ID.
+        * @param array  $terms      An array of object terms.
+        * @param array  $tt_ids     An array of term taxonomy IDs.
+        * @param string $taxonomy   Taxonomy slug.
+        * @param bool   $append     Whether to append new terms to the old terms.
+        * @param array  $old_tt_ids Old array of term taxonomy IDs.
+        */
+       do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids );
+       return $tt_ids;
+}
+
+/**
+ * Add term(s) associated with a given object.
+ *
+ * @since 3.6.0
+ *
+ * @param int              $object_id The ID of the object to which the terms will be added.
+ * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to add.
+ * @param array|string     $taxonomy  Taxonomy name.
+ * @return array|WP_Error Affected Term IDs
+ */
+function wp_add_object_terms( $object_id, $terms, $taxonomy ) {
+       return wp_set_object_terms( $object_id, $terms, $taxonomy, true );
+}
+
+/**
+ * Remove term(s) associated with a given object.
+ *
+ * @since 3.6.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int              $object_id The ID of the object from which the terms will be removed.
+ * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to remove.
+ * @param array|string     $taxonomy  Taxonomy name.
+ * @return bool|WP_Error True on success, false or WP_Error on failure.
+ */
+function wp_remove_object_terms( $object_id, $terms, $taxonomy ) {
+       global $wpdb;
+
+       $object_id = (int) $object_id;
+
+       if ( ! taxonomy_exists( $taxonomy ) ) {
+               return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
+       }
+
+       if ( ! is_array( $terms ) ) {
+               $terms = array( $terms );
+       }
+
+       $tt_ids = array();
+
+       foreach ( (array) $terms as $term ) {
+               if ( ! strlen( trim( $term ) ) ) {
+                       continue;
+               }
+
+               if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
+                       // Skip if a non-existent term ID is passed.
+                       if ( is_int( $term ) ) {
+                               continue;
+                       }
+               }
+
+               if ( is_wp_error( $term_info ) ) {
+                       return $term_info;
+               }
+
+               $tt_ids[] = $term_info['term_taxonomy_id'];
+       }
+
+       if ( $tt_ids ) {
+               $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
+
+               /**
+                * Fires immediately before an object-term relationship is deleted.
+                *
+                * @since 2.9.0
+                *
+                * @param int   $object_id Object ID.
+                * @param array $tt_ids    An array of term taxonomy IDs.
+                */
+               do_action( 'delete_term_relationships', $object_id, $tt_ids );
+               $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
+
+               wp_cache_delete( $object_id, $taxonomy . '_relationships' );
+
+               /**
+                * Fires immediately after an object-term relationship is deleted.
+                *
+                * @since 2.9.0
+                *
+                * @param int   $object_id Object ID.
+                * @param array $tt_ids    An array of term taxonomy IDs.
+                */
+               do_action( 'deleted_term_relationships', $object_id, $tt_ids );
+
+               wp_update_term_count( $tt_ids, $taxonomy );
+
+               return (bool) $deleted;
+       }
+
+       return false;
+}
+
+/**
+ * Will make slug unique, if it isn't already.
+ *
+ * The `$slug` has to be unique global to every taxonomy, meaning that one
+ * taxonomy term can't have a matching slug with another taxonomy term. Each
+ * slug has to be globally unique for every taxonomy.
+ *
+ * The way this works is that if the taxonomy that the term belongs to is
+ * hierarchical and has a parent, it will append that parent to the $slug.
+ *
+ * If that still doesn't return an unique slug, then it try to append a number
+ * until it finds a number that is truly unique.
+ *
+ * The only purpose for `$term` is for appending a parent, if one exists.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $slug The string that will be tried for a unique slug.
+ * @param object $term The term object that the `$slug` will belong to.
+ * @return string Will return a true unique slug.
+ */
+function wp_unique_term_slug( $slug, $term ) {
+       global $wpdb;
+
+       $needs_suffix = true;
+       $original_slug = $slug;
+
+       // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies.
+       if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
+               $needs_suffix = false;
+       }
+
+       /*
+        * If the taxonomy supports hierarchy and the term has a parent, make the slug unique
+        * by incorporating parent slugs.
+        */
+       $parent_suffix = '';
+       if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) {
+               $the_parent = $term->parent;
+               while ( ! empty($the_parent) ) {
+                       $parent_term = get_term($the_parent, $term->taxonomy);
+                       if ( is_wp_error($parent_term) || empty($parent_term) )
+                               break;
+                       $parent_suffix .= '-' . $parent_term->slug;
+                       if ( ! term_exists( $slug . $parent_suffix ) ) {
+                               break;
+                       }
+
+                       if ( empty($parent_term->parent) )
+                               break;
+                       $the_parent = $parent_term->parent;
+               }
+       }
+
+       // If we didn't get a unique slug, try appending a number to make it unique.
+
+       /**
+        * Filter whether the proposed unique term slug is bad.
+        *
+        * @since 4.3.0
+        *
+        * @param bool   $needs_suffix Whether the slug needs to be made unique with a suffix.
+        * @param string $slug         The slug.
+        * @param object $term         Term object.
+        */
+       if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
+               if ( $parent_suffix ) {
+                       $slug .= $parent_suffix;
+               } else {
+                       if ( ! empty( $term->term_id ) )
+                               $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
+                       else
+                               $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
+
+                       if ( $wpdb->get_var( $query ) ) {
+                               $num = 2;
+                               do {
+                                       $alt_slug = $slug . "-$num";
+                                       $num++;
+                                       $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
+                               } while ( $slug_check );
+                               $slug = $alt_slug;
+                       }
+               }
+       }
+
+       /**
+        * Filter the unique term slug.
+        *
+        * @since 4.3.0
+        *
+        * @param string $slug          Unique term slug.
+        * @param object $term          Term object.
+        * @param string $original_slug Slug originally passed to the function for testing.
+        */
+       return apply_filters( 'wp_unique_term_slug', $slug, $term, $original_slug );
+}
+
+/**
+ * Update term based on arguments provided.
+ *
+ * The $args will indiscriminately override all values with the same field name.
+ * Care must be taken to not override important information need to update or
+ * update will fail (or perhaps create a new term, neither would be acceptable).
+ *
+ * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
+ * defined in $args already.
+ *
+ * 'alias_of' will create a term group, if it doesn't already exist, and update
+ * it for the $term.
+ *
+ * If the 'slug' argument in $args is missing, then the 'name' in $args will be
+ * used. It should also be noted that if you set 'slug' and it isn't unique then
+ * a WP_Error will be passed back. If you don't pass any slug, then a unique one
+ * will be created for you.
+ *
+ * For what can be overrode in `$args`, check the term scheme can contain and stay
+ * away from the term keys.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int          $term_id  The ID of the term
+ * @param string       $taxonomy The context in which to relate the term to the object.
+ * @param array|string $args     Optional. Array of get_terms() arguments. Default empty array.
+ * @return array|WP_Error Returns Term ID and Taxonomy Term ID
+ */
+function wp_update_term( $term_id, $taxonomy, $args = array() ) {
+       global $wpdb;
+
+       if ( ! taxonomy_exists( $taxonomy ) ) {
+               return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+       }
+
+       $term_id = (int) $term_id;
+
+       // First, get all of the original args
+       $term = get_term( $term_id, $taxonomy );
+
+       if ( is_wp_error( $term ) ) {
+               return $term;
+       }
+
+       if ( ! $term ) {
+               return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
+       }
+
+       $term = (array) $term->data;
+
+       // Escape data pulled from DB.
+       $term = wp_slash( $term );
+
+       // Merge old and new args with new args overwriting old ones.
+       $args = array_merge($term, $args);
+
+       $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+       $args = wp_parse_args($args, $defaults);
+       $args = sanitize_term($args, $taxonomy, 'db');
+       $parsed_args = $args;
+
+       // expected_slashed ($name)
+       $name = wp_unslash( $args['name'] );
+       $description = wp_unslash( $args['description'] );
+
+       $parsed_args['name'] = $name;
+       $parsed_args['description'] = $description;
+
+       if ( '' == trim($name) )
+               return new WP_Error('empty_term_name', __('A name is required for this term'));
+
+       if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) {
+               return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
+       }
+
+       $empty_slug = false;
+       if ( empty( $args['slug'] ) ) {
+               $empty_slug = true;
+               $slug = sanitize_title($name);
+       } else {
+               $slug = $args['slug'];
+       }
+
+       $parsed_args['slug'] = $slug;
+
+       $term_group = isset( $parsed_args['term_group'] ) ? $parsed_args['term_group'] : 0;
+       if ( $args['alias_of'] ) {
+               $alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
+               if ( ! empty( $alias->term_group ) ) {
+                       // The alias we want is already in a group, so let's use that one.
+                       $term_group = $alias->term_group;
+               } elseif ( ! empty( $alias->term_id ) ) {
+                       /*
+                        * The alias is not in a group, so we create a new one
+                        * and add the alias to it.
+                        */
+                       $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+
+                       wp_update_term( $alias->term_id, $taxonomy, array(
+                               'term_group' => $term_group,
+                       ) );
+               }
+
+               $parsed_args['term_group'] = $term_group;
+       }
+
+       /**
+        * Filter the term parent.
+        *
+        * Hook to this filter to see if it will cause a hierarchy loop.
+        *
+        * @since 3.1.0
+        *
+        * @param int    $parent      ID of the parent term.
+        * @param int    $term_id     Term ID.
+        * @param string $taxonomy    Taxonomy slug.
+        * @param array  $parsed_args An array of potentially altered update arguments for the given term.
+        * @param array  $args        An array of update arguments for the given term.
+        */
+       $parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args );
+
+       // Check for duplicate slug
+       $duplicate = get_term_by( 'slug', $slug, $taxonomy );
+       if ( $duplicate && $duplicate->term_id != $term_id ) {
+               // If an empty slug was passed or the parent changed, reset the slug to something unique.
+               // Otherwise, bail.
+               if ( $empty_slug || ( $parent != $term['parent']) )
+                       $slug = wp_unique_term_slug($slug, (object) $args);
+               else
+                       return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
+       }
+
+       $tt_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );
+
+       // Check whether this is a shared term that needs splitting.
+       $_term_id = _split_shared_term( $term_id, $tt_id );
+       if ( ! is_wp_error( $_term_id ) ) {
+               $term_id = $_term_id;
+       }
+
+       /**
+        * Fires immediately before the given terms are edited.
+        *
+        * @since 2.9.0
+        *
+        * @param int    $term_id  Term ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( 'edit_terms', $term_id, $taxonomy );
+       $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
+       if ( empty($slug) ) {
+               $slug = sanitize_title($name, $term_id);
+               $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+       }
+
+       /**
+        * Fires immediately after the given terms are edited.
+        *
+        * @since 2.9.0
+        *
+        * @param int    $term_id  Term ID
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( 'edited_terms', $term_id, $taxonomy );
+
+       /**
+        * Fires immediate before a term-taxonomy relationship is updated.
+        *
+        * @since 2.9.0
+        *
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
+
+       $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
+
+       /**
+        * Fires immediately after a term-taxonomy relationship is updated.
+        *
+        * @since 2.9.0
+        *
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
+
+       // Clean the relationship caches for all object types using this term.
+       $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
+       $tax_object = get_taxonomy( $taxonomy );
+       foreach ( $tax_object->object_type as $object_type ) {
+               clean_object_term_cache( $objects, $object_type );
+       }
+
+       /**
+        * Fires after a term has been updated, but before the term cache has been cleaned.
+        *
+        * @since 2.3.0
+        *
+        * @param int    $term_id  Term ID.
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( "edit_term", $term_id, $tt_id, $taxonomy );
+
+       /**
+        * Fires after a term in a specific taxonomy has been updated, but before the term
+        * cache has been cleaned.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
+        *
+        * @since 2.3.0
+        *
+        * @param int $term_id Term ID.
+        * @param int $tt_id   Term taxonomy ID.
+        */
+       do_action( "edit_$taxonomy", $term_id, $tt_id );
+
+       /** This filter is documented in wp-includes/taxonomy-functions.php */
+       $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
+
+       clean_term_cache($term_id, $taxonomy);
+
+       /**
+        * Fires after a term has been updated, and the term cache has been cleaned.
+        *
+        * @since 2.3.0
+        *
+        * @param int    $term_id  Term ID.
+        * @param int    $tt_id    Term taxonomy ID.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       do_action( "edited_term", $term_id, $tt_id, $taxonomy );
+
+       /**
+        * Fires after a term for a specific taxonomy has been updated, and the term
+        * cache has been cleaned.
+        *
+        * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
+        *
+        * @since 2.3.0
+        *
+        * @param int $term_id Term ID.
+        * @param int $tt_id   Term taxonomy ID.
+        */
+       do_action( "edited_$taxonomy", $term_id, $tt_id );
+
+       return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Enable or disable term counting.
+ *
+ * @since 2.5.0
+ *
+ * @staticvar bool $_defer
+ *
+ * @param bool $defer Optional. Enable if true, disable if false.
+ * @return bool Whether term counting is enabled or disabled.
+ */
+function wp_defer_term_counting($defer=null) {
+       static $_defer = false;
+
+       if ( is_bool($defer) ) {
+               $_defer = $defer;
+               // flush any deferred counts
+               if ( !$defer )
+                       wp_update_term_count( null, null, true );
+       }
+
+       return $_defer;
+}
+
+/**
+ * Updates the amount of terms in taxonomy.
+ *
+ * If there is a taxonomy callback applied, then it will be called for updating
+ * the count.
+ *
+ * The default action is to count what the amount of terms have the relationship
+ * of term ID. Once that is done, then update the database.
+ *
+ * @since 2.3.0
+ *
+ * @staticvar array $_deferred
+ *
+ * @param int|array $terms    The term_taxonomy_id of the terms.
+ * @param string    $taxonomy The context of the term.
+ * @return bool If no terms will return false, and if successful will return true.
+ */
+function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) {
+       static $_deferred = array();
+
+       if ( $do_deferred ) {
+               foreach ( (array) array_keys($_deferred) as $tax ) {
+                       wp_update_term_count_now( $_deferred[$tax], $tax );
+                       unset( $_deferred[$tax] );
+               }
+       }
+
+       if ( empty($terms) )
+               return false;
+
+       if ( !is_array($terms) )
+               $terms = array($terms);
+
+       if ( wp_defer_term_counting() ) {
+               if ( !isset($_deferred[$taxonomy]) )
+                       $_deferred[$taxonomy] = array();
+               $_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
+               return true;
+       }
+
+       return wp_update_term_count_now( $terms, $taxonomy );
+}
+
+/**
+ * Perform term count update immediately.
+ *
+ * @since 2.5.0
+ *
+ * @param array  $terms    The term_taxonomy_id of terms to update.
+ * @param string $taxonomy The context of the term.
+ * @return true Always true when complete.
+ */
+function wp_update_term_count_now( $terms, $taxonomy ) {
+       $terms = array_map('intval', $terms);
+
+       $taxonomy = get_taxonomy($taxonomy);
+       if ( !empty($taxonomy->update_count_callback) ) {
+               call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
+       } else {
+               $object_types = (array) $taxonomy->object_type;
+               foreach ( $object_types as &$object_type ) {
+                       if ( 0 === strpos( $object_type, 'attachment:' ) )
+                               list( $object_type ) = explode( ':', $object_type );
+               }
+
+               if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
+                       // Only post types are attached to this taxonomy
+                       _update_post_term_count( $terms, $taxonomy );
+               } else {
+                       // Default count updater
+                       _update_generic_term_count( $terms, $taxonomy );
+               }
+       }
+
+       clean_term_cache($terms, '', false);
+
+       return true;
+}
+
+//
+// Cache
+//
+
+/**
+ * Removes the taxonomy relationship to terms from the cache.
+ *
+ * Will remove the entire taxonomy relationship containing term `$object_id`. The
+ * term IDs have to exist within the taxonomy `$object_type` for the deletion to
+ * take place.
+ *
+ * @since 2.3.0
+ *
+ * @see get_object_taxonomies() for more on $object_type.
+ *
+ * @param int|array    $object_ids  Single or list of term object ID(s).
+ * @param array|string $object_type The taxonomy object type.
+ */
+function clean_object_term_cache($object_ids, $object_type) {
+       if ( !is_array($object_ids) )
+               $object_ids = array($object_ids);
+
+       $taxonomies = get_object_taxonomies( $object_type );
+
+       foreach ( $object_ids as $id ) {
+               foreach ( $taxonomies as $taxonomy ) {
+                       wp_cache_delete($id, "{$taxonomy}_relationships");
+               }
+       }
+
+       /**
+        * Fires after the object term cache has been cleaned.
+        *
+        * @since 2.5.0
+        *
+        * @param array  $object_ids An array of object IDs.
+        * @param string $objet_type Object type.
+        */
+       do_action( 'clean_object_term_cache', $object_ids, $object_type );
+}
+
+/**
+ * Will remove all of the term ids from the cache.
+ *
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @global bool $_wp_suspend_cache_invalidation
+ *
+ * @param int|array $ids            Single or list of Term IDs.
+ * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
+ *                                  Default empty.
+ * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
+ *                                  term object caches (false). Default true.
+ */
+function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
+       global $wpdb, $_wp_suspend_cache_invalidation;
+
+       if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
+               return;
+       }
+
+       if ( !is_array($ids) )
+               $ids = array($ids);
+
+       $taxonomies = array();
+       // If no taxonomy, assume tt_ids.
+       if ( empty($taxonomy) ) {
+               $tt_ids = array_map('intval', $ids);
+               $tt_ids = implode(', ', $tt_ids);
+               $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
+               $ids = array();
+               foreach ( (array) $terms as $term ) {
+                       $taxonomies[] = $term->taxonomy;
+                       $ids[] = $term->term_id;
+                       wp_cache_delete( $term->term_id, 'terms' );
+               }
+               $taxonomies = array_unique($taxonomies);
+       } else {
+               $taxonomies = array($taxonomy);
+               foreach ( $taxonomies as $taxonomy ) {
+                       foreach ( $ids as $id ) {
+                               wp_cache_delete( $id, 'terms' );
+                       }
+               }
+       }
+
+       foreach ( $taxonomies as $taxonomy ) {
+               if ( $clean_taxonomy ) {
+                       wp_cache_delete('all_ids', $taxonomy);
+                       wp_cache_delete('get', $taxonomy);
+                       delete_option("{$taxonomy}_children");
+                       // Regenerate {$taxonomy}_children
+                       _get_term_hierarchy($taxonomy);
+               }
+
+               /**
+                * Fires once after each taxonomy's term cache has been cleaned.
+                *
+                * @since 2.5.0
+                *
+                * @param array  $ids      An array of term IDs.
+                * @param string $taxonomy Taxonomy slug.
+                */
+               do_action( 'clean_term_cache', $ids, $taxonomy );
+       }
+
+       wp_cache_set( 'last_changed', microtime(), 'terms' );
+}
+
+/**
+ * Retrieves the taxonomy relationship to the term object id.
+ *
+ * @since 2.3.0
+ *
+ * @param int    $id       Term object ID.
+ * @param string $taxonomy Taxonomy name.
+ * @return bool|mixed Empty array if $terms found, but not `$taxonomy`. False if nothing is in cache
+ *                    for `$taxonomy` and `$id`.
+ */
+function get_object_term_cache( $id, $taxonomy ) {
+       return wp_cache_get( $id, "{$taxonomy}_relationships" );
+}
+
+/**
+ * Updates the cache for the given term object ID(s).
+ *
+ * Note: Due to performance concerns, great care should be taken to only update
+ * term caches when necessary. Processing time can increase exponentially depending
+ * on both the number of passed term IDs and the number of taxonomies those terms
+ * belong to.
+ *
+ * Caches will only be updated for terms not already cached.
+ *
+ * @since 2.3.0
+ *
+ * @param string|array $object_ids  Comma-separated list or array of term object IDs.
+ * @param array|string $object_type The taxonomy object type.
+ * @return void|false False if all of the terms in `$object_ids` are already cached.
+ */
+function update_object_term_cache($object_ids, $object_type) {
+       if ( empty($object_ids) )
+               return;
+
+       if ( !is_array($object_ids) )
+               $object_ids = explode(',', $object_ids);
+
+       $object_ids = array_map('intval', $object_ids);
+
+       $taxonomies = get_object_taxonomies($object_type);
+
+       $ids = array();
+       foreach ( (array) $object_ids as $id ) {
+               foreach ( $taxonomies as $taxonomy ) {
+                       if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
+                               $ids[] = $id;
+                               break;
+                       }
+               }
+       }
+
+       if ( empty( $ids ) )
+               return false;
+
+       $terms = wp_get_object_terms( $ids, $taxonomies, array(
+               'fields' => 'all_with_object_id',
+               'orderby' => 'none',
+               'update_term_meta_cache' => false,
+       ) );
+
+       $object_terms = array();
+       foreach ( (array) $terms as $term )
+               $object_terms[$term->object_id][$term->taxonomy][] = $term;
+
+       foreach ( $ids as $id ) {
+               foreach ( $taxonomies as $taxonomy ) {
+                       if ( ! isset($object_terms[$id][$taxonomy]) ) {
+                               if ( !isset($object_terms[$id]) )
+                                       $object_terms[$id] = array();
+                               $object_terms[$id][$taxonomy] = array();
+                       }
+               }
+       }
+
+       foreach ( $object_terms as $id => $value ) {
+               foreach ( $value as $taxonomy => $terms ) {
+                       wp_cache_add( $id, $terms, "{$taxonomy}_relationships" );
+               }
+       }
+}
+
+/**
+ * Updates Terms to Taxonomy in cache.
+ *
+ * @since 2.3.0
+ *
+ * @param array  $terms    List of term objects to change.
+ * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty.
+ */
+function update_term_cache( $terms, $taxonomy = '' ) {
+       foreach ( (array) $terms as $term ) {
+               // Create a copy in case the array was passed by reference.
+               $_term = $term;
+
+               // Object ID should not be cached.
+               unset( $_term->object_id );
+
+               wp_cache_add( $term->term_id, $_term, 'terms' );
+       }
+}
+
+//
+// Private
+//
+
+/**
+ * Retrieves children of taxonomy as Term IDs.
+ *
+ * @ignore
+ * @since 2.3.0
+ *
+ * @param string $taxonomy Taxonomy name.
+ * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
+ */
+function _get_term_hierarchy( $taxonomy ) {
+       if ( !is_taxonomy_hierarchical($taxonomy) )
+               return array();
+       $children = get_option("{$taxonomy}_children");
+
+       if ( is_array($children) )
+               return $children;
+       $children = array();
+       $terms = get_terms($taxonomy, array('get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent'));
+       foreach ( $terms as $term_id => $parent ) {
+               if ( $parent > 0 )
+                       $children[$parent][] = $term_id;
+       }
+       update_option("{$taxonomy}_children", $children);
+
+       return $children;
+}
+
+/**
+ * Get the subset of $terms that are descendants of $term_id.
+ *
+ * If `$terms` is an array of objects, then _get_term_children() returns an array of objects.
+ * If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs.
+ *
+ * @access private
+ * @since 2.3.0
+ *
+ * @param int    $term_id   The ancestor term: all returned terms should be descendants of `$term_id`.
+ * @param array  $terms     The set of terms - either an array of term objects or term IDs - from which those that
+ *                          are descendants of $term_id will be chosen.
+ * @param string $taxonomy  The taxonomy which determines the hierarchy of the terms.
+ * @param array  $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep
+ *                          track of found terms when recursing the hierarchy. The array of located ancestors is used
+ *                          to prevent infinite recursion loops. For performance, `term_ids` are used as array keys,
+ *                          with 1 as value. Default empty array.
+ * @return array|WP_Error The subset of $terms that are descendants of $term_id.
+ */
+function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
+       $empty_array = array();
+       if ( empty($terms) )
+               return $empty_array;
+
+       $term_list = array();
+       $has_children = _get_term_hierarchy($taxonomy);
+
+       if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
+               return $empty_array;
+
+       // Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
+       if ( empty( $ancestors ) ) {
+               $ancestors[ $term_id ] = 1;
+       }
+
+       foreach ( (array) $terms as $term ) {
+               $use_id = false;
+               if ( !is_object($term) ) {
+                       $term = get_term($term, $taxonomy);
+                       if ( is_wp_error( $term ) )
+                               return $term;
+                       $use_id = true;
+               }
+
+               // Don't recurse if we've already identified the term as a child - this indicates a loop.
+               if ( isset( $ancestors[ $term->term_id ] ) ) {
+                       continue;
+               }
+
+               if ( $term->parent == $term_id ) {
+                       if ( $use_id )
+                               $term_list[] = $term->term_id;
+                       else
+                               $term_list[] = $term;
+
+                       if ( !isset($has_children[$term->term_id]) )
+                               continue;
+
+                       $ancestors[ $term->term_id ] = 1;
+
+                       if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors) )
+                               $term_list = array_merge($term_list, $children);
+               }
+       }
+
+       return $term_list;
+}
+
+/**
+ * Add count of children to parent count.
+ *
+ * Recalculates term counts by including items from child terms. Assumes all
+ * relevant children are already in the $terms argument.
+ *
+ * @access private
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array  $terms    List of term objects, passed by reference.
+ * @param string $taxonomy Term context.
+ */
+function _pad_term_counts( &$terms, $taxonomy ) {
+       global $wpdb;
+
+       // This function only works for hierarchical taxonomies like post categories.
+       if ( !is_taxonomy_hierarchical( $taxonomy ) )
+               return;
+
+       $term_hier = _get_term_hierarchy($taxonomy);
+
+       if ( empty($term_hier) )
+               return;
+
+       $term_items = array();
+       $terms_by_id = array();
+       $term_ids = array();
+
+       foreach ( (array) $terms as $key => $term ) {
+               $terms_by_id[$term->term_id] = & $terms[$key];
+               $term_ids[$term->term_taxonomy_id] = $term->term_id;
+       }
+
+       // Get the object and term ids and stick them in a lookup table.
+       $tax_obj = get_taxonomy($taxonomy);
+       $object_types = esc_sql($tax_obj->object_type);
+       $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
+       foreach ( $results as $row ) {
+               $id = $term_ids[$row->term_taxonomy_id];
+               $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
+       }
+
+       // Touch every ancestor's lookup row for each post in each term.
+       foreach ( $term_ids as $term_id ) {
+               $child = $term_id;
+               $ancestors = array();
+               while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
+                       $ancestors[] = $child;
+                       if ( !empty( $term_items[$term_id] ) )
+                               foreach ( $term_items[$term_id] as $item_id => $touches ) {
+                                       $term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
+                               }
+                       $child = $parent;
+
+                       if ( in_array( $parent, $ancestors ) ) {
+                               break;
+                       }
+               }
+       }
+
+       // Transfer the touched cells.
+       foreach ( (array) $term_items as $id => $items )
+               if ( isset($terms_by_id[$id]) )
+                       $terms_by_id[$id]->count = count($items);
+}
+
+//
+// Default callbacks
+//
+
+/**
+ * Will update term count based on object types of the current taxonomy.
+ *
+ * Private function for the default callback for post_tag and category
+ * taxonomies.
+ *
+ * @access private
+ * @since 2.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array  $terms    List of Term taxonomy IDs.
+ * @param object $taxonomy Current taxonomy object of terms.
+ */
+function _update_post_term_count( $terms, $taxonomy ) {
+       global $wpdb;
+
+       $object_types = (array) $taxonomy->object_type;
+
+       foreach ( $object_types as &$object_type )
+               list( $object_type ) = explode( ':', $object_type );
+
+       $object_types = array_unique( $object_types );
+
+       if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
+               unset( $object_types[ $check_attachments ] );
+               $check_attachments = true;
+       }
+
+       if ( $object_types )
+               $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
+
+       foreach ( (array) $terms as $term ) {
+               $count = 0;
+
+               // Attachments can be 'inherit' status, we need to base count off the parent's status if so.
+               if ( $check_attachments )
+                       $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
+
+               if ( $object_types )
+                       $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
+               $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
+       }
+}
+
+/**
+ * Will update term count based on number of objects.
+ *
+ * Default callback for the 'link_category' taxonomy.
+ *
+ * @since 3.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array  $terms    List of term taxonomy IDs.
+ * @param object $taxonomy Current taxonomy object of terms.
+ */
+function _update_generic_term_count( $terms, $taxonomy ) {
+       global $wpdb;
+
+       foreach ( (array) $terms as $term ) {
+               $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
+               $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+
+               /** This action is documented in wp-includes/taxonomy-functions.php */
+               do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
+       }
+}
+
+/**
+ * Create a new term for a term_taxonomy item that currently shares its term
+ * with another term_taxonomy.
+ *
+ * @ignore
+ * @since 4.2.0
+ * @since 4.3.0 Introduced `$record` parameter. Also, `$term_id` and
+ *              `$term_taxonomy_id` can now accept objects.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int|object $term_id          ID of the shared term, or the shared term object.
+ * @param int|object $term_taxonomy_id ID of the term_taxonomy item to receive a new term, or the term_taxonomy object
+ *                                     (corresponding to a row from the term_taxonomy table).
+ * @param bool       $record           Whether to record data about the split term in the options table. The recording
+ *                                     process has the potential to be resource-intensive, so during batch operations
+ *                                     it can be beneficial to skip inline recording and do it just once, after the
+ *                                     batch is processed. Only set this to `false` if you know what you are doing.
+ *                                     Default: true.
+ * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current
+ *                      database schema), `$term_id` is returned. When the term is successfully split, the
+ *                      new term_id is returned. A WP_Error is returned for miscellaneous errors.
+ */
+function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) {
+       global $wpdb;
+
+       if ( is_object( $term_id ) ) {
+               $shared_term = $term_id;
+               $term_id = intval( $shared_term->term_id );
+       }
+
+       if ( is_object( $term_taxonomy_id ) ) {
+               $term_taxonomy = $term_taxonomy_id;
+               $term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
+       }
+
+       // If there are no shared term_taxonomy rows, there's nothing to do here.
+       $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) );
+
+       if ( ! $shared_tt_count ) {
+               return $term_id;
+       }
+
+       /*
+        * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id.
+        * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db.
+        */
+       $check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
+       if ( $check_term_id != $term_id ) {
+               return $check_term_id;
+       }
+
+       // Pull up data about the currently shared slug, which we'll use to populate the new one.
+       if ( empty( $shared_term ) ) {
+               $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
+       }
+
+       $new_term_data = array(
+               'name' => $shared_term->name,
+               'slug' => $shared_term->slug,
+               'term_group' => $shared_term->term_group,
+       );
+
+       if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) {
+               return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error );
+       }
+
+       $new_term_id = (int) $wpdb->insert_id;
+
+       // Update the existing term_taxonomy to point to the newly created term.
+       $wpdb->update( $wpdb->term_taxonomy,
+               array( 'term_id' => $new_term_id ),
+               array( 'term_taxonomy_id' => $term_taxonomy_id )
+       );
+
+       // Reassign child terms to the new parent.
+       if ( empty( $term_taxonomy ) ) {
+               $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
+       }
+
+       $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) );
+       if ( ! empty( $children_tt_ids ) ) {
+               foreach ( $children_tt_ids as $child_tt_id ) {
+                       $wpdb->update( $wpdb->term_taxonomy,
+                               array( 'parent' => $new_term_id ),
+                               array( 'term_taxonomy_id' => $child_tt_id )
+                       );
+                       clean_term_cache( $term_id, $term_taxonomy->taxonomy );
+               }
+       } else {
+               // If the term has no children, we must force its taxonomy cache to be rebuilt separately.
+               clean_term_cache( $new_term_id, $term_taxonomy->taxonomy );
+       }
+
+       // Clean the cache for term taxonomies formerly shared with the current term.
+       $shared_term_taxonomies = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
+       if ( $shared_term_taxonomies ) {
+               foreach ( $shared_term_taxonomies as $shared_term_taxonomy ) {
+                       clean_term_cache( $term_id, $shared_term_taxonomy );
+               }
+       }
+
+       // Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}.
+       if ( $record ) {
+               $split_term_data = get_option( '_split_terms', array() );
+               if ( ! isset( $split_term_data[ $term_id ] ) ) {
+                       $split_term_data[ $term_id ] = array();
+               }
+
+               $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id;
+               update_option( '_split_terms', $split_term_data );
+       }
+
+       // If we've just split the final shared term, set the "finished" flag.
+       $shared_terms_exist = $wpdb->get_results(
+               "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
+                LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
+                GROUP BY t.term_id
+                HAVING term_tt_count > 1
+                LIMIT 1"
+       );
+       if ( ! $shared_terms_exist ) {
+               update_option( 'finished_splitting_shared_terms', true );
+       }
+
+       /**
+        * Fires after a previously shared taxonomy term is split into two separate terms.
+        *
+        * @since 4.2.0
+        *
+        * @param int    $term_id          ID of the formerly shared term.
+        * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
+        * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
+        * @param string $taxonomy         Taxonomy for the split term.
+        */
+       do_action( 'split_shared_term', $term_id, $new_term_id, $term_taxonomy_id, $term_taxonomy->taxonomy );
+
+       return $new_term_id;
+}
+
+/**
+ * Splits a batch of shared taxonomy terms.
+ *
+ * @since 4.3.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ */
+function _wp_batch_split_terms() {
+       global $wpdb;
+
+       $lock_name = 'term_split.lock';
+
+       // Try to lock.
+       $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
+
+       if ( ! $lock_result ) {
+               $lock_result = get_option( $lock_name );
+
+               // Bail if we were unable to create a lock, or if the existing lock is still valid.
+               if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) {
+                       wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
+                       return;
+               }
+       }
+
+       // Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
+       update_option( $lock_name, time() );
+
+       // Get a list of shared terms (those with more than one associated row in term_taxonomy).
+       $shared_terms = $wpdb->get_results(
+               "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
+                LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
+                GROUP BY t.term_id
+                HAVING term_tt_count > 1
+                LIMIT 10"
+       );
+
+       // No more terms, we're done here.
+       if ( ! $shared_terms ) {
+               update_option( 'finished_splitting_shared_terms', true );
+               delete_option( $lock_name );
+               return;
+       }
+
+       // Shared terms found? We'll need to run this script again.
+       wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
+
+       // Rekey shared term array for faster lookups.
+       $_shared_terms = array();
+       foreach ( $shared_terms as $shared_term ) {
+               $term_id = intval( $shared_term->term_id );
+               $_shared_terms[ $term_id ] = $shared_term;
+       }
+       $shared_terms = $_shared_terms;
+
+       // Get term taxonomy data for all shared terms.
+       $shared_term_ids = implode( ',', array_keys( $shared_terms ) );
+       $shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
+
+       // Split term data recording is slow, so we do it just once, outside the loop.
+       $split_term_data = get_option( '_split_terms', array() );
+       $skipped_first_term = $taxonomies = array();
+       foreach ( $shared_tts as $shared_tt ) {
+               $term_id = intval( $shared_tt->term_id );
+
+               // Don't split the first tt belonging to a given term_id.
+               if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
+                       $skipped_first_term[ $term_id ] = 1;
+                       continue;
+               }
+
+               if ( ! isset( $split_term_data[ $term_id ] ) ) {
+                       $split_term_data[ $term_id ] = array();
+               }
+
+               // Keep track of taxonomies whose hierarchies need flushing.
+               if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) {
+                       $taxonomies[ $shared_tt->taxonomy ] = 1;
+               }
+
+               // Split the term.
+               $split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false );
+       }
+
+       // Rebuild the cached hierarchy for each affected taxonomy.
+       foreach ( array_keys( $taxonomies ) as $tax ) {
+               delete_option( "{$tax}_children" );
+               _get_term_hierarchy( $tax );
+       }
+
+       update_option( '_split_terms', $split_term_data );
+
+       delete_option( $lock_name );
+}
+
+/**
+ * In order to avoid the _wp_batch_split_terms() job being accidentally removed,
+ * check that it's still scheduled while we haven't finished splitting terms.
+ *
+ * @ignore
+ * @since 4.3.0
+ */
+function _wp_check_for_scheduled_split_terms() {
+       if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_split_shared_term_batch' ) ) {
+               wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_split_shared_term_batch' );
+       }
+}
+
+/**
+ * Check default categories when a term gets split to see if any of them need to be updated.
+ *
+ * @ignore
+ * @since 4.2.0
+ *
+ * @param int    $term_id          ID of the formerly shared term.
+ * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
+ * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
+ * @param string $taxonomy         Taxonomy for the split term.
+ */
+function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
+       if ( 'category' != $taxonomy ) {
+               return;
+       }
+
+       foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) {
+               if ( $term_id == get_option( $option, -1 ) ) {
+                       update_option( $option, $new_term_id );
+               }
+       }
+}
+
+/**
+ * Check menu items when a term gets split to see if any of them need to be updated.
+ *
+ * @ignore
+ * @since 4.2.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int    $term_id          ID of the formerly shared term.
+ * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
+ * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
+ * @param string $taxonomy         Taxonomy for the split term.
+ */
+function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
+       global $wpdb;
+       $post_ids = $wpdb->get_col( $wpdb->prepare(
+               "SELECT m1.post_id
+               FROM {$wpdb->postmeta} AS m1
+                       INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id )
+                       INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id )
+               WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' )
+                       AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = '%s' )
+                       AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )",
+               $taxonomy,
+               $term_id
+       ) );
+
+       if ( $post_ids ) {
+               foreach ( $post_ids as $post_id ) {
+                       update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id );
+               }
+       }
+}
+
+/**
+ * If the term being split is a nav_menu, change associations.
+ *
+ * @ignore
+ * @since 4.3.0
+ *
+ * @param int    $term_id          ID of the formerly shared term.
+ * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
+ * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
+ * @param string $taxonomy         Taxonomy for the split term.
+ */
+function _wp_check_split_nav_menu_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
+       if ( 'nav_menu' !== $taxonomy ) {
+               return;
+       }
+
+       // Update menu locations.
+       $locations = get_nav_menu_locations();
+       foreach ( $locations as $location => $menu_id ) {
+               if ( $term_id == $menu_id ) {
+                       $locations[ $location ] = $new_term_id;
+               }
+       }
+       set_theme_mod( 'nav_menu_locations', $locations );
+}
+
+/**
+ * Get data about terms that previously shared a single term_id, but have since been split.
+ *
+ * @since 4.2.0
+ *
+ * @param int $old_term_id Term ID. This is the old, pre-split term ID.
+ * @return array Array of new term IDs, keyed by taxonomy.
+ */
+function wp_get_split_terms( $old_term_id ) {
+       $split_terms = get_option( '_split_terms', array() );
+
+       $terms = array();
+       if ( isset( $split_terms[ $old_term_id ] ) ) {
+               $terms = $split_terms[ $old_term_id ];
+       }
+
+       return $terms;
+}
+
+/**
+ * Get the new term ID corresponding to a previously split term.
+ *
+ * @since 4.2.0
+ *
+ * @param int    $old_term_id Term ID. This is the old, pre-split term ID.
+ * @param string $taxonomy    Taxonomy that the term belongs to.
+ * @return int|false If a previously split term is found corresponding to the old term_id and taxonomy,
+ *                   the new term_id will be returned. If no previously split term is found matching
+ *                   the parameters, returns false.
+ */
+function wp_get_split_term( $old_term_id, $taxonomy ) {
+       $split_terms = wp_get_split_terms( $old_term_id );
+
+       $term_id = false;
+       if ( isset( $split_terms[ $taxonomy ] ) ) {
+               $term_id = (int) $split_terms[ $taxonomy ];
+       }
+
+       return $term_id;
+}
+
+/**
+ * Determine whether a term is shared between multiple taxonomies.
+ *
+ * Shared taxonomy terms began to be split in 4.3, but failed cron tasks or other delays in upgrade routines may cause
+ * shared terms to remain.
+ *
+ * @since 4.4.0
+ *
+ * @param int $term_id
+ * @return bool
+ */
+function wp_term_is_shared( $term_id ) {
+       global $wpdb;
+
+       if ( get_option( 'finished_splitting_shared_terms' ) ) {
+               return false;
+       }
+
+       $tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
+
+       return $tt_count > 1;
+}
+
+/**
+ * Generate a permalink for a taxonomy term archive.
+ *
+ * @since 2.5.0
+ *
+ * @global WP_Rewrite $wp_rewrite
+ *
+ * @param object|int|string $term     The term object, ID, or slug whose link will be retrieved.
+ * @param string            $taxonomy Optional. Taxonomy. Default empty.
+ * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
+ */
+function get_term_link( $term, $taxonomy = '' ) {
+       global $wp_rewrite;
+
+       if ( !is_object($term) ) {
+               if ( is_int( $term ) ) {
+                       $term = get_term( $term, $taxonomy );
+               } else {
+                       $term = get_term_by( 'slug', $term, $taxonomy );
+               }
+       }
+
+       if ( !is_object($term) )
+               $term = new WP_Error('invalid_term', __('Empty Term'));
+
+       if ( is_wp_error( $term ) )
+               return $term;
+
+       $taxonomy = $term->taxonomy;
+
+       $termlink = $wp_rewrite->get_extra_permastruct($taxonomy);
+
+       $slug = $term->slug;
+       $t = get_taxonomy($taxonomy);
+
+       if ( empty($termlink) ) {
+               if ( 'category' == $taxonomy )
+                       $termlink = '?cat=' . $term->term_id;
+               elseif ( $t->query_var )
+                       $termlink = "?$t->query_var=$slug";
+               else
+                       $termlink = "?taxonomy=$taxonomy&term=$slug";
+               $termlink = home_url($termlink);
+       } else {
+               if ( $t->rewrite['hierarchical'] ) {
+                       $hierarchical_slugs = array();
+                       $ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
+                       foreach ( (array)$ancestors as $ancestor ) {
+                               $ancestor_term = get_term($ancestor, $taxonomy);
+                               $hierarchical_slugs[] = $ancestor_term->slug;
+                       }
+                       $hierarchical_slugs = array_reverse($hierarchical_slugs);
+                       $hierarchical_slugs[] = $slug;
+                       $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
+               } else {
+                       $termlink = str_replace("%$taxonomy%", $slug, $termlink);
+               }
+               $termlink = home_url( user_trailingslashit($termlink, 'category') );
+       }
+       // Back Compat filters.
+       if ( 'post_tag' == $taxonomy ) {
+
+               /**
+                * Filter the tag link.
+                *
+                * @since 2.3.0
+                * @deprecated 2.5.0 Use 'term_link' instead.
+                *
+                * @param string $termlink Tag link URL.
+                * @param int    $term_id  Term ID.
+                */
+               $termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
+       } elseif ( 'category' == $taxonomy ) {
+
+               /**
+                * Filter the category link.
+                *
+                * @since 1.5.0
+                * @deprecated 2.5.0 Use 'term_link' instead.
+                *
+                * @param string $termlink Category link URL.
+                * @param int    $term_id  Term ID.
+                */
+               $termlink = apply_filters( 'category_link', $termlink, $term->term_id );
+       }
+
+       /**
+        * Filter the term link.
+        *
+        * @since 2.5.0
+        *
+        * @param string $termlink Term link URL.
+        * @param object $term     Term object.
+        * @param string $taxonomy Taxonomy slug.
+        */
+       return apply_filters( 'term_link', $termlink, $term, $taxonomy );
+}
+
+/**
+ * Display the taxonomies of a post with available options.
+ *
+ * This function can be used within the loop to display the taxonomies for a
+ * post without specifying the Post ID. You can also use it outside the Loop to
+ * display the taxonomies for a specific post.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args {
+ *     Arguments about which post to use and how to format the output. Shares all of the arguments
+ *     supported by get_the_taxonomies(), in addition to the following.
+ *
+ *     @type  int|WP_Post $post   Post ID or object to get taxonomies of. Default current post.
+ *     @type  string      $before Displays before the taxonomies. Default empty string.
+ *     @type  string      $sep    Separates each taxonomy. Default is a space.
+ *     @type  string      $after  Displays after the taxonomies. Default empty string.
+ * }
+ * @param array $args See {@link get_the_taxonomies()} for a description of arguments and their defaults.
+ */
+function the_taxonomies( $args = array() ) {
+       $defaults = array(
+               'post' => 0,
+               'before' => '',
+               'sep' => ' ',
+               'after' => '',
+       );
+
+       $r = wp_parse_args( $args, $defaults );
+
+       echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
+}
+
+/**
+ * Retrieve all taxonomies associated with a post.
+ *
+ * This function can be used within the loop. It will also return an array of
+ * the taxonomies with links to the taxonomy and name.
+ *
+ * @since 2.5.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
+ * @param array $args {
+ *     Optional. Arguments about how to format the list of taxonomies. Default empty array.
+ *
+ *     @type string $template      Template for displaying a taxonomy label and list of terms.
+ *                                 Default is "Label: Terms."
+ *     @type string $term_template Template for displaying a single term in the list. Default is the term name
+ *                                 linked to its archive.
+ * }
+ * @return array List of taxonomies.
+ */
+function get_the_taxonomies( $post = 0, $args = array() ) {
+       $post = get_post( $post );
+
+       $args = wp_parse_args( $args, array(
+               /* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
+               'template' => __( '%s: %l.' ),
+               'term_template' => '<a href="%1$s">%2$s</a>',
+       ) );
+
+       $taxonomies = array();
+
+       if ( ! $post ) {
+               return $taxonomies;
+       }
+
+       foreach ( get_object_taxonomies( $post ) as $taxonomy ) {
+               $t = (array) get_taxonomy( $taxonomy );
+               if ( empty( $t['label'] ) ) {
+                       $t['label'] = $taxonomy;
+               }
+               if ( empty( $t['args'] ) ) {
+                       $t['args'] = array();
+               }
+               if ( empty( $t['template'] ) ) {
+                       $t['template'] = $args['template'];
+               }
+               if ( empty( $t['term_template'] ) ) {
+                       $t['term_template'] = $args['term_template'];
+               }
+
+               $terms = get_object_term_cache( $post->ID, $taxonomy );
+               if ( false === $terms ) {
+                       $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
+               }
+               $links = array();
+
+               foreach ( $terms as $term ) {
+                       $links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name );
+               }
+               if ( $links ) {
+                       $taxonomies[$taxonomy] = wp_sprintf( $t['template'], $t['label'], $links, $terms );
+               }
+       }
+       return $taxonomies;
+}
+
+/**
+ * Retrieve all taxonomies of a post with just the names.
+ *
+ * @since 2.5.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
+ * @return array
+ */
+function get_post_taxonomies( $post = 0 ) {
+       $post = get_post( $post );
+
+       return get_object_taxonomies($post);
+}
+
+/**
+ * Determine if the given object is associated with any of the given terms.
+ *
+ * The given terms are checked against the object's terms' term_ids, names and slugs.
+ * Terms given as integers will only be checked against the object's terms' term_ids.
+ * If no terms are given, determines if object is associated with any terms in the given taxonomy.
+ *
+ * @since 2.7.0
+ *
+ * @param int              $object_id ID of the object (post ID, link ID, ...).
+ * @param string           $taxonomy  Single taxonomy name.
+ * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
+ * @return bool|WP_Error WP_Error on input error.
+ */
+function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
+       if ( !$object_id = (int) $object_id )
+               return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
+
+       $object_terms = get_object_term_cache( $object_id, $taxonomy );
+       if ( false === $object_terms ) {
+               $object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) );
+               wp_cache_set( $object_id, $object_terms, "{$taxonomy}_relationships" );
+       }
+
+       if ( is_wp_error( $object_terms ) )
+               return $object_terms;
+       if ( empty( $object_terms ) )
+               return false;
+       if ( empty( $terms ) )
+               return ( !empty( $object_terms ) );
+
+       $terms = (array) $terms;
+
+       if ( $ints = array_filter( $terms, 'is_int' ) )
+               $strs = array_diff( $terms, $ints );
+       else
+               $strs =& $terms;
+
+       foreach ( $object_terms as $object_term ) {
+               // If term is an int, check against term_ids only.
+               if ( $ints && in_array( $object_term->term_id, $ints ) ) {
+                       return true;
+               }
+
+               if ( $strs ) {
+                       // Only check numeric strings against term_id, to avoid false matches due to type juggling.
+                       $numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
+                       if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
+                               return true;
+                       }
+
+                       if ( in_array( $object_term->name, $strs ) ) return true;
+                       if ( in_array( $object_term->slug, $strs ) ) return true;
+               }
+       }
+
+       return false;
+}
+
+/**
+ * Determine if the given object type is associated with the given taxonomy.
+ *
+ * @since 3.0.0
+ *
+ * @param string $object_type Object type string.
+ * @param string $taxonomy    Single taxonomy name.
+ * @return bool True if object is associated with the taxonomy, otherwise false.
+ */
+function is_object_in_taxonomy( $object_type, $taxonomy ) {
+       $taxonomies = get_object_taxonomies( $object_type );
+       if ( empty( $taxonomies ) ) {
+               return false;
+       }
+       return in_array( $taxonomy, $taxonomies );
+}
+
+/**
+ * Get an array of ancestor IDs for a given object.
+ *
+ * @since 3.1.0
+ * @since 4.1.0 Introduced the `$resource_type` argument.
+ *
+ * @param int    $object_id     Optional. The ID of the object. Default 0.
+ * @param string $object_type   Optional. The type of object for which we'll be retrieving
+ *                              ancestors. Accepts a post type or a taxonomy name. Default empty.
+ * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type'
+ *                              or 'taxonomy'. Default empty.
+ * @return array An array of ancestors from lowest to highest in the hierarchy.
+ */
+function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) {
+       $object_id = (int) $object_id;
+
+       $ancestors = array();
+
+       if ( empty( $object_id ) ) {
+
+               /** This filter is documented in wp-includes/taxonomy-functions.php */
+               return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
+       }
+
+       if ( ! $resource_type ) {
+               if ( is_taxonomy_hierarchical( $object_type ) ) {
+                       $resource_type = 'taxonomy';
+               } elseif ( post_type_exists( $object_type ) ) {
+                       $resource_type = 'post_type';
+               }
+       }
+
+       if ( 'taxonomy' === $resource_type ) {
+               $term = get_term($object_id, $object_type);
+               while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
+                       $ancestors[] = (int) $term->parent;
+                       $term = get_term($term->parent, $object_type);
+               }
+       } elseif ( 'post_type' === $resource_type ) {
+               $ancestors = get_post_ancestors($object_id);
+       }
+
+       /**
+        * Filter a given object's ancestors.
+        *
+        * @since 3.1.0
+        * @since 4.1.1 Introduced the `$resource_type` parameter.
+        *
+        * @param array  $ancestors     An array of object ancestors.
+        * @param int    $object_id     Object ID.
+        * @param string $object_type   Type of object.
+        * @param string $resource_type Type of resource $object_type is.
+        */
+       return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
+}
+
+/**
+ * Returns the term's parent's term_ID.
+ *
+ * @since 3.1.0
+ *
+ * @param int    $term_id  Term ID.
+ * @param string $taxonomy Taxonomy name.
+ * @return int|false False on error.
+ */
+function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) {
+       $term = get_term( $term_id, $taxonomy );
+       if ( ! $term || is_wp_error( $term ) ) {
+               return false;
+       }
+       return (int) $term->parent;
+}
+
+/**
+ * Checks the given subset of the term hierarchy for hierarchy loops.
+ * Prevents loops from forming and breaks those that it finds.
+ *
+ * Attached to the {@see 'wp_update_term_parent'} filter.
+ *
+ * @since 3.1.0
+ *
+ * @param int    $parent   `term_id` of the parent for the term we're checking.
+ * @param int    $term_id  The term we're checking.
+ * @param string $taxonomy The taxonomy of the term we're checking.
+ *
+ * @return int The new parent for the term.
+ */
+function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
+       // Nothing fancy here - bail
+       if ( !$parent )
+               return 0;
+
+       // Can't be its own parent.
+       if ( $parent == $term_id )
+               return 0;
+
+       // Now look for larger loops.
+       if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) )
+               return $parent; // No loop
+
+       // Setting $parent to the given value causes a loop.
+       if ( isset( $loop[$term_id] ) )
+               return 0;
+
+       // There's a loop, but it doesn't contain $term_id. Break the loop.
+       foreach ( array_keys( $loop ) as $loop_member )
+               wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) );
+
+       return $parent;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesuserfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/user-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/user-functions.php  2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/user-functions.php    2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,2294 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * User API: Top-level users functionality
- *
- * @package WordPress
- * @subpackage Users
- * @since 4.4.0
- */
-
-/**
- * Authenticate user with remember capability.
- *
- * The credentials is an array that has 'user_login', 'user_password', and
- * 'remember' indices. If the credentials is not given, then the log in form
- * will be assumed and used if set.
- *
- * The various authentication cookies will be set by this function and will be
- * set for a longer period depending on if the 'remember' credential is set to
- * true.
- *
- * @since 2.5.0
- *
- * @global string $auth_secure_cookie
- *
- * @param array       $credentials   Optional. User info in order to sign on.
- * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
- * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
- */
-function wp_signon( $credentials = array(), $secure_cookie = '' ) {
-       if ( empty($credentials) ) {
-               if ( ! empty($_POST['log']) )
-                       $credentials['user_login'] = $_POST['log'];
-               if ( ! empty($_POST['pwd']) )
-                       $credentials['user_password'] = $_POST['pwd'];
-               if ( ! empty($_POST['rememberme']) )
-                       $credentials['remember'] = $_POST['rememberme'];
-       }
-
-       if ( !empty($credentials['remember']) )
-               $credentials['remember'] = true;
-       else
-               $credentials['remember'] = false;
-
-       /**
-        * Fires before the user is authenticated.
-        *
-        * The variables passed to the callbacks are passed by reference,
-        * and can be modified by callback functions.
-        *
-        * @since 1.5.1
-        *
-        * @todo Decide whether to deprecate the wp_authenticate action.
-        *
-        * @param string $user_login    Username, passed by reference.
-        * @param string $user_password User password, passed by reference.
-        */
-       do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
-
-       if ( '' === $secure_cookie )
-               $secure_cookie = is_ssl();
-
-       /**
-        * Filter whether to use a secure sign-on cookie.
-        *
-        * @since 3.1.0
-        *
-        * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
-        * @param array $credentials {
-        *     Array of entered sign-on data.
-        *
-        *     @type string $user_login    Username.
-        *     @type string $user_password Password entered.
-        *     @type bool   $remember      Whether to 'remember' the user. Increases the time
-        *                                 that the cookie will be kept. Default false.
-        * }
-        */
-       $secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
-
-       global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
-       $auth_secure_cookie = $secure_cookie;
-
-       add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
-
-       $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
-
-       if ( is_wp_error($user) ) {
-               if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
-                       $user = new WP_Error('', '');
-               }
-
-               return $user;
-       }
-
-       wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
-       /**
-        * Fires after the user has successfully logged in.
-        *
-        * @since 1.5.0
-        *
-        * @param string  $user_login Username.
-        * @param WP_User $user       WP_User object of the logged-in user.
-        */
-       do_action( 'wp_login', $user->user_login, $user );
-       return $user;
-}
-
-/**
- * Authenticate the user using the username and password.
- *
- * @since 2.8.0
- *
- * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
- * @param string                $username Username for authentication.
- * @param string                $password Password for authentication.
- * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
- */
-function wp_authenticate_username_password($user, $username, $password) {
-       if ( $user instanceof WP_User ) {
-               return $user;
-       }
-
-       if ( empty($username) || empty($password) ) {
-               if ( is_wp_error( $user ) )
-                       return $user;
-
-               $error = new WP_Error();
-
-               if ( empty($username) )
-                       $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
-
-               if ( empty($password) )
-                       $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
-
-               return $error;
-       }
-
-       $user = get_user_by('login', $username);
-
-       if ( !$user ) {
-               return new WP_Error( 'invalid_username',
-                       __( '<strong>ERROR</strong>: Invalid username.' ) .
-                       ' <a href="' . wp_lostpassword_url() . '">' .
-                       __( 'Lost your password?' ) .
-                       '</a>'
-               );
-       }
-
-       /**
-        * Filter whether the given user can be authenticated with the provided $password.
-        *
-        * @since 2.5.0
-        *
-        * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
-        *                                   callback failed authentication.
-        * @param string           $password Password to check against the user.
-        */
-       $user = apply_filters( 'wp_authenticate_user', $user, $password );
-       if ( is_wp_error($user) )
-               return $user;
-
-       if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
-               return new WP_Error( 'incorrect_password',
-                       sprintf(
-                               /* translators: %s: user name */
-                               __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
-                               '<strong>' . $username . '</strong>'
-                       ) .
-                       ' <a href="' . wp_lostpassword_url() . '">' .
-                       __( 'Lost your password?' ) .
-                       '</a>'
-               );
-       }
-
-       return $user;
-}
-
-/**
- * Authenticate the user using the WordPress auth cookie.
- *
- * @since 2.8.0
- *
- * @global string $auth_secure_cookie
- *
- * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
- * @param string                $username Username. If not empty, cancels the cookie authentication.
- * @param string                $password Password. If not empty, cancels the cookie authentication.
- * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
- */
-function wp_authenticate_cookie($user, $username, $password) {
-       if ( $user instanceof WP_User ) {
-               return $user;
-       }
-
-       if ( empty($username) && empty($password) ) {
-               $user_id = wp_validate_auth_cookie();
-               if ( $user_id )
-                       return new WP_User($user_id);
-
-               global $auth_secure_cookie;
-
-               if ( $auth_secure_cookie )
-                       $auth_cookie = SECURE_AUTH_COOKIE;
-               else
-                       $auth_cookie = AUTH_COOKIE;
-
-               if ( !empty($_COOKIE[$auth_cookie]) )
-                       return new WP_Error('expired_session', __('Please log in again.'));
-
-               // If the cookie is not set, be silent.
-       }
-
-       return $user;
-}
-
-/**
- * For Multisite blogs, check if the authenticated user has been marked as a
- * spammer, or if the user's primary blog has been marked as spam.
- *
- * @since 3.7.0
- *
- * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null.
- * @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer.
- */
-function wp_authenticate_spam_check( $user ) {
-       if ( $user instanceof WP_User && is_multisite() ) {
-               /**
-                * Filter whether the user has been marked as a spammer.
-                *
-                * @since 3.7.0
-                *
-                * @param bool    $spammed Whether the user is considered a spammer.
-                * @param WP_User $user    User to check against.
-                */
-               $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
-
-               if ( $spammed )
-                       return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
-       }
-       return $user;
-}
-
-/**
- * Validate the logged-in cookie.
- *
- * Checks the logged-in cookie if the previous auth cookie could not be
- * validated and parsed.
- *
- * This is a callback for the determine_current_user filter, rather than API.
- *
- * @since 3.9.0
- *
- * @param int|bool $user_id The user ID (or false) as received from the
- *                       determine_current_user filter.
- * @return int|false User ID if validated, false otherwise. If a user ID from
- *                   an earlier filter callback is received, that value is returned.
- */
-function wp_validate_logged_in_cookie( $user_id ) {
-       if ( $user_id ) {
-               return $user_id;
-       }
-
-       if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) {
-               return false;
-       }
-
-       return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' );
-}
-
-/**
- * Number of posts user has written.
- *
- * @since 3.0.0
- * @since 4.1.0 Added `$post_type` argument.
- * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array
- *              of post types to `$post_type`.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int          $userid      User ID.
- * @param array|string $post_type   Optional. Single post type or array of post types to count the number of posts for. Default 'post'.
- * @param bool         $public_only Optional. Whether to only return counts for public posts. Default false.
- * @return int Number of posts the user has written in this post type.
- */
-function count_user_posts( $userid, $post_type = 'post', $public_only = false ) {
-       global $wpdb;
-
-       $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
-
-       $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
-
-       /**
-        * Filter the number of posts a user has written.
-        *
-        * @since 2.7.0
-        * @since 4.1.0 Added `$post_type` argument.
-        * @since 4.3.1 Added `$public_only` argument.
-        *
-        * @param int          $count       The user's post count.
-        * @param int          $userid      User ID.
-        * @param string|array $post_type   Single post type or array of post types to count the number of posts for.
-        * @param bool         $public_only Whether to limit counted posts to public posts.
-        */
-       return apply_filters( 'get_usernumposts', $count, $userid, $post_type, $public_only );
-}
-
-/**
- * Number of posts written by a list of users.
- *
- * @since 3.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array        $users       Array of user IDs.
- * @param string|array $post_type   Optional. Single post type or array of post types to check. Defaults to 'post'.
- * @param bool         $public_only Optional. Only return counts for public posts.  Defaults to false.
- * @return array Amount of posts each user has written.
- */
-function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
-       global $wpdb;
-
-       $count = array();
-       if ( empty( $users ) || ! is_array( $users ) )
-               return $count;
-
-       $userlist = implode( ',', array_map( 'absint', $users ) );
-       $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
-
-       $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
-       foreach ( $result as $row ) {
-               $count[ $row[0] ] = $row[1];
-       }
-
-       foreach ( $users as $id ) {
-               if ( ! isset( $count[ $id ] ) )
-                       $count[ $id ] = 0;
-       }
-
-       return $count;
-}
-
-//
-// User option functions
-//
-
-/**
- * Get the current user's ID
- *
- * @since MU
- *
- * @return int The current user's ID
- */
-function get_current_user_id() {
-       if ( ! function_exists( 'wp_get_current_user' ) )
-               return 0;
-       $user = wp_get_current_user();
-       return ( isset( $user->ID ) ? (int) $user->ID : 0 );
-}
-
-/**
- * Retrieve user option that can be either per Site or per Network.
- *
- * If the user ID is not given, then the current user will be used instead. If
- * the user ID is given, then the user data will be retrieved. The filter for
- * the result, will also pass the original option name and finally the user data
- * object as the third parameter.
- *
- * The option will first check for the per site name and then the per Network name.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $option     User option name.
- * @param int    $user       Optional. User ID.
- * @param string $deprecated Use get_option() to check for an option in the options table.
- * @return mixed User option value on success, false on failure.
- */
-function get_user_option( $option, $user = 0, $deprecated = '' ) {
-       global $wpdb;
-
-       if ( !empty( $deprecated ) )
-               _deprecated_argument( __FUNCTION__, '3.0' );
-
-       if ( empty( $user ) )
-               $user = get_current_user_id();
-
-       if ( ! $user = get_userdata( $user ) )
-               return false;
-
-       $prefix = $wpdb->get_blog_prefix();
-       if ( $user->has_prop( $prefix . $option ) ) // Blog specific
-               $result = $user->get( $prefix . $option );
-       elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
-               $result = $user->get( $option );
-       else
-               $result = false;
-
-       /**
-        * Filter a specific user option value.
-        *
-        * The dynamic portion of the hook name, `$option`, refers to the user option name.
-        *
-        * @since 2.5.0
-        *
-        * @param mixed   $result Value for the user's option.
-        * @param string  $option Name of the option being retrieved.
-        * @param WP_User $user   WP_User object of the user whose option is being retrieved.
-        */
-       return apply_filters( "get_user_option_{$option}", $result, $option, $user );
-}
-
-/**
- * Update user option with global blog capability.
- *
- * User options are just like user metadata except that they have support for
- * global blog options. If the 'global' parameter is false, which it is by default
- * it will prepend the WordPress table prefix to the option name.
- *
- * Deletes the user option if $newvalue is empty.
- *
- * @since 2.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int    $user_id     User ID.
- * @param string $option_name User option name.
- * @param mixed  $newvalue    User option value.
- * @param bool   $global      Optional. Whether option name is global or blog specific.
- *                            Default false (blog specific).
- * @return int|bool User meta ID if the option didn't exist, true on successful update,
- *                  false on failure.
- */
-function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
-       global $wpdb;
-
-       if ( !$global )
-               $option_name = $wpdb->get_blog_prefix() . $option_name;
-
-       return update_user_meta( $user_id, $option_name, $newvalue );
-}
-
-/**
- * Delete user option with global blog capability.
- *
- * User options are just like user metadata except that they have support for
- * global blog options. If the 'global' parameter is false, which it is by default
- * it will prepend the WordPress table prefix to the option name.
- *
- * @since 3.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int    $user_id     User ID
- * @param string $option_name User option name.
- * @param bool   $global      Optional. Whether option name is global or blog specific.
- *                            Default false (blog specific).
- * @return bool True on success, false on failure.
- */
-function delete_user_option( $user_id, $option_name, $global = false ) {
-       global $wpdb;
-
-       if ( !$global )
-               $option_name = $wpdb->get_blog_prefix() . $option_name;
-       return delete_user_meta( $user_id, $option_name );
-}
-
-/**
- * Retrieve list of users matching criteria.
- *
- * @since 3.1.0
- *
- * @see WP_User_Query
- *
- * @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()}
- *                    for more information on accepted arguments.
- * @return array List of users.
- */
-function get_users( $args = array() ) {
-
-       $args = wp_parse_args( $args );
-       $args['count_total'] = false;
-
-       $user_search = new WP_User_Query($args);
-
-       return (array) $user_search->get_results();
-}
-
-/**
- * Get the blogs a user belongs to.
- *
- * @since 3.0.0
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param int  $user_id User ID
- * @param bool $all     Whether to retrieve all blogs, or only blogs that are not
- *                      marked as deleted, archived, or spam.
- * @return array A list of the user's blogs. An empty array if the user doesn't exist
- *               or belongs to no blogs.
- */
-function get_blogs_of_user( $user_id, $all = false ) {
-       global $wpdb;
-
-       $user_id = (int) $user_id;
-
-       // Logged out users can't have blogs
-       if ( empty( $user_id ) )
-               return array();
-
-       $keys = get_user_meta( $user_id );
-       if ( empty( $keys ) )
-               return array();
-
-       if ( ! is_multisite() ) {
-               $blog_id = get_current_blog_id();
-               $blogs = array( $blog_id => new stdClass );
-               $blogs[ $blog_id ]->userblog_id = $blog_id;
-               $blogs[ $blog_id ]->blogname = get_option('blogname');
-               $blogs[ $blog_id ]->domain = '';
-               $blogs[ $blog_id ]->path = '';
-               $blogs[ $blog_id ]->site_id = 1;
-               $blogs[ $blog_id ]->siteurl = get_option('siteurl');
-               $blogs[ $blog_id ]->archived = 0;
-               $blogs[ $blog_id ]->spam = 0;
-               $blogs[ $blog_id ]->deleted = 0;
-               return $blogs;
-       }
-
-       $blogs = array();
-
-       if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
-               $blog = get_blog_details( 1 );
-               if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
-                       $blogs[ 1 ] = (object) array(
-                               'userblog_id' => 1,
-                               'blogname'    => $blog->blogname,
-                               'domain'      => $blog->domain,
-                               'path'        => $blog->path,
-                               'site_id'     => $blog->site_id,
-                               'siteurl'     => $blog->siteurl,
-                               'archived'    => $blog->archived,
-                               'mature'      => $blog->mature,
-                               'spam'        => $blog->spam,
-                               'deleted'     => $blog->deleted,
-                       );
-               }
-               unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
-       }
-
-       $keys = array_keys( $keys );
-
-       foreach ( $keys as $key ) {
-               if ( 'capabilities' !== substr( $key, -12 ) )
-                       continue;
-               if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
-                       continue;
-               $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
-               if ( ! is_numeric( $blog_id ) )
-                       continue;
-
-               $blog_id = (int) $blog_id;
-               $blog = get_blog_details( $blog_id );
-               if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
-                       $blogs[ $blog_id ] = (object) array(
-                               'userblog_id' => $blog_id,
-                               'blogname'    => $blog->blogname,
-                               'domain'      => $blog->domain,
-                               'path'        => $blog->path,
-                               'site_id'     => $blog->site_id,
-                               'siteurl'     => $blog->siteurl,
-                               'archived'    => $blog->archived,
-                               'mature'      => $blog->mature,
-                               'spam'        => $blog->spam,
-                               'deleted'     => $blog->deleted,
-                       );
-               }
-       }
-
-       /**
-        * Filter the list of blogs a user belongs to.
-        *
-        * @since MU
-        *
-        * @param array $blogs   An array of blog objects belonging to the user.
-        * @param int   $user_id User ID.
-        * @param bool  $all     Whether the returned blogs array should contain all blogs, including
-        *                       those marked 'deleted', 'archived', or 'spam'. Default false.
-        */
-       return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
-}
-
-/**
- * Find out whether a user is a member of a given blog.
- *
- * @since MU 1.1
- *
- * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
- * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
- * @return bool
- */
-function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
-       global $wpdb;
-
-       $user_id = (int) $user_id;
-       $blog_id = (int) $blog_id;
-
-       if ( empty( $user_id ) ) {
-               $user_id = get_current_user_id();
-       }
-
-       // Technically not needed, but does save calls to get_blog_details and get_user_meta
-       // in the event that the function is called when a user isn't logged in
-       if ( empty( $user_id ) ) {
-               return false;
-       } else {
-               $user = get_userdata( $user_id );
-               if ( ! $user instanceof WP_User ) {
-                       return false;
-               }
-       }
-
-       if ( ! is_multisite() ) {
-               return true;
-       }
-
-       if ( empty( $blog_id ) ) {
-               $blog_id = get_current_blog_id();
-       }
-
-       $blog = get_blog_details( $blog_id );
-
-       if ( ! $blog || ! isset( $blog->domain ) || $blog->archived || $blog->spam || $blog->deleted ) {
-               return false;
-       }
-
-       $keys = get_user_meta( $user_id );
-       if ( empty( $keys ) ) {
-               return false;
-       }
-
-       // no underscore before capabilities in $base_capabilities_key
-       $base_capabilities_key = $wpdb->base_prefix . 'capabilities';
-       $site_capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities';
-
-       if ( isset( $keys[ $base_capabilities_key ] ) && $blog_id == 1 ) {
-               return true;
-       }
-
-       if ( isset( $keys[ $site_capabilities_key ] ) ) {
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * Add meta data field to a user.
- *
- * Post meta data is called "Custom Fields" on the Administration Screens.
- *
- * @since 3.0.0
- * @link https://codex.wordpress.org/Function_Reference/add_user_meta
- *
- * @param int    $user_id    User ID.
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Metadata value.
- * @param bool   $unique     Optional, default is false. Whether the same key should not be added.
- * @return int|false Meta ID on success, false on failure.
- */
-function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
-       return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
-}
-
-/**
- * Remove metadata matching criteria from a user.
- *
- * You can match based on the key, or key and value. Removing based on key and
- * value, will keep from removing duplicate metadata with the same key. It also
- * allows removing all metadata matching key, if needed.
- *
- * @since 3.0.0
- * @link https://codex.wordpress.org/Function_Reference/delete_user_meta
- *
- * @param int    $user_id    User ID
- * @param string $meta_key   Metadata name.
- * @param mixed  $meta_value Optional. Metadata value.
- * @return bool True on success, false on failure.
- */
-function delete_user_meta($user_id, $meta_key, $meta_value = '') {
-       return delete_metadata('user', $user_id, $meta_key, $meta_value);
-}
-
-/**
- * Retrieve user meta field for a user.
- *
- * @since 3.0.0
- * @link https://codex.wordpress.org/Function_Reference/get_user_meta
- *
- * @param int    $user_id User ID.
- * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
- * @param bool   $single  Whether to return a single value.
- * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
- */
-function get_user_meta($user_id, $key = '', $single = false) {
-       return get_metadata('user', $user_id, $key, $single);
-}
-
-/**
- * Update user meta field based on user ID.
- *
- * Use the $prev_value parameter to differentiate between meta fields with the
- * same key and user ID.
- *
- * If the meta field for the user does not exist, it will be added.
- *
- * @since 3.0.0
- * @link https://codex.wordpress.org/Function_Reference/update_user_meta
- *
- * @param int    $user_id    User ID.
- * @param string $meta_key   Metadata key.
- * @param mixed  $meta_value Metadata value.
- * @param mixed  $prev_value Optional. Previous value to check before removing.
- * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
- */
-function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
-       return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
-}
-
-/**
- * Count number of users who have each of the user roles.
- *
- * Assumes there are neither duplicated nor orphaned capabilities meta_values.
- * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
- * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
- * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
- *
- * @since 3.0.0
- * @since 4.4.0 The number of users with no role is now included in the `none` element.
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string $strategy 'time' or 'memory'
- * @return array Includes a grand total and an array of counts indexed by role strings.
- */
-function count_users($strategy = 'time') {
-       global $wpdb;
-
-       // Initialize
-       $id = get_current_blog_id();
-       $blog_prefix = $wpdb->get_blog_prefix($id);
-       $result = array();
-
-       if ( 'time' == $strategy ) {
-               $avail_roles = wp_roles()->get_names();
-
-               // Build a CPU-intensive query that will return concise information.
-               $select_count = array();
-               foreach ( $avail_roles as $this_role => $name ) {
-                       $select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%');
-               }
-               $select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))";
-               $select_count = implode(', ', $select_count);
-
-               // Add the meta_value index to the selection list, then run the query.
-               $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
-
-               // Run the previous loop again to associate results with role names.
-               $col = 0;
-               $role_counts = array();
-               foreach ( $avail_roles as $this_role => $name ) {
-                       $count = (int) $row[$col++];
-                       if ($count > 0) {
-                               $role_counts[$this_role] = $count;
-                       }
-               }
-
-               $role_counts['none'] = (int) $row[$col++];
-
-               // Get the meta_value index from the end of the result set.
-               $total_users = (int) $row[$col];
-
-               $result['total_users'] = $total_users;
-               $result['avail_roles'] =& $role_counts;
-       } else {
-               $avail_roles = array(
-                       'none' => 0,
-               );
-
-               $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
-
-               foreach ( $users_of_blog as $caps_meta ) {
-                       $b_roles = maybe_unserialize($caps_meta);
-                       if ( ! is_array( $b_roles ) )
-                               continue;
-                       if ( empty( $b_roles ) ) {
-                               $avail_roles['none']++;
-                       }
-                       foreach ( $b_roles as $b_role => $val ) {
-                               if ( isset($avail_roles[$b_role]) ) {
-                                       $avail_roles[$b_role]++;
-                               } else {
-                                       $avail_roles[$b_role] = 1;
-                               }
-                       }
-               }
-
-               $result['total_users'] = count( $users_of_blog );
-               $result['avail_roles'] =& $avail_roles;
-       }
-
-       if ( is_multisite() ) {
-               $result['avail_roles']['none'] = 0;
-       }
-
-       return $result;
-}
-
-//
-// Private helper functions
-//
-
-/**
- * Set up global user vars.
- *
- * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
- *
- * @since 2.0.4
- *
- * @global string $user_login    The user username for logging in
- * @global object $userdata      User data.
- * @global int    $user_level    The level of the user
- * @global int    $user_ID       The ID of the user
- * @global string $user_email    The email address of the user
- * @global string $user_url      The url in the user's profile
- * @global string $user_identity The display name of the user
- *
- * @param int $for_user_id Optional. User ID to set up global data.
- */
-function setup_userdata($for_user_id = '') {
-       global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
-
-       if ( '' == $for_user_id )
-               $for_user_id = get_current_user_id();
-       $user = get_userdata( $for_user_id );
-
-       if ( ! $user ) {
-               $user_ID = 0;
-               $user_level = 0;
-               $userdata = null;
-               $user_login = $user_email = $user_url = $user_identity = '';
-               return;
-       }
-
-       $user_ID    = (int) $user->ID;
-       $user_level = (int) $user->user_level;
-       $userdata   = $user;
-       $user_login = $user->user_login;
-       $user_email = $user->user_email;
-       $user_url   = $user->user_url;
-       $user_identity = $user->display_name;
-}
-
-/**
- * Create dropdown HTML content of users.
- *
- * The content can either be displayed, which it is by default or retrieved by
- * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
- * need to be used; all users will be displayed in that case. Only one can be
- * used, either 'include' or 'exclude', but not both.
- *
- * The available arguments are as follows:
- *
- * @since 2.3.0
- *
- * @global int  $blog_id
- *
- * @param array|string $args {
- *     Optional. Array or string of arguments to generate a drop-down of users.
- *     {@see WP_User_Query::prepare_query() for additional available arguments.
- *
- *     @type string       $show_option_all         Text to show as the drop-down default (all).
- *                                                 Default empty.
- *     @type string       $show_option_none        Text to show as the drop-down default when no
- *                                                 users were found. Default empty.
- *     @type int|string   $option_none_value       Value to use for $show_option_non when no users
- *                                                 were found. Default -1.
- *     @type string       $hide_if_only_one_author Whether to skip generating the drop-down
- *                                                 if only one user was found. Default empty.
- *     @type string       $orderby                 Field to order found users by. Accepts user fields.
- *                                                 Default 'display_name'.
- *     @type string       $order                   Whether to order users in ascending or descending
- *                                                 order. Accepts 'ASC' (ascending) or 'DESC' (descending).
- *                                                 Default 'ASC'.
- *     @type array|string $include                 Array or comma-separated list of user IDs to include.
- *                                                 Default empty.
- *     @type array|string $exclude                 Array or comma-separated list of user IDs to exclude.
- *                                                 Default empty.
- *     @type bool|int     $multi                   Whether to skip the ID attribute on the 'select' element.
- *                                                 Accepts 1|true or 0|false. Default 0|false.
- *     @type string       $show                    User table column to display. If the selected item is empty
- *                                                 then the 'user_login' will be displayed in parentheses.
- *                                                 Accepts user fields. Default 'display_name'.
- *     @type int|bool     $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
- *                                                 or 0|false (return). Default 1|true.
- *     @type int          $selected                Which user ID should be selected. Default 0.
- *     @type bool         $include_selected        Whether to always include the selected user ID in the drop-
- *                                                 down. Default false.
- *     @type string       $name                    Name attribute of select element. Default 'user'.
- *     @type string       $id                      ID attribute of the select element. Default is the value of $name.
- *     @type string       $class                   Class attribute of the select element. Default empty.
- *     @type int          $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
- *     @type string       $who                     Which type of users to query. Accepts only an empty string or
- *                                                 'authors'. Default empty.
- * }
- * @return string String of HTML content.
- */
-function wp_dropdown_users( $args = '' ) {
-       $defaults = array(
-               'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
-               'orderby' => 'display_name', 'order' => 'ASC',
-               'include' => '', 'exclude' => '', 'multi' => 0,
-               'show' => 'display_name', 'echo' => 1,
-               'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
-               'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
-               'option_none_value' => -1
-       );
-
-       $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
-
-       $r = wp_parse_args( $args, $defaults );
-       $show = $r['show'];
-       $show_option_all = $r['show_option_all'];
-       $show_option_none = $r['show_option_none'];
-       $option_none_value = $r['option_none_value'];
-
-       $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
-       $query_args['fields'] = array( 'ID', 'user_login', $show );
-
-       /**
-        * Filter the query arguments for the user drop-down.
-        *
-        * @since 4.4.0
-        *
-        * @param array $query_args The query arguments for wp_dropdown_users().
-        * @param array $r          The default arguments for wp_dropdown_users().
-        */
-       $query_args = apply_filters( 'wp_dropdown_users_args', $query_args, $r );
-
-       $users = get_users( $query_args );
-
-       $output = '';
-       if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) {
-               $name = esc_attr( $r['name'] );
-               if ( $r['multi'] && ! $r['id'] ) {
-                       $id = '';
-               } else {
-                       $id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'";
-               }
-               $output = "<select name='{$name}'{$id} class='" . $r['class'] . "'>\n";
-
-               if ( $show_option_all ) {
-                       $output .= "\t<option value='0'>$show_option_all</option>\n";
-               }
-
-               if ( $show_option_none ) {
-                       $_selected = selected( $option_none_value, $r['selected'], false );
-                       $output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
-               }
-
-               $found_selected = false;
-               foreach ( (array) $users as $user ) {
-                       $user->ID = (int) $user->ID;
-                       $_selected = selected( $user->ID, $r['selected'], false );
-                       if ( $_selected ) {
-                               $found_selected = true;
-                       }
-                       $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
-                       $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
-               }
-
-               if ( $r['include_selected'] && ! $found_selected && ( $r['selected'] > 0 ) ) {
-                       $user = get_userdata( $r['selected'] );
-                       $_selected = selected( $user->ID, $r['selected'], false );
-                       $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
-                       $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
-               }
-
-               $output .= "</select>";
-       }
-
-       /**
-        * Filter the wp_dropdown_users() HTML output.
-        *
-        * @since 2.3.0
-        *
-        * @param string $output HTML output generated by wp_dropdown_users().
-        */
-       $html = apply_filters( 'wp_dropdown_users', $output );
-
-       if ( $r['echo'] ) {
-               echo $html;
-       }
-       return $html;
-}
-
-/**
- * Sanitize user field based on context.
- *
- * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
- * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
- * when calling filters.
- *
- * @since 2.3.0
- *
- * @param string $field   The user Object field name.
- * @param mixed  $value   The user Object value.
- * @param int    $user_id User ID.
- * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
- *                        'attribute' and 'js'.
- * @return mixed Sanitized value.
- */
-function sanitize_user_field($field, $value, $user_id, $context) {
-       $int_fields = array('ID');
-       if ( in_array($field, $int_fields) )
-               $value = (int) $value;
-
-       if ( 'raw' == $context )
-               return $value;
-
-       if ( !is_string($value) && !is_numeric($value) )
-               return $value;
-
-       $prefixed = false !== strpos( $field, 'user_' );
-
-       if ( 'edit' == $context ) {
-               if ( $prefixed ) {
-
-                       /** This filter is documented in wp-includes/post-functions.php */
-                       $value = apply_filters( "edit_{$field}", $value, $user_id );
-               } else {
-
-                       /**
-                        * Filter a user field value in the 'edit' context.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
-                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param mixed $value   Value of the prefixed user field.
-                        * @param int   $user_id User ID.
-                        */
-                       $value = apply_filters( "edit_user_{$field}", $value, $user_id );
-               }
-
-               if ( 'description' == $field )
-                       $value = esc_html( $value ); // textarea_escaped?
-               else
-                       $value = esc_attr($value);
-       } elseif ( 'db' == $context ) {
-               if ( $prefixed ) {
-                       /** This filter is documented in wp-includes/post-functions.php */
-                       $value = apply_filters( "pre_{$field}", $value );
-               } else {
-
-                       /**
-                        * Filter the value of a user field in the 'db' context.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
-                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param mixed $value Value of the prefixed user field.
-                        */
-                       $value = apply_filters( "pre_user_{$field}", $value );
-               }
-       } else {
-               // Use display filters by default.
-               if ( $prefixed ) {
-
-                       /** This filter is documented in wp-includes/post-functions.php */
-                       $value = apply_filters( $field, $value, $user_id, $context );
-               } else {
-
-                       /**
-                        * Filter the value of a user field in a standard context.
-                        *
-                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
-                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
-                        *
-                        * @since 2.9.0
-                        *
-                        * @param mixed  $value   The user object value to sanitize.
-                        * @param int    $user_id User ID.
-                        * @param string $context The context to filter within.
-                        */
-                       $value = apply_filters( "user_{$field}", $value, $user_id, $context );
-               }
-       }
-
-       if ( 'user_url' == $field )
-               $value = esc_url($value);
-
-       if ( 'attribute' == $context ) {
-               $value = esc_attr( $value );
-       } elseif ( 'js' == $context ) {
-               $value = esc_js( $value );
-       }
-       return $value;
-}
-
-/**
- * Update all user caches
- *
- * @since 3.0.0
- *
- * @param object|WP_User $user User object to be cached
- * @return bool|null Returns false on failure.
- */
-function update_user_caches( $user ) {
-       if ( $user instanceof WP_User ) {
-               if ( ! $user->exists() ) {
-                       return false;
-               }
-
-               $user = $user->data;
-       }
-
-       wp_cache_add($user->ID, $user, 'users');
-       wp_cache_add($user->user_login, $user->ID, 'userlogins');
-       wp_cache_add($user->user_email, $user->ID, 'useremail');
-       wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
-}
-
-/**
- * Clean all user caches
- *
- * @since 3.0.0
- * @since 4.4.0 'clean_user_cache' action was added.
- *
- * @param WP_User|int $user User object or ID to be cleaned from the cache
- */
-function clean_user_cache( $user ) {
-       if ( is_numeric( $user ) )
-               $user = new WP_User( $user );
-
-       if ( ! $user->exists() )
-               return;
-
-       wp_cache_delete( $user->ID, 'users' );
-       wp_cache_delete( $user->user_login, 'userlogins' );
-       wp_cache_delete( $user->user_email, 'useremail' );
-       wp_cache_delete( $user->user_nicename, 'userslugs' );
-
-       /**
-        * Fires immediately after the given user's cache is cleaned.
-        *
-        * @since 4.4.0
-        *
-        * @param int     $user_id User ID.
-        * @param WP_User $user    User object.
-        */
-       do_action( 'clean_user_cache', $user->ID, $user );
-}
-
-/**
- * Checks whether the given username exists.
- *
- * @since 2.0.0
- *
- * @param string $username Username.
- * @return int|false The user's ID on success, and false on failure.
- */
-function username_exists( $username ) {
-       if ( $user = get_user_by( 'login', $username ) ) {
-               return $user->ID;
-       }
-       return false;
-}
-
-/**
- * Checks whether the given email exists.
- *
- * @since 2.1.0
- *
- * @param string $email Email.
- * @return int|false The user's ID on success, and false on failure.
- */
-function email_exists( $email ) {
-       if ( $user = get_user_by( 'email', $email) ) {
-               return $user->ID;
-       }
-       return false;
-}
-
-/**
- * Checks whether a username is valid.
- *
- * @since 2.0.1
- * @since 4.4.0 Empty sanitized usernames are now considered invalid
- *
- * @param string $username Username.
- * @return bool Whether username given is valid
- */
-function validate_username( $username ) {
-       $sanitized = sanitize_user( $username, true );
-       $valid = ( $sanitized == $username && ! empty( $sanitized ) );
-
-       /**
-        * Filter whether the provided username is valid or not.
-        *
-        * @since 2.0.1
-        *
-        * @param bool   $valid    Whether given username is valid.
-        * @param string $username Username to check.
-        */
-       return apply_filters( 'validate_username', $valid, $username );
-}
-
-/**
- * Insert a user into the database.
- *
- * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
- * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
- * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
- * name. An example using 'description' would have the filter called, 'pre_user_description' that
- * can be hooked into.
- *
- * @since 2.0.0
- * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact
- *              methods for new installs. See wp_get_user_contact_methods().
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param array|object|WP_User $userdata {
- *     An array, object, or WP_User object of user data arguments.
- *
- *     @type int         $ID                   User ID. If supplied, the user will be updated.
- *     @type string      $user_pass            The plain-text user password.
- *     @type string      $user_login           The user's login username.
- *     @type string      $user_nicename        The URL-friendly user name.
- *     @type string      $user_url             The user URL.
- *     @type string      $user_email           The user email address.
- *     @type string      $display_name         The user's display name.
- *                                             Default is the the user's username.
- *     @type string      $nickname             The user's nickname.
- *                                             Default is the the user's username.
- *     @type string      $first_name           The user's first name. For new users, will be used
- *                                             to build the first part of the user's display name
- *                                             if `$display_name` is not specified.
- *     @type string      $last_name            The user's last name. For new users, will be used
- *                                             to build the second part of the user's display name
- *                                             if `$display_name` is not specified.
- *     @type string      $description          The user's biographical description.
- *     @type string|bool $rich_editing         Whether to enable the rich-editor for the user.
- *                                             False if not empty.
- *     @type string|bool $comment_shortcuts    Whether to enable comment moderation keyboard
- *                                             shortcuts for the user. Default false.
- *     @type string      $admin_color          Admin color scheme for the user. Default 'fresh'.
- *     @type bool        $use_ssl              Whether the user should always access the admin over
- *                                             https. Default false.
- *     @type string      $user_registered      Date the user registered. Format is 'Y-m-d H:i:s'.
- *     @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the
- *                                             site's frontend. Default true.
- *     @type string      $role                 User's role.
- * }
- * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
- *                      be created.
- */
-function wp_insert_user( $userdata ) {
-       global $wpdb;
-
-       if ( $userdata instanceof stdClass ) {
-               $userdata = get_object_vars( $userdata );
-       } elseif ( $userdata instanceof WP_User ) {
-               $userdata = $userdata->to_array();
-       }
-
-       // Are we updating or creating?
-       if ( ! empty( $userdata['ID'] ) ) {
-               $ID = (int) $userdata['ID'];
-               $update = true;
-               $old_user_data = get_userdata( $ID );
-
-               if ( ! $old_user_data ) {
-                       return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
-               }
-
-               // hashed in wp_update_user(), plaintext if called directly
-               $user_pass = ! empty( $userdata['user_pass'] ) ? $userdata['user_pass'] : $old_user_data->user_pass;
-       } else {
-               $update = false;
-               // Hash the password
-               $user_pass = wp_hash_password( $userdata['user_pass'] );
-       }
-
-       $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
-
-       /**
-        * Filter a username after it has been sanitized.
-        *
-        * This filter is called before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $sanitized_user_login Username after it has been sanitized.
-        */
-       $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
-
-       //Remove any non-printable chars from the login string to see if we have ended up with an empty username
-       $user_login = trim( $pre_user_login );
-
-       // user_login must be between 0 and 60 characters.
-       if ( empty( $user_login ) ) {
-               return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
-       } elseif ( mb_strlen( $user_login ) > 60 ) {
-               return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) );
-       }
-
-       if ( ! $update && username_exists( $user_login ) ) {
-               return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
-       }
-
-       /**
-        * Filter the list of blacklisted usernames.
-        *
-        * @since 4.4.0
-        *
-        * @param array $usernames Array of blacklisted usernames.
-        */
-       $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
-
-       if ( in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
-               return new WP_Error( 'illegal_user_login', __( 'Sorry, that username is not allowed.' ) );
-       }
-
-       /*
-        * If a nicename is provided, remove unsafe user characters before using it.
-        * Otherwise build a nicename from the user_login.
-        */
-       if ( ! empty( $userdata['user_nicename'] ) ) {
-               $user_nicename = sanitize_user( $userdata['user_nicename'], true );
-               if ( mb_strlen( $user_nicename ) > 50 ) {
-                       return new WP_Error( 'user_nicename_too_long', __( 'Nicename may not be longer than 50 characters.' ) );
-               }
-       } else {
-               $user_nicename = mb_substr( $user_login, 0, 50 );
-       }
-
-       $user_nicename = sanitize_title( $user_nicename );
-
-       // Store values to save in user meta.
-       $meta = array();
-
-       /**
-        * Filter a user's nicename before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $user_nicename The user's nicename.
-        */
-       $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename );
-
-       $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
-
-       /**
-        * Filter a user's URL before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $raw_user_url The user's URL.
-        */
-       $user_url = apply_filters( 'pre_user_url', $raw_user_url );
-
-       $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
-
-       /**
-        * Filter a user's email before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $raw_user_email The user's email.
-        */
-       $user_email = apply_filters( 'pre_user_email', $raw_user_email );
-
-       /*
-        * If there is no update, just check for `email_exists`. If there is an update,
-        * check if current email and new email are the same, or not, and check `email_exists`
-        * accordingly.
-        */
-       if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
-               && ! defined( 'WP_IMPORTING' )
-               && email_exists( $user_email )
-       ) {
-               return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
-       }
-       $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
-
-       /**
-        * Filter a user's nickname before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $nickname The user's nickname.
-        */
-       $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname );
-
-       $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name'];
-
-       /**
-        * Filter a user's first name before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $first_name The user's first name.
-        */
-       $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name );
-
-       $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name'];
-
-       /**
-        * Filter a user's last name before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $last_name The user's last name.
-        */
-       $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name );
-
-       if ( empty( $userdata['display_name'] ) ) {
-               if ( $update ) {
-                       $display_name = $user_login;
-               } elseif ( $meta['first_name'] && $meta['last_name'] ) {
-                       /* translators: 1: first name, 2: last name */
-                       $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
-               } elseif ( $meta['first_name'] ) {
-                       $display_name = $meta['first_name'];
-               } elseif ( $meta['last_name'] ) {
-                       $display_name = $meta['last_name'];
-               } else {
-                       $display_name = $user_login;
-               }
-       } else {
-               $display_name = $userdata['display_name'];
-       }
-
-       /**
-        * Filter a user's display name before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $display_name The user's display name.
-        */
-       $display_name = apply_filters( 'pre_user_display_name', $display_name );
-
-       $description = empty( $userdata['description'] ) ? '' : $userdata['description'];
-
-       /**
-        * Filter a user's description before the user is created or updated.
-        *
-        * @since 2.0.3
-        *
-        * @param string $description The user's description.
-        */
-       $meta['description'] = apply_filters( 'pre_user_description', $description );
-
-       $meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing'];
-
-       $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
-
-       $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
-       $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
-
-       $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
-
-       $user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
-
-       $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
-
-       $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
-
-       if ( $user_nicename_check ) {
-               $suffix = 2;
-               while ($user_nicename_check) {
-                       // user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
-                       $base_length = 49 - mb_strlen( $suffix );
-                       $alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
-                       $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
-                       $suffix++;
-               }
-               $user_nicename = $alt_user_nicename;
-       }
-
-       $compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
-       $data = wp_unslash( $compacted );
-
-       if ( $update ) {
-               if ( $user_email !== $old_user_data->user_email ) {
-                       $data['user_activation_key'] = '';
-               }
-               $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
-               $user_id = (int) $ID;
-       } else {
-               $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
-               $user_id = (int) $wpdb->insert_id;
-       }
-
-       $user = new WP_User( $user_id );
-
-       /**
-        * Filter a user's meta values and keys before the user is created or updated.
-        *
-        * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
-        *
-        * @since 4.4.0
-        *
-        * @param array $meta {
-        *     Default meta values and keys for the user.
-        *
-        *     @type string   $nickname             The user's nickname. Default is the the user's username.
-        *     @type string   $first_name           The user's first name.
-        *     @type string   $last_name            The user's last name.
-        *     @type string   $description          The user's description.
-        *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
-        *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
-        *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
-        *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
-        *                                          not forced.
-        *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
-        *                                          Default true.
-        * }
-        * @param WP_User $user   User object.
-        * @param bool    $update Whether the user is being updated rather than created.
-        */
-       $meta = apply_filters( 'insert_user_meta', $meta, $user, $update );
-
-       // Update user meta.
-       foreach ( $meta as $key => $value ) {
-               update_user_meta( $user_id, $key, $value );
-       }
-
-       foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
-               if ( isset( $userdata[ $key ] ) ) {
-                       update_user_meta( $user_id, $key, $userdata[ $key ] );
-               }
-       }
-
-       if ( isset( $userdata['role'] ) ) {
-               $user->set_role( $userdata['role'] );
-       } elseif ( ! $update ) {
-               $user->set_role(get_option('default_role'));
-       }
-       wp_cache_delete( $user_id, 'users' );
-       wp_cache_delete( $user_login, 'userlogins' );
-
-       if ( $update ) {
-               /**
-                * Fires immediately after an existing user is updated.
-                *
-                * @since 2.0.0
-                *
-                * @param int    $user_id       User ID.
-                * @param object $old_user_data Object containing user's data prior to update.
-                */
-               do_action( 'profile_update', $user_id, $old_user_data );
-       } else {
-               /**
-                * Fires immediately after a new user is registered.
-                *
-                * @since 1.5.0
-                *
-                * @param int $user_id User ID.
-                */
-               do_action( 'user_register', $user_id );
-       }
-
-       return $user_id;
-}
-
-/**
- * Update a user in the database.
- *
- * It is possible to update a user's password by specifying the 'user_pass'
- * value in the $userdata parameter array.
- *
- * If current user's password is being updated, then the cookies will be
- * cleared.
- *
- * @since 2.0.0
- *
- * @see wp_insert_user() For what fields can be set in $userdata.
- *
- * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
- * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
- */
-function wp_update_user($userdata) {
-       if ( $userdata instanceof stdClass ) {
-               $userdata = get_object_vars( $userdata );
-       } elseif ( $userdata instanceof WP_User ) {
-               $userdata = $userdata->to_array();
-       }
-
-       $ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
-       if ( ! $ID ) {
-               return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
-       }
-
-       // First, get all of the original fields
-       $user_obj = get_userdata( $ID );
-       if ( ! $user_obj ) {
-               return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
-       }
-
-       $user = $user_obj->to_array();
-
-       // Add additional custom fields
-       foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
-               $user[ $key ] = get_user_meta( $ID, $key, true );
-       }
-
-       // Escape data pulled from DB.
-       $user = add_magic_quotes( $user );
-
-       if ( ! empty( $userdata['user_pass'] ) && $userdata['user_pass'] !== $user_obj->user_pass ) {
-               // If password is changing, hash it now
-               $plaintext_pass = $userdata['user_pass'];
-               $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
-
-               /**
-                * Filter whether to send the password change email.
-                *
-                * @since 4.3.0
-                *
-                * @see wp_insert_user() For `$user` and `$userdata` fields.
-                *
-                * @param bool  $send     Whether to send the email.
-                * @param array $user     The original user array.
-                * @param array $userdata The updated user array.
-                *
-                */
-               $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
-       }
-
-       if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
-               /**
-                * Filter whether to send the email change email.
-                *
-                * @since 4.3.0
-                *
-                * @see wp_insert_user() For `$user` and `$userdata` fields.
-                *
-                * @param bool  $send     Whether to send the email.
-                * @param array $user     The original user array.
-                * @param array $userdata The updated user array.
-                *
-                */
-               $send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
-       }
-
-       wp_cache_delete( $user['user_email'], 'useremail' );
-
-       // Merge old and new fields with new fields overwriting old ones.
-       $userdata = array_merge( $user, $userdata );
-       $user_id = wp_insert_user( $userdata );
-
-       if ( ! is_wp_error( $user_id ) ) {
-
-               $blog_name = wp_specialchars_decode( get_option( 'blogname' ) );
-
-               if ( ! empty( $send_password_change_email ) ) {
-
-                       /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
-                       $pass_change_text = __( 'Hi ###USERNAME###,
-
-This notice confirms that your password was changed on ###SITENAME###.
-
-If you did not change your password, please contact the Site Administrator at
-###ADMIN_EMAIL###
-
-This email has been sent to ###EMAIL###
-
-Regards,
-All at ###SITENAME###
-###SITEURL###' );
-
-                       $pass_change_email = array(
-                               'to'      => $user['user_email'],
-                               'subject' => __( '[%s] Notice of Password Change' ),
-                               'message' => $pass_change_text,
-                               'headers' => '',
-                       );
-
-                       /**
-                        * Filter the contents of the email sent when the user's password is changed.
-                        *
-                        * @since 4.3.0
-                        *
-                        * @param array $pass_change_email {
-                        *            Used to build wp_mail().
-                        *            @type string $to      The intended recipients. Add emails in a comma separated string.
-                        *            @type string $subject The subject of the email.
-                        *            @type string $message The content of the email.
-                        *                The following strings have a special meaning and will get replaced dynamically:
-                        *                - ###USERNAME###    The current user's username.
-                        *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
-                        *                - ###EMAIL###       The old email.
-                        *                - ###SITENAME###    The name of the site.
-                        *                - ###SITEURL###     The URL to the site.
-                        *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
-                        *        }
-                        * @param array $user     The original user array.
-                        * @param array $userdata The updated user array.
-                        *
-                        */
-                       $pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
-
-                       $pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
-                       $pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
-                       $pass_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $pass_change_email['message'] );
-                       $pass_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $pass_change_email['message'] );
-                       $pass_change_email['message'] = str_replace( '###SITEURL###', home_url(), $pass_change_email['message'] );
-
-                       wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
-               }
-
-               if ( ! empty( $send_email_change_email ) ) {
-                       /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
-                       $email_change_text = __( 'Hi ###USERNAME###,
-
-This notice confirms that your email was changed on ###SITENAME###.
-
-If you did not change your email, please contact the Site Administrator at
-###ADMIN_EMAIL###
-
-This email has been sent to ###EMAIL###
-
-Regards,
-All at ###SITENAME###
-###SITEURL###' );
-
-                       $email_change_email = array(
-                               'to'      => $user['user_email'],
-                               'subject' => __( '[%s] Notice of Email Change' ),
-                               'message' => $email_change_text,
-                               'headers' => '',
-                       );
-
-                       /**
-                        * Filter the contents of the email sent when the user's email is changed.
-                        *
-                        * @since 4.3.0
-                        *
-                        * @param array $email_change_email {
-                        *            Used to build wp_mail().
-                        *            @type string $to      The intended recipients.
-                        *            @type string $subject The subject of the email.
-                        *            @type string $message The content of the email.
-                        *                The following strings have a special meaning and will get replaced dynamically:
-                        *                - ###USERNAME###    The current user's username.
-                        *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
-                        *                - ###EMAIL###       The old email.
-                        *                - ###SITENAME###    The name of the site.
-                        *                - ###SITEURL###     The URL to the site.
-                        *            @type string $headers Headers.
-                        *        }
-                        * @param array $user The original user array.
-                        * @param array $userdata The updated user array.
-                        */
-                       $email_change_email = apply_filters( 'email_change_email', $email_change_email, $user, $userdata );
-
-                       $email_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $email_change_email['message'] );
-                       $email_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $email_change_email['message'] );
-                       $email_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $email_change_email['message'] );
-                       $email_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $email_change_email['message'] );
-                       $email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
-
-                       wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
-               }
-       }
-
-       // Update the cookies if the password changed.
-       $current_user = wp_get_current_user();
-       if ( $current_user->ID == $ID ) {
-               if ( isset($plaintext_pass) ) {
-                       wp_clear_auth_cookie();
-
-                       // Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
-                       // If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
-                       $logged_in_cookie    = wp_parse_auth_cookie( '', 'logged_in' );
-                       /** This filter is documented in wp-includes/pluggable.php */
-                       $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
-                       $remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
-
-                       wp_set_auth_cookie( $ID, $remember );
-               }
-       }
-
-       return $user_id;
-}
-
-/**
- * A simpler way of inserting a user into the database.
- *
- * Creates a new user with just the username, password, and email. For more
- * complex user creation use {@see wp_insert_user()} to specify more information.
- *
- * @since 2.0.0
- * @see wp_insert_user() More complete way to create a new user
- *
- * @param string $username The user's username.
- * @param string $password The user's password.
- * @param string $email    Optional. The user's email. Default empty.
- * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
- *                      be created.
- */
-function wp_create_user($username, $password, $email = '') {
-       $user_login = wp_slash( $username );
-       $user_email = wp_slash( $email    );
-       $user_pass = $password;
-
-       $userdata = compact('user_login', 'user_email', 'user_pass');
-       return wp_insert_user($userdata);
-}
-
-/**
- * Returns a list of meta keys to be (maybe) populated in wp_update_user().
- *
- * The list of keys returned via this function are dependent on the presence
- * of those keys in the user meta data to be set.
- *
- * @since 3.3.0
- * @access private
- *
- * @param WP_User $user WP_User instance.
- * @return array List of user keys to be populated in wp_update_user().
- */
-function _get_additional_user_keys( $user ) {
-       $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
-       return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
-}
-
-/**
- * Set up the user contact methods.
- *
- * Default contact methods were removed in 3.6. A filter dictates contact methods.
- *
- * @since 3.7.0
- *
- * @param WP_User $user Optional. WP_User object.
- * @return array Array of contact methods and their labels.
- */
-function wp_get_user_contact_methods( $user = null ) {
-       $methods = array();
-       if ( get_site_option( 'initial_db_version' ) < 23588 ) {
-               $methods = array(
-                       'aim'    => __( 'AIM' ),
-                       'yim'    => __( 'Yahoo IM' ),
-                       'jabber' => __( 'Jabber / Google Talk' )
-               );
-       }
-
-       /**
-        * Filter the user contact methods.
-        *
-        * @since 2.9.0
-        *
-        * @param array   $methods Array of contact methods and their labels.
-        * @param WP_User $user    WP_User object.
-        */
-       return apply_filters( 'user_contactmethods', $methods, $user );
-}
-
-/**
- * The old private function for setting up user contact methods.
- *
- * @since 2.9.0
- * @access private
- */
-function _wp_get_user_contactmethods( $user = null ) {
-       return wp_get_user_contact_methods( $user );
-}
-
-/**
- * Gets the text suggesting how to create strong passwords.
- *
- * @since 4.1.0
- *
- * @return string The password hint text.
- */
-function wp_get_password_hint() {
-       $hint = __( 'Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ &amp; ).' );
-
-       /**
-        * Filter the text describing the site's password complexity policy.
-        *
-        * @since 4.1.0
-        *
-        * @param string $hint The password hint text.
-        */
-       return apply_filters( 'password_hint', $hint );
-}
-
-/**
- * Creates, stores, then returns a password reset key for user.
- *
- * @since 4.4.0
- *
- * @global wpdb         $wpdb      WordPress database abstraction object.
- * @global PasswordHash $wp_hasher Portable PHP password hashing framework.
- *
- * @param WP_User $user User to retrieve password reset key for.
- *
- * @return string|WP_Error Password reset key on success. WP_Error on error.
- */
-function get_password_reset_key( $user ) {
-       global $wpdb, $wp_hasher;
-
-       /**
-        * Fires before a new password is retrieved.
-        *
-        * @since 1.5.0
-        * @deprecated 1.5.1 Misspelled. Use 'retrieve_password' hook instead.
-        *
-        * @param string $user_login The user login name.
-        */
-       do_action( 'retreive_password', $user->user_login );
-
-       /**
-        * Fires before a new password is retrieved.
-        *
-        * @since 1.5.1
-        *
-        * @param string $user_login The user login name.
-        */
-       do_action( 'retrieve_password', $user->user_login );
-
-       /**
-        * Filter whether to allow a password to be reset.
-        *
-        * @since 2.7.0
-        *
-        * @param bool true           Whether to allow the password to be reset. Default true.
-        * @param int  $user_data->ID The ID of the user attempting to reset a password.
-        */
-       $allow = apply_filters( 'allow_password_reset', true, $user->ID );
-
-       if ( ! $allow ) {
-               return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user' ) );
-       } elseif ( is_wp_error( $allow ) ) {
-               return $allow;
-       }
-
-       // Generate something random for a password reset key.
-       $key = wp_generate_password( 20, false );
-
-       /**
-        * Fires when a password reset key is generated.
-        *
-        * @since 2.5.0
-        *
-        * @param string $user_login The username for the user.
-        * @param string $key        The generated password reset key.
-        */
-       do_action( 'retrieve_password_key', $user->user_login, $key );
-
-       // Now insert the key, hashed, into the DB.
-       if ( empty( $wp_hasher ) ) {
-               require_once ABSPATH . WPINC . '/class-phpass.php';
-               $wp_hasher = new PasswordHash( 8, true );
-       }
-       $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
-       $key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
-       if ( false === $key_saved ) {
-               return WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) );
-       }
-
-       return $key;
-}
-
-/**
- * Retrieves a user row based on password reset key and login
- *
- * A key is considered 'expired' if it exactly matches the value of the
- * user_activation_key field, rather than being matched after going through the
- * hashing process. This field is now hashed; old values are no longer accepted
- * but have a different WP_Error code so good user feedback can be provided.
- *
- * @since 3.1.0
- *
- * @global wpdb         $wpdb      WordPress database object for queries.
- * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
- *
- * @param string $key       Hash to validate sending user's password.
- * @param string $login     The user login.
- * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
- */
-function check_password_reset_key($key, $login) {
-       global $wpdb, $wp_hasher;
-
-       $key = preg_replace('/[^a-z0-9]/i', '', $key);
-
-       if ( empty( $key ) || !is_string( $key ) )
-               return new WP_Error('invalid_key', __('Invalid key'));
-
-       if ( empty($login) || !is_string($login) )
-               return new WP_Error('invalid_key', __('Invalid key'));
-
-       $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
-       if ( ! $row )
-               return new WP_Error('invalid_key', __('Invalid key'));
-
-       if ( empty( $wp_hasher ) ) {
-               require_once ABSPATH . WPINC . '/class-phpass.php';
-               $wp_hasher = new PasswordHash( 8, true );
-       }
-
-       /**
-        * Filter the expiration time of password reset keys.
-        *
-        * @since 4.3.0
-        *
-        * @param int $expiration The expiration time in seconds.
-        */
-       $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
-
-       if ( false !== strpos( $row->user_activation_key, ':' ) ) {
-               list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
-               $expiration_time = $pass_request_time + $expiration_duration;
-       } else {
-               $pass_key = $row->user_activation_key;
-               $expiration_time = false;
-       }
-
-       $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
-
-       if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
-               return get_userdata( $row->ID );
-       } elseif ( $hash_is_correct && $expiration_time ) {
-               // Key has an expiration time that's passed
-               return new WP_Error( 'expired_key', __( 'Invalid key' ) );
-       }
-
-       if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
-               $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
-               $user_id = $row->ID;
-
-               /**
-                * Filter the return value of check_password_reset_key() when an
-                * old-style key is used.
-                *
-                * @since 3.7.0 Previously plain-text keys were stored in the database.
-                * @since 4.3.0 Previously key hashes were stored without an expiration time.
-                *
-                * @param WP_Error $return  A WP_Error object denoting an expired key.
-                *                          Return a WP_User object to validate the key.
-                * @param int      $user_id The matched user ID.
-                */
-               return apply_filters( 'password_reset_key_expired', $return, $user_id );
-       }
-
-       return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
-}
-
-/**
- * Handles resetting the user's password.
- *
- * @since 2.5.0
- *
- * @param object $user     The user
- * @param string $new_pass New password for the user in plaintext
- */
-function reset_password( $user, $new_pass ) {
-       /**
-        * Fires before the user's password is reset.
-        *
-        * @since 1.5.0
-        *
-        * @param object $user     The user.
-        * @param string $new_pass New user password.
-        */
-       do_action( 'password_reset', $user, $new_pass );
-
-       wp_set_password( $new_pass, $user->ID );
-       update_user_option( $user->ID, 'default_password_nag', false, true );
-
-       /**
-        * Fires after the user's password is reset.
-        *
-        * @since 4.4.0
-        *
-        * @param object $user     The user.
-        * @param string $new_pass New user password.
-        */
-       do_action( 'after_password_reset', $user, $new_pass );
-}
-
-/**
- * Handles registering a new user.
- *
- * @since 2.5.0
- *
- * @param string $user_login User's username for logging in
- * @param string $user_email User's email address to send password and add
- * @return int|WP_Error Either user's ID or error on failure.
- */
-function register_new_user( $user_login, $user_email ) {
-       $errors = new WP_Error();
-
-       $sanitized_user_login = sanitize_user( $user_login );
-       /**
-        * Filter the email address of a user being registered.
-        *
-        * @since 2.1.0
-        *
-        * @param string $user_email The email address of the new user.
-        */
-       $user_email = apply_filters( 'user_registration_email', $user_email );
-
-       // Check the username
-       if ( $sanitized_user_login == '' ) {
-               $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
-       } elseif ( ! validate_username( $user_login ) ) {
-               $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
-               $sanitized_user_login = '';
-       } elseif ( username_exists( $sanitized_user_login ) ) {
-               $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
-       }
-
-       // Check the email address
-       if ( $user_email == '' ) {
-               $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your email address.' ) );
-       } elseif ( ! is_email( $user_email ) ) {
-               $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
-               $user_email = '';
-       } elseif ( email_exists( $user_email ) ) {
-               $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
-       }
-
-       /**
-        * Fires when submitting registration form data, before the user is created.
-        *
-        * @since 2.1.0
-        *
-        * @param string   $sanitized_user_login The submitted username after being sanitized.
-        * @param string   $user_email           The submitted email.
-        * @param WP_Error $errors               Contains any errors with submitted username and email,
-        *                                       e.g., an empty field, an invalid username or email,
-        *                                       or an existing username or email.
-        */
-       do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
-
-       /**
-        * Filter the errors encountered when a new user is being registered.
-        *
-        * The filtered WP_Error object may, for example, contain errors for an invalid
-        * or existing username or email address. A WP_Error object should always returned,
-        * but may or may not contain errors.
-        *
-        * If any errors are present in $errors, this will abort the user's registration.
-        *
-        * @since 2.1.0
-        *
-        * @param WP_Error $errors               A WP_Error object containing any errors encountered
-        *                                       during registration.
-        * @param string   $sanitized_user_login User's username after it has been sanitized.
-        * @param string   $user_email           User's email.
-        */
-       $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
-
-       if ( $errors->get_error_code() )
-               return $errors;
-
-       $user_pass = wp_generate_password( 12, false );
-       $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
-       if ( ! $user_id || is_wp_error( $user_id ) ) {
-               $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
-               return $errors;
-       }
-
-       update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
-
-       /**
-        * Fires after a new user registration has been recorded.
-        *
-        * @since 4.4.0
-        *
-        * @param int $user_id ID of the newly registered user.
-        */
-       do_action( 'register_new_user', $user_id );
-
-       return $user_id;
-}
-
-/**
- * Initiate email notifications related to the creation of new users.
- *
- * Notifications are sent both to the site admin and to the newly created user.
- *
- * @since 4.4.0
- *
- * @param int $user_id ID of the newly created user.
- */
-function wp_send_new_user_notifications( $user_id ) {
-       wp_new_user_notification( $user_id, null, 'both' );
-}
-
-/**
- * Retrieve the current session token from the logged_in cookie.
- *
- * @since 4.0.0
- *
- * @return string Token.
- */
-function wp_get_session_token() {
-       $cookie = wp_parse_auth_cookie( '', 'logged_in' );
-       return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
-}
-
-/**
- * Retrieve a list of sessions for the current user.
- *
- * @since 4.0.0
- * @return array Array of sessions.
- */
-function wp_get_all_sessions() {
-       $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
-       return $manager->get_all();
-}
-
-/**
- * Remove the current session token from the database.
- *
- * @since 4.0.0
- */
-function wp_destroy_current_session() {
-       $token = wp_get_session_token();
-       if ( $token ) {
-               $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
-               $manager->destroy( $token );
-       }
-}
-
-/**
- * Remove all but the current session token for the current user for the database.
- *
- * @since 4.0.0
- */
-function wp_destroy_other_sessions() {
-       $token = wp_get_session_token();
-       if ( $token ) {
-               $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
-               $manager->destroy_others( $token );
-       }
-}
-
-/**
- * Remove all session tokens for the current user from the database.
- *
- * @since 4.0.0
- */
-function wp_destroy_all_sessions() {
-       $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
-       $manager->destroy_all();
-}
-
-/**
- * Get the user IDs of all users with no role on this site.
- *
- * This function returns an empty array when used on Multisite.
- *
- * @since 4.4.0
- *
- * @return array Array of user IDs.
- */
-function wp_get_users_with_no_role() {
-       global $wpdb;
-
-       if ( is_multisite() ) {
-               return array();
-       }
-
-       $prefix = $wpdb->get_blog_prefix();
-       $regex  = implode( '|', wp_roles()->get_names() );
-       $regex  = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
-       $users  = $wpdb->get_col( $wpdb->prepare( "
-               SELECT user_id
-               FROM $wpdb->usermeta
-               WHERE meta_key = '{$prefix}capabilities'
-               AND meta_value NOT REGEXP %s
-       ", $regex ) );
-
-       return $users;
-}
</del></span></pre></div>
<a id="trunksrcwpincludesuserphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/user.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/user.php    2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/user.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,14 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core User API
- *
- * @package WordPress
- * @subpackage Users
- * @since 2.1.0
- */
-
-/** Core users functionality */
-require_once( ABSPATH . WPINC . '/user-functions.php' );
-
-/** WP_User_Query class */
-require_once( ABSPATH . WPINC . '/class-wp-user-query.php' );
</del></span></pre></div>
<a id="trunksrcwpincludesuserphpfromrev35712trunksrcwpincludesuserfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/user.php (from rev 35712, trunk/src/wp-includes/user-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/user.php                            (rev 0)
+++ trunk/src/wp-includes/user.php      2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,2293 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core User API
+ *
+ * @package WordPress
+ * @subpackage Users
+ */
+
+/**
+ * Authenticate user with remember capability.
+ *
+ * The credentials is an array that has 'user_login', 'user_password', and
+ * 'remember' indices. If the credentials is not given, then the log in form
+ * will be assumed and used if set.
+ *
+ * The various authentication cookies will be set by this function and will be
+ * set for a longer period depending on if the 'remember' credential is set to
+ * true.
+ *
+ * @since 2.5.0
+ *
+ * @global string $auth_secure_cookie
+ *
+ * @param array       $credentials   Optional. User info in order to sign on.
+ * @param string|bool $secure_cookie Optional. Whether to use secure cookie.
+ * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
+ */
+function wp_signon( $credentials = array(), $secure_cookie = '' ) {
+       if ( empty($credentials) ) {
+               if ( ! empty($_POST['log']) )
+                       $credentials['user_login'] = $_POST['log'];
+               if ( ! empty($_POST['pwd']) )
+                       $credentials['user_password'] = $_POST['pwd'];
+               if ( ! empty($_POST['rememberme']) )
+                       $credentials['remember'] = $_POST['rememberme'];
+       }
+
+       if ( !empty($credentials['remember']) )
+               $credentials['remember'] = true;
+       else
+               $credentials['remember'] = false;
+
+       /**
+        * Fires before the user is authenticated.
+        *
+        * The variables passed to the callbacks are passed by reference,
+        * and can be modified by callback functions.
+        *
+        * @since 1.5.1
+        *
+        * @todo Decide whether to deprecate the wp_authenticate action.
+        *
+        * @param string $user_login    Username, passed by reference.
+        * @param string $user_password User password, passed by reference.
+        */
+       do_action_ref_array( 'wp_authenticate', array( &$credentials['user_login'], &$credentials['user_password'] ) );
+
+       if ( '' === $secure_cookie )
+               $secure_cookie = is_ssl();
+
+       /**
+        * Filter whether to use a secure sign-on cookie.
+        *
+        * @since 3.1.0
+        *
+        * @param bool  $secure_cookie Whether to use a secure sign-on cookie.
+        * @param array $credentials {
+        *     Array of entered sign-on data.
+        *
+        *     @type string $user_login    Username.
+        *     @type string $user_password Password entered.
+        *     @type bool   $remember      Whether to 'remember' the user. Increases the time
+        *                                 that the cookie will be kept. Default false.
+        * }
+        */
+       $secure_cookie = apply_filters( 'secure_signon_cookie', $secure_cookie, $credentials );
+
+       global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
+       $auth_secure_cookie = $secure_cookie;
+
+       add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
+
+       $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
+
+       if ( is_wp_error($user) ) {
+               if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
+                       $user = new WP_Error('', '');
+               }
+
+               return $user;
+       }
+
+       wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
+       /**
+        * Fires after the user has successfully logged in.
+        *
+        * @since 1.5.0
+        *
+        * @param string  $user_login Username.
+        * @param WP_User $user       WP_User object of the logged-in user.
+        */
+       do_action( 'wp_login', $user->user_login, $user );
+       return $user;
+}
+
+/**
+ * Authenticate the user using the username and password.
+ *
+ * @since 2.8.0
+ *
+ * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
+ * @param string                $username Username for authentication.
+ * @param string                $password Password for authentication.
+ * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
+ */
+function wp_authenticate_username_password($user, $username, $password) {
+       if ( $user instanceof WP_User ) {
+               return $user;
+       }
+
+       if ( empty($username) || empty($password) ) {
+               if ( is_wp_error( $user ) )
+                       return $user;
+
+               $error = new WP_Error();
+
+               if ( empty($username) )
+                       $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
+
+               if ( empty($password) )
+                       $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
+
+               return $error;
+       }
+
+       $user = get_user_by('login', $username);
+
+       if ( !$user ) {
+               return new WP_Error( 'invalid_username',
+                       __( '<strong>ERROR</strong>: Invalid username.' ) .
+                       ' <a href="' . wp_lostpassword_url() . '">' .
+                       __( 'Lost your password?' ) .
+                       '</a>'
+               );
+       }
+
+       /**
+        * Filter whether the given user can be authenticated with the provided $password.
+        *
+        * @since 2.5.0
+        *
+        * @param WP_User|WP_Error $user     WP_User or WP_Error object if a previous
+        *                                   callback failed authentication.
+        * @param string           $password Password to check against the user.
+        */
+       $user = apply_filters( 'wp_authenticate_user', $user, $password );
+       if ( is_wp_error($user) )
+               return $user;
+
+       if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
+               return new WP_Error( 'incorrect_password',
+                       sprintf(
+                               /* translators: %s: user name */
+                               __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
+                               '<strong>' . $username . '</strong>'
+                       ) .
+                       ' <a href="' . wp_lostpassword_url() . '">' .
+                       __( 'Lost your password?' ) .
+                       '</a>'
+               );
+       }
+
+       return $user;
+}
+
+/**
+ * Authenticate the user using the WordPress auth cookie.
+ *
+ * @since 2.8.0
+ *
+ * @global string $auth_secure_cookie
+ *
+ * @param WP_User|WP_Error|null $user     WP_User or WP_Error object from a previous callback. Default null.
+ * @param string                $username Username. If not empty, cancels the cookie authentication.
+ * @param string                $password Password. If not empty, cancels the cookie authentication.
+ * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
+ */
+function wp_authenticate_cookie($user, $username, $password) {
+       if ( $user instanceof WP_User ) {
+               return $user;
+       }
+
+       if ( empty($username) && empty($password) ) {
+               $user_id = wp_validate_auth_cookie();
+               if ( $user_id )
+                       return new WP_User($user_id);
+
+               global $auth_secure_cookie;
+
+               if ( $auth_secure_cookie )
+                       $auth_cookie = SECURE_AUTH_COOKIE;
+               else
+                       $auth_cookie = AUTH_COOKIE;
+
+               if ( !empty($_COOKIE[$auth_cookie]) )
+                       return new WP_Error('expired_session', __('Please log in again.'));
+
+               // If the cookie is not set, be silent.
+       }
+
+       return $user;
+}
+
+/**
+ * For Multisite blogs, check if the authenticated user has been marked as a
+ * spammer, or if the user's primary blog has been marked as spam.
+ *
+ * @since 3.7.0
+ *
+ * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null.
+ * @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer.
+ */
+function wp_authenticate_spam_check( $user ) {
+       if ( $user instanceof WP_User && is_multisite() ) {
+               /**
+                * Filter whether the user has been marked as a spammer.
+                *
+                * @since 3.7.0
+                *
+                * @param bool    $spammed Whether the user is considered a spammer.
+                * @param WP_User $user    User to check against.
+                */
+               $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
+
+               if ( $spammed )
+                       return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
+       }
+       return $user;
+}
+
+/**
+ * Validate the logged-in cookie.
+ *
+ * Checks the logged-in cookie if the previous auth cookie could not be
+ * validated and parsed.
+ *
+ * This is a callback for the determine_current_user filter, rather than API.
+ *
+ * @since 3.9.0
+ *
+ * @param int|bool $user_id The user ID (or false) as received from the
+ *                       determine_current_user filter.
+ * @return int|false User ID if validated, false otherwise. If a user ID from
+ *                   an earlier filter callback is received, that value is returned.
+ */
+function wp_validate_logged_in_cookie( $user_id ) {
+       if ( $user_id ) {
+               return $user_id;
+       }
+
+       if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) {
+               return false;
+       }
+
+       return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' );
+}
+
+/**
+ * Number of posts user has written.
+ *
+ * @since 3.0.0
+ * @since 4.1.0 Added `$post_type` argument.
+ * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array
+ *              of post types to `$post_type`.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int          $userid      User ID.
+ * @param array|string $post_type   Optional. Single post type or array of post types to count the number of posts for. Default 'post'.
+ * @param bool         $public_only Optional. Whether to only return counts for public posts. Default false.
+ * @return int Number of posts the user has written in this post type.
+ */
+function count_user_posts( $userid, $post_type = 'post', $public_only = false ) {
+       global $wpdb;
+
+       $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
+
+       $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
+
+       /**
+        * Filter the number of posts a user has written.
+        *
+        * @since 2.7.0
+        * @since 4.1.0 Added `$post_type` argument.
+        * @since 4.3.1 Added `$public_only` argument.
+        *
+        * @param int          $count       The user's post count.
+        * @param int          $userid      User ID.
+        * @param string|array $post_type   Single post type or array of post types to count the number of posts for.
+        * @param bool         $public_only Whether to limit counted posts to public posts.
+        */
+       return apply_filters( 'get_usernumposts', $count, $userid, $post_type, $public_only );
+}
+
+/**
+ * Number of posts written by a list of users.
+ *
+ * @since 3.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array        $users       Array of user IDs.
+ * @param string|array $post_type   Optional. Single post type or array of post types to check. Defaults to 'post'.
+ * @param bool         $public_only Optional. Only return counts for public posts.  Defaults to false.
+ * @return array Amount of posts each user has written.
+ */
+function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
+       global $wpdb;
+
+       $count = array();
+       if ( empty( $users ) || ! is_array( $users ) )
+               return $count;
+
+       $userlist = implode( ',', array_map( 'absint', $users ) );
+       $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
+
+       $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
+       foreach ( $result as $row ) {
+               $count[ $row[0] ] = $row[1];
+       }
+
+       foreach ( $users as $id ) {
+               if ( ! isset( $count[ $id ] ) )
+                       $count[ $id ] = 0;
+       }
+
+       return $count;
+}
+
+//
+// User option functions
+//
+
+/**
+ * Get the current user's ID
+ *
+ * @since MU
+ *
+ * @return int The current user's ID
+ */
+function get_current_user_id() {
+       if ( ! function_exists( 'wp_get_current_user' ) )
+               return 0;
+       $user = wp_get_current_user();
+       return ( isset( $user->ID ) ? (int) $user->ID : 0 );
+}
+
+/**
+ * Retrieve user option that can be either per Site or per Network.
+ *
+ * If the user ID is not given, then the current user will be used instead. If
+ * the user ID is given, then the user data will be retrieved. The filter for
+ * the result, will also pass the original option name and finally the user data
+ * object as the third parameter.
+ *
+ * The option will first check for the per site name and then the per Network name.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $option     User option name.
+ * @param int    $user       Optional. User ID.
+ * @param string $deprecated Use get_option() to check for an option in the options table.
+ * @return mixed User option value on success, false on failure.
+ */
+function get_user_option( $option, $user = 0, $deprecated = '' ) {
+       global $wpdb;
+
+       if ( !empty( $deprecated ) )
+               _deprecated_argument( __FUNCTION__, '3.0' );
+
+       if ( empty( $user ) )
+               $user = get_current_user_id();
+
+       if ( ! $user = get_userdata( $user ) )
+               return false;
+
+       $prefix = $wpdb->get_blog_prefix();
+       if ( $user->has_prop( $prefix . $option ) ) // Blog specific
+               $result = $user->get( $prefix . $option );
+       elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
+               $result = $user->get( $option );
+       else
+               $result = false;
+
+       /**
+        * Filter a specific user option value.
+        *
+        * The dynamic portion of the hook name, `$option`, refers to the user option name.
+        *
+        * @since 2.5.0
+        *
+        * @param mixed   $result Value for the user's option.
+        * @param string  $option Name of the option being retrieved.
+        * @param WP_User $user   WP_User object of the user whose option is being retrieved.
+        */
+       return apply_filters( "get_user_option_{$option}", $result, $option, $user );
+}
+
+/**
+ * Update user option with global blog capability.
+ *
+ * User options are just like user metadata except that they have support for
+ * global blog options. If the 'global' parameter is false, which it is by default
+ * it will prepend the WordPress table prefix to the option name.
+ *
+ * Deletes the user option if $newvalue is empty.
+ *
+ * @since 2.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int    $user_id     User ID.
+ * @param string $option_name User option name.
+ * @param mixed  $newvalue    User option value.
+ * @param bool   $global      Optional. Whether option name is global or blog specific.
+ *                            Default false (blog specific).
+ * @return int|bool User meta ID if the option didn't exist, true on successful update,
+ *                  false on failure.
+ */
+function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
+       global $wpdb;
+
+       if ( !$global )
+               $option_name = $wpdb->get_blog_prefix() . $option_name;
+
+       return update_user_meta( $user_id, $option_name, $newvalue );
+}
+
+/**
+ * Delete user option with global blog capability.
+ *
+ * User options are just like user metadata except that they have support for
+ * global blog options. If the 'global' parameter is false, which it is by default
+ * it will prepend the WordPress table prefix to the option name.
+ *
+ * @since 3.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int    $user_id     User ID
+ * @param string $option_name User option name.
+ * @param bool   $global      Optional. Whether option name is global or blog specific.
+ *                            Default false (blog specific).
+ * @return bool True on success, false on failure.
+ */
+function delete_user_option( $user_id, $option_name, $global = false ) {
+       global $wpdb;
+
+       if ( !$global )
+               $option_name = $wpdb->get_blog_prefix() . $option_name;
+       return delete_user_meta( $user_id, $option_name );
+}
+
+/**
+ * Retrieve list of users matching criteria.
+ *
+ * @since 3.1.0
+ *
+ * @see WP_User_Query
+ *
+ * @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()}
+ *                    for more information on accepted arguments.
+ * @return array List of users.
+ */
+function get_users( $args = array() ) {
+
+       $args = wp_parse_args( $args );
+       $args['count_total'] = false;
+
+       $user_search = new WP_User_Query($args);
+
+       return (array) $user_search->get_results();
+}
+
+/**
+ * Get the blogs a user belongs to.
+ *
+ * @since 3.0.0
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param int  $user_id User ID
+ * @param bool $all     Whether to retrieve all blogs, or only blogs that are not
+ *                      marked as deleted, archived, or spam.
+ * @return array A list of the user's blogs. An empty array if the user doesn't exist
+ *               or belongs to no blogs.
+ */
+function get_blogs_of_user( $user_id, $all = false ) {
+       global $wpdb;
+
+       $user_id = (int) $user_id;
+
+       // Logged out users can't have blogs
+       if ( empty( $user_id ) )
+               return array();
+
+       $keys = get_user_meta( $user_id );
+       if ( empty( $keys ) )
+               return array();
+
+       if ( ! is_multisite() ) {
+               $blog_id = get_current_blog_id();
+               $blogs = array( $blog_id => new stdClass );
+               $blogs[ $blog_id ]->userblog_id = $blog_id;
+               $blogs[ $blog_id ]->blogname = get_option('blogname');
+               $blogs[ $blog_id ]->domain = '';
+               $blogs[ $blog_id ]->path = '';
+               $blogs[ $blog_id ]->site_id = 1;
+               $blogs[ $blog_id ]->siteurl = get_option('siteurl');
+               $blogs[ $blog_id ]->archived = 0;
+               $blogs[ $blog_id ]->spam = 0;
+               $blogs[ $blog_id ]->deleted = 0;
+               return $blogs;
+       }
+
+       $blogs = array();
+
+       if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
+               $blog = get_blog_details( 1 );
+               if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
+                       $blogs[ 1 ] = (object) array(
+                               'userblog_id' => 1,
+                               'blogname'    => $blog->blogname,
+                               'domain'      => $blog->domain,
+                               'path'        => $blog->path,
+                               'site_id'     => $blog->site_id,
+                               'siteurl'     => $blog->siteurl,
+                               'archived'    => $blog->archived,
+                               'mature'      => $blog->mature,
+                               'spam'        => $blog->spam,
+                               'deleted'     => $blog->deleted,
+                       );
+               }
+               unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
+       }
+
+       $keys = array_keys( $keys );
+
+       foreach ( $keys as $key ) {
+               if ( 'capabilities' !== substr( $key, -12 ) )
+                       continue;
+               if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
+                       continue;
+               $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
+               if ( ! is_numeric( $blog_id ) )
+                       continue;
+
+               $blog_id = (int) $blog_id;
+               $blog = get_blog_details( $blog_id );
+               if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
+                       $blogs[ $blog_id ] = (object) array(
+                               'userblog_id' => $blog_id,
+                               'blogname'    => $blog->blogname,
+                               'domain'      => $blog->domain,
+                               'path'        => $blog->path,
+                               'site_id'     => $blog->site_id,
+                               'siteurl'     => $blog->siteurl,
+                               'archived'    => $blog->archived,
+                               'mature'      => $blog->mature,
+                               'spam'        => $blog->spam,
+                               'deleted'     => $blog->deleted,
+                       );
+               }
+       }
+
+       /**
+        * Filter the list of blogs a user belongs to.
+        *
+        * @since MU
+        *
+        * @param array $blogs   An array of blog objects belonging to the user.
+        * @param int   $user_id User ID.
+        * @param bool  $all     Whether the returned blogs array should contain all blogs, including
+        *                       those marked 'deleted', 'archived', or 'spam'. Default false.
+        */
+       return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
+}
+
+/**
+ * Find out whether a user is a member of a given blog.
+ *
+ * @since MU 1.1
+ *
+ * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
+ * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
+ * @return bool
+ */
+function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
+       global $wpdb;
+
+       $user_id = (int) $user_id;
+       $blog_id = (int) $blog_id;
+
+       if ( empty( $user_id ) ) {
+               $user_id = get_current_user_id();
+       }
+
+       // Technically not needed, but does save calls to get_blog_details and get_user_meta
+       // in the event that the function is called when a user isn't logged in
+       if ( empty( $user_id ) ) {
+               return false;
+       } else {
+               $user = get_userdata( $user_id );
+               if ( ! $user instanceof WP_User ) {
+                       return false;
+               }
+       }
+
+       if ( ! is_multisite() ) {
+               return true;
+       }
+
+       if ( empty( $blog_id ) ) {
+               $blog_id = get_current_blog_id();
+       }
+
+       $blog = get_blog_details( $blog_id );
+
+       if ( ! $blog || ! isset( $blog->domain ) || $blog->archived || $blog->spam || $blog->deleted ) {
+               return false;
+       }
+
+       $keys = get_user_meta( $user_id );
+       if ( empty( $keys ) ) {
+               return false;
+       }
+
+       // no underscore before capabilities in $base_capabilities_key
+       $base_capabilities_key = $wpdb->base_prefix . 'capabilities';
+       $site_capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities';
+
+       if ( isset( $keys[ $base_capabilities_key ] ) && $blog_id == 1 ) {
+               return true;
+       }
+
+       if ( isset( $keys[ $site_capabilities_key ] ) ) {
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Add meta data field to a user.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Screens.
+ *
+ * @since 3.0.0
+ * @link https://codex.wordpress.org/Function_Reference/add_user_meta
+ *
+ * @param int    $user_id    User ID.
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Metadata value.
+ * @param bool   $unique     Optional, default is false. Whether the same key should not be added.
+ * @return int|false Meta ID on success, false on failure.
+ */
+function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
+       return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a user.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 3.0.0
+ * @link https://codex.wordpress.org/Function_Reference/delete_user_meta
+ *
+ * @param int    $user_id    User ID
+ * @param string $meta_key   Metadata name.
+ * @param mixed  $meta_value Optional. Metadata value.
+ * @return bool True on success, false on failure.
+ */
+function delete_user_meta($user_id, $meta_key, $meta_value = '') {
+       return delete_metadata('user', $user_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve user meta field for a user.
+ *
+ * @since 3.0.0
+ * @link https://codex.wordpress.org/Function_Reference/get_user_meta
+ *
+ * @param int    $user_id User ID.
+ * @param string $key     Optional. The meta key to retrieve. By default, returns data for all keys.
+ * @param bool   $single  Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
+ */
+function get_user_meta($user_id, $key = '', $single = false) {
+       return get_metadata('user', $user_id, $key, $single);
+}
+
+/**
+ * Update user meta field based on user ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and user ID.
+ *
+ * If the meta field for the user does not exist, it will be added.
+ *
+ * @since 3.0.0
+ * @link https://codex.wordpress.org/Function_Reference/update_user_meta
+ *
+ * @param int    $user_id    User ID.
+ * @param string $meta_key   Metadata key.
+ * @param mixed  $meta_value Metadata value.
+ * @param mixed  $prev_value Optional. Previous value to check before removing.
+ * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
+ */
+function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
+       return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Count number of users who have each of the user roles.
+ *
+ * Assumes there are neither duplicated nor orphaned capabilities meta_values.
+ * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
+ * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
+ * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
+ *
+ * @since 3.0.0
+ * @since 4.4.0 The number of users with no role is now included in the `none` element.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $strategy 'time' or 'memory'
+ * @return array Includes a grand total and an array of counts indexed by role strings.
+ */
+function count_users($strategy = 'time') {
+       global $wpdb;
+
+       // Initialize
+       $id = get_current_blog_id();
+       $blog_prefix = $wpdb->get_blog_prefix($id);
+       $result = array();
+
+       if ( 'time' == $strategy ) {
+               $avail_roles = wp_roles()->get_names();
+
+               // Build a CPU-intensive query that will return concise information.
+               $select_count = array();
+               foreach ( $avail_roles as $this_role => $name ) {
+                       $select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%');
+               }
+               $select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))";
+               $select_count = implode(', ', $select_count);
+
+               // Add the meta_value index to the selection list, then run the query.
+               $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
+
+               // Run the previous loop again to associate results with role names.
+               $col = 0;
+               $role_counts = array();
+               foreach ( $avail_roles as $this_role => $name ) {
+                       $count = (int) $row[$col++];
+                       if ($count > 0) {
+                               $role_counts[$this_role] = $count;
+                       }
+               }
+
+               $role_counts['none'] = (int) $row[$col++];
+
+               // Get the meta_value index from the end of the result set.
+               $total_users = (int) $row[$col];
+
+               $result['total_users'] = $total_users;
+               $result['avail_roles'] =& $role_counts;
+       } else {
+               $avail_roles = array(
+                       'none' => 0,
+               );
+
+               $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
+
+               foreach ( $users_of_blog as $caps_meta ) {
+                       $b_roles = maybe_unserialize($caps_meta);
+                       if ( ! is_array( $b_roles ) )
+                               continue;
+                       if ( empty( $b_roles ) ) {
+                               $avail_roles['none']++;
+                       }
+                       foreach ( $b_roles as $b_role => $val ) {
+                               if ( isset($avail_roles[$b_role]) ) {
+                                       $avail_roles[$b_role]++;
+                               } else {
+                                       $avail_roles[$b_role] = 1;
+                               }
+                       }
+               }
+
+               $result['total_users'] = count( $users_of_blog );
+               $result['avail_roles'] =& $avail_roles;
+       }
+
+       if ( is_multisite() ) {
+               $result['avail_roles']['none'] = 0;
+       }
+
+       return $result;
+}
+
+//
+// Private helper functions
+//
+
+/**
+ * Set up global user vars.
+ *
+ * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
+ *
+ * @since 2.0.4
+ *
+ * @global string $user_login    The user username for logging in
+ * @global object $userdata      User data.
+ * @global int    $user_level    The level of the user
+ * @global int    $user_ID       The ID of the user
+ * @global string $user_email    The email address of the user
+ * @global string $user_url      The url in the user's profile
+ * @global string $user_identity The display name of the user
+ *
+ * @param int $for_user_id Optional. User ID to set up global data.
+ */
+function setup_userdata($for_user_id = '') {
+       global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
+
+       if ( '' == $for_user_id )
+               $for_user_id = get_current_user_id();
+       $user = get_userdata( $for_user_id );
+
+       if ( ! $user ) {
+               $user_ID = 0;
+               $user_level = 0;
+               $userdata = null;
+               $user_login = $user_email = $user_url = $user_identity = '';
+               return;
+       }
+
+       $user_ID    = (int) $user->ID;
+       $user_level = (int) $user->user_level;
+       $userdata   = $user;
+       $user_login = $user->user_login;
+       $user_email = $user->user_email;
+       $user_url   = $user->user_url;
+       $user_identity = $user->display_name;
+}
+
+/**
+ * Create dropdown HTML content of users.
+ *
+ * The content can either be displayed, which it is by default or retrieved by
+ * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
+ * need to be used; all users will be displayed in that case. Only one can be
+ * used, either 'include' or 'exclude', but not both.
+ *
+ * The available arguments are as follows:
+ *
+ * @since 2.3.0
+ *
+ * @global int  $blog_id
+ *
+ * @param array|string $args {
+ *     Optional. Array or string of arguments to generate a drop-down of users.
+ *     {@see WP_User_Query::prepare_query() for additional available arguments.
+ *
+ *     @type string       $show_option_all         Text to show as the drop-down default (all).
+ *                                                 Default empty.
+ *     @type string       $show_option_none        Text to show as the drop-down default when no
+ *                                                 users were found. Default empty.
+ *     @type int|string   $option_none_value       Value to use for $show_option_non when no users
+ *                                                 were found. Default -1.
+ *     @type string       $hide_if_only_one_author Whether to skip generating the drop-down
+ *                                                 if only one user was found. Default empty.
+ *     @type string       $orderby                 Field to order found users by. Accepts user fields.
+ *                                                 Default 'display_name'.
+ *     @type string       $order                   Whether to order users in ascending or descending
+ *                                                 order. Accepts 'ASC' (ascending) or 'DESC' (descending).
+ *                                                 Default 'ASC'.
+ *     @type array|string $include                 Array or comma-separated list of user IDs to include.
+ *                                                 Default empty.
+ *     @type array|string $exclude                 Array or comma-separated list of user IDs to exclude.
+ *                                                 Default empty.
+ *     @type bool|int     $multi                   Whether to skip the ID attribute on the 'select' element.
+ *                                                 Accepts 1|true or 0|false. Default 0|false.
+ *     @type string       $show                    User table column to display. If the selected item is empty
+ *                                                 then the 'user_login' will be displayed in parentheses.
+ *                                                 Accepts user fields. Default 'display_name'.
+ *     @type int|bool     $echo                    Whether to echo or return the drop-down. Accepts 1|true (echo)
+ *                                                 or 0|false (return). Default 1|true.
+ *     @type int          $selected                Which user ID should be selected. Default 0.
+ *     @type bool         $include_selected        Whether to always include the selected user ID in the drop-
+ *                                                 down. Default false.
+ *     @type string       $name                    Name attribute of select element. Default 'user'.
+ *     @type string       $id                      ID attribute of the select element. Default is the value of $name.
+ *     @type string       $class                   Class attribute of the select element. Default empty.
+ *     @type int          $blog_id                 ID of blog (Multisite only). Default is ID of the current blog.
+ *     @type string       $who                     Which type of users to query. Accepts only an empty string or
+ *                                                 'authors'. Default empty.
+ * }
+ * @return string String of HTML content.
+ */
+function wp_dropdown_users( $args = '' ) {
+       $defaults = array(
+               'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
+               'orderby' => 'display_name', 'order' => 'ASC',
+               'include' => '', 'exclude' => '', 'multi' => 0,
+               'show' => 'display_name', 'echo' => 1,
+               'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
+               'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false,
+               'option_none_value' => -1
+       );
+
+       $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
+
+       $r = wp_parse_args( $args, $defaults );
+       $show = $r['show'];
+       $show_option_all = $r['show_option_all'];
+       $show_option_none = $r['show_option_none'];
+       $option_none_value = $r['option_none_value'];
+
+       $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
+       $query_args['fields'] = array( 'ID', 'user_login', $show );
+
+       /**
+        * Filter the query arguments for the user drop-down.
+        *
+        * @since 4.4.0
+        *
+        * @param array $query_args The query arguments for wp_dropdown_users().
+        * @param array $r          The default arguments for wp_dropdown_users().
+        */
+       $query_args = apply_filters( 'wp_dropdown_users_args', $query_args, $r );
+
+       $users = get_users( $query_args );
+
+       $output = '';
+       if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) {
+               $name = esc_attr( $r['name'] );
+               if ( $r['multi'] && ! $r['id'] ) {
+                       $id = '';
+               } else {
+                       $id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'";
+               }
+               $output = "<select name='{$name}'{$id} class='" . $r['class'] . "'>\n";
+
+               if ( $show_option_all ) {
+                       $output .= "\t<option value='0'>$show_option_all</option>\n";
+               }
+
+               if ( $show_option_none ) {
+                       $_selected = selected( $option_none_value, $r['selected'], false );
+                       $output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$_selected>$show_option_none</option>\n";
+               }
+
+               $found_selected = false;
+               foreach ( (array) $users as $user ) {
+                       $user->ID = (int) $user->ID;
+                       $_selected = selected( $user->ID, $r['selected'], false );
+                       if ( $_selected ) {
+                               $found_selected = true;
+                       }
+                       $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
+                       $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
+               }
+
+               if ( $r['include_selected'] && ! $found_selected && ( $r['selected'] > 0 ) ) {
+                       $user = get_userdata( $r['selected'] );
+                       $_selected = selected( $user->ID, $r['selected'], false );
+                       $display = ! empty( $user->$show ) ? $user->$show : '('. $user->user_login . ')';
+                       $output .= "\t<option value='$user->ID'$_selected>" . esc_html( $display ) . "</option>\n";
+               }
+
+               $output .= "</select>";
+       }
+
+       /**
+        * Filter the wp_dropdown_users() HTML output.
+        *
+        * @since 2.3.0
+        *
+        * @param string $output HTML output generated by wp_dropdown_users().
+        */
+       $html = apply_filters( 'wp_dropdown_users', $output );
+
+       if ( $r['echo'] ) {
+               echo $html;
+       }
+       return $html;
+}
+
+/**
+ * Sanitize user field based on context.
+ *
+ * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
+ * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
+ * when calling filters.
+ *
+ * @since 2.3.0
+ *
+ * @param string $field   The user Object field name.
+ * @param mixed  $value   The user Object value.
+ * @param int    $user_id User ID.
+ * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
+ *                        'attribute' and 'js'.
+ * @return mixed Sanitized value.
+ */
+function sanitize_user_field($field, $value, $user_id, $context) {
+       $int_fields = array('ID');
+       if ( in_array($field, $int_fields) )
+               $value = (int) $value;
+
+       if ( 'raw' == $context )
+               return $value;
+
+       if ( !is_string($value) && !is_numeric($value) )
+               return $value;
+
+       $prefixed = false !== strpos( $field, 'user_' );
+
+       if ( 'edit' == $context ) {
+               if ( $prefixed ) {
+
+                       /** This filter is documented in wp-includes/post-functions.php */
+                       $value = apply_filters( "edit_{$field}", $value, $user_id );
+               } else {
+
+                       /**
+                        * Filter a user field value in the 'edit' context.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
+                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param mixed $value   Value of the prefixed user field.
+                        * @param int   $user_id User ID.
+                        */
+                       $value = apply_filters( "edit_user_{$field}", $value, $user_id );
+               }
+
+               if ( 'description' == $field )
+                       $value = esc_html( $value ); // textarea_escaped?
+               else
+                       $value = esc_attr($value);
+       } elseif ( 'db' == $context ) {
+               if ( $prefixed ) {
+                       /** This filter is documented in wp-includes/post-functions.php */
+                       $value = apply_filters( "pre_{$field}", $value );
+               } else {
+
+                       /**
+                        * Filter the value of a user field in the 'db' context.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
+                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param mixed $value Value of the prefixed user field.
+                        */
+                       $value = apply_filters( "pre_user_{$field}", $value );
+               }
+       } else {
+               // Use display filters by default.
+               if ( $prefixed ) {
+
+                       /** This filter is documented in wp-includes/post-functions.php */
+                       $value = apply_filters( $field, $value, $user_id, $context );
+               } else {
+
+                       /**
+                        * Filter the value of a user field in a standard context.
+                        *
+                        * The dynamic portion of the hook name, `$field`, refers to the prefixed user
+                        * field being filtered, such as 'user_login', 'user_email', 'first_name', etc.
+                        *
+                        * @since 2.9.0
+                        *
+                        * @param mixed  $value   The user object value to sanitize.
+                        * @param int    $user_id User ID.
+                        * @param string $context The context to filter within.
+                        */
+                       $value = apply_filters( "user_{$field}", $value, $user_id, $context );
+               }
+       }
+
+       if ( 'user_url' == $field )
+               $value = esc_url($value);
+
+       if ( 'attribute' == $context ) {
+               $value = esc_attr( $value );
+       } elseif ( 'js' == $context ) {
+               $value = esc_js( $value );
+       }
+       return $value;
+}
+
+/**
+ * Update all user caches
+ *
+ * @since 3.0.0
+ *
+ * @param object|WP_User $user User object to be cached
+ * @return bool|null Returns false on failure.
+ */
+function update_user_caches( $user ) {
+       if ( $user instanceof WP_User ) {
+               if ( ! $user->exists() ) {
+                       return false;
+               }
+
+               $user = $user->data;
+       }
+
+       wp_cache_add($user->ID, $user, 'users');
+       wp_cache_add($user->user_login, $user->ID, 'userlogins');
+       wp_cache_add($user->user_email, $user->ID, 'useremail');
+       wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
+}
+
+/**
+ * Clean all user caches
+ *
+ * @since 3.0.0
+ * @since 4.4.0 'clean_user_cache' action was added.
+ *
+ * @param WP_User|int $user User object or ID to be cleaned from the cache
+ */
+function clean_user_cache( $user ) {
+       if ( is_numeric( $user ) )
+               $user = new WP_User( $user );
+
+       if ( ! $user->exists() )
+               return;
+
+       wp_cache_delete( $user->ID, 'users' );
+       wp_cache_delete( $user->user_login, 'userlogins' );
+       wp_cache_delete( $user->user_email, 'useremail' );
+       wp_cache_delete( $user->user_nicename, 'userslugs' );
+
+       /**
+        * Fires immediately after the given user's cache is cleaned.
+        *
+        * @since 4.4.0
+        *
+        * @param int     $user_id User ID.
+        * @param WP_User $user    User object.
+        */
+       do_action( 'clean_user_cache', $user->ID, $user );
+}
+
+/**
+ * Checks whether the given username exists.
+ *
+ * @since 2.0.0
+ *
+ * @param string $username Username.
+ * @return int|false The user's ID on success, and false on failure.
+ */
+function username_exists( $username ) {
+       if ( $user = get_user_by( 'login', $username ) ) {
+               return $user->ID;
+       }
+       return false;
+}
+
+/**
+ * Checks whether the given email exists.
+ *
+ * @since 2.1.0
+ *
+ * @param string $email Email.
+ * @return int|false The user's ID on success, and false on failure.
+ */
+function email_exists( $email ) {
+       if ( $user = get_user_by( 'email', $email) ) {
+               return $user->ID;
+       }
+       return false;
+}
+
+/**
+ * Checks whether a username is valid.
+ *
+ * @since 2.0.1
+ * @since 4.4.0 Empty sanitized usernames are now considered invalid
+ *
+ * @param string $username Username.
+ * @return bool Whether username given is valid
+ */
+function validate_username( $username ) {
+       $sanitized = sanitize_user( $username, true );
+       $valid = ( $sanitized == $username && ! empty( $sanitized ) );
+
+       /**
+        * Filter whether the provided username is valid or not.
+        *
+        * @since 2.0.1
+        *
+        * @param bool   $valid    Whether given username is valid.
+        * @param string $username Username to check.
+        */
+       return apply_filters( 'validate_username', $valid, $username );
+}
+
+/**
+ * Insert a user into the database.
+ *
+ * Most of the `$userdata` array fields have filters associated with the values. Exceptions are
+ * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl',
+ * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field
+ * name. An example using 'description' would have the filter called, 'pre_user_description' that
+ * can be hooked into.
+ *
+ * @since 2.0.0
+ * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact
+ *              methods for new installs. See wp_get_user_contact_methods().
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param array|object|WP_User $userdata {
+ *     An array, object, or WP_User object of user data arguments.
+ *
+ *     @type int         $ID                   User ID. If supplied, the user will be updated.
+ *     @type string      $user_pass            The plain-text user password.
+ *     @type string      $user_login           The user's login username.
+ *     @type string      $user_nicename        The URL-friendly user name.
+ *     @type string      $user_url             The user URL.
+ *     @type string      $user_email           The user email address.
+ *     @type string      $display_name         The user's display name.
+ *                                             Default is the the user's username.
+ *     @type string      $nickname             The user's nickname.
+ *                                             Default is the the user's username.
+ *     @type string      $first_name           The user's first name. For new users, will be used
+ *                                             to build the first part of the user's display name
+ *                                             if `$display_name` is not specified.
+ *     @type string      $last_name            The user's last name. For new users, will be used
+ *                                             to build the second part of the user's display name
+ *                                             if `$display_name` is not specified.
+ *     @type string      $description          The user's biographical description.
+ *     @type string|bool $rich_editing         Whether to enable the rich-editor for the user.
+ *                                             False if not empty.
+ *     @type string|bool $comment_shortcuts    Whether to enable comment moderation keyboard
+ *                                             shortcuts for the user. Default false.
+ *     @type string      $admin_color          Admin color scheme for the user. Default 'fresh'.
+ *     @type bool        $use_ssl              Whether the user should always access the admin over
+ *                                             https. Default false.
+ *     @type string      $user_registered      Date the user registered. Format is 'Y-m-d H:i:s'.
+ *     @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the
+ *                                             site's frontend. Default true.
+ *     @type string      $role                 User's role.
+ * }
+ * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
+ *                      be created.
+ */
+function wp_insert_user( $userdata ) {
+       global $wpdb;
+
+       if ( $userdata instanceof stdClass ) {
+               $userdata = get_object_vars( $userdata );
+       } elseif ( $userdata instanceof WP_User ) {
+               $userdata = $userdata->to_array();
+       }
+
+       // Are we updating or creating?
+       if ( ! empty( $userdata['ID'] ) ) {
+               $ID = (int) $userdata['ID'];
+               $update = true;
+               $old_user_data = get_userdata( $ID );
+
+               if ( ! $old_user_data ) {
+                       return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
+               }
+
+               // hashed in wp_update_user(), plaintext if called directly
+               $user_pass = ! empty( $userdata['user_pass'] ) ? $userdata['user_pass'] : $old_user_data->user_pass;
+       } else {
+               $update = false;
+               // Hash the password
+               $user_pass = wp_hash_password( $userdata['user_pass'] );
+       }
+
+       $sanitized_user_login = sanitize_user( $userdata['user_login'], true );
+
+       /**
+        * Filter a username after it has been sanitized.
+        *
+        * This filter is called before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $sanitized_user_login Username after it has been sanitized.
+        */
+       $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
+
+       //Remove any non-printable chars from the login string to see if we have ended up with an empty username
+       $user_login = trim( $pre_user_login );
+
+       // user_login must be between 0 and 60 characters.
+       if ( empty( $user_login ) ) {
+               return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
+       } elseif ( mb_strlen( $user_login ) > 60 ) {
+               return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) );
+       }
+
+       if ( ! $update && username_exists( $user_login ) ) {
+               return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
+       }
+
+       /**
+        * Filter the list of blacklisted usernames.
+        *
+        * @since 4.4.0
+        *
+        * @param array $usernames Array of blacklisted usernames.
+        */
+       $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
+
+       if ( in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
+               return new WP_Error( 'illegal_user_login', __( 'Sorry, that username is not allowed.' ) );
+       }
+
+       /*
+        * If a nicename is provided, remove unsafe user characters before using it.
+        * Otherwise build a nicename from the user_login.
+        */
+       if ( ! empty( $userdata['user_nicename'] ) ) {
+               $user_nicename = sanitize_user( $userdata['user_nicename'], true );
+               if ( mb_strlen( $user_nicename ) > 50 ) {
+                       return new WP_Error( 'user_nicename_too_long', __( 'Nicename may not be longer than 50 characters.' ) );
+               }
+       } else {
+               $user_nicename = mb_substr( $user_login, 0, 50 );
+       }
+
+       $user_nicename = sanitize_title( $user_nicename );
+
+       // Store values to save in user meta.
+       $meta = array();
+
+       /**
+        * Filter a user's nicename before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $user_nicename The user's nicename.
+        */
+       $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename );
+
+       $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url'];
+
+       /**
+        * Filter a user's URL before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $raw_user_url The user's URL.
+        */
+       $user_url = apply_filters( 'pre_user_url', $raw_user_url );
+
+       $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email'];
+
+       /**
+        * Filter a user's email before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $raw_user_email The user's email.
+        */
+       $user_email = apply_filters( 'pre_user_email', $raw_user_email );
+
+       /*
+        * If there is no update, just check for `email_exists`. If there is an update,
+        * check if current email and new email are the same, or not, and check `email_exists`
+        * accordingly.
+        */
+       if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) )
+               && ! defined( 'WP_IMPORTING' )
+               && email_exists( $user_email )
+       ) {
+               return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
+       }
+       $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname'];
+
+       /**
+        * Filter a user's nickname before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $nickname The user's nickname.
+        */
+       $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname );
+
+       $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name'];
+
+       /**
+        * Filter a user's first name before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $first_name The user's first name.
+        */
+       $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name );
+
+       $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name'];
+
+       /**
+        * Filter a user's last name before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $last_name The user's last name.
+        */
+       $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name );
+
+       if ( empty( $userdata['display_name'] ) ) {
+               if ( $update ) {
+                       $display_name = $user_login;
+               } elseif ( $meta['first_name'] && $meta['last_name'] ) {
+                       /* translators: 1: first name, 2: last name */
+                       $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] );
+               } elseif ( $meta['first_name'] ) {
+                       $display_name = $meta['first_name'];
+               } elseif ( $meta['last_name'] ) {
+                       $display_name = $meta['last_name'];
+               } else {
+                       $display_name = $user_login;
+               }
+       } else {
+               $display_name = $userdata['display_name'];
+       }
+
+       /**
+        * Filter a user's display name before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $display_name The user's display name.
+        */
+       $display_name = apply_filters( 'pre_user_display_name', $display_name );
+
+       $description = empty( $userdata['description'] ) ? '' : $userdata['description'];
+
+       /**
+        * Filter a user's description before the user is created or updated.
+        *
+        * @since 2.0.3
+        *
+        * @param string $description The user's description.
+        */
+       $meta['description'] = apply_filters( 'pre_user_description', $description );
+
+       $meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing'];
+
+       $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true';
+
+       $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color'];
+       $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color );
+
+       $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl'];
+
+       $user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered'];
+
+       $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front'];
+
+       $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
+
+       if ( $user_nicename_check ) {
+               $suffix = 2;
+               while ($user_nicename_check) {
+                       // user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix.
+                       $base_length = 49 - mb_strlen( $suffix );
+                       $alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
+                       $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
+                       $suffix++;
+               }
+               $user_nicename = $alt_user_nicename;
+       }
+
+       $compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
+       $data = wp_unslash( $compacted );
+
+       if ( $update ) {
+               if ( $user_email !== $old_user_data->user_email ) {
+                       $data['user_activation_key'] = '';
+               }
+               $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
+               $user_id = (int) $ID;
+       } else {
+               $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
+               $user_id = (int) $wpdb->insert_id;
+       }
+
+       $user = new WP_User( $user_id );
+
+       /**
+        * Filter a user's meta values and keys before the user is created or updated.
+        *
+        * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`.
+        *
+        * @since 4.4.0
+        *
+        * @param array $meta {
+        *     Default meta values and keys for the user.
+        *
+        *     @type string   $nickname             The user's nickname. Default is the the user's username.
+        *     @type string   $first_name           The user's first name.
+        *     @type string   $last_name            The user's last name.
+        *     @type string   $description          The user's description.
+        *     @type bool     $rich_editing         Whether to enable the rich-editor for the user. False if not empty.
+        *     @type bool     $comment_shortcuts    Whether to enable keyboard shortcuts for the user. Default false.
+        *     @type string   $admin_color          The color scheme for a user's admin screen. Default 'fresh'.
+        *     @type int|bool $use_ssl              Whether to force SSL on the user's admin area. 0|false if SSL is
+        *                                          not forced.
+        *     @type bool     $show_admin_bar_front Whether to show the admin bar on the front end for the user.
+        *                                          Default true.
+        * }
+        * @param WP_User $user   User object.
+        * @param bool    $update Whether the user is being updated rather than created.
+        */
+       $meta = apply_filters( 'insert_user_meta', $meta, $user, $update );
+
+       // Update user meta.
+       foreach ( $meta as $key => $value ) {
+               update_user_meta( $user_id, $key, $value );
+       }
+
+       foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) {
+               if ( isset( $userdata[ $key ] ) ) {
+                       update_user_meta( $user_id, $key, $userdata[ $key ] );
+               }
+       }
+
+       if ( isset( $userdata['role'] ) ) {
+               $user->set_role( $userdata['role'] );
+       } elseif ( ! $update ) {
+               $user->set_role(get_option('default_role'));
+       }
+       wp_cache_delete( $user_id, 'users' );
+       wp_cache_delete( $user_login, 'userlogins' );
+
+       if ( $update ) {
+               /**
+                * Fires immediately after an existing user is updated.
+                *
+                * @since 2.0.0
+                *
+                * @param int    $user_id       User ID.
+                * @param object $old_user_data Object containing user's data prior to update.
+                */
+               do_action( 'profile_update', $user_id, $old_user_data );
+       } else {
+               /**
+                * Fires immediately after a new user is registered.
+                *
+                * @since 1.5.0
+                *
+                * @param int $user_id User ID.
+                */
+               do_action( 'user_register', $user_id );
+       }
+
+       return $user_id;
+}
+
+/**
+ * Update a user in the database.
+ *
+ * It is possible to update a user's password by specifying the 'user_pass'
+ * value in the $userdata parameter array.
+ *
+ * If current user's password is being updated, then the cookies will be
+ * cleared.
+ *
+ * @since 2.0.0
+ *
+ * @see wp_insert_user() For what fields can be set in $userdata.
+ *
+ * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
+ * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
+ */
+function wp_update_user($userdata) {
+       if ( $userdata instanceof stdClass ) {
+               $userdata = get_object_vars( $userdata );
+       } elseif ( $userdata instanceof WP_User ) {
+               $userdata = $userdata->to_array();
+       }
+
+       $ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0;
+       if ( ! $ID ) {
+               return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
+       }
+
+       // First, get all of the original fields
+       $user_obj = get_userdata( $ID );
+       if ( ! $user_obj ) {
+               return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
+       }
+
+       $user = $user_obj->to_array();
+
+       // Add additional custom fields
+       foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
+               $user[ $key ] = get_user_meta( $ID, $key, true );
+       }
+
+       // Escape data pulled from DB.
+       $user = add_magic_quotes( $user );
+
+       if ( ! empty( $userdata['user_pass'] ) && $userdata['user_pass'] !== $user_obj->user_pass ) {
+               // If password is changing, hash it now
+               $plaintext_pass = $userdata['user_pass'];
+               $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] );
+
+               /**
+                * Filter whether to send the password change email.
+                *
+                * @since 4.3.0
+                *
+                * @see wp_insert_user() For `$user` and `$userdata` fields.
+                *
+                * @param bool  $send     Whether to send the email.
+                * @param array $user     The original user array.
+                * @param array $userdata The updated user array.
+                *
+                */
+               $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata );
+       }
+
+       if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) {
+               /**
+                * Filter whether to send the email change email.
+                *
+                * @since 4.3.0
+                *
+                * @see wp_insert_user() For `$user` and `$userdata` fields.
+                *
+                * @param bool  $send     Whether to send the email.
+                * @param array $user     The original user array.
+                * @param array $userdata The updated user array.
+                *
+                */
+               $send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata );
+       }
+
+       wp_cache_delete( $user['user_email'], 'useremail' );
+
+       // Merge old and new fields with new fields overwriting old ones.
+       $userdata = array_merge( $user, $userdata );
+       $user_id = wp_insert_user( $userdata );
+
+       if ( ! is_wp_error( $user_id ) ) {
+
+               $blog_name = wp_specialchars_decode( get_option( 'blogname' ) );
+
+               if ( ! empty( $send_password_change_email ) ) {
+
+                       /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
+                       $pass_change_text = __( 'Hi ###USERNAME###,
+
+This notice confirms that your password was changed on ###SITENAME###.
+
+If you did not change your password, please contact the Site Administrator at
+###ADMIN_EMAIL###
+
+This email has been sent to ###EMAIL###
+
+Regards,
+All at ###SITENAME###
+###SITEURL###' );
+
+                       $pass_change_email = array(
+                               'to'      => $user['user_email'],
+                               'subject' => __( '[%s] Notice of Password Change' ),
+                               'message' => $pass_change_text,
+                               'headers' => '',
+                       );
+
+                       /**
+                        * Filter the contents of the email sent when the user's password is changed.
+                        *
+                        * @since 4.3.0
+                        *
+                        * @param array $pass_change_email {
+                        *            Used to build wp_mail().
+                        *            @type string $to      The intended recipients. Add emails in a comma separated string.
+                        *            @type string $subject The subject of the email.
+                        *            @type string $message The content of the email.
+                        *                The following strings have a special meaning and will get replaced dynamically:
+                        *                - ###USERNAME###    The current user's username.
+                        *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
+                        *                - ###EMAIL###       The old email.
+                        *                - ###SITENAME###    The name of the site.
+                        *                - ###SITEURL###     The URL to the site.
+                        *            @type string $headers Headers. Add headers in a newline (\r\n) separated string.
+                        *        }
+                        * @param array $user     The original user array.
+                        * @param array $userdata The updated user array.
+                        *
+                        */
+                       $pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata );
+
+                       $pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] );
+                       $pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] );
+                       $pass_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $pass_change_email['message'] );
+                       $pass_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $pass_change_email['message'] );
+                       $pass_change_email['message'] = str_replace( '###SITEURL###', home_url(), $pass_change_email['message'] );
+
+                       wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] );
+               }
+
+               if ( ! empty( $send_email_change_email ) ) {
+                       /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
+                       $email_change_text = __( 'Hi ###USERNAME###,
+
+This notice confirms that your email was changed on ###SITENAME###.
+
+If you did not change your email, please contact the Site Administrator at
+###ADMIN_EMAIL###
+
+This email has been sent to ###EMAIL###
+
+Regards,
+All at ###SITENAME###
+###SITEURL###' );
+
+                       $email_change_email = array(
+                               'to'      => $user['user_email'],
+                               'subject' => __( '[%s] Notice of Email Change' ),
+                               'message' => $email_change_text,
+                               'headers' => '',
+                       );
+
+                       /**
+                        * Filter the contents of the email sent when the user's email is changed.
+                        *
+                        * @since 4.3.0
+                        *
+                        * @param array $email_change_email {
+                        *            Used to build wp_mail().
+                        *            @type string $to      The intended recipients.
+                        *            @type string $subject The subject of the email.
+                        *            @type string $message The content of the email.
+                        *                The following strings have a special meaning and will get replaced dynamically:
+                        *                - ###USERNAME###    The current user's username.
+                        *                - ###ADMIN_EMAIL### The admin email in case this was unexpected.
+                        *                - ###EMAIL###       The old email.
+                        *                - ###SITENAME###    The name of the site.
+                        *                - ###SITEURL###     The URL to the site.
+                        *            @type string $headers Headers.
+                        *        }
+                        * @param array $user The original user array.
+                        * @param array $userdata The updated user array.
+                        */
+                       $email_change_email = apply_filters( 'email_change_email', $email_change_email, $user, $userdata );
+
+                       $email_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $email_change_email['message'] );
+                       $email_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $email_change_email['message'] );
+                       $email_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $email_change_email['message'] );
+                       $email_change_email['message'] = str_replace( '###SITENAME###', get_option( 'blogname' ), $email_change_email['message'] );
+                       $email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] );
+
+                       wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
+               }
+       }
+
+       // Update the cookies if the password changed.
+       $current_user = wp_get_current_user();
+       if ( $current_user->ID == $ID ) {
+               if ( isset($plaintext_pass) ) {
+                       wp_clear_auth_cookie();
+
+                       // Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
+                       // If it's greater than this, then we know the user checked 'Remember Me' when they logged in.
+                       $logged_in_cookie    = wp_parse_auth_cookie( '', 'logged_in' );
+                       /** This filter is documented in wp-includes/pluggable.php */
+                       $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false );
+                       $remember            = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life );
+
+                       wp_set_auth_cookie( $ID, $remember );
+               }
+       }
+
+       return $user_id;
+}
+
+/**
+ * A simpler way of inserting a user into the database.
+ *
+ * Creates a new user with just the username, password, and email. For more
+ * complex user creation use {@see wp_insert_user()} to specify more information.
+ *
+ * @since 2.0.0
+ * @see wp_insert_user() More complete way to create a new user
+ *
+ * @param string $username The user's username.
+ * @param string $password The user's password.
+ * @param string $email    Optional. The user's email. Default empty.
+ * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not
+ *                      be created.
+ */
+function wp_create_user($username, $password, $email = '') {
+       $user_login = wp_slash( $username );
+       $user_email = wp_slash( $email    );
+       $user_pass = $password;
+
+       $userdata = compact('user_login', 'user_email', 'user_pass');
+       return wp_insert_user($userdata);
+}
+
+/**
+ * Returns a list of meta keys to be (maybe) populated in wp_update_user().
+ *
+ * The list of keys returned via this function are dependent on the presence
+ * of those keys in the user meta data to be set.
+ *
+ * @since 3.3.0
+ * @access private
+ *
+ * @param WP_User $user WP_User instance.
+ * @return array List of user keys to be populated in wp_update_user().
+ */
+function _get_additional_user_keys( $user ) {
+       $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
+       return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) );
+}
+
+/**
+ * Set up the user contact methods.
+ *
+ * Default contact methods were removed in 3.6. A filter dictates contact methods.
+ *
+ * @since 3.7.0
+ *
+ * @param WP_User $user Optional. WP_User object.
+ * @return array Array of contact methods and their labels.
+ */
+function wp_get_user_contact_methods( $user = null ) {
+       $methods = array();
+       if ( get_site_option( 'initial_db_version' ) < 23588 ) {
+               $methods = array(
+                       'aim'    => __( 'AIM' ),
+                       'yim'    => __( 'Yahoo IM' ),
+                       'jabber' => __( 'Jabber / Google Talk' )
+               );
+       }
+
+       /**
+        * Filter the user contact methods.
+        *
+        * @since 2.9.0
+        *
+        * @param array   $methods Array of contact methods and their labels.
+        * @param WP_User $user    WP_User object.
+        */
+       return apply_filters( 'user_contactmethods', $methods, $user );
+}
+
+/**
+ * The old private function for setting up user contact methods.
+ *
+ * @since 2.9.0
+ * @access private
+ */
+function _wp_get_user_contactmethods( $user = null ) {
+       return wp_get_user_contact_methods( $user );
+}
+
+/**
+ * Gets the text suggesting how to create strong passwords.
+ *
+ * @since 4.1.0
+ *
+ * @return string The password hint text.
+ */
+function wp_get_password_hint() {
+       $hint = __( 'Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ &amp; ).' );
+
+       /**
+        * Filter the text describing the site's password complexity policy.
+        *
+        * @since 4.1.0
+        *
+        * @param string $hint The password hint text.
+        */
+       return apply_filters( 'password_hint', $hint );
+}
+
+/**
+ * Creates, stores, then returns a password reset key for user.
+ *
+ * @since 4.4.0
+ *
+ * @global wpdb         $wpdb      WordPress database abstraction object.
+ * @global PasswordHash $wp_hasher Portable PHP password hashing framework.
+ *
+ * @param WP_User $user User to retrieve password reset key for.
+ *
+ * @return string|WP_Error Password reset key on success. WP_Error on error.
+ */
+function get_password_reset_key( $user ) {
+       global $wpdb, $wp_hasher;
+
+       /**
+        * Fires before a new password is retrieved.
+        *
+        * @since 1.5.0
+        * @deprecated 1.5.1 Misspelled. Use 'retrieve_password' hook instead.
+        *
+        * @param string $user_login The user login name.
+        */
+       do_action( 'retreive_password', $user->user_login );
+
+       /**
+        * Fires before a new password is retrieved.
+        *
+        * @since 1.5.1
+        *
+        * @param string $user_login The user login name.
+        */
+       do_action( 'retrieve_password', $user->user_login );
+
+       /**
+        * Filter whether to allow a password to be reset.
+        *
+        * @since 2.7.0
+        *
+        * @param bool true           Whether to allow the password to be reset. Default true.
+        * @param int  $user_data->ID The ID of the user attempting to reset a password.
+        */
+       $allow = apply_filters( 'allow_password_reset', true, $user->ID );
+
+       if ( ! $allow ) {
+               return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user' ) );
+       } elseif ( is_wp_error( $allow ) ) {
+               return $allow;
+       }
+
+       // Generate something random for a password reset key.
+       $key = wp_generate_password( 20, false );
+
+       /**
+        * Fires when a password reset key is generated.
+        *
+        * @since 2.5.0
+        *
+        * @param string $user_login The username for the user.
+        * @param string $key        The generated password reset key.
+        */
+       do_action( 'retrieve_password_key', $user->user_login, $key );
+
+       // Now insert the key, hashed, into the DB.
+       if ( empty( $wp_hasher ) ) {
+               require_once ABSPATH . WPINC . '/class-phpass.php';
+               $wp_hasher = new PasswordHash( 8, true );
+       }
+       $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
+       $key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
+       if ( false === $key_saved ) {
+               return WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) );
+       }
+
+       return $key;
+}
+
+/**
+ * Retrieves a user row based on password reset key and login
+ *
+ * A key is considered 'expired' if it exactly matches the value of the
+ * user_activation_key field, rather than being matched after going through the
+ * hashing process. This field is now hashed; old values are no longer accepted
+ * but have a different WP_Error code so good user feedback can be provided.
+ *
+ * @since 3.1.0
+ *
+ * @global wpdb         $wpdb      WordPress database object for queries.
+ * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
+ *
+ * @param string $key       Hash to validate sending user's password.
+ * @param string $login     The user login.
+ * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
+ */
+function check_password_reset_key($key, $login) {
+       global $wpdb, $wp_hasher;
+
+       $key = preg_replace('/[^a-z0-9]/i', '', $key);
+
+       if ( empty( $key ) || !is_string( $key ) )
+               return new WP_Error('invalid_key', __('Invalid key'));
+
+       if ( empty($login) || !is_string($login) )
+               return new WP_Error('invalid_key', __('Invalid key'));
+
+       $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) );
+       if ( ! $row )
+               return new WP_Error('invalid_key', __('Invalid key'));
+
+       if ( empty( $wp_hasher ) ) {
+               require_once ABSPATH . WPINC . '/class-phpass.php';
+               $wp_hasher = new PasswordHash( 8, true );
+       }
+
+       /**
+        * Filter the expiration time of password reset keys.
+        *
+        * @since 4.3.0
+        *
+        * @param int $expiration The expiration time in seconds.
+        */
+       $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS );
+
+       if ( false !== strpos( $row->user_activation_key, ':' ) ) {
+               list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 );
+               $expiration_time = $pass_request_time + $expiration_duration;
+       } else {
+               $pass_key = $row->user_activation_key;
+               $expiration_time = false;
+       }
+
+       $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
+
+       if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
+               return get_userdata( $row->ID );
+       } elseif ( $hash_is_correct && $expiration_time ) {
+               // Key has an expiration time that's passed
+               return new WP_Error( 'expired_key', __( 'Invalid key' ) );
+       }
+
+       if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) {
+               $return = new WP_Error( 'expired_key', __( 'Invalid key' ) );
+               $user_id = $row->ID;
+
+               /**
+                * Filter the return value of check_password_reset_key() when an
+                * old-style key is used.
+                *
+                * @since 3.7.0 Previously plain-text keys were stored in the database.
+                * @since 4.3.0 Previously key hashes were stored without an expiration time.
+                *
+                * @param WP_Error $return  A WP_Error object denoting an expired key.
+                *                          Return a WP_User object to validate the key.
+                * @param int      $user_id The matched user ID.
+                */
+               return apply_filters( 'password_reset_key_expired', $return, $user_id );
+       }
+
+       return new WP_Error( 'invalid_key', __( 'Invalid key' ) );
+}
+
+/**
+ * Handles resetting the user's password.
+ *
+ * @since 2.5.0
+ *
+ * @param object $user     The user
+ * @param string $new_pass New password for the user in plaintext
+ */
+function reset_password( $user, $new_pass ) {
+       /**
+        * Fires before the user's password is reset.
+        *
+        * @since 1.5.0
+        *
+        * @param object $user     The user.
+        * @param string $new_pass New user password.
+        */
+       do_action( 'password_reset', $user, $new_pass );
+
+       wp_set_password( $new_pass, $user->ID );
+       update_user_option( $user->ID, 'default_password_nag', false, true );
+
+       /**
+        * Fires after the user's password is reset.
+        *
+        * @since 4.4.0
+        *
+        * @param object $user     The user.
+        * @param string $new_pass New user password.
+        */
+       do_action( 'after_password_reset', $user, $new_pass );
+}
+
+/**
+ * Handles registering a new user.
+ *
+ * @since 2.5.0
+ *
+ * @param string $user_login User's username for logging in
+ * @param string $user_email User's email address to send password and add
+ * @return int|WP_Error Either user's ID or error on failure.
+ */
+function register_new_user( $user_login, $user_email ) {
+       $errors = new WP_Error();
+
+       $sanitized_user_login = sanitize_user( $user_login );
+       /**
+        * Filter the email address of a user being registered.
+        *
+        * @since 2.1.0
+        *
+        * @param string $user_email The email address of the new user.
+        */
+       $user_email = apply_filters( 'user_registration_email', $user_email );
+
+       // Check the username
+       if ( $sanitized_user_login == '' ) {
+               $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
+       } elseif ( ! validate_username( $user_login ) ) {
+               $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
+               $sanitized_user_login = '';
+       } elseif ( username_exists( $sanitized_user_login ) ) {
+               $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
+       }
+
+       // Check the email address
+       if ( $user_email == '' ) {
+               $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your email address.' ) );
+       } elseif ( ! is_email( $user_email ) ) {
+               $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
+               $user_email = '';
+       } elseif ( email_exists( $user_email ) ) {
+               $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
+       }
+
+       /**
+        * Fires when submitting registration form data, before the user is created.
+        *
+        * @since 2.1.0
+        *
+        * @param string   $sanitized_user_login The submitted username after being sanitized.
+        * @param string   $user_email           The submitted email.
+        * @param WP_Error $errors               Contains any errors with submitted username and email,
+        *                                       e.g., an empty field, an invalid username or email,
+        *                                       or an existing username or email.
+        */
+       do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
+
+       /**
+        * Filter the errors encountered when a new user is being registered.
+        *
+        * The filtered WP_Error object may, for example, contain errors for an invalid
+        * or existing username or email address. A WP_Error object should always returned,
+        * but may or may not contain errors.
+        *
+        * If any errors are present in $errors, this will abort the user's registration.
+        *
+        * @since 2.1.0
+        *
+        * @param WP_Error $errors               A WP_Error object containing any errors encountered
+        *                                       during registration.
+        * @param string   $sanitized_user_login User's username after it has been sanitized.
+        * @param string   $user_email           User's email.
+        */
+       $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
+
+       if ( $errors->get_error_code() )
+               return $errors;
+
+       $user_pass = wp_generate_password( 12, false );
+       $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
+       if ( ! $user_id || is_wp_error( $user_id ) ) {
+               $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
+               return $errors;
+       }
+
+       update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
+
+       /**
+        * Fires after a new user registration has been recorded.
+        *
+        * @since 4.4.0
+        *
+        * @param int $user_id ID of the newly registered user.
+        */
+       do_action( 'register_new_user', $user_id );
+
+       return $user_id;
+}
+
+/**
+ * Initiate email notifications related to the creation of new users.
+ *
+ * Notifications are sent both to the site admin and to the newly created user.
+ *
+ * @since 4.4.0
+ *
+ * @param int $user_id ID of the newly created user.
+ */
+function wp_send_new_user_notifications( $user_id ) {
+       wp_new_user_notification( $user_id, null, 'both' );
+}
+
+/**
+ * Retrieve the current session token from the logged_in cookie.
+ *
+ * @since 4.0.0
+ *
+ * @return string Token.
+ */
+function wp_get_session_token() {
+       $cookie = wp_parse_auth_cookie( '', 'logged_in' );
+       return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
+}
+
+/**
+ * Retrieve a list of sessions for the current user.
+ *
+ * @since 4.0.0
+ * @return array Array of sessions.
+ */
+function wp_get_all_sessions() {
+       $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
+       return $manager->get_all();
+}
+
+/**
+ * Remove the current session token from the database.
+ *
+ * @since 4.0.0
+ */
+function wp_destroy_current_session() {
+       $token = wp_get_session_token();
+       if ( $token ) {
+               $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
+               $manager->destroy( $token );
+       }
+}
+
+/**
+ * Remove all but the current session token for the current user for the database.
+ *
+ * @since 4.0.0
+ */
+function wp_destroy_other_sessions() {
+       $token = wp_get_session_token();
+       if ( $token ) {
+               $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
+               $manager->destroy_others( $token );
+       }
+}
+
+/**
+ * Remove all session tokens for the current user from the database.
+ *
+ * @since 4.0.0
+ */
+function wp_destroy_all_sessions() {
+       $manager = WP_Session_Tokens::get_instance( get_current_user_id() );
+       $manager->destroy_all();
+}
+
+/**
+ * Get the user IDs of all users with no role on this site.
+ *
+ * This function returns an empty array when used on Multisite.
+ *
+ * @since 4.4.0
+ *
+ * @return array Array of user IDs.
+ */
+function wp_get_users_with_no_role() {
+       global $wpdb;
+
+       if ( is_multisite() ) {
+               return array();
+       }
+
+       $prefix = $wpdb->get_blog_prefix();
+       $regex  = implode( '|', wp_roles()->get_names() );
+       $regex  = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex );
+       $users  = $wpdb->get_col( $wpdb->prepare( "
+               SELECT user_id
+               FROM $wpdb->usermeta
+               WHERE meta_key = '{$prefix}capabilities'
+               AND meta_value NOT REGEXP %s
+       ", $regex ) );
+
+       return $users;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludeswidgetfunctionsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/widget-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/widget-functions.php        2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/widget-functions.php  2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,1381 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Widget API: Top-level widget functionality
- *
- * @package WordPress
- * @subpackage Widgets
- * @since 4.4.0
- */
-
-//
-// Template tags & API functions
-//
-
-/**
- * Register a widget
- *
- * Registers a WP_Widget widget
- *
- * @since 2.8.0
- *
- * @see WP_Widget
- *
- * @global WP_Widget_Factory $wp_widget_factory
- *
- * @param string $widget_class The name of a class that extends WP_Widget
- */
-function register_widget($widget_class) {
-       global $wp_widget_factory;
-
-       $wp_widget_factory->register($widget_class);
-}
-
-/**
- * Unregister a widget
- *
- * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
- * Run within a function hooked to the widgets_init action.
- *
- * @since 2.8.0
- *
- * @see WP_Widget
- *
- * @global WP_Widget_Factory $wp_widget_factory
- *
- * @param string $widget_class The name of a class that extends WP_Widget
- */
-function unregister_widget($widget_class) {
-       global $wp_widget_factory;
-
-       $wp_widget_factory->unregister($widget_class);
-}
-
-/**
- * Creates multiple sidebars.
- *
- * If you wanted to quickly create multiple sidebars for a theme or internally.
- * This function will allow you to do so. If you don't pass the 'name' and/or
- * 'id' in `$args`, then they will be built for you.
- *
- * @since 2.2.0
- *
- * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
- *
- * @global array $wp_registered_sidebars
- *
- * @param int          $number Optional. Number of sidebars to create. Default 1.
- * @param array|string $args {
- *     Optional. Array or string of arguments for building a sidebar.
- *
- *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
- *                        sidebars are being defined, the id will have "-2" appended, and so on.
- *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
- *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
- *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
- *                        assigned number for each sidebar.
- *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
- * }
- */
-function register_sidebars( $number = 1, $args = array() ) {
-       global $wp_registered_sidebars;
-       $number = (int) $number;
-
-       if ( is_string($args) )
-               parse_str($args, $args);
-
-       for ( $i = 1; $i <= $number; $i++ ) {
-               $_args = $args;
-
-               if ( $number > 1 )
-                       $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
-               else
-                       $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
-
-               // Custom specified ID's are suffixed if they exist already.
-               // Automatically generated sidebar names need to be suffixed regardless starting at -0
-               if ( isset($args['id']) ) {
-                       $_args['id'] = $args['id'];
-                       $n = 2; // Start at -2 for conflicting custom ID's
-                       while ( is_registered_sidebar( $_args['id'] ) ) {
-                               $_args['id'] = $args['id'] . '-' . $n++;
-                       }
-               } else {
-                       $n = count( $wp_registered_sidebars );
-                       do {
-                               $_args['id'] = 'sidebar-' . ++$n;
-                       } while ( is_registered_sidebar( $_args['id'] ) );
-               }
-               register_sidebar($_args);
-       }
-}
-
-/**
- * Builds the definition for a single sidebar and returns the ID.
- *
- * Accepts either a string or an array and then parses that against a set
- * of default arguments for the new sidebar. WordPress will automatically
- * generate a sidebar ID and name based on the current number of registered
- * sidebars if those arguments are not included.
- *
- * When allowing for automatic generation of the name and ID parameters, keep
- * in mind that the incrementor for your sidebar can change over time depending
- * on what other plugins and themes are installed.
- *
- * If theme support for 'widgets' has not yet been added when this function is
- * called, it will be automatically enabled through the use of add_theme_support()
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
- *
- * @param array|string $args {
- *     Optional. Array or string of arguments for the sidebar being registered.
- *
- *     @type string $name          The name or title of the sidebar displayed in the Widgets
- *                                 interface. Default 'Sidebar $instance'.
- *     @type string $id            The unique identifier by which the sidebar will be called.
- *                                 Default 'sidebar-$instance'.
- *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
- *                                 Default empty string.
- *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
- *                                 Default empty.
- *     @type string $before_widget HTML content to prepend to each widget's HTML output when
- *                                 assigned to this sidebar. Default is an opening list item element.
- *     @type string $after_widget  HTML content to append to each widget's HTML output when
- *                                 assigned to this sidebar. Default is a closing list item element.
- *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
- *                                 Default is an opening h2 element.
- *     @type string $after_title   HTML content to append to the sidebar title when displayed.
- *                                 Default is a closing h2 element.
- * }
- * @return string Sidebar ID added to $wp_registered_sidebars global.
- */
-function register_sidebar($args = array()) {
-       global $wp_registered_sidebars;
-
-       $i = count($wp_registered_sidebars) + 1;
-
-       $id_is_empty = empty( $args['id'] );
-
-       $defaults = array(
-               'name' => sprintf(__('Sidebar %d'), $i ),
-               'id' => "sidebar-$i",
-               'description' => '',
-               'class' => '',
-               'before_widget' => '<li id="%1$s" class="widget %2$s">',
-               'after_widget' => "</li>\n",
-               'before_title' => '<h2 class="widgettitle">',
-               'after_title' => "</h2>\n",
-       );
-
-       $sidebar = wp_parse_args( $args, $defaults );
-
-       if ( $id_is_empty ) {
-               /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
-               _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
-       }
-
-       $wp_registered_sidebars[$sidebar['id']] = $sidebar;
-
-       add_theme_support('widgets');
-
-       /**
-        * Fires once a sidebar has been registered.
-        *
-        * @since 3.0.0
-        *
-        * @param array $sidebar Parsed arguments for the registered sidebar.
-        */
-       do_action( 'register_sidebar', $sidebar );
-
-       return $sidebar['id'];
-}
-
-/**
- * Removes a sidebar from the list.
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
- *
- * @param string $name The ID of the sidebar when it was added.
- */
-function unregister_sidebar( $name ) {
-       global $wp_registered_sidebars;
-
-       unset( $wp_registered_sidebars[ $name ] );
-}
-
-/**
- * Checks if a sidebar is registered.
- *
- * @since 4.4.0
- *
- * @global array $wp_registered_sidebars Registered sidebars.
- *
- * @param string|int $sidebar_id The ID of the sidebar when it was registered.
- * @return bool True if the sidebar is registered, false otherwise.
- */
-function is_registered_sidebar( $sidebar_id ) {
-       global $wp_registered_sidebars;
-
-       return isset( $wp_registered_sidebars[ $sidebar_id ] );
-}
-
-/**
- * Register an instance of a widget.
- *
- * The default widget option is 'classname' that can be overridden.
- *
- * The function can also be used to un-register widgets when `$output_callback`
- * parameter is an empty string.
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_widgets       Uses stored registered widgets.
- * @global array $wp_register_widget_defaults Retrieves widget defaults.
- * @global array $wp_registered_widget_updates
- * @global array $_wp_deprecated_widgets_callbacks
- *
- * @param int|string $id              Widget ID.
- * @param string     $name            Widget display title.
- * @param callable   $output_callback Run when widget is called.
- * @param array      $options {
- *     Optional. An array of supplementary widget options for the instance.
- *
- *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
- *                               version of the output callback name.
- *     @type string $description Widget description for display in the widget administration
- *                               panel and/or theme.
- * }
- */
-function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
-       global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
-
-       $id = strtolower($id);
-
-       if ( empty($output_callback) ) {
-               unset($wp_registered_widgets[$id]);
-               return;
-       }
-
-       $id_base = _get_widget_id_base($id);
-       if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
-               unset( $wp_registered_widget_controls[ $id ] );
-               unset( $wp_registered_widget_updates[ $id_base ] );
-               return;
-       }
-
-       $defaults = array('classname' => $output_callback);
-       $options = wp_parse_args($options, $defaults);
-       $widget = array(
-               'name' => $name,
-               'id' => $id,
-               'callback' => $output_callback,
-               'params' => array_slice(func_get_args(), 4)
-       );
-       $widget = array_merge($widget, $options);
-
-       if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
-
-               /**
-                * Fires once for each registered widget.
-                *
-                * @since 3.0.0
-                *
-                * @param array $widget An array of default widget arguments.
-                */
-               do_action( 'wp_register_sidebar_widget', $widget );
-               $wp_registered_widgets[$id] = $widget;
-       }
-}
-
-/**
- * Retrieve description for widget.
- *
- * When registering widgets, the options can also include 'description' that
- * describes the widget for display on the widget administration panel or
- * in the theme.
- *
- * @since 2.5.0
- *
- * @global array $wp_registered_widgets
- *
- * @param int|string $id Widget ID.
- * @return string|void Widget description, if available.
- */
-function wp_widget_description( $id ) {
-       if ( !is_scalar($id) )
-               return;
-
-       global $wp_registered_widgets;
-
-       if ( isset($wp_registered_widgets[$id]['description']) )
-               return esc_html( $wp_registered_widgets[$id]['description'] );
-}
-
-/**
- * Retrieve description for a sidebar.
- *
- * When registering sidebars a 'description' parameter can be included that
- * describes the sidebar for display on the widget administration panel.
- *
- * @since 2.9.0
- *
- * @global array $wp_registered_sidebars
- *
- * @param string $id sidebar ID.
- * @return string|void Sidebar description, if available.
- */
-function wp_sidebar_description( $id ) {
-       if ( !is_scalar($id) )
-               return;
-
-       global $wp_registered_sidebars;
-
-       if ( isset($wp_registered_sidebars[$id]['description']) )
-               return esc_html( $wp_registered_sidebars[$id]['description'] );
-}
-
-/**
- * Remove widget from sidebar.
- *
- * @since 2.2.0
- *
- * @param int|string $id Widget ID.
- */
-function wp_unregister_sidebar_widget($id) {
-
-       /**
-        * Fires just before a widget is removed from a sidebar.
-        *
-        * @since 3.0.0
-        *
-        * @param int $id The widget ID.
-        */
-       do_action( 'wp_unregister_sidebar_widget', $id );
-
-       wp_register_sidebar_widget($id, '', '');
-       wp_unregister_widget_control($id);
-}
-
-/**
- * Registers widget control callback for customizing options.
- *
- * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
- * option is never used. The 'width' option is the width of the fully expanded
- * control form, but try hard to use the default width. The 'id_base' is for
- * multi-widgets (widgets which allow multiple instances such as the text
- * widget), an id_base must be provided. The widget id will end up looking like
- * `{$id_base}-{$unique_number}`.
- *
- * @since 2.2.0
- *
- * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
- * @todo `$params` parameter?
- *
- * @global array $wp_registered_widget_controls
- * @global array $wp_registered_widget_updates
- * @global array $wp_registered_widgets
- * @global array $_wp_deprecated_widgets_callbacks
- *
- * @param int|string   $id               Sidebar ID.
- * @param string       $name             Sidebar display name.
- * @param callable     $control_callback Run when sidebar is displayed.
- * @param array|string $options          Optional. Widget options. See description above. Default empty array.
- */
-function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
-       global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
-
-       $id = strtolower($id);
-       $id_base = _get_widget_id_base($id);
-
-       if ( empty($control_callback) ) {
-               unset($wp_registered_widget_controls[$id]);
-               unset($wp_registered_widget_updates[$id_base]);
-               return;
-       }
-
-       if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
-               unset( $wp_registered_widgets[ $id ] );
-               return;
-       }
-
-       if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
-               return;
-
-       $defaults = array('width' => 250, 'height' => 200 ); // height is never used
-       $options = wp_parse_args($options, $defaults);
-       $options['width'] = (int) $options['width'];
-       $options['height'] = (int) $options['height'];
-
-       $widget = array(
-               'name' => $name,
-               'id' => $id,
-               'callback' => $control_callback,
-               'params' => array_slice(func_get_args(), 4)
-       );
-       $widget = array_merge($widget, $options);
-
-       $wp_registered_widget_controls[$id] = $widget;
-
-       if ( isset($wp_registered_widget_updates[$id_base]) )
-               return;
-
-       if ( isset($widget['params'][0]['number']) )
-               $widget['params'][0]['number'] = -1;
-
-       unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
-       $wp_registered_widget_updates[$id_base] = $widget;
-}
-
-/**
- * @global array $wp_registered_widget_updates
- *
- * @param string   $id_base
- * @param callable $update_callback
- * @param array    $options
- */
-function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
-       global $wp_registered_widget_updates;
-
-       if ( isset($wp_registered_widget_updates[$id_base]) ) {
-               if ( empty($update_callback) )
-                       unset($wp_registered_widget_updates[$id_base]);
-               return;
-       }
-
-       $widget = array(
-               'callback' => $update_callback,
-               'params' => array_slice(func_get_args(), 3)
-       );
-
-       $widget = array_merge($widget, $options);
-       $wp_registered_widget_updates[$id_base] = $widget;
-}
-
-/**
- *
- * @global array $wp_registered_widget_controls
- *
- * @param int|string $id
- * @param string     $name
- * @param callable   $form_callback
- * @param array      $options
- */
-function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
-       global $wp_registered_widget_controls;
-
-       $id = strtolower($id);
-
-       if ( empty($form_callback) ) {
-               unset($wp_registered_widget_controls[$id]);
-               return;
-       }
-
-       if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
-               return;
-
-       $defaults = array('width' => 250, 'height' => 200 );
-       $options = wp_parse_args($options, $defaults);
-       $options['width'] = (int) $options['width'];
-       $options['height'] = (int) $options['height'];
-
-       $widget = array(
-               'name' => $name,
-               'id' => $id,
-               'callback' => $form_callback,
-               'params' => array_slice(func_get_args(), 4)
-       );
-       $widget = array_merge($widget, $options);
-
-       $wp_registered_widget_controls[$id] = $widget;
-}
-
-/**
- * Remove control callback for widget.
- *
- * @since 2.2.0
- *
- * @param int|string $id Widget ID.
- */
-function wp_unregister_widget_control($id) {
-       wp_register_widget_control( $id, '', '' );
-}
-
-/**
- * Display dynamic sidebar.
- *
- * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
- * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
- * Otherwise, you can pass in a numerical index to display the sidebar at that index.
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_sidebars
- * @global array $wp_registered_widgets
- *
- * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
- * @return bool True, if widget sidebar was found and called. False if not found or not called.
- */
-function dynamic_sidebar( $index = 1 ) {
-       global $wp_registered_sidebars, $wp_registered_widgets;
-
-       if ( is_int( $index ) ) {
-               $index = "sidebar-$index";
-       } else {
-               $sanitized_index = sanitize_title( $index );
-               foreach ( (array) $wp_registered_sidebars as $key => $value ) {
-                       if ( sanitize_title( $value['name'] ) == $sanitized_index ) {
-                               $index = $key;
-                               break;
-                       }
-               }
-       }
-
-       $sidebars_widgets = wp_get_sidebars_widgets();
-       if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
-               /** This action is documented in wp-includes/widget-functions.php */
-               do_action( 'dynamic_sidebar_before', $index, false );
-               /** This action is documented in wp-includes/widget-functions.php */
-               do_action( 'dynamic_sidebar_after',  $index, false );
-               /** This filter is documented in wp-includes/widget-functions.php */
-               return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
-       }
-
-       /**
-        * Fires before widgets are rendered in a dynamic sidebar.
-        *
-        * Note: The action also fires for empty sidebars, and on both the front-end
-        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
-        *
-        * @since 3.9.0
-        *
-        * @param int|string $index       Index, name, or ID of the dynamic sidebar.
-        * @param bool       $has_widgets Whether the sidebar is populated with widgets.
-        *                                Default true.
-        */
-       do_action( 'dynamic_sidebar_before', $index, true );
-       $sidebar = $wp_registered_sidebars[$index];
-
-       $did_one = false;
-       foreach ( (array) $sidebars_widgets[$index] as $id ) {
-
-               if ( !isset($wp_registered_widgets[$id]) ) continue;
-
-               $params = array_merge(
-                       array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
-                       (array) $wp_registered_widgets[$id]['params']
-               );
-
-               // Substitute HTML id and class attributes into before_widget
-               $classname_ = '';
-               foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
-                       if ( is_string($cn) )
-                               $classname_ .= '_' . $cn;
-                       elseif ( is_object($cn) )
-                               $classname_ .= '_' . get_class($cn);
-               }
-               $classname_ = ltrim($classname_, '_');
-               $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
-
-               /**
-                * Filter the parameters passed to a widget's display callback.
-                *
-                * Note: The filter is evaluated on both the front-end and back-end,
-                * including for the Inactive Widgets sidebar on the Widgets screen.
-                *
-                * @since 2.5.0
-                *
-                * @see register_sidebar()
-                *
-                * @param array $params {
-                *     @type array $args  {
-                *         An array of widget display arguments.
-                *
-                *         @type string $name          Name of the sidebar the widget is assigned to.
-                *         @type string $id            ID of the sidebar the widget is assigned to.
-                *         @type string $description   The sidebar description.
-                *         @type string $class         CSS class applied to the sidebar container.
-                *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
-                *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
-                *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
-                *         @type string $after_title   HTML markup to append to the widget title when displayed.
-                *         @type string $widget_id     ID of the widget.
-                *         @type string $widget_name   Name of the widget.
-                *     }
-                *     @type array $widget_args {
-                *         An array of multi-widget arguments.
-                *
-                *         @type int $number Number increment used for multiples of the same widget.
-                *     }
-                * }
-                */
-               $params = apply_filters( 'dynamic_sidebar_params', $params );
-
-               $callback = $wp_registered_widgets[$id]['callback'];
-
-               /**
-                * Fires before a widget's display callback is called.
-                *
-                * Note: The action fires on both the front-end and back-end, including
-                * for widgets in the Inactive Widgets sidebar on the Widgets screen.
-                *
-                * The action is not fired for empty sidebars.
-                *
-                * @since 3.0.0
-                *
-                * @param array $widget_id {
-                *     An associative array of widget arguments.
-                *
-                *     @type string $name                Name of the widget.
-                *     @type string $id                  Widget ID.
-                *     @type array|callable $callback    When the hook is fired on the front-end, $callback is an array
-                *                                       containing the widget object. Fired on the back-end, $callback
-                *                                       is 'wp_widget_control', see $_callback.
-                *     @type array          $params      An associative array of multi-widget arguments.
-                *     @type string         $classname   CSS class applied to the widget container.
-                *     @type string         $description The widget description.
-                *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
-                *                                       with an array containing the widget object, see $callback.
-                * }
-                */
-               do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
-
-               if ( is_callable($callback) ) {
-                       call_user_func_array($callback, $params);
-                       $did_one = true;
-               }
-       }
-
-       /**
-        * Fires after widgets are rendered in a dynamic sidebar.
-        *
-        * Note: The action also fires for empty sidebars, and on both the front-end
-        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
-        *
-        * @since 3.9.0
-        *
-        * @param int|string $index       Index, name, or ID of the dynamic sidebar.
-        * @param bool       $has_widgets Whether the sidebar is populated with widgets.
-        *                                Default true.
-        */
-       do_action( 'dynamic_sidebar_after', $index, true );
-
-       /**
-        * Filter whether a sidebar has widgets.
-        *
-        * Note: The filter is also evaluated for empty sidebars, and on both the front-end
-        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
-        *
-        * @since 3.9.0
-        *
-        * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
-        *                            Default false.
-        * @param int|string $index   Index, name, or ID of the dynamic sidebar.
-        */
-       return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
-}
-
-/**
- * Whether widget is displayed on the front-end.
- *
- * Either $callback or $id_base can be used
- * $id_base is the first argument when extending WP_Widget class
- * Without the optional $widget_id parameter, returns the ID of the first sidebar
- * in which the first instance of the widget with the given callback or $id_base is found.
- * With the $widget_id parameter, returns the ID of the sidebar where
- * the widget with that callback/$id_base AND that ID is found.
- *
- * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
- * this function has to run after widgets have initialized, at action 'init' or later.
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_widgets
- *
- * @param string $callback      Optional, Widget callback to check.
- * @param int    $widget_id     Optional, but needed for checking. Widget ID.
- * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
- * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
- * @return string|false False if widget is not active or id of sidebar in which the widget is active.
- */
-function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
-       global $wp_registered_widgets;
-
-       $sidebars_widgets = wp_get_sidebars_widgets();
-
-       if ( is_array($sidebars_widgets) ) {
-               foreach ( $sidebars_widgets as $sidebar => $widgets ) {
-                       if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
-                               continue;
-                       }
-
-                       if ( is_array($widgets) ) {
-                               foreach ( $widgets as $widget ) {
-                                       if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
-                                               if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
-                                                       return $sidebar;
-                                       }
-                               }
-                       }
-               }
-       }
-       return false;
-}
-
-/**
- * Whether the dynamic sidebar is enabled and used by theme.
- *
- * @since 2.2.0
- *
- * @global array $wp_registered_widgets
- * @global array $wp_registered_sidebars
- *
- * @return bool True, if using widgets. False, if not using widgets.
- */
-function is_dynamic_sidebar() {
-       global $wp_registered_widgets, $wp_registered_sidebars;
-       $sidebars_widgets = get_option('sidebars_widgets');
-       foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
-               if ( count($sidebars_widgets[$index]) ) {
-                       foreach ( (array) $sidebars_widgets[$index] as $widget )
-                               if ( array_key_exists($widget, $wp_registered_widgets) )
-                                       return true;
-               }
-       }
-       return false;
-}
-
-/**
- * Whether a sidebar is in use.
- *
- * @since 2.8.0
- *
- * @param string|int $index Sidebar name, id or number to check.
- * @return bool true if the sidebar is in use, false otherwise.
- */
-function is_active_sidebar( $index ) {
-       $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
-       $sidebars_widgets = wp_get_sidebars_widgets();
-       $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
-
-       /**
-        * Filter whether a dynamic sidebar is considered "active".
-        *
-        * @since 3.9.0
-        *
-        * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
-        *                                      In other words, whether the sidebar contains any widgets.
-        * @param int|string $index             Index, name, or ID of the dynamic sidebar.
-        */
-       return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
-}
-
-//
-// Internal Functions
-//
-
-/**
- * Retrieve full list of sidebars and their widget instance IDs.
- *
- * Will upgrade sidebar widget list, if needed. Will also save updated list, if
- * needed.
- *
- * @since 2.2.0
- * @access private
- *
- * @global array $_wp_sidebars_widgets
- * @global array $sidebars_widgets
- *
- * @param bool $deprecated Not used (argument deprecated).
- * @return array Upgraded list of widgets to version 3 array format when called from the admin.
- */
-function wp_get_sidebars_widgets( $deprecated = true ) {
-       if ( $deprecated !== true )
-               _deprecated_argument( __FUNCTION__, '2.8.1' );
-
-       global $_wp_sidebars_widgets, $sidebars_widgets;
-
-       // If loading from front page, consult $_wp_sidebars_widgets rather than options
-       // to see if wp_convert_widget_settings() has made manipulations in memory.
-       if ( !is_admin() ) {
-               if ( empty($_wp_sidebars_widgets) )
-                       $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
-
-               $sidebars_widgets = $_wp_sidebars_widgets;
-       } else {
-               $sidebars_widgets = get_option('sidebars_widgets', array());
-       }
-
-       if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
-               unset($sidebars_widgets['array_version']);
-
-       /**
-        * Filter the list of sidebars and their widgets.
-        *
-        * @since 2.7.0
-        *
-        * @param array $sidebars_widgets An associative array of sidebars and their widgets.
-        */
-       return apply_filters( 'sidebars_widgets', $sidebars_widgets );
-}
-
-/**
- * Set the sidebar widget option to update sidebars.
- *
- * @since 2.2.0
- * @access private
- *
- * @param array $sidebars_widgets Sidebar widgets and their settings.
- */
-function wp_set_sidebars_widgets( $sidebars_widgets ) {
-       if ( !isset( $sidebars_widgets['array_version'] ) )
-               $sidebars_widgets['array_version'] = 3;
-       update_option( 'sidebars_widgets', $sidebars_widgets );
-}
-
-/**
- * Retrieve default registered sidebars list.
- *
- * @since 2.2.0
- * @access private
- *
- * @global array $wp_registered_sidebars
- *
- * @return array
- */
-function wp_get_widget_defaults() {
-       global $wp_registered_sidebars;
-
-       $defaults = array();
-
-       foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
-               $defaults[$index] = array();
-
-       return $defaults;
-}
-
-/**
- * Convert the widget settings from single to multi-widget format.
- *
- * @since 2.8.0
- *
- * @global array $_wp_sidebars_widgets
- *
- * @param string $base_name
- * @param string $option_name
- * @param array  $settings
- * @return array
- */
-function wp_convert_widget_settings($base_name, $option_name, $settings) {
-       // This test may need expanding.
-       $single = $changed = false;
-       if ( empty($settings) ) {
-               $single = true;
-       } else {
-               foreach ( array_keys($settings) as $number ) {
-                       if ( 'number' == $number )
-                               continue;
-                       if ( !is_numeric($number) ) {
-                               $single = true;
-                               break;
-                       }
-               }
-       }
-
-       if ( $single ) {
-               $settings = array( 2 => $settings );
-
-               // If loading from the front page, update sidebar in memory but don't save to options
-               if ( is_admin() ) {
-                       $sidebars_widgets = get_option('sidebars_widgets');
-               } else {
-                       if ( empty($GLOBALS['_wp_sidebars_widgets']) )
-                               $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
-                       $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
-               }
-
-               foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
-                       if ( is_array($sidebar) ) {
-                               foreach ( $sidebar as $i => $name ) {
-                                       if ( $base_name == $name ) {
-                                               $sidebars_widgets[$index][$i] = "$name-2";
-                                               $changed = true;
-                                               break 2;
-                                       }
-                               }
-                       }
-               }
-
-               if ( is_admin() && $changed )
-                       update_option('sidebars_widgets', $sidebars_widgets);
-       }
-
-       $settings['_multiwidget'] = 1;
-       if ( is_admin() )
-               update_option( $option_name, $settings );
-
-       return $settings;
-}
-
-/**
- * Output an arbitrary widget as a template tag.
- *
- * @since 2.8.0
- *
- * @global WP_Widget_Factory $wp_widget_factory
- *
- * @param string $widget   The widget's PHP class name (see class-wp-widget.php).
- * @param array  $instance Optional. The widget's instance settings. Default empty array.
- * @param array  $args {
- *     Optional. Array of arguments to configure the display of the widget.
- *
- *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
- *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
- *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
- *                                 Default `</div>`.
- *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
- *                                 Default `<h2 class="widgettitle">`.
- *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
- *                                 Default `</h2>`.
- * }
- */
-function the_widget( $widget, $instance = array(), $args = array() ) {
-       global $wp_widget_factory;
-
-       $widget_obj = $wp_widget_factory->widgets[$widget];
-       if ( ! ( $widget_obj instanceof WP_Widget ) ) {
-               return;
-       }
-
-       $default_args = array(
-               'before_widget' => '<div class="widget %s">',
-               'after_widget'  => "</div>",
-               'before_title'  => '<h2 class="widgettitle">',
-               'after_title'   => '</h2>',
-       );
-       $args = wp_parse_args( $args, $default_args );
-       $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
-
-       $instance = wp_parse_args($instance);
-
-       /**
-        * Fires before rendering the requested widget.
-        *
-        * @since 3.0.0
-        *
-        * @param string $widget   The widget's class name.
-        * @param array  $instance The current widget instance's settings.
-        * @param array  $args     An array of the widget's sidebar arguments.
-        */
-       do_action( 'the_widget', $widget, $instance, $args );
-
-       $widget_obj->_set(-1);
-       $widget_obj->widget($args, $instance);
-}
-
-/**
- * Private
- *
- * @return string
- */
-function _get_widget_id_base($id) {
-       return preg_replace( '/-[0-9]+$/', '', $id );
-}
-
-/**
- * Handle sidebars config after theme change
- *
- * @access private
- * @since 3.3.0
- *
- * @global array $sidebars_widgets
- */
-function _wp_sidebars_changed() {
-       global $sidebars_widgets;
-
-       if ( ! is_array( $sidebars_widgets ) )
-               $sidebars_widgets = wp_get_sidebars_widgets();
-
-       retrieve_widgets(true);
-}
-
-/**
- * Look for "lost" widgets, this has to run at least on each theme change.
- *
- * @since 2.8.0
- *
- * @global array $wp_registered_sidebars
- * @global array $sidebars_widgets
- * @global array $wp_registered_widgets
- *
- * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
- *                                   of 'customize' defers updates for the Customizer.
- * @return array|void
- */
-function retrieve_widgets( $theme_changed = false ) {
-       global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
-
-       $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
-       $orphaned = 0;
-
-       $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
-       if ( is_array( $old_sidebars_widgets ) ) {
-               // time() that sidebars were stored is in $old_sidebars_widgets['time']
-               $_sidebars_widgets = $old_sidebars_widgets['data'];
-
-               if ( 'customize' !== $theme_changed ) {
-                       remove_theme_mod( 'sidebars_widgets' );
-               }
-
-               foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
-                       if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
-                               continue;
-                       }
-
-                       if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
-                               $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
-                               unset( $_sidebars_widgets[$sidebar] );
-                       }
-               }
-       } else {
-               if ( empty( $sidebars_widgets ) )
-                       return;
-
-               unset( $sidebars_widgets['array_version'] );
-
-               $old = array_keys($sidebars_widgets);
-               sort($old);
-               sort($registered_sidebar_keys);
-
-               if ( $old == $registered_sidebar_keys )
-                       return;
-
-               $_sidebars_widgets = array(
-                       'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
-               );
-
-               unset( $sidebars_widgets['wp_inactive_widgets'] );
-
-               foreach ( $wp_registered_sidebars as $id => $settings ) {
-                       if ( $theme_changed ) {
-                               $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
-                       } else {
-                               // no theme change, grab only sidebars that are currently registered
-                               if ( isset( $sidebars_widgets[$id] ) ) {
-                                       $_sidebars_widgets[$id] = $sidebars_widgets[$id];
-                                       unset( $sidebars_widgets[$id] );
-                               }
-                       }
-               }
-
-               foreach ( $sidebars_widgets as $val ) {
-                       if ( is_array($val) && ! empty( $val ) )
-                               $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
-               }
-       }
-
-       // discard invalid, theme-specific widgets from sidebars
-       $shown_widgets = array();
-
-       foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
-               if ( !is_array($widgets) )
-                       continue;
-
-               $_widgets = array();
-               foreach ( $widgets as $widget ) {
-                       if ( isset($wp_registered_widgets[$widget]) )
-                               $_widgets[] = $widget;
-               }
-
-               $_sidebars_widgets[$sidebar] = $_widgets;
-               $shown_widgets = array_merge($shown_widgets, $_widgets);
-       }
-
-       $sidebars_widgets = $_sidebars_widgets;
-       unset($_sidebars_widgets, $_widgets);
-
-       // find hidden/lost multi-widget instances
-       $lost_widgets = array();
-       foreach ( $wp_registered_widgets as $key => $val ) {
-               if ( in_array($key, $shown_widgets, true) )
-                       continue;
-
-               $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
-
-               if ( 2 > (int) $number )
-                       continue;
-
-               $lost_widgets[] = $key;
-       }
-
-       $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
-       if ( 'customize' !== $theme_changed ) {
-               wp_set_sidebars_widgets( $sidebars_widgets );
-       }
-
-       return $sidebars_widgets;
-}
-
-/**
- * Display the RSS entries in a list.
- *
- * @since 2.5.0
- *
- * @param string|array|object $rss RSS url.
- * @param array $args Widget arguments.
- */
-function wp_widget_rss_output( $rss, $args = array() ) {
-       if ( is_string( $rss ) ) {
-               $rss = fetch_feed($rss);
-       } elseif ( is_array($rss) && isset($rss['url']) ) {
-               $args = $rss;
-               $rss = fetch_feed($rss['url']);
-       } elseif ( !is_object($rss) ) {
-               return;
-       }
-
-       if ( is_wp_error($rss) ) {
-               if ( is_admin() || current_user_can('manage_options') )
-                       echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
-               return;
-       }
-
-       $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'items' => 0 );
-       $args = wp_parse_args( $args, $default_args );
-
-       $items = (int) $args['items'];
-       if ( $items < 1 || 20 < $items )
-               $items = 10;
-       $show_summary  = (int) $args['show_summary'];
-       $show_author   = (int) $args['show_author'];
-       $show_date     = (int) $args['show_date'];
-
-       if ( !$rss->get_item_quantity() ) {
-               echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
-               $rss->__destruct();
-               unset($rss);
-               return;
-       }
-
-       echo '<ul>';
-       foreach ( $rss->get_items( 0, $items ) as $item ) {
-               $link = $item->get_link();
-               while ( stristr( $link, 'http' ) != $link ) {
-                       $link = substr( $link, 1 );
-               }
-               $link = esc_url( strip_tags( $link ) );
-
-               $title = esc_html( trim( strip_tags( $item->get_title() ) ) );
-               if ( empty( $title ) ) {
-                       $title = __( 'Untitled' );
-               }
-
-               $desc = @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
-               $desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
-
-               $summary = '';
-               if ( $show_summary ) {
-                       $summary = $desc;
-
-                       // Change existing [...] to [&hellip;].
-                       if ( '[...]' == substr( $summary, -5 ) ) {
-                               $summary = substr( $summary, 0, -5 ) . '[&hellip;]';
-                       }
-
-                       $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
-               }
-
-               $date = '';
-               if ( $show_date ) {
-                       $date = $item->get_date( 'U' );
-
-                       if ( $date ) {
-                               $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
-                       }
-               }
-
-               $author = '';
-               if ( $show_author ) {
-                       $author = $item->get_author();
-                       if ( is_object($author) ) {
-                               $author = $author->get_name();
-                               $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
-                       }
-               }
-
-               if ( $link == '' ) {
-                       echo "<li>$title{$date}{$summary}{$author}</li>";
-               } elseif ( $show_summary ) {
-                       echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
-               } else {
-                       echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
-               }
-       }
-       echo '</ul>';
-       $rss->__destruct();
-       unset($rss);
-}
-
-/**
- * Display RSS widget options form.
- *
- * The options for what fields are displayed for the RSS form are all booleans
- * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
- * 'show_date'.
- *
- * @since 2.5.0
- *
- * @param array|string $args Values for input fields.
- * @param array $inputs Override default display options.
- */
-function wp_widget_rss_form( $args, $inputs = null ) {
-       $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
-       $inputs = wp_parse_args( $inputs, $default_inputs );
-
-       $args['title'] = isset( $args['title'] ) ? $args['title'] : '';
-       $args['url'] = isset( $args['url'] ) ? $args['url'] : '';
-       $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
-
-       if ( $args['items'] < 1 || 20 < $args['items'] ) {
-               $args['items'] = 10;
-       }
-
-       $args['show_summary']   = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
-       $args['show_author']    = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
-       $args['show_date']      = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
-
-       if ( ! empty( $args['error'] ) ) {
-               echo '<p class="widget-error"><strong>' . sprintf( __( 'RSS Error: %s' ), $args['error'] ) . '</strong></p>';
-       }
-
-       $esc_number = esc_attr( $args['number'] );
-       if ( $inputs['url'] ) :
-?>
-       <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
-       <input class="widefat" id="rss-url-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][url]" type="text" value="<?php echo esc_url( $args['url'] ); ?>" /></p>
-<?php endif; if ( $inputs['title'] ) : ?>
-       <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
-       <input class="widefat" id="rss-title-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][title]" type="text" value="<?php echo esc_attr( $args['title'] ); ?>" /></p>
-<?php endif; if ( $inputs['items'] ) : ?>
-       <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
-       <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
-       <?php
-       for ( $i = 1; $i <= 20; ++$i ) {
-               echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
-       }
-       ?>
-       </select></p>
-<?php endif; if ( $inputs['show_summary'] ) : ?>
-       <p><input id="rss-show-summary-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_summary]" type="checkbox" value="1" <?php checked( $args['show_summary'] ); ?> />
-       <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label></p>
-<?php endif; if ( $inputs['show_author'] ) : ?>
-       <p><input id="rss-show-author-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_author]" type="checkbox" value="1" <?php checked( $args['show_author'] ); ?> />
-       <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label></p>
-<?php endif; if ( $inputs['show_date'] ) : ?>
-       <p><input id="rss-show-date-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_date]" type="checkbox" value="1" <?php checked( $args['show_date'] ); ?>/>
-       <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label></p>
-<?php
-       endif;
-       foreach ( array_keys($default_inputs) as $input ) :
-               if ( 'hidden' === $inputs[$input] ) :
-                       $id = str_replace( '_', '-', $input );
-?>
-       <input type="hidden" id="rss-<?php echo esc_attr( $id ); ?>-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][<?php echo esc_attr( $input ); ?>]" value="<?php echo esc_attr( $args[ $input ] ); ?>" />
-<?php
-               endif;
-       endforeach;
-}
-
-/**
- * Process RSS feed widget data and optionally retrieve feed items.
- *
- * The feed widget can not have more than 20 items or it will reset back to the
- * default, which is 10.
- *
- * The resulting array has the feed title, feed url, feed link (from channel),
- * feed items, error (if any), and whether to show summary, author, and date.
- * All respectively in the order of the array elements.
- *
- * @since 2.5.0
- *
- * @param array $widget_rss RSS widget feed data. Expects unescaped data.
- * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
- * @return array
- */
-function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
-       $items = (int) $widget_rss['items'];
-       if ( $items < 1 || 20 < $items )
-               $items = 10;
-       $url           = esc_url_raw( strip_tags( $widget_rss['url'] ) );
-       $title         = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
-       $show_summary  = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
-       $show_author   = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] :0;
-       $show_date     = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
-
-       if ( $check_feed ) {
-               $rss = fetch_feed($url);
-               $error = false;
-               $link = '';
-               if ( is_wp_error($rss) ) {
-                       $error = $rss->get_error_message();
-               } else {
-                       $link = esc_url(strip_tags($rss->get_permalink()));
-                       while ( stristr($link, 'http') != $link )
-                               $link = substr($link, 1);
-
-                       $rss->__destruct();
-                       unset($rss);
-               }
-       }
-
-       return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
-}
-
-/**
- * Register all of the default WordPress widgets on startup.
- *
- * Calls 'widgets_init' action after all of the WordPress widgets have been
- * registered.
- *
- * @since 2.2.0
- */
-function wp_widgets_init() {
-       if ( !is_blog_installed() )
-               return;
-
-       register_widget('WP_Widget_Pages');
-
-       register_widget('WP_Widget_Calendar');
-
-       register_widget('WP_Widget_Archives');
-
-       if ( get_option( 'link_manager_enabled' ) )
-               register_widget('WP_Widget_Links');
-
-       register_widget('WP_Widget_Meta');
-
-       register_widget('WP_Widget_Search');
-
-       register_widget('WP_Widget_Text');
-
-       register_widget('WP_Widget_Categories');
-
-       register_widget('WP_Widget_Recent_Posts');
-
-       register_widget('WP_Widget_Recent_Comments');
-
-       register_widget('WP_Widget_RSS');
-
-       register_widget('WP_Widget_Tag_Cloud');
-
-       register_widget('WP_Nav_Menu_Widget');
-
-       /**
-        * Fires after all default WordPress widgets have been registered.
-        *
-        * @since 2.2.0
-        */
-       do_action( 'widgets_init' );
-}
</del></span></pre></div>
<a id="trunksrcwpincludeswidgetsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/src/wp-includes/widgets.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/widgets.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-includes/widgets.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,100 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Core Widgets API
- *
- * This API is used for creating dynamic sidebar without hardcoding functionality into
- * themes
- *
- * Includes both internal WordPress routines and theme-use routines.
- *
- * This functionality was found in a plugin before the WordPress 2.2 release, which
- * included it in the core from that point on.
- *
- * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
- * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
- *
- * @package WordPress
- * @subpackage Widgets
- * @since 2.2.0
- */
-
-//
-// Global Variables
-//
-
-/** @ignore */
-global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
-
-/**
- * Stores the sidebars, since many themes can have more than one.
- *
- * @global array $wp_registered_sidebars
- * @since 2.2.0
- */
-$wp_registered_sidebars = array();
-
-/**
- * Stores the registered widgets.
- *
- * @global array $wp_registered_widgets
- * @since 2.2.0
- */
-$wp_registered_widgets = array();
-
-/**
- * Stores the registered widget control (options).
- *
- * @global array $wp_registered_widget_controls
- * @since 2.2.0
- */
-$wp_registered_widget_controls = array();
-/**
- * @global array $wp_registered_widget_updates
- */
-$wp_registered_widget_updates = array();
-
-/**
- * Private
- *
- * @global array $_wp_sidebars_widgets
- */
-$_wp_sidebars_widgets = array();
-
-/**
- * Private
- *
- * @global array $_wp_deprecated_widgets_callbacks
- */
-$GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
-       'wp_widget_pages',
-       'wp_widget_pages_control',
-       'wp_widget_calendar',
-       'wp_widget_calendar_control',
-       'wp_widget_archives',
-       'wp_widget_archives_control',
-       'wp_widget_links',
-       'wp_widget_meta',
-       'wp_widget_meta_control',
-       'wp_widget_search',
-       'wp_widget_recent_entries',
-       'wp_widget_recent_entries_control',
-       'wp_widget_tag_cloud',
-       'wp_widget_tag_cloud_control',
-       'wp_widget_categories',
-       'wp_widget_categories_control',
-       'wp_widget_text',
-       'wp_widget_text_control',
-       'wp_widget_rss',
-       'wp_widget_rss_control',
-       'wp_widget_recent_comments',
-       'wp_widget_recent_comments_control'
-);
-
-/** WP_Widget class */
-require_once( ABSPATH . WPINC . '/class-wp-widget.php' );
-
-/** WP_Widget_Factory class */
-require_once( ABSPATH . WPINC . '/class-wp-widget-factory.php' );
-
-/** Core widgets functionality */
-require_once( ABSPATH . WPINC . '/widget-functions.php' );
</del></span></pre></div>
<a id="trunksrcwpincludeswidgetsphpfromrev35712trunksrcwpincludeswidgetfunctionsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/src/wp-includes/widgets.php (from rev 35712, trunk/src/wp-includes/widget-functions.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/widgets.php                         (rev 0)
+++ trunk/src/wp-includes/widgets.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,1464 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Core Widgets API
+ *
+ * This API is used for creating dynamic sidebar without hardcoding functionality into
+ * themes
+ *
+ * Includes both internal WordPress routines and theme-use routines.
+ *
+ * This functionality was found in a plugin before the WordPress 2.2 release, which
+ * included it in the core from that point on.
+ *
+ * @link https://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
+ * @link https://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
+ *
+ * @package WordPress
+ * @subpackage Widgets
+ * @since 2.2.0
+ */
+
+//
+// Global Variables
+//
+
+/** @ignore */
+global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
+
+/**
+ * Stores the sidebars, since many themes can have more than one.
+ *
+ * @global array $wp_registered_sidebars
+ * @since 2.2.0
+ */
+$wp_registered_sidebars = array();
+
+/**
+ * Stores the registered widgets.
+ *
+ * @global array $wp_registered_widgets
+ * @since 2.2.0
+ */
+$wp_registered_widgets = array();
+
+/**
+ * Stores the registered widget control (options).
+ *
+ * @global array $wp_registered_widget_controls
+ * @since 2.2.0
+ */
+$wp_registered_widget_controls = array();
+/**
+ * @global array $wp_registered_widget_updates
+ */
+$wp_registered_widget_updates = array();
+
+/**
+ * Private
+ *
+ * @global array $_wp_sidebars_widgets
+ */
+$_wp_sidebars_widgets = array();
+
+/**
+ * Private
+ *
+ * @global array $_wp_deprecated_widgets_callbacks
+ */
+$GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
+       'wp_widget_pages',
+       'wp_widget_pages_control',
+       'wp_widget_calendar',
+       'wp_widget_calendar_control',
+       'wp_widget_archives',
+       'wp_widget_archives_control',
+       'wp_widget_links',
+       'wp_widget_meta',
+       'wp_widget_meta_control',
+       'wp_widget_search',
+       'wp_widget_recent_entries',
+       'wp_widget_recent_entries_control',
+       'wp_widget_tag_cloud',
+       'wp_widget_tag_cloud_control',
+       'wp_widget_categories',
+       'wp_widget_categories_control',
+       'wp_widget_text',
+       'wp_widget_text_control',
+       'wp_widget_rss',
+       'wp_widget_rss_control',
+       'wp_widget_recent_comments',
+       'wp_widget_recent_comments_control'
+);
+
+//
+// Template tags & API functions
+//
+
+/**
+ * Register a widget
+ *
+ * Registers a WP_Widget widget
+ *
+ * @since 2.8.0
+ *
+ * @see WP_Widget
+ *
+ * @global WP_Widget_Factory $wp_widget_factory
+ *
+ * @param string $widget_class The name of a class that extends WP_Widget
+ */
+function register_widget($widget_class) {
+       global $wp_widget_factory;
+
+       $wp_widget_factory->register($widget_class);
+}
+
+/**
+ * Unregister a widget
+ *
+ * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
+ * Run within a function hooked to the widgets_init action.
+ *
+ * @since 2.8.0
+ *
+ * @see WP_Widget
+ *
+ * @global WP_Widget_Factory $wp_widget_factory
+ *
+ * @param string $widget_class The name of a class that extends WP_Widget
+ */
+function unregister_widget($widget_class) {
+       global $wp_widget_factory;
+
+       $wp_widget_factory->unregister($widget_class);
+}
+
+/**
+ * Creates multiple sidebars.
+ *
+ * If you wanted to quickly create multiple sidebars for a theme or internally.
+ * This function will allow you to do so. If you don't pass the 'name' and/or
+ * 'id' in `$args`, then they will be built for you.
+ *
+ * @since 2.2.0
+ *
+ * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
+ *
+ * @global array $wp_registered_sidebars
+ *
+ * @param int          $number Optional. Number of sidebars to create. Default 1.
+ * @param array|string $args {
+ *     Optional. Array or string of arguments for building a sidebar.
+ *
+ *     @type string $id   The base string of the unique identifier for each sidebar. If provided, and multiple
+ *                        sidebars are being defined, the id will have "-2" appended, and so on.
+ *                        Default 'sidebar-' followed by the number the sidebar creation is currently at.
+ *     @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering
+ *                        more than one sidebar, include '%d' in the string as a placeholder for the uniquely
+ *                        assigned number for each sidebar.
+ *                        Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'.
+ * }
+ */
+function register_sidebars( $number = 1, $args = array() ) {
+       global $wp_registered_sidebars;
+       $number = (int) $number;
+
+       if ( is_string($args) )
+               parse_str($args, $args);
+
+       for ( $i = 1; $i <= $number; $i++ ) {
+               $_args = $args;
+
+               if ( $number > 1 )
+                       $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
+               else
+                       $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
+
+               // Custom specified ID's are suffixed if they exist already.
+               // Automatically generated sidebar names need to be suffixed regardless starting at -0
+               if ( isset($args['id']) ) {
+                       $_args['id'] = $args['id'];
+                       $n = 2; // Start at -2 for conflicting custom ID's
+                       while ( is_registered_sidebar( $_args['id'] ) ) {
+                               $_args['id'] = $args['id'] . '-' . $n++;
+                       }
+               } else {
+                       $n = count( $wp_registered_sidebars );
+                       do {
+                               $_args['id'] = 'sidebar-' . ++$n;
+                       } while ( is_registered_sidebar( $_args['id'] ) );
+               }
+               register_sidebar($_args);
+       }
+}
+
+/**
+ * Builds the definition for a single sidebar and returns the ID.
+ *
+ * Accepts either a string or an array and then parses that against a set
+ * of default arguments for the new sidebar. WordPress will automatically
+ * generate a sidebar ID and name based on the current number of registered
+ * sidebars if those arguments are not included.
+ *
+ * When allowing for automatic generation of the name and ID parameters, keep
+ * in mind that the incrementor for your sidebar can change over time depending
+ * on what other plugins and themes are installed.
+ *
+ * If theme support for 'widgets' has not yet been added when this function is
+ * called, it will be automatically enabled through the use of add_theme_support()
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ *
+ * @param array|string $args {
+ *     Optional. Array or string of arguments for the sidebar being registered.
+ *
+ *     @type string $name          The name or title of the sidebar displayed in the Widgets
+ *                                 interface. Default 'Sidebar $instance'.
+ *     @type string $id            The unique identifier by which the sidebar will be called.
+ *                                 Default 'sidebar-$instance'.
+ *     @type string $description   Description of the sidebar, displayed in the Widgets interface.
+ *                                 Default empty string.
+ *     @type string $class         Extra CSS class to assign to the sidebar in the Widgets interface.
+ *                                 Default empty.
+ *     @type string $before_widget HTML content to prepend to each widget's HTML output when
+ *                                 assigned to this sidebar. Default is an opening list item element.
+ *     @type string $after_widget  HTML content to append to each widget's HTML output when
+ *                                 assigned to this sidebar. Default is a closing list item element.
+ *     @type string $before_title  HTML content to prepend to the sidebar title when displayed.
+ *                                 Default is an opening h2 element.
+ *     @type string $after_title   HTML content to append to the sidebar title when displayed.
+ *                                 Default is a closing h2 element.
+ * }
+ * @return string Sidebar ID added to $wp_registered_sidebars global.
+ */
+function register_sidebar($args = array()) {
+       global $wp_registered_sidebars;
+
+       $i = count($wp_registered_sidebars) + 1;
+
+       $id_is_empty = empty( $args['id'] );
+
+       $defaults = array(
+               'name' => sprintf(__('Sidebar %d'), $i ),
+               'id' => "sidebar-$i",
+               'description' => '',
+               'class' => '',
+               'before_widget' => '<li id="%1$s" class="widget %2$s">',
+               'after_widget' => "</li>\n",
+               'before_title' => '<h2 class="widgettitle">',
+               'after_title' => "</h2>\n",
+       );
+
+       $sidebar = wp_parse_args( $args, $defaults );
+
+       if ( $id_is_empty ) {
+               /* translators: 1: the id argument, 2: sidebar name, 3: recommended id value */
+               _doing_it_wrong( __FUNCTION__, sprintf( __( 'No %1$s was set in the arguments array for the "%2$s" sidebar. Defaulting to "%3$s". Manually set the %1$s to "%3$s" to silence this notice and keep existing sidebar content.' ), '<code>id</code>', $sidebar['name'], $sidebar['id'] ), '4.2.0' );
+       }
+
+       $wp_registered_sidebars[$sidebar['id']] = $sidebar;
+
+       add_theme_support('widgets');
+
+       /**
+        * Fires once a sidebar has been registered.
+        *
+        * @since 3.0.0
+        *
+        * @param array $sidebar Parsed arguments for the registered sidebar.
+        */
+       do_action( 'register_sidebar', $sidebar );
+
+       return $sidebar['id'];
+}
+
+/**
+ * Removes a sidebar from the list.
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ *
+ * @param string $name The ID of the sidebar when it was added.
+ */
+function unregister_sidebar( $name ) {
+       global $wp_registered_sidebars;
+
+       unset( $wp_registered_sidebars[ $name ] );
+}
+
+/**
+ * Checks if a sidebar is registered.
+ *
+ * @since 4.4.0
+ *
+ * @global array $wp_registered_sidebars Registered sidebars.
+ *
+ * @param string|int $sidebar_id The ID of the sidebar when it was registered.
+ * @return bool True if the sidebar is registered, false otherwise.
+ */
+function is_registered_sidebar( $sidebar_id ) {
+       global $wp_registered_sidebars;
+
+       return isset( $wp_registered_sidebars[ $sidebar_id ] );
+}
+
+/**
+ * Register an instance of a widget.
+ *
+ * The default widget option is 'classname' that can be overridden.
+ *
+ * The function can also be used to un-register widgets when `$output_callback`
+ * parameter is an empty string.
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_widgets       Uses stored registered widgets.
+ * @global array $wp_register_widget_defaults Retrieves widget defaults.
+ * @global array $wp_registered_widget_updates
+ * @global array $_wp_deprecated_widgets_callbacks
+ *
+ * @param int|string $id              Widget ID.
+ * @param string     $name            Widget display title.
+ * @param callable   $output_callback Run when widget is called.
+ * @param array      $options {
+ *     Optional. An array of supplementary widget options for the instance.
+ *
+ *     @type string $classname   Class name for the widget's HTML container. Default is a shortened
+ *                               version of the output callback name.
+ *     @type string $description Widget description for display in the widget administration
+ *                               panel and/or theme.
+ * }
+ */
+function wp_register_sidebar_widget( $id, $name, $output_callback, $options = array() ) {
+       global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
+
+       $id = strtolower($id);
+
+       if ( empty($output_callback) ) {
+               unset($wp_registered_widgets[$id]);
+               return;
+       }
+
+       $id_base = _get_widget_id_base($id);
+       if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
+               unset( $wp_registered_widget_controls[ $id ] );
+               unset( $wp_registered_widget_updates[ $id_base ] );
+               return;
+       }
+
+       $defaults = array('classname' => $output_callback);
+       $options = wp_parse_args($options, $defaults);
+       $widget = array(
+               'name' => $name,
+               'id' => $id,
+               'callback' => $output_callback,
+               'params' => array_slice(func_get_args(), 4)
+       );
+       $widget = array_merge($widget, $options);
+
+       if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
+
+               /**
+                * Fires once for each registered widget.
+                *
+                * @since 3.0.0
+                *
+                * @param array $widget An array of default widget arguments.
+                */
+               do_action( 'wp_register_sidebar_widget', $widget );
+               $wp_registered_widgets[$id] = $widget;
+       }
+}
+
+/**
+ * Retrieve description for widget.
+ *
+ * When registering widgets, the options can also include 'description' that
+ * describes the widget for display on the widget administration panel or
+ * in the theme.
+ *
+ * @since 2.5.0
+ *
+ * @global array $wp_registered_widgets
+ *
+ * @param int|string $id Widget ID.
+ * @return string|void Widget description, if available.
+ */
+function wp_widget_description( $id ) {
+       if ( !is_scalar($id) )
+               return;
+
+       global $wp_registered_widgets;
+
+       if ( isset($wp_registered_widgets[$id]['description']) )
+               return esc_html( $wp_registered_widgets[$id]['description'] );
+}
+
+/**
+ * Retrieve description for a sidebar.
+ *
+ * When registering sidebars a 'description' parameter can be included that
+ * describes the sidebar for display on the widget administration panel.
+ *
+ * @since 2.9.0
+ *
+ * @global array $wp_registered_sidebars
+ *
+ * @param string $id sidebar ID.
+ * @return string|void Sidebar description, if available.
+ */
+function wp_sidebar_description( $id ) {
+       if ( !is_scalar($id) )
+               return;
+
+       global $wp_registered_sidebars;
+
+       if ( isset($wp_registered_sidebars[$id]['description']) )
+               return esc_html( $wp_registered_sidebars[$id]['description'] );
+}
+
+/**
+ * Remove widget from sidebar.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_sidebar_widget($id) {
+
+       /**
+        * Fires just before a widget is removed from a sidebar.
+        *
+        * @since 3.0.0
+        *
+        * @param int $id The widget ID.
+        */
+       do_action( 'wp_unregister_sidebar_widget', $id );
+
+       wp_register_sidebar_widget($id, '', '');
+       wp_unregister_widget_control($id);
+}
+
+/**
+ * Registers widget control callback for customizing options.
+ *
+ * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
+ * option is never used. The 'width' option is the width of the fully expanded
+ * control form, but try hard to use the default width. The 'id_base' is for
+ * multi-widgets (widgets which allow multiple instances such as the text
+ * widget), an id_base must be provided. The widget id will end up looking like
+ * `{$id_base}-{$unique_number}`.
+ *
+ * @since 2.2.0
+ *
+ * @todo Document `$options` as a hash notation, re: WP_Widget::__construct() cross-reference.
+ * @todo `$params` parameter?
+ *
+ * @global array $wp_registered_widget_controls
+ * @global array $wp_registered_widget_updates
+ * @global array $wp_registered_widgets
+ * @global array $_wp_deprecated_widgets_callbacks
+ *
+ * @param int|string   $id               Sidebar ID.
+ * @param string       $name             Sidebar display name.
+ * @param callable     $control_callback Run when sidebar is displayed.
+ * @param array|string $options          Optional. Widget options. See description above. Default empty array.
+ */
+function wp_register_widget_control( $id, $name, $control_callback, $options = array() ) {
+       global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
+
+       $id = strtolower($id);
+       $id_base = _get_widget_id_base($id);
+
+       if ( empty($control_callback) ) {
+               unset($wp_registered_widget_controls[$id]);
+               unset($wp_registered_widget_updates[$id_base]);
+               return;
+       }
+
+       if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
+               unset( $wp_registered_widgets[ $id ] );
+               return;
+       }
+
+       if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
+               return;
+
+       $defaults = array('width' => 250, 'height' => 200 ); // height is never used
+       $options = wp_parse_args($options, $defaults);
+       $options['width'] = (int) $options['width'];
+       $options['height'] = (int) $options['height'];
+
+       $widget = array(
+               'name' => $name,
+               'id' => $id,
+               'callback' => $control_callback,
+               'params' => array_slice(func_get_args(), 4)
+       );
+       $widget = array_merge($widget, $options);
+
+       $wp_registered_widget_controls[$id] = $widget;
+
+       if ( isset($wp_registered_widget_updates[$id_base]) )
+               return;
+
+       if ( isset($widget['params'][0]['number']) )
+               $widget['params'][0]['number'] = -1;
+
+       unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
+       $wp_registered_widget_updates[$id_base] = $widget;
+}
+
+/**
+ * @global array $wp_registered_widget_updates
+ *
+ * @param string   $id_base
+ * @param callable $update_callback
+ * @param array    $options
+ */
+function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
+       global $wp_registered_widget_updates;
+
+       if ( isset($wp_registered_widget_updates[$id_base]) ) {
+               if ( empty($update_callback) )
+                       unset($wp_registered_widget_updates[$id_base]);
+               return;
+       }
+
+       $widget = array(
+               'callback' => $update_callback,
+               'params' => array_slice(func_get_args(), 3)
+       );
+
+       $widget = array_merge($widget, $options);
+       $wp_registered_widget_updates[$id_base] = $widget;
+}
+
+/**
+ *
+ * @global array $wp_registered_widget_controls
+ *
+ * @param int|string $id
+ * @param string     $name
+ * @param callable   $form_callback
+ * @param array      $options
+ */
+function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
+       global $wp_registered_widget_controls;
+
+       $id = strtolower($id);
+
+       if ( empty($form_callback) ) {
+               unset($wp_registered_widget_controls[$id]);
+               return;
+       }
+
+       if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
+               return;
+
+       $defaults = array('width' => 250, 'height' => 200 );
+       $options = wp_parse_args($options, $defaults);
+       $options['width'] = (int) $options['width'];
+       $options['height'] = (int) $options['height'];
+
+       $widget = array(
+               'name' => $name,
+               'id' => $id,
+               'callback' => $form_callback,
+               'params' => array_slice(func_get_args(), 4)
+       );
+       $widget = array_merge($widget, $options);
+
+       $wp_registered_widget_controls[$id] = $widget;
+}
+
+/**
+ * Remove control callback for widget.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_widget_control($id) {
+       wp_register_widget_control( $id, '', '' );
+}
+
+/**
+ * Display dynamic sidebar.
+ *
+ * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
+ * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
+ * Otherwise, you can pass in a numerical index to display the sidebar at that index.
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_sidebars
+ * @global array $wp_registered_widgets
+ *
+ * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
+ * @return bool True, if widget sidebar was found and called. False if not found or not called.
+ */
+function dynamic_sidebar( $index = 1 ) {
+       global $wp_registered_sidebars, $wp_registered_widgets;
+
+       if ( is_int( $index ) ) {
+               $index = "sidebar-$index";
+       } else {
+               $sanitized_index = sanitize_title( $index );
+               foreach ( (array) $wp_registered_sidebars as $key => $value ) {
+                       if ( sanitize_title( $value['name'] ) == $sanitized_index ) {
+                               $index = $key;
+                               break;
+                       }
+               }
+       }
+
+       $sidebars_widgets = wp_get_sidebars_widgets();
+       if ( empty( $wp_registered_sidebars[ $index ] ) || empty( $sidebars_widgets[ $index ] ) || ! is_array( $sidebars_widgets[ $index ] ) ) {
+               /** This action is documented in wp-includes/widget-functions.php */
+               do_action( 'dynamic_sidebar_before', $index, false );
+               /** This action is documented in wp-includes/widget-functions.php */
+               do_action( 'dynamic_sidebar_after',  $index, false );
+               /** This filter is documented in wp-includes/widget-functions.php */
+               return apply_filters( 'dynamic_sidebar_has_widgets', false, $index );
+       }
+
+       /**
+        * Fires before widgets are rendered in a dynamic sidebar.
+        *
+        * Note: The action also fires for empty sidebars, and on both the front-end
+        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
+        *
+        * @since 3.9.0
+        *
+        * @param int|string $index       Index, name, or ID of the dynamic sidebar.
+        * @param bool       $has_widgets Whether the sidebar is populated with widgets.
+        *                                Default true.
+        */
+       do_action( 'dynamic_sidebar_before', $index, true );
+       $sidebar = $wp_registered_sidebars[$index];
+
+       $did_one = false;
+       foreach ( (array) $sidebars_widgets[$index] as $id ) {
+
+               if ( !isset($wp_registered_widgets[$id]) ) continue;
+
+               $params = array_merge(
+                       array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
+                       (array) $wp_registered_widgets[$id]['params']
+               );
+
+               // Substitute HTML id and class attributes into before_widget
+               $classname_ = '';
+               foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
+                       if ( is_string($cn) )
+                               $classname_ .= '_' . $cn;
+                       elseif ( is_object($cn) )
+                               $classname_ .= '_' . get_class($cn);
+               }
+               $classname_ = ltrim($classname_, '_');
+               $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
+
+               /**
+                * Filter the parameters passed to a widget's display callback.
+                *
+                * Note: The filter is evaluated on both the front-end and back-end,
+                * including for the Inactive Widgets sidebar on the Widgets screen.
+                *
+                * @since 2.5.0
+                *
+                * @see register_sidebar()
+                *
+                * @param array $params {
+                *     @type array $args  {
+                *         An array of widget display arguments.
+                *
+                *         @type string $name          Name of the sidebar the widget is assigned to.
+                *         @type string $id            ID of the sidebar the widget is assigned to.
+                *         @type string $description   The sidebar description.
+                *         @type string $class         CSS class applied to the sidebar container.
+                *         @type string $before_widget HTML markup to prepend to each widget in the sidebar.
+                *         @type string $after_widget  HTML markup to append to each widget in the sidebar.
+                *         @type string $before_title  HTML markup to prepend to the widget title when displayed.
+                *         @type string $after_title   HTML markup to append to the widget title when displayed.
+                *         @type string $widget_id     ID of the widget.
+                *         @type string $widget_name   Name of the widget.
+                *     }
+                *     @type array $widget_args {
+                *         An array of multi-widget arguments.
+                *
+                *         @type int $number Number increment used for multiples of the same widget.
+                *     }
+                * }
+                */
+               $params = apply_filters( 'dynamic_sidebar_params', $params );
+
+               $callback = $wp_registered_widgets[$id]['callback'];
+
+               /**
+                * Fires before a widget's display callback is called.
+                *
+                * Note: The action fires on both the front-end and back-end, including
+                * for widgets in the Inactive Widgets sidebar on the Widgets screen.
+                *
+                * The action is not fired for empty sidebars.
+                *
+                * @since 3.0.0
+                *
+                * @param array $widget_id {
+                *     An associative array of widget arguments.
+                *
+                *     @type string $name                Name of the widget.
+                *     @type string $id                  Widget ID.
+                *     @type array|callable $callback    When the hook is fired on the front-end, $callback is an array
+                *                                       containing the widget object. Fired on the back-end, $callback
+                *                                       is 'wp_widget_control', see $_callback.
+                *     @type array          $params      An associative array of multi-widget arguments.
+                *     @type string         $classname   CSS class applied to the widget container.
+                *     @type string         $description The widget description.
+                *     @type array          $_callback   When the hook is fired on the back-end, $_callback is populated
+                *                                       with an array containing the widget object, see $callback.
+                * }
+                */
+               do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] );
+
+               if ( is_callable($callback) ) {
+                       call_user_func_array($callback, $params);
+                       $did_one = true;
+               }
+       }
+
+       /**
+        * Fires after widgets are rendered in a dynamic sidebar.
+        *
+        * Note: The action also fires for empty sidebars, and on both the front-end
+        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
+        *
+        * @since 3.9.0
+        *
+        * @param int|string $index       Index, name, or ID of the dynamic sidebar.
+        * @param bool       $has_widgets Whether the sidebar is populated with widgets.
+        *                                Default true.
+        */
+       do_action( 'dynamic_sidebar_after', $index, true );
+
+       /**
+        * Filter whether a sidebar has widgets.
+        *
+        * Note: The filter is also evaluated for empty sidebars, and on both the front-end
+        * and back-end, including the Inactive Widgets sidebar on the Widgets screen.
+        *
+        * @since 3.9.0
+        *
+        * @param bool       $did_one Whether at least one widget was rendered in the sidebar.
+        *                            Default false.
+        * @param int|string $index   Index, name, or ID of the dynamic sidebar.
+        */
+       return apply_filters( 'dynamic_sidebar_has_widgets', $did_one, $index );
+}
+
+/**
+ * Whether widget is displayed on the front-end.
+ *
+ * Either $callback or $id_base can be used
+ * $id_base is the first argument when extending WP_Widget class
+ * Without the optional $widget_id parameter, returns the ID of the first sidebar
+ * in which the first instance of the widget with the given callback or $id_base is found.
+ * With the $widget_id parameter, returns the ID of the sidebar where
+ * the widget with that callback/$id_base AND that ID is found.
+ *
+ * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
+ * this function has to run after widgets have initialized, at action 'init' or later.
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_widgets
+ *
+ * @param string $callback      Optional, Widget callback to check.
+ * @param int    $widget_id     Optional, but needed for checking. Widget ID.
+ * @param string $id_base       Optional, the base ID of a widget created by extending WP_Widget.
+ * @param bool   $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
+ * @return string|false False if widget is not active or id of sidebar in which the widget is active.
+ */
+function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
+       global $wp_registered_widgets;
+
+       $sidebars_widgets = wp_get_sidebars_widgets();
+
+       if ( is_array($sidebars_widgets) ) {
+               foreach ( $sidebars_widgets as $sidebar => $widgets ) {
+                       if ( $skip_inactive && ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) ) {
+                               continue;
+                       }
+
+                       if ( is_array($widgets) ) {
+                               foreach ( $widgets as $widget ) {
+                                       if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
+                                               if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
+                                                       return $sidebar;
+                                       }
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+/**
+ * Whether the dynamic sidebar is enabled and used by theme.
+ *
+ * @since 2.2.0
+ *
+ * @global array $wp_registered_widgets
+ * @global array $wp_registered_sidebars
+ *
+ * @return bool True, if using widgets. False, if not using widgets.
+ */
+function is_dynamic_sidebar() {
+       global $wp_registered_widgets, $wp_registered_sidebars;
+       $sidebars_widgets = get_option('sidebars_widgets');
+       foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
+               if ( count($sidebars_widgets[$index]) ) {
+                       foreach ( (array) $sidebars_widgets[$index] as $widget )
+                               if ( array_key_exists($widget, $wp_registered_widgets) )
+                                       return true;
+               }
+       }
+       return false;
+}
+
+/**
+ * Whether a sidebar is in use.
+ *
+ * @since 2.8.0
+ *
+ * @param string|int $index Sidebar name, id or number to check.
+ * @return bool true if the sidebar is in use, false otherwise.
+ */
+function is_active_sidebar( $index ) {
+       $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
+       $sidebars_widgets = wp_get_sidebars_widgets();
+       $is_active_sidebar = ! empty( $sidebars_widgets[$index] );
+
+       /**
+        * Filter whether a dynamic sidebar is considered "active".
+        *
+        * @since 3.9.0
+        *
+        * @param bool       $is_active_sidebar Whether or not the sidebar should be considered "active".
+        *                                      In other words, whether the sidebar contains any widgets.
+        * @param int|string $index             Index, name, or ID of the dynamic sidebar.
+        */
+       return apply_filters( 'is_active_sidebar', $is_active_sidebar, $index );
+}
+
+//
+// Internal Functions
+//
+
+/**
+ * Retrieve full list of sidebars and their widget instance IDs.
+ *
+ * Will upgrade sidebar widget list, if needed. Will also save updated list, if
+ * needed.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @global array $_wp_sidebars_widgets
+ * @global array $sidebars_widgets
+ *
+ * @param bool $deprecated Not used (argument deprecated).
+ * @return array Upgraded list of widgets to version 3 array format when called from the admin.
+ */
+function wp_get_sidebars_widgets( $deprecated = true ) {
+       if ( $deprecated !== true )
+               _deprecated_argument( __FUNCTION__, '2.8.1' );
+
+       global $_wp_sidebars_widgets, $sidebars_widgets;
+
+       // If loading from front page, consult $_wp_sidebars_widgets rather than options
+       // to see if wp_convert_widget_settings() has made manipulations in memory.
+       if ( !is_admin() ) {
+               if ( empty($_wp_sidebars_widgets) )
+                       $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
+
+               $sidebars_widgets = $_wp_sidebars_widgets;
+       } else {
+               $sidebars_widgets = get_option('sidebars_widgets', array());
+       }
+
+       if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
+               unset($sidebars_widgets['array_version']);
+
+       /**
+        * Filter the list of sidebars and their widgets.
+        *
+        * @since 2.7.0
+        *
+        * @param array $sidebars_widgets An associative array of sidebars and their widgets.
+        */
+       return apply_filters( 'sidebars_widgets', $sidebars_widgets );
+}
+
+/**
+ * Set the sidebar widget option to update sidebars.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @param array $sidebars_widgets Sidebar widgets and their settings.
+ */
+function wp_set_sidebars_widgets( $sidebars_widgets ) {
+       if ( !isset( $sidebars_widgets['array_version'] ) )
+               $sidebars_widgets['array_version'] = 3;
+       update_option( 'sidebars_widgets', $sidebars_widgets );
+}
+
+/**
+ * Retrieve default registered sidebars list.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @global array $wp_registered_sidebars
+ *
+ * @return array
+ */
+function wp_get_widget_defaults() {
+       global $wp_registered_sidebars;
+
+       $defaults = array();
+
+       foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
+               $defaults[$index] = array();
+
+       return $defaults;
+}
+
+/**
+ * Convert the widget settings from single to multi-widget format.
+ *
+ * @since 2.8.0
+ *
+ * @global array $_wp_sidebars_widgets
+ *
+ * @param string $base_name
+ * @param string $option_name
+ * @param array  $settings
+ * @return array
+ */
+function wp_convert_widget_settings($base_name, $option_name, $settings) {
+       // This test may need expanding.
+       $single = $changed = false;
+       if ( empty($settings) ) {
+               $single = true;
+       } else {
+               foreach ( array_keys($settings) as $number ) {
+                       if ( 'number' == $number )
+                               continue;
+                       if ( !is_numeric($number) ) {
+                               $single = true;
+                               break;
+                       }
+               }
+       }
+
+       if ( $single ) {
+               $settings = array( 2 => $settings );
+
+               // If loading from the front page, update sidebar in memory but don't save to options
+               if ( is_admin() ) {
+                       $sidebars_widgets = get_option('sidebars_widgets');
+               } else {
+                       if ( empty($GLOBALS['_wp_sidebars_widgets']) )
+                               $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
+                       $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
+               }
+
+               foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
+                       if ( is_array($sidebar) ) {
+                               foreach ( $sidebar as $i => $name ) {
+                                       if ( $base_name == $name ) {
+                                               $sidebars_widgets[$index][$i] = "$name-2";
+                                               $changed = true;
+                                               break 2;
+                                       }
+                               }
+                       }
+               }
+
+               if ( is_admin() && $changed )
+                       update_option('sidebars_widgets', $sidebars_widgets);
+       }
+
+       $settings['_multiwidget'] = 1;
+       if ( is_admin() )
+               update_option( $option_name, $settings );
+
+       return $settings;
+}
+
+/**
+ * Output an arbitrary widget as a template tag.
+ *
+ * @since 2.8.0
+ *
+ * @global WP_Widget_Factory $wp_widget_factory
+ *
+ * @param string $widget   The widget's PHP class name (see class-wp-widget.php).
+ * @param array  $instance Optional. The widget's instance settings. Default empty array.
+ * @param array  $args {
+ *     Optional. Array of arguments to configure the display of the widget.
+ *
+ *     @type string $before_widget HTML content that will be prepended to the widget's HTML output.
+ *                                 Default `<div class="widget %s">`, where `%s` is the widget's class name.
+ *     @type string $after_widget  HTML content that will be appended to the widget's HTML output.
+ *                                 Default `</div>`.
+ *     @type string $before_title  HTML content that will be prepended to the widget's title when displayed.
+ *                                 Default `<h2 class="widgettitle">`.
+ *     @type string $after_title   HTML content that will be appended to the widget's title when displayed.
+ *                                 Default `</h2>`.
+ * }
+ */
+function the_widget( $widget, $instance = array(), $args = array() ) {
+       global $wp_widget_factory;
+
+       $widget_obj = $wp_widget_factory->widgets[$widget];
+       if ( ! ( $widget_obj instanceof WP_Widget ) ) {
+               return;
+       }
+
+       $default_args = array(
+               'before_widget' => '<div class="widget %s">',
+               'after_widget'  => "</div>",
+               'before_title'  => '<h2 class="widgettitle">',
+               'after_title'   => '</h2>',
+       );
+       $args = wp_parse_args( $args, $default_args );
+       $args['before_widget'] = sprintf( $args['before_widget'], $widget_obj->widget_options['classname'] );
+
+       $instance = wp_parse_args($instance);
+
+       /**
+        * Fires before rendering the requested widget.
+        *
+        * @since 3.0.0
+        *
+        * @param string $widget   The widget's class name.
+        * @param array  $instance The current widget instance's settings.
+        * @param array  $args     An array of the widget's sidebar arguments.
+        */
+       do_action( 'the_widget', $widget, $instance, $args );
+
+       $widget_obj->_set(-1);
+       $widget_obj->widget($args, $instance);
+}
+
+/**
+ * Private
+ *
+ * @return string
+ */
+function _get_widget_id_base($id) {
+       return preg_replace( '/-[0-9]+$/', '', $id );
+}
+
+/**
+ * Handle sidebars config after theme change
+ *
+ * @access private
+ * @since 3.3.0
+ *
+ * @global array $sidebars_widgets
+ */
+function _wp_sidebars_changed() {
+       global $sidebars_widgets;
+
+       if ( ! is_array( $sidebars_widgets ) )
+               $sidebars_widgets = wp_get_sidebars_widgets();
+
+       retrieve_widgets(true);
+}
+
+/**
+ * Look for "lost" widgets, this has to run at least on each theme change.
+ *
+ * @since 2.8.0
+ *
+ * @global array $wp_registered_sidebars
+ * @global array $sidebars_widgets
+ * @global array $wp_registered_widgets
+ *
+ * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value
+ *                                   of 'customize' defers updates for the Customizer.
+ * @return array|void
+ */
+function retrieve_widgets( $theme_changed = false ) {
+       global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
+
+       $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
+       $orphaned = 0;
+
+       $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
+       if ( is_array( $old_sidebars_widgets ) ) {
+               // time() that sidebars were stored is in $old_sidebars_widgets['time']
+               $_sidebars_widgets = $old_sidebars_widgets['data'];
+
+               if ( 'customize' !== $theme_changed ) {
+                       remove_theme_mod( 'sidebars_widgets' );
+               }
+
+               foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
+                       if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {
+                               continue;
+                       }
+
+                       if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
+                               $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
+                               unset( $_sidebars_widgets[$sidebar] );
+                       }
+               }
+       } else {
+               if ( empty( $sidebars_widgets ) )
+                       return;
+
+               unset( $sidebars_widgets['array_version'] );
+
+               $old = array_keys($sidebars_widgets);
+               sort($old);
+               sort($registered_sidebar_keys);
+
+               if ( $old == $registered_sidebar_keys )
+                       return;
+
+               $_sidebars_widgets = array(
+                       'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
+               );
+
+               unset( $sidebars_widgets['wp_inactive_widgets'] );
+
+               foreach ( $wp_registered_sidebars as $id => $settings ) {
+                       if ( $theme_changed ) {
+                               $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
+                       } else {
+                               // no theme change, grab only sidebars that are currently registered
+                               if ( isset( $sidebars_widgets[$id] ) ) {
+                                       $_sidebars_widgets[$id] = $sidebars_widgets[$id];
+                                       unset( $sidebars_widgets[$id] );
+                               }
+                       }
+               }
+
+               foreach ( $sidebars_widgets as $val ) {
+                       if ( is_array($val) && ! empty( $val ) )
+                               $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
+               }
+       }
+
+       // discard invalid, theme-specific widgets from sidebars
+       $shown_widgets = array();
+
+       foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
+               if ( !is_array($widgets) )
+                       continue;
+
+               $_widgets = array();
+               foreach ( $widgets as $widget ) {
+                       if ( isset($wp_registered_widgets[$widget]) )
+                               $_widgets[] = $widget;
+               }
+
+               $_sidebars_widgets[$sidebar] = $_widgets;
+               $shown_widgets = array_merge($shown_widgets, $_widgets);
+       }
+
+       $sidebars_widgets = $_sidebars_widgets;
+       unset($_sidebars_widgets, $_widgets);
+
+       // find hidden/lost multi-widget instances
+       $lost_widgets = array();
+       foreach ( $wp_registered_widgets as $key => $val ) {
+               if ( in_array($key, $shown_widgets, true) )
+                       continue;
+
+               $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
+
+               if ( 2 > (int) $number )
+                       continue;
+
+               $lost_widgets[] = $key;
+       }
+
+       $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
+       if ( 'customize' !== $theme_changed ) {
+               wp_set_sidebars_widgets( $sidebars_widgets );
+       }
+
+       return $sidebars_widgets;
+}
+
+/**
+ * Display the RSS entries in a list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array|object $rss RSS url.
+ * @param array $args Widget arguments.
+ */
+function wp_widget_rss_output( $rss, $args = array() ) {
+       if ( is_string( $rss ) ) {
+               $rss = fetch_feed($rss);
+       } elseif ( is_array($rss) && isset($rss['url']) ) {
+               $args = $rss;
+               $rss = fetch_feed($rss['url']);
+       } elseif ( !is_object($rss) ) {
+               return;
+       }
+
+       if ( is_wp_error($rss) ) {
+               if ( is_admin() || current_user_can('manage_options') )
+                       echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
+               return;
+       }
+
+       $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0, 'items' => 0 );
+       $args = wp_parse_args( $args, $default_args );
+
+       $items = (int) $args['items'];
+       if ( $items < 1 || 20 < $items )
+               $items = 10;
+       $show_summary  = (int) $args['show_summary'];
+       $show_author   = (int) $args['show_author'];
+       $show_date     = (int) $args['show_date'];
+
+       if ( !$rss->get_item_quantity() ) {
+               echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
+               $rss->__destruct();
+               unset($rss);
+               return;
+       }
+
+       echo '<ul>';
+       foreach ( $rss->get_items( 0, $items ) as $item ) {
+               $link = $item->get_link();
+               while ( stristr( $link, 'http' ) != $link ) {
+                       $link = substr( $link, 1 );
+               }
+               $link = esc_url( strip_tags( $link ) );
+
+               $title = esc_html( trim( strip_tags( $item->get_title() ) ) );
+               if ( empty( $title ) ) {
+                       $title = __( 'Untitled' );
+               }
+
+               $desc = @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option( 'blog_charset' ) );
+               $desc = esc_attr( wp_trim_words( $desc, 55, ' [&hellip;]' ) );
+
+               $summary = '';
+               if ( $show_summary ) {
+                       $summary = $desc;
+
+                       // Change existing [...] to [&hellip;].
+                       if ( '[...]' == substr( $summary, -5 ) ) {
+                               $summary = substr( $summary, 0, -5 ) . '[&hellip;]';
+                       }
+
+                       $summary = '<div class="rssSummary">' . esc_html( $summary ) . '</div>';
+               }
+
+               $date = '';
+               if ( $show_date ) {
+                       $date = $item->get_date( 'U' );
+
+                       if ( $date ) {
+                               $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
+                       }
+               }
+
+               $author = '';
+               if ( $show_author ) {
+                       $author = $item->get_author();
+                       if ( is_object($author) ) {
+                               $author = $author->get_name();
+                               $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
+                       }
+               }
+
+               if ( $link == '' ) {
+                       echo "<li>$title{$date}{$summary}{$author}</li>";
+               } elseif ( $show_summary ) {
+                       echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$summary}{$author}</li>";
+               } else {
+                       echo "<li><a class='rsswidget' href='$link'>$title</a>{$date}{$author}</li>";
+               }
+       }
+       echo '</ul>';
+       $rss->__destruct();
+       unset($rss);
+}
+
+/**
+ * Display RSS widget options form.
+ *
+ * The options for what fields are displayed for the RSS form are all booleans
+ * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
+ * 'show_date'.
+ *
+ * @since 2.5.0
+ *
+ * @param array|string $args Values for input fields.
+ * @param array $inputs Override default display options.
+ */
+function wp_widget_rss_form( $args, $inputs = null ) {
+       $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
+       $inputs = wp_parse_args( $inputs, $default_inputs );
+
+       $args['title'] = isset( $args['title'] ) ? $args['title'] : '';
+       $args['url'] = isset( $args['url'] ) ? $args['url'] : '';
+       $args['items'] = isset( $args['items'] ) ? (int) $args['items'] : 0;
+
+       if ( $args['items'] < 1 || 20 < $args['items'] ) {
+               $args['items'] = 10;
+       }
+
+       $args['show_summary']   = isset( $args['show_summary'] ) ? (int) $args['show_summary'] : (int) $inputs['show_summary'];
+       $args['show_author']    = isset( $args['show_author'] ) ? (int) $args['show_author'] : (int) $inputs['show_author'];
+       $args['show_date']      = isset( $args['show_date'] ) ? (int) $args['show_date'] : (int) $inputs['show_date'];
+
+       if ( ! empty( $args['error'] ) ) {
+               echo '<p class="widget-error"><strong>' . sprintf( __( 'RSS Error: %s' ), $args['error'] ) . '</strong></p>';
+       }
+
+       $esc_number = esc_attr( $args['number'] );
+       if ( $inputs['url'] ) :
+?>
+       <p><label for="rss-url-<?php echo $esc_number; ?>"><?php _e( 'Enter the RSS feed URL here:' ); ?></label>
+       <input class="widefat" id="rss-url-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][url]" type="text" value="<?php echo esc_url( $args['url'] ); ?>" /></p>
+<?php endif; if ( $inputs['title'] ) : ?>
+       <p><label for="rss-title-<?php echo $esc_number; ?>"><?php _e( 'Give the feed a title (optional):' ); ?></label>
+       <input class="widefat" id="rss-title-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][title]" type="text" value="<?php echo esc_attr( $args['title'] ); ?>" /></p>
+<?php endif; if ( $inputs['items'] ) : ?>
+       <p><label for="rss-items-<?php echo $esc_number; ?>"><?php _e( 'How many items would you like to display?' ); ?></label>
+       <select id="rss-items-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][items]">
+       <?php
+       for ( $i = 1; $i <= 20; ++$i ) {
+               echo "<option value='$i' " . selected( $args['items'], $i, false ) . ">$i</option>";
+       }
+       ?>
+       </select></p>
+<?php endif; if ( $inputs['show_summary'] ) : ?>
+       <p><input id="rss-show-summary-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_summary]" type="checkbox" value="1" <?php checked( $args['show_summary'] ); ?> />
+       <label for="rss-show-summary-<?php echo $esc_number; ?>"><?php _e( 'Display item content?' ); ?></label></p>
+<?php endif; if ( $inputs['show_author'] ) : ?>
+       <p><input id="rss-show-author-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_author]" type="checkbox" value="1" <?php checked( $args['show_author'] ); ?> />
+       <label for="rss-show-author-<?php echo $esc_number; ?>"><?php _e( 'Display item author if available?' ); ?></label></p>
+<?php endif; if ( $inputs['show_date'] ) : ?>
+       <p><input id="rss-show-date-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][show_date]" type="checkbox" value="1" <?php checked( $args['show_date'] ); ?>/>
+       <label for="rss-show-date-<?php echo $esc_number; ?>"><?php _e( 'Display item date?' ); ?></label></p>
+<?php
+       endif;
+       foreach ( array_keys($default_inputs) as $input ) :
+               if ( 'hidden' === $inputs[$input] ) :
+                       $id = str_replace( '_', '-', $input );
+?>
+       <input type="hidden" id="rss-<?php echo esc_attr( $id ); ?>-<?php echo $esc_number; ?>" name="widget-rss[<?php echo $esc_number; ?>][<?php echo esc_attr( $input ); ?>]" value="<?php echo esc_attr( $args[ $input ] ); ?>" />
+<?php
+               endif;
+       endforeach;
+}
+
+/**
+ * Process RSS feed widget data and optionally retrieve feed items.
+ *
+ * The feed widget can not have more than 20 items or it will reset back to the
+ * default, which is 10.
+ *
+ * The resulting array has the feed title, feed url, feed link (from channel),
+ * feed items, error (if any), and whether to show summary, author, and date.
+ * All respectively in the order of the array elements.
+ *
+ * @since 2.5.0
+ *
+ * @param array $widget_rss RSS widget feed data. Expects unescaped data.
+ * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
+ * @return array
+ */
+function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
+       $items = (int) $widget_rss['items'];
+       if ( $items < 1 || 20 < $items )
+               $items = 10;
+       $url           = esc_url_raw( strip_tags( $widget_rss['url'] ) );
+       $title         = isset( $widget_rss['title'] ) ? trim( strip_tags( $widget_rss['title'] ) ) : '';
+       $show_summary  = isset( $widget_rss['show_summary'] ) ? (int) $widget_rss['show_summary'] : 0;
+       $show_author   = isset( $widget_rss['show_author'] ) ? (int) $widget_rss['show_author'] :0;
+       $show_date     = isset( $widget_rss['show_date'] ) ? (int) $widget_rss['show_date'] : 0;
+
+       if ( $check_feed ) {
+               $rss = fetch_feed($url);
+               $error = false;
+               $link = '';
+               if ( is_wp_error($rss) ) {
+                       $error = $rss->get_error_message();
+               } else {
+                       $link = esc_url(strip_tags($rss->get_permalink()));
+                       while ( stristr($link, 'http') != $link )
+                               $link = substr($link, 1);
+
+                       $rss->__destruct();
+                       unset($rss);
+               }
+       }
+
+       return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
+}
+
+/**
+ * Register all of the default WordPress widgets on startup.
+ *
+ * Calls 'widgets_init' action after all of the WordPress widgets have been
+ * registered.
+ *
+ * @since 2.2.0
+ */
+function wp_widgets_init() {
+       if ( !is_blog_installed() )
+               return;
+
+       register_widget('WP_Widget_Pages');
+
+       register_widget('WP_Widget_Calendar');
+
+       register_widget('WP_Widget_Archives');
+
+       if ( get_option( 'link_manager_enabled' ) )
+               register_widget('WP_Widget_Links');
+
+       register_widget('WP_Widget_Meta');
+
+       register_widget('WP_Widget_Search');
+
+       register_widget('WP_Widget_Text');
+
+       register_widget('WP_Widget_Categories');
+
+       register_widget('WP_Widget_Recent_Posts');
+
+       register_widget('WP_Widget_Recent_Comments');
+
+       register_widget('WP_Widget_RSS');
+
+       register_widget('WP_Widget_Tag_Cloud');
+
+       register_widget('WP_Nav_Menu_Widget');
+
+       /**
+        * Fires after all default WordPress widgets have been registered.
+        *
+        * @since 2.2.0
+        */
+       do_action( 'widgets_init' );
+}
</ins></span></pre></div>
<a id="trunksrcwpsettingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-settings.php 2015-11-20 06:15:34 UTC (rev 35717)
+++ trunk/src/wp-settings.php   2015-11-20 07:23:04 UTC (rev 35718)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -122,27 +122,41 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/class-wp-ajax-response.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/formatting.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/capabilities.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-roles.php' );
+require( ABSPATH . WPINC . '/class-wp-role.php' );
+require( ABSPATH . WPINC . '/class-wp-user.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/query.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/date.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/theme.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/class-wp-theme.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/user.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-user-query.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/session.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/meta.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-meta-query.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/general-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/link-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/author-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/post.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-walker-page.php' );
+require( ABSPATH . WPINC . '/class-walker-page-dropdown.php' );
+require( ABSPATH . WPINC . '/class-wp-post.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/post-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/revision.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/post-formats.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/post-thumbnail-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/category.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-walker-category.php' );
+require( ABSPATH . WPINC . '/class-walker-category-dropdown.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/category-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/comment.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-comment.php' );
+require( ABSPATH . WPINC . '/class-wp-comment-query.php' );
+require( ABSPATH . WPINC . '/class-walker-comment.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/comment-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/rewrite.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-rewrite.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/feed.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/bookmark.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/bookmark-template.php' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -151,19 +165,33 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/deprecated.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/script-loader.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/taxonomy.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-term.php' );
+require( ABSPATH . WPINC . '/class-wp-tax-query.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/update.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/canonical.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/shortcodes.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/embed.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/class-wp-embed.php' );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-require( ABSPATH . WPINC . '/embed-functions.php' );
</del><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/class-wp-oembed-controller.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/media.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/http.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-http.php' );
+require( ABSPATH . WPINC . '/class-wp-http-streams.php' );
+require( ABSPATH . WPINC . '/class-wp-http-curl.php' );
+require( ABSPATH . WPINC . '/class-wp-http-proxy.php' );
+require( ABSPATH . WPINC . '/class-wp-http-cookie.php' );
+require( ABSPATH . WPINC . '/class-wp-http-encoding.php' );
+require( ABSPATH . WPINC . '/class-wp-http-response.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/widgets.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-widget.php' );
+require( ABSPATH . WPINC . '/class-wp-widget-factory.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/nav-menu.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/nav-menu-template.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/admin-bar.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/rest-api.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
+require( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
+require( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Load multisite-specific files.
</span><span class="cx" style="display: block; padding: 0 10px"> if ( is_multisite() ) {
</span></span></pre>
</div>
</div>

</body>
</html>