* @param string $old_status Previous post status.
* @param WP_Post $post Post data.
function wp_transition_post_status( $new_status, $old_status, $post ) {
* Fires when a post is transitioned from one status to another.
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
do_action( 'transition_post_status', $new_status, $old_status, $post );
* Fires when a post is transitioned from one status to another.
* The dynamic portions of the hook name, `$new_status` and `$old_status`,
* refer to the old and new post statuses, respectively.
* @param WP_Post $post Post object.
do_action( "{$old_status}_to_{$new_status}", $post );
* Fires when a post is transitioned from one status to another.
* The dynamic portions of the hook name, `$new_status` and `$post->post_type`,
* refer to the new post status and post type, respectively.
* Please note: When this action is hooked using a particular post status (like
* 'publish', as `publish_{$post->post_type}`), it will fire both when a post is
* first transitioned to that status from something else, as well as upon
* subsequent post updates (old and new status are both the same).
* Therefore, if you are looking to only fire a callback when a post is first
* transitioned to a status, use the {@see 'transition_post_status'} hook instead.
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
* Fires actions after a post, its terms and meta data has been saved.
* @param int|WP_Post $post The post ID or object that has been saved.
* @param bool $update Whether this is an existing post being updated.
* @param null|WP_Post $post_before Null for new posts, the WP_Post object prior
* to the update for updated posts.
function wp_after_insert_post( $post, $update, $post_before ) {
$post = get_post( $post );
* Fires once a post, its terms and meta data has been saved.
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
* @param bool $update Whether this is an existing post being updated.
* @param null|WP_Post $post_before Null for new posts, the WP_Post object prior
* to the update for updated posts.
do_action( 'wp_after_insert_post', $post_id, $post, $update, $post_before );
// Comment, trackback, and pingback functions.
* Add a URL to those already pinged.
* @since 4.7.0 `$post_id` can be a WP_Post object.
* @since 4.7.0 `$uri` can be an array of URIs.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int|WP_Post $post_id Post object or ID.
* @param string|array $uri Ping URI or array of URIs.
* @return int|false How many rows were updated.
function add_ping( $post_id, $uri ) {
$post = get_post( $post_id );
$pung = trim( $post->pinged );
$pung = preg_split( '/\s/', $pung );
if ( is_array( $uri ) ) {
$pung = array_merge( $pung, $uri );
$new = implode( "\n", $pung );
* Filters the new ping URL to add for the given post.
* @param string $new New ping URL to add.
$new = apply_filters( 'add_ping', $new );
$return = $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post->ID ) );
clean_post_cache( $post->ID );
* Retrieve enclosures already enclosed for a post.
* @param int $post_id Post ID.
* @return string[] Array of enclosures for the given post.
function get_enclosed( $post_id ) {
$custom_fields = get_post_custom( $post_id );
if ( ! is_array( $custom_fields ) ) {
foreach ( $custom_fields as $key => $val ) {
if ( 'enclosure' !== $key || ! is_array( $val ) ) {
foreach ( $val as $enc ) {
$enclosure = explode( "\n", $enc );
$pung[] = trim( $enclosure[0] );
* Filters the list of enclosures already enclosed for the given post.
* @param string[] $pung Array of enclosures for the given post.
* @param int $post_id Post ID.
return apply_filters( 'get_enclosed', $pung, $post_id );
* Retrieve URLs already pinged for a post.
* @since 4.7.0 `$post_id` can be a WP_Post object.
* @param int|WP_Post $post_id Post ID or object.
* @return string[]|false Array of URLs already pinged for the given post, false if the post is not found.
function get_pung( $post_id ) {
$post = get_post( $post_id );
$pung = trim( $post->pinged );
$pung = preg_split( '/\s/', $pung );
* Filters the list of already-pinged URLs for the given post.
* @param string[] $pung Array of URLs already pinged for the given post.
return apply_filters( 'get_pung', $pung );
* Retrieve URLs that need to be pinged.
* @since 4.7.0 `$post_id` can be a WP_Post object.
* @param int|WP_Post $post_id Post Object or ID
* @return string[]|false List of URLs yet to ping.
function get_to_ping( $post_id ) {
$post = get_post( $post_id );
$to_ping = sanitize_trackback_urls( $post->to_ping );
$to_ping = preg_split( '/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY );
* Filters the list of URLs yet to ping for the given post.
* @param string[] $to_ping List of URLs yet to ping.
return apply_filters( 'get_to_ping', $to_ping );
* Do trackbacks for a list of URLs.
* @param string $tb_list Comma separated list of URLs.
* @param int $post_id Post ID.
function trackback_url_list( $tb_list, $post_id ) {
if ( ! empty( $tb_list ) ) {
$postdata = get_post( $post_id, ARRAY_A );
$excerpt = strip_tags( $postdata['post_excerpt'] ? $postdata['post_excerpt'] : $postdata['post_content'] );
if ( strlen( $excerpt ) > 255 ) {
$excerpt = substr( $excerpt, 0, 252 ) . '…';
$trackback_urls = explode( ',', $tb_list );
foreach ( (array) $trackback_urls as $tb_url ) {
$tb_url = trim( $tb_url );
trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id );
* Get a list of page IDs.
* @global wpdb $wpdb WordPress database abstraction object.
* @return string[] List of page IDs as strings.
function get_all_page_ids() {
$page_ids = wp_cache_get( 'all_page_ids', 'posts' );
if ( ! is_array( $page_ids ) ) {
$page_ids = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'page'" );
wp_cache_add( 'all_page_ids', $page_ids, 'posts' );
* Retrieves page data given a page ID or page object.
* Use get_post() instead of get_page().
* @deprecated 3.5.0 Use get_post()
* @param int|WP_Post $page Page object or page ID. Passed by reference.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
* correspond to a WP_Post object, an associative array, or a numeric array,
* respectively. Default OBJECT.
* @param string $filter Optional. How the return value should be filtered. Accepts 'raw',
* 'edit', 'db', 'display'. Default 'raw'.
* @return WP_Post|array|null WP_Post or array on success, null on failure.
function get_page( $page, $output = OBJECT, $filter = 'raw' ) {
return get_post( $page, $output, $filter );
* Retrieves a page given its path.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $page_path Page path.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
* correspond to a WP_Post object, an associative array, or a numeric array,
* respectively. Default OBJECT.
* @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
* @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
$last_changed = wp_cache_get_last_changed( 'posts' );
$hash = md5( $page_path . serialize( $post_type ) );
$cache_key = "get_page_by_path:$hash:$last_changed";
$cached = wp_cache_get( $cache_key, 'posts' );
if ( false !== $cached ) {
// Special case: '0' is a bad `$page_path`.
if ( '0' === $cached || 0 === $cached ) {
return get_post( $cached, $output );
$page_path = rawurlencode( urldecode( $page_path ) );
$page_path = str_replace( '%2F', '/', $page_path );
$page_path = str_replace( '%20', ' ', $page_path );
$parts = explode( '/', trim( $page_path, '/' ) );
$parts = array_map( 'sanitize_title_for_query', $parts );
$escaped_parts = esc_sql( $parts );
$in_string = "'" . implode( "','", $escaped_parts ) . "'";
if ( is_array( $post_type ) ) {
$post_types = $post_type;
$post_types = array( $post_type, 'attachment' );
$post_types = esc_sql( $post_types );
$post_type_in_string = "'" . implode( "','", $post_types ) . "'";
SELECT ID, post_name, post_parent, post_type
WHERE post_name IN ($in_string)
AND post_type IN ($post_type_in_string)
$pages = $wpdb->get_results( $sql, OBJECT_K );
$revparts = array_reverse( $parts );
foreach ( (array) $pages as $page ) {
if ( $page->post_name == $revparts[0] ) {
* Loop through the given path parts from right to left,
* ensuring each matches the post ancestry.
while ( 0 != $p->post_parent && isset( $pages[ $p->post_parent ] ) ) {
$parent = $pages[ $p->post_parent ];
if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] ) {
if ( 0 == $p->post_parent && count( $revparts ) == $count + 1 && $p->post_name == $revparts[ $count ] ) {
if ( $page->post_type == $post_type ) {
// We cache misses as well as hits.
wp_cache_set( $cache_key, $foundid, 'posts' );
return get_post( $foundid, $output );
* Retrieve a page given its title.
* If more than one post uses the same title, the post with the smallest ID will be returned.
* Be careful: in case of more than one post having the same title, it will check the oldest
* publication date, not the smallest ID.
* Because this function uses the MySQL '=' comparison, $page_title will usually be matched
* as case-insensitive with default collation.
* @since 3.0.0 The `$post_type` parameter was added.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $page_title Page title.
* @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
* correspond to a WP_Post object, an associative array, or a numeric array,
* respectively. Default OBJECT.
* @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
* @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) {
if ( is_array( $post_type ) ) {
$post_type = esc_sql( $post_type );
$post_type_in_string = "'" . implode( "','", $post_type ) . "'";
AND post_type IN ($post_type_in_string)
$page = $wpdb->get_var( $sql );
return get_post( $page, $output );
* Identify descendants of a given page ID in a list of page objects.
* Descendants are identified from the `$pages` array passed to the function. No database queries are performed.
* @param int $page_id Page ID.
* @param array $pages List of page objects from which descendants should be identified.
* @return array List of page children.
function get_page_children( $page_id, $pages ) {
// Build a hash of ID -> children.
foreach ( (array) $pages as $page ) {
$children[ (int) $page->post_parent ][] = $page;
// Start the search by looking at immediate children.
if ( isset( $children[ $page_id ] ) ) {
// Always start at the end of the stack in order to preserve original `$pages` order.
$to_look = array_reverse( $children[ $page_id ] );
$p = array_pop( $to_look );
if ( isset( $children[ $p->ID ] ) ) {
foreach ( array_reverse( $children[ $p->ID ] ) as $child ) {
// Append to the `$to_look` stack to descend the tree.
* Order the pages with children under parents in a flat list.
* It uses auxiliary structure to hold parent-children relationships and
* runs in O(N) complexity
* @param WP_Post[] $pages Posts array (passed by reference).