wp_xmlrpc_server::pingback_ping( array $args )

Retrieves a pingback and registers it.


Parameters

$args

(array) (Required) Method arguments. Note: arguments must be ordered as documented.

  • 'pagelinkedfrom'
    (string)
  • 'pagelinkedto'
    (string)


Return

(string|IXR_Error)


Source

File: wp-includes/class-wp-xmlrpc-server.php

	public function pingback_ping( $args ) {
		global $wpdb;

		/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
		do_action( 'xmlrpc_call', 'pingback.ping' );

		$this->escape( $args );

		$pagelinkedfrom = str_replace( '&', '&', $args[0] );
		$pagelinkedto = str_replace( '&', '&', $args[1] );
		$pagelinkedto = str_replace( '&', '&', $pagelinkedto );

		/**
		 * Filters the pingback source URI.
		 *
		 * @since WP-3.6.0
		 *
		 * @param string $pagelinkedfrom URI of the page linked from.
		 * @param string $pagelinkedto   URI of the page linked to.
		 */
		$pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto );

		if ( ! $pagelinkedfrom )
			return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) );

		// Check if the page linked to is in our site
		$pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
		if ( !$pos1 )
			return $this->pingback_error( 0, __( 'Is there no link to us?' ) );

		// let's find which post is linked to
		// FIXME: does url_to_postid() cover all these cases already?
		//        if so, then let's use it and drop the old code.
		$urltest = parse_url($pagelinkedto);
		if ( $post_ID = url_to_postid($pagelinkedto) ) {
			// $way
		} elseif ( isset( $urltest['path'] ) && preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
			// the path defines the post_ID (archives/p/XXXX)
			$blah = explode('/', $match[0]);
			$post_ID = (int) $blah[1];
		} elseif ( isset( $urltest['query'] ) && preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
			// the querystring defines the post_ID (?p=XXXX)
			$blah = explode('=', $match[0]);
			$post_ID = (int) $blah[1];
		} elseif ( isset($urltest['fragment']) ) {
			// an #anchor is there, it's either...
			if ( intval($urltest['fragment']) ) {
				// ...an integer #XXXX (simplest case)
				$post_ID = (int) $urltest['fragment'];
			} elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
				// ...a post id in the form 'post-###'
				$post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
			} elseif ( is_string($urltest['fragment']) ) {
				// ...or a string #title, a little more complicated
				$title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
				$sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title );
				if (! ($post_ID = $wpdb->get_var($sql)) ) {
					// returning unknown error '0' is better than die()ing
			  		return $this->pingback_error( 0, '' );
				}
			}
		} else {
			// TODO: Attempt to extract a post ID from the given URL
	  		return $this->pingback_error( 33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );
		}
		$post_ID = (int) $post_ID;

		$post = get_post($post_ID);

		if ( !$post ) // Post_ID not found
	  		return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );

		if ( $post_ID == url_to_postid($pagelinkedfrom) )
			return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) );

		// Check if pings are on
		if ( !pings_open($post) )
	  		return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.' ) );

		// Let's check that the remote site didn't already pingback this entry
		if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
			return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) );

		// very stupid, but gives time to the 'from' server to publish !
		sleep(1);

		$remote_ip = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] );

		$user_agent = classicpress_user_agent();

		// Let's check the remote site
		$http_api_args = array(
			'timeout' => 10,
			'redirection' => 0,
			'limit_response_size' => 153600, // 150 KB
			'user-agent' => "$user_agent; verifying pingback from $remote_ip",
			'headers' => array(
				'X-Pingback-Forwarded-For' => $remote_ip,
			),
		);

		$request = wp_safe_remote_get( $pagelinkedfrom, $http_api_args );
		$remote_source = $remote_source_original = wp_remote_retrieve_body( $request );

		if ( ! $remote_source ) {
			return $this->pingback_error( 16, __( 'The source URL does not exist.' ) );
		}

		/**
		 * Filters the pingback remote source.
		 *
		 * @since WP-2.5.0
		 *
		 * @param string $remote_source Response source for the page linked from.
		 * @param string $pagelinkedto  URL of the page linked to.
		 */
		$remote_source = apply_filters( 'pre_remote_source', $remote_source, $pagelinkedto );

		// Work around bug in strip_tags():
		$remote_source = str_replace( '<!DOC', '<DOC', $remote_source );
		$remote_source = preg_replace( '/[\r\n\t ]+/', ' ', $remote_source ); // normalize spaces
		$remote_source = preg_replace( "/<\/*(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $remote_source );

		preg_match( '|<title>([^<]*?)</title>|is', $remote_source, $matchtitle );
		$title = isset( $matchtitle[1] ) ? $matchtitle[1] : '';
		if ( empty( $title ) ) {
			return $this->pingback_error( 32, __( 'We cannot find a title on that page.' ) );
		}

		$remote_source = strip_tags( $remote_source, '<a>' ); // just keep the tag we need

		$p = explode( "\n\n", $remote_source );

		$preg_target = preg_quote($pagelinkedto, '|');

		foreach ( $p as $para ) {
			if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
				preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);

				// If the URL isn't in a link context, keep looking
				if ( empty($context) )
					continue;

				// We're going to use this fake tag to mark the context in a bit
				// the marker is needed in case the link text appears more than once in the paragraph
				$excerpt = preg_replace('|\</?wpcontext\>|', '', $para);

				// prevent really long link text
				if ( strlen($context[1]) > 100 )
					$context[1] = substr($context[1], 0, 100) . '&#8230;';

				$marker = '<wpcontext>'.$context[1].'</wpcontext>';    // set up our marker
				$excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
				$excerpt = strip_tags($excerpt, '<wpcontext>');        // strip all tags but our context marker
				$excerpt = trim($excerpt);
				$preg_marker = preg_quote($marker, '|');
				$excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
				$excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
				break;
			}
		}

		if ( empty($context) ) // Link to target not found
			return $this->pingback_error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) );

		$pagelinkedfrom = str_replace('&', '&amp;', $pagelinkedfrom);

		$context = '[&#8230;] ' . esc_html( $excerpt ) . ' [&#8230;]';
		$pagelinkedfrom = $this->escape( $pagelinkedfrom );

		$comment_post_ID = (int) $post_ID;
		$comment_author = $title;
		$comment_author_email = '';
		$this->escape($comment_author);
		$comment_author_url = $pagelinkedfrom;
		$comment_content = $context;
		$this->escape($comment_content);
		$comment_type = 'pingback';

		$commentdata = compact(
			'comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email',
			'comment_content', 'comment_type', 'remote_source', 'remote_source_original'
		);

		$comment_ID = wp_new_comment($commentdata);

		if ( is_wp_error( $comment_ID ) ) {
			return $this->pingback_error( 0, $comment_ID->get_error_message() );
		}

		/**
		 * Fires after a post pingback has been sent.
		 *
		 * @since WP-0.71
		 *
		 * @param int $comment_ID Comment ID.
		 */
		do_action( 'pingback_post', $comment_ID );

		/* translators: 1: URL of the page linked from, 2: URL of the page linked to */
		return sprintf( __( 'Pingback from %1$s to %2$s registered. Keep the web talking! :-)' ), $pagelinkedfrom, $pagelinkedto );
	}


Changelog

Changelog
Version Description
WP-1.5.0 Introduced.