id = 'thinkrank/get-integrations-status'; $this->label = __( 'Get Integrations Status', 'thinkrank' ); $this->description = __( 'Report the connection status of the Google Analytics, Search Console, and PageSpeed integrations (connected/configured flags, selected GA4 property, selected Search Console site). Never returns API keys or OAuth tokens.', 'thinkrank' ); } /** * {@inheritDoc} * * @return array */ public function get_annotations() { return [ 'readonly' => true, 'destructive' => false, 'idempotent' => true, 'priority' => 1.0, 'openWorldHint' => false, ]; } /** * {@inheritDoc} * * @return array */ public function get_input_schema() { return [ 'type' => 'object', 'additionalProperties' => false, 'properties' => self::empty_properties(), ]; } /** * {@inheritDoc} * * @return array */ public function get_output_schema() { return [ 'type' => 'object', 'properties' => [ 'google_account_connected' => [ 'type' => 'boolean' ], 'google_analytics' => [ 'type' => 'object', 'additionalProperties' => true, ], 'search_console' => [ 'type' => 'object', 'additionalProperties' => true, ], 'pagespeed' => [ 'type' => 'object', 'additionalProperties' => true, ], ], ]; } /** * Execute ability. * * @param array $input Ability input payload. * @return array */ public function execute( $input ) { $settings = Settings::instance(); // "Configured" must mean "this integration can actually make a call", // derived from the SAME conditions the client-initialization code uses. // // It previously keyed off three manual `*_api_key` options that no // current code path writes — the OAuth connect flow stores tokens only // (Google_OAuth_Proxy) and the property pickers store property ids — so // an OAuth-connected site actively serving GA4/GSC/PSI data reported // `configured: false` for all three while the same payload reported // `google_account_connected: true`. The report contradicted itself on // the one thing it exists to answer, which is worse than useless to an // agent deciding whether an integration is available. // // The keys are retained as OR-branches: they are optional for data // retrieval but still honored when present (see // Google_PageSpeed_Client::for_site()). $oauth_present = '' !== (string) $settings->get( 'google_access_token', '' ); // GA4: Analytics_Manager builds the Data API client only when a token // AND a selected property both exist — mirror that exactly. $ga_property = (string) $settings->get( 'seo_analytics_google_analytics_property_id', '' ); $ga_configured = ( $oauth_present && '' !== $ga_property ) || '' !== (string) $settings->get( 'google_analytics_api_key', '' ); // Search Console: the client authenticates with the token; the API key // is passed as '' on an OAuth site. A property is not required to // construct it (Analytics_Manager falls back to the site URL). $sc_property = (string) $settings->get( 'search_console_property', '' ); $sc_configured = $oauth_present || '' !== (string) $settings->get( 'google_search_console_api_key', '' ); // PageSpeed: for_site() prefers a dedicated key, else the OAuth token, // else runs keyless on the per-IP quota. Report credentialed state, and // read it from the same predicate the Performance tab gates on, so the // two screens cannot disagree about the same site again (#519). $ps_key = (string) $settings->get( 'google_pagespeed_api_key', '' ); $ps_configured = Google_PageSpeed_Client::site_has_credentials(); $google_analytics = [ 'configured' => $ga_configured, // The selected GA4 property, in the Admin API's // "properties/XXXXXXXX" form. Empty means no property picked, // which is the usual reason GA is connected but unusable. 'property_id' => $ga_property, ]; /** * Filters the google_analytics block of the integrations status. * * ThinkRank Pro, which installs the GA4 tag, adds its state here as * `tag_injection`. That describes the tag Pro prints, not whether the * site has a working GA4 tag (#250); `configured` answers whether * ThinkRank can read Analytics data. * * @since 2.6.0 * * @param array $google_analytics Status block. */ $filtered = apply_filters( 'thinkrank_integrations_status_google_analytics', $google_analytics ); return [ 'google_account_connected' => (bool) $settings->get( 'google_account_connected', false ), 'google_analytics' => is_array( $filtered ) ? $filtered : $google_analytics, 'search_console' => [ 'configured' => $sc_configured, // Was reading `google_search_console_site` — a key with no // writer anywhere in the plugin (only two disconnect paths // clear it), so this was unconditionally ''. The property // picker writes `search_console_property`. 'site' => $sc_property, ], 'pagespeed' => [ 'configured' => $ps_configured, 'oauth_connected' => $oauth_present, // Distinguishes "own key, own quota" from "shared OAuth quota" // — the difference between reliable and 429-prone PSI runs. 'has_api_key' => '' !== $ps_key, ], ]; } }