=== TurtleReport ===
Contributors: hellokhoyer
Tags: search console, google analytics, seo report, client reporting, white label
Requires at least: 6.3
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

White-label SEO reports and client monitoring for agencies: Search Console and GA4 leads per client, branded PDFs and scheduled emails.

== Description ==

TurtleReport brings Google Search Console, GA4 and Google Business Profile reporting into WordPress. Build reports for your clients, add your branding, schedule PDF emails and give each client access to their own reports. It uses your own Google Cloud credentials and adds no tracking to your public pages.

**Reports and comparisons**

* Search Console clicks, impressions, CTR and average position, with pages, search queries, ranking changes, opportunities, countries and devices.
* GA4 conversions grouped under labels you choose, plus the landing pages that brought those leads or sales. Choose your own events or start with a business preset.
* Traffic from AI assistants, website traffic metrics and optional Business Profile calls, website clicks, direction requests and views.
* Brand/non-brand, intent, page-type and custom segments, including inverse segments and side-by-side comparisons.
* Last 7 days, 28 days, 3 months, 6 months or custom dates, compared with the previous period.

Choose the sections and metrics for each client. Disabled sections are not fetched. Genuine zeros and organically unavailable sections remain valid results; authentication, permission, transport and malformed-response failures remain errors.

**Client Monitor**

The daily monitor highlights meaningful drops in search clicks, rankings, important pages, leads and conversion tracking. Each issue shows the dates, before/after numbers, supporting evidence and practical checks. Related page and query changes are grouped together rather than producing duplicate alerts.

Set client goals, important pages and priority conversion events to put the most relevant issues first. Mark issues as handled, snooze them for seven days or restore them. Issues resolve when the numbers recover; source failures preserve earlier alerts. Choose standard sensitivity or only large drops.

Optionally share an issue to Slack with a note, or copy a message to send yourself. A weekly summary email can list the clients needing attention and the top priorities. These features use the Client Monitor's stored evidence.

**Optional AI Advisor**

Bring your own OpenAI, Anthropic Claude, Google Gemini or xAI Grok key. The Advisor is off by default. Managers can ask about one client, all clients they may access, or a specific issue. Answers use connected report and monitor data, identify sources and dates, and distinguish observations from possible causes and missing information.

Each provider has its own encrypted server-side key. Choose a suggested model or load models available to your key, and set daily/monthly question limits and answer length. The Advisor is read-only. Slack drafts require a person to review and send them. Chats stay in page memory and disappear when the page is left or reloaded; they are not saved in WordPress or browser storage.

**Delivery, branding and access**

Use your logo, brand colour, client logo and footer on reports, PDFs and emails. Public report credits are off unless you explicitly opt in.

Schedule client reports, attach a server-generated PDF and optionally include an expiring signed download link. Delivery history records each client-report recipient, retries failed sends and protects accepted recipients from duplicate sends. Mail-system acceptance is not proof of inbox delivery. Review reports before sending or hold explicit data-fetch failures for attention.

Managers configure connections, clients and access. Clients and other viewers see only the report sites granted to their account or role. Each source may use a different Google connection. Settings, connection checks and the built-in setup guide help you configure Google OAuth or a service account, scheduling and optional integrations.

See the external-service and library sections below for transmitted data, service terms and source/licence details. Google requests run only for configured sources; AI and Slack require their own configuration and explicit use. Reports, PDFs and emails use the same reporting data and periods.

== Installation ==

1. Upload the `turtlereport` folder to `/wp-content/plugins/`, or install it from Plugins → Add New.
2. Activate it.
3. Open **TurtleReport → Setup guide** and follow it to create Google credentials (about 15 minutes the first time).
4. Add a connection under **TurtleReport → Connections**.
5. Add a site under **TurtleReport → Sites & access**, choose what it collects, and choose who can see it.

Google sign-in needs your admin to run on HTTPS. Service-account keys work without it.

== Frequently Asked Questions ==

= I used this plugin when it was called Turtlelytics. What do I do? =

Install and activate TurtleReport first, then delete Turtlelytics. On activation TurtleReport switches Turtlelytics off and moves everything over on each site: settings, sites, Google connections, schedules, recipients, delivery history, viewer access and display preferences. Saved secrets stay readable, the OAuth redirect URI already registered in Google Cloud keeps working, and secure report links you already sent stay valid until they expire. Don't delete Turtlelytics before TurtleReport has been activated: deleting it removes its data.

= Does this add tracking to my website? =

No. TurtleReport reads data you already collect in Google's products. It adds nothing to your public pages and collects nothing from visitors.

= Which connection type should I use? =

Google sign-in is quickest if your Google account already has access to the properties, and it's the only option that supports Business Profile. A service-account key never expires and doesn't depend on a person's account, which suits agencies; you add its email as a user in each Search Console and GA4 property.

