wp/wp-includes/post.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * Post functions and post utility function.
     3  * Core Post API
     4  *
     4  *
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Post
     6  * @subpackage Post
     7  * @since 1.5.0
       
     8  */
     7  */
     9 
     8 
    10 //
     9 //
    11 // Post Type Registration
    10 // Post Type Registration
    12 //
    11 //
    13 
    12 
    14 /**
    13 /**
    15  * Creates the initial post types when 'init' action is fired.
    14  * Creates the initial post types when 'init' action is fired.
    16  *
    15  *
       
    16  * See {@see 'init'}.
       
    17  *
    17  * @since 2.9.0
    18  * @since 2.9.0
    18  */
    19  */
    19 function create_initial_post_types() {
    20 function create_initial_post_types() {
    20 	register_post_type( 'post', array(
    21 	register_post_type( 'post', array(
    21 		'labels' => array(
    22 		'labels' => array(
    22 			'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
    23 			'name_admin_bar' => _x( 'Post', 'add new from admin bar' ),
    23 		),
    24 		),
    24 		'public'  => true,
    25 		'public'  => true,
    25 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    26 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    26 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    27 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    27 		'capability_type' => 'post',
    28 		'capability_type' => 'post',
    28 		'map_meta_cap' => true,
    29 		'map_meta_cap' => true,
       
    30 		'menu_position' => 5,
    29 		'hierarchical' => false,
    31 		'hierarchical' => false,
    30 		'rewrite' => false,
    32 		'rewrite' => false,
    31 		'query_var' => false,
    33 		'query_var' => false,
    32 		'delete_with_user' => true,
    34 		'delete_with_user' => true,
    33 		'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
    35 		'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
       
    36 		'show_in_rest' => true,
       
    37 		'rest_base' => 'posts',
       
    38 		'rest_controller_class' => 'WP_REST_Posts_Controller',
    34 	) );
    39 	) );
    35 
    40 
    36 	register_post_type( 'page', array(
    41 	register_post_type( 'page', array(
    37 		'labels' => array(
    42 		'labels' => array(
    38 			'name_admin_bar' => _x( 'Page', 'add new on admin bar' ),
    43 			'name_admin_bar' => _x( 'Page', 'add new from admin bar' ),
    39 		),
    44 		),
    40 		'public' => true,
    45 		'public' => true,
    41 		'publicly_queryable' => false,
    46 		'publicly_queryable' => false,
    42 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    47 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    43 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    48 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    44 		'capability_type' => 'page',
    49 		'capability_type' => 'page',
    45 		'map_meta_cap' => true,
    50 		'map_meta_cap' => true,
       
    51 		'menu_position' => 20,
    46 		'hierarchical' => true,
    52 		'hierarchical' => true,
    47 		'rewrite' => false,
    53 		'rewrite' => false,
    48 		'query_var' => false,
    54 		'query_var' => false,
    49 		'delete_with_user' => true,
    55 		'delete_with_user' => true,
    50 		'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
    56 		'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
       
    57 		'show_in_rest' => true,
       
    58 		'rest_base' => 'pages',
       
    59 		'rest_controller_class' => 'WP_REST_Posts_Controller',
    51 	) );
    60 	) );
    52 
    61 
    53 	register_post_type( 'attachment', array(
    62 	register_post_type( 'attachment', array(
    54 		'labels' => array(
    63 		'labels' => array(
    55 			'name' => _x('Media', 'post type general name'),
    64 			'name' => _x('Media', 'post type general name'),
    56 			'name_admin_bar' => _x( 'Media', 'add new from admin bar' ),
    65 			'name_admin_bar' => _x( 'Media', 'add new from admin bar' ),
    57 			'add_new' => _x( 'Add New', 'add new media' ),
    66 			'add_new' => _x( 'Add New', 'add new media' ),
    58  			'edit_item' => __( 'Edit Media' ),
    67  			'edit_item' => __( 'Edit Media' ),
    59  			'view_item' => __( 'View Attachment Page' ),
    68  			'view_item' => __( 'View Attachment Page' ),
       
    69 			'attributes' => __( 'Attachment Attributes' ),
    60 		),
    70 		),
    61 		'public' => true,
    71 		'public' => true,
    62 		'show_ui' => true,
    72 		'show_ui' => true,
    63 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    73 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
    64 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    74 		'_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
    71 		'rewrite' => false,
    81 		'rewrite' => false,
    72 		'query_var' => false,
    82 		'query_var' => false,
    73 		'show_in_nav_menus' => false,
    83 		'show_in_nav_menus' => false,
    74 		'delete_with_user' => true,
    84 		'delete_with_user' => true,
    75 		'supports' => array( 'title', 'author', 'comments' ),
    85 		'supports' => array( 'title', 'author', 'comments' ),
       
    86 		'show_in_rest' => true,
       
    87 		'rest_base' => 'media',
       
    88 		'rest_controller_class' => 'WP_REST_Attachments_Controller',
    76 	) );
    89 	) );
    77 	add_post_type_support( 'attachment:audio', 'thumbnail' );
    90 	add_post_type_support( 'attachment:audio', 'thumbnail' );
    78 	add_post_type_support( 'attachment:video', 'thumbnail' );
    91 	add_post_type_support( 'attachment:video', 'thumbnail' );
    79 
    92 
    80 	register_post_type( 'revision', array(
    93 	register_post_type( 'revision', array(
   106 		'rewrite' => false,
   119 		'rewrite' => false,
   107 		'delete_with_user' => false,
   120 		'delete_with_user' => false,
   108 		'query_var' => false,
   121 		'query_var' => false,
   109 	) );
   122 	) );
   110 
   123 
       
   124 	register_post_type( 'custom_css', array(
       
   125 		'labels' => array(
       
   126 			'name'          => __( 'Custom CSS' ),
       
   127 			'singular_name' => __( 'Custom CSS' ),
       
   128 		),
       
   129 		'public'           => false,
       
   130 		'hierarchical'     => false,
       
   131 		'rewrite'          => false,
       
   132 		'query_var'        => false,
       
   133 		'delete_with_user' => false,
       
   134 		'can_export'       => true,
       
   135 		'_builtin'         => true, /* internal use only. don't use this when registering your own post type. */
       
   136 		'supports'         => array( 'title', 'revisions' ),
       
   137 		'capabilities'     => array(
       
   138 			'delete_posts'           => 'edit_theme_options',
       
   139 			'delete_post'            => 'edit_theme_options',
       
   140 			'delete_published_posts' => 'edit_theme_options',
       
   141 			'delete_private_posts'   => 'edit_theme_options',
       
   142 			'delete_others_posts'    => 'edit_theme_options',
       
   143 			'edit_post'              => 'edit_css',
       
   144 			'edit_posts'             => 'edit_css',
       
   145 			'edit_others_posts'      => 'edit_css',
       
   146 			'edit_published_posts'   => 'edit_css',
       
   147 			'read_post'              => 'read',
       
   148 			'read_private_posts'     => 'read',
       
   149 			'publish_posts'          => 'edit_theme_options',
       
   150 		),
       
   151 	) );
       
   152 
       
   153 	register_post_type( 'customize_changeset', array(
       
   154 		'labels' => array(
       
   155 			'name'               => _x( 'Changesets', 'post type general name' ),
       
   156 			'singular_name'      => _x( 'Changeset', 'post type singular name' ),
       
   157 			'menu_name'          => _x( 'Changesets', 'admin menu' ),
       
   158 			'name_admin_bar'     => _x( 'Changeset', 'add new on admin bar' ),
       
   159 			'add_new'            => _x( 'Add New', 'Customize Changeset' ),
       
   160 			'add_new_item'       => __( 'Add New Changeset' ),
       
   161 			'new_item'           => __( 'New Changeset' ),
       
   162 			'edit_item'          => __( 'Edit Changeset' ),
       
   163 			'view_item'          => __( 'View Changeset' ),
       
   164 			'all_items'          => __( 'All Changesets' ),
       
   165 			'search_items'       => __( 'Search Changesets' ),
       
   166 			'not_found'          => __( 'No changesets found.' ),
       
   167 			'not_found_in_trash' => __( 'No changesets found in Trash.' ),
       
   168 		),
       
   169 		'public' => false,
       
   170 		'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
       
   171 		'map_meta_cap' => true,
       
   172 		'hierarchical' => false,
       
   173 		'rewrite' => false,
       
   174 		'query_var' => false,
       
   175 		'can_export' => false,
       
   176 		'delete_with_user' => false,
       
   177 		'supports' => array( 'title', 'author' ),
       
   178 		'capability_type' => 'customize_changeset',
       
   179 		'capabilities' => array(
       
   180 			'create_posts' => 'customize',
       
   181 			'delete_others_posts' => 'customize',
       
   182 			'delete_post' => 'customize',
       
   183 			'delete_posts' => 'customize',
       
   184 			'delete_private_posts' => 'customize',
       
   185 			'delete_published_posts' => 'customize',
       
   186 			'edit_others_posts' => 'customize',
       
   187 			'edit_post' => 'customize',
       
   188 			'edit_posts' => 'customize',
       
   189 			'edit_private_posts' => 'customize',
       
   190 			'edit_published_posts' => 'do_not_allow',
       
   191 			'publish_posts' => 'customize',
       
   192 			'read' => 'read',
       
   193 			'read_post' => 'customize',
       
   194 			'read_private_posts' => 'customize',
       
   195 		),
       
   196 	) );
       
   197 
       
   198 	register_post_type( 'oembed_cache', array(
       
   199 		'labels' => array(
       
   200 			'name'          => __( 'oEmbed Responses' ),
       
   201 			'singular_name' => __( 'oEmbed Response' ),
       
   202 		),
       
   203 		'public'           => false,
       
   204 		'hierarchical'     => false,
       
   205 		'rewrite'          => false,
       
   206 		'query_var'        => false,
       
   207 		'delete_with_user' => false,
       
   208 		'can_export'       => false,
       
   209 		'_builtin'         => true, /* internal use only. don't use this when registering your own post type. */
       
   210 		'supports'         => array(),
       
   211 	) );
       
   212 
       
   213 	register_post_type( 'user_request', array(
       
   214 		'labels'           => array(
       
   215 			'name'          => __( 'User Requests' ),
       
   216 			'singular_name' => __( 'User Request' ),
       
   217 		),
       
   218 		'public'           => false,
       
   219 		'_builtin'         => true, /* internal use only. don't use this when registering your own post type. */
       
   220 		'hierarchical'     => false,
       
   221 		'rewrite'          => false,
       
   222 		'query_var'        => false,
       
   223 		'can_export'       => false,
       
   224 		'delete_with_user' => false,
       
   225 		'supports'         => array(),
       
   226 	) );
       
   227 
   111 	register_post_status( 'publish', array(
   228 	register_post_status( 'publish', array(
   112 		'label'       => _x( 'Published', 'post' ),
   229 		'label'       => _x( 'Published', 'post status' ),
   113 		'public'      => true,
   230 		'public'      => true,
   114 		'_builtin'    => true, /* internal use only. */
   231 		'_builtin'    => true, /* internal use only. */
   115 		'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
   232 		'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
   116 	) );
   233 	) );
   117 
   234 
   118 	register_post_status( 'future', array(
   235 	register_post_status( 'future', array(
   119 		'label'       => _x( 'Scheduled', 'post' ),
   236 		'label'       => _x( 'Scheduled', 'post status' ),
   120 		'protected'   => true,
   237 		'protected'   => true,
   121 		'_builtin'    => true, /* internal use only. */
   238 		'_builtin'    => true, /* internal use only. */
   122 		'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
   239 		'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
   123 	) );
   240 	) );
   124 
   241 
   125 	register_post_status( 'draft', array(
   242 	register_post_status( 'draft', array(
   126 		'label'       => _x( 'Draft', 'post' ),
   243 		'label'       => _x( 'Draft', 'post status' ),
   127 		'protected'   => true,
   244 		'protected'   => true,
   128 		'_builtin'    => true, /* internal use only. */
   245 		'_builtin'    => true, /* internal use only. */
   129 		'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
   246 		'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
   130 	) );
   247 	) );
   131 
   248 
   132 	register_post_status( 'pending', array(
   249 	register_post_status( 'pending', array(
   133 		'label'       => _x( 'Pending', 'post' ),
   250 		'label'       => _x( 'Pending', 'post status' ),
   134 		'protected'   => true,
   251 		'protected'   => true,
   135 		'_builtin'    => true, /* internal use only. */
   252 		'_builtin'    => true, /* internal use only. */
   136 		'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
   253 		'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
   137 	) );
   254 	) );
   138 
   255 
   139 	register_post_status( 'private', array(
   256 	register_post_status( 'private', array(
   140 		'label'       => _x( 'Private', 'post' ),
   257 		'label'       => _x( 'Private', 'post status' ),
   141 		'private'     => true,
   258 		'private'     => true,
   142 		'_builtin'    => true, /* internal use only. */
   259 		'_builtin'    => true, /* internal use only. */
   143 		'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
   260 		'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
   144 	) );
   261 	) );
   145 
   262 
   146 	register_post_status( 'trash', array(
   263 	register_post_status( 'trash', array(
   147 		'label'       => _x( 'Trash', 'post' ),
   264 		'label'       => _x( 'Trash', 'post status' ),
   148 		'internal'    => true,
   265 		'internal'    => true,
   149 		'_builtin'    => true, /* internal use only. */
   266 		'_builtin'    => true, /* internal use only. */
   150 		'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
   267 		'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
   151 		'show_in_admin_status_list' => true,
   268 		'show_in_admin_status_list' => true,
   152 	) );
   269 	) );
   161 		'label'    => 'inherit',
   278 		'label'    => 'inherit',
   162 		'internal' => true,
   279 		'internal' => true,
   163 		'_builtin' => true, /* internal use only. */
   280 		'_builtin' => true, /* internal use only. */
   164 		'exclude_from_search' => false,
   281 		'exclude_from_search' => false,
   165 	) );
   282 	) );
       
   283 
       
   284 	register_post_status( 'request-pending', array(
       
   285 		'label'               => _x( 'Pending', 'request status' ),
       
   286 		'internal'            => true,
       
   287 		'_builtin'            => true, /* internal use only. */
       
   288 		'exclude_from_search' => false,
       
   289 	) );
       
   290 
       
   291 	register_post_status( 'request-confirmed', array(
       
   292 		'label'               => _x( 'Confirmed', 'request status' ),
       
   293 		'internal'            => true,
       
   294 		'_builtin'            => true, /* internal use only. */
       
   295 		'exclude_from_search' => false,
       
   296 	) );
       
   297 
       
   298 	register_post_status( 'request-failed', array(
       
   299 		'label'               => _x( 'Failed', 'request status' ),
       
   300 		'internal'            => true,
       
   301 		'_builtin'            => true, /* internal use only. */
       
   302 		'exclude_from_search' => false,
       
   303 	) );
       
   304 
       
   305 	register_post_status( 'request-completed', array(
       
   306 		'label'               => _x( 'Completed', 'request status' ),
       
   307 		'internal'            => true,
       
   308 		'_builtin'            => true, /* internal use only. */
       
   309 		'exclude_from_search' => false,
       
   310 	) );
   166 }
   311 }
   167 
   312 
   168 /**
   313 /**
   169  * Retrieve attached file path based on attachment ID.
   314  * Retrieve attached file path based on attachment ID.
   170  *
   315  *
   179  *
   324  *
   180  * @since 2.0.0
   325  * @since 2.0.0
   181  *
   326  *
   182  * @param int  $attachment_id Attachment ID.
   327  * @param int  $attachment_id Attachment ID.
   183  * @param bool $unfiltered    Optional. Whether to apply filters. Default false.
   328  * @param bool $unfiltered    Optional. Whether to apply filters. Default false.
   184  * @return string|bool The file path to where the attached file should be, false otherwise.
   329  * @return string|false The file path to where the attached file should be, false otherwise.
   185  */
   330  */
   186 function get_attached_file( $attachment_id, $unfiltered = false ) {
   331 function get_attached_file( $attachment_id, $unfiltered = false ) {
   187 	$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
   332 	$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
       
   333 
   188 	// If the file is relative, prepend upload dir.
   334 	// If the file is relative, prepend upload dir.
   189 	if ( $file && 0 !== strpos($file, '/') && !preg_match('|^.:\\\|', $file) && ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) )
   335 	if ( $file && 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) && ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) ) {
   190 		$file = $uploads['basedir'] . "/$file";
   336 		$file = $uploads['basedir'] . "/$file";
   191 	if ( $unfiltered )
   337 	}
       
   338 
       
   339 	if ( $unfiltered ) {
   192 		return $file;
   340 		return $file;
       
   341 	}
   193 
   342 
   194 	/**
   343 	/**
   195 	 * Filter the attached file based on the given ID.
   344 	 * Filters the attached file based on the given ID.
   196 	 *
   345 	 *
   197 	 * @since 2.1.0
   346 	 * @since 2.1.0
   198 	 *
   347 	 *
   199 	 * @param string $file          Path to attached file.
   348 	 * @param string $file          Path to attached file.
   200 	 * @param int    $attachment_id Attachment ID.
   349 	 * @param int    $attachment_id Attachment ID.
   217 function update_attached_file( $attachment_id, $file ) {
   366 function update_attached_file( $attachment_id, $file ) {
   218 	if ( !get_post( $attachment_id ) )
   367 	if ( !get_post( $attachment_id ) )
   219 		return false;
   368 		return false;
   220 
   369 
   221 	/**
   370 	/**
   222 	 * Filter the path to the attached file to update.
   371 	 * Filters the path to the attached file to update.
   223 	 *
   372 	 *
   224 	 * @since 2.1.0
   373 	 * @since 2.1.0
   225 	 *
   374 	 *
   226 	 * @param string $file          Path to the attached file to update.
   375 	 * @param string $file          Path to the attached file to update.
   227 	 * @param int    $attachment_id Attachment ID.
   376 	 * @param int    $attachment_id Attachment ID.
   245  * @return string Relative path on success, unchanged path on failure.
   394  * @return string Relative path on success, unchanged path on failure.
   246  */
   395  */
   247 function _wp_relative_upload_path( $path ) {
   396 function _wp_relative_upload_path( $path ) {
   248 	$new_path = $path;
   397 	$new_path = $path;
   249 
   398 
   250 	$uploads = wp_upload_dir();
   399 	$uploads = wp_get_upload_dir();
   251 	if ( 0 === strpos( $new_path, $uploads['basedir'] ) ) {
   400 	if ( 0 === strpos( $new_path, $uploads['basedir'] ) ) {
   252 			$new_path = str_replace( $uploads['basedir'], '', $new_path );
   401 			$new_path = str_replace( $uploads['basedir'], '', $new_path );
   253 			$new_path = ltrim( $new_path, '/' );
   402 			$new_path = ltrim( $new_path, '/' );
   254 	}
   403 	}
   255 
   404 
   256 	/**
   405 	/**
   257 	 * Filter the relative path to an uploaded file.
   406 	 * Filters the relative path to an uploaded file.
   258 	 *
   407 	 *
   259 	 * @since 2.9.0
   408 	 * @since 2.9.0
   260 	 *
   409 	 *
   261 	 * @param string $new_path Relative path to the file.
   410 	 * @param string $new_path Relative path to the file.
   262 	 * @param string $path     Full path to the file.
   411 	 * @param string $path     Full path to the file.
   275  * what context you wish to retrieve the children of.
   424  * what context you wish to retrieve the children of.
   276  *
   425  *
   277  * Attachments may also be made the child of a post, so if that is an accurate
   426  * Attachments may also be made the child of a post, so if that is an accurate
   278  * statement (which needs to be verified), it would then be possible to get
   427  * statement (which needs to be verified), it would then be possible to get
   279  * all of the attachments for a post. Attachments have since changed since
   428  * all of the attachments for a post. Attachments have since changed since
   280  * version 2.5, so this is most likely unaccurate, but serves generally as an
   429  * version 2.5, so this is most likely inaccurate, but serves generally as an
   281  * example of what is possible.
   430  * example of what is possible.
   282  *
   431  *
   283  * The arguments listed as defaults are for this function and also of the
   432  * The arguments listed as defaults are for this function and also of the
   284  * {@link get_posts()} function. The arguments are combined with the
   433  * get_posts() function. The arguments are combined with the get_children defaults
   285  * get_children defaults and are then passed to the {@link get_posts()}
   434  * and are then passed to the get_posts() function, which accepts additional arguments.
   286  * function, which accepts additional arguments. You can replace the defaults in
   435  * You can replace the defaults in this function, listed below and the additional
   287  * this function, listed below and the additional arguments listed in the
   436  * arguments listed in the get_posts() function.
   288  * {@link get_posts()} function.
       
   289  *
   437  *
   290  * The 'post_parent' is the most important argument and important attention
   438  * The 'post_parent' is the most important argument and important attention
   291  * needs to be paid to the $args parameter. If you pass either an object or an
   439  * needs to be paid to the $args parameter. If you pass either an object or an
   292  * integer (number), then just the 'post_parent' is grabbed and everything else
   440  * integer (number), then just the 'post_parent' is grabbed and everything else
   293  * is lost. If you don't specify any arguments, then it is assumed that you are
   441  * is lost. If you don't specify any arguments, then it is assumed that you are
   306  * @since 2.0.0
   454  * @since 2.0.0
   307  *
   455  *
   308  * @see get_posts()
   456  * @see get_posts()
   309  * @todo Check validity of description.
   457  * @todo Check validity of description.
   310  *
   458  *
       
   459  * @global WP_Post $post
       
   460  *
   311  * @param mixed  $args   Optional. User defined arguments for replacing the defaults. Default empty.
   461  * @param mixed  $args   Optional. User defined arguments for replacing the defaults. Default empty.
   312  * @param string $output Optional. Constant for return type. Accepts OBJECT, ARRAY_A, ARRAY_N.
   462  * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   313  *                       Default OBJECt.
   463  *                       a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
   314  * @return array Array of children, where the type of each element is determined by $output parameter.
   464  * @return array Array of children, where the type of each element is determined by $output parameter.
   315  *               Empty array on failure.
   465  *               Empty array on failure.
   316  */
   466  */
   317 function get_children( $args = '', $output = OBJECT ) {
   467 function get_children( $args = '', $output = OBJECT ) {
   318 	$kids = array();
   468 	$kids = array();
   379  * `<!--more-->` comment. The 'more_text' key has the custom "Read More" text.
   529  * `<!--more-->` comment. The 'more_text' key has the custom "Read More" text.
   380  *
   530  *
   381  * @since 1.0.0
   531  * @since 1.0.0
   382  *
   532  *
   383  * @param string $post Post content.
   533  * @param string $post Post content.
   384  * @return array Post before ('main'), after ('extended'), and custom readmore ('more_text').
   534  * @return array Post before ('main'), after ('extended'), and custom read more ('more_text').
   385  */
   535  */
   386 function get_extended( $post ) {
   536 function get_extended( $post ) {
   387 	//Match the new style more links.
   537 	//Match the new style more links.
   388 	if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
   538 	if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
   389 		list($main, $extended) = explode($matches[0], $post, 2);
   539 		list($main, $extended) = explode($matches[0], $post, 2);
   403 }
   553 }
   404 
   554 
   405 /**
   555 /**
   406  * Retrieves post data given a post ID or post object.
   556  * Retrieves post data given a post ID or post object.
   407  *
   557  *
   408  * See {@link sanitize_post()} for optional $filter values. Also, the parameter
   558  * See sanitize_post() for optional $filter values. Also, the parameter
   409  * $post, must be given as a variable, since it is passed by reference.
   559  * `$post`, must be given as a variable, since it is passed by reference.
   410  *
   560  *
   411  * @since 1.5.1
   561  * @since 1.5.1
   412  *
   562  *
   413  * @param int|WP_Post $post   Optional. Post ID or post object. Defaults to global $post.
   563  * @global WP_Post $post
   414  * @param string      $output Optional, default is Object. Accepts OBJECT, ARRAY_A, or ARRAY_N.
   564  *
   415  *                            Default OBJECT.
   565  * @param int|WP_Post|null $post   Optional. Post ID or post object. Defaults to global $post.
   416  * @param string      $filter Optional. Type of filter to apply. Accepts 'raw', 'edit', 'db',
   566  * @param string           $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   417  *                            or 'display'. Default 'raw'.
   567  *                                 a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
       
   568  * @param string           $filter Optional. Type of filter to apply. Accepts 'raw', 'edit', 'db',
       
   569  *                                 or 'display'. Default 'raw'.
   418  * @return WP_Post|array|null Type corresponding to $output on success or null on failure.
   570  * @return WP_Post|array|null Type corresponding to $output on success or null on failure.
   419  *                            When $output is OBJECT, a `WP_Post` instance is returned.
   571  *                            When $output is OBJECT, a `WP_Post` instance is returned.
   420  */
   572  */
   421 function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
   573 function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
   422 	if ( empty( $post ) && isset( $GLOBALS['post'] ) )
   574 	if ( empty( $post ) && isset( $GLOBALS['post'] ) )
   449 
   601 
   450 	return $_post;
   602 	return $_post;
   451 }
   603 }
   452 
   604 
   453 /**
   605 /**
   454  * WordPress Post class.
       
   455  *
       
   456  * @since 3.5.0
       
   457  *
       
   458  * @property-read array  $ancestors
       
   459  * @property-read string $page_template
       
   460  * @property-read int    $post_category
       
   461  * @property-read string $tag_input
       
   462  *
       
   463  */
       
   464 final class WP_Post {
       
   465 
       
   466 	/**
       
   467 	 * Post ID.
       
   468 	 *
       
   469 	 * @var int
       
   470 	 */
       
   471 	public $ID;
       
   472 
       
   473 	/**
       
   474 	 * ID of post author.
       
   475 	 *
       
   476 	 * A numeric string, for compatibility reasons.
       
   477 	 *
       
   478 	 * @var string
       
   479 	 */
       
   480 	public $post_author = 0;
       
   481 
       
   482 	/**
       
   483 	 * The post's local publication time.
       
   484 	 *
       
   485 	 * @var string
       
   486 	 */
       
   487 	public $post_date = '0000-00-00 00:00:00';
       
   488 
       
   489 	/**
       
   490 	 * The post's GMT publication time.
       
   491 	 *
       
   492 	 * @var string
       
   493 	 */
       
   494 	public $post_date_gmt = '0000-00-00 00:00:00';
       
   495 
       
   496 	/**
       
   497 	 * The post's content.
       
   498 	 *
       
   499 	 * @var string
       
   500 	 */
       
   501 	public $post_content = '';
       
   502 
       
   503 	/**
       
   504 	 * The post's title.
       
   505 	 *
       
   506 	 * @var string
       
   507 	 */
       
   508 	public $post_title = '';
       
   509 
       
   510 	/**
       
   511 	 * The post's excerpt.
       
   512 	 *
       
   513 	 * @var string
       
   514 	 */
       
   515 	public $post_excerpt = '';
       
   516 
       
   517 	/**
       
   518 	 * The post's status.
       
   519 	 *
       
   520 	 * @var string
       
   521 	 */
       
   522 	public $post_status = 'publish';
       
   523 
       
   524 	/**
       
   525 	 * Whether comments are allowed.
       
   526 	 *
       
   527 	 * @var string
       
   528 	 */
       
   529 	public $comment_status = 'open';
       
   530 
       
   531 	/**
       
   532 	 * Whether pings are allowed.
       
   533 	 *
       
   534 	 * @var string
       
   535 	 */
       
   536 	public $ping_status = 'open';
       
   537 
       
   538 	/**
       
   539 	 * The post's password in plain text.
       
   540 	 *
       
   541 	 * @var string
       
   542 	 */
       
   543 	public $post_password = '';
       
   544 
       
   545 	/**
       
   546 	 * The post's slug.
       
   547 	 *
       
   548 	 * @var string
       
   549 	 */
       
   550 	public $post_name = '';
       
   551 
       
   552 	/**
       
   553 	 * URLs queued to be pinged.
       
   554 	 *
       
   555 	 * @var string
       
   556 	 */
       
   557 	public $to_ping = '';
       
   558 
       
   559 	/**
       
   560 	 * URLs that have been pinged.
       
   561 	 *
       
   562 	 * @var string
       
   563 	 */
       
   564 	public $pinged = '';
       
   565 
       
   566 	/**
       
   567 	 * The post's local modified time.
       
   568 	 *
       
   569 	 * @var string
       
   570 	 */
       
   571 	public $post_modified = '0000-00-00 00:00:00';
       
   572 
       
   573 	/**
       
   574 	 * The post's GMT modified time.
       
   575 	 *
       
   576 	 * @var string
       
   577 	 */
       
   578 	public $post_modified_gmt = '0000-00-00 00:00:00';
       
   579 
       
   580 	/**
       
   581 	 * A utility DB field for post content.
       
   582 	 *
       
   583 	 *
       
   584 	 * @var string
       
   585 	 */
       
   586 	public $post_content_filtered = '';
       
   587 
       
   588 	/**
       
   589 	 * ID of a post's parent post.
       
   590 	 *
       
   591 	 * @var int
       
   592 	 */
       
   593 	public $post_parent = 0;
       
   594 
       
   595 	/**
       
   596 	 * The unique identifier for a post, not necessarily a URL, used as the feed GUID.
       
   597 	 *
       
   598 	 * @var string
       
   599 	 */
       
   600 	public $guid = '';
       
   601 
       
   602 	/**
       
   603 	 * A field used for ordering posts.
       
   604 	 *
       
   605 	 * @var int
       
   606 	 */
       
   607 	public $menu_order = 0;
       
   608 
       
   609 	/**
       
   610 	 * The post's type, like post or page.
       
   611 	 *
       
   612 	 * @var string
       
   613 	 */
       
   614 	public $post_type = 'post';
       
   615 
       
   616 	/**
       
   617 	 * An attachment's mime type.
       
   618 	 *
       
   619 	 * @var string
       
   620 	 */
       
   621 	public $post_mime_type = '';
       
   622 
       
   623 	/**
       
   624 	 * Cached comment count.
       
   625 	 *
       
   626 	 * A numeric string, for compatibility reasons.
       
   627 	 *
       
   628 	 * @var string
       
   629 	 */
       
   630 	public $comment_count = 0;
       
   631 
       
   632 	/**
       
   633 	 * Stores the post object's sanitization level.
       
   634 	 *
       
   635 	 * Does not correspond to a DB field.
       
   636 	 *
       
   637 	 * @var string
       
   638 	 */
       
   639 	public $filter;
       
   640 
       
   641 	/**
       
   642 	 * Retrieve WP_Post instance.
       
   643 	 *
       
   644 	 * @static
       
   645 	 * @access public
       
   646 	 *
       
   647 	 * @param int $post_id Post ID.
       
   648 	 * @return WP_Post|bool Post object, false otherwise.
       
   649 	 */
       
   650 	public static function get_instance( $post_id ) {
       
   651 		global $wpdb;
       
   652 
       
   653 		$post_id = (int) $post_id;
       
   654 		if ( ! $post_id )
       
   655 			return false;
       
   656 
       
   657 		$_post = wp_cache_get( $post_id, 'posts' );
       
   658 
       
   659 		if ( ! $_post ) {
       
   660 			$_post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post_id ) );
       
   661 
       
   662 			if ( ! $_post )
       
   663 				return false;
       
   664 
       
   665 			$_post = sanitize_post( $_post, 'raw' );
       
   666 			wp_cache_add( $_post->ID, $_post, 'posts' );
       
   667 		} elseif ( empty( $_post->filter ) ) {
       
   668 			$_post = sanitize_post( $_post, 'raw' );
       
   669 		}
       
   670 
       
   671 		return new WP_Post( $_post );
       
   672 	}
       
   673 
       
   674 	/**
       
   675 	 * Constructor.
       
   676 	 *
       
   677 	 * @param WP_Post $post Post object.
       
   678 	 */
       
   679 	public function __construct( $post ) {
       
   680 		foreach ( get_object_vars( $post ) as $key => $value )
       
   681 			$this->$key = $value;
       
   682 	}
       
   683 
       
   684 	/**
       
   685 	 * Isset-er.
       
   686 	 *
       
   687 	 * @param string $key Property to check if set.
       
   688 	 * @return bool
       
   689 	 */
       
   690 	public function __isset( $key ) {
       
   691 		if ( 'ancestors' == $key )
       
   692 			return true;
       
   693 
       
   694 		if ( 'page_template' == $key )
       
   695 			return ( 'page' == $this->post_type );
       
   696 
       
   697 		if ( 'post_category' == $key )
       
   698 		   return true;
       
   699 
       
   700 		if ( 'tags_input' == $key )
       
   701 		   return true;
       
   702 
       
   703 		return metadata_exists( 'post', $this->ID, $key );
       
   704 	}
       
   705 
       
   706 	/**
       
   707 	 * Getter.
       
   708 	 *
       
   709 	 * @param string $key Key to get.
       
   710 	 * @return array|mixed
       
   711 	 */
       
   712 	public function __get( $key ) {
       
   713 		if ( 'page_template' == $key && $this->__isset( $key ) ) {
       
   714 			return get_post_meta( $this->ID, '_wp_page_template', true );
       
   715 		}
       
   716 
       
   717 		if ( 'post_category' == $key ) {
       
   718 			if ( is_object_in_taxonomy( $this->post_type, 'category' ) )
       
   719 				$terms = get_the_terms( $this, 'category' );
       
   720 
       
   721 			if ( empty( $terms ) )
       
   722 				return array();
       
   723 
       
   724 			return wp_list_pluck( $terms, 'term_id' );
       
   725 		}
       
   726 
       
   727 		if ( 'tags_input' == $key ) {
       
   728 			if ( is_object_in_taxonomy( $this->post_type, 'post_tag' ) )
       
   729 				$terms = get_the_terms( $this, 'post_tag' );
       
   730 
       
   731 			if ( empty( $terms ) )
       
   732 				return array();
       
   733 
       
   734 			return wp_list_pluck( $terms, 'name' );
       
   735 		}
       
   736 
       
   737 		// Rest of the values need filtering.
       
   738 		if ( 'ancestors' == $key )
       
   739 			$value = get_post_ancestors( $this );
       
   740 		else
       
   741 			$value = get_post_meta( $this->ID, $key, true );
       
   742 
       
   743 		if ( $this->filter )
       
   744 			$value = sanitize_post_field( $key, $value, $this->ID, $this->filter );
       
   745 
       
   746 		return $value;
       
   747 	}
       
   748 
       
   749 	/**
       
   750 	 * {@Missing Summary}
       
   751 	 *
       
   752 	 * @param string $filter Filter.
       
   753 	 * @return $this|array|bool|object|WP_Post
       
   754 	 */
       
   755 	public function filter( $filter ) {
       
   756 		if ( $this->filter == $filter )
       
   757 			return $this;
       
   758 
       
   759 		if ( $filter == 'raw' )
       
   760 			return self::get_instance( $this->ID );
       
   761 
       
   762 		return sanitize_post( $this, $filter );
       
   763 	}
       
   764 
       
   765 	/**
       
   766 	 * Convert object to array.
       
   767 	 *
       
   768 	 * @return array Object as array.
       
   769 	 */
       
   770 	public function to_array() {
       
   771 		$post = get_object_vars( $this );
       
   772 
       
   773 		foreach ( array( 'ancestors', 'page_template', 'post_category', 'tags_input' ) as $key ) {
       
   774 			if ( $this->__isset( $key ) )
       
   775 				$post[ $key ] = $this->__get( $key );
       
   776 		}
       
   777 
       
   778 		return $post;
       
   779 	}
       
   780 }
       
   781 
       
   782 /**
       
   783  * Retrieve ancestors of a post.
   606  * Retrieve ancestors of a post.
   784  *
   607  *
   785  * @since 2.5.0
   608  * @since 2.5.0
   786  *
   609  *
   787  * @param int|WP_Post $post Post ID or post object.
   610  * @param int|WP_Post $post Post ID or post object.
   816  *
   639  *
   817  * The context values are based off of the taxonomy filter functions and
   640  * The context values are based off of the taxonomy filter functions and
   818  * supported values are found within those functions.
   641  * supported values are found within those functions.
   819  *
   642  *
   820  * @since 2.3.0
   643  * @since 2.3.0
       
   644  * @since 4.5.0 The `$post` parameter was made optional.
   821  *
   645  *
   822  * @see sanitize_post_field()
   646  * @see sanitize_post_field()
   823  *
   647  *
   824  * @param string      $field   Post field name.
   648  * @param string      $field   Post field name.
   825  * @param int|WP_Post $post    Post ID or post object.
   649  * @param int|WP_Post $post    Optional. Post ID or post object. Defaults to current post.
   826  * @param string      $context Optional. How to filter the field. Accepts 'raw', 'edit', 'db',
   650  * @param string      $context Optional. How to filter the field. Accepts 'raw', 'edit', 'db',
   827  *                             or 'display'. Default 'display'.
   651  *                             or 'display'. Default 'display'.
   828  * @return string The value of the post field on success, empty string on failure.
   652  * @return string The value of the post field on success, empty string on failure.
   829  */
   653  */
   830 function get_post_field( $field, $post, $context = 'display' ) {
   654 function get_post_field( $field, $post = null, $context = 'display' ) {
   831 	$post = get_post( $post );
   655 	$post = get_post( $post );
   832 
   656 
   833 	if ( !$post )
   657 	if ( !$post )
   834 		return '';
   658 		return '';
   835 
   659 
   894 			}
   718 			}
   895 		}
   719 		}
   896 
   720 
   897 	}
   721 	}
   898 
   722 
   899 	return $post->post_status;
   723 	/**
       
   724 	 * Filters the post status.
       
   725 	 *
       
   726 	 * @since 4.4.0
       
   727 	 *
       
   728 	 * @param string  $post_status The post status.
       
   729 	 * @param WP_Post $post        The post object.
       
   730 	 */
       
   731 	return apply_filters( 'get_post_status', $post->post_status, $post );
   900 }
   732 }
   901 
   733 
   902 /**
   734 /**
   903  * Retrieve all of the WordPress supported post statuses.
   735  * Retrieve all of the WordPress supported post statuses.
   904  *
   736  *
   939 
   771 
   940 	return $status;
   772 	return $status;
   941 }
   773 }
   942 
   774 
   943 /**
   775 /**
       
   776  * Return statuses for privacy requests.
       
   777  *
       
   778  * @since 5.0.0
       
   779  *
       
   780  * @return array
       
   781  */
       
   782 function _wp_privacy_statuses() {
       
   783 	return array(
       
   784 		'request-pending'   => __( 'Pending' ),      // Pending confirmation from user.
       
   785 		'request-confirmed' => __( 'Confirmed' ),    // User has confirmed the action.
       
   786 		'request-failed'    => __( 'Failed' ),       // User failed to confirm the action.
       
   787 		'request-completed' => __( 'Completed' ),    // Admin has handled the request.
       
   788 	);
       
   789 }
       
   790 
       
   791 /**
   944  * Register a post status. Do not use before init.
   792  * Register a post status. Do not use before init.
   945  *
   793  *
   946  * A simple function for creating or modifying a post status based on the
   794  * A simple function for creating or modifying a post status based on the
   947  * parameters given. The function will accept an array (second optional
   795  * parameters given. The function will accept an array (second optional
   948  * parameter), along with a string for the post status name.
   796  * parameter), along with a string for the post status name.
   949  *
   797  *
   950  * Arguments prefixed with an _underscore shouldn't be used by plugins and themes.
   798  * Arguments prefixed with an _underscore shouldn't be used by plugins and themes.
   951  *
   799  *
   952  * @since 3.0.0
   800  * @since 3.0.0
   953  * @uses $wp_post_statuses Inserts new post status object into the list
   801  * @global array $wp_post_statuses Inserts new post status object into the list
   954  *
   802  *
   955  * @param string $post_status Name of the post status.
   803  * @param string $post_status Name of the post status.
   956  * @param array|string $args {
   804  * @param array|string $args {
   957  *     Optional. Array or string of post status arguments.
   805  *     Optional. Array or string of post status arguments.
   958  *
   806  *
   963  *     @type bool        $exclude_from_search       Whether to exclude posts with this post status
   811  *     @type bool        $exclude_from_search       Whether to exclude posts with this post status
   964  *                                                  from search results. Default is value of $internal.
   812  *                                                  from search results. Default is value of $internal.
   965  *     @type bool        $_builtin                  Whether the status is built-in. Core-use only.
   813  *     @type bool        $_builtin                  Whether the status is built-in. Core-use only.
   966  *                                                  Default false.
   814  *                                                  Default false.
   967  *     @type bool        $public                    Whether posts of this status should be shown
   815  *     @type bool        $public                    Whether posts of this status should be shown
   968  *                                                  in the front end of the site. Default true.
   816  *                                                  in the front end of the site. Default false.
   969  *     @type bool        $internal                  Whether the status is for internal use only.
   817  *     @type bool        $internal                  Whether the status is for internal use only.
   970  *                                                  Default false.
   818  *                                                  Default false.
   971  *     @type bool        $protected                 Whether posts with this status should be protected.
   819  *     @type bool        $protected                 Whether posts with this status should be protected.
   972  *                                                  Default false.
   820  *                                                  Default false.
   973  *     @type bool        $private                   Whether posts with this status should be private.
   821  *     @type bool        $private                   Whether posts with this status should be private.
   979  *     @type bool        $show_in_admin_status_list Show in the list of statuses with post counts at
   827  *     @type bool        $show_in_admin_status_list Show in the list of statuses with post counts at
   980  *                                                  the top of the edit listings,
   828  *                                                  the top of the edit listings,
   981  *                                                  e.g. All (12) | Published (9) | My Custom Status (2)
   829  *                                                  e.g. All (12) | Published (9) | My Custom Status (2)
   982  *                                                  Default is value of $internal.
   830  *                                                  Default is value of $internal.
   983  * }
   831  * }
       
   832  * @return object
   984  */
   833  */
   985 function register_post_status( $post_status, $args = array() ) {
   834 function register_post_status( $post_status, $args = array() ) {
   986 	global $wp_post_statuses;
   835 	global $wp_post_statuses;
   987 
   836 
   988 	if (!is_array($wp_post_statuses))
   837 	if (!is_array($wp_post_statuses))
  1038 
   887 
  1039 	if ( false === $args->label )
   888 	if ( false === $args->label )
  1040 		$args->label = $post_status;
   889 		$args->label = $post_status;
  1041 
   890 
  1042 	if ( false === $args->label_count )
   891 	if ( false === $args->label_count )
  1043 		$args->label_count = array( $args->label, $args->label );
   892 		$args->label_count = _n_noop( $args->label, $args->label );
  1044 
   893 
  1045 	$wp_post_statuses[$post_status] = $args;
   894 	$wp_post_statuses[$post_status] = $args;
  1046 
   895 
  1047 	return $args;
   896 	return $args;
  1048 }
   897 }
  1055  * @global array $wp_post_statuses List of post statuses.
   904  * @global array $wp_post_statuses List of post statuses.
  1056  *
   905  *
  1057  * @see register_post_status()
   906  * @see register_post_status()
  1058  *
   907  *
  1059  * @param string $post_status The name of a registered post status.
   908  * @param string $post_status The name of a registered post status.
  1060  * @return object A post status object.
   909  * @return object|null A post status object.
  1061  */
   910  */
  1062 function get_post_status_object( $post_status ) {
   911 function get_post_status_object( $post_status ) {
  1063 	global $wp_post_statuses;
   912 	global $wp_post_statuses;
  1064 
   913 
  1065 	if ( empty($wp_post_statuses[$post_status]) )
   914 	if ( empty($wp_post_statuses[$post_status]) )
  1126 function post_type_exists( $post_type ) {
   975 function post_type_exists( $post_type ) {
  1127 	return (bool) get_post_type_object( $post_type );
   976 	return (bool) get_post_type_object( $post_type );
  1128 }
   977 }
  1129 
   978 
  1130 /**
   979 /**
  1131  * Retrieve the post type of the current post or of a given post.
   980  * Retrieves the post type of the current post or of a given post.
  1132  *
   981  *
  1133  * @since 2.1.0
   982  * @since 2.1.0
  1134  *
   983  *
  1135  * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post.
   984  * @param int|WP_Post|null $post Optional. Post ID or post object. Default is global $post.
  1136  * @return string|false Post type on success, false on failure.
   985  * @return string|false          Post type on success, false on failure.
  1137  */
   986  */
  1138 function get_post_type( $post = null ) {
   987 function get_post_type( $post = null ) {
  1139 	if ( $post = get_post( $post ) )
   988 	if ( $post = get_post( $post ) )
  1140 		return $post->post_type;
   989 		return $post->post_type;
  1141 
   990 
  1142 	return false;
   991 	return false;
  1143 }
   992 }
  1144 
   993 
  1145 /**
   994 /**
  1146  * Retrieve a post type object by name.
   995  * Retrieves a post type object by name.
  1147  *
   996  *
  1148  * @since 3.0.0
   997  * @since 3.0.0
       
   998  * @since 4.6.0 Object returned is now an instance of WP_Post_Type.
  1149  *
   999  *
  1150  * @global array $wp_post_types List of post types.
  1000  * @global array $wp_post_types List of post types.
  1151  *
  1001  *
  1152  * @see register_post_type()
  1002  * @see register_post_type()
  1153  *
  1003  *
  1154  * @param string $post_type The name of a registered post type.
  1004  * @param string $post_type The name of a registered post type.
  1155  * @return object A post type object.
  1005  * @return WP_Post_Type|null WP_Post_Type object if it exists, null otherwise.
  1156  */
  1006  */
  1157 function get_post_type_object( $post_type ) {
  1007 function get_post_type_object( $post_type ) {
  1158 	global $wp_post_types;
  1008 	global $wp_post_types;
  1159 
  1009 
  1160 	if ( empty($wp_post_types[$post_type]) )
  1010 	if ( ! is_scalar( $post_type ) || empty( $wp_post_types[ $post_type ] ) ) {
  1161 		return null;
  1011 		return null;
  1162 
  1012 	}
  1163 	return $wp_post_types[$post_type];
  1013 
       
  1014 	return $wp_post_types[ $post_type ];
  1164 }
  1015 }
  1165 
  1016 
  1166 /**
  1017 /**
  1167  * Get a list of all registered post type objects.
  1018  * Get a list of all registered post type objects.
  1168  *
  1019  *
  1176  *                               the post type objects. Default empty array.
  1027  *                               the post type objects. Default empty array.
  1177  * @param string       $output   Optional. The type of output to return. Accepts post type 'names'
  1028  * @param string       $output   Optional. The type of output to return. Accepts post type 'names'
  1178  *                               or 'objects'. Default 'names'.
  1029  *                               or 'objects'. Default 'names'.
  1179  * @param string       $operator Optional. The logical operation to perform. 'or' means only one
  1030  * @param string       $operator Optional. The logical operation to perform. 'or' means only one
  1180  *                               element from the array needs to match; 'and' means all elements
  1031  *                               element from the array needs to match; 'and' means all elements
  1181  *                               must match. Accepts 'or' or 'and'. Default 'and'.
  1032  *                               must match; 'not' means no elements may match. Default 'and'.
  1182  * @return array A list of post type names or objects.
  1033  * @return array A list of post type names or objects.
  1183  */
  1034  */
  1184 function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) {
  1035 function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) {
  1185 	global $wp_post_types;
  1036 	global $wp_post_types;
  1186 
  1037 
  1188 
  1039 
  1189 	return wp_filter_object_list($wp_post_types, $args, $operator, $field);
  1040 	return wp_filter_object_list($wp_post_types, $args, $operator, $field);
  1190 }
  1041 }
  1191 
  1042 
  1192 /**
  1043 /**
  1193  * Register a post type. Do not use before init.
  1044  * Registers a post type.
  1194  *
  1045  *
  1195  * A function for creating or modifying a post type based on the
  1046  * Note: Post type registrations should not be hooked before the
  1196  * parameters given. The function will accept an array (second optional
  1047  * {@see 'init'} action. Also, any taxonomy connections should be
  1197  * parameter), along with a string for the post type name.
  1048  * registered via the `$taxonomies` argument to ensure consistency
       
  1049  * when hooks such as {@see 'parse_query'} or {@see 'pre_get_posts'}
       
  1050  * are used.
       
  1051  *
       
  1052  * Post types can support any number of built-in core features such
       
  1053  * as meta boxes, custom fields, post thumbnails, post statuses,
       
  1054  * comments, and more. See the `$supports` argument for a complete
       
  1055  * list of supported features.
  1198  *
  1056  *
  1199  * @since 2.9.0
  1057  * @since 2.9.0
  1200  *
  1058  * @since 3.0.0 The `show_ui` argument is now enforced on the new post screen.
  1201  * @global array      $wp_post_types List of post types.
  1059  * @since 4.4.0 The `show_ui` argument is now enforced on the post type listing
  1202  * @global WP_Rewrite $wp_rewrite    Used for default feeds.
  1060  *              screen and post editing screen.
  1203  * @global WP         $wp            Used to add query vars.
  1061  * @since 4.6.0 Post type object returned is now an instance of WP_Post_Type.
  1204  *
  1062  * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class'
  1205  * @param string $post_type Post type key, must not exceed 20 characters.
  1063  *              arguments to register the post type in REST API.
       
  1064  *
       
  1065  * @global array $wp_post_types List of post types.
       
  1066  *
       
  1067  * @param string $post_type Post type key. Must not exceed 20 characters and may
       
  1068  *                          only contain lowercase alphanumeric characters, dashes,
       
  1069  *                          and underscores. See sanitize_key().
  1206  * @param array|string $args {
  1070  * @param array|string $args {
  1207  *     Array or string of arguments for registering a post type.
  1071  *     Array or string of arguments for registering a post type.
  1208  *
  1072  *
  1209  *     @type string      $label                Name of the post type shown in the menu. Usually plural.
  1073  *     @type string      $label                 Name of the post type shown in the menu. Usually plural.
  1210  *                                             Default is value of $labels['name'].
  1074  *                                              Default is value of $labels['name'].
  1211  *     @type array       $labels               An array of labels for this post type. If not set, post
  1075  *     @type array       $labels                An array of labels for this post type. If not set, post
  1212  *                                             labels are inherited for non-hierarchical types and page
  1076  *                                              labels are inherited for non-hierarchical types and page
  1213  *                                             labels for hierarchical ones. {@see get_post_type_labels()}.
  1077  *                                              labels for hierarchical ones. See get_post_type_labels() for a full
  1214  *     @type string      $description          A short descriptive summary of what the post type is.
  1078  *                                              list of supported labels.
  1215  *                                             Default empty.
  1079  *     @type string      $description           A short descriptive summary of what the post type is.
  1216  *     @type bool        $public               Whether a post type is intended for use publicly either via
  1080  *                                              Default empty.
  1217  *                                             the admin interface or by front-end users. While the default
  1081  *     @type bool        $public                Whether a post type is intended for use publicly either via
  1218  *                                             settings of $exclude_from_search, $publicly_queryable, $show_ui,
  1082  *                                              the admin interface or by front-end users. While the default
  1219  *                                             and $show_in_nav_menus are inherited from public, each does not
  1083  *                                              settings of $exclude_from_search, $publicly_queryable, $show_ui,
  1220  *                                             rely on this relationship and controls a very specific intention.
  1084  *                                              and $show_in_nav_menus are inherited from public, each does not
  1221  *                                             Default false.
  1085  *                                              rely on this relationship and controls a very specific intention.
  1222  *     @type bool        $hierarchical         Whether the post type is hierarchical (e.g. page). Default false.
  1086  *                                              Default false.
  1223  *     @type bool        $exclude_from_search  Whether to exclude posts with this post type from front end search
  1087  *     @type bool        $hierarchical          Whether the post type is hierarchical (e.g. page). Default false.
  1224  *                                             results. Default is the opposite value of $public.
  1088  *     @type bool        $exclude_from_search   Whether to exclude posts with this post type from front end search
  1225  *     @type bool        $publicly_queryable   Whether queries can be performed on the front end for the post type
  1089  *                                              results. Default is the opposite value of $public.
  1226  *                                             as part of {@see parse_request()}. Endpoints would include:
  1090  *     @type bool        $publicly_queryable    Whether queries can be performed on the front end for the post type
  1227  *                                             * ?post_type={post_type_key}
  1091  *                                              as part of parse_request(). Endpoints would include:
  1228  *                                             * ?{post_type_key}={single_post_slug}
  1092  *                                              * ?post_type={post_type_key}
  1229  *                                             * ?{post_type_query_var}={single_post_slug}
  1093  *                                              * ?{post_type_key}={single_post_slug}
  1230  *                                             If not set, the default is inherited from $public.
  1094  *                                              * ?{post_type_query_var}={single_post_slug}
  1231  *     @type bool        $show_ui              Whether to generate a default UI for managing this post type in the
  1095  *                                              If not set, the default is inherited from $public.
  1232  *                                             admin. Default is value of $public.
  1096  *     @type bool        $show_ui               Whether to generate and allow a UI for managing this post type in the
  1233  *     @type bool        $show_in_menu         Where to show the post type in the admin menu. To work, $show_ui
  1097  *                                              admin. Default is value of $public.
  1234  *                                             must be true. If true, the post type is shown in its own top level
  1098  *     @type bool        $show_in_menu          Where to show the post type in the admin menu. To work, $show_ui
  1235  *                                             menu. If false, no menu is shown. If a string of an existing top
  1099  *                                              must be true. If true, the post type is shown in its own top level
  1236  *                                             level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post
  1100  *                                              menu. If false, no menu is shown. If a string of an existing top
  1237  *                                             type will be placed as a sub-menu of that.
  1101  *                                              level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post
  1238  *                                             Default is value of $show_ui.
  1102  *                                              type will be placed as a sub-menu of that.
  1239  *     @type bool        $show_in_nav_menus    Makes this post type available for selection in navigation menus.
  1103  *                                              Default is value of $show_ui.
  1240  *                                             Default is value $public.
  1104  *     @type bool        $show_in_nav_menus     Makes this post type available for selection in navigation menus.
  1241  *     @type bool        $show_in_admin_bar    Makes this post type available via the admin bar. Default is value
  1105  *                                              Default is value $public.
  1242  *                                             of $show_in_menu.
  1106  *     @type bool        $show_in_admin_bar     Makes this post type available via the admin bar. Default is value
  1243  *     @type int         $menu_position        The position in the menu order the post type should appear. To work,
  1107  *                                              of $show_in_menu.
  1244  *                                             $show_in_menu must be true. Default null (at the bottom).
  1108  *     @type bool        $show_in_rest          Whether to add the post type route in the REST API 'wp/v2' namespace.
  1245  *     @type string      $menu_icon            The url to the icon to be used for this menu. Pass a base64-encoded
  1109  *     @type string      $rest_base             To change the base url of REST API route. Default is $post_type.
  1246  *                                             SVG using a data URI, which will be colored to match the color scheme
  1110  *     @type string      $rest_controller_class REST API Controller class name. Default is 'WP_REST_Posts_Controller'.
  1247  *                                             -- this should begin with 'data:image/svg+xml;base64,'. Pass the name
  1111  *     @type int         $menu_position         The position in the menu order the post type should appear. To work,
  1248  *                                             of a Dashicons helper class to use a font icon, e.g.
  1112  *                                              $show_in_menu must be true. Default null (at the bottom).
  1249  *                                             'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty
  1113  *     @type string      $menu_icon             The url to the icon to be used for this menu. Pass a base64-encoded
  1250  *                                             so an icon can be added via CSS. Defaults to use the posts icon.
  1114  *                                              SVG using a data URI, which will be colored to match the color scheme
  1251  *     @type string      $capability_type      The string to use to build the read, edit, and delete capabilities.
  1115  *                                              -- this should begin with 'data:image/svg+xml;base64,'. Pass the name
  1252  *                                             May be passed as an array to allow for alternative plurals when using
  1116  *                                              of a Dashicons helper class to use a font icon, e.g.
  1253  *                                             this argument as a base to construct the capabilities, e.g.
  1117  *                                              'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty
  1254  *                                             array('story', 'stories'). Default 'post'.
  1118  *                                              so an icon can be added via CSS. Defaults to use the posts icon.
  1255  *     @type array       $capabilities         Array of capabilities for this post type. $capability_type is used
  1119  *     @type string      $capability_type       The string to use to build the read, edit, and delete capabilities.
  1256  *                                             as a base to construct capabilities by default.
  1120  *                                              May be passed as an array to allow for alternative plurals when using
  1257  *                                             {@see get_post_type_capabilities()}.
  1121  *                                              this argument as a base to construct the capabilities, e.g.
  1258  *     @type bool        $map_meta_cap         Whether to use the internal default meta capability handling.
  1122  *                                              array('story', 'stories'). Default 'post'.
  1259  *                                             Default false.
  1123  *     @type array       $capabilities          Array of capabilities for this post type. $capability_type is used
  1260  *     @type array       $supports             An alias for calling {@see add_post_type_support()} directly.
  1124  *                                              as a base to construct capabilities by default.
  1261  *                                             Defaults to array containing 'title' & 'editor'.
  1125  *                                              See get_post_type_capabilities().
  1262  *     @type callback    $register_meta_box_cb Provide a callback function that sets up the meta boxes for the
  1126  *     @type bool        $map_meta_cap          Whether to use the internal default meta capability handling.
  1263  *                                             edit form. Do remove_meta_box() and add_meta_box() calls in the
  1127  *                                              Default false.
  1264  *                                             callback. Default null.
  1128  *     @type array       $supports              Core feature(s) the post type supports. Serves as an alias for calling
  1265  *     @type array       $taxonomies           An array of taxonomy identifiers that will be registered for the
  1129  *                                              add_post_type_support() directly. Core features include 'title',
  1266  *                                             post type. Taxonomies can be registered later with
  1130  *                                              'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt',
  1267  *                                             {@see register_taxonomy()} or {@see register_taxonomy_for_object_type()}.
  1131  *                                              'page-attributes', 'thumbnail', 'custom-fields', and 'post-formats'.
  1268  *                                             Default empty array.
  1132  *                                              Additionally, the 'revisions' feature dictates whether the post type
  1269  *     @type bool|string $has_archive          Whether there should be post type archives, or if a string, the
  1133  *                                              will store revisions, and the 'comments' feature dictates whether the
  1270  *                                             archive slug to use. Will generate the proper rewrite rules if
  1134  *                                              comments count will show on the edit screen. Defaults is an array
  1271  *                                             $rewrite is enabled. Default false.
  1135  *                                              containing 'title' and 'editor'.
       
  1136  *     @type callable    $register_meta_box_cb  Provide a callback function that sets up the meta boxes for the
       
  1137  *                                              edit form. Do remove_meta_box() and add_meta_box() calls in the
       
  1138  *                                              callback. Default null.
       
  1139  *     @type array       $taxonomies            An array of taxonomy identifiers that will be registered for the
       
  1140  *                                              post type. Taxonomies can be registered later with register_taxonomy()
       
  1141  *                                              or register_taxonomy_for_object_type().
       
  1142  *                                              Default empty array.
       
  1143  *     @type bool|string $has_archive           Whether there should be post type archives, or if a string, the
       
  1144  *                                              archive slug to use. Will generate the proper rewrite rules if
       
  1145  *                                              $rewrite is enabled. Default false.
  1272  *     @type bool|array  $rewrite              {
  1146  *     @type bool|array  $rewrite              {
  1273  *         Triggers the handling of rewrites for this post type. To prevent rewrite, set to false.
  1147  *         Triggers the handling of rewrites for this post type. To prevent rewrite, set to false.
  1274  *         Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be
  1148  *         Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be
  1275  *         passed with any of these keys:
  1149  *         passed with any of these keys:
  1276  *
  1150  *
  1282  *         @type bool   $pages      Whether the permastruct should provide for pagination. Default true.
  1156  *         @type bool   $pages      Whether the permastruct should provide for pagination. Default true.
  1283  *         @type const  $ep_mask    Endpoint mask to assign. If not specified and permalink_epmask is set,
  1157  *         @type const  $ep_mask    Endpoint mask to assign. If not specified and permalink_epmask is set,
  1284  *                                  inherits from $permalink_epmask. If not specified and permalink_epmask
  1158  *                                  inherits from $permalink_epmask. If not specified and permalink_epmask
  1285  *                                  is not set, defaults to EP_PERMALINK.
  1159  *                                  is not set, defaults to EP_PERMALINK.
  1286  *     }
  1160  *     }
  1287  *     @type string|bool $query_var            Sets the query_var key for this post type. Defaults to $post_type
  1161  *     @type string|bool $query_var             Sets the query_var key for this post type. Defaults to $post_type
  1288  *                                             key. If false, a post type cannot be loaded at
  1162  *                                              key. If false, a post type cannot be loaded at
  1289  *                                             ?{query_var}={post_slug}. If specified as a string, the query
  1163  *                                              ?{query_var}={post_slug}. If specified as a string, the query
  1290  *                                             ?{query_var_string}={post_slug} will be valid.
  1164  *                                              ?{query_var_string}={post_slug} will be valid.
  1291  *     @type bool        $can_export           Whether to allow this post type to be exported. Default true.
  1165  *     @type bool        $can_export            Whether to allow this post type to be exported. Default true.
  1292  *     @type bool        $delete_with_user     Whether to delete posts of this type when deleting a user. If true,
  1166  *     @type bool        $delete_with_user      Whether to delete posts of this type when deleting a user. If true,
  1293  *                                             posts of this type belonging to the user will be moved to trash
  1167  *                                              posts of this type belonging to the user will be moved to trash
  1294  *                                             when then user is deleted. If false, posts of this type belonging
  1168  *                                              when then user is deleted. If false, posts of this type belonging
  1295  *                                             to the user will *not* be trashed or deleted. If not set (the default),
  1169  *                                              to the user will *not* be trashed or deleted. If not set (the default),
  1296  *                                             posts are trashed if post_type_supports('author'). Otherwise posts
  1170  *                                              posts are trashed if post_type_supports('author'). Otherwise posts
  1297  *                                             are not trashed or deleted. Default null.
  1171  *                                              are not trashed or deleted. Default null.
  1298  *     @type bool        $_builtin             FOR INTERNAL USE ONLY! True if this post type is a native or
  1172  *     @type bool        $_builtin              FOR INTERNAL USE ONLY! True if this post type is a native or
  1299  *                                             "built-in" post_type. Default false.
  1173  *                                              "built-in" post_type. Default false.
  1300  *     @type string      $_edit_link           FOR INTERNAL USE ONLY! URL segment to use for edit link of
  1174  *     @type string      $_edit_link            FOR INTERNAL USE ONLY! URL segment to use for edit link of
  1301  *                                             this post type. Default 'post.php?post=%d'.
  1175  *                                              this post type. Default 'post.php?post=%d'.
  1302  * }
  1176  * }
  1303  * @return object|WP_Error The registered post type object, or an error object.
  1177  * @return WP_Post_Type|WP_Error The registered post type object, or an error object.
  1304  */
  1178  */
  1305 function register_post_type( $post_type, $args = array() ) {
  1179 function register_post_type( $post_type, $args = array() ) {
  1306 	global $wp_post_types, $wp_rewrite, $wp;
  1180 	global $wp_post_types;
  1307 
  1181 
  1308 	if ( ! is_array( $wp_post_types ) )
  1182 	if ( ! is_array( $wp_post_types ) ) {
  1309 		$wp_post_types = array();
  1183 		$wp_post_types = array();
  1310 
  1184 	}
  1311 	// Args prefixed with an underscore are reserved for internal use.
  1185 
  1312 	$defaults = array(
  1186 	// Sanitize post type name
  1313 		'labels'               => array(),
       
  1314 		'description'          => '',
       
  1315 		'public'               => false,
       
  1316 		'hierarchical'         => false,
       
  1317 		'exclude_from_search'  => null,
       
  1318 		'publicly_queryable'   => null,
       
  1319 		'show_ui'              => null,
       
  1320 		'show_in_menu'         => null,
       
  1321 		'show_in_nav_menus'    => null,
       
  1322 		'show_in_admin_bar'    => null,
       
  1323 		'menu_position'        => null,
       
  1324 		'menu_icon'            => null,
       
  1325 		'capability_type'      => 'post',
       
  1326 		'capabilities'         => array(),
       
  1327 		'map_meta_cap'         => null,
       
  1328 		'supports'             => array(),
       
  1329 		'register_meta_box_cb' => null,
       
  1330 		'taxonomies'           => array(),
       
  1331 		'has_archive'          => false,
       
  1332 		'rewrite'              => true,
       
  1333 		'query_var'            => true,
       
  1334 		'can_export'           => true,
       
  1335 		'delete_with_user'     => null,
       
  1336 		'_builtin'             => false,
       
  1337 		'_edit_link'           => 'post.php?post=%d',
       
  1338 	);
       
  1339 	$args = wp_parse_args( $args, $defaults );
       
  1340 	$args = (object) $args;
       
  1341 
       
  1342 	$post_type = sanitize_key( $post_type );
  1187 	$post_type = sanitize_key( $post_type );
  1343 	$args->name = $post_type;
       
  1344 
  1188 
  1345 	if ( empty( $post_type ) || strlen( $post_type ) > 20 ) {
  1189 	if ( empty( $post_type ) || strlen( $post_type ) > 20 ) {
  1346 		_doing_it_wrong( __FUNCTION__, __( 'Post type names must be between 1 and 20 characters in length.' ), '4.2' );
  1190 		_doing_it_wrong( __FUNCTION__, __( 'Post type names must be between 1 and 20 characters in length.' ), '4.2.0' );
  1347 		return new WP_Error( 'post_type_length_invalid', __( 'Post type names must be between 1 and 20 characters in length.' ) );
  1191 		return new WP_Error( 'post_type_length_invalid', __( 'Post type names must be between 1 and 20 characters in length.' ) );
  1348 	}
  1192 	}
  1349 
  1193 
  1350 	// If not set, default to the setting for public.
  1194 	$post_type_object = new WP_Post_Type( $post_type, $args );
  1351 	if ( null === $args->publicly_queryable )
  1195 	$post_type_object->add_supports();
  1352 		$args->publicly_queryable = $args->public;
  1196 	$post_type_object->add_rewrite_rules();
  1353 
  1197 	$post_type_object->register_meta_boxes();
  1354 	// If not set, default to the setting for public.
  1198 
  1355 	if ( null === $args->show_ui )
  1199 	$wp_post_types[ $post_type ] = $post_type_object;
  1356 		$args->show_ui = $args->public;
  1200 
  1357 
  1201 	$post_type_object->add_hooks();
  1358 	// If not set, default to the setting for show_ui.
  1202 	$post_type_object->register_taxonomies();
  1359 	if ( null === $args->show_in_menu || ! $args->show_ui )
       
  1360 		$args->show_in_menu = $args->show_ui;
       
  1361 
       
  1362 	// If not set, default to the whether the full UI is shown.
       
  1363 	if ( null === $args->show_in_admin_bar )
       
  1364 		$args->show_in_admin_bar = (bool) $args->show_in_menu;
       
  1365 
       
  1366 	// If not set, default to the setting for public.
       
  1367 	if ( null === $args->show_in_nav_menus )
       
  1368 		$args->show_in_nav_menus = $args->public;
       
  1369 
       
  1370 	// If not set, default to true if not public, false if public.
       
  1371 	if ( null === $args->exclude_from_search )
       
  1372 		$args->exclude_from_search = !$args->public;
       
  1373 
       
  1374 	// Back compat with quirky handling in version 3.0. #14122.
       
  1375 	if ( empty( $args->capabilities ) && null === $args->map_meta_cap && in_array( $args->capability_type, array( 'post', 'page' ) ) )
       
  1376 		$args->map_meta_cap = true;
       
  1377 
       
  1378 	// If not set, default to false.
       
  1379 	if ( null === $args->map_meta_cap )
       
  1380 		$args->map_meta_cap = false;
       
  1381 
       
  1382 	$args->cap = get_post_type_capabilities( $args );
       
  1383 	unset( $args->capabilities );
       
  1384 
       
  1385 	if ( is_array( $args->capability_type ) )
       
  1386 		$args->capability_type = $args->capability_type[0];
       
  1387 
       
  1388 	if ( ! empty( $args->supports ) ) {
       
  1389 		add_post_type_support( $post_type, $args->supports );
       
  1390 		unset( $args->supports );
       
  1391 	} elseif ( false !== $args->supports ) {
       
  1392 		// Add default features
       
  1393 		add_post_type_support( $post_type, array( 'title', 'editor' ) );
       
  1394 	}
       
  1395 
       
  1396 	if ( false !== $args->query_var && ! empty( $wp ) ) {
       
  1397 		if ( true === $args->query_var )
       
  1398 			$args->query_var = $post_type;
       
  1399 		else
       
  1400 			$args->query_var = sanitize_title_with_dashes( $args->query_var );
       
  1401 		$wp->add_query_var( $args->query_var );
       
  1402 	}
       
  1403 
       
  1404 	if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
       
  1405 		if ( ! is_array( $args->rewrite ) )
       
  1406 			$args->rewrite = array();
       
  1407 		if ( empty( $args->rewrite['slug'] ) )
       
  1408 			$args->rewrite['slug'] = $post_type;
       
  1409 		if ( ! isset( $args->rewrite['with_front'] ) )
       
  1410 			$args->rewrite['with_front'] = true;
       
  1411 		if ( ! isset( $args->rewrite['pages'] ) )
       
  1412 			$args->rewrite['pages'] = true;
       
  1413 		if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
       
  1414 			$args->rewrite['feeds'] = (bool) $args->has_archive;
       
  1415 		if ( ! isset( $args->rewrite['ep_mask'] ) ) {
       
  1416 			if ( isset( $args->permalink_epmask ) )
       
  1417 				$args->rewrite['ep_mask'] = $args->permalink_epmask;
       
  1418 			else
       
  1419 				$args->rewrite['ep_mask'] = EP_PERMALINK;
       
  1420 		}
       
  1421 
       
  1422 		if ( $args->hierarchical )
       
  1423 			add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
       
  1424 		else
       
  1425 			add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );
       
  1426 
       
  1427 		if ( $args->has_archive ) {
       
  1428 			$archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
       
  1429 			if ( $args->rewrite['with_front'] )
       
  1430 				$archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
       
  1431 			else
       
  1432 				$archive_slug = $wp_rewrite->root . $archive_slug;
       
  1433 
       
  1434 			add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
       
  1435 			if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
       
  1436 				$feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
       
  1437 				add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
       
  1438 				add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
       
  1439 			}
       
  1440 			if ( $args->rewrite['pages'] )
       
  1441 				add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
       
  1442 		}
       
  1443 
       
  1444 		$permastruct_args = $args->rewrite;
       
  1445 		$permastruct_args['feed'] = $permastruct_args['feeds'];
       
  1446 		add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
       
  1447 	}
       
  1448 
       
  1449 	// Register the post type meta box if a custom callback was specified.
       
  1450 	if ( $args->register_meta_box_cb )
       
  1451 		add_action( 'add_meta_boxes_' . $post_type, $args->register_meta_box_cb, 10, 1 );
       
  1452 
       
  1453 	$args->labels = get_post_type_labels( $args );
       
  1454 	$args->label = $args->labels->name;
       
  1455 
       
  1456 	$wp_post_types[ $post_type ] = $args;
       
  1457 
       
  1458 	add_action( 'future_' . $post_type, '_future_post_hook', 5, 2 );
       
  1459 
       
  1460 	foreach ( $args->taxonomies as $taxonomy ) {
       
  1461 		register_taxonomy_for_object_type( $taxonomy, $post_type );
       
  1462 	}
       
  1463 
  1203 
  1464 	/**
  1204 	/**
  1465 	 * Fires after a post type is registered.
  1205 	 * Fires after a post type is registered.
  1466 	 *
  1206 	 *
  1467 	 * @since 3.3.0
  1207 	 * @since 3.3.0
  1468 	 *
  1208 	 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
  1469 	 * @param string $post_type Post type.
  1209 	 *
  1470 	 * @param object $args      Arguments used to register the post type.
  1210 	 * @param string       $post_type        Post type.
       
  1211 	 * @param WP_Post_Type $post_type_object Arguments used to register the post type.
  1471 	 */
  1212 	 */
  1472 	do_action( 'registered_post_type', $post_type, $args );
  1213 	do_action( 'registered_post_type', $post_type, $post_type_object );
  1473 
  1214 
  1474 	return $args;
  1215 	return $post_type_object;
       
  1216 }
       
  1217 
       
  1218 /**
       
  1219  * Unregisters a post type.
       
  1220  *
       
  1221  * Can not be used to unregister built-in post types.
       
  1222  *
       
  1223  * @since 4.5.0
       
  1224  *
       
  1225  * @global array $wp_post_types List of post types.
       
  1226  *
       
  1227  * @param string $post_type Post type to unregister.
       
  1228  * @return bool|WP_Error True on success, WP_Error on failure or if the post type doesn't exist.
       
  1229  */
       
  1230 function unregister_post_type( $post_type ) {
       
  1231 	global $wp_post_types;
       
  1232 
       
  1233 	if ( ! post_type_exists( $post_type ) ) {
       
  1234 		return new WP_Error( 'invalid_post_type', __( 'Invalid post type.' ) );
       
  1235 	}
       
  1236 
       
  1237 	$post_type_object = get_post_type_object( $post_type );
       
  1238 
       
  1239 	// Do not allow unregistering internal post types.
       
  1240 	if ( $post_type_object->_builtin ) {
       
  1241 		return new WP_Error( 'invalid_post_type', __( 'Unregistering a built-in post type is not allowed' ) );
       
  1242 	}
       
  1243 
       
  1244 	$post_type_object->remove_supports();
       
  1245 	$post_type_object->remove_rewrite_rules();
       
  1246 	$post_type_object->unregister_meta_boxes();
       
  1247 	$post_type_object->remove_hooks();
       
  1248 	$post_type_object->unregister_taxonomies();
       
  1249 
       
  1250 	unset( $wp_post_types[ $post_type ] );
       
  1251 
       
  1252 	/**
       
  1253 	 * Fires after a post type was unregistered.
       
  1254 	 *
       
  1255 	 * @since 4.5.0
       
  1256 	 *
       
  1257 	 * @param string $post_type Post type key.
       
  1258 	 */
       
  1259 	do_action( 'unregistered_post_type', $post_type );
       
  1260 
       
  1261 	return true;
  1475 }
  1262 }
  1476 
  1263 
  1477 /**
  1264 /**
  1478  * Build an object with all post type capabilities out of a post type object
  1265  * Build an object with all post type capabilities out of a post type object
  1479  *
  1266  *
  1525  *
  1312  *
  1526  * @see register_post_type()
  1313  * @see register_post_type()
  1527  * @see map_meta_cap()
  1314  * @see map_meta_cap()
  1528  *
  1315  *
  1529  * @param object $args Post type registration arguments.
  1316  * @param object $args Post type registration arguments.
  1530  * @return object object with all the capabilities as member variables.
  1317  * @return object Object with all the capabilities as member variables.
  1531  */
  1318  */
  1532 function get_post_type_capabilities( $args ) {
  1319 function get_post_type_capabilities( $args ) {
  1533 	if ( ! is_array( $args->capability_type ) )
  1320 	if ( ! is_array( $args->capability_type ) )
  1534 		$args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
  1321 		$args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
  1535 
  1322 
  1579  * Store or return a list of post type meta caps for map_meta_cap().
  1366  * Store or return a list of post type meta caps for map_meta_cap().
  1580  *
  1367  *
  1581  * @since 3.1.0
  1368  * @since 3.1.0
  1582  * @access private
  1369  * @access private
  1583  *
  1370  *
  1584  * @param null|array $capabilities Post type meta capabilities.
  1371  * @global array $post_type_meta_caps Used to store meta capabilities.
       
  1372  *
       
  1373  * @param array $capabilities Post type meta capabilities.
  1585  */
  1374  */
  1586 function _post_type_meta_capabilities( $capabilities = null ) {
  1375 function _post_type_meta_capabilities( $capabilities = null ) {
  1587 	static $meta_caps = array();
  1376 	global $post_type_meta_caps;
  1588 	if ( null === $capabilities )
  1377 
  1589 		return $meta_caps;
       
  1590 	foreach ( $capabilities as $core => $custom ) {
  1378 	foreach ( $capabilities as $core => $custom ) {
  1591 		if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
  1379 		if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) ) {
  1592 			$meta_caps[ $custom ] = $core;
  1380 			$post_type_meta_caps[ $custom ] = $core;
  1593 	}
  1381 		}
  1594 }
  1382 	}
  1595 
  1383 }
  1596 /**
  1384 
  1597  * Build an object with all post type labels out of a post type object
  1385 /**
       
  1386  * Builds an object with all post type labels out of a post type object.
  1598  *
  1387  *
  1599  * Accepted keys of the label array in the post type object:
  1388  * Accepted keys of the label array in the post type object:
  1600  *
  1389  *
  1601  * - name - general name for the post type, usually plural. The same and overridden
  1390  * - `name` - General name for the post type, usually plural. The same and overridden
  1602  *          by $post_type_object->label. Default is Posts/Pages
  1391  *          by `$post_type_object->label`. Default is 'Posts' / 'Pages'.
  1603  * - singular_name - name for one object of this post type. Default is Post/Page
  1392  * - `singular_name` - Name for one object of this post type. Default is 'Post' / 'Page'.
  1604  * - add_new - Default is Add New for both hierarchical and non-hierarchical types.
  1393  * - `add_new` - Default is 'Add New' for both hierarchical and non-hierarchical types.
  1605  *             When internationalizing this string, please use a gettext context
  1394  *             When internationalizing this string, please use a {@link https://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context gettext context}
  1606  *             {@link https://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context}
  1395  *             matching your post type. Example: `_x( 'Add New', 'product', 'textdomain' );`.
  1607  *             matching your post type. Example: `_x( 'Add New', 'product' );`.
  1396  * - `add_new_item` - Label for adding a new singular item. Default is 'Add New Post' / 'Add New Page'.
  1608  * - add_new_item - Default is Add New Post/Add New Page.
  1397  * - `edit_item` - Label for editing a singular item. Default is 'Edit Post' / 'Edit Page'.
  1609  * - edit_item - Default is Edit Post/Edit Page.
  1398  * - `new_item` - Label for the new item page title. Default is 'New Post' / 'New Page'.
  1610  * - new_item - Default is New Post/New Page.
  1399  * - `view_item` - Label for viewing a singular item. Default is 'View Post' / 'View Page'.
  1611  * - view_item - Default is View Post/View Page.
  1400  * - `view_items` - Label for viewing post type archives. Default is 'View Posts' / 'View Pages'.
  1612  * - search_items - Default is Search Posts/Search Pages.
  1401  * - `search_items` - Label for searching plural items. Default is 'Search Posts' / 'Search Pages'.
  1613  * - not_found - Default is No posts found/No pages found.
  1402  * - `not_found` - Label used when no items are found. Default is 'No posts found' / 'No pages found'.
  1614  * - not_found_in_trash - Default is No posts found in Trash/No pages found in Trash.
  1403  * - `not_found_in_trash` - Label used when no items are in the trash. Default is 'No posts found in Trash' /
  1615  * - parent_item_colon - This string isn't used on non-hierarchical types. In hierarchical
  1404  *                        'No pages found in Trash'.
  1616  *                       ones the default is 'Parent Page:'.
  1405  * - `parent_item_colon` - Label used to prefix parents of hierarchical items. Not used on non-hierarchical
  1617  * - all_items - String for the submenu. Default is All Posts/All Pages.
  1406  *                       post types. Default is 'Parent Page:'.
  1618  * - menu_name - Default is the same as `name`.
  1407  * - `all_items` - Label to signify all items in a submenu link. Default is 'All Posts' / 'All Pages'.
       
  1408  * - `archives` - Label for archives in nav menus. Default is 'Post Archives' / 'Page Archives'.
       
  1409  * - `attributes` - Label for the attributes meta box. Default is 'Post Attributes' / 'Page Attributes'.
       
  1410  * - `insert_into_item` - Label for the media frame button. Default is 'Insert into post' / 'Insert into page'.
       
  1411  * - `uploaded_to_this_item` - Label for the media frame filter. Default is 'Uploaded to this post' /
       
  1412  *                           'Uploaded to this page'.
       
  1413  * - `featured_image` - Label for the Featured Image meta box title. Default is 'Featured Image'.
       
  1414  * - `set_featured_image` - Label for setting the featured image. Default is 'Set featured image'.
       
  1415  * - `remove_featured_image` - Label for removing the featured image. Default is 'Remove featured image'.
       
  1416  * - `use_featured_image` - Label in the media frame for using a featured image. Default is 'Use as featured image'.
       
  1417  * - `menu_name` - Label for the menu name. Default is the same as `name`.
       
  1418  * - `filter_items_list` - Label for the table views hidden heading. Default is 'Filter posts list' /
       
  1419  *                       'Filter pages list'.
       
  1420  * - `items_list_navigation` - Label for the table pagination hidden heading. Default is 'Posts list navigation' /
       
  1421  *                           'Pages list navigation'.
       
  1422  * - `items_list` - Label for the table hidden heading. Default is 'Posts list' / 'Pages list'.
  1619  *
  1423  *
  1620  * Above, the first default value is for non-hierarchical post types (like posts)
  1424  * Above, the first default value is for non-hierarchical post types (like posts)
  1621  * and the second one is for hierarchical post types (like pages).
  1425  * and the second one is for hierarchical post types (like pages).
  1622  *
  1426  *
       
  1427  * Note: To set labels used in post type admin notices, see the {@see 'post_updated_messages'} filter.
       
  1428  *
  1623  * @since 3.0.0
  1429  * @since 3.0.0
       
  1430  * @since 4.3.0 Added the `featured_image`, `set_featured_image`, `remove_featured_image`,
       
  1431  *              and `use_featured_image` labels.
       
  1432  * @since 4.4.0 Added the `archives`, `insert_into_item`, `uploaded_to_this_item`, `filter_items_list`,
       
  1433  *              `items_list_navigation`, and `items_list` labels.
       
  1434  * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
       
  1435  * @since 4.7.0 Added the `view_items` and `attributes` labels.
       
  1436  *
  1624  * @access private
  1437  * @access private
  1625  *
  1438  *
  1626  * @param object $post_type_object Post type object.
  1439  * @param object|WP_Post_Type $post_type_object Post type object.
  1627  * @return object object with all the labels as member variables.
  1440  * @return object Object with all the labels as member variables.
  1628  */
  1441  */
  1629 function get_post_type_labels( $post_type_object ) {
  1442 function get_post_type_labels( $post_type_object ) {
  1630 	$nohier_vs_hier_defaults = array(
  1443 	$nohier_vs_hier_defaults = array(
  1631 		'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
  1444 		'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
  1632 		'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
  1445 		'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
  1633 		'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
  1446 		'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
  1634 		'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
  1447 		'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
  1635 		'edit_item' => array( __('Edit Post'), __('Edit Page') ),
  1448 		'edit_item' => array( __('Edit Post'), __('Edit Page') ),
  1636 		'new_item' => array( __('New Post'), __('New Page') ),
  1449 		'new_item' => array( __('New Post'), __('New Page') ),
  1637 		'view_item' => array( __('View Post'), __('View Page') ),
  1450 		'view_item' => array( __('View Post'), __('View Page') ),
       
  1451 		'view_items' => array( __('View Posts'), __('View Pages') ),
  1638 		'search_items' => array( __('Search Posts'), __('Search Pages') ),
  1452 		'search_items' => array( __('Search Posts'), __('Search Pages') ),
  1639 		'not_found' => array( __('No posts found.'), __('No pages found.') ),
  1453 		'not_found' => array( __('No posts found.'), __('No pages found.') ),
  1640 		'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
  1454 		'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
  1641 		'parent_item_colon' => array( null, __('Parent Page:') ),
  1455 		'parent_item_colon' => array( null, __('Parent Page:') ),
  1642 		'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) )
  1456 		'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) ),
       
  1457 		'archives' => array( __( 'Post Archives' ), __( 'Page Archives' ) ),
       
  1458 		'attributes' => array( __( 'Post Attributes' ), __( 'Page Attributes' ) ),
       
  1459 		'insert_into_item' => array( __( 'Insert into post' ), __( 'Insert into page' ) ),
       
  1460 		'uploaded_to_this_item' => array( __( 'Uploaded to this post' ), __( 'Uploaded to this page' ) ),
       
  1461 		'featured_image' => array( _x( 'Featured Image', 'post' ), _x( 'Featured Image', 'page' ) ),
       
  1462 		'set_featured_image' => array( _x( 'Set featured image', 'post' ), _x( 'Set featured image', 'page' ) ),
       
  1463 		'remove_featured_image' => array( _x( 'Remove featured image', 'post' ), _x( 'Remove featured image', 'page' ) ),
       
  1464 		'use_featured_image' => array( _x( 'Use as featured image', 'post' ), _x( 'Use as featured image', 'page' ) ),
       
  1465 		'filter_items_list' => array( __( 'Filter posts list' ), __( 'Filter pages list' ) ),
       
  1466 		'items_list_navigation' => array( __( 'Posts list navigation' ), __( 'Pages list navigation' ) ),
       
  1467 		'items_list' => array( __( 'Posts list' ), __( 'Pages list' ) ),
  1643 	);
  1468 	);
  1644 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
  1469 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
  1645 
  1470 
  1646 	$labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
  1471 	$labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
  1647 
  1472 
  1648 	$post_type = $post_type_object->name;
  1473 	$post_type = $post_type_object->name;
  1649 
  1474 
       
  1475 	$default_labels = clone $labels;
       
  1476 
  1650 	/**
  1477 	/**
  1651 	 * Filter the labels of a specific post type.
  1478 	 * Filters the labels of a specific post type.
  1652 	 *
  1479 	 *
  1653 	 * The dynamic portion of the hook name, `$post_type`, refers to
  1480 	 * The dynamic portion of the hook name, `$post_type`, refers to
  1654 	 * the post type slug.
  1481 	 * the post type slug.
  1655 	 *
  1482 	 *
  1656 	 * @since 3.5.0
  1483 	 * @since 3.5.0
  1657 	 *
  1484 	 *
  1658 	 * @see get_post_type_labels() for the full list of labels.
  1485 	 * @see get_post_type_labels() for the full list of labels.
  1659 	 *
  1486 	 *
  1660 	 * @param array $labels Array of labels for the given post type.
  1487 	 * @param object $labels Object with labels for the post type as member variables.
  1661 	 */
  1488 	 */
  1662 	return apply_filters( "post_type_labels_{$post_type}", $labels );
  1489 	$labels = apply_filters( "post_type_labels_{$post_type}", $labels );
       
  1490 
       
  1491 	// Ensure that the filtered labels contain all required default values.
       
  1492 	$labels = (object) array_merge( (array) $default_labels, (array) $labels );
       
  1493 
       
  1494 	return $labels;
  1663 }
  1495 }
  1664 
  1496 
  1665 /**
  1497 /**
  1666  * Build an object with custom-something object (post type, taxonomy) labels
  1498  * Build an object with custom-something object (post type, taxonomy) labels
  1667  * out of a custom-something object
  1499  * out of a custom-something object
  1669  * @since 3.0.0
  1501  * @since 3.0.0
  1670  * @access private
  1502  * @access private
  1671  *
  1503  *
  1672  * @param object $object                  A custom-something object.
  1504  * @param object $object                  A custom-something object.
  1673  * @param array  $nohier_vs_hier_defaults Hierarchical vs non-hierarchical default labels.
  1505  * @param array  $nohier_vs_hier_defaults Hierarchical vs non-hierarchical default labels.
       
  1506  * @return object Object containing labels for the given custom-something object.
  1674  */
  1507  */
  1675 function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
  1508 function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
  1676 	$object->labels = (array) $object->labels;
  1509 	$object->labels = (array) $object->labels;
  1677 
  1510 
  1678 	if ( isset( $object->label ) && empty( $object->labels['name'] ) )
  1511 	if ( isset( $object->label ) && empty( $object->labels['name'] ) )
  1687 	if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
  1520 	if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
  1688 		$object->labels['menu_name'] = $object->labels['name'];
  1521 		$object->labels['menu_name'] = $object->labels['name'];
  1689 
  1522 
  1690 	if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
  1523 	if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
  1691 		$object->labels['all_items'] = $object->labels['menu_name'];
  1524 		$object->labels['all_items'] = $object->labels['menu_name'];
       
  1525 
       
  1526 	if ( !isset( $object->labels['archives'] ) && isset( $object->labels['all_items'] ) ) {
       
  1527 		$object->labels['archives'] = $object->labels['all_items'];
       
  1528 	}
  1692 
  1529 
  1693 	$defaults = array();
  1530 	$defaults = array();
  1694 	foreach ( $nohier_vs_hier_defaults as $key => $value ) {
  1531 	foreach ( $nohier_vs_hier_defaults as $key => $value ) {
  1695 		$defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
  1532 		$defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
  1696 	}
  1533 	}
  1697 	$labels = array_merge( $defaults, $object->labels );
  1534 	$labels = array_merge( $defaults, $object->labels );
  1698 	return (object)$labels;
  1535 	$object->labels = (object) $object->labels;
       
  1536 
       
  1537 	return (object) $labels;
  1699 }
  1538 }
  1700 
  1539 
  1701 /**
  1540 /**
  1702  * Add submenus for post types.
  1541  * Add submenus for post types.
  1703  *
  1542  *
  1726  * store revisions, and the 'comments' feature dictates whether the comments
  1565  * store revisions, and the 'comments' feature dictates whether the comments
  1727  * count will show on the edit screen.
  1566  * count will show on the edit screen.
  1728  *
  1567  *
  1729  * @since 3.0.0
  1568  * @since 3.0.0
  1730  *
  1569  *
       
  1570  * @global array $_wp_post_type_features
       
  1571  *
  1731  * @param string       $post_type The post type for which to add the feature.
  1572  * @param string       $post_type The post type for which to add the feature.
  1732  * @param string|array $feature   The feature being added, accepts an array of
  1573  * @param string|array $feature   The feature being added, accepts an array of
  1733  *                                feature strings or a single string.
  1574  *                                feature strings or a single string.
  1734  */
  1575  */
  1735 function add_post_type_support( $post_type, $feature ) {
  1576 function add_post_type_support( $post_type, $feature ) {
  1747 /**
  1588 /**
  1748  * Remove support for a feature from a post type.
  1589  * Remove support for a feature from a post type.
  1749  *
  1590  *
  1750  * @since 3.0.0
  1591  * @since 3.0.0
  1751  *
  1592  *
       
  1593  * @global array $_wp_post_type_features
       
  1594  *
  1752  * @param string $post_type The post type for which to remove the feature.
  1595  * @param string $post_type The post type for which to remove the feature.
  1753  * @param string $feature   The feature being removed.
  1596  * @param string $feature   The feature being removed.
  1754  */
  1597  */
  1755 function remove_post_type_support( $post_type, $feature ) {
  1598 function remove_post_type_support( $post_type, $feature ) {
  1756 	global $_wp_post_type_features;
  1599 	global $_wp_post_type_features;
  1757 
  1600 
  1758 	if ( isset( $_wp_post_type_features[$post_type][$feature] ) )
  1601 	unset( $_wp_post_type_features[ $post_type ][ $feature ] );
  1759 		unset( $_wp_post_type_features[$post_type][$feature] );
       
  1760 }
  1602 }
  1761 
  1603 
  1762 /**
  1604 /**
  1763  * Get all the post type features
  1605  * Get all the post type features
  1764  *
  1606  *
  1765  * @since 3.4.0
  1607  * @since 3.4.0
       
  1608  *
       
  1609  * @global array $_wp_post_type_features
  1766  *
  1610  *
  1767  * @param string $post_type The post type.
  1611  * @param string $post_type The post type.
  1768  * @return array Post type supports list.
  1612  * @return array Post type supports list.
  1769  */
  1613  */
  1770 function get_all_post_type_supports( $post_type ) {
  1614 function get_all_post_type_supports( $post_type ) {
  1779 /**
  1623 /**
  1780  * Check a post type's support for a given feature.
  1624  * Check a post type's support for a given feature.
  1781  *
  1625  *
  1782  * @since 3.0.0
  1626  * @since 3.0.0
  1783  *
  1627  *
       
  1628  * @global array $_wp_post_type_features
       
  1629  *
  1784  * @param string $post_type The post type being checked.
  1630  * @param string $post_type The post type being checked.
  1785  * @param string $feature the feature being checked.
  1631  * @param string $feature   The feature being checked.
  1786  * @return bool Whether the post type supports the given feature.
  1632  * @return bool Whether the post type supports the given feature.
  1787  */
  1633  */
  1788 function post_type_supports( $post_type, $feature ) {
  1634 function post_type_supports( $post_type, $feature ) {
  1789 	global $_wp_post_type_features;
  1635 	global $_wp_post_type_features;
  1790 
  1636 
  1791 	return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
  1637 	return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
       
  1638 }
       
  1639 
       
  1640 /**
       
  1641  * Retrieves a list of post type names that support a specific feature.
       
  1642  *
       
  1643  * @since 4.5.0
       
  1644  *
       
  1645  * @global array $_wp_post_type_features Post type features
       
  1646  *
       
  1647  * @param array|string $feature  Single feature or an array of features the post types should support.
       
  1648  * @param string       $operator Optional. The logical operation to perform. 'or' means
       
  1649  *                               only one element from the array needs to match; 'and'
       
  1650  *                               means all elements must match; 'not' means no elements may
       
  1651  *                               match. Default 'and'.
       
  1652  * @return array A list of post type names.
       
  1653  */
       
  1654 function get_post_types_by_support( $feature, $operator = 'and' ) {
       
  1655 	global $_wp_post_type_features;
       
  1656 
       
  1657 	$features = array_fill_keys( (array) $feature, true );
       
  1658 
       
  1659 	return array_keys( wp_filter_object_list( $_wp_post_type_features, $features, $operator ) );
  1792 }
  1660 }
  1793 
  1661 
  1794 /**
  1662 /**
  1795  * Update the post type for the post ID.
  1663  * Update the post type for the post ID.
  1796  *
  1664  *
  1801  * @global wpdb $wpdb WordPress database abstraction object.
  1669  * @global wpdb $wpdb WordPress database abstraction object.
  1802  *
  1670  *
  1803  * @param int    $post_id   Optional. Post ID to change post type. Default 0.
  1671  * @param int    $post_id   Optional. Post ID to change post type. Default 0.
  1804  * @param string $post_type Optional. Post type. Accepts 'post' or 'page' to
  1672  * @param string $post_type Optional. Post type. Accepts 'post' or 'page' to
  1805  *                          name a few. Default 'post'.
  1673  *                          name a few. Default 'post'.
  1806  * @return int Amount of rows changed. Should be 1 for success and 0 for failure.
  1674  * @return int|false Amount of rows changed. Should be 1 for success and 0 for failure.
  1807  */
  1675  */
  1808 function set_post_type( $post_id = 0, $post_type = 'post' ) {
  1676 function set_post_type( $post_id = 0, $post_type = 'post' ) {
  1809 	global $wpdb;
  1677 	global $wpdb;
  1810 
  1678 
  1811 	$post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
  1679 	$post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
  1815 
  1683 
  1816 	return $return;
  1684 	return $return;
  1817 }
  1685 }
  1818 
  1686 
  1819 /**
  1687 /**
       
  1688  * Determines whether a post type is considered "viewable".
       
  1689  *
       
  1690  * For built-in post types such as posts and pages, the 'public' value will be evaluated.
       
  1691  * For all others, the 'publicly_queryable' value will be used.
       
  1692  *
       
  1693  * @since 4.4.0
       
  1694  * @since 4.5.0 Added the ability to pass a post type name in addition to object.
       
  1695  * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
       
  1696  *
       
  1697  * @param string|WP_Post_Type $post_type Post type name or object.
       
  1698  * @return bool Whether the post type should be considered viewable.
       
  1699  */
       
  1700 function is_post_type_viewable( $post_type ) {
       
  1701 	if ( is_scalar( $post_type ) ) {
       
  1702 		$post_type = get_post_type_object( $post_type );
       
  1703 		if ( ! $post_type ) {
       
  1704 			return false;
       
  1705 		}
       
  1706 	}
       
  1707 
       
  1708 	return $post_type->publicly_queryable || ( $post_type->_builtin && $post_type->public );
       
  1709 }
       
  1710 
       
  1711 /**
  1820  * Retrieve list of latest posts or posts matching criteria.
  1712  * Retrieve list of latest posts or posts matching criteria.
  1821  *
  1713  *
  1822  * The defaults are as follows:
  1714  * The defaults are as follows:
  1823  *
  1715  *
  1824  * @since 1.2.0
  1716  * @since 1.2.0
  1825  *
  1717  *
  1826  * @see WP_Query::parse_query()
  1718  * @see WP_Query::parse_query()
  1827  *
  1719  *
  1828  * @param array $args {
  1720  * @param array $args {
  1829  *     Optional. Arguments to retrieve posts. {@see WP_Query::parse_query()} for more
  1721  *     Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all
  1830  *     available arguments.
  1722  *     available arguments.
  1831  *
  1723  *
  1832  *     @type int        $numberposts      Total number of posts to retrieve. Is an alias of $posts_per_page
  1724  *     @type int        $numberposts      Total number of posts to retrieve. Is an alias of $posts_per_page
  1833  *                                        in WP_Query. Accepts 1+ and -1 for all. Default 5.
  1725  *                                        in WP_Query. Accepts -1 for all. Default 5.
  1834  *     @type int        $offset           The number of posts to offset before retrieval. Default 0.
       
  1835  *     @type int|string $category         Category ID or comma-separated list of IDs (this or any children).
  1726  *     @type int|string $category         Category ID or comma-separated list of IDs (this or any children).
  1836  *                                        Is an alias of $cat in WP_Query. Default 0.
  1727  *                                        Is an alias of $cat in WP_Query. Default 0.
  1837  *     @type string     $orderby          Which field to order posts by. Accepts post fields. Default 'date'.
       
  1838  *     @type array      $include          An array of post IDs to retrieve, sticky posts will be included.
  1728  *     @type array      $include          An array of post IDs to retrieve, sticky posts will be included.
  1839  *                                        Is an alias of $post__in in WP_Query. Default empty array.
  1729  *                                        Is an alias of $post__in in WP_Query. Default empty array.
  1840  *     @type array      $exclude          An array of post IDs not to retrieve. Default empty array.
  1730  *     @type array      $exclude          An array of post IDs not to retrieve. Default empty array.
  1841  *     @type string     $meta_key         Custom field key. Default empty.
       
  1842  *     @type mixed      $meta_value       Custom field value. Default empty string.
       
  1843  *     @type string     $post_type        Post type. Default 'post'.
       
  1844  *     @type bool       $suppress_filters Whether to suppress filters. Default true.
  1731  *     @type bool       $suppress_filters Whether to suppress filters. Default true.
  1845  * }
  1732  * }
  1846  * @return array List of posts.
  1733  * @return array List of posts.
  1847  */
  1734  */
  1848 function get_posts( $args = null ) {
  1735 function get_posts( $args = null ) {
  1849 	$defaults = array(
  1736 	$defaults = array(
  1850 		'numberposts' => 5, 'offset' => 0,
  1737 		'numberposts' => 5,
  1851 		'category' => 0, 'orderby' => 'date',
  1738 		'category' => 0, 'orderby' => 'date',
  1852 		'order' => 'DESC', 'include' => array(),
  1739 		'order' => 'DESC', 'include' => array(),
  1853 		'exclude' => array(), 'meta_key' => '',
  1740 		'exclude' => array(), 'meta_key' => '',
  1854 		'meta_value' =>'', 'post_type' => 'post',
  1741 		'meta_value' =>'', 'post_type' => 'post',
  1855 		'suppress_filters' => true
  1742 		'suppress_filters' => true
  1891  * @param int    $post_id    Post ID.
  1778  * @param int    $post_id    Post ID.
  1892  * @param string $meta_key   Metadata name.
  1779  * @param string $meta_key   Metadata name.
  1893  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
  1780  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
  1894  * @param bool   $unique     Optional. Whether the same key should not be added.
  1781  * @param bool   $unique     Optional. Whether the same key should not be added.
  1895  *                           Default false.
  1782  *                           Default false.
  1896  * @return int|bool Meta ID on success, false on failure.
  1783  * @return int|false Meta ID on success, false on failure.
  1897  */
  1784  */
  1898 function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
  1785 function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
  1899 	// Make sure meta is added to the post, not a revision.
  1786 	// Make sure meta is added to the post, not a revision.
  1900 	if ( $the_post = wp_is_post_revision($post_id) )
  1787 	if ( $the_post = wp_is_post_revision($post_id) )
  1901 		$post_id = $the_post;
  1788 		$post_id = $the_post;
  1902 
  1789 
  1903 	return add_metadata('post', $post_id, $meta_key, $meta_value, $unique);
  1790 	$added = add_metadata( 'post', $post_id, $meta_key, $meta_value, $unique );
       
  1791 	if ( $added ) {
       
  1792 		wp_cache_set( 'last_changed', microtime(), 'posts' );
       
  1793 	}
       
  1794 	return $added;
  1904 }
  1795 }
  1905 
  1796 
  1906 /**
  1797 /**
  1907  * Remove metadata matching criteria from a post.
  1798  * Remove metadata matching criteria from a post.
  1908  *
  1799  *
  1921 function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
  1812 function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
  1922 	// Make sure meta is added to the post, not a revision.
  1813 	// Make sure meta is added to the post, not a revision.
  1923 	if ( $the_post = wp_is_post_revision($post_id) )
  1814 	if ( $the_post = wp_is_post_revision($post_id) )
  1924 		$post_id = $the_post;
  1815 		$post_id = $the_post;
  1925 
  1816 
  1926 	return delete_metadata('post', $post_id, $meta_key, $meta_value);
  1817 	$deleted = delete_metadata( 'post', $post_id, $meta_key, $meta_value );
       
  1818 	if ( $deleted ) {
       
  1819 		wp_cache_set( 'last_changed', microtime(), 'posts' );
       
  1820 	}
       
  1821 	return $deleted;
  1927 }
  1822 }
  1928 
  1823 
  1929 /**
  1824 /**
  1930  * Retrieve post meta field for a post.
  1825  * Retrieve post meta field for a post.
  1931  *
  1826  *
  1963 function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
  1858 function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
  1964 	// Make sure meta is added to the post, not a revision.
  1859 	// Make sure meta is added to the post, not a revision.
  1965 	if ( $the_post = wp_is_post_revision($post_id) )
  1860 	if ( $the_post = wp_is_post_revision($post_id) )
  1966 		$post_id = $the_post;
  1861 		$post_id = $the_post;
  1967 
  1862 
  1968 	return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
  1863 	$updated = update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );
       
  1864 	if ( $updated ) {
       
  1865 		wp_cache_set( 'last_changed', microtime(), 'posts' );
       
  1866 	}
       
  1867 	return $updated;
  1969 }
  1868 }
  1970 
  1869 
  1971 /**
  1870 /**
  1972  * Delete everything from post meta matching meta key.
  1871  * Delete everything from post meta matching meta key.
  1973  *
  1872  *
  1975  *
  1874  *
  1976  * @param string $post_meta_key Key to search for when deleting.
  1875  * @param string $post_meta_key Key to search for when deleting.
  1977  * @return bool Whether the post meta key was deleted from the database.
  1876  * @return bool Whether the post meta key was deleted from the database.
  1978  */
  1877  */
  1979 function delete_post_meta_by_key( $post_meta_key ) {
  1878 function delete_post_meta_by_key( $post_meta_key ) {
  1980 	return delete_metadata( 'post', null, $post_meta_key, '', true );
  1879 	$deleted = delete_metadata( 'post', null, $post_meta_key, '', true );
       
  1880 	if ( $deleted ) {
       
  1881 		wp_cache_set( 'last_changed', microtime(), 'posts' );
       
  1882 	}
       
  1883 	return $deleted;
       
  1884 }
       
  1885 
       
  1886 /**
       
  1887  * Registers a meta key for posts.
       
  1888  *
       
  1889  * @since 4.9.8
       
  1890  *
       
  1891  * @param string $post_type Post type to register a meta key for. Pass an empty string
       
  1892  *                          to register the meta key across all existing post types.
       
  1893  * @param string $meta_key  The meta key to register.
       
  1894  * @param array  $args      Data used to describe the meta key when registered. See
       
  1895  *                          {@see register_meta()} for a list of supported arguments.
       
  1896  * @return bool True if the meta key was successfully registered, false if not.
       
  1897  */
       
  1898 function register_post_meta( $post_type, $meta_key, array $args ) {
       
  1899 	$args['object_subtype'] = $post_type;
       
  1900 
       
  1901 	return register_meta( 'post', $meta_key, $args );
       
  1902 }
       
  1903 
       
  1904 /**
       
  1905  * Unregisters a meta key for posts.
       
  1906  *
       
  1907  * @since 4.9.8
       
  1908  *
       
  1909  * @param string $post_type Post type the meta key is currently registered for. Pass
       
  1910  *                          an empty string if the meta key is registered across all
       
  1911  *                          existing post types.
       
  1912  * @param string $meta_key  The meta key to unregister.
       
  1913  * @return bool True on success, false if the meta key was not previously registered.
       
  1914  */
       
  1915 function unregister_post_meta( $post_type, $meta_key ) {
       
  1916 	return unregister_meta_key( 'post', $meta_key, $post_type );
  1981 }
  1917 }
  1982 
  1918 
  1983 /**
  1919 /**
  1984  * Retrieve post meta fields, based on post ID.
  1920  * Retrieve post meta fields, based on post ID.
  1985  *
  1921  *
  2005  * If there are no meta fields, then nothing (null) will be returned.
  1941  * If there are no meta fields, then nothing (null) will be returned.
  2006  *
  1942  *
  2007  * @since 1.2.0
  1943  * @since 1.2.0
  2008  *
  1944  *
  2009  * @param int $post_id Optional. Post ID. Default is ID of the global $post.
  1945  * @param int $post_id Optional. Post ID. Default is ID of the global $post.
  2010  * @return array|null Either array of the keys, or null if keys could not be
  1946  * @return array|void Array of the keys, if retrieved.
  2011  *                    retrieved.
       
  2012  */
  1947  */
  2013 function get_post_custom_keys( $post_id = 0 ) {
  1948 function get_post_custom_keys( $post_id = 0 ) {
  2014 	$custom = get_post_custom( $post_id );
  1949 	$custom = get_post_custom( $post_id );
  2015 
  1950 
  2016 	if ( !is_array($custom) )
  1951 	if ( !is_array($custom) )
  2028  *
  1963  *
  2029  * @since 1.2.0
  1964  * @since 1.2.0
  2030  *
  1965  *
  2031  * @param string $key     Optional. Meta field key. Default empty.
  1966  * @param string $key     Optional. Meta field key. Default empty.
  2032  * @param int    $post_id Optional. Post ID. Default is ID of the global $post.
  1967  * @param int    $post_id Optional. Post ID. Default is ID of the global $post.
  2033  * @return array Meta field values.
  1968  * @return array|null Meta field values.
  2034  */
  1969  */
  2035 function get_post_custom_values( $key = '', $post_id = 0 ) {
  1970 function get_post_custom_values( $key = '', $post_id = 0 ) {
  2036 	if ( !$key )
  1971 	if ( !$key )
  2037 		return null;
  1972 		return null;
  2038 
  1973 
  2094 		if ( !isset($post->ID) )
  2029 		if ( !isset($post->ID) )
  2095 			$post->ID = 0;
  2030 			$post->ID = 0;
  2096 		foreach ( array_keys(get_object_vars($post)) as $field )
  2031 		foreach ( array_keys(get_object_vars($post)) as $field )
  2097 			$post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
  2032 			$post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
  2098 		$post->filter = $context;
  2033 		$post->filter = $context;
  2099 	} else {
  2034 	} elseif ( is_array( $post ) ) {
  2100 		// Check if post already filtered for this context.
  2035 		// Check if post already filtered for this context.
  2101 		if ( isset($post['filter']) && $context == $post['filter'] )
  2036 		if ( isset($post['filter']) && $context == $post['filter'] )
  2102 			return $post;
  2037 			return $post;
  2103 		if ( !isset($post['ID']) )
  2038 		if ( !isset($post['ID']) )
  2104 			$post['ID'] = 0;
  2039 			$post['ID'] = 0;
  2115  * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and
  2050  * Possible context values are:  'raw', 'edit', 'db', 'display', 'attribute' and
  2116  * 'js'. The 'display' context is used by default. 'attribute' and 'js' contexts
  2051  * 'js'. The 'display' context is used by default. 'attribute' and 'js' contexts
  2117  * are treated like 'display' when calling filters.
  2052  * are treated like 'display' when calling filters.
  2118  *
  2053  *
  2119  * @since 2.3.0
  2054  * @since 2.3.0
       
  2055  * @since 4.4.0 Like `sanitize_post()`, `$context` defaults to 'display'.
  2120  *
  2056  *
  2121  * @param string $field   The Post Object field name.
  2057  * @param string $field   The Post Object field name.
  2122  * @param mixed  $value   The Post Object value.
  2058  * @param mixed  $value   The Post Object value.
  2123  * @param int    $post_id Post ID.
  2059  * @param int    $post_id Post ID.
  2124  * @param string $context How to sanitize post fields. Looks for 'raw', 'edit',
  2060  * @param string $context Optional. How to sanitize post fields. Looks for 'raw', 'edit',
  2125  *                        'db', 'display', 'attribute' and 'js'.
  2061  *                        'db', 'display', 'attribute' and 'js'. Default 'display'.
  2126  * @return mixed Sanitized value.
  2062  * @return mixed Sanitized value.
  2127  */
  2063  */
  2128 function sanitize_post_field($field, $value, $post_id, $context) {
  2064 function sanitize_post_field( $field, $value, $post_id, $context = 'display' ) {
  2129 	$int_fields = array('ID', 'post_parent', 'menu_order');
  2065 	$int_fields = array('ID', 'post_parent', 'menu_order');
  2130 	if ( in_array($field, $int_fields) )
  2066 	if ( in_array($field, $int_fields) )
  2131 		$value = (int) $value;
  2067 		$value = (int) $value;
  2132 
  2068 
  2133 	// Fields which contain arrays of integers.
  2069 	// Fields which contain arrays of integers.
  2150 		$format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
  2086 		$format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
  2151 
  2087 
  2152 		if ( $prefixed ) {
  2088 		if ( $prefixed ) {
  2153 
  2089 
  2154 			/**
  2090 			/**
  2155 			 * Filter the value of a specific post field to edit.
  2091 			 * Filters the value of a specific post field to edit.
  2156 			 *
  2092 			 *
  2157 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2093 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2158 			 * field name.
  2094 			 * field name.
  2159 			 *
  2095 			 *
  2160 			 * @since 2.3.0
  2096 			 * @since 2.3.0
  2163 			 * @param int   $post_id Post ID.
  2099 			 * @param int   $post_id Post ID.
  2164 			 */
  2100 			 */
  2165 			$value = apply_filters( "edit_{$field}", $value, $post_id );
  2101 			$value = apply_filters( "edit_{$field}", $value, $post_id );
  2166 
  2102 
  2167 			/**
  2103 			/**
  2168 			 * Filter the value of a specific post field to edit.
  2104 			 * Filters the value of a specific post field to edit.
  2169 			 *
  2105 			 *
  2170 			 * The dynamic portion of the hook name, `$field_no_prefix`, refers to
  2106 			 * The dynamic portion of the hook name, `$field_no_prefix`, refers to
  2171 			 * the post field name.
  2107 			 * the post field name.
  2172 			 *
  2108 			 *
  2173 			 * @since 2.3.0
  2109 			 * @since 2.3.0
  2190 		}
  2126 		}
  2191 	} elseif ( 'db' == $context ) {
  2127 	} elseif ( 'db' == $context ) {
  2192 		if ( $prefixed ) {
  2128 		if ( $prefixed ) {
  2193 
  2129 
  2194 			/**
  2130 			/**
  2195 			 * Filter the value of a specific post field before saving.
  2131 			 * Filters the value of a specific post field before saving.
  2196 			 *
  2132 			 *
  2197 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2133 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2198 			 * field name.
  2134 			 * field name.
  2199 			 *
  2135 			 *
  2200 			 * @since 2.3.0
  2136 			 * @since 2.3.0
  2202 			 * @param mixed $value Value of the post field.
  2138 			 * @param mixed $value Value of the post field.
  2203 			 */
  2139 			 */
  2204 			$value = apply_filters( "pre_{$field}", $value );
  2140 			$value = apply_filters( "pre_{$field}", $value );
  2205 
  2141 
  2206 			/**
  2142 			/**
  2207 			 * Filter the value of a specific field before saving.
  2143 			 * Filters the value of a specific field before saving.
  2208 			 *
  2144 			 *
  2209 			 * The dynamic portion of the hook name, `$field_no_prefix`, refers
  2145 			 * The dynamic portion of the hook name, `$field_no_prefix`, refers
  2210 			 * to the post field name.
  2146 			 * to the post field name.
  2211 			 *
  2147 			 *
  2212 			 * @since 2.3.0
  2148 			 * @since 2.3.0
  2216 			$value = apply_filters( "{$field_no_prefix}_save_pre", $value );
  2152 			$value = apply_filters( "{$field_no_prefix}_save_pre", $value );
  2217 		} else {
  2153 		} else {
  2218 			$value = apply_filters( "pre_post_{$field}", $value );
  2154 			$value = apply_filters( "pre_post_{$field}", $value );
  2219 
  2155 
  2220 			/**
  2156 			/**
  2221 			 * Filter the value of a specific post field before saving.
  2157 			 * Filters the value of a specific post field before saving.
  2222 			 *
  2158 			 *
  2223 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2159 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2224 			 * field name.
  2160 			 * field name.
  2225 			 *
  2161 			 *
  2226 			 * @since 2.3.0
  2162 			 * @since 2.3.0
  2233 
  2169 
  2234 		// Use display filters by default.
  2170 		// Use display filters by default.
  2235 		if ( $prefixed ) {
  2171 		if ( $prefixed ) {
  2236 
  2172 
  2237 			/**
  2173 			/**
  2238 			 * Filter the value of a specific post field for display.
  2174 			 * Filters the value of a specific post field for display.
  2239 			 *
  2175 			 *
  2240 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2176 			 * The dynamic portion of the hook name, `$field`, refers to the post
  2241 			 * field name.
  2177 			 * field name.
  2242 			 *
  2178 			 *
  2243 			 * @since 2.3.0
  2179 			 * @since 2.3.0
  2246 			 * @param int    $post_id Post ID.
  2182 			 * @param int    $post_id Post ID.
  2247 			 * @param string $context Context for how to sanitize the field. Possible
  2183 			 * @param string $context Context for how to sanitize the field. Possible
  2248 			 *                        values include 'raw', 'edit', 'db', 'display',
  2184 			 *                        values include 'raw', 'edit', 'db', 'display',
  2249 			 *                        'attribute' and 'js'.
  2185 			 *                        'attribute' and 'js'.
  2250 			 */
  2186 			 */
  2251 			$value = apply_filters( $field, $value, $post_id, $context );
  2187 			$value = apply_filters( "{$field}", $value, $post_id, $context );
  2252 		} else {
  2188 		} else {
  2253 			$value = apply_filters( "post_{$field}", $value, $post_id, $context );
  2189 			$value = apply_filters( "post_{$field}", $value, $post_id, $context );
  2254 		}
  2190 		}
  2255 	}
  2191 
  2256 
  2192 		if ( 'attribute' == $context ) {
  2257 	if ( 'attribute' == $context )
  2193 			$value = esc_attr( $value );
  2258 		$value = esc_attr($value);
  2194 		} elseif ( 'js' == $context ) {
  2259 	elseif ( 'js' == $context )
  2195 			$value = esc_js( $value );
  2260 		$value = esc_js($value);
  2196 		}
       
  2197 	}
  2261 
  2198 
  2262 	return $value;
  2199 	return $value;
  2263 }
  2200 }
  2264 
  2201 
  2265 /**
  2202 /**
  2278 		$stickies = array($post_id);
  2215 		$stickies = array($post_id);
  2279 
  2216 
  2280 	if ( ! in_array($post_id, $stickies) )
  2217 	if ( ! in_array($post_id, $stickies) )
  2281 		$stickies[] = $post_id;
  2218 		$stickies[] = $post_id;
  2282 
  2219 
  2283 	update_option('sticky_posts', $stickies);
  2220 	$updated = update_option( 'sticky_posts', $stickies );
       
  2221 
       
  2222 	if ( $updated ) {
       
  2223 		/**
       
  2224 		 * Fires once a post has been added to the sticky list.
       
  2225 		 *
       
  2226 		 * @since 4.6.0
       
  2227 		 *
       
  2228 		 * @param int $post_id ID of the post that was stuck.
       
  2229 		 */
       
  2230 		do_action( 'post_stuck', $post_id );
       
  2231 	}
  2284 }
  2232 }
  2285 
  2233 
  2286 /**
  2234 /**
  2287  * Un-stick a post.
  2235  * Un-stick a post.
  2288  *
  2236  *
  2305 	if ( false === $offset )
  2253 	if ( false === $offset )
  2306 		return;
  2254 		return;
  2307 
  2255 
  2308 	array_splice($stickies, $offset, 1);
  2256 	array_splice($stickies, $offset, 1);
  2309 
  2257 
  2310 	update_option('sticky_posts', $stickies);
  2258 	$updated = update_option( 'sticky_posts', $stickies );
       
  2259 
       
  2260 	if ( $updated ) {
       
  2261 		/**
       
  2262 		 * Fires once a post has been removed from the sticky list.
       
  2263 		 *
       
  2264 		 * @since 4.6.0
       
  2265 		 *
       
  2266 		 * @param int $post_id ID of the post that was unstuck.
       
  2267 		 */
       
  2268 		do_action( 'post_unstuck', $post_id );
       
  2269 	}
  2311 }
  2270 }
  2312 
  2271 
  2313 /**
  2272 /**
  2314  * Return the cache key for wp_count_posts() based on the passed arguments.
  2273  * Return the cache key for wp_count_posts() based on the passed arguments.
  2315  *
  2274  *
  2340  *
  2299  *
  2341  * The $perm parameter checks for 'readable' value and if the user can read
  2300  * The $perm parameter checks for 'readable' value and if the user can read
  2342  * private posts, it will display that for the user that is signed in.
  2301  * private posts, it will display that for the user that is signed in.
  2343  *
  2302  *
  2344  * @since 2.5.0
  2303  * @since 2.5.0
       
  2304  *
       
  2305  * @global wpdb $wpdb WordPress database abstraction object.
  2345  *
  2306  *
  2346  * @param string $type Optional. Post type to retrieve count. Default 'post'.
  2307  * @param string $type Optional. Post type to retrieve count. Default 'post'.
  2347  * @param string $perm Optional. 'readable' or empty. Default empty.
  2308  * @param string $perm Optional. 'readable' or empty. Default empty.
  2348  * @return object Number of posts for each status.
  2309  * @return object Number of posts for each status.
  2349  */
  2310  */
  2404  * you the number of attachments that are children of a post. You can get that
  2365  * you the number of attachments that are children of a post. You can get that
  2405  * by counting the number of children that post has.
  2366  * by counting the number of children that post has.
  2406  *
  2367  *
  2407  * @since 2.5.0
  2368  * @since 2.5.0
  2408  *
  2369  *
       
  2370  * @global wpdb $wpdb WordPress database abstraction object.
       
  2371  *
  2409  * @param string|array $mime_type Optional. Array or comma-separated list of
  2372  * @param string|array $mime_type Optional. Array or comma-separated list of
  2410  *                                MIME patterns. Default empty.
  2373  *                                MIME patterns. Default empty.
  2411  * @return object An object containing the attachment counts by mime type.
  2374  * @return object An object containing the attachment counts by mime type.
  2412  */
  2375  */
  2413 function wp_count_attachments( $mime_type = '' ) {
  2376 function wp_count_attachments( $mime_type = '' ) {
  2415 
  2378 
  2416 	$and = wp_post_mime_type_where( $mime_type );
  2379 	$and = wp_post_mime_type_where( $mime_type );
  2417 	$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 );
  2380 	$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 );
  2418 
  2381 
  2419 	$counts = array();
  2382 	$counts = array();
  2420 	foreach( (array) $count as $row ) {
  2383 	foreach ( (array) $count as $row ) {
  2421 		$counts[ $row['post_mime_type'] ] = $row['num_posts'];
  2384 		$counts[ $row['post_mime_type'] ] = $row['num_posts'];
  2422 	}
  2385 	}
  2423 	$counts['trash'] = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and");
  2386 	$counts['trash'] = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and");
  2424 
  2387 
  2425 	/**
  2388 	/**
  2448 		'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
  2411 		'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
  2449 		'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
  2412 		'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
  2450 	);
  2413 	);
  2451 
  2414 
  2452 	/**
  2415 	/**
  2453 	 * Filter the default list of post mime types.
  2416 	 * Filters the default list of post mime types.
  2454 	 *
  2417 	 *
  2455 	 * @since 2.5.0
  2418 	 * @since 2.5.0
  2456 	 *
  2419 	 *
  2457 	 * @param array $post_mime_types Default list of post mime types.
  2420 	 * @param array $post_mime_types Default list of post mime types.
  2458 	 */
  2421 	 */
  2578  * @see wp_trash_post()
  2541  * @see wp_trash_post()
  2579  *
  2542  *
  2580  * @param int  $postid       Optional. Post ID. Default 0.
  2543  * @param int  $postid       Optional. Post ID. Default 0.
  2581  * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
  2544  * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
  2582  *                           Default false.
  2545  *                           Default false.
  2583  * @return array|bool|WP_Post False on failure.
  2546  * @return WP_Post|false|null Post data on success, false or null on failure.
  2584  */
  2547  */
  2585 function wp_delete_post( $postid = 0, $force_delete = false ) {
  2548 function wp_delete_post( $postid = 0, $force_delete = false ) {
  2586 	global $wpdb;
  2549 	global $wpdb;
  2587 
  2550 
  2588 	if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
  2551 	$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $postid ) );
       
  2552 
       
  2553 	if ( ! $post ) {
  2589 		return $post;
  2554 		return $post;
  2590 
  2555 	}
  2591 	if ( !$force_delete && ( $post->post_type == 'post' || $post->post_type == 'page') && get_post_status( $postid ) != 'trash' && EMPTY_TRASH_DAYS )
  2556 
  2592 			return wp_trash_post($postid);
  2557 	$post = get_post( $post );
  2593 
  2558 
  2594 	if ( $post->post_type == 'attachment' )
  2559 	if ( ! $force_delete && ( 'post' === $post->post_type || 'page' === $post->post_type ) && 'trash' !== get_post_status( $postid ) && EMPTY_TRASH_DAYS ) {
       
  2560 		return wp_trash_post( $postid );
       
  2561 	}
       
  2562 
       
  2563 	if ( 'attachment' === $post->post_type ) {
  2595 		return wp_delete_attachment( $postid, $force_delete );
  2564 		return wp_delete_attachment( $postid, $force_delete );
       
  2565 	}
       
  2566 
       
  2567 	/**
       
  2568 	 * Filters whether a post deletion should take place.
       
  2569 	 *
       
  2570 	 * @since 4.4.0
       
  2571 	 *
       
  2572 	 * @param bool    $delete       Whether to go forward with deletion.
       
  2573 	 * @param WP_Post $post         Post object.
       
  2574 	 * @param bool    $force_delete Whether to bypass the trash.
       
  2575 	 */
       
  2576 	$check = apply_filters( 'pre_delete_post', null, $post, $force_delete );
       
  2577 	if ( null !== $check ) {
       
  2578 		return $check;
       
  2579 	}
  2596 
  2580 
  2597 	/**
  2581 	/**
  2598 	 * Fires before a post is deleted, at the start of wp_delete_post().
  2582 	 * Fires before a post is deleted, at the start of wp_delete_post().
  2599 	 *
  2583 	 *
  2600 	 * @since 3.2.0
  2584 	 * @since 3.2.0
  2615 
  2599 
  2616 	if ( is_post_type_hierarchical( $post->post_type ) ) {
  2600 	if ( is_post_type_hierarchical( $post->post_type ) ) {
  2617 		// Point children of this page to its parent, also clean the cache of affected children.
  2601 		// Point children of this page to its parent, also clean the cache of affected children.
  2618 		$children_query = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $postid, $post->post_type );
  2602 		$children_query = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $postid, $post->post_type );
  2619 		$children = $wpdb->get_results( $children_query );
  2603 		$children = $wpdb->get_results( $children_query );
  2620 
  2604 		if ( $children ) {
  2621 		$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
  2605 			$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
       
  2606 		}
  2622 	}
  2607 	}
  2623 
  2608 
  2624 	// Do raw query. wp_get_post_revisions() is filtered.
  2609 	// Do raw query. wp_get_post_revisions() is filtered.
  2625 	$revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
  2610 	$revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
  2626 	// Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
  2611 	// Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
  2628 		wp_delete_post_revision( $revision_id );
  2613 		wp_delete_post_revision( $revision_id );
  2629 
  2614 
  2630 	// Point all attachments to this post up one level.
  2615 	// Point all attachments to this post up one level.
  2631 	$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
  2616 	$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
  2632 
  2617 
       
  2618 	wp_defer_comment_counting( true );
       
  2619 
  2633 	$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
  2620 	$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
  2634 	foreach ( $comment_ids as $comment_id )
  2621 	foreach ( $comment_ids as $comment_id ) {
  2635 		wp_delete_comment( $comment_id, true );
  2622 		wp_delete_comment( $comment_id, true );
       
  2623 	}
       
  2624 
       
  2625 	wp_defer_comment_counting( false );
  2636 
  2626 
  2637 	$post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
  2627 	$post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
  2638 	foreach ( $post_meta_ids as $mid )
  2628 	foreach ( $post_meta_ids as $mid )
  2639 		delete_metadata_by_mid( 'post', $mid );
  2629 		delete_metadata_by_mid( 'post', $mid );
  2640 
  2630 
  2721  *
  2711  *
  2722  * @see wp_delete_post()
  2712  * @see wp_delete_post()
  2723  *
  2713  *
  2724  * @param int $post_id Optional. Post ID. Default is ID of the global $post
  2714  * @param int $post_id Optional. Post ID. Default is ID of the global $post
  2725  *                     if EMPTY_TRASH_DAYS equals true.
  2715  *                     if EMPTY_TRASH_DAYS equals true.
  2726  * @return bool|array Post data array, otherwise false.
  2716  * @return WP_Post|false|null Post data on success, false or null on failure.
  2727  */
  2717  */
  2728 function wp_trash_post( $post_id = 0 ) {
  2718 function wp_trash_post( $post_id = 0 ) {
  2729 	if ( !EMPTY_TRASH_DAYS )
  2719 	if ( ! EMPTY_TRASH_DAYS ) {
  2730 		return wp_delete_post($post_id, true);
  2720 		return wp_delete_post( $post_id, true );
  2731 
  2721 	}
  2732 	if ( !$post = get_post($post_id, ARRAY_A) )
  2722 
       
  2723 	$post = get_post( $post_id );
       
  2724 
       
  2725 	if ( ! $post ) {
  2733 		return $post;
  2726 		return $post;
  2734 
  2727 	}
  2735 	if ( $post['post_status'] == 'trash' )
  2728 
       
  2729 	if ( 'trash' === $post->post_status ) {
  2736 		return false;
  2730 		return false;
       
  2731 	}
       
  2732 
       
  2733 	/**
       
  2734 	 * Filters whether a post trashing should take place.
       
  2735 	 *
       
  2736 	 * @since 4.9.0
       
  2737 	 *
       
  2738 	 * @param bool    $trash Whether to go forward with trashing.
       
  2739 	 * @param WP_Post $post  Post object.
       
  2740 	 */
       
  2741 	$check = apply_filters( 'pre_trash_post', null, $post );
       
  2742 	if ( null !== $check ) {
       
  2743 		return $check;
       
  2744 	}
  2737 
  2745 
  2738 	/**
  2746 	/**
  2739 	 * Fires before a post is sent to the trash.
  2747 	 * Fires before a post is sent to the trash.
  2740 	 *
  2748 	 *
  2741 	 * @since 3.3.0
  2749 	 * @since 3.3.0
  2742 	 *
  2750 	 *
  2743 	 * @param int $post_id Post ID.
  2751 	 * @param int $post_id Post ID.
  2744 	 */
  2752 	 */
  2745 	do_action( 'wp_trash_post', $post_id );
  2753 	do_action( 'wp_trash_post', $post_id );
  2746 
  2754 
  2747 	add_post_meta($post_id,'_wp_trash_meta_status', $post['post_status']);
  2755 	add_post_meta( $post_id, '_wp_trash_meta_status', $post->post_status );
  2748 	add_post_meta($post_id,'_wp_trash_meta_time', time());
  2756 	add_post_meta( $post_id, '_wp_trash_meta_time', time() );
  2749 
  2757 
  2750 	$post['post_status'] = 'trash';
  2758 	wp_update_post( array( 'ID' => $post_id, 'post_status' => 'trash' ) );
  2751 	wp_insert_post($post);
  2759 
  2752 
  2760 	wp_trash_post_comments( $post_id );
  2753 	wp_trash_post_comments($post_id);
       
  2754 
  2761 
  2755 	/**
  2762 	/**
  2756 	 * Fires after a post is sent to the trash.
  2763 	 * Fires after a post is sent to the trash.
  2757 	 *
  2764 	 *
  2758 	 * @since 2.9.0
  2765 	 * @since 2.9.0
  2768  * Restore a post or page from the Trash.
  2775  * Restore a post or page from the Trash.
  2769  *
  2776  *
  2770  * @since 2.9.0
  2777  * @since 2.9.0
  2771  *
  2778  *
  2772  * @param int $post_id Optional. Post ID. Default is ID of the global $post.
  2779  * @param int $post_id Optional. Post ID. Default is ID of the global $post.
  2773  * @return WP_Post|bool WP_Post object. False on failure.
  2780  * @return WP_Post|false|null Post data on success, false or null on failure.
  2774  */
  2781  */
  2775 function wp_untrash_post( $post_id = 0 ) {
  2782 function wp_untrash_post( $post_id = 0 ) {
  2776 	if ( !$post = get_post($post_id, ARRAY_A) )
  2783 	$post = get_post( $post_id );
       
  2784 
       
  2785 	if ( ! $post ) {
  2777 		return $post;
  2786 		return $post;
  2778 
  2787 	}
  2779 	if ( $post['post_status'] != 'trash' )
  2788 
       
  2789 	if ( 'trash' !== $post->post_status ) {
  2780 		return false;
  2790 		return false;
       
  2791 	}
       
  2792 
       
  2793 	/**
       
  2794 	 * Filters whether a post untrashing should take place.
       
  2795 	 *
       
  2796 	 * @since 4.9.0
       
  2797 	 *
       
  2798 	 * @param bool    $untrash Whether to go forward with untrashing.
       
  2799 	 * @param WP_Post $post    Post object.
       
  2800 	 */
       
  2801 	$check = apply_filters( 'pre_untrash_post', null, $post );
       
  2802 	if ( null !== $check ) {
       
  2803 		return $check;
       
  2804 	}
  2781 
  2805 
  2782 	/**
  2806 	/**
  2783 	 * Fires before a post is restored from the trash.
  2807 	 * Fires before a post is restored from the trash.
  2784 	 *
  2808 	 *
  2785 	 * @since 2.9.0
  2809 	 * @since 2.9.0
  2786 	 *
  2810 	 *
  2787 	 * @param int $post_id Post ID.
  2811 	 * @param int $post_id Post ID.
  2788 	 */
  2812 	 */
  2789 	do_action( 'untrash_post', $post_id );
  2813 	do_action( 'untrash_post', $post_id );
  2790 
  2814 
  2791 	$post_status = get_post_meta($post_id, '_wp_trash_meta_status', true);
  2815 	$post_status = get_post_meta( $post_id, '_wp_trash_meta_status', true );
  2792 
  2816 
  2793 	$post['post_status'] = $post_status;
  2817 	delete_post_meta( $post_id, '_wp_trash_meta_status' );
  2794 
  2818 	delete_post_meta( $post_id, '_wp_trash_meta_time' );
  2795 	delete_post_meta($post_id, '_wp_trash_meta_status');
  2819 
  2796 	delete_post_meta($post_id, '_wp_trash_meta_time');
  2820 	wp_update_post( array( 'ID' => $post_id, 'post_status' => $post_status ) );
  2797 
  2821 
  2798 	wp_insert_post($post);
  2822 	wp_untrash_post_comments( $post_id );
  2799 
       
  2800 	wp_untrash_post_comments($post_id);
       
  2801 
  2823 
  2802 	/**
  2824 	/**
  2803 	 * Fires after a post is restored from the trash.
  2825 	 * Fires after a post is restored from the trash.
  2804 	 *
  2826 	 *
  2805 	 * @since 2.9.0
  2827 	 * @since 2.9.0
  2816  *
  2838  *
  2817  * @since 2.9.0
  2839  * @since 2.9.0
  2818  *
  2840  *
  2819  * @global wpdb $wpdb WordPress database abstraction object.
  2841  * @global wpdb $wpdb WordPress database abstraction object.
  2820  *
  2842  *
  2821  * @param int|WP_Post $post Optional. Post ID or post object. Defaults to global $post.
  2843  * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
  2822  * @return mixed False on failure.
  2844  * @return mixed|void False on failure.
  2823  */
  2845  */
  2824 function wp_trash_post_comments( $post = null ) {
  2846 function wp_trash_post_comments( $post = null ) {
  2825 	global $wpdb;
  2847 	global $wpdb;
  2826 
  2848 
  2827 	$post = get_post($post);
  2849 	$post = get_post($post);
  2870 /**
  2892 /**
  2871  * Restore comments for a post from the trash.
  2893  * Restore comments for a post from the trash.
  2872  *
  2894  *
  2873  * @since 2.9.0
  2895  * @since 2.9.0
  2874  *
  2896  *
  2875  * @param int|WP_Post $post Optional. Post ID or post object. Defaults to global $post.
  2897  * @global wpdb $wpdb WordPress database abstraction object.
  2876  * @return null|bool Null on failure.
  2898  *
       
  2899  * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
       
  2900  * @return true|void
  2877  */
  2901  */
  2878 function wp_untrash_post_comments( $post = null ) {
  2902 function wp_untrash_post_comments( $post = null ) {
  2879 	global $wpdb;
  2903 	global $wpdb;
  2880 
  2904 
  2881 	$post = get_post($post);
  2905 	$post = get_post($post);
  2903 	foreach ( $statuses as $comment_id => $comment_status )
  2927 	foreach ( $statuses as $comment_id => $comment_status )
  2904 		$group_by_status[$comment_status][] = $comment_id;
  2928 		$group_by_status[$comment_status][] = $comment_id;
  2905 
  2929 
  2906 	foreach ( $group_by_status as $status => $comments ) {
  2930 	foreach ( $group_by_status as $status => $comments ) {
  2907 		// Sanity check. This shouldn't happen.
  2931 		// Sanity check. This shouldn't happen.
  2908 		if ( 'post-trashed' == $status )
  2932 		if ( 'post-trashed' == $status ) {
  2909 			$status = '0';
  2933 			$status = '0';
  2910 		$comments_in = implode( "', '", $comments );
  2934 		}
  2911 		$wpdb->query( "UPDATE $wpdb->comments SET comment_approved = '$status' WHERE comment_ID IN ('" . $comments_in . "')" );
  2935 		$comments_in = implode( ', ', array_map( 'intval', $comments ) );
       
  2936 		$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) );
  2912 	}
  2937 	}
  2913 
  2938 
  2914 	clean_comment_cache( array_keys($statuses) );
  2939 	clean_comment_cache( array_keys($statuses) );
  2915 
  2940 
  2916 	delete_post_meta($post_id, '_wp_trash_meta_comments_status');
  2941 	delete_post_meta($post_id, '_wp_trash_meta_comments_status');
  2935  *
  2960  *
  2936  * @see wp_get_object_terms()
  2961  * @see wp_get_object_terms()
  2937  *
  2962  *
  2938  * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
  2963  * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
  2939  *                       global $post. Default 0.
  2964  *                       global $post. Default 0.
  2940  * @param array $args    Optional. Category arguments. Default empty.
  2965  * @param array $args    Optional. Category query parameters. Default empty array.
  2941  * @return array List of categories.
  2966  *                       See WP_Term_Query::__construct() for supported arguments.
       
  2967  * @return array|WP_Error List of categories. If the `$fields` argument passed via `$args` is 'all' or
       
  2968  *                        'all_with_object_id', an array of WP_Term objects will be returned. If `$fields`
       
  2969  *                        is 'ids', an array of category ids. If `$fields` is 'names', an array of category names.
       
  2970  *                        WP_Error object if 'category' taxonomy doesn't exist.
  2942  */
  2971  */
  2943 function wp_get_post_categories( $post_id = 0, $args = array() ) {
  2972 function wp_get_post_categories( $post_id = 0, $args = array() ) {
  2944 	$post_id = (int) $post_id;
  2973 	$post_id = (int) $post_id;
  2945 
  2974 
  2946 	$defaults = array('fields' => 'ids');
  2975 	$defaults = array('fields' => 'ids');
  2953 /**
  2982 /**
  2954  * Retrieve the tags for a post.
  2983  * Retrieve the tags for a post.
  2955  *
  2984  *
  2956  * There is only one default for this function, called 'fields' and by default
  2985  * There is only one default for this function, called 'fields' and by default
  2957  * is set to 'all'. There are other defaults that can be overridden in
  2986  * is set to 'all'. There are other defaults that can be overridden in
  2958  * {@link wp_get_object_terms()}.
  2987  * wp_get_object_terms().
  2959  *
  2988  *
  2960  * @since 2.3.0
  2989  * @since 2.3.0
  2961  *
  2990  *
  2962  * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
  2991  * @param int   $post_id Optional. The Post ID. Does not default to the ID of the
  2963  *                       global $post. Defualt 0.
  2992  *                       global $post. Default 0.
  2964  * @param array $args Optional. Overwrite the defaults
  2993  * @param array $args    Optional. Tag query parameters. Default empty array.
  2965  * @return array List of post tags.
  2994  *                       See WP_Term_Query::__construct() for supported arguments.
       
  2995  * @return array|WP_Error Array of WP_Term objects on success or empty array if no tags were found.
       
  2996  *                        WP_Error object if 'post_tag' taxonomy doesn't exist.
  2966  */
  2997  */
  2967 function wp_get_post_tags( $post_id = 0, $args = array() ) {
  2998 function wp_get_post_tags( $post_id = 0, $args = array() ) {
  2968 	return wp_get_post_terms( $post_id, 'post_tag', $args);
  2999 	return wp_get_post_terms( $post_id, 'post_tag', $args);
  2969 }
  3000 }
  2970 
  3001 
  2971 /**
  3002 /**
  2972  * Retrieve the terms for a post.
  3003  * Retrieves the terms for a post.
  2973  *
       
  2974  * There is only one default for this function, called 'fields' and by default
       
  2975  * is set to 'all'. There are other defaults that can be overridden in
       
  2976  * {@link wp_get_object_terms()}.
       
  2977  *
  3004  *
  2978  * @since 2.8.0
  3005  * @since 2.8.0
  2979  *
  3006  *
  2980  * @param int    $post_id  Optional. The Post ID. Does not default to the ID of the
  3007  * @param int          $post_id  Optional. The Post ID. Does not default to the ID of the
  2981  *                         global $post. Default 0.
  3008  *                               global $post. Default 0.
  2982  * @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
  3009  * @param string|array $taxonomy Optional. The taxonomy slug or array of slugs for which
  2983  * @param array  $args     Optional. {@link wp_get_object_terms()} arguments. Default empty array.
  3010  *                               to retrieve terms. Default 'post_tag'.
  2984  * @return array List of post tags.
  3011  * @param array        $args     {
       
  3012  *     Optional. Term query parameters. See WP_Term_Query::__construct() for supported arguments.
       
  3013  *
       
  3014  *     @type string $fields Term fields to retrieve. Default 'all'.
       
  3015  * }
       
  3016  * @return array|WP_Error Array of WP_Term objects on success or empty array if no terms were found.
       
  3017  *                        WP_Error object if `$taxonomy` doesn't exist.
  2985  */
  3018  */
  2986 function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
  3019 function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
  2987 	$post_id = (int) $post_id;
  3020 	$post_id = (int) $post_id;
  2988 
  3021 
  2989 	$defaults = array('fields' => 'all');
  3022 	$defaults = array('fields' => 'all');
  2999  *
  3032  *
  3000  * @since 1.0.0
  3033  * @since 1.0.0
  3001  *
  3034  *
  3002  * @see get_posts()
  3035  * @see get_posts()
  3003  *
  3036  *
  3004  * @param array  $args       Optional. Arguments to retrieve posts. Default empty array.
  3037  * @param array  $args   Optional. Arguments to retrieve posts. Default empty array.
  3005  * @param string $output     Optional. Type of output. Accepts ARRAY_A or ''. Default ARRAY_A.
  3038  * @param string $output Optional. The required return type. One of OBJECT or ARRAY_A, which correspond to
  3006  * @return array|bool Associative array if $output equals ARRAY_A, array or false if no results.
  3039  *                       a WP_Post object or an associative array, respectively. Default ARRAY_A.
       
  3040  * @return array|false Array of recent posts, where the type of each element is determined by $output parameter.
       
  3041  *                     Empty array on failure.
  3007  */
  3042  */
  3008 function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) {
  3043 function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) {
  3009 
  3044 
  3010 	if ( is_numeric( $args ) ) {
  3045 	if ( is_numeric( $args ) ) {
  3011 		_deprecated_argument( __FUNCTION__, '3.1', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
  3046 		_deprecated_argument( __FUNCTION__, '3.1.0', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
  3012 		$args = array( 'numberposts' => absint( $args ) );
  3047 		$args = array( 'numberposts' => absint( $args ) );
  3013 	}
  3048 	}
  3014 
  3049 
  3015 	// Set default arguments.
  3050 	// Set default arguments.
  3016 	$defaults = array(
  3051 	$defaults = array(
  3026 
  3061 
  3027 	$results = get_posts( $r );
  3062 	$results = get_posts( $r );
  3028 
  3063 
  3029 	// Backward compatibility. Prior to 3.1 expected posts to be returned in array.
  3064 	// Backward compatibility. Prior to 3.1 expected posts to be returned in array.
  3030 	if ( ARRAY_A == $output ){
  3065 	if ( ARRAY_A == $output ){
  3031 		foreach( $results as $key => $result ) {
  3066 		foreach ( $results as $key => $result ) {
  3032 			$results[$key] = get_object_vars( $result );
  3067 			$results[$key] = get_object_vars( $result );
  3033 		}
  3068 		}
  3034 		return $results ? $results : array();
  3069 		return $results ? $results : array();
  3035 	}
  3070 	}
  3036 
  3071 
  3047  * and 'post_date_gmt' keys. You can close the comments or open the comments by
  3082  * and 'post_date_gmt' keys. You can close the comments or open the comments by
  3048  * setting the value for 'comment_status' key.
  3083  * setting the value for 'comment_status' key.
  3049  *
  3084  *
  3050  * @since 1.0.0
  3085  * @since 1.0.0
  3051  * @since 4.2.0 Support was added for encoding emoji in the post title, content, and excerpt.
  3086  * @since 4.2.0 Support was added for encoding emoji in the post title, content, and excerpt.
       
  3087  * @since 4.4.0 A 'meta_input' array can now be passed to `$postarr` to add post meta data.
  3052  *
  3088  *
  3053  * @see sanitize_post()
  3089  * @see sanitize_post()
  3054  * @global wpdb $wpdb WordPress database abstraction object.
  3090  * @global wpdb $wpdb WordPress database abstraction object.
  3055  *
  3091  *
  3056  * @param array $postarr {
  3092  * @param array $postarr {
  3072  *     @type string $comment_status        Whether the post can accept comments. Accepts 'open' or 'closed'.
  3108  *     @type string $comment_status        Whether the post can accept comments. Accepts 'open' or 'closed'.
  3073  *                                         Default is the value of 'default_comment_status' option.
  3109  *                                         Default is the value of 'default_comment_status' option.
  3074  *     @type string $ping_status           Whether the post can accept pings. Accepts 'open' or 'closed'.
  3110  *     @type string $ping_status           Whether the post can accept pings. Accepts 'open' or 'closed'.
  3075  *                                         Default is the value of 'default_ping_status' option.
  3111  *                                         Default is the value of 'default_ping_status' option.
  3076  *     @type string $post_password         The password to access the post. Default empty.
  3112  *     @type string $post_password         The password to access the post. Default empty.
  3077  *     @type string $post_name             The post name. Default is the sanitized post title.
  3113  *     @type string $post_name             The post name. Default is the sanitized post title
       
  3114  *                                         when creating a new post.
  3078  *     @type string $to_ping               Space or carriage return-separated list of URLs to ping.
  3115  *     @type string $to_ping               Space or carriage return-separated list of URLs to ping.
  3079  *                                         Default empty.
  3116  *                                         Default empty.
  3080  *     @type string $pinged                Space or carriage return-separated list of URLs that have
  3117  *     @type string $pinged                Space or carriage return-separated list of URLs that have
  3081  *                                         been pinged. Default empty.
  3118  *                                         been pinged. Default empty.
  3082  *     @type string $post_modified         The date when the post was last modified. Default is
  3119  *     @type string $post_modified         The date when the post was last modified. Default is
  3085  *                                         timezone. Default is the current time.
  3122  *                                         timezone. Default is the current time.
  3086  *     @type int    $post_parent           Set this for the post it belongs to, if any. Default 0.
  3123  *     @type int    $post_parent           Set this for the post it belongs to, if any. Default 0.
  3087  *     @type int    $menu_order            The order the post should be displayed in. Default 0.
  3124  *     @type int    $menu_order            The order the post should be displayed in. Default 0.
  3088  *     @type string $post_mime_type        The mime type of the post. Default empty.
  3125  *     @type string $post_mime_type        The mime type of the post. Default empty.
  3089  *     @type string $guid                  Global Unique ID for referencing the post. Default empty.
  3126  *     @type string $guid                  Global Unique ID for referencing the post. Default empty.
       
  3127  *     @type array  $post_category         Array of category names, slugs, or IDs.
       
  3128  *                                         Defaults to value of the 'default_category' option.
       
  3129  *     @type array  $tags_input            Array of tag names, slugs, or IDs. Default empty.
       
  3130  *     @type array  $tax_input             Array of taxonomy terms keyed by their taxonomy name. Default empty.
       
  3131  *     @type array  $meta_input            Array of post meta values keyed by their post meta key. Default empty.
  3090  * }
  3132  * }
  3091  * @param bool  $wp_error Optional. Whether to allow return of WP_Error on failure. Default false.
  3133  * @param bool  $wp_error Optional. Whether to return a WP_Error on failure. Default false.
  3092  * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure.
  3134  * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure.
  3093  */
  3135  */
  3094 function wp_insert_post( $postarr, $wp_error = false ) {
  3136 function wp_insert_post( $postarr, $wp_error = false ) {
  3095 	global $wpdb;
  3137 	global $wpdb;
  3096 
  3138 
  3097 	$user_id = get_current_user_id();
  3139 	$user_id = get_current_user_id();
  3098 
  3140 
  3099 	$defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_id,
  3141 	$defaults = array(
  3100 		'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
  3142 		'post_author' => $user_id,
  3101 		'menu_order' => 0, 'to_ping' =>  '', 'pinged' => '', 'post_password' => '',
  3143 		'post_content' => '',
  3102 		'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0,
  3144 		'post_content_filtered' => '',
  3103 		'post_content' => '', 'post_title' => '', 'context' => '');
  3145 		'post_title' => '',
       
  3146 		'post_excerpt' => '',
       
  3147 		'post_status' => 'draft',
       
  3148 		'post_type' => 'post',
       
  3149 		'comment_status' => '',
       
  3150 		'ping_status' => '',
       
  3151 		'post_password' => '',
       
  3152 		'to_ping' =>  '',
       
  3153 		'pinged' => '',
       
  3154 		'post_parent' => 0,
       
  3155 		'menu_order' => 0,
       
  3156 		'guid' => '',
       
  3157 		'import_id' => 0,
       
  3158 		'context' => '',
       
  3159 	);
  3104 
  3160 
  3105 	$postarr = wp_parse_args($postarr, $defaults);
  3161 	$postarr = wp_parse_args($postarr, $defaults);
  3106 
  3162 
  3107 	unset( $postarr[ 'filter' ] );
  3163 	unset( $postarr[ 'filter' ] );
  3108 
  3164 
  3137 	$post_title = $postarr['post_title'];
  3193 	$post_title = $postarr['post_title'];
  3138 	$post_content = $postarr['post_content'];
  3194 	$post_content = $postarr['post_content'];
  3139 	$post_excerpt = $postarr['post_excerpt'];
  3195 	$post_excerpt = $postarr['post_excerpt'];
  3140 	if ( isset( $postarr['post_name'] ) ) {
  3196 	if ( isset( $postarr['post_name'] ) ) {
  3141 		$post_name = $postarr['post_name'];
  3197 		$post_name = $postarr['post_name'];
       
  3198 	} elseif ( $update ) {
       
  3199 		// For an update, don't modify the post_name if it wasn't supplied as an argument.
       
  3200 		$post_name = $post_before->post_name;
  3142 	}
  3201 	}
  3143 
  3202 
  3144 	$maybe_empty = 'attachment' !== $post_type
  3203 	$maybe_empty = 'attachment' !== $post_type
  3145 		&& ! $post_content && ! $post_title && ! $post_excerpt
  3204 		&& ! $post_content && ! $post_title && ! $post_excerpt
  3146 		&& post_type_supports( $post_type, 'editor' )
  3205 		&& post_type_supports( $post_type, 'editor' )
  3147 		&& post_type_supports( $post_type, 'title' )
  3206 		&& post_type_supports( $post_type, 'title' )
  3148 		&& post_type_supports( $post_type, 'excerpt' );
  3207 		&& post_type_supports( $post_type, 'excerpt' );
  3149 
  3208 
  3150 	/**
  3209 	/**
  3151 	 * Filter whether the post should be considered "empty".
  3210 	 * Filters whether the post should be considered "empty".
  3152 	 *
  3211 	 *
  3153 	 * The post is considered "empty" if both:
  3212 	 * The post is considered "empty" if both:
  3154 	 * 1. The post type supports the title, editor, and excerpt fields
  3213 	 * 1. The post type supports the title, editor, and excerpt fields
  3155 	 * 2. The title, editor, and excerpt fields are all empty
  3214 	 * 2. The title, editor, and excerpt fields are all empty
  3156 	 *
  3215 	 *
  3170 			return 0;
  3229 			return 0;
  3171 		}
  3230 		}
  3172 	}
  3231 	}
  3173 
  3232 
  3174 	$post_status = empty( $postarr['post_status'] ) ? 'draft' : $postarr['post_status'];
  3233 	$post_status = empty( $postarr['post_status'] ) ? 'draft' : $postarr['post_status'];
  3175 	if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash' ) ) ) {
  3234 	if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash', 'auto-draft' ), true ) ) {
  3176 		$post_status = 'inherit';
  3235 		$post_status = 'inherit';
  3177 	}
  3236 	}
  3178 
  3237 
  3179 	if ( ! empty( $postarr['post_category'] ) ) {
  3238 	if ( ! empty( $postarr['post_category'] ) ) {
  3180 		// Filter out empty terms.
  3239 		// Filter out empty terms.
  3219 	/*
  3278 	/*
  3220 	 * If the post date is empty (due to having been new or a draft) and status
  3279 	 * If the post date is empty (due to having been new or a draft) and status
  3221 	 * is not 'draft' or 'pending', set date to now.
  3280 	 * is not 'draft' or 'pending', set date to now.
  3222 	 */
  3281 	 */
  3223 	if ( empty( $postarr['post_date'] ) || '0000-00-00 00:00:00' == $postarr['post_date'] ) {
  3282 	if ( empty( $postarr['post_date'] ) || '0000-00-00 00:00:00' == $postarr['post_date'] ) {
  3224 		$post_date = current_time( 'mysql' );
  3283 		if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['post_date_gmt'] ) {
       
  3284 			$post_date = current_time( 'mysql' );
       
  3285 		} else {
       
  3286 			$post_date = get_date_from_gmt( $postarr['post_date_gmt'] );
       
  3287 		}
  3225 	} else {
  3288 	} else {
  3226 		$post_date = $postarr['post_date'];
  3289 		$post_date = $postarr['post_date'];
  3227 	}
  3290 	}
  3228 
  3291 
  3229 	// Validate the date.
  3292 	// Validate the date.
  3231 	$jj = substr( $post_date, 8, 2 );
  3294 	$jj = substr( $post_date, 8, 2 );
  3232 	$aa = substr( $post_date, 0, 4 );
  3295 	$aa = substr( $post_date, 0, 4 );
  3233 	$valid_date = wp_checkdate( $mm, $jj, $aa, $post_date );
  3296 	$valid_date = wp_checkdate( $mm, $jj, $aa, $post_date );
  3234 	if ( ! $valid_date ) {
  3297 	if ( ! $valid_date ) {
  3235 		if ( $wp_error ) {
  3298 		if ( $wp_error ) {
  3236 			return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
  3299 			return new WP_Error( 'invalid_date', __( 'Invalid date.' ) );
  3237 		} else {
  3300 		} else {
  3238 			return 0;
  3301 			return 0;
  3239 		}
  3302 		}
  3240 	}
  3303 	}
  3241 
  3304 
  3261 		if ( 'publish' == $post_status ) {
  3324 		if ( 'publish' == $post_status ) {
  3262 			$now = gmdate('Y-m-d H:i:59');
  3325 			$now = gmdate('Y-m-d H:i:59');
  3263 			if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) ) {
  3326 			if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) ) {
  3264 				$post_status = 'future';
  3327 				$post_status = 'future';
  3265 			}
  3328 			}
  3266 		} elseif( 'future' == $post_status ) {
  3329 		} elseif ( 'future' == $post_status ) {
  3267 			$now = gmdate('Y-m-d H:i:59');
  3330 			$now = gmdate('Y-m-d H:i:59');
  3268 			if ( mysql2date('U', $post_date_gmt, false) <= mysql2date('U', $now, false) ) {
  3331 			if ( mysql2date('U', $post_date_gmt, false) <= mysql2date('U', $now, false) ) {
  3269 				$post_status = 'publish';
  3332 				$post_status = 'publish';
  3270 			}
  3333 			}
  3271 		}
  3334 		}
  3272 	}
  3335 	}
  3273 
  3336 
       
  3337 	// Comment status.
  3274 	if ( empty( $postarr['comment_status'] ) ) {
  3338 	if ( empty( $postarr['comment_status'] ) ) {
  3275 		if ( $update ) {
  3339 		if ( $update ) {
  3276 			$comment_status = 'closed';
  3340 			$comment_status = 'closed';
  3277 		} else {
  3341 		} else {
  3278 			$comment_status = get_option('default_comment_status');
  3342 			$comment_status = get_default_comment_status( $post_type );
  3279 		}
  3343 		}
  3280 	} else {
  3344 	} else {
  3281 		$comment_status = $postarr['comment_status'];
  3345 		$comment_status = $postarr['comment_status'];
  3282 	}
  3346 	}
  3283 
  3347 
  3284 	// These variables are needed by compact() later.
  3348 	// These variables are needed by compact() later.
  3285 	$post_content_filtered = $postarr['post_content_filtered'];
  3349 	$post_content_filtered = $postarr['post_content_filtered'];
  3286 	$post_author = empty( $postarr['post_author'] ) ? $user_id : $postarr['post_author'];
  3350 	$post_author = isset( $postarr['post_author'] ) ? $postarr['post_author'] : $user_id;
  3287 	$ping_status = empty( $postarr['ping_status'] ) ? get_option( 'default_ping_status' ) : $postarr['ping_status'];
  3351 	$ping_status = empty( $postarr['ping_status'] ) ? get_default_comment_status( $post_type, 'pingback' ) : $postarr['ping_status'];
  3288 	$to_ping = isset( $postarr['to_ping'] ) ? sanitize_trackback_urls( $postarr['to_ping'] ) : '';
  3352 	$to_ping = isset( $postarr['to_ping'] ) ? sanitize_trackback_urls( $postarr['to_ping'] ) : '';
  3289 	$pinged = isset( $postarr['pinged'] ) ? $postarr['pinged'] : '';
  3353 	$pinged = isset( $postarr['pinged'] ) ? $postarr['pinged'] : '';
  3290 	$import_id = isset( $postarr['import_id'] ) ? $postarr['import_id'] : 0;
  3354 	$import_id = isset( $postarr['import_id'] ) ? $postarr['import_id'] : 0;
  3291 
  3355 
  3292 	/*
  3356 	/*
  3309 	} else {
  3373 	} else {
  3310 		$post_parent = 0;
  3374 		$post_parent = 0;
  3311 	}
  3375 	}
  3312 
  3376 
  3313 	/**
  3377 	/**
  3314 	 * Filter the post parent -- used to check for and prevent hierarchy loops.
  3378 	 * Filters the post parent -- used to check for and prevent hierarchy loops.
  3315 	 *
  3379 	 *
  3316 	 * @since 3.1.0
  3380 	 * @since 3.1.0
  3317 	 *
  3381 	 *
  3318 	 * @param int   $post_parent Post parent ID.
  3382 	 * @param int   $post_parent Post parent ID.
  3319 	 * @param int   $post_ID     Post ID.
  3383 	 * @param int   $post_ID     Post ID.
  3320 	 * @param array $new_postarr Array of parsed post data.
  3384 	 * @param array $new_postarr Array of parsed post data.
  3321 	 * @param array $postarr     Array of sanitized, but otherwise unmodified post data.
  3385 	 * @param array $postarr     Array of sanitized, but otherwise unmodified post data.
  3322 	 */
  3386 	 */
  3323 	$post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
  3387 	$post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
  3324 
  3388 
       
  3389 	/*
       
  3390 	 * If the post is being untrashed and it has a desired slug stored in post meta,
       
  3391 	 * reassign it.
       
  3392 	 */
       
  3393 	if ( 'trash' === $previous_status && 'trash' !== $post_status ) {
       
  3394 		$desired_post_slug = get_post_meta( $post_ID, '_wp_desired_post_slug', true );
       
  3395 		if ( $desired_post_slug ) {
       
  3396 			delete_post_meta( $post_ID, '_wp_desired_post_slug' );
       
  3397 			$post_name = $desired_post_slug;
       
  3398 		}
       
  3399 	}
       
  3400 
       
  3401 	// If a trashed post has the desired slug, change it and let this post have it.
       
  3402 	if ( 'trash' !== $post_status && $post_name ) {
       
  3403 		wp_add_trashed_suffix_to_post_name_for_trashed_posts( $post_name, $post_ID );
       
  3404 	}
       
  3405 
       
  3406 	// When trashing an existing post, change its slug to allow non-trashed posts to use it.
       
  3407 	if ( 'trash' === $post_status && 'trash' !== $previous_status && 'new' !== $previous_status ) {
       
  3408 		$post_name = wp_add_trashed_suffix_to_post_name_for_post( $post_ID );
       
  3409 	}
       
  3410 
  3325 	$post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent );
  3411 	$post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent );
  3326 
  3412 
  3327 	// Don't unslash.
  3413 	// Don't unslash.
  3328 	$post_mime_type = isset( $postarr['post_mime_type'] ) ? $postarr['post_mime_type'] : '';
  3414 	$post_mime_type = isset( $postarr['post_mime_type'] ) ? $postarr['post_mime_type'] : '';
  3329 
  3415 
  3330 	// Expected_slashed (everything!).
  3416 	// Expected_slashed (everything!).
  3331 	$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' );
  3417 	$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' );
  3332 
  3418 
  3333 	$emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' );
  3419 	$emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' );
  3334 
  3420 
  3335 	foreach( $emoji_fields as $emoji_field ) {
  3421 	foreach ( $emoji_fields as $emoji_field ) {
  3336 		if ( isset( $data[ $emoji_field ] ) ) {
  3422 		if ( isset( $data[ $emoji_field ] ) ) {
  3337 			$charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field );
  3423 			$charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field );
  3338 			if ( 'utf8' === $charset ) {
  3424 			if ( 'utf8' === $charset ) {
  3339 				$data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] );
  3425 				$data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] );
  3340 			}
  3426 			}
  3341 		}
  3427 		}
  3342 	}
  3428 	}
  3343 
  3429 
  3344 	if ( 'attachment' === $post_type ) {
  3430 	if ( 'attachment' === $post_type ) {
  3345 		/**
  3431 		/**
  3346 		 * Filter attachment post data before it is updated in or added to the database.
  3432 		 * Filters attachment post data before it is updated in or added to the database.
  3347 		 *
  3433 		 *
  3348 		 * @since 3.9.0
  3434 		 * @since 3.9.0
  3349 		 *
  3435 		 *
  3350 		 * @param array $data    An array of sanitized attachment post data.
  3436 		 * @param array $data    An array of sanitized attachment post data.
  3351 		 * @param array $postarr An array of unsanitized attachment post data.
  3437 		 * @param array $postarr An array of unsanitized attachment post data.
  3352 		 */
  3438 		 */
  3353 		$data = apply_filters( 'wp_insert_attachment_data', $data, $postarr );
  3439 		$data = apply_filters( 'wp_insert_attachment_data', $data, $postarr );
  3354 	} else {
  3440 	} else {
  3355 		/**
  3441 		/**
  3356 		 * Filter slashed post data just before it is inserted into the database.
  3442 		 * Filters slashed post data just before it is inserted into the database.
  3357 		 *
  3443 		 *
  3358 		 * @since 2.7.0
  3444 		 * @since 2.7.0
  3359 		 *
  3445 		 *
  3360 		 * @param array $data    An array of slashed post data.
  3446 		 * @param array $data    An array of slashed post data.
  3361 		 * @param array $postarr An array of sanitized, but otherwise unmodified post data.
  3447 		 * @param array $postarr An array of sanitized, but otherwise unmodified post data.
  3402 		// Use the newly generated $post_ID.
  3488 		// Use the newly generated $post_ID.
  3403 		$where = array( 'ID' => $post_ID );
  3489 		$where = array( 'ID' => $post_ID );
  3404 	}
  3490 	}
  3405 
  3491 
  3406 	if ( empty( $data['post_name'] ) && ! in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
  3492 	if ( empty( $data['post_name'] ) && ! in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
  3407 		$data['post_name'] = sanitize_title( $data['post_title'], $post_ID );
  3493 		$data['post_name'] = wp_unique_post_slug( sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data['post_status'], $post_type, $post_parent );
  3408 		$wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
  3494 		$wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
       
  3495 		clean_post_cache( $post_ID );
  3409 	}
  3496 	}
  3410 
  3497 
  3411 	if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
  3498 	if ( is_object_in_taxonomy( $post_type, 'category' ) ) {
  3412 		wp_set_post_categories( $post_ID, $post_category );
  3499 		wp_set_post_categories( $post_ID, $post_category );
  3413 	}
  3500 	}
  3418 
  3505 
  3419 	// New-style support for all custom taxonomies.
  3506 	// New-style support for all custom taxonomies.
  3420 	if ( ! empty( $postarr['tax_input'] ) ) {
  3507 	if ( ! empty( $postarr['tax_input'] ) ) {
  3421 		foreach ( $postarr['tax_input'] as $taxonomy => $tags ) {
  3508 		foreach ( $postarr['tax_input'] as $taxonomy => $tags ) {
  3422 			$taxonomy_obj = get_taxonomy($taxonomy);
  3509 			$taxonomy_obj = get_taxonomy($taxonomy);
       
  3510 			if ( ! $taxonomy_obj ) {
       
  3511 				/* translators: %s: taxonomy name */
       
  3512 				_doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid taxonomy: %s.' ), $taxonomy ), '4.4.0' );
       
  3513 				continue;
       
  3514 			}
       
  3515 
  3423 			// array = hierarchical, string = non-hierarchical.
  3516 			// array = hierarchical, string = non-hierarchical.
  3424 			if ( is_array( $tags ) ) {
  3517 			if ( is_array( $tags ) ) {
  3425 				$tags = array_filter($tags);
  3518 				$tags = array_filter($tags);
  3426 			}
  3519 			}
  3427 			if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
  3520 			if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) {
  3428 				wp_set_post_terms( $post_ID, $tags, $taxonomy );
  3521 				wp_set_post_terms( $post_ID, $tags, $taxonomy );
  3429 			}
  3522 			}
  3430 		}
  3523 		}
  3431 	}
  3524 	}
  3432 
  3525 
       
  3526 	if ( ! empty( $postarr['meta_input'] ) ) {
       
  3527 		foreach ( $postarr['meta_input'] as $field => $value ) {
       
  3528 			update_post_meta( $post_ID, $field, $value );
       
  3529 		}
       
  3530 	}
       
  3531 
  3433 	$current_guid = get_post_field( 'guid', $post_ID );
  3532 	$current_guid = get_post_field( 'guid', $post_ID );
  3434 
  3533 
  3435 	// Set GUID.
  3534 	// Set GUID.
  3436 	if ( ! $update && '' == $current_guid ) {
  3535 	if ( ! $update && '' == $current_guid ) {
  3437 		$wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
  3536 		$wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
  3445 		if ( ! empty( $postarr['context'] ) ) {
  3544 		if ( ! empty( $postarr['context'] ) ) {
  3446 			add_post_meta( $post_ID, '_wp_attachment_context', $postarr['context'], true );
  3545 			add_post_meta( $post_ID, '_wp_attachment_context', $postarr['context'], true );
  3447 		}
  3546 		}
  3448 	}
  3547 	}
  3449 
  3548 
       
  3549 	// Set or remove featured image.
       
  3550 	if ( isset( $postarr['_thumbnail_id'] ) ) {
       
  3551 		$thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' ) || 'revision' === $post_type;
       
  3552 		if ( ! $thumbnail_support && 'attachment' === $post_type && $post_mime_type ) {
       
  3553 			if ( wp_attachment_is( 'audio', $post_ID ) ) {
       
  3554 				$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
       
  3555 			} elseif ( wp_attachment_is( 'video', $post_ID ) ) {
       
  3556 				$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
       
  3557 			}
       
  3558 		}
       
  3559 
       
  3560 		if ( $thumbnail_support ) {
       
  3561 			$thumbnail_id = intval( $postarr['_thumbnail_id'] );
       
  3562 			if ( -1 === $thumbnail_id ) {
       
  3563 				delete_post_thumbnail( $post_ID );
       
  3564 			} else {
       
  3565 				set_post_thumbnail( $post_ID, $thumbnail_id );
       
  3566 			}
       
  3567 		}
       
  3568 	}
       
  3569 
  3450 	clean_post_cache( $post_ID );
  3570 	clean_post_cache( $post_ID );
  3451 
  3571 
  3452 	$post = get_post( $post_ID );
  3572 	$post = get_post( $post_ID );
  3453 
  3573 
  3454 	if ( ! empty( $postarr['page_template'] ) && 'page' == $data['post_type'] ) {
  3574 	if ( ! empty( $postarr['page_template'] ) ) {
  3455 		$post->page_template = $postarr['page_template'];
  3575 		$post->page_template = $postarr['page_template'];
  3456 		$page_templates = wp_get_theme()->get_page_templates( $post );
  3576 		$page_templates = wp_get_theme()->get_page_templates( $post );
  3457 		if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) {
  3577 		if ( 'default' != $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) {
  3458 			if ( $wp_error ) {
  3578 			if ( $wp_error ) {
  3459 				return new WP_Error('invalid_page_template', __('The page template is invalid.'));
  3579 				return new WP_Error( 'invalid_page_template', __( 'Invalid page template.' ) );
  3460 			}
  3580 			}
  3461 			update_post_meta( $post_ID, '_wp_page_template', 'default' );
  3581 			update_post_meta( $post_ID, '_wp_page_template', 'default' );
  3462 		} else {
  3582 		} else {
  3463 			update_post_meta( $post_ID, '_wp_page_template', $postarr['page_template'] );
  3583 			update_post_meta( $post_ID, '_wp_page_template', $postarr['page_template'] );
  3464 		}
  3584 		}
  3474 			 * @since 2.0.0
  3594 			 * @since 2.0.0
  3475 			 *
  3595 			 *
  3476 			 * @param int $post_ID Attachment ID.
  3596 			 * @param int $post_ID Attachment ID.
  3477 			 */
  3597 			 */
  3478 			do_action( 'edit_attachment', $post_ID );
  3598 			do_action( 'edit_attachment', $post_ID );
       
  3599 			$post_after = get_post( $post_ID );
       
  3600 
       
  3601 			/**
       
  3602 			 * Fires once an existing attachment has been updated.
       
  3603 			 *
       
  3604 			 * @since 4.4.0
       
  3605 			 *
       
  3606 			 * @param int     $post_ID      Post ID.
       
  3607 			 * @param WP_Post $post_after   Post object following the update.
       
  3608 			 * @param WP_Post $post_before  Post object before the update.
       
  3609 			 */
       
  3610 			do_action( 'attachment_updated', $post_ID, $post_after, $post_before );
  3479 		} else {
  3611 		} else {
  3480 
  3612 
  3481 			/**
  3613 			/**
  3482 			 * Fires once an attachment has been added.
  3614 			 * Fires once an attachment has been added.
  3483 			 *
  3615 			 *
  3660  * from publishing drafts, etc.
  3792  * from publishing drafts, etc.
  3661  *
  3793  *
  3662  * @since 2.5.0
  3794  * @since 2.5.0
  3663  *
  3795  *
  3664  * @param int|WP_Post $post_id Post ID or post object.
  3796  * @param int|WP_Post $post_id Post ID or post object.
  3665  * @return null Nothing is returned. Which can mean that no action is required
       
  3666  *              or post was published.
       
  3667  */
  3797  */
  3668 function check_and_publish_future_post( $post_id ) {
  3798 function check_and_publish_future_post( $post_id ) {
  3669 
       
  3670 	$post = get_post($post_id);
  3799 	$post = get_post($post_id);
  3671 
  3800 
  3672 	if ( empty($post) )
  3801 	if ( empty($post) )
  3673 		return;
  3802 		return;
  3674 
  3803 
  3682 		wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // clear anything else in the system
  3811 		wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // clear anything else in the system
  3683 		wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
  3812 		wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
  3684 		return;
  3813 		return;
  3685 	}
  3814 	}
  3686 
  3815 
  3687 	return wp_publish_post($post_id);
  3816 	// wp_publish_post() returns no meaningful value.
       
  3817 	wp_publish_post( $post_id );
  3688 }
  3818 }
  3689 
  3819 
  3690 /**
  3820 /**
  3691  * Computes a unique slug for the post, when given the desired slug and some post details.
  3821  * Computes a unique slug for the post, when given the desired slug and some post details.
  3692  *
  3822  *
  3693  * @since 2.8.0
  3823  * @since 2.8.0
  3694  *
  3824  *
  3695  * @global wpdb $wpdb WordPress database abstraction object.
  3825  * @global wpdb       $wpdb WordPress database abstraction object.
  3696  * @global WP_Rewrite $wp_rewrite
  3826  * @global WP_Rewrite $wp_rewrite
  3697  *
  3827  *
  3698  * @param string $slug        The desired slug (post_name).
  3828  * @param string $slug        The desired slug (post_name).
  3699  * @param int    $post_ID     Post ID.
  3829  * @param int    $post_ID     Post ID.
  3700  * @param string $post_status No uniqueness checks are made if the post is still draft or pending.
  3830  * @param string $post_status No uniqueness checks are made if the post is still draft or pending.
  3701  * @param string $post_type   Post type.
  3831  * @param string $post_type   Post type.
  3702  * @param int    $post_parent Post parent ID.
  3832  * @param int    $post_parent Post parent ID.
  3703  * @return string Unique slug for the post, based on $post_name (with a -1, -2, etc. suffix)
  3833  * @return string Unique slug for the post, based on $post_name (with a -1, -2, etc. suffix)
  3704  */
  3834  */
  3705 function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) {
  3835 function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) {
  3706 	if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) || ( 'inherit' == $post_status && 'revision' == $post_type ) )
  3836 	if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) || ( 'inherit' == $post_status && 'revision' == $post_type ) || 'user_request' === $post_type )
  3707 		return $slug;
  3837 		return $slug;
  3708 
  3838 
  3709 	global $wpdb, $wp_rewrite;
  3839 	global $wpdb, $wp_rewrite;
  3710 
  3840 
  3711 	$original_slug = $slug;
  3841 	$original_slug = $slug;
  3718 		// Attachment slugs must be unique across all types.
  3848 		// Attachment slugs must be unique across all types.
  3719 		$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
  3849 		$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
  3720 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
  3850 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
  3721 
  3851 
  3722 		/**
  3852 		/**
  3723 		 * Filter whether the post slug would make a bad attachment slug.
  3853 		 * Filters whether the post slug would make a bad attachment slug.
  3724 		 *
  3854 		 *
  3725 		 * @since 3.1.0
  3855 		 * @since 3.1.0
  3726 		 *
  3856 		 *
  3727 		 * @param bool   $bad_slug Whether the slug would be bad as an attachment slug.
  3857 		 * @param bool   $bad_slug Whether the slug would be bad as an attachment slug.
  3728 		 * @param string $slug     The post slug.
  3858 		 * @param string $slug     The post slug.
  3729 		 */
  3859 		 */
  3730 		if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
  3860 		if ( $post_name_check || in_array( $slug, $feeds ) || 'embed' === $slug || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
  3731 			$suffix = 2;
  3861 			$suffix = 2;
  3732 			do {
  3862 			do {
  3733 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3863 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3734 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID ) );
  3864 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID ) );
  3735 				$suffix++;
  3865 				$suffix++;
  3746 		 */
  3876 		 */
  3747 		$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";
  3877 		$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";
  3748 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );
  3878 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) );
  3749 
  3879 
  3750 		/**
  3880 		/**
  3751 		 * Filter whether the post slug would make a bad hierarchical post slug.
  3881 		 * Filters whether the post slug would make a bad hierarchical post slug.
  3752 		 *
  3882 		 *
  3753 		 * @since 3.1.0
  3883 		 * @since 3.1.0
  3754 		 *
  3884 		 *
  3755 		 * @param bool   $bad_slug    Whether the post slug would be bad in a hierarchical post context.
  3885 		 * @param bool   $bad_slug    Whether the post slug would be bad in a hierarchical post context.
  3756 		 * @param string $slug        The post slug.
  3886 		 * @param string $slug        The post slug.
  3757 		 * @param string $post_type   Post type.
  3887 		 * @param string $post_type   Post type.
  3758 		 * @param int    $post_parent Post parent ID.
  3888 		 * @param int    $post_parent Post parent ID.
  3759 		 */
  3889 		 */
  3760 		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 ) ) {
  3890 		if ( $post_name_check || in_array( $slug, $feeds ) || 'embed' === $slug || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug )  || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ) ) {
  3761 			$suffix = 2;
  3891 			$suffix = 2;
  3762 			do {
  3892 			do {
  3763 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3893 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3764 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID, $post_parent ) );
  3894 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID, $post_parent ) );
  3765 				$suffix++;
  3895 				$suffix++;
  3769 	} else {
  3899 	} else {
  3770 		// Post slugs must be unique across all posts.
  3900 		// Post slugs must be unique across all posts.
  3771 		$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
  3901 		$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
  3772 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );
  3902 		$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );
  3773 
  3903 
       
  3904 		// Prevent new post slugs that could result in URLs that conflict with date archives.
       
  3905 		$post = get_post( $post_ID );
       
  3906 		$conflicts_with_date_archive = false;
       
  3907 		if ( 'post' === $post_type && ( ! $post || $post->post_name !== $slug ) && preg_match( '/^[0-9]+$/', $slug ) && $slug_num = intval( $slug ) ) {
       
  3908 			$permastructs   = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
       
  3909 			$postname_index = array_search( '%postname%', $permastructs );
       
  3910 
       
  3911 			/*
       
  3912 			 * Potential date clashes are as follows:
       
  3913 			 *
       
  3914 			 * - Any integer in the first permastruct position could be a year.
       
  3915 			 * - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum'.
       
  3916 			 * - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day'.
       
  3917 			 */
       
  3918 			if ( 0 === $postname_index ||
       
  3919 				( $postname_index && '%year%' === $permastructs[ $postname_index - 1 ] && 13 > $slug_num ) ||
       
  3920 				( $postname_index && '%monthnum%' === $permastructs[ $postname_index - 1 ] && 32 > $slug_num )
       
  3921 			) {
       
  3922 				$conflicts_with_date_archive = true;
       
  3923 			}
       
  3924 		}
       
  3925 
  3774 		/**
  3926 		/**
  3775 		 * Filter whether the post slug would be bad as a flat slug.
  3927 		 * Filters whether the post slug would be bad as a flat slug.
  3776 		 *
  3928 		 *
  3777 		 * @since 3.1.0
  3929 		 * @since 3.1.0
  3778 		 *
  3930 		 *
  3779 		 * @param bool   $bad_slug  Whether the post slug would be bad as a flat slug.
  3931 		 * @param bool   $bad_slug  Whether the post slug would be bad as a flat slug.
  3780 		 * @param string $slug      The post slug.
  3932 		 * @param string $slug      The post slug.
  3781 		 * @param string $post_type Post type.
  3933 		 * @param string $post_type Post type.
  3782 		 */
  3934 		 */
  3783 		if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
  3935 		if ( $post_name_check || in_array( $slug, $feeds ) || 'embed' === $slug || $conflicts_with_date_archive || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
  3784 			$suffix = 2;
  3936 			$suffix = 2;
  3785 			do {
  3937 			do {
  3786 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3938 				$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
  3787 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) );
  3939 				$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) );
  3788 				$suffix++;
  3940 				$suffix++;
  3790 			$slug = $alt_post_name;
  3942 			$slug = $alt_post_name;
  3791 		}
  3943 		}
  3792 	}
  3944 	}
  3793 
  3945 
  3794 	/**
  3946 	/**
  3795 	 * Filter the unique post slug.
  3947 	 * Filters the unique post slug.
  3796 	 *
  3948 	 *
  3797 	 * @since 3.3.0
  3949 	 * @since 3.3.0
  3798 	 *
  3950 	 *
  3799 	 * @param string $slug          The post slug.
  3951 	 * @param string $slug          The post slug.
  3800 	 * @param int    $post_ID       Post ID.
  3952 	 * @param int    $post_ID       Post ID.
  3835  *
  3987  *
  3836  * @see wp_set_post_tags()
  3988  * @see wp_set_post_tags()
  3837  *
  3989  *
  3838  * @since 2.3.0
  3990  * @since 2.3.0
  3839  *
  3991  *
  3840  * @param int    $post_id Optional. The Post ID. Does not default to the ID of the global $post.
  3992  * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
  3841  *                        Default 0.
  3993  * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
  3842  * @param string $tags    Optional. The tags to set for the post, separated by commas. Default empty.
  3994  *                              separated by commas. Default empty.
  3843  * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise.
  3995  * @return array|false|WP_Error Array of affected term IDs. WP_Error or false on failure.
  3844  */
  3996  */
  3845 function wp_add_post_tags( $post_id = 0, $tags = '' ) {
  3997 function wp_add_post_tags( $post_id = 0, $tags = '' ) {
  3846 	return wp_set_post_tags($post_id, $tags, true);
  3998 	return wp_set_post_tags($post_id, $tags, true);
  3847 }
  3999 }
  3848 
  4000 
  3851  *
  4003  *
  3852  * @since 2.3.0
  4004  * @since 2.3.0
  3853  *
  4005  *
  3854  * @see wp_set_object_terms()
  4006  * @see wp_set_object_terms()
  3855  *
  4007  *
  3856  * @param int    $post_id Optional. The Post ID. Does not default to the ID of the global $post.
  4008  * @param int          $post_id Optional. The Post ID. Does not default to the ID of the global $post.
  3857  * @param string $tags    Optional. The tags to set for the post, separated by commas.
  4009  * @param string|array $tags    Optional. An array of tags to set for the post, or a string of tags
  3858  *                        Default empty.
  4010  *                              separated by commas. Default empty.
  3859  * @param bool   $append  Optional. If true, don't delete existing tags, just add on. If false,
  4011  * @param bool         $append  Optional. If true, don't delete existing tags, just add on. If false,
  3860  *                        replace the tags with the new tags. Default false.
  4012  *                              replace the tags with the new tags. Default false.
  3861  * @return mixed Array of affected term IDs. WP_Error or false on failure.
  4013  * @return array|false|WP_Error Array of term taxonomy IDs of affected terms. WP_Error or false on failure.
  3862  */
  4014  */
  3863 function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
  4015 function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
  3864 	return wp_set_post_terms( $post_id, $tags, 'post_tag', $append);
  4016 	return wp_set_post_terms( $post_id, $tags, 'post_tag', $append);
  3865 }
  4017 }
  3866 
  4018 
  3869  *
  4021  *
  3870  * @since 2.8.0
  4022  * @since 2.8.0
  3871  *
  4023  *
  3872  * @see wp_set_object_terms()
  4024  * @see wp_set_object_terms()
  3873  *
  4025  *
  3874  * @param int    $post_id  Optional. The Post ID. Does not default to the ID of the global $post.
  4026  * @param int          $post_id  Optional. The Post ID. Does not default to the ID of the global $post.
  3875  * @param string $tags     Optional. The tags to set for the post, separated by commas. Default empty.
  4027  * @param string|array $tags     Optional. An array of terms to set for the post, or a string of terms
  3876  * @param string $taxonomy Optional. Taxonomy name. Default 'post_tag'.
  4028  *                               separated by commas. Default empty.
  3877  * @param bool   $append   Optional. If true, don't delete existing tags, just add on. If false,
  4029  * @param string       $taxonomy Optional. Taxonomy name. Default 'post_tag'.
  3878  *                         replace the tags with the new tags. Default false.
  4030  * @param bool         $append   Optional. If true, don't delete existing terms, just add on. If false,
  3879  * @return mixed Array of affected term IDs. WP_Error or false on failure.
  4031  *                               replace the terms with the new terms. Default false.
       
  4032  * @return array|false|WP_Error Array of term taxonomy IDs of affected terms. WP_Error or false on failure.
  3880  */
  4033  */
  3881 function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = false ) {
  4034 function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = false ) {
  3882 	$post_id = (int) $post_id;
  4035 	$post_id = (int) $post_id;
  3883 
  4036 
  3884 	if ( !$post_id )
  4037 	if ( !$post_id )
  3917  *                                   of the global $post. Default 0.
  4070  *                                   of the global $post. Default 0.
  3918  * @param array|int $post_categories Optional. List of categories or ID of category.
  4071  * @param array|int $post_categories Optional. List of categories or ID of category.
  3919  *                                   Default empty array.
  4072  *                                   Default empty array.
  3920  * @param bool      $append         If true, don't delete existing categories, just add on.
  4073  * @param bool      $append         If true, don't delete existing categories, just add on.
  3921  *                                  If false, replace the categories with the new categories.
  4074  *                                  If false, replace the categories with the new categories.
  3922  * @return bool|mixed
  4075  * @return array|false|WP_Error Array of term taxonomy IDs of affected categories. WP_Error or false on failure.
  3923  */
  4076  */
  3924 function wp_set_post_categories( $post_ID = 0, $post_categories = array(), $append = false ) {
  4077 function wp_set_post_categories( $post_ID = 0, $post_categories = array(), $append = false ) {
  3925 	$post_ID = (int) $post_ID;
  4078 	$post_ID = (int) $post_ID;
  3926 	$post_type = get_post_type( $post_ID );
  4079 	$post_type = get_post_type( $post_ID );
  3927 	$post_status = get_post_status( $post_ID );
  4080 	$post_status = get_post_status( $post_ID );
  3940 
  4093 
  3941 	return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
  4094 	return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
  3942 }
  4095 }
  3943 
  4096 
  3944 /**
  4097 /**
  3945  * Transition the post status of a post.
  4098  * Fires actions related to the transitioning of a post's status.
  3946  *
  4099  *
  3947  * When a post is saved, the post status is "transitioned" from one status to another,
  4100  * When a post is saved, the post status is "transitioned" from one status to another,
  3948  * though this does not always mean the status has actually changed before and after
  4101  * though this does not always mean the status has actually changed before and after
  3949  * the save.
  4102  * the save. This function fires a number of action hooks related to that transition:
       
  4103  * the generic {@see 'transition_post_status'} action, as well as the dynamic hooks
       
  4104  * {@see '$old_status_to_$new_status'} and {@see '$new_status_$post->post_type'}. Note
       
  4105  * that the function does not transition the post object in the database.
  3950  *
  4106  *
  3951  * For instance: When publishing a post for the first time, the post status may transition
  4107  * For instance: When publishing a post for the first time, the post status may transition
  3952  * from 'draft' – or some other status – to 'publish'. However, if a post is already
  4108  * from 'draft' – or some other status – to 'publish'. However, if a post is already
  3953  * published and is simply being updated, the "old" and "new" statuses may both be 'publish'
  4109  * published and is simply being updated, the "old" and "new" statuses may both be 'publish'
  3954  * before and after the transition.
  4110  * before and after the transition.
  4004 	 */
  4160 	 */
  4005 	do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
  4161 	do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
  4006 }
  4162 }
  4007 
  4163 
  4008 //
  4164 //
  4009 // Trackback and ping functions
  4165 // Comment, trackback, and pingback functions.
  4010 //
  4166 //
  4011 
  4167 
  4012 /**
  4168 /**
  4013  * Add a URL to those already pinged.
  4169  * Add a URL to those already pinged.
  4014  *
  4170  *
  4015  * @since 1.5.0
  4171  * @since 1.5.0
       
  4172  * @since 4.7.0 $post_id can be a WP_Post object.
       
  4173  * @since 4.7.0 $uri can be an array of URIs.
  4016  *
  4174  *
  4017  * @global wpdb $wpdb WordPress database abstraction object.
  4175  * @global wpdb $wpdb WordPress database abstraction object.
  4018  *
  4176  *
  4019  * @param int    $post_id Post ID.
  4177  * @param int|WP_Post  $post_id Post object or ID.
  4020  * @param string $uri     Ping URI.
  4178  * @param string|array $uri     Ping URI or array of URIs.
  4021  * @return int How many rows were updated.
  4179  * @return int|false How many rows were updated.
  4022  */
  4180  */
  4023 function add_ping( $post_id, $uri ) {
  4181 function add_ping( $post_id, $uri ) {
  4024 	global $wpdb;
  4182 	global $wpdb;
  4025 	$pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
  4183 
  4026 	$pung = trim($pung);
  4184 	$post = get_post( $post_id );
  4027 	$pung = preg_split('/\s/', $pung);
  4185 	if ( ! $post ) {
  4028 	$pung[] = $uri;
  4186 		return false;
       
  4187 	}
       
  4188 
       
  4189 	$pung = trim( $post->pinged );
       
  4190 	$pung = preg_split( '/\s/', $pung );
       
  4191 
       
  4192 	if ( is_array( $uri ) ) {
       
  4193 		$pung = array_merge( $pung, $uri );
       
  4194 	}
       
  4195 	else {
       
  4196 		$pung[] = $uri;
       
  4197 	}
  4029 	$new = implode("\n", $pung);
  4198 	$new = implode("\n", $pung);
  4030 
  4199 
  4031 	/**
  4200 	/**
  4032 	 * Filter the new ping URL to add for the given post.
  4201 	 * Filters the new ping URL to add for the given post.
  4033 	 *
  4202 	 *
  4034 	 * @since 2.0.0
  4203 	 * @since 2.0.0
  4035 	 *
  4204 	 *
  4036 	 * @param string $new New ping URL to add.
  4205 	 * @param string $new New ping URL to add.
  4037 	 */
  4206 	 */
  4038 	$new = apply_filters( 'add_ping', $new );
  4207 	$new = apply_filters( 'add_ping', $new );
  4039 
  4208 
  4040 	// expected_slashed ($new).
  4209 	$return = $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post->ID ) );
  4041 	$new = wp_unslash($new);
  4210 	clean_post_cache( $post->ID );
  4042 	return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
  4211 	return $return;
  4043 }
  4212 }
  4044 
  4213 
  4045 /**
  4214 /**
  4046  * Retrieve enclosures already enclosed for a post.
  4215  * Retrieve enclosures already enclosed for a post.
  4047  *
  4216  *
  4057 		return $pung;
  4226 		return $pung;
  4058 
  4227 
  4059 	foreach ( $custom_fields as $key => $val ) {
  4228 	foreach ( $custom_fields as $key => $val ) {
  4060 		if ( 'enclosure' != $key || !is_array( $val ) )
  4229 		if ( 'enclosure' != $key || !is_array( $val ) )
  4061 			continue;
  4230 			continue;
  4062 		foreach( $val as $enc ) {
  4231 		foreach ( $val as $enc ) {
  4063 			$enclosure = explode( "\n", $enc );
  4232 			$enclosure = explode( "\n", $enc );
  4064 			$pung[] = trim( $enclosure[ 0 ] );
  4233 			$pung[] = trim( $enclosure[ 0 ] );
  4065 		}
  4234 		}
  4066 	}
  4235 	}
  4067 
  4236 
  4068 	/**
  4237 	/**
  4069 	 * Filter the list of enclosures already enclosed for the given post.
  4238 	 * Filters the list of enclosures already enclosed for the given post.
  4070 	 *
  4239 	 *
  4071 	 * @since 2.0.0
  4240 	 * @since 2.0.0
  4072 	 *
  4241 	 *
  4073 	 * @param array $pung    Array of enclosures for the given post.
  4242 	 * @param array $pung    Array of enclosures for the given post.
  4074 	 * @param int   $post_id Post ID.
  4243 	 * @param int   $post_id Post ID.
  4075 	 */
  4244 	 */
  4076 	$pung = apply_filters( 'get_enclosed', $pung, $post_id );
  4245 	return apply_filters( 'get_enclosed', $pung, $post_id );
  4077 	return $pung;
       
  4078 }
  4246 }
  4079 
  4247 
  4080 /**
  4248 /**
  4081  * Retrieve URLs already pinged for a post.
  4249  * Retrieve URLs already pinged for a post.
  4082  *
  4250  *
  4083  * @since 1.5.0
  4251  * @since 1.5.0
  4084  *
  4252  *
  4085  * @global wpdb $wpdb WordPress database abstraction object.
  4253  * @since 4.7.0 $post_id can be a WP_Post object.
  4086  *
  4254  *
  4087  * @param int $post_id Post ID.
  4255  * @param int|WP_Post $post_id Post ID or object.
  4088  * @return array
  4256  * @return array
  4089  */
  4257  */
  4090 function get_pung( $post_id ) {
  4258 function get_pung( $post_id ) {
  4091 	global $wpdb;
  4259 	$post = get_post( $post_id );
  4092 	$pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
  4260 	if ( ! $post ) {
  4093 	$pung = trim($pung);
  4261 		return false;
  4094 	$pung = preg_split('/\s/', $pung);
  4262 	}
       
  4263 
       
  4264 	$pung = trim( $post->pinged );
       
  4265 	$pung = preg_split( '/\s/', $pung );
  4095 
  4266 
  4096 	/**
  4267 	/**
  4097 	 * Filter the list of already-pinged URLs for the given post.
  4268 	 * Filters the list of already-pinged URLs for the given post.
  4098 	 *
  4269 	 *
  4099 	 * @since 2.0.0
  4270 	 * @since 2.0.0
  4100 	 *
  4271 	 *
  4101 	 * @param array $pung Array of URLs already pinged for the given post.
  4272 	 * @param array $pung Array of URLs already pinged for the given post.
  4102 	 */
  4273 	 */
  4103 	$pung = apply_filters( 'get_pung', $pung );
  4274 	return apply_filters( 'get_pung', $pung );
  4104 	return $pung;
       
  4105 }
  4275 }
  4106 
  4276 
  4107 /**
  4277 /**
  4108  * Retrieve URLs that need to be pinged.
  4278  * Retrieve URLs that need to be pinged.
  4109  *
  4279  *
  4110  * @since 1.5.0
  4280  * @since 1.5.0
  4111  *
  4281  * @since 4.7.0 $post_id can be a WP_Post object.
  4112  * @global wpdb $wpdb WordPress database abstraction object.
  4282  *
  4113  *
  4283  * @param int|WP_Post $post_id Post Object or ID
  4114  * @param int $post_id Post ID
       
  4115  * @return array
  4284  * @return array
  4116  */
  4285  */
  4117 function get_to_ping( $post_id ) {
  4286 function get_to_ping( $post_id ) {
  4118 	global $wpdb;
  4287 	$post = get_post( $post_id );
  4119 	$to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
  4288 
  4120 	$to_ping = sanitize_trackback_urls( $to_ping );
  4289 	if ( ! $post ) {
       
  4290 		return false;
       
  4291 	}
       
  4292 
       
  4293 	$to_ping = sanitize_trackback_urls( $post->to_ping );
  4121 	$to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
  4294 	$to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
  4122 
  4295 
  4123 	/**
  4296 	/**
  4124 	 * Filter the list of URLs yet to ping for the given post.
  4297 	 * Filters the list of URLs yet to ping for the given post.
  4125 	 *
  4298 	 *
  4126 	 * @since 2.0.0
  4299 	 * @since 2.0.0
  4127 	 *
  4300 	 *
  4128 	 * @param array $to_ping List of URLs yet to ping.
  4301 	 * @param array $to_ping List of URLs yet to ping.
  4129 	 */
  4302 	 */
  4130 	$to_ping = apply_filters( 'get_to_ping', $to_ping );
  4303 	return apply_filters( 'get_to_ping', $to_ping );
  4131 	return $to_ping;
       
  4132 }
  4304 }
  4133 
  4305 
  4134 /**
  4306 /**
  4135  * Do trackbacks for a list of URLs.
  4307  * Do trackbacks for a list of URLs.
  4136  *
  4308  *
  4150 		if ( strlen( $excerpt ) > 255 ) {
  4322 		if ( strlen( $excerpt ) > 255 ) {
  4151 			$excerpt = substr( $excerpt, 0, 252 ) . '&hellip;';
  4323 			$excerpt = substr( $excerpt, 0, 252 ) . '&hellip;';
  4152 		}
  4324 		}
  4153 
  4325 
  4154 		$trackback_urls = explode( ',', $tb_list );
  4326 		$trackback_urls = explode( ',', $tb_list );
  4155 		foreach( (array) $trackback_urls as $tb_url ) {
  4327 		foreach ( (array) $trackback_urls as $tb_url ) {
  4156 			$tb_url = trim( $tb_url );
  4328 			$tb_url = trim( $tb_url );
  4157 			trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id );
  4329 			trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id );
  4158 		}
  4330 		}
  4159 	}
  4331 	}
  4160 }
  4332 }
  4191  *
  4363  *
  4192  * @since 1.5.1
  4364  * @since 1.5.1
  4193  * @deprecated 3.5.0 Use get_post()
  4365  * @deprecated 3.5.0 Use get_post()
  4194  *
  4366  *
  4195  * @param mixed  $page   Page object or page ID. Passed by reference.
  4367  * @param mixed  $page   Page object or page ID. Passed by reference.
  4196  * @param string $output Optional. What to output. Accepts OBJECT, ARRAY_A, or ARRAY_N.
  4368  * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
  4197  *                       Default OBJECT.
  4369  *                       a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
  4198  * @param string $filter Optional. How the return value should be filtered. Accepts 'raw',
  4370  * @param string $filter Optional. How the return value should be filtered. Accepts 'raw',
  4199  *                       'edit', 'db', 'display'. Default 'raw'.
  4371  *                       'edit', 'db', 'display'. Default 'raw'.
  4200  * @return WP_Post|null WP_Post on success or null on failure.
  4372  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
  4201  */
  4373  */
  4202 function get_page( $page, $output = OBJECT, $filter = 'raw') {
  4374 function get_page( $page, $output = OBJECT, $filter = 'raw') {
  4203 	return get_post( $page, $output, $filter );
  4375 	return get_post( $page, $output, $filter );
  4204 }
  4376 }
  4205 
  4377 
  4209  * @since 2.1.0
  4381  * @since 2.1.0
  4210  *
  4382  *
  4211  * @global wpdb $wpdb WordPress database abstraction object.
  4383  * @global wpdb $wpdb WordPress database abstraction object.
  4212  *
  4384  *
  4213  * @param string       $page_path Page path.
  4385  * @param string       $page_path Page path.
  4214  * @param string       $output    Optional. Output type. Accepts OBJECT, ARRAY_N, or ARRAY_A.
  4386  * @param string       $output    Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
  4215  *                                Default OBJECT.
  4387  *                                a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
  4216  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
  4388  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
  4217  * @return WP_Post|null WP_Post on success or null on failure.
  4389  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
  4218  */
  4390  */
  4219 function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
  4391 function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
  4220 	global $wpdb;
  4392 	global $wpdb;
       
  4393 
       
  4394 	$last_changed = wp_cache_get_last_changed( 'posts' );
       
  4395 
       
  4396 	$hash = md5( $page_path . serialize( $post_type ) );
       
  4397 	$cache_key = "get_page_by_path:$hash:$last_changed";
       
  4398 	$cached = wp_cache_get( $cache_key, 'posts' );
       
  4399 	if ( false !== $cached ) {
       
  4400 		// Special case: '0' is a bad `$page_path`.
       
  4401 		if ( '0' === $cached || 0 === $cached ) {
       
  4402 			return;
       
  4403 		} else {
       
  4404 			return get_post( $cached, $output );
       
  4405 		}
       
  4406 	}
  4221 
  4407 
  4222 	$page_path = rawurlencode(urldecode($page_path));
  4408 	$page_path = rawurlencode(urldecode($page_path));
  4223 	$page_path = str_replace('%2F', '/', $page_path);
  4409 	$page_path = str_replace('%2F', '/', $page_path);
  4224 	$page_path = str_replace('%20', ' ', $page_path);
  4410 	$page_path = str_replace('%20', ' ', $page_path);
  4225 	$parts = explode( '/', trim( $page_path, '/' ) );
  4411 	$parts = explode( '/', trim( $page_path, '/' ) );
  4226 	$parts = esc_sql( $parts );
       
  4227 	$parts = array_map( 'sanitize_title_for_query', $parts );
  4412 	$parts = array_map( 'sanitize_title_for_query', $parts );
  4228 
  4413 	$escaped_parts = esc_sql( $parts );
  4229 	$in_string = "'" . implode( "','", $parts ) . "'";
  4414 
       
  4415 	$in_string = "'" . implode( "','", $escaped_parts ) . "'";
  4230 
  4416 
  4231 	if ( is_array( $post_type ) ) {
  4417 	if ( is_array( $post_type ) ) {
  4232 		$post_types = $post_type;
  4418 		$post_types = $post_type;
  4233 	} else {
  4419 	} else {
  4234 		$post_types = array( $post_type, 'attachment' );
  4420 		$post_types = array( $post_type, 'attachment' );
  4250 	$foundid = 0;
  4436 	$foundid = 0;
  4251 	foreach ( (array) $pages as $page ) {
  4437 	foreach ( (array) $pages as $page ) {
  4252 		if ( $page->post_name == $revparts[0] ) {
  4438 		if ( $page->post_name == $revparts[0] ) {
  4253 			$count = 0;
  4439 			$count = 0;
  4254 			$p = $page;
  4440 			$p = $page;
       
  4441 
       
  4442 			/*
       
  4443 			 * Loop through the given path parts from right to left,
       
  4444 			 * ensuring each matches the post ancestry.
       
  4445 			 */
  4255 			while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
  4446 			while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
  4256 				$count++;
  4447 				$count++;
  4257 				$parent = $pages[ $p->post_parent ];
  4448 				$parent = $pages[ $p->post_parent ];
  4258 				if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] )
  4449 				if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] )
  4259 					break;
  4450 					break;
  4266 					break;
  4457 					break;
  4267 			}
  4458 			}
  4268 		}
  4459 		}
  4269 	}
  4460 	}
  4270 
  4461 
  4271 	if ( $foundid )
  4462 	// We cache misses as well as hits.
       
  4463 	wp_cache_set( $cache_key, $foundid, 'posts' );
       
  4464 
       
  4465 	if ( $foundid ) {
  4272 		return get_post( $foundid, $output );
  4466 		return get_post( $foundid, $output );
  4273 
  4467 	}
  4274 	return null;
       
  4275 }
  4468 }
  4276 
  4469 
  4277 /**
  4470 /**
  4278  * Retrieve a page given its title.
  4471  * Retrieve a page given its title.
  4279  *
  4472  *
  4280  * @since 2.1.0
  4473  * @since 2.1.0
  4281  *
  4474  *
  4282  * @global wpdb $wpdb WordPress database abstraction object.
  4475  * @global wpdb $wpdb WordPress database abstraction object.
  4283  *
  4476  *
  4284  * @param string       $page_title Page title
  4477  * @param string       $page_title Page title
  4285  * @param string       $output     Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A.
  4478  * @param string       $output     Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
  4286  *                                 Default OBJECT.
  4479  *                                 a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
  4287  * @param string|array $post_type  Optional. Post type or array of post types. Default 'page'.
  4480  * @param string|array $post_type  Optional. Post type or array of post types. Default 'page'.
  4288  * @return WP_Post|null WP_Post on success or null on failure
  4481  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
  4289  */
  4482  */
  4290 function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
  4483 function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
  4291 	global $wpdb;
  4484 	global $wpdb;
  4292 
  4485 
  4293 	if ( is_array( $post_type ) ) {
  4486 	if ( is_array( $post_type ) ) {
  4308 		", $page_title, $post_type );
  4501 		", $page_title, $post_type );
  4309 	}
  4502 	}
  4310 
  4503 
  4311 	$page = $wpdb->get_var( $sql );
  4504 	$page = $wpdb->get_var( $sql );
  4312 
  4505 
  4313 	if ( $page )
  4506 	if ( $page ) {
  4314 		return get_post( $page, $output );
  4507 		return get_post( $page, $output );
  4315 
  4508 	}
  4316 	return null;
  4509 }
  4317 }
  4510 
  4318 
  4511 /**
  4319 /**
  4512  * Identify descendants of a given page ID in a list of page objects.
  4320  * Retrieve child pages from list of pages matching page ID.
  4513  *
  4321  *
  4514  * Descendants are identified from the `$pages` array passed to the function. No database queries are performed.
  4322  * Matches against the pages parameter against the page ID. Also matches all
       
  4323  * children for the same to retrieve all children of a page. Does not make any
       
  4324  * SQL queries to get the children.
       
  4325  *
  4515  *
  4326  * @since 1.5.1
  4516  * @since 1.5.1
  4327  *
  4517  *
  4328  * @param int   $page_id    Page ID.
  4518  * @param int   $page_id Page ID.
  4329  * @param array $pages      List of pages' objects.
  4519  * @param array $pages   List of page objects from which descendants should be identified.
  4330  * @return array List of page children.
  4520  * @return array List of page children.
  4331  */
  4521  */
  4332 function get_page_children( $page_id, $pages ) {
  4522 function get_page_children( $page_id, $pages ) {
       
  4523 	// Build a hash of ID -> children.
       
  4524 	$children = array();
       
  4525 	foreach ( (array) $pages as $page ) {
       
  4526 		$children[ intval( $page->post_parent ) ][] = $page;
       
  4527 	}
       
  4528 
  4333 	$page_list = array();
  4529 	$page_list = array();
  4334 	foreach ( (array) $pages as $page ) {
  4530 
  4335 		if ( $page->post_parent == $page_id ) {
  4531 	// Start the search by looking at immediate children.
  4336 			$page_list[] = $page;
  4532 	if ( isset( $children[ $page_id ] ) ) {
  4337 			if ( $children = get_page_children( $page->ID, $pages ) ) {
  4533 		// Always start at the end of the stack in order to preserve original `$pages` order.
  4338 				$page_list = array_merge( $page_list, $children );
  4534 		$to_look = array_reverse( $children[ $page_id ] );
       
  4535 
       
  4536 		while ( $to_look ) {
       
  4537 			$p = array_pop( $to_look );
       
  4538 			$page_list[] = $p;
       
  4539 			if ( isset( $children[ $p->ID ] ) ) {
       
  4540 				foreach ( array_reverse( $children[ $p->ID ] ) as $child ) {
       
  4541 					// Append to the `$to_look` stack to descend the tree.
       
  4542 					$to_look[] = $child;
       
  4543 				}
  4339 			}
  4544 			}
  4340 		}
  4545 		}
  4341 	}
  4546 	}
  4342 
  4547 
  4343 	return $page_list;
  4548 	return $page_list;
  4349  * It uses auxiliary structure to hold parent-children relationships and
  4554  * It uses auxiliary structure to hold parent-children relationships and
  4350  * runs in O(N) complexity
  4555  * runs in O(N) complexity
  4351  *
  4556  *
  4352  * @since 2.0.0
  4557  * @since 2.0.0
  4353  *
  4558  *
  4354  * @param array $pages   Posts array, passed by reference.
  4559  * @param array $pages   Posts array (passed by reference).
  4355  * @param int   $page_id Optional. Parent page ID. Default 0.
  4560  * @param int   $page_id Optional. Parent page ID. Default 0.
  4356  * @return array A list arranged by hierarchy. Children immediately follow their parents.
  4561  * @return array A list arranged by hierarchy. Children immediately follow their parents.
  4357  */
  4562  */
  4358 function get_page_hierarchy( &$pages, $page_id = 0 ) {
  4563 function get_page_hierarchy( &$pages, $page_id = 0 ) {
  4359 	if ( empty( $pages ) ) {
  4564 	if ( empty( $pages ) ) {
  4360 		$result = array();
  4565 		return array();
  4361 		return $result;
       
  4362 	}
  4566 	}
  4363 
  4567 
  4364 	$children = array();
  4568 	$children = array();
  4365 	foreach ( (array) $pages as $p ) {
  4569 	foreach ( (array) $pages as $p ) {
  4366 		$parent_id = intval( $p->post_parent );
  4570 		$parent_id = intval( $p->post_parent );
  4381  * @since 2.9.0
  4585  * @since 2.9.0
  4382  *
  4586  *
  4383  * @see _page_traverse_name()
  4587  * @see _page_traverse_name()
  4384  *
  4588  *
  4385  * @param int   $page_id   Page ID.
  4589  * @param int   $page_id   Page ID.
  4386  * @param array &$children Parent-children relations, passed by reference.
  4590  * @param array $children  Parent-children relations (passed by reference).
  4387  * @param array &$result   Result, passed by reference.
  4591  * @param array $result    Result (passed by reference).
  4388  */
  4592  */
  4389 function _page_traverse_name( $page_id, &$children, &$result ){
  4593 function _page_traverse_name( $page_id, &$children, &$result ){
  4390 	if ( isset( $children[ $page_id ] ) ){
  4594 	if ( isset( $children[ $page_id ] ) ){
  4391 		foreach( (array)$children[ $page_id ] as $child ) {
  4595 		foreach ( (array)$children[ $page_id ] as $child ) {
  4392 			$result[ $child->ID ] = $child->post_name;
  4596 			$result[ $child->ID ] = $child->post_name;
  4393 			_page_traverse_name( $child->ID, $children, $result );
  4597 			_page_traverse_name( $child->ID, $children, $result );
  4394 		}
  4598 		}
  4395 	}
  4599 	}
  4396 }
  4600 }
  4397 
  4601 
  4398 /**
  4602 /**
  4399  * Build URI for a page.
  4603  * Build the URI path for a page.
  4400  *
  4604  *
  4401  * Sub pages will be in the "directory" under the parent page post name.
  4605  * Sub pages will be in the "directory" under the parent page post name.
  4402  *
  4606  *
  4403  * @since 1.5.0
  4607  * @since 1.5.0
  4404  *
  4608  * @since 4.6.0 Converted the `$page` parameter to optional.
  4405  * @param WP_Post|object|int $page Page object or page ID.
  4609  *
       
  4610  * @param WP_Post|object|int $page Optional. Page ID or WP_Post object. Default is global $post.
  4406  * @return string|false Page URI, false on error.
  4611  * @return string|false Page URI, false on error.
  4407  */
  4612  */
  4408 function get_page_uri( $page ) {
  4613 function get_page_uri( $page = 0 ) {
  4409 	$page = get_post( $page );
  4614 	if ( ! $page instanceof WP_Post ) {
       
  4615 		$page = get_post( $page );
       
  4616 	}
  4410 
  4617 
  4411 	if ( ! $page )
  4618 	if ( ! $page )
  4412 		return false;
  4619 		return false;
  4413 
  4620 
  4414 	$uri = $page->post_name;
  4621 	$uri = $page->post_name;
  4415 
  4622 
  4416 	foreach ( $page->ancestors as $parent ) {
  4623 	foreach ( $page->ancestors as $parent ) {
  4417 		$uri = get_post( $parent )->post_name . '/' . $uri;
  4624 		$parent = get_post( $parent );
  4418 	}
  4625 		if ( $parent && $parent->post_name ) {
  4419 
  4626 			$uri = $parent->post_name . '/' . $uri;
  4420 	return $uri;
  4627 		}
  4421 }
  4628 	}
  4422 
  4629 
  4423 /**
  4630 	/**
  4424  * Retrieve a list of pages.
  4631 	 * Filters the URI for a page.
       
  4632 	 *
       
  4633 	 * @since 4.4.0
       
  4634 	 *
       
  4635 	 * @param string  $uri  Page URI.
       
  4636 	 * @param WP_Post $page Page object.
       
  4637 	 */
       
  4638 	return apply_filters( 'get_page_uri', $uri, $page );
       
  4639 }
       
  4640 
       
  4641 /**
       
  4642  * Retrieve a list of pages (or hierarchical post type items).
  4425  *
  4643  *
  4426  * @global wpdb $wpdb WordPress database abstraction object.
  4644  * @global wpdb $wpdb WordPress database abstraction object.
  4427  *
  4645  *
  4428  * @since 1.5.0
  4646  * @since 1.5.0
  4429  *
  4647  *
  4430  * @param array|string $args {
  4648  * @param array|string $args {
  4431  *     Optional. Array or string of arguments to retrieve pages.
  4649  *     Optional. Array or string of arguments to retrieve pages.
  4432  *
  4650  *
  4433  *     @type int          $child_of     Page ID to return child and grandchild pages of.
  4651  *     @type int          $child_of     Page ID to return child and grandchild pages of. Note: The value
  4434  *                                      Default 0, or no restriction.
  4652  *                                      of `$hierarchical` has no bearing on whether `$child_of` returns
       
  4653  *                                      hierarchical results. Default 0, or no restriction.
  4435  *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
  4654  *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
  4436  *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
  4655  *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
  4437  *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
  4656  *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
  4438  *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
  4657  *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
  4439  *                                      'post_' can be omitted for any values that start with it.
  4658  *                                      'post_' can be omitted for any values that start with it.
  4440  *                                      Default 'post_title'.
  4659  *                                      Default 'post_title'.
  4441  *     @type bool         $hierarchical Whether to return pages hierarchically. Default true.
  4660  *     @type bool         $hierarchical Whether to return pages hierarchically. If false in conjunction with
       
  4661  *                                      `$child_of` also being false, both arguments will be disregarded.
       
  4662  *                                      Default true.
  4442  *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
  4663  *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
  4443  *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
  4664  *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
  4444  *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
  4665  *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
  4445  *                                      Default empty array.
  4666  *                                      Default empty array.
  4446  *     @type string       $meta_key     Only include pages with this meta key. Default empty.
  4667  *     @type string       $meta_key     Only include pages with this meta key. Default empty.
  4447  *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
  4668  *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
  4448  *                                      Default empty.
  4669  *                                      Default empty.
  4449  *     @type string       $authors      A comma-separated list of author IDs. Default empty.
  4670  *     @type string       $authors      A comma-separated list of author IDs. Default empty.
  4450  *     @type int          $parent       Page ID to return direct children of. `$hierarchical` must be false.
  4671  *     @type int          $parent       Page ID to return direct children of. Default -1, or no restriction.
  4451  *                                      Default -1, or no restriction.
       
  4452  *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
  4672  *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
  4453  *                                      Default empty array.
  4673  *                                      Default empty array.
  4454  *     @type int          $number       The number of pages to return. Default 0, or all pages.
  4674  *     @type int          $number       The number of pages to return. Default 0, or all pages.
  4455  *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
  4675  *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
  4456  *                                      Default 0.
  4676  *                                      Default 0.
  4457  *     @type string       $post_type    The post type to query. Default 'page'.
  4677  *     @type string       $post_type    The post type to query. Default 'page'.
  4458  *     @type string       $post_status  A comma-separated list of post status types to include.
  4678  *     @type string|array $post_status  A comma-separated list or array of post statuses to include.
  4459  *                                      Default 'publish'.
  4679  *                                      Default 'publish'.
  4460  * }
  4680  * }
  4461  * @return array List of pages matching defaults or `$args`.
  4681  * @return array|false List of pages matching defaults or `$args`.
  4462  */
  4682  */
  4463 function get_pages( $args = array() ) {
  4683 function get_pages( $args = array() ) {
  4464 	global $wpdb;
  4684 	global $wpdb;
  4465 
  4685 
  4466 	$defaults = array(
  4686 	$defaults = array(
  4467 		'child_of' => 0, 'sort_order' => 'ASC',
  4687 		'child_of'     => 0,
  4468 		'sort_column' => 'post_title', 'hierarchical' => 1,
  4688 		'sort_order'   => 'ASC',
  4469 		'exclude' => array(), 'include' => array(),
  4689 		'sort_column'  => 'post_title',
  4470 		'meta_key' => '', 'meta_value' => '',
  4690 		'hierarchical' => 1,
  4471 		'authors' => '', 'parent' => -1, 'exclude_tree' => array(),
  4691 		'exclude'      => array(),
  4472 		'number' => '', 'offset' => 0,
  4692 		'include'      => array(),
  4473 		'post_type' => 'page', 'post_status' => 'publish',
  4693 		'meta_key'     => '',
       
  4694 		'meta_value'   => '',
       
  4695 		'authors'      => '',
       
  4696 		'parent'       => -1,
       
  4697 		'exclude_tree' => array(),
       
  4698 		'number'       => '',
       
  4699 		'offset'       => 0,
       
  4700 		'post_type'    => 'page',
       
  4701 		'post_status'  => 'publish',
  4474 	);
  4702 	);
  4475 
  4703 
  4476 	$r = wp_parse_args( $args, $defaults );
  4704 	$r = wp_parse_args( $args, $defaults );
  4477 
  4705 
  4478 	$number = (int) $r['number'];
  4706 	$number = (int) $r['number'];
  4503 		return false;
  4731 		return false;
  4504 	}
  4732 	}
  4505 
  4733 
  4506 	// $args can be whatever, only use the args defined in defaults to compute the key.
  4734 	// $args can be whatever, only use the args defined in defaults to compute the key.
  4507 	$key = md5( serialize( wp_array_slice_assoc( $r, array_keys( $defaults ) ) ) );
  4735 	$key = md5( serialize( wp_array_slice_assoc( $r, array_keys( $defaults ) ) ) );
  4508 	$last_changed = wp_cache_get( 'last_changed', 'posts' );
  4736 	$last_changed = wp_cache_get_last_changed( 'posts' );
  4509 	if ( ! $last_changed ) {
       
  4510 		$last_changed = microtime();
       
  4511 		wp_cache_set( 'last_changed', $last_changed, 'posts' );
       
  4512 	}
       
  4513 
  4737 
  4514 	$cache_key = "get_pages:$key:$last_changed";
  4738 	$cache_key = "get_pages:$key:$last_changed";
  4515 	if ( $cache = wp_cache_get( $cache_key, 'posts' ) ) {
  4739 	if ( $cache = wp_cache_get( $cache_key, 'posts' ) ) {
  4516 		// Convert to WP_Post instances.
  4740 		// Convert to WP_Post instances.
  4517 		$pages = array_map( 'get_post', $cache );
  4741 		$pages = array_map( 'get_post', $cache );
  4675 		$pages = get_page_children($child_of, $pages);
  4899 		$pages = get_page_children($child_of, $pages);
  4676 	}
  4900 	}
  4677 
  4901 
  4678 	if ( ! empty( $r['exclude_tree'] ) ) {
  4902 	if ( ! empty( $r['exclude_tree'] ) ) {
  4679 		$exclude = wp_parse_id_list( $r['exclude_tree'] );
  4903 		$exclude = wp_parse_id_list( $r['exclude_tree'] );
  4680 		foreach( $exclude as $id ) {
  4904 		foreach ( $exclude as $id ) {
  4681 			$children = get_page_children( $id, $pages );
  4905 			$children = get_page_children( $id, $pages );
  4682 			foreach ( $children as $child ) {
  4906 			foreach ( $children as $child ) {
  4683 				$exclude[] = $child->ID;
  4907 				$exclude[] = $child->ID;
  4684 			}
  4908 			}
  4685 		}
  4909 		}
  4701 
  4925 
  4702 	// Convert to WP_Post instances
  4926 	// Convert to WP_Post instances
  4703 	$pages = array_map( 'get_post', $pages );
  4927 	$pages = array_map( 'get_post', $pages );
  4704 
  4928 
  4705 	/**
  4929 	/**
  4706 	 * Filter the retrieved list of pages.
  4930 	 * Filters the retrieved list of pages.
  4707 	 *
  4931 	 *
  4708 	 * @since 2.1.0
  4932 	 * @since 2.1.0
  4709 	 *
  4933 	 *
  4710 	 * @param array $pages List of pages to retrieve.
  4934 	 * @param array $pages List of pages to retrieve.
  4711 	 * @param array $r     Array of get_pages() arguments.
  4935 	 * @param array $r     Array of get_pages() arguments.
  4712 	 */
  4936 	 */
  4713 	$pages = apply_filters( 'get_pages', $pages, $r );
  4937 	return apply_filters( 'get_pages', $pages, $r );
  4714 
       
  4715 	return $pages;
       
  4716 }
  4938 }
  4717 
  4939 
  4718 //
  4940 //
  4719 // Attachment functions
  4941 // Attachment functions
  4720 //
  4942 //
  4753  * By default, the comments will use the default settings for whether the
  4975  * By default, the comments will use the default settings for whether the
  4754  * comments are allowed. You can close them manually or keep them open by
  4976  * comments are allowed. You can close them manually or keep them open by
  4755  * setting the value for the 'comment_status' key.
  4977  * setting the value for the 'comment_status' key.
  4756  *
  4978  *
  4757  * @since 2.0.0
  4979  * @since 2.0.0
       
  4980  * @since 4.7.0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure.
  4758  *
  4981  *
  4759  * @see wp_insert_post()
  4982  * @see wp_insert_post()
  4760  *
  4983  *
  4761  * @param string|array $args   Arguments for inserting an attachment.
  4984  * @param string|array $args     Arguments for inserting an attachment.
  4762  * @param string       $file   Optional. Filename.
  4985  * @param string       $file     Optional. Filename.
  4763  * @param int          $parent Optional. Parent post ID.
  4986  * @param int          $parent   Optional. Parent post ID.
  4764  * @return int Attachment ID.
  4987  * @param bool         $wp_error Optional. Whether to return a WP_Error on failure. Default false.
  4765  */
  4988  * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
  4766 function wp_insert_attachment( $args, $file = false, $parent = 0 ) {
  4989  */
       
  4990 function wp_insert_attachment( $args, $file = false, $parent = 0, $wp_error = false ) {
  4767 	$defaults = array(
  4991 	$defaults = array(
  4768 		'file'        => $file,
  4992 		'file'        => $file,
  4769 		'post_parent' => 0
  4993 		'post_parent' => 0
  4770 	);
  4994 	);
  4771 
  4995 
  4775 		$data['post_parent'] = $parent;
  4999 		$data['post_parent'] = $parent;
  4776 	}
  5000 	}
  4777 
  5001 
  4778 	$data['post_type'] = 'attachment';
  5002 	$data['post_type'] = 'attachment';
  4779 
  5003 
  4780 	return wp_insert_post( $data );
  5004 	return wp_insert_post( $data, $wp_error );
  4781 }
  5005 }
  4782 
  5006 
  4783 /**
  5007 /**
  4784  * Trash or delete an attachment.
  5008  * Trash or delete an attachment.
  4785  *
  5009  *
  4795  * @global wpdb $wpdb WordPress database abstraction object.
  5019  * @global wpdb $wpdb WordPress database abstraction object.
  4796  *
  5020  *
  4797  * @param int  $post_id      Attachment ID.
  5021  * @param int  $post_id      Attachment ID.
  4798  * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
  5022  * @param bool $force_delete Optional. Whether to bypass trash and force deletion.
  4799  *                           Default false.
  5023  *                           Default false.
  4800  * @return mixed False on failure. Post data on success.
  5024  * @return WP_Post|false|null Post data on success, false or null on failure.
  4801  */
  5025  */
  4802 function wp_delete_attachment( $post_id, $force_delete = false ) {
  5026 function wp_delete_attachment( $post_id, $force_delete = false ) {
  4803 	global $wpdb;
  5027 	global $wpdb;
  4804 
  5028 
  4805 	if ( !$post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) ) )
  5029 	$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id ) );
       
  5030 
       
  5031 	if ( ! $post ) {
  4806 		return $post;
  5032 		return $post;
  4807 
  5033 	}
  4808 	if ( 'attachment' != $post->post_type )
  5034 
       
  5035 	$post = get_post( $post );
       
  5036 
       
  5037 	if ( 'attachment' !== $post->post_type ) {
  4809 		return false;
  5038 		return false;
  4810 
  5039 	}
  4811 	if ( !$force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' != $post->post_status )
  5040 
       
  5041 	if ( ! $force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' !== $post->post_status ) {
  4812 		return wp_trash_post( $post_id );
  5042 		return wp_trash_post( $post_id );
       
  5043 	}
  4813 
  5044 
  4814 	delete_post_meta($post_id, '_wp_trash_meta_status');
  5045 	delete_post_meta($post_id, '_wp_trash_meta_status');
  4815 	delete_post_meta($post_id, '_wp_trash_meta_time');
  5046 	delete_post_meta($post_id, '_wp_trash_meta_time');
  4816 
  5047 
  4817 	$meta = wp_get_attachment_metadata( $post_id );
  5048 	$meta = wp_get_attachment_metadata( $post_id );
  4834 	wp_delete_object_term_relationships($post_id, get_object_taxonomies($post->post_type));
  5065 	wp_delete_object_term_relationships($post_id, get_object_taxonomies($post->post_type));
  4835 
  5066 
  4836 	// Delete all for any posts.
  5067 	// Delete all for any posts.
  4837 	delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );
  5068 	delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );
  4838 
  5069 
       
  5070 	wp_defer_comment_counting( true );
       
  5071 
  4839 	$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ));
  5072 	$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ));
  4840 	foreach ( $comment_ids as $comment_id )
  5073 	foreach ( $comment_ids as $comment_id ) {
  4841 		wp_delete_comment( $comment_id, true );
  5074 		wp_delete_comment( $comment_id, true );
       
  5075 	}
       
  5076 
       
  5077 	wp_defer_comment_counting( false );
  4842 
  5078 
  4843 	$post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ));
  5079 	$post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ));
  4844 	foreach ( $post_meta_ids as $mid )
  5080 	foreach ( $post_meta_ids as $mid )
  4845 		delete_metadata_by_mid( 'post', $mid );
  5081 		delete_metadata_by_mid( 'post', $mid );
  4846 
  5082 
  4851 		return false;
  5087 		return false;
  4852 	}
  5088 	}
  4853 	/** This action is documented in wp-includes/post.php */
  5089 	/** This action is documented in wp-includes/post.php */
  4854 	do_action( 'deleted_post', $post_id );
  5090 	do_action( 'deleted_post', $post_id );
  4855 
  5091 
  4856 	$uploadpath = wp_upload_dir();
  5092 	wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file );
  4857 
  5093 
  4858 	if ( ! empty($meta['thumb']) ) {
  5094 	clean_post_cache( $post );
       
  5095 
       
  5096 	return $post;
       
  5097 }
       
  5098 
       
  5099 /**
       
  5100  * Deletes all files that belong to the given attachment.
       
  5101  *
       
  5102  * @since 4.9.7
       
  5103  *
       
  5104  * @param int    $post_id      Attachment ID.
       
  5105  * @param array  $meta         The attachment's meta data.
       
  5106  * @param array  $backup_sizes The meta data for the attachment's backup images.
       
  5107  * @param string $file         Absolute path to the attachment's file.
       
  5108  * @return bool True on success, false on failure.
       
  5109  */
       
  5110 function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) {
       
  5111 	global $wpdb;
       
  5112 
       
  5113 	$uploadpath = wp_get_upload_dir();
       
  5114 	$deleted    = true;
       
  5115 
       
  5116 	if ( ! empty( $meta['thumb'] ) ) {
  4859 		// Don't delete the thumb if another attachment uses it.
  5117 		// Don't delete the thumb if another attachment uses it.
  4860 		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)) ) {
  5118 		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 ) ) ) {
  4861 			$thumbfile = str_replace(basename($file), $meta['thumb'], $file);
  5119 			$thumbfile = str_replace( basename( $file ), $meta['thumb'], $file );
  4862 			/** This filter is documented in wp-includes/functions.php */
  5120 			if ( ! empty( $thumbfile ) ) {
  4863 			$thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
  5121 				$thumbfile = path_join( $uploadpath['basedir'], $thumbfile );
  4864 			@ unlink( path_join($uploadpath['basedir'], $thumbfile) );
  5122 				$thumbdir  = path_join( $uploadpath['basedir'], dirname( $file ) );
       
  5123 
       
  5124 				if ( ! wp_delete_file_from_directory( $thumbfile, $thumbdir ) ) {
       
  5125 					$deleted = false;
       
  5126 				}
       
  5127 			}
  4865 		}
  5128 		}
  4866 	}
  5129 	}
  4867 
  5130 
  4868 	// Remove intermediate and backup images if there are any.
  5131 	// Remove intermediate and backup images if there are any.
  4869 	if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) {
  5132 	if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) {
       
  5133 		$intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) );
  4870 		foreach ( $meta['sizes'] as $size => $sizeinfo ) {
  5134 		foreach ( $meta['sizes'] as $size => $sizeinfo ) {
  4871 			$intermediate_file = str_replace( basename( $file ), $sizeinfo['file'], $file );
  5135 			$intermediate_file = str_replace( basename( $file ), $sizeinfo['file'], $file );
  4872 			/** This filter is documented in wp-includes/functions.php */
  5136 			if ( ! empty( $intermediate_file ) ) {
  4873 			$intermediate_file = apply_filters( 'wp_delete_file', $intermediate_file );
  5137 				$intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file );
  4874 			@ unlink( path_join( $uploadpath['basedir'], $intermediate_file ) );
  5138 
  4875 		}
  5139 				if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) {
  4876 	}
  5140 					$deleted = false;
  4877 
  5141 				}
  4878 	if ( is_array($backup_sizes) ) {
  5142 			}
       
  5143 		}
       
  5144 	}
       
  5145 
       
  5146 	if ( is_array( $backup_sizes ) ) {
       
  5147 		$del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) );
  4879 		foreach ( $backup_sizes as $size ) {
  5148 		foreach ( $backup_sizes as $size ) {
  4880 			$del_file = path_join( dirname($meta['file']), $size['file'] );
  5149 			$del_file = path_join( dirname( $meta['file'] ), $size['file'] );
  4881 			/** This filter is documented in wp-includes/functions.php */
  5150 			if ( ! empty( $del_file ) ) {
  4882 			$del_file = apply_filters( 'wp_delete_file', $del_file );
  5151 				$del_file = path_join( $uploadpath['basedir'], $del_file );
  4883 			@ unlink( path_join($uploadpath['basedir'], $del_file) );
  5152 
  4884 		}
  5153 				if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) {
  4885 	}
  5154 					$deleted = false;
  4886 
  5155 				}
  4887 	wp_delete_file( $file );
  5156 			}
  4888 
  5157 		}
  4889 	clean_post_cache( $post );
  5158 	}
  4890 
  5159 
  4891 	return $post;
  5160 	if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) {
       
  5161 		$deleted = false;
       
  5162 	}
       
  5163 
       
  5164 	return $deleted;
  4892 }
  5165 }
  4893 
  5166 
  4894 /**
  5167 /**
  4895  * Retrieve attachment meta field for attachment ID.
  5168  * Retrieve attachment meta field for attachment ID.
  4896  *
  5169  *
  4897  * @since 2.1.0
  5170  * @since 2.1.0
  4898  *
  5171  *
  4899  * @param int  $post_id    Attachment ID. Default 0.
  5172  * @param int  $attachment_id Attachment post ID. Defaults to global $post.
  4900  * @param bool $unfiltered Optional. If true, filters are not run. Default false.
  5173  * @param bool $unfiltered    Optional. If true, filters are not run. Default false.
  4901  * @return string|bool Attachment meta field. False on failure.
  5174  * @return mixed Attachment meta field. False on failure.
  4902  */
  5175  */
  4903 function wp_get_attachment_metadata( $post_id = 0, $unfiltered = false ) {
  5176 function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) {
  4904 	$post_id = (int) $post_id;
  5177 	$attachment_id = (int) $attachment_id;
  4905 	if ( !$post = get_post( $post_id ) )
  5178 	if ( ! $post = get_post( $attachment_id ) ) {
  4906 		return false;
  5179 		return false;
       
  5180 	}
  4907 
  5181 
  4908 	$data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
  5182 	$data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
  4909 
  5183 
  4910 	if ( $unfiltered )
  5184 	if ( $unfiltered )
  4911 		return $data;
  5185 		return $data;
  4912 
  5186 
  4913 	/**
  5187 	/**
  4914 	 * Filter the attachment meta data.
  5188 	 * Filters the attachment meta data.
  4915 	 *
  5189 	 *
  4916 	 * @since 2.1.0
  5190 	 * @since 2.1.0
  4917 	 *
  5191 	 *
  4918 	 * @param array|bool $data    Array of meta data for the given attachment, or false
  5192 	 * @param array|bool $data          Array of meta data for the given attachment, or false
  4919 	 *                            if the object does not exist.
  5193 	 *                                  if the object does not exist.
  4920 	 * @param int        $post_id Attachment ID.
  5194 	 * @param int        $attachment_id Attachment post ID.
  4921 	 */
  5195 	 */
  4922 	return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
  5196 	return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
  4923 }
  5197 }
  4924 
  5198 
  4925 /**
  5199 /**
  4926  * Update metadata for an attachment.
  5200  * Update metadata for an attachment.
  4927  *
  5201  *
  4928  * @since 2.1.0
  5202  * @since 2.1.0
  4929  *
  5203  *
  4930  * @param int   $post_id Attachment ID.
  5204  * @param int   $attachment_id Attachment post ID.
  4931  * @param array $data    Attachment data.
  5205  * @param array $data          Attachment meta data.
  4932  * @return int|bool False if $post is invalid.
  5206  * @return int|bool False if $post is invalid.
  4933  */
  5207  */
  4934 function wp_update_attachment_metadata( $post_id, $data ) {
  5208 function wp_update_attachment_metadata( $attachment_id, $data ) {
  4935 	$post_id = (int) $post_id;
  5209 	$attachment_id = (int) $attachment_id;
  4936 	if ( !$post = get_post( $post_id ) )
  5210 	if ( ! $post = get_post( $attachment_id ) ) {
  4937 		return false;
  5211 		return false;
       
  5212 	}
  4938 
  5213 
  4939 	/**
  5214 	/**
  4940 	 * Filter the updated attachment meta data.
  5215 	 * Filters the updated attachment meta data.
  4941 	 *
  5216 	 *
  4942 	 * @since 2.1.0
  5217 	 * @since 2.1.0
  4943 	 *
  5218 	 *
  4944 	 * @param array $data    Array of updated attachment meta data.
  5219 	 * @param array $data          Array of updated attachment meta data.
  4945 	 * @param int   $post_id Attachment ID.
  5220 	 * @param int   $attachment_id Attachment post ID.
  4946 	 */
  5221 	 */
  4947 	if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
  5222 	if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
  4948 		return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
  5223 		return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
  4949 	else
  5224 	else
  4950 		return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
  5225 		return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
  4953 /**
  5228 /**
  4954  * Retrieve the URL for an attachment.
  5229  * Retrieve the URL for an attachment.
  4955  *
  5230  *
  4956  * @since 2.1.0
  5231  * @since 2.1.0
  4957  *
  5232  *
  4958  * @param int $post_id Optional. Attachment ID. Default 0.
  5233  * @global string $pagenow
  4959  * @return string|bool Attachment URL, otherwise false.
  5234  *
  4960  */
  5235  * @param int $attachment_id Optional. Attachment post ID. Defaults to global $post.
  4961 function wp_get_attachment_url( $post_id = 0 ) {
  5236  * @return string|false Attachment URL, otherwise false.
  4962 	$post_id = (int) $post_id;
  5237  */
  4963 	if ( !$post = get_post( $post_id ) )
  5238 function wp_get_attachment_url( $attachment_id = 0 ) {
       
  5239 	$attachment_id = (int) $attachment_id;
       
  5240 	if ( ! $post = get_post( $attachment_id ) ) {
  4964 		return false;
  5241 		return false;
       
  5242 	}
  4965 
  5243 
  4966 	if ( 'attachment' != $post->post_type )
  5244 	if ( 'attachment' != $post->post_type )
  4967 		return false;
  5245 		return false;
  4968 
  5246 
  4969 	$url = '';
  5247 	$url = '';
  4970 	// Get attached file.
  5248 	// Get attached file.
  4971 	if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true) ) {
  5249 	if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true ) ) {
  4972 		// Get upload directory.
  5250 		// Get upload directory.
  4973 		if ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) {
  5251 		if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
  4974 			// Check that the upload base exists in the file location.
  5252 			// Check that the upload base exists in the file location.
  4975 			if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
  5253 			if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
  4976 				// Replace file location with url location.
  5254 				// Replace file location with url location.
  4977 				$url = str_replace($uploads['basedir'], $uploads['baseurl'], $file);
  5255 				$url = str_replace($uploads['basedir'], $uploads['baseurl'], $file);
  4978 			} elseif ( false !== strpos($file, 'wp-content/uploads') ) {
  5256 			} elseif ( false !== strpos($file, 'wp-content/uploads') ) {
  4979 				$url = $uploads['baseurl'] . substr( $file, strpos($file, 'wp-content/uploads') + 18 );
  5257 				// Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
       
  5258 				$url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $file ) ) . basename( $file );
  4980 			} else {
  5259 			} else {
  4981 				// It's a newly-uploaded file, therefore $file is relative to the basedir.
  5260 				// It's a newly-uploaded file, therefore $file is relative to the basedir.
  4982 				$url = $uploads['baseurl'] . "/$file";
  5261 				$url = $uploads['baseurl'] . "/$file";
  4983 			}
  5262 			}
  4984 		}
  5263 		}
  4990 	 */
  5269 	 */
  4991 	if ( empty($url) ) {
  5270 	if ( empty($url) ) {
  4992 		$url = get_the_guid( $post->ID );
  5271 		$url = get_the_guid( $post->ID );
  4993 	}
  5272 	}
  4994 
  5273 
  4995 	// On SSL front-end, URLs should be HTTPS.
  5274 	// On SSL front end, URLs should be HTTPS.
  4996 	if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] ) {
  5275 	if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] ) {
  4997 		$url = set_url_scheme( $url );
  5276 		$url = set_url_scheme( $url );
  4998 	}
  5277 	}
  4999 
  5278 
  5000 	/**
  5279 	/**
  5001 	 * Filter the attachment URL.
  5280 	 * Filters the attachment URL.
  5002 	 *
  5281 	 *
  5003 	 * @since 2.1.0
  5282 	 * @since 2.1.0
  5004 	 *
  5283 	 *
  5005 	 * @param string $url     URL for the given attachment.
  5284 	 * @param string $url           URL for the given attachment.
       
  5285 	 * @param int    $attachment_id Attachment post ID.
       
  5286 	 */
       
  5287 	$url = apply_filters( 'wp_get_attachment_url', $url, $post->ID );
       
  5288 
       
  5289 	if ( empty( $url ) )
       
  5290 		return false;
       
  5291 
       
  5292 	return $url;
       
  5293 }
       
  5294 
       
  5295 /**
       
  5296  * Retrieves the caption for an attachment.
       
  5297  *
       
  5298  * @since 4.6.0
       
  5299  *
       
  5300  * @param int $post_id Optional. Attachment ID. Default is the ID of the global `$post`.
       
  5301  * @return string|false False on failure. Attachment caption on success.
       
  5302  */
       
  5303 function wp_get_attachment_caption( $post_id = 0 ) {
       
  5304 	$post_id = (int) $post_id;
       
  5305 	if ( ! $post = get_post( $post_id ) ) {
       
  5306 		return false;
       
  5307 	}
       
  5308 
       
  5309 	if ( 'attachment' !== $post->post_type ) {
       
  5310 		return false;
       
  5311 	}
       
  5312 
       
  5313 	$caption = $post->post_excerpt;
       
  5314 
       
  5315 	/**
       
  5316 	 * Filters the attachment caption.
       
  5317 	 *
       
  5318 	 * @since 4.6.0
       
  5319 	 *
       
  5320 	 * @param string $caption Caption for the given attachment.
  5006 	 * @param int    $post_id Attachment ID.
  5321 	 * @param int    $post_id Attachment ID.
  5007 	 */
  5322 	 */
  5008 	$url = apply_filters( 'wp_get_attachment_url', $url, $post->ID );
  5323 	return apply_filters( 'wp_get_attachment_caption', $caption, $post->ID );
  5009 
       
  5010 	if ( empty( $url ) )
       
  5011 		return false;
       
  5012 
       
  5013 	return $url;
       
  5014 }
  5324 }
  5015 
  5325 
  5016 /**
  5326 /**
  5017  * Retrieve thumbnail for an attachment.
  5327  * Retrieve thumbnail for an attachment.
  5018  *
  5328  *
  5019  * @since 2.1.0
  5329  * @since 2.1.0
  5020  *
  5330  *
  5021  * @param int $post_id Optional. Attachment ID. Default 0.
  5331  * @param int $post_id Optional. Attachment ID. Default 0.
  5022  * @return mixed False on failure. Thumbnail file path on success.
  5332  * @return string|false False on failure. Thumbnail file path on success.
  5023  */
  5333  */
  5024 function wp_get_attachment_thumb_file( $post_id = 0 ) {
  5334 function wp_get_attachment_thumb_file( $post_id = 0 ) {
  5025 	$post_id = (int) $post_id;
  5335 	$post_id = (int) $post_id;
  5026 	if ( !$post = get_post( $post_id ) )
  5336 	if ( !$post = get_post( $post_id ) )
  5027 		return false;
  5337 		return false;
  5030 
  5340 
  5031 	$file = get_attached_file( $post->ID );
  5341 	$file = get_attached_file( $post->ID );
  5032 
  5342 
  5033 	if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) ) {
  5343 	if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) ) {
  5034 		/**
  5344 		/**
  5035 		 * Filter the attachment thumbnail file path.
  5345 		 * Filters the attachment thumbnail file path.
  5036 		 *
  5346 		 *
  5037 		 * @since 2.1.0
  5347 		 * @since 2.1.0
  5038 		 *
  5348 		 *
  5039 		 * @param string $thumbfile File path to the attachment thumbnail.
  5349 		 * @param string $thumbfile File path to the attachment thumbnail.
  5040 		 * @param int    $post_id   Attachment ID.
  5350 		 * @param int    $post_id   Attachment ID.
  5048  * Retrieve URL for an attachment thumbnail.
  5358  * Retrieve URL for an attachment thumbnail.
  5049  *
  5359  *
  5050  * @since 2.1.0
  5360  * @since 2.1.0
  5051  *
  5361  *
  5052  * @param int $post_id Optional. Attachment ID. Default 0.
  5362  * @param int $post_id Optional. Attachment ID. Default 0.
  5053  * @return string|bool False on failure. Thumbnail URL on success.
  5363  * @return string|false False on failure. Thumbnail URL on success.
  5054  */
  5364  */
  5055 function wp_get_attachment_thumb_url( $post_id = 0 ) {
  5365 function wp_get_attachment_thumb_url( $post_id = 0 ) {
  5056 	$post_id = (int) $post_id;
  5366 	$post_id = (int) $post_id;
  5057 	if ( !$post = get_post( $post_id ) )
  5367 	if ( !$post = get_post( $post_id ) )
  5058 		return false;
  5368 		return false;
  5067 		return false;
  5377 		return false;
  5068 
  5378 
  5069 	$url = str_replace(basename($url), basename($thumb), $url);
  5379 	$url = str_replace(basename($url), basename($thumb), $url);
  5070 
  5380 
  5071 	/**
  5381 	/**
  5072 	 * Filter the attachment thumbnail URL.
  5382 	 * Filters the attachment thumbnail URL.
  5073 	 *
  5383 	 *
  5074 	 * @since 2.1.0
  5384 	 * @since 2.1.0
  5075 	 *
  5385 	 *
  5076 	 * @param string $url     URL for the attachment thumbnail.
  5386 	 * @param string $url     URL for the attachment thumbnail.
  5077 	 * @param int    $post_id Attachment ID.
  5387 	 * @param int    $post_id Attachment ID.
  5082 /**
  5392 /**
  5083  * Verifies an attachment is of a given type.
  5393  * Verifies an attachment is of a given type.
  5084  *
  5394  *
  5085  * @since 4.2.0
  5395  * @since 4.2.0
  5086  *
  5396  *
  5087  * @param string      $type    Attachment type. Accepts 'image', 'audio', or 'video'.
  5397  * @param string      $type Attachment type. Accepts 'image', 'audio', or 'video'.
  5088  * @param int|WP_Post $post_id Optional. Attachment ID. Default 0.
  5398  * @param int|WP_Post $post Optional. Attachment ID or object. Default is global $post.
  5089  * @return bool True if one of the accepted types, false otherwise.
  5399  * @return bool True if one of the accepted types, false otherwise.
  5090  */
  5400  */
  5091 function wp_attachment_is( $type, $post_id = 0 ) {
  5401 function wp_attachment_is( $type, $post = null ) {
  5092 	if ( ! $post = get_post( $post_id ) ) {
  5402 	if ( ! $post = get_post( $post ) ) {
  5093 		return false;
  5403 		return false;
  5094 	}
  5404 	}
  5095 
  5405 
  5096 	if ( ! $file = get_attached_file( $post->ID ) ) {
  5406 	if ( ! $file = get_attached_file( $post->ID ) ) {
  5097 		return false;
  5407 		return false;
  5130 
  5440 
  5131 /**
  5441 /**
  5132  * Checks if the attachment is an image.
  5442  * Checks if the attachment is an image.
  5133  *
  5443  *
  5134  * @since 2.1.0
  5444  * @since 2.1.0
  5135  * @since 4.2.0 Modified into wrapper for wp_attachment_is()
  5445  * @since 4.2.0 Modified into wrapper for wp_attachment_is() and
  5136  *
  5446  *              allowed WP_Post object to be passed.
  5137  * @param int|WP_Post $post Optional. Attachment ID. Default 0.
  5447  *
       
  5448  * @param int|WP_Post $post Optional. Attachment ID or object. Default is global $post.
  5138  * @return bool Whether the attachment is an image.
  5449  * @return bool Whether the attachment is an image.
  5139  */
  5450  */
  5140 function wp_attachment_is_image( $post = 0 ) {
  5451 function wp_attachment_is_image( $post = null ) {
  5141 	return wp_attachment_is( 'image', $post );
  5452 	return wp_attachment_is( 'image', $post );
  5142 }
  5453 }
  5143 
  5454 
  5144 /**
  5455 /**
  5145  * Retrieve the icon for a MIME type.
  5456  * Retrieve the icon for a MIME type.
  5146  *
  5457  *
  5147  * @since 2.1.0
  5458  * @since 2.1.0
  5148  *
  5459  *
  5149  * @param string|int $mime MIME type or attachment ID.
  5460  * @param string|int $mime MIME type or attachment ID.
  5150  * @return string|bool Icon, false otherwise.
  5461  * @return string|false Icon, false otherwise.
  5151  */
  5462  */
  5152 function wp_mime_type_icon( $mime = 0 ) {
  5463 function wp_mime_type_icon( $mime = 0 ) {
  5153 	if ( !is_numeric($mime) )
  5464 	if ( !is_numeric($mime) )
  5154 		$icon = wp_cache_get("mime_type_icon_$mime");
  5465 		$icon = wp_cache_get("mime_type_icon_$mime");
  5155 
  5466 
  5158 		$post_mimes = array();
  5469 		$post_mimes = array();
  5159 		if ( is_numeric($mime) ) {
  5470 		if ( is_numeric($mime) ) {
  5160 			$mime = (int) $mime;
  5471 			$mime = (int) $mime;
  5161 			if ( $post = get_post( $mime ) ) {
  5472 			if ( $post = get_post( $mime ) ) {
  5162 				$post_id = (int) $post->ID;
  5473 				$post_id = (int) $post->ID;
  5163 				$ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $post->guid);
  5474 				$file = get_attached_file( $post_id );
       
  5475 				$ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $file);
  5164 				if ( !empty($ext) ) {
  5476 				if ( !empty($ext) ) {
  5165 					$post_mimes[] = $ext;
  5477 					$post_mimes[] = $ext;
  5166 					if ( $ext_type = wp_ext2type( $ext ) )
  5478 					if ( $ext_type = wp_ext2type( $ext ) )
  5167 						$post_mimes[] = $ext_type;
  5479 						$post_mimes[] = $ext_type;
  5168 				}
  5480 				}
  5176 
  5488 
  5177 		$icon_files = wp_cache_get('icon_files');
  5489 		$icon_files = wp_cache_get('icon_files');
  5178 
  5490 
  5179 		if ( !is_array($icon_files) ) {
  5491 		if ( !is_array($icon_files) ) {
  5180 			/**
  5492 			/**
  5181 			 * Filter the icon directory path.
  5493 			 * Filters the icon directory path.
  5182 			 *
  5494 			 *
  5183 			 * @since 2.0.0
  5495 			 * @since 2.0.0
  5184 			 *
  5496 			 *
  5185 			 * @param string $path Icon directory absolute path.
  5497 			 * @param string $path Icon directory absolute path.
  5186 			 */
  5498 			 */
  5187 			$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
  5499 			$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
  5188 
  5500 
  5189 			/**
  5501 			/**
  5190 			 * Filter the icon directory URI.
  5502 			 * Filters the icon directory URI.
  5191 			 *
  5503 			 *
  5192 			 * @since 2.0.0
  5504 			 * @since 2.0.0
  5193 			 *
  5505 			 *
  5194 			 * @param string $uri Icon directory URI.
  5506 			 * @param string $uri Icon directory URI.
  5195 			 */
  5507 			 */
  5196 			$icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url( 'images/media' ) );
  5508 			$icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url( 'images/media' ) );
  5197 
  5509 
  5198 			/**
  5510 			/**
  5199 			 * Filter the list of icon directory URIs.
  5511 			 * Filters the list of icon directory URIs.
  5200 			 *
  5512 			 *
  5201 			 * @since 2.5.0
  5513 			 * @since 2.5.0
  5202 			 *
  5514 			 *
  5203 			 * @param array $uris List of icon directory URIs.
  5515 			 * @param array $uris List of icon directory URIs.
  5204 			 */
  5516 			 */
  5239 
  5551 
  5240 		$matches = wp_match_mime_types(array_keys($types), $post_mimes);
  5552 		$matches = wp_match_mime_types(array_keys($types), $post_mimes);
  5241 		$matches['default'] = array('default');
  5553 		$matches['default'] = array('default');
  5242 
  5554 
  5243 		foreach ( $matches as $match => $wilds ) {
  5555 		foreach ( $matches as $match => $wilds ) {
  5244 			if ( isset($types[$wilds[0]])) {
  5556 			foreach ( $wilds as $wild ) {
  5245 				$icon = $types[$wilds[0]];
  5557 				if ( ! isset( $types[ $wild ] ) ) {
  5246 				if ( !is_numeric($mime) )
  5558 					continue;
  5247 					wp_cache_add("mime_type_icon_$mime", $icon);
  5559 				}
  5248 				break;
  5560 
       
  5561 				$icon = $types[ $wild ];
       
  5562 				if ( ! is_numeric( $mime ) ) {
       
  5563 					wp_cache_add( "mime_type_icon_$mime", $icon );
       
  5564 				}
       
  5565 				break 2;
  5249 			}
  5566 			}
  5250 		}
  5567 		}
  5251 	}
  5568 	}
  5252 
  5569 
  5253 	/**
  5570 	/**
  5254 	 * Filter the mime type icon.
  5571 	 * Filters the mime type icon.
  5255 	 *
  5572 	 *
  5256 	 * @since 2.1.0
  5573 	 * @since 2.1.0
  5257 	 *
  5574 	 *
  5258 	 * @param string $icon    Path to the mime type icon.
  5575 	 * @param string $icon    Path to the mime type icon.
  5259 	 * @param string $mime    Mime type.
  5576 	 * @param string $mime    Mime type.
  5279  * @since 2.1.0
  5596  * @since 2.1.0
  5280  *
  5597  *
  5281  * @param int     $post_id     Post ID.
  5598  * @param int     $post_id     Post ID.
  5282  * @param WP_Post $post        The Post Object
  5599  * @param WP_Post $post        The Post Object
  5283  * @param WP_Post $post_before The Previous Post Object
  5600  * @param WP_Post $post_before The Previous Post Object
  5284  * @return int Same as $post_id
       
  5285  */
  5601  */
  5286 function wp_check_for_changed_slugs( $post_id, $post, $post_before ) {
  5602 function wp_check_for_changed_slugs( $post_id, $post, $post_before ) {
  5287 	// Don't bother if it hasnt changed.
  5603 	// Don't bother if it hasn't changed.
  5288 	if ( $post->post_name == $post_before->post_name )
  5604 	if ( $post->post_name == $post_before->post_name ) {
  5289 		return;
  5605 		return;
       
  5606 	}
  5290 
  5607 
  5291 	// We're only concerned with published, non-hierarchical objects.
  5608 	// We're only concerned with published, non-hierarchical objects.
  5292 	if ( $post->post_status != 'publish' || is_post_type_hierarchical( $post->post_type ) )
  5609 	if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) {
  5293 		return;
  5610 		return;
  5294 
  5611 	}
  5295 	$old_slugs = (array) get_post_meta($post_id, '_wp_old_slug');
  5612 
       
  5613 	$old_slugs = (array) get_post_meta( $post_id, '_wp_old_slug' );
  5296 
  5614 
  5297 	// If we haven't added this old slug before, add it now.
  5615 	// If we haven't added this old slug before, add it now.
  5298 	if ( !empty( $post_before->post_name ) && !in_array($post_before->post_name, $old_slugs) )
  5616 	if ( ! empty( $post_before->post_name ) && ! in_array( $post_before->post_name, $old_slugs ) ) {
  5299 		add_post_meta($post_id, '_wp_old_slug', $post_before->post_name);
  5617 		add_post_meta( $post_id, '_wp_old_slug', $post_before->post_name );
       
  5618 	}
  5300 
  5619 
  5301 	// If the new slug was used previously, delete it from the list.
  5620 	// If the new slug was used previously, delete it from the list.
  5302 	if ( in_array($post->post_name, $old_slugs) )
  5621 	if ( in_array( $post->post_name, $old_slugs ) ) {
  5303 		delete_post_meta($post_id, '_wp_old_slug', $post->post_name);
  5622 		delete_post_meta( $post_id, '_wp_old_slug', $post->post_name );
       
  5623 	}
       
  5624 }
       
  5625 
       
  5626 /**
       
  5627  * Check for changed dates for published post objects and save the old date.
       
  5628  *
       
  5629  * The function is used when a post object of any type is updated,
       
  5630  * by comparing the current and previous post objects.
       
  5631  *
       
  5632  * If the date was changed and not already part of the old dates then it will be
       
  5633  * added to the post meta field ('_wp_old_date') for storing old dates for that
       
  5634  * post.
       
  5635  *
       
  5636  * The most logically usage of this function is redirecting changed post objects, so
       
  5637  * that those that linked to an changed post will be redirected to the new post.
       
  5638  *
       
  5639  * @since 4.9.3
       
  5640  *
       
  5641  * @param int     $post_id     Post ID.
       
  5642  * @param WP_Post $post        The Post Object
       
  5643  * @param WP_Post $post_before The Previous Post Object
       
  5644  */
       
  5645 function wp_check_for_changed_dates( $post_id, $post, $post_before ) {
       
  5646 	$previous_date = date( 'Y-m-d', strtotime( $post_before->post_date ) );
       
  5647 	$new_date = date( 'Y-m-d', strtotime( $post->post_date ) );
       
  5648 	// Don't bother if it hasn't changed.
       
  5649 	if ( $new_date == $previous_date ) {
       
  5650 		return;
       
  5651 	}
       
  5652 	// We're only concerned with published, non-hierarchical objects.
       
  5653 	if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) {
       
  5654 		return;
       
  5655 	}
       
  5656 	$old_dates = (array) get_post_meta( $post_id, '_wp_old_date' );
       
  5657 	// If we haven't added this old date before, add it now.
       
  5658 	if ( ! empty( $previous_date ) && ! in_array( $previous_date, $old_dates ) ) {
       
  5659 		add_post_meta( $post_id, '_wp_old_date', $previous_date );
       
  5660 	}
       
  5661 	// If the new slug was used previously, delete it from the list.
       
  5662 	if ( in_array( $new_date, $old_dates ) ) {
       
  5663 		delete_post_meta( $post_id, '_wp_old_date', $new_date );
       
  5664 	}
  5304 }
  5665 }
  5305 
  5666 
  5306 /**
  5667 /**
  5307  * Retrieve the private post SQL based on capability.
  5668  * Retrieve the private post SQL based on capability.
  5308  *
  5669  *
  5310  * post_status of a post type. The function will return a piece of SQL code
  5671  * post_status of a post type. The function will return a piece of SQL code
  5311  * that can be added to a WHERE clause; this SQL is constructed to allow all
  5672  * that can be added to a WHERE clause; this SQL is constructed to allow all
  5312  * published posts, and all private posts to which the user has access.
  5673  * published posts, and all private posts to which the user has access.
  5313  *
  5674  *
  5314  * @since 2.2.0
  5675  * @since 2.2.0
  5315  *
  5676  * @since 4.3.0 Added the ability to pass an array to `$post_type`.
  5316  * @param string $post_type Post type. Currently only supports 'post' or 'page'.
  5677  *
       
  5678  * @param string|array $post_type Single post type or an array of post types. Currently only supports 'post' or 'page'.
  5317  * @return string SQL code that can be added to a where clause.
  5679  * @return string SQL code that can be added to a where clause.
  5318  */
  5680  */
  5319 function get_private_posts_cap_sql( $post_type ) {
  5681 function get_private_posts_cap_sql( $post_type ) {
  5320 	return get_posts_by_author_sql( $post_type, false );
  5682 	return get_posts_by_author_sql( $post_type, false );
  5321 }
  5683 }
  5322 
  5684 
  5323 /**
  5685 /**
  5324  * Retrieve the post SQL based on capability, author, and type.
  5686  * Retrieve the post SQL based on capability, author, and type.
  5325  *
  5687  *
  5326  * @since 3.0.0
  5688  * @since 3.0.0
       
  5689  * @since 4.3.0 Introduced the ability to pass an array of post types to `$post_type`.
  5327  *
  5690  *
  5328  * @see get_private_posts_cap_sql()
  5691  * @see get_private_posts_cap_sql()
  5329  *
  5692  * @global wpdb $wpdb WordPress database abstraction object.
  5330  * @param string $post_type   Post type.
  5693  *
  5331  * @param bool   $full        Optional. Returns a full WHERE statement instead of just
  5694  * @param array|string   $post_type   Single post type or an array of post types.
  5332  *                            an 'andalso' term. Default true.
  5695  * @param bool           $full        Optional. Returns a full WHERE statement instead of just
  5333  * @param int    $post_author Optional. Query posts having a single author ID. Default null.
  5696  *                                    an 'andalso' term. Default true.
  5334  * @param bool   $public_only Optional. Only return public posts. Skips cap checks for
  5697  * @param int            $post_author Optional. Query posts having a single author ID. Default null.
  5335  *                            $current_user.  Default false.
  5698  * @param bool           $public_only Optional. Only return public posts. Skips cap checks for
       
  5699  *                                    $current_user.  Default false.
  5336  * @return string SQL WHERE code that can be added to a query.
  5700  * @return string SQL WHERE code that can be added to a query.
  5337  */
  5701  */
  5338 function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) {
  5702 function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) {
  5339 	global $wpdb;
  5703 	global $wpdb;
  5340 
  5704 
  5341 	// Private posts.
  5705 	if ( is_array( $post_type ) ) {
  5342 	$post_type_obj = get_post_type_object( $post_type );
  5706 		$post_types = $post_type;
  5343 	if ( ! $post_type_obj )
  5707 	} else {
  5344 		return $full ? 'WHERE 1 = 0' : ' 1 = 0 ';
  5708 		$post_types = array( $post_type );
  5345 
  5709 	}
  5346 	/**
  5710 
  5347 	 * Filter the capability to read private posts for a custom post type
  5711 	$post_type_clauses = array();
  5348 	 * when generating SQL for getting posts by author.
  5712 	foreach ( $post_types as $post_type ) {
  5349 	 *
  5713 		$post_type_obj = get_post_type_object( $post_type );
  5350 	 * @since 2.2.0
  5714 		if ( ! $post_type_obj ) {
  5351 	 * @deprecated 3.2.0 The hook transitioned from "somewhat useless" to "totally useless".
  5715 			continue;
  5352 	 *
  5716 		}
  5353 	 * @param string $cap Capability.
  5717 
  5354 	 */
  5718 		/**
  5355 	if ( ! $cap = apply_filters( 'pub_priv_sql_capability', '' ) ) {
  5719 		 * Filters the capability to read private posts for a custom post type
  5356 		$cap = $post_type_obj->cap->read_private_posts;
  5720 		 * when generating SQL for getting posts by author.
  5357 	}
  5721 		 *
  5358 
  5722 		 * @since 2.2.0
  5359 	$sql = $wpdb->prepare( 'post_type = %s', $post_type );
  5723 		 * @deprecated 3.2.0 The hook transitioned from "somewhat useless" to "totally useless".
       
  5724 		 *
       
  5725 		 * @param string $cap Capability.
       
  5726 		 */
       
  5727 		if ( ! $cap = apply_filters( 'pub_priv_sql_capability', '' ) ) {
       
  5728 			$cap = current_user_can( $post_type_obj->cap->read_private_posts );
       
  5729 		}
       
  5730 
       
  5731 		// Only need to check the cap if $public_only is false.
       
  5732 		$post_status_sql = "post_status = 'publish'";
       
  5733 		if ( false === $public_only ) {
       
  5734 			if ( $cap ) {
       
  5735 				// Does the user have the capability to view private posts? Guess so.
       
  5736 				$post_status_sql .= " OR post_status = 'private'";
       
  5737 			} elseif ( is_user_logged_in() ) {
       
  5738 				// Users can view their own private posts.
       
  5739 				$id = get_current_user_id();
       
  5740 				if ( null === $post_author || ! $full ) {
       
  5741 					$post_status_sql .= " OR post_status = 'private' AND post_author = $id";
       
  5742 				} elseif ( $id == (int) $post_author ) {
       
  5743 					$post_status_sql .= " OR post_status = 'private'";
       
  5744 				} // else none
       
  5745 			} // else none
       
  5746 		}
       
  5747 
       
  5748 		$post_type_clauses[] = "( post_type = '" . $post_type . "' AND ( $post_status_sql ) )";
       
  5749 	}
       
  5750 
       
  5751 	if ( empty( $post_type_clauses ) ) {
       
  5752 		return $full ? 'WHERE 1 = 0' : '1 = 0';
       
  5753 	}
       
  5754 
       
  5755 	$sql = '( '. implode( ' OR ', $post_type_clauses ) . ' )';
  5360 
  5756 
  5361 	if ( null !== $post_author ) {
  5757 	if ( null !== $post_author ) {
  5362 		$sql .= $wpdb->prepare( ' AND post_author = %d', $post_author );
  5758 		$sql .= $wpdb->prepare( ' AND post_author = %d', $post_author );
  5363 	}
  5759 	}
  5364 
       
  5365 	// Only need to check the cap if $public_only is false.
       
  5366 	$post_status_sql = "post_status = 'publish'";
       
  5367 	if ( false === $public_only ) {
       
  5368 		if ( current_user_can( $cap ) ) {
       
  5369 			// Does the user have the capability to view private posts? Guess so.
       
  5370 			$post_status_sql .= " OR post_status = 'private'";
       
  5371 		} elseif ( is_user_logged_in() ) {
       
  5372 			// Users can view their own private posts.
       
  5373 			$id = get_current_user_id();
       
  5374 			if ( null === $post_author || ! $full ) {
       
  5375 				$post_status_sql .= " OR post_status = 'private' AND post_author = $id";
       
  5376 			} elseif ( $id == (int) $post_author ) {
       
  5377 				$post_status_sql .= " OR post_status = 'private'";
       
  5378 			} // else none
       
  5379 		} // else none
       
  5380 	}
       
  5381 
       
  5382 	$sql .= " AND ($post_status_sql)";
       
  5383 
  5760 
  5384 	if ( $full ) {
  5761 	if ( $full ) {
  5385 		$sql = 'WHERE ' . $sql;
  5762 		$sql = 'WHERE ' . $sql;
  5386 	}
  5763 	}
  5387 
  5764 
  5394  * The server timezone is the default and is the difference between GMT and
  5771  * The server timezone is the default and is the difference between GMT and
  5395  * server time. The 'blog' value is the date when the last post was posted. The
  5772  * server time. The 'blog' value is the date when the last post was posted. The
  5396  * 'gmt' is when the last post was posted in GMT formatted date.
  5773  * 'gmt' is when the last post was posted in GMT formatted date.
  5397  *
  5774  *
  5398  * @since 0.71
  5775  * @since 0.71
  5399  *
  5776  * @since 4.4.0 The `$post_type` argument was added.
  5400  * @param string $timezone The location to get the time. Accepts 'gmt', 'blog',
  5777  *
  5401  *                         or 'server'. Default 'server'.
  5778  * @param string $timezone  Optional. The timezone for the timestamp. Accepts 'server', 'blog', or 'gmt'.
       
  5779  *                          'server' uses the server's internal timezone.
       
  5780  *                          'blog' uses the `post_modified` field, which proxies to the timezone set for the site.
       
  5781  *                          'gmt' uses the `post_modified_gmt` field.
       
  5782  *                          Default 'server'.
       
  5783  * @param string $post_type Optional. The post type to check. Default 'any'.
  5402  * @return string The date of the last post.
  5784  * @return string The date of the last post.
  5403  */
  5785  */
  5404 function get_lastpostdate( $timezone = 'server' ) {
  5786 function get_lastpostdate( $timezone = 'server', $post_type = 'any' ) {
  5405 	/**
  5787 	/**
  5406 	 * Filter the date the last post was published.
  5788 	 * Filters the date the last post was published.
  5407 	 *
  5789 	 *
  5408 	 * @since 2.3.0
  5790 	 * @since 2.3.0
  5409 	 *
  5791 	 *
  5410 	 * @param string $date     Date the last post was published. Likely values are 'gmt',
  5792 	 * @param string $date     Date the last post was published.
  5411 	 *                         'blog', or 'server'.
       
  5412 	 * @param string $timezone Location to use for getting the post published date.
  5793 	 * @param string $timezone Location to use for getting the post published date.
       
  5794 	 *                         See get_lastpostdate() for accepted `$timezone` values.
  5413 	 */
  5795 	 */
  5414 	return apply_filters( 'get_lastpostdate', _get_last_post_time( $timezone, 'date' ), $timezone );
  5796 	return apply_filters( 'get_lastpostdate', _get_last_post_time( $timezone, 'date', $post_type ), $timezone );
  5415 }
  5797 }
  5416 
  5798 
  5417 /**
  5799 /**
  5418  * Get the timestamp of the last time any post was modified.
  5800  * Get the timestamp of the last time any post was modified.
  5419  *
  5801  *
  5420  * The server timezone is the default and is the difference between GMT and
  5802  * The server timezone is the default and is the difference between GMT and
  5421  * server time. The 'blog' value is just when the last post was modified. The
  5803  * server time. The 'blog' value is just when the last post was modified. The
  5422  * 'gmt' is when the last post was modified in GMT time.
  5804  * 'gmt' is when the last post was modified in GMT time.
  5423  *
  5805  *
  5424  * @since 1.2.0
  5806  * @since 1.2.0
  5425  *
  5807  * @since 4.4.0 The `$post_type` argument was added.
  5426  * @param string $timezone Optional. The timezone for the timestamp. Uses the server's internal timezone.
  5808  *
  5427  *                         Accepts 'server', 'blog', 'gmt'. or 'server'. 'server' uses the server's
  5809  * @param string $timezone  Optional. The timezone for the timestamp. See get_lastpostdate()
  5428  *                         internal timezone. 'blog' uses the `post_modified` field, which proxies
  5810  *                          for information on accepted values.
  5429  *                         to the timezone set for the site. 'gmt' uses the `post_modified_gmt` field.
  5811  *                          Default 'server'.
  5430  *                         Default 'server'.
  5812  * @param string $post_type Optional. The post type to check. Default 'any'.
  5431  * @return string The timestamp.
  5813  * @return string The timestamp.
  5432  */
  5814  */
  5433 function get_lastpostmodified( $timezone = 'server' ) {
  5815 function get_lastpostmodified( $timezone = 'server', $post_type = 'any' ) {
  5434 	$lastpostmodified = _get_last_post_time( $timezone, 'modified' );
  5816 	/**
       
  5817 	 * Pre-filter the return value of get_lastpostmodified() before the query is run.
       
  5818 	 *
       
  5819 	 * @since 4.4.0
       
  5820 	 *
       
  5821 	 * @param string $lastpostmodified Date the last post was modified.
       
  5822 	 *                                 Returning anything other than false will short-circuit the function.
       
  5823 	 * @param string $timezone         Location to use for getting the post modified date.
       
  5824 	 *                                 See get_lastpostdate() for accepted `$timezone` values.
       
  5825 	 * @param string $post_type        The post type to check.
       
  5826 	 */
       
  5827 	$lastpostmodified = apply_filters( 'pre_get_lastpostmodified', false, $timezone, $post_type );
       
  5828 	if ( false !== $lastpostmodified ) {
       
  5829 		return $lastpostmodified;
       
  5830 	}
       
  5831 
       
  5832 	$lastpostmodified = _get_last_post_time( $timezone, 'modified', $post_type );
  5435 
  5833 
  5436 	$lastpostdate = get_lastpostdate($timezone);
  5834 	$lastpostdate = get_lastpostdate($timezone);
  5437 	if ( $lastpostdate > $lastpostmodified )
  5835 	if ( $lastpostdate > $lastpostmodified ) {
  5438 		$lastpostmodified = $lastpostdate;
  5836 		$lastpostmodified = $lastpostdate;
       
  5837 	}
  5439 
  5838 
  5440 	/**
  5839 	/**
  5441 	 * Filter the date the last post was modified.
  5840 	 * Filters the date the last post was modified.
  5442 	 *
  5841 	 *
  5443 	 * @since 2.3.0
  5842 	 * @since 2.3.0
  5444 	 *
  5843 	 *
  5445 	 * @param string $lastpostmodified Date the last post was modified.
  5844 	 * @param string $lastpostmodified Date the last post was modified.
  5446 	 * @param string $timezone         Location to use for getting the post modified date.
  5845 	 * @param string $timezone         Location to use for getting the post modified date.
  5447 	 *                                 See {@see get_lastpostmodified()} for accepted `$timezone` values.
  5846 	 *                                 See get_lastpostdate() for accepted `$timezone` values.
  5448 	 */
  5847 	 */
  5449 	return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
  5848 	return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
  5450 }
  5849 }
  5451 
  5850 
  5452 /**
  5851 /**
  5453  * Get the timestamp of the last time any post was modified or published.
  5852  * Get the timestamp of the last time any post was modified or published.
  5454  *
  5853  *
  5455  * @since 3.1.0
  5854  * @since 3.1.0
       
  5855  * @since 4.4.0 The `$post_type` argument was added.
  5456  * @access private
  5856  * @access private
  5457  *
  5857  *
  5458  * @param string $timezone The timezone for the timestamp. See {@see get_lastpostmodified()}
  5858  * @global wpdb $wpdb WordPress database abstraction object.
  5459  *                         for information on accepted values.
  5859  *
  5460  * @param string $field    Post field to check. Accepts 'date' or 'modified'.
  5860  * @param string $timezone  The timezone for the timestamp. See get_lastpostdate().
  5461  * @return string The timestamp.
  5861  *                          for information on accepted values.
  5462  */
  5862  * @param string $field     Post field to check. Accepts 'date' or 'modified'.
  5463 function _get_last_post_time( $timezone, $field ) {
  5863  * @param string $post_type Optional. The post type to check. Default 'any'.
       
  5864  * @return string|false The timestamp.
       
  5865  */
       
  5866 function _get_last_post_time( $timezone, $field, $post_type = 'any' ) {
  5464 	global $wpdb;
  5867 	global $wpdb;
  5465 
  5868 
  5466 	if ( !in_array( $field, array( 'date', 'modified' ) ) )
  5869 	if ( ! in_array( $field, array( 'date', 'modified' ) ) ) {
  5467 		return false;
  5870 		return false;
       
  5871 	}
  5468 
  5872 
  5469 	$timezone = strtolower( $timezone );
  5873 	$timezone = strtolower( $timezone );
  5470 
  5874 
  5471 	$key = "lastpost{$field}:$timezone";
  5875 	$key = "lastpost{$field}:$timezone";
       
  5876 	if ( 'any' !== $post_type ) {
       
  5877 		$key .= ':' . sanitize_key( $post_type );
       
  5878 	}
  5472 
  5879 
  5473 	$date = wp_cache_get( $key, 'timeinfo' );
  5880 	$date = wp_cache_get( $key, 'timeinfo' );
  5474 
  5881 	if ( false !== $date ) {
  5475 	if ( !$date ) {
  5882 		return $date;
  5476 		$add_seconds_server = date('Z');
  5883 	}
  5477 
  5884 
       
  5885 	if ( 'any' === $post_type ) {
  5478 		$post_types = get_post_types( array( 'public' => true ) );
  5886 		$post_types = get_post_types( array( 'public' => true ) );
  5479 		array_walk( $post_types, array( &$wpdb, 'escape_by_ref' ) );
  5887 		array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) );
  5480 		$post_types = "'" . implode( "', '", $post_types ) . "'";
  5888 		$post_types = "'" . implode( "', '", $post_types ) . "'";
  5481 
  5889 	} else {
  5482 		switch ( $timezone ) {
  5890 		$post_types = "'" . sanitize_key( $post_type ) . "'";
  5483 			case 'gmt':
  5891 	}
  5484 				$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");
  5892 
  5485 				break;
  5893 	switch ( $timezone ) {
  5486 			case 'blog':
  5894 		case 'gmt':
  5487 				$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");
  5895 			$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");
  5488 				break;
  5896 			break;
  5489 			case 'server':
  5897 		case 'blog':
  5490 				$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");
  5898 			$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");
  5491 				break;
  5899 			break;
  5492 		}
  5900 		case 'server':
  5493 
  5901 			$add_seconds_server = date( 'Z' );
  5494 		if ( $date )
  5902 			$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");
  5495 			wp_cache_set( $key, $date, 'timeinfo' );
  5903 			break;
  5496 	}
  5904 	}
  5497 
  5905 
  5498 	return $date;
  5906 	if ( $date ) {
       
  5907 		wp_cache_set( $key, $date, 'timeinfo' );
       
  5908 
       
  5909 		return $date;
       
  5910 	}
       
  5911 
       
  5912 	return false;
  5499 }
  5913 }
  5500 
  5914 
  5501 /**
  5915 /**
  5502  * Updates posts in cache.
  5916  * Updates posts in cache.
  5503  *
  5917  *
  5504  * @since 1.5.1
  5918  * @since 1.5.1
  5505  *
  5919  *
  5506  * @param array $posts Array of post objects, passed by reference.
  5920  * @param array $posts Array of post objects (passed by reference).
  5507  */
  5921  */
  5508 function update_post_cache( &$posts ) {
  5922 function update_post_cache( &$posts ) {
  5509 	if ( ! $posts )
  5923 	if ( ! $posts )
  5510 		return;
  5924 		return;
  5511 
  5925 
  5522  * This function not run if $_wp_suspend_cache_invalidation is not empty. See
  5936  * This function not run if $_wp_suspend_cache_invalidation is not empty. See
  5523  * wp_suspend_cache_invalidation().
  5937  * wp_suspend_cache_invalidation().
  5524  *
  5938  *
  5525  * @since 2.0.0
  5939  * @since 2.0.0
  5526  *
  5940  *
  5527  * @global wpdb $wpdb WordPress database abstraction object.
  5941  * @global bool $_wp_suspend_cache_invalidation
  5528  *
  5942  *
  5529  * @param int|WP_Post $post Post ID or post object to remove from the cache.
  5943  * @param int|WP_Post $post Post ID or post object to remove from the cache.
  5530  */
  5944  */
  5531 function clean_post_cache( $post ) {
  5945 function clean_post_cache( $post ) {
  5532 	global $_wp_suspend_cache_invalidation, $wpdb;
  5946 	global $_wp_suspend_cache_invalidation;
  5533 
  5947 
  5534 	if ( ! empty( $_wp_suspend_cache_invalidation ) )
  5948 	if ( ! empty( $_wp_suspend_cache_invalidation ) )
  5535 		return;
  5949 		return;
  5536 
  5950 
  5537 	$post = get_post( $post );
  5951 	$post = get_post( $post );
  5625  * function, do not need to perform SQL queries on their own.
  6039  * function, do not need to perform SQL queries on their own.
  5626  *
  6040  *
  5627  * @since 2.1.0
  6041  * @since 2.1.0
  5628  *
  6042  *
  5629  * @param array $post_ids List of post IDs.
  6043  * @param array $post_ids List of post IDs.
  5630  * @return bool|array Returns false if there is nothing to update or an array
  6044  * @return array|false Returns false if there is nothing to update or an array
  5631  *                    of metadata.
  6045  *                     of metadata.
  5632  */
  6046  */
  5633 function update_postmeta_cache( $post_ids ) {
  6047 function update_postmeta_cache( $post_ids ) {
  5634 	return update_meta_cache('post', $post_ids);
  6048 	return update_meta_cache('post', $post_ids);
  5635 }
  6049 }
  5636 
  6050 
  5642  *
  6056  *
  5643  * This function will not run if $_wp_suspend_cache_invalidation is not empty.
  6057  * This function will not run if $_wp_suspend_cache_invalidation is not empty.
  5644  *
  6058  *
  5645  * @since 3.0.0
  6059  * @since 3.0.0
  5646  *
  6060  *
  5647  * @see wp_suspend_cache_invalidation()
  6061  * @global bool $_wp_suspend_cache_invalidation
  5648  *
  6062  *
  5649  * @param int  $id          The attachment ID in the cache to clean.
  6063  * @param int  $id          The attachment ID in the cache to clean.
  5650  * @param bool $clean_terms Optional. Whether to clean terms cache. Default false.
  6064  * @param bool $clean_terms Optional. Whether to clean terms cache. Default false.
  5651  */
  6065  */
  5652 function clean_attachment_cache( $id, $clean_terms = false ) {
  6066 function clean_attachment_cache( $id, $clean_terms = false ) {
  5712 	// If published posts changed clear the lastpostmodified cache.
  6126 	// If published posts changed clear the lastpostmodified cache.
  5713 	if ( 'publish' == $new_status || 'publish' == $old_status) {
  6127 	if ( 'publish' == $new_status || 'publish' == $old_status) {
  5714 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
  6128 		foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
  5715 			wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' );
  6129 			wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' );
  5716 			wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' );
  6130 			wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' );
       
  6131 			wp_cache_delete( "lastpostdate:$timezone:{$post->post_type}", 'timeinfo' );
  5717 		}
  6132 		}
  5718 	}
  6133 	}
  5719 
  6134 
  5720 	if ( $new_status !== $old_status ) {
  6135 	if ( $new_status !== $old_status ) {
  5721 		wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
  6136 		wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
  5734  * @since 2.3.0
  6149  * @since 2.3.0
  5735  * @access private
  6150  * @access private
  5736  *
  6151  *
  5737  * @param int     $deprecated Not used. Can be set to null. Never implemented. Not marked
  6152  * @param int     $deprecated Not used. Can be set to null. Never implemented. Not marked
  5738  *                            as deprecated with _deprecated_argument() as it conflicts with
  6153  *                            as deprecated with _deprecated_argument() as it conflicts with
  5739  *                            wp_transition_post_status() and the default filter for
  6154  *                            wp_transition_post_status() and the default filter for _future_post_hook().
  5740  *                            {@see _future_post_hook()}.
       
  5741  * @param WP_Post $post       Post object.
  6155  * @param WP_Post $post       Post object.
  5742  */
  6156  */
  5743 function _future_post_hook( $deprecated, $post ) {
  6157 function _future_post_hook( $deprecated, $post ) {
  5744 	wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) );
  6158 	wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) );
  5745 	wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT') , 'publish_future_post', array( $post->ID ) );
  6159 	wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT') , 'publish_future_post', array( $post->ID ) );
  5772 
  6186 
  5773 	if ( get_option('default_pingback_flag') )
  6187 	if ( get_option('default_pingback_flag') )
  5774 		add_post_meta( $post_id, '_pingme', '1' );
  6188 		add_post_meta( $post_id, '_pingme', '1' );
  5775 	add_post_meta( $post_id, '_encloseme', '1' );
  6189 	add_post_meta( $post_id, '_encloseme', '1' );
  5776 
  6190 
  5777 	wp_schedule_single_event(time(), 'do_pings');
  6191 	if ( ! wp_next_scheduled( 'do_pings' ) ) {
       
  6192 		wp_schedule_single_event( time(), 'do_pings' );
       
  6193 	}
  5778 }
  6194 }
  5779 
  6195 
  5780 /**
  6196 /**
  5781  * Return the post's parent's post_ID
  6197  * Return the post's parent's post_ID
  5782  *
  6198  *
  5783  * @since 3.1.0
  6199  * @since 3.1.0
  5784  *
  6200  *
  5785  * @param int $post_ID
  6201  * @param int $post_ID
  5786  *
  6202  *
  5787  * @return int|bool Post parent ID, otherwise false.
  6203  * @return int|false Post parent ID, otherwise false.
  5788  */
  6204  */
  5789 function wp_get_post_parent_id( $post_ID ) {
  6205 function wp_get_post_parent_id( $post_ID ) {
  5790 	$post = get_post( $post_ID );
  6206 	$post = get_post( $post_ID );
  5791 	if ( !$post || is_wp_error( $post ) )
  6207 	if ( !$post || is_wp_error( $post ) )
  5792 		return false;
  6208 		return false;
  5795 
  6211 
  5796 /**
  6212 /**
  5797  * Check the given subset of the post hierarchy for hierarchy loops.
  6213  * Check the given subset of the post hierarchy for hierarchy loops.
  5798  *
  6214  *
  5799  * Prevents loops from forming and breaks those that it finds. Attached
  6215  * Prevents loops from forming and breaks those that it finds. Attached
  5800  * to the 'wp_insert_post_parent' filter.
  6216  * to the {@see 'wp_insert_post_parent'} filter.
  5801  *
  6217  *
  5802  * @since 3.1.0
  6218  * @since 3.1.0
  5803  *
  6219  *
  5804  * @see wp_find_hierarchy_loop()
  6220  * @see wp_find_hierarchy_loop()
  5805  *
  6221  *
  5840  *
  6256  *
  5841  * @since 3.1.0
  6257  * @since 3.1.0
  5842  *
  6258  *
  5843  * @param int|WP_Post $post         Post ID or post object where thumbnail should be attached.
  6259  * @param int|WP_Post $post         Post ID or post object where thumbnail should be attached.
  5844  * @param int         $thumbnail_id Thumbnail to attach.
  6260  * @param int         $thumbnail_id Thumbnail to attach.
  5845  * @return bool True on success, false on failure.
  6261  * @return int|bool True on success, false on failure.
  5846  */
  6262  */
  5847 function set_post_thumbnail( $post, $thumbnail_id ) {
  6263 function set_post_thumbnail( $post, $thumbnail_id ) {
  5848 	$post = get_post( $post );
  6264 	$post = get_post( $post );
  5849 	$thumbnail_id = absint( $thumbnail_id );
  6265 	$thumbnail_id = absint( $thumbnail_id );
  5850 	if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) {
  6266 	if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) {
  5888 		wp_delete_post( $delete, true );
  6304 		wp_delete_post( $delete, true );
  5889 	}
  6305 	}
  5890 }
  6306 }
  5891 
  6307 
  5892 /**
  6308 /**
       
  6309  * Queues posts for lazy-loading of term meta.
       
  6310  *
       
  6311  * @since 4.5.0
       
  6312  *
       
  6313  * @param array $posts Array of WP_Post objects.
       
  6314  */
       
  6315 function wp_queue_posts_for_term_meta_lazyload( $posts ) {
       
  6316 	$post_type_taxonomies = $term_ids = array();
       
  6317 	foreach ( $posts as $post ) {
       
  6318 		if ( ! ( $post instanceof WP_Post ) ) {
       
  6319 			continue;
       
  6320 		}
       
  6321 
       
  6322 		if ( ! isset( $post_type_taxonomies[ $post->post_type ] ) ) {
       
  6323 			$post_type_taxonomies[ $post->post_type ] = get_object_taxonomies( $post->post_type );
       
  6324 		}
       
  6325 
       
  6326 		foreach ( $post_type_taxonomies[ $post->post_type ] as $taxonomy ) {
       
  6327 			// Term cache should already be primed by `update_post_term_cache()`.
       
  6328 			$terms = get_object_term_cache( $post->ID, $taxonomy );
       
  6329 			if ( false !== $terms ) {
       
  6330 				foreach ( $terms as $term ) {
       
  6331 					if ( ! isset( $term_ids[ $term->term_id ] ) ) {
       
  6332 						$term_ids[] = $term->term_id;
       
  6333 					}
       
  6334 				}
       
  6335 			}
       
  6336 		}
       
  6337 	}
       
  6338 
       
  6339 	if ( $term_ids ) {
       
  6340 		$lazyloader = wp_metadata_lazyloader();
       
  6341 		$lazyloader->queue_objects( 'term', $term_ids );
       
  6342 	}
       
  6343 }
       
  6344 
       
  6345 /**
  5893  * Update the custom taxonomies' term counts when a post's status is changed.
  6346  * Update the custom taxonomies' term counts when a post's status is changed.
  5894  *
  6347  *
  5895  * For example, default posts term counts (for custom taxonomies) don't include
  6348  * For example, default posts term counts (for custom taxonomies) don't include
  5896  * private / draft posts.
  6349  * private / draft posts.
  5897  *
  6350  *
  5916  * @since 3.4.0
  6369  * @since 3.4.0
  5917  * @access private
  6370  * @access private
  5918  *
  6371  *
  5919  * @see update_post_caches()
  6372  * @see update_post_caches()
  5920  *
  6373  *
  5921  * @param array $ids               ID list
  6374  * @global wpdb $wpdb WordPress database abstraction object.
       
  6375  *
       
  6376  * @param array $ids               ID list.
  5922  * @param bool  $update_term_cache Optional. Whether to update the term cache. Default true.
  6377  * @param bool  $update_term_cache Optional. Whether to update the term cache. Default true.
  5923  * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
  6378  * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
  5924  */
  6379  */
  5925 function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) {
  6380 function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) {
  5926 	global $wpdb;
  6381 	global $wpdb;
  5930 		$fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) );
  6385 		$fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) );
  5931 
  6386 
  5932 		update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
  6387 		update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
  5933 	}
  6388 	}
  5934 }
  6389 }
       
  6390 
       
  6391 /**
       
  6392  * Adds a suffix if any trashed posts have a given slug.
       
  6393  *
       
  6394  * Store its desired (i.e. current) slug so it can try to reclaim it
       
  6395  * if the post is untrashed.
       
  6396  *
       
  6397  * For internal use.
       
  6398  *
       
  6399  * @since 4.5.0
       
  6400  * @access private
       
  6401  *
       
  6402  * @param string $post_name Slug.
       
  6403  * @param string $post_ID   Optional. Post ID that should be ignored. Default 0.
       
  6404  */
       
  6405 function wp_add_trashed_suffix_to_post_name_for_trashed_posts( $post_name, $post_ID = 0 ) {
       
  6406 	$trashed_posts_with_desired_slug = get_posts( array(
       
  6407 		'name' => $post_name,
       
  6408 		'post_status' => 'trash',
       
  6409 		'post_type' => 'any',
       
  6410 		'nopaging' => true,
       
  6411 		'post__not_in' => array( $post_ID )
       
  6412 	) );
       
  6413 
       
  6414 	if ( ! empty( $trashed_posts_with_desired_slug ) ) {
       
  6415 		foreach ( $trashed_posts_with_desired_slug as $_post ) {
       
  6416 			wp_add_trashed_suffix_to_post_name_for_post( $_post );
       
  6417 		}
       
  6418 	}
       
  6419 }
       
  6420 
       
  6421 /**
       
  6422  * Adds a trashed suffix for a given post.
       
  6423  *
       
  6424  * Store its desired (i.e. current) slug so it can try to reclaim it
       
  6425  * if the post is untrashed.
       
  6426  *
       
  6427  * For internal use.
       
  6428  *
       
  6429  * @since 4.5.0
       
  6430  * @access private
       
  6431  *
       
  6432  * @param WP_Post $post The post.
       
  6433  * @return string New slug for the post.
       
  6434  */
       
  6435 function wp_add_trashed_suffix_to_post_name_for_post( $post ) {
       
  6436 	global $wpdb;
       
  6437 
       
  6438 	$post = get_post( $post );
       
  6439 
       
  6440 	if ( '__trashed' === substr( $post->post_name, -9 ) ) {
       
  6441 		return $post->post_name;
       
  6442 	}
       
  6443 	add_post_meta( $post->ID, '_wp_desired_post_slug', $post->post_name );
       
  6444 	$post_name = _truncate_post_slug( $post->post_name, 191 ) . '__trashed';
       
  6445 	$wpdb->update( $wpdb->posts, array( 'post_name' => $post_name ), array( 'ID' => $post->ID ) );
       
  6446 	clean_post_cache( $post->ID );
       
  6447 	return $post_name;
       
  6448 }
       
  6449 
       
  6450 /**
       
  6451  * Filter the SQL clauses of an attachment query to include filenames.
       
  6452  *
       
  6453  * @since 4.7.0
       
  6454  * @access private
       
  6455  *
       
  6456  * @global wpdb $wpdb WordPress database abstraction object.
       
  6457  *
       
  6458  * @param array $clauses An array including WHERE, GROUP BY, JOIN, ORDER BY,
       
  6459  *                       DISTINCT, fields (SELECT), and LIMITS clauses.
       
  6460  * @return array The modified clauses.
       
  6461  */
       
  6462 function _filter_query_attachment_filenames( $clauses ) {
       
  6463 	global $wpdb;
       
  6464 	remove_filter( 'posts_clauses', __FUNCTION__ );
       
  6465 
       
  6466 	// Add a LEFT JOIN of the postmeta table so we don't trample existing JOINs.
       
  6467 	$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS sq1 ON ( {$wpdb->posts}.ID = sq1.post_id AND sq1.meta_key = '_wp_attached_file' )";
       
  6468 
       
  6469 	$clauses['groupby'] = "{$wpdb->posts}.ID";
       
  6470 
       
  6471 	$clauses['where'] = preg_replace(
       
  6472 		"/\({$wpdb->posts}.post_content (NOT LIKE|LIKE) (\'[^']+\')\)/",
       
  6473 		"$0 OR ( sq1.meta_value $1 $2 )",
       
  6474 		$clauses['where'] );
       
  6475 
       
  6476 	return $clauses;
       
  6477 }