'suppress_filters' => false,
'meta_key' => '_trackbackme',
foreach ( $trackbacks as $trackback ) {
delete_post_meta( $trackback, '_trackbackme' );
do_trackbacks( $trackback );
* @since 4.7.0 `$post` can be a WP_Post object.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int|WP_Post $post Post ID or object to do trackbacks on.
* @return void|false Returns false on failure.
function do_trackbacks( $post ) {
$post = get_post( $post );
$to_ping = get_to_ping( $post );
$pinged = get_pung( $post );
if ( empty( $to_ping ) ) {
$wpdb->update( $wpdb->posts, array( 'to_ping' => '' ), array( 'ID' => $post->ID ) );
if ( empty( $post->post_excerpt ) ) {
/** This filter is documented in wp-includes/post-template.php */
$excerpt = apply_filters( 'the_content', $post->post_content, $post->ID );
/** This filter is documented in wp-includes/post-template.php */
$excerpt = apply_filters( 'the_excerpt', $post->post_excerpt );
$excerpt = str_replace( ']]>', ']]>', $excerpt );
$excerpt = wp_html_excerpt( $excerpt, 252, '…' );
/** This filter is documented in wp-includes/post-template.php */
$post_title = apply_filters( 'the_title', $post->post_title, $post->ID );
$post_title = strip_tags( $post_title );
foreach ( (array) $to_ping as $tb_ping ) {
$tb_ping = trim( $tb_ping );
if ( ! in_array( $tb_ping, $pinged, true ) ) {
trackback( $tb_ping, $post_title, $excerpt, $post->ID );
"UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s,
* Sends pings to all of the ping site services.
* @param int $post_id Post ID.
* @return int Same post ID as provided.
function generic_ping( $post_id = 0 ) {
$services = get_option( 'ping_sites' );
$services = explode( "\n", $services );
foreach ( (array) $services as $service ) {
$service = trim( $service );
* Pings back the links found in a post.
* @since 4.7.0 `$post` can be a WP_Post object.
* @since 6.8.0 Returns an array of pingback statuses indexed by link.
* @param string $content Post content to check for links. If empty will retrieve from post.
* @param int|WP_Post $post Post ID or object.
* @return array<string, bool> An array of pingback statuses indexed by link.
function pingback( $content, $post ) {
require_once ABSPATH . WPINC . '/class-IXR.php';
require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
// Original code by Mort (http://mort.mine.nu:8080).
$post = get_post( $post );
$pung = get_pung( $post );
if ( empty( $content ) ) {
$content = $post->post_content;
* Parsing the post, external links (if any) are stored in the $post_links array.
$post_links_temp = wp_extract_urls( $content );
* Walking through the links array.
* First we get rid of links pointing to sites, not to specific files.
* http://dummy-weblog.org
* http://dummy-weblog.org/
* http://dummy-weblog.org/post.php
* We don't wanna ping first and second types, even if they have a valid <link/>.
foreach ( (array) $post_links_temp as $link_test ) {
// If we haven't pung it already and it isn't a link to itself.
if ( ! in_array( $link_test, $pung, true ) && ( url_to_postid( $link_test ) !== $post->ID )
// Also, let's never ping local attachments.
&& ! is_local_attachment( $link_test )
$test = parse_url( $link_test );
if ( isset( $test['query'] ) ) {
$post_links[] = $link_test;
} elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
$post_links[] = $link_test;
$post_links = array_unique( $post_links );
* Fires just before pinging back links found in a post.
* @param string[] $post_links Array of link URLs to be checked (passed by reference).
* @param string[] $pung Array of link URLs already pinged (passed by reference).
* @param int $post_id The post ID.
do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post->ID ) );
foreach ( (array) $post_links as $pagelinkedto ) {
$pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
if ( $pingback_server_url ) {
// Allow an additional 60 seconds for each pingback to complete.
if ( function_exists( 'set_time_limit' ) ) {
$pagelinkedfrom = get_permalink( $post );
// Using a timeout of 3 seconds should be enough to cover slow servers.
$client = new WP_HTTP_IXR_Client( $pingback_server_url );
* Filters the user agent sent when pinging-back a URL.
* @param string $concat_useragent The user agent concatenated with ' -- WordPress/'
* and the WordPress version.
* @param string $useragent The useragent.
* @param string $pingback_server_url The server URL being linked to.
* @param string $pagelinkedto URL of page linked to.
* @param string $pagelinkedfrom URL of page linked from.
$client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . get_bloginfo( 'version' ), $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom );
// When set to true, this outputs debug messages by itself.
$status = $client->query( 'pingback.ping', $pagelinkedfrom, $pagelinkedto );
if ( $status // Ping registered.
|| ( isset( $client->error->code ) && 48 === $client->error->code ) // Already registered.
add_ping( $post, $pagelinkedto );
$ping_status[ $pagelinkedto ] = $status;
* Checks whether blog is public before returning sites.
* @param mixed $sites Will return if blog is public, will not return if not public.
* @return mixed Empty string if blog is not public, returns $sites, if site is public.
function privacy_ping_filter( $sites ) {
if ( '0' !== get_option( 'blog_public' ) ) {
* Updates database when sending trackback to prevent duplicates.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $trackback_url URL to send trackbacks.
* @param string $title Title of post.
* @param string $excerpt Excerpt of post.
* @param int $post_id Post ID.
* @return int|false|void Database query from update.
function trackback( $trackback_url, $title, $excerpt, $post_id ) {
if ( empty( $trackback_url ) ) {
$options['timeout'] = 10;
$options['body'] = array(
'url' => get_permalink( $post_id ),
'blog_name' => get_option( 'blogname' ),
$response = wp_safe_remote_post( $trackback_url, $options );
if ( is_wp_error( $response ) ) {
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $post_id ) );
return $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $post_id ) );
* @param string $server Host of blog to connect to.
* @param string $path Path to send the ping.
function weblog_ping( $server = '', $path = '' ) {
require_once ABSPATH . WPINC . '/class-IXR.php';
require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
// Using a timeout of 3 seconds should be enough to cover slow servers.
$client = new WP_HTTP_IXR_Client( $server, ( ( ! strlen( trim( $path ) ) || ( '/' === $path ) ) ? false : $path ) );
$client->useragent .= ' -- WordPress/' . get_bloginfo( 'version' );
// When set to true, this outputs debug messages by itself.
$home = trailingslashit( home_url() );
if ( ! $client->query( 'weblogUpdates.extendedPing', get_option( 'blogname' ), $home, get_bloginfo( 'rss2_url' ) ) ) { // Then try a normal ping.
$client->query( 'weblogUpdates.ping', get_option( 'blogname' ), $home );
* Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI.
* @see wp_http_validate_url()
* @param string $source_uri
function pingback_ping_source_uri( $source_uri ) {
return (string) wp_http_validate_url( $source_uri );
* Default filter attached to xmlrpc_pingback_error.
* Returns a generic pingback error code unless the error code is 48,
* which reports that the pingback is already registered.
* @link https://www.hixie.ch/specs/pingback/pingback#TOC3
* @param IXR_Error $ixr_error
function xmlrpc_pingback_error( $ixr_error ) {
if ( 48 === $ixr_error->code ) {
return new IXR_Error( 0, '' );
* Removes a comment from the object cache.
* @param int|array $ids Comment ID or an array of comment IDs to remove from cache.
function clean_comment_cache( $ids ) {
$comment_ids = (array) $ids;
wp_cache_delete_multiple( $comment_ids, 'comment' );
foreach ( $comment_ids as $id ) {
* Fires immediately after a comment has been removed from the object cache.
* @param int $id Comment ID.
do_action( 'clean_comment_cache', $id );
wp_cache_set_comments_last_changed();
* Updates the comment cache of given comments.
* Will add the comments in $comments to the cache. If comment ID already exists
* in the comment cache then it will not be updated. The comment is added to the
* cache using the comment group with the key using the ID of the comments.
* @since 4.4.0 Introduced the `$update_meta_cache` parameter.
* @param WP_Comment[] $comments Array of comment objects
* @param bool $update_meta_cache Whether to update commentmeta cache. Default true.
function update_comment_cache( $comments, $update_meta_cache = true ) {
foreach ( (array) $comments as $comment ) {
$data[ $comment->comment_ID ] = $comment;
wp_cache_add_multiple( $data, 'comment' );
if ( $update_meta_cache ) {
// Avoid `wp_list_pluck()` in case `$comments` is passed by reference.
foreach ( $comments as $comment ) {
$comment_ids[] = $comment->comment_ID;
update_meta_cache( 'comment', $comment_ids );
* Adds any comments from the given IDs to the cache that do not already exist in cache.
* @since 6.1.0 This function is no longer marked as "private".
* @since 6.3.0 Use wp_lazyload_comment_meta() for lazy-loading of comment meta.
* @see update_comment_cache()
* @global wpdb $wpdb WordPress database abstraction object.
* @param int[] $comment_ids Array of comment IDs.
* @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true.
function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
$non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
if ( ! empty( $non_cached_ids ) ) {
$fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", implode( ',', array_map( 'intval', $non_cached_ids ) ) ) );
update_comment_cache( $fresh_comments, false );
if ( $update_meta_cache ) {
wp_lazyload_comment_meta( $comment_ids );
* Closes comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
* @param WP_Post $posts Post data object.
* @param WP_Query $query Query object.
function _close_comments_for_old_posts( $posts, $query ) {
if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) ) {
* Filters the list of post types to automatically close comments for.
* @param string[] $post_types An array of post type names.
$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
if ( ! in_array( $posts[0]->post_type, $post_types, true ) ) {
$days_old = (int) get_option( 'close_comments_days_old' );
if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) {
$posts[0]->comment_status = 'closed';
$posts[0]->ping_status = 'closed';
* Closes comments on an old post. Hooked to comments_open and pings_open.
* @param bool $open Comments open or closed.
* @param int $post_id Post ID.
function _close_comments_for_old_post( $open, $post_id ) {
if ( ! get_option( 'close_comments_for_old_posts' ) ) {
$days_old = (int) get_option( 'close_comments_days_old' );
$post = get_post( $post_id );
/** This filter is documented in wp-includes/comment.php */
$post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
if ( ! in_array( $post->post_type, $post_types, true ) ) {
// Undated drafts should not show up as comments closed.
if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) {