= The Search Console or GA4 list on "Add site" only shows "None". =

Read the message under the list. "Can't see any yet" means the Google account on that connection (its email is shown on the Connections screen) has no access to any property: sign in with the account that owns them, or add it as a user in Search Console or GA4. A permission message means a box was left unticked on Google's consent screen, so sign in with Google again and tick every box. If an "API is not enabled" message appears, enable that API in your Cloud project. Then click "Reload lists from Google".

= My Google sign-in stops working after a week. =

Your OAuth app is still in "Testing", where Google expires sign-ins after 7 days. In Google Cloud, open Google Auth Platform → Audience and click Publish app, then reconnect.

= Business Profile says it's waiting for approval. =

Google keeps the Business Profile APIs closed until it approves your Cloud project. Apply with Google's form and choose "Application for Basic API Access". The setup guide has the details.

= Can a client see another client's report? =

No. Unless they're an administrator, a user sees only the sites granted to them or their role. The REST API checks this for every request.

= Why do numbers differ slightly from Google's own screens? =

Search Console runs about two days behind and hides rare queries. Conversion counts follow the channel setting chosen for each site. Reports are cached for up to three hours (a day for older periods); "Refresh data" fetches fresh numbers.

= What happens to my data if I delete the plugin? =

Deleting the plugin revokes Google sign-ins where possible and removes all connections, credentials, sites, access grants, cached data and the Report viewer role.

= Who receives scheduled emails? =

You choose per site, under "Scheduled email report → Send to": everyone who can view that site (the users and roles granted it, so new clients are included automatically and removed ones stop receiving it), specific WordPress users, and other addresses. Administrators only receive it if you add them. Each person gets their own email, so recipients never see each other's addresses.

= Do scheduled emails need anything special? =

They use WP-Cron, which runs when your site gets visits, so on a quiet site a report can go out late (never twice: if several sends were missed, only the latest is sent). For on-time delivery, add a server cron job that calls `wp-cron.php` every 15 minutes and set `DISABLE_WP_CRON` to `true` in wp-config.php. TurtleReport → Settings shows when background jobs last ran and the exact command. An SMTP plugin is recommended so emails don't land in spam.

"Accepted by the mail system" means WordPress handed the email to your mail server without an error. It can't confirm the email reached the inbox; your SMTP or mail provider's logs can.

= How can I check the weekly founder summary? =

Settings → Client Monitor shows the last scheduled summary attempt and whether WordPress accepted, rejected or partly accepted its messages. An interrupted attempt has an unknown outcome; check your mail provider before sending a test. Scheduled summary attempts are claimed before sending and are not retried automatically, to avoid duplicate mail. A test send is separate and does not replace the recorded scheduled outcome.

= Can I attach the PDF to scheduled emails? =

Yes. Scheduled reports can attach a PDF made on your server, with headline numbers, highlights, a trend chart, conversions and top pages. Choose "Attach a two-page PDF of the report" in the site's email settings. Existing sites keep their saved delivery choices. The "Download PDF" button on the report screen makes the full, longer PDF in the browser.

You can also add a secure link to the PDF (valid 1–90 days) for recipients without a login. Links are signed for one site and one report, stop working when they expire, and can all be cancelled with "Revoke every link sent so far for this site".

= What happens to a report when Google data is missing? =

Each scheduled report is checked before sending. If a part failed (for example an expired sign-in), the report is held and administrators are emailed with the reason and a link to the Deliveries screen, or, if you chose "Send it anyway, with a clear warning", it goes out with a short note explaining what is missing. Genuine zero results and organically unavailable sections are not errors by themselves. Existing sites keep their saved delivery choices.

= How do brand and non-brand segments work? =

Add the "Brand searches" segment and enter your brand names. Choose "Brand" or "Not Brand" on the report. Google hides very rare queries for privacy, so the two add up to slightly less than total clicks.

= How does the Client Monitor decide a client needs attention? =

Once a day it compares each client's last 28 days with the 28 days before, using the same Search Console and GA4 data as the reports. A client is flagged when Google clicks fall 20% or more (with at least 100 clicks before), leads fall 25% or more (with at least 10 before), an important page (a top page by clicks, or one that brought leads) loses 30% or more of its clicks, keywords that brought clicks drop 3 or more places (at least three of them, or 30+ clicks lost), or a conversion event records nothing for 7 days after a steady month while visitors keep arriving. "Only big drops" in Settings raises these thresholds. An alert clears by itself once the numbers recover past a lower level, so it doesn't flicker on and off.

= Does the Client Monitor use AI or send data anywhere? =

The Client Monitor itself doesn't use AI: its checks and "what to check" lists are fixed rules applied to your own numbers, on your server. Nothing leaves your site unless you press "Send to Slack", which posts that one issue to the Slack webhook you saved, or you use the optional AI Advisor.

