Altering the pingback functionality

Actually, it turned out quite easy, as the post can be retrieved from the slug:

// get the url of the reffering post
$ping_slug = $comment->comment_author_url;
// keep just the slug
$ping_slug = trim(parse_url($ping_slug, PHP_URL_PATH), "https://wordpress.stackexchange.com/");
// get the post from the slug
$ping_post = get_page_by_path($ping_slug, OBJECT, 'post');
// find the post author data
$ping_author = get_userdata($ping_post->post_author);
// display the author name
echo $ping_author->display_name;
// so on, so forth

UPDATE:

I ended up skipping the xmlrpc api altogether as it’s less than optimal for internal links only since we alreay have direct access / only reused the wp component that looks for links
This could be done more easily with just custom fields, but repurposing comments has the advantage that one could use the known interface to either edit or simply delete links they don’t want unde their posts.
Also, you can chose not to actually display the pingbacks but it’s still useful to keep track on internal links in the comments admin section.

So the function runs like this:

add_action('post_updated', 'my_cute_internal_pings');
function my_cute_internal_pings() {
global $post;

// defining or initializing variables
$title = get_the_title($post->ID);
$url = get_the_permalink($post->ID);
$content = get_the_content($post->ID);
$postid = get_the_ID($post->ID);
$links = array();

// this is the function wordpress uses to look for links
$links = wp_extract_urls($content);

// cleaning protocols and whatever – this is for a non-www domani so make sure you make adjustments if needed
$protocols = array('http://', 'https://', 'http://www.', 'https://www.', 'www.');
$domain = str_replace($protocols, '', get_bloginfo('url'));

// here it goes
$allpings = array();
foreach ($links as $key => $link) {

// remove links to other sites
if(!strpos($link, $domain)) {  unset($links[$key]);  }

// keep slug only so you can search for the target post in the database
$parts = explode("https://wordpress.stackexchange.com/", $link);
$link = implode("https://wordpress.stackexchange.com/", array_slice($parts, 3, 1));

// now find the post
$postobject = get_page_by_path( $link, OBJECT, array( 'post' ) );

// and make a nice array of ids
$allpings[] = $postobject->ID;
}

// (a list of sent pings should be kept so you don't send them on every update – details below)

// get the previous* list from the custom field
$oldpings = array();
$oldpings = get_post_meta($postid, 'pings', $single = true);

check if there's something new
$newpings = array_diff($allpings,$oldpings);

// now rebuild a complete list of articles mentioned...
$fullpings = array_unique(array_merge($oldpings,$newpings));

and store it store in *a/the custom field
update_post_meta($postid, 'pings', $fullpings );

// so what should the actual comment be? you can either leave it empty and use the actual excerpt etc for display or...
// you can try and find the exact context on the link

foreach ($newpings as $key => $ping) {
$url = get_permalink($ping);

// this great regex is courtesy of Wiktor Stribiżew https://stackoverflow.com/questions/70433338/regex-php-to-extract-a-sentence-that-contains-a-link
// what it does is to get the entire sentence that contains the link (in $ = output).

$regex = '~\b(?:[^.?!]|https?://[^<>\s"\']++)*?'.preg_quote($url, '~').'(?:[^.?!]|https?://[^<>\s"\']++)*[.?!]*~u';
if (preg_match_all($regex, $content, $match)){$output = array_map(function($x) {return strip_tags($x);}, $match[0]);}

// (optional) if we think the sentence may be to long, we can set a length limit
$output = substr($output[0], 0, 300);

// now that we have everything we need, we can generate a brand new comment.

wp_insert_comment(array(
// (optional) use this in case you still have regular comments, to differentiate. 
// You may also want to make sure that exclude pingbacks from the comments loop, just search 'separate comments and pingbacks'.
// If you have pingbacks too, you may want to call it something else... trackbacks or whatever.
    'comment_type' => 'pingback',
// indicating the post we comment on
    'comment_post_ID' => $ping,
// (optional) using the post title as the author. I only view this in admin, but you can put whatever here and maybe use it for display too
    'comment_author' => $title, 
// here I repurposed the e-mail field, which is not needed for pingbacks
    'comment_author_email' => $postid, 
// here we put the url of the post, again mostly for admin display
    'comment_author_url' => $url, 
// and this is the content that we got with that regex
    'comment_content' => $output
    ));
    }
}

Now, to actually display the pingbacks, add this to your comment template

$comments = get_comments(array('post_id' => $post->ID));
if ( $comments ) { 

// here you can do an `echo '[Posts that link here]';` or whatever for the title

// getting the 'comments' newest first
foreach (array_reverse($comments) as $comment) {

// now we get the post id for each originating article
$post = get_post($comment->comment_author_email);

// get everything there is about that article
setup_postdata($post);
global $post;

// if the comment has the content found by that regex, replace the article excerpt on-the-fly
if($comment->comment_content) {$post->post_excerpt="[…] <q>" . $comment->comment_content . '</q> […]';}

// [here goes your template for excerpts with all the usual bells and whistles / title, link, thumbnail, taxonomies, actual (not 'comment') date, (replaced) excerpt etc. ]

// prepare to start over with the nest comment
wp_reset_postdata();
    } 
}

Leave a Comment