Altering the pingback functionality

I’d like to make good use of the ole pingback on a multi-author site, but with some alterations and concerns.

  1. They should be only available internally, no external pingbacks accepted. If I understand right, disabling them in the general options while leaving them open on each post should do it – is this correct?

  2. I want to alter their format. Right now the reffering page title becomes the author which is not cool. I’d rather have the actual post author as author and the_title() / <h1> as headline (new field), with the snippet staying in place as content. I didn’t find much about this, is there a documented API (non-obsolete) or some hook/filter that could accomplish it?

Note: I suppose that something should rather happen on the sending end, like passing the post id for later use. I have an idea on how to do it but it involes adding the post id on the visible content (like url) and I’m reluctant to do that.

  1. Is the pingback functionality going to be supported long-term in WordPress or is it likely to be deprecated. In case it’s going anywhere, is it likely to have a sort of legacy enabling like the ‘links’ do, or will my pingbacks end up in limbo?

  2. Webmentions a better idea or a dead/er end?

1 Answer
1

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