PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.4.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.4.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 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / abilities / analysis / class-get-integrations-status.php

class-get-integrations-status.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.4.0, at includes/abilities/analysis/class-get-integrations-status.php

193 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Get integrations status ability.
4 *
5 * @package ThinkRank\Abilities\Analysis
6 */
7
8 declare(strict_types=1);
9
10 namespace ThinkRank\Abilities\Analysis;
11
12 use ThinkRank\Abilities\Ability_Base;
13 use ThinkRank\Core\Settings;
14 use ThinkRank\Integrations\Google_PageSpeed_Client;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 /**
21 * Reports the connection status of ThinkRank's Google integrations.
22 *
23 * Covers Google Analytics (GA4), Search Console, and PageSpeed. Returns only
24 * non-sensitive status — connected/configured booleans, the public GA4
25 * measurement ID, and the selected Search Console site. It deliberately never
26 * returns API keys, OAuth access/refresh tokens, or any secret material.
27 */
28 class Get_Integrations_Status extends Ability_Base {
29 /**
30 * Constructor.
31 */
32 public function __construct() {
33 $this->id = 'thinkrank/get-integrations-status';
34 $this->label = __( 'Get Integrations Status', 'thinkrank' );
35 $this->description = __( 'Report the connection status of the Google Analytics, Search Console, and PageSpeed integrations (connected/configured flags, GA4 measurement ID, selected Search Console site). Never returns API keys or OAuth tokens.', 'thinkrank' );
36 }
37
38 /**
39 * {@inheritDoc}
40 *
41 * @return array<string, bool|float|string>
42 */
43 public function get_annotations() {
44 return [
45 'readonly' => true,
46 'destructive' => false,
47 'idempotent' => true,
48 'priority' => 1.0,
49 'openWorldHint' => false,
50 ];
51 }
52
53 /**
54 * {@inheritDoc}
55 *
56 * @return array<string, mixed>
57 */
58 public function get_input_schema() {
59 return [
60 'type' => 'object',
61 'additionalProperties' => false,
62 'properties' => self::empty_properties(),
63 ];
64 }
65
66 /**
67 * {@inheritDoc}
68 *
69 * @return array<string, mixed>
70 */
71 public function get_output_schema() {
72 return [
73 'type' => 'object',
74 'properties' => [
75 'google_account_connected' => [ 'type' => 'boolean' ],
76 'google_analytics' => [
77 'type' => 'object',
78 'additionalProperties' => true,
79 ],
80 'search_console' => [
81 'type' => 'object',
82 'additionalProperties' => true,
83 ],
84 'pagespeed' => [
85 'type' => 'object',
86 'additionalProperties' => true,
87 ],
88 ],
89 ];
90 }
91
92 /**
93 * Execute ability.
94 *
95 * @param array<string, mixed> $input Ability input payload.
96 * @return array<string, mixed>
97 */
98 public function execute( $input ) {
99 $settings = Settings::instance();
100
101 // "Configured" must mean "this integration can actually make a call",
102 // derived from the SAME conditions the client-initialization code uses.
103 //
104 // It previously keyed off three manual `*_api_key` options that no
105 // current code path writes — the OAuth connect flow stores tokens only
106 // (Google_OAuth_Proxy) and the property pickers store property ids — so
107 // an OAuth-connected site actively serving GA4/GSC/PSI data reported
108 // `configured: false` for all three while the same payload reported
109 // `google_account_connected: true`. The report contradicted itself on
110 // the one thing it exists to answer, which is worse than useless to an
111 // agent deciding whether an integration is available.
112 //
113 // The keys are retained as OR-branches: they are optional for data
114 // retrieval but still honored when present (see
115 // Google_PageSpeed_Client::for_site()).
116 $oauth_present = '' !== (string) $settings->get( 'google_access_token', '' );
117
118 // GA4: Analytics_Manager builds the Data API client only when a token
119 // AND a selected property both exist — mirror that exactly.
120 $ga_property = (string) $settings->get( 'seo_analytics_google_analytics_property_id', '' );
121 $ga_configured = ( $oauth_present && '' !== $ga_property )
122 || '' !== (string) $settings->get( 'google_analytics_api_key', '' );
123
124 // Search Console: the client authenticates with the token; the API key
125 // is passed as '' on an OAuth site. A property is not required to
126 // construct it (Analytics_Manager falls back to the site URL).
127 $sc_property = (string) $settings->get( 'search_console_property', '' );
128 $sc_configured = $oauth_present
129 || '' !== (string) $settings->get( 'google_search_console_api_key', '' );
130
131 // PageSpeed: for_site() prefers a dedicated key, else the OAuth token,
132 // else runs keyless on the per-IP quota. Report credentialed state, and
133 // read it from the same predicate the Performance tab gates on, so the
134 // two screens cannot disagree about the same site again (#519).
135 $ps_key = (string) $settings->get( 'google_pagespeed_api_key', '' );
136 $ps_configured = Google_PageSpeed_Client::site_has_credentials();
137
138 // ThinkRank's own tag-injection state (see the google_analytics block).
139 $ga4_measurement_id = (string) $settings->get( 'ga4_measurement_id', '' );
140 $ga4_verified = (bool) $settings->get( 'ga4_tracking_verified', false );
141
142 return [
143 'google_account_connected' => (bool) $settings->get( 'google_account_connected', false ),
144 'google_analytics' => [
145 'configured' => $ga_configured,
146 // The selected GA4 property, in the Admin API's
147 // "properties/XXXXXXXX" form. Empty means no property picked,
148 // which is the usual reason GA is connected but unusable.
149 'property_id' => $ga_property,
150
151 // The two fields below describe ThinkRank's OWN optional
152 // tag-injection feature — NOT whether the site has a working
153 // GA4 tag. On an OAuth-connected site that never used
154 // injection they are legitimately empty/false, and a client
155 // read that as "GA4 tracking is broken" on a site whose tag
156 // was working fine (#250). They are nested and named for what
157 // they actually are so the payload cannot be misread; the
158 // question "can ThinkRank read Analytics data?" is answered by
159 // `configured` above.
160 //
161 // Kept at the top level as well, deprecated, so an existing
162 // consumer does not break on this release.
163 'tag_injection' => [
164 'measurement_id' => $ga4_measurement_id,
165 'auto_inject_enabled' => (bool) $settings->get( 'ga4_auto_inject', false ),
166 'last_check_passed' => $ga4_verified,
167 'last_checked' => (string) $settings->get( 'ga4_last_verification', '' ),
168 ],
169
170 /** @deprecated 1.27.0 Use tag_injection.measurement_id. */
171 'measurement_id' => $ga4_measurement_id,
172 /** @deprecated 1.27.0 Use tag_injection.last_check_passed. */
173 'tracking_verified' => $ga4_verified,
174 ],
175 'search_console' => [
176 'configured' => $sc_configured,
177 // Was reading `google_search_console_site` — a key with no
178 // writer anywhere in the plugin (only two disconnect paths
179 // clear it), so this was unconditionally ''. The property
180 // picker writes `search_console_property`.
181 'site' => $sc_property,
182 ],
183 'pagespeed' => [
184 'configured' => $ps_configured,
185 'oauth_connected' => $oauth_present,
186 // Distinguishes "own key, own quota" from "shared OAuth quota"
187 // — the difference between reliable and 429-prone PSI runs.
188 'has_api_key' => '' !== $ps_key,
189 ],
190 ];
191 }
192 }
193