: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* from 'draft' – or some other status – to 'publish'. However, if a post is already
* published and is simply being updated, the "old" and "new" statuses may both be 'publish'
* before and after the transition.
* @param string $new_status Transition to this post status.
* @param string $old_status Previous post status.
* @param WP_Post $post Post data.
function wp_transition_post_status( $new_status, $old_status, $post ) {
* Fires when a post is transitioned from one status to another.
* @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.
* Possible hook names include:
* @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.
* Possible hook names include:
* Please note: When this action is hooked using a particular post status (like
* 'publish', as `publish_{$post->post_type}`), it will fire both when a post is
* first transitioned to that status from something else, as well as upon
* subsequent post updates (old and new status are both the same).
* Therefore, if you are looking to only fire a callback when a post is first
* transitioned to a status, use the {@see 'transition_post_status'} hook instead.
* @since 5.9.0 Added `$old_status` parameter.
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
* @param string $old_status Old post status.
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post, $old_status );
* 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.
* Adds a URL to those already pinged.
* @since 4.7.0 `$post` 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 Post ID or post object.
* @param string|array $uri Ping URI or array of URIs.
* @return int|false How many rows were updated.
function add_ping( $post, $uri ) {
$post = get_post( $post );
$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 );
* Retrieves 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 );
* Retrieves URLs already pinged for a post.
* @since 4.7.0 `$post` can be a WP_Post object.
* @param int|WP_Post $post 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 ) {
$post = get_post( $post );
$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 );
* Retrieves URLs that need to be pinged.
* @since 4.7.0 `$post` can be a WP_Post object.
* @param int|WP_Post $post Post ID or post object.
* @return string[]|false List of URLs yet to ping.
function get_to_ping( $post ) {
$post = get_post( $post );
$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 );
* Does 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 );
* Gets 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, 'post-queries' );
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, 'post-queries' );
return get_post( $foundid, $output );
* Identifies 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 WP_Post[] $pages List of page objects from which descendants should be identified.
* @return WP_Post[] 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.
* Orders 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).
* @param int $page_id Optional. Parent page ID. Default 0.
* @return string[] Array of post names keyed by ID and arranged by hierarchy. Children immediately follow their parents.
function get_page_hierarchy( &$pages, $page_id = 0 ) {
foreach ( (array) $pages as $p ) {
$parent_id = (int) $p->post_parent;
$children[ $parent_id ][] = $p;
_page_traverse_name( $page_id, $children, $result );
* Traverses and return all the nested children post names of a root page.