= What does the AI Advisor send to the AI provider, and what does it cost? =

It's off until an administrator switches it on and saves their own API key for the provider they pick (OpenAI, Anthropic Claude, Google Gemini or xAI Grok), and it only sends anything when someone asks a question. Then it sends the question, the earlier questions and answers in that conversation, and for the clients it's about: their name and website, Search Console, GA4 and Business Profile totals for the dates asked, the pages and keywords that changed most, and their Client Monitor issues. It never sends email addresses, user names, Google account details, tokens or keys. Requests are made from your server, only to the provider you picked (OpenAI requests use "store" switched off). Questions are billed to your account with that provider; a question typically uses 2,000 to 8,000 tokens. Settings → AI Advisor shows this month's usage and lets you limit questions per day and per month.

= Can the AI Advisor change anything? =

No. It only reads report data and writes answers. Slack drafts are put into the issue's Slack box for you to review, edit and send yourself.

= Can I keep the encryption key out of the database? =

Yes. Define `TURTLEREPORT_ENCRYPTION_KEY` in wp-config.php before adding connections. By default the key is derived from your site's security salts, so changing those means reconnecting.

== External services ==

This plugin connects to Google's APIs to read reporting data. It only contacts Google after an administrator adds a connection, and only to read data for the sites and sections they set up. Requests are made from your server; nothing is sent to the plugin author or any other party.

* **Google OAuth 2.0** (accounts.google.com, oauth2.googleapis.com) – signs in to Google, refreshes and revokes access, and exchanges service-account keys for access tokens. Sent: your OAuth client ID and secret or a signed service-account assertion, and authorisation codes or tokens.
* **Google Search Console API** (www.googleapis.com/webmasters/v3) – lists your properties and reads search performance. Sent: the property and date range.
* **Google Analytics Data API and Admin API** (analyticsdata.googleapis.com, analyticsadmin.googleapis.com) – lists GA4 properties and reads event, traffic and channel reports. Sent: the property, date range, metrics and filters.
* **Google Business Profile APIs** (mybusinessaccountmanagement.googleapis.com, mybusinessbusinessinformation.googleapis.com, businessprofileperformance.googleapis.com) – lists locations and reads daily performance metrics. Sent: the location and date range. Only used if you turn Business Profile on.

* **Slack incoming webhooks** (hooks.slack.com) – only if an administrator saves a Slack webhook in Settings → Client Monitor, and only when someone presses "Send to Slack" or "Send a test message". Sent: the client's name, the issue's title, the affected address, its key numbers, what the data suggests, the recommended checks, the optional note, the name of the person sharing it and a link to the report in your WordPress admin. Slack's [Terms of Service](https://slack.com/terms-of-service) and [Privacy Policy](https://slack.com/trust/privacy/privacy-policy) apply.

* **AI providers** – configured by an administrator in Settings → AI Advisor with a provider and that provider's API key. Client data is sent only while the Advisor is switched on and a manager asks a question. "Test the connection" sends a generic connection-test prompt, and "Load my models" requests model names; these setup actions can run while the Advisor is switched off. Each request goes to the chosen provider:
  * **OpenAI** (api.openai.com/v1/responses, /v1/models) – OpenAI's [Terms of Use](https://openai.com/policies/terms-of-use) and [Privacy Policy](https://openai.com/policies/privacy-policy) apply.
  * **Anthropic Claude** (api.anthropic.com/v1/messages, /v1/models) – Anthropic's [Commercial Terms](https://www.anthropic.com/legal/commercial-terms) and [Privacy Policy](https://www.anthropic.com/legal/privacy) apply.
  * **Google Gemini** (generativelanguage.googleapis.com/v1beta/models) – the [Gemini API Additional Terms of Service](https://ai.google.dev/gemini-api/terms) and Google's [Privacy Policy](https://policies.google.com/privacy) apply.
  * **xAI Grok** (api.x.ai/v1/chat/completions, /v1/models) – xAI's [Terms of Service](https://x.ai/legal/terms-of-service) and [Privacy Policy](https://x.ai/legal/privacy-policy) apply.

  Sent: your API key (as an authorisation header), the question and earlier turns of that conversation, and for the clients it's about their name, website, Search Console, GA4 and Business Profile numbers for the dates asked, the pages and keywords that changed most, and their Client Monitor issues. WordPress account names, report-recipient email addresses and Google credentials are not included. Search queries, page addresses and other client report content may themselves contain personal data; review your client data and the provider's terms before enabling the Advisor. Listing models sends only the API key.

Background jobs (daily connection checks, overnight report loading, the Client Monitor's daily check and scheduled emails) make the same kinds of Google requests from your server. Scheduled emails are sent through your site's own mail setup (`wp_mail`) to the addresses an administrator enters.

Google's [Terms of Service](https://policies.google.com/terms), [Privacy Policy](https://policies.google.com/privacy) and [API Services User Data Policy](https://developers.google.com/terms/api-services-user-data-policy) apply.

== Third-party libraries ==

Bundled in `assets/vendor/` (all MIT licensed, licences in `assets/vendor/licenses/`):

* Chart.js 4.5.1 – source/build tools: https://github.com/chartjs/Chart.js/tree/v4.5.1 (package.json and rollup.config.js).
* jsPDF 4.2.1 – source/build tools: https://github.com/parallax/jsPDF/tree/v4.2.1 (package.json and rollup.config.js).
* html2canvas 1.4.1 – source/build tools: https://github.com/niklasvh/html2canvas/tree/v1.4.1 (package.json and rollup.config.js).

These vendor JavaScript files correspond to the versions' official npm distributions. Chart.js and jsPDF omit only the trailing source-map comment and trailing blank lines; their executable content is unchanged. html2canvas matches its distribution byte for byte. Their build commands and dependency versions are provided in each pinned repository's package.json.

First-party administrative JavaScript is built with Vite from the feature modules in `resources/admin/src/`. Development source, locked dependencies and reproduction instructions (`BUILD.txt`) are maintained at https://github.com/hellokhoyer/turtlereport . Use the source revision matching the plugin release. Run `npm ci`, `npm run check`, `npm test` and `npm run build`; the build manifest declares WordPress script dependencies. React, WordPress Element, API Fetch, i18n and URL utilities are supplied by WordPress and are not bundled. Core's REST authentication and the native PHP forms remain authoritative.

PHP class loading uses Composer's generated production autoloader. Its MIT licence is included at `vendor/composer/LICENSE`; Composer source is available at https://github.com/composer/composer . The plugin does not include its development Composer dependencies.

The jsPDF and html2canvas files load only when someone downloads a PDF.

Font in `assets/fonts/`: Inter 4.001 (variable, Latin and Latin Extended), recorded source commit https://github.com/rsms/inter/tree/66647c0bbbe41a850d79d9c76fb13add3378940f – SIL Open Font License 1.1, licence in `assets/fonts/OFL.txt`. The pinned repository includes font source and build tools. It is served from your own site; no font is loaded from Google. `assets/fonts/pdf/` holds the static Regular and SemiBold Inter files used to draw emailed PDFs on the server (same licence, `assets/fonts/pdf/OFL.txt`).

The server-side PDF is written by the plugin's own code (`src/Pdf/`); no PDF library or external service is used.

Each report can be emailed to up to 50 unique addresses. Viewer recipients are considered first, then individually chosen users, then typed addresses; duplicate addresses count once. This mail-processing limit does not restrict report access or grant revocation. Credits on PDFs and emails are off unless you explicitly choose to show them in Settings.

== Screenshots ==

1. A client report with Search Console and GA4 headline numbers, trends and conversions.
2. Client Monitor: clients with issues that need attention.
3. An open issue: what changed, what the data suggests, the recommended checks and the Slack message.
4. A white-labelled PDF report.
5. A scheduled report email as the client receives it.
6. Leads by GA4 event and landing page.
7. AI assistant traffic, with pages gaining and losing clicks.
8. Brand and non-brand report segments.
9. A client's report access on desktop and phone.
10. Email delivery history and recipient status.
11. Choosing which GA4 events count as leads.
12. A separate Google account for each data source.
13. Brand and white-label settings.
14. Google connection health checks.
15. Dark theme.

== Changelog ==

= 1.2.0 =
* Add daily Client Monitor checks, evidence-based alerts, handling and snooze controls, and client goals and priorities.
* Add optional Slack sharing and a weekly client-monitor summary email.
* Add an optional AI Advisor using your own OpenAI, Anthropic, Gemini or xAI key, with client-scoped context and usage limits.
* Improve report summaries, comparisons, navigation and setup guidance.
* Respect the WordPress menu preference and show scheduled weekly summary outcomes.
* Turning secure report links off and on again now invalidates links sent earlier.
* People left without a role on a site no longer receive its scheduled reports.
* Keep scheduled emails and summaries on time across daylight-saving changes.
* Preserve the 1.0 security, delivery, privacy and data-storage safeguards.

= 1.0 =
* First release of TurtleReport.
* Search Console, GA4 and Google Business Profile reports, PDF exports, scheduled emails, delivery review and per-site access control.

== Upgrade Notice ==

= 1.2.0 =
Adds Client Monitor, optional Slack sharing, weekly summaries and AI Advisor. Existing reports, connections and access grants are preserved. AI requests require your own provider key and explicit use.
