PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.10.0
2.10.0 2.9.0 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 All 51 releases
← All changes | includes/mcp/class-mcp-self-test.php +43 -0 2.0.2 → 2.10.0 View file →
@@ -110,8 +110,18 @@
110 110 $result['message'] = __( 'No connection token exists yet. Click Connect to mint one, then run the test again.', 'thinkrank' );
111 111 return $result;
112 112 }
113 113
114 + if ( Mcp_Pairing::state()['token_sealed'] ) {
115 + // A token exists and still authenticates the clients holding it,
116 + // but this site can no longer decrypt it, so there is nothing to
117 + // present. Probing with '' would report an authentication failure
118 + // and point support at entirely the wrong thing.
119 + $result['stage'] = 'token_sealed';
120 + $result['message'] = __( 'A connection token exists but can no longer be read on this site — the security keys in wp-config.php changed after it was minted. Clients already set up with it keep working. Use Reset token to mint one this site can show, then run the test again.', 'thinkrank' );
121 + return $result;
122 + }
123 +
114 124 $token = Mcp_Pairing::site_token();
115 125
116 126 $pretty = self::probe_jsonrpc( $endpoint, $token );
117 127 $rest = self::probe_jsonrpc( $fallback, $token );
@@ -345,8 +355,41 @@
345 355 * @return array{stage:string,detail:string}
346 356 */
347 357 private static function probe_discovery(): array {
348 358 $documents = [];
359 +
360 + // --- Published files vs. the identity this site has NOW -----------
361 + // The static /.well-known/ documents embed absolute home_url()-derived
362 + // identifiers, and the whole reason they exist is that the host serves
363 + // them before WordPress. After a domain change, an http->https switch
364 + // or a staging clone, the stale copy therefore wins over the correct
365 + // dynamic route and the site advertises an issuer it no longer owns,
366 + // which a spec-compliant client must refuse (#486).
367 + //
368 + // Checked on disk, ahead of the HTTP probes below, because loopback
369 + // does not always take the path an external client does — a site can
370 + // serve a stale document to the internet while our own request never
371 + // sees it, and every probe below then passes.
372 + $stale = Mcp_Static_Discovery::stale_document();
373 + if ( null !== $stale ) {
374 + Mcp_Static_Discovery::refresh();
375 + $still_stale = Mcp_Static_Discovery::stale_document();
376 +
377 + if ( null !== $still_stale ) {
378 + return [
379 + 'stage' => 'stale_static_discovery',
380 + 'documents' => $documents,
381 + 'detail' => sprintf(
382 + /* translators: 1: file path relative to the site root, 2: identifier name, 3: value found in the file, 4: value it should carry. */
383 + __( 'The static discovery file %1$s advertises %2$s as %3$s, but this site is %4$s. It was written before the site URL changed, the host serves it ahead of WordPress, and it could not be rewritten or removed — so clients read the old identity and refuse to connect. Delete that file from the site root, or restore write access there and run this test again.', 'thinkrank' ),
384 + $still_stale['file'],
385 + $still_stale['key'],
386 + '' === $still_stale['found'] ? __( 'nothing', 'thinkrank' ) : $still_stale['found'],
387 + $still_stale['expected']
388 + ),
389 + ];
390 + }
391 + }
349 392
350 393 // --- The documents clients are POINTED at (must work) -------------
351 394 // The 401 challenge advertises the REST-served resource metadata, and
352 395 // spec-compliant clients derive the OIDC-suffix form of the AS