=== Grovik Publisher ===
Contributors: mikkelholmnielsen
Tags: seo, ai, publishing, automation, content
Requires at least: 5.3
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 2.3.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Connect your site to Grovik and let it research, write and publish SEO articles for you. Requires a Grovik account.

== Description ==

Grovik Publisher is the bridge between your WordPress site and Grovik — an
SEO content service that decides what to write about, writes it, and puts it
live here on a schedule you set.

**This plugin does not generate content by itself.** It is the publishing end
of a service that does the work before an article ever reaches your site:

* **Keyword research against real search data.** Grovik pulls actual monthly
  search volumes and competition figures, then picks the topics worth writing
  about for your site specifically — not a generic list.
* **Articles written in your site's own voice.** Grovik reads your existing
  content first and builds a profile of how you write, so new articles sound
  like the rest of your site instead of like a text generator.
* **Internal links that fit.** Every article is linked to the pages you
  already have, using the anchor text that makes sense — the part of SEO
  content that is normally left undone.
* **A publishing schedule, not a queue you babysit.** You decide the cadence;
  Grovik fills the calendar and publishes on its own.
* **Featured images included.** Each article arrives with an image, which this
  plugin downloads into your own Media Library.

What the plugin adds on the WordPress side:

* A dedicated API key generated on this site, independent of WordPress's own
  Application Passwords — so it keeps working even if a security plugin such
  as Wordfence disables those.
* No WordPress username involved anywhere: just this site's URL and the key.
* A connection status panel showing whether Grovik has reached your site, when
  it last published, and how many articles it has published in total.
* A default author and category applied to every article Grovik publishes.
* One-click key rotation — generating a new key revokes the old one instantly.
* Unpublish, re-publish and delete straight from Grovik, without opening
  wp-admin. Deletes go to Trash, so they stay recoverable.

= See what your site needs first =

You do not need this plugin, or an account, to find out where your site
stands. Grovik's [free SEO audit](https://grovik.ai/audit) crawls your pages
and reports the technical, on-page and AI-search issues holding your rankings
back. No sign-up, no email, and every finding is shown in full.

= Requires an account =

Grovik Publisher is useless on its own. It does nothing until you connect it
to a Grovik account at [grovik.ai](https://grovik.ai) — the plugin has no
content generation in it, and nothing in it is unlocked by payment. Grovik is
a paid service with its own pricing and terms.

== External services ==

This plugin connects your WordPress site to **Grovik**, an external SEO
content service operated by Grovik at [grovik.ai](https://grovik.ai). **A
Grovik account is required** — without one, this plugin has nothing to connect
to and will never publish anything.

**How the connection works**

The plugin does not call Grovik. It registers REST endpoints under
`/wp-json/grovik/v1/` on your own site and waits; Grovik's servers connect
*to* your site, authenticating with the API key this plugin generates. Nothing
is transmitted anywhere when you simply install or activate the plugin, and
nothing is transmitted when you open its settings screen.

**What Grovik sends to your site**

When Grovik publishes or updates an article, it sends the article title, the
article content, a URL slug, the web address of a featured image, and that
image's alt text. When it unpublishes or deletes, it sends the WordPress post
ID of a post it previously created here.

**What your site sends back to Grovik**

Only the direct response to each of those requests: the post ID and permalink
of the article that was just saved, and — when Grovik tests the connection —
your site's name, its WordPress version, and this plugin's version. Your site
never initiates contact with Grovik and never sends visitor data, personal
data, or site analytics.

**What your site fetches from elsewhere**

The one outbound request this plugin makes is downloading the featured image
from the address Grovik supplies (Grovik's image storage), so the image
becomes a real attachment in your own Media Library rather than a hotlink.
No code, scripts, styles, fonts or images are ever loaded from an external
domain — every asset the plugin uses ships inside the plugin itself.

**What Grovik stores about your site**

You paste this site's URL and API key into your Grovik dashboard yourself, so
Grovik holds those two values in order to reach your site. Grovik also holds
the content it produced for you.

**Terms and privacy**

* [Terms of service](https://grovik.ai/terms-of-service)
* [Privacy policy](https://grovik.ai/privacy-policy)

== Installation ==

1. Upload the `grovik-publisher` folder to `/wp-content/plugins/`, or install the zip directly from Plugins → Add New → Upload Plugin.
2. Activate the plugin — you'll be redirected straight to its settings screen with a freshly generated key.
3. Copy the key and paste it into your Grovik dashboard's Publishing settings, along with this site's URL.
4. Run "Test connection" in Grovik. The status panel on the plugin's settings screen will show the connection as active.
5. Optionally set a default author and category for articles Grovik publishes.

== Frequently Asked Questions ==

= Can I check my site before installing anything? =

Yes. Grovik's [free SEO audit](https://grovik.ai/audit) is open to anyone — no
account, no email, nothing hidden. It crawls your site and lists what it
finds. Installing this plugin is a separate decision you can make afterwards.

= Do I need a Grovik account? =

Yes. The plugin is the publishing end of the Grovik service and does nothing
on its own — no account, no articles. Grovik is a paid service; see
[grovik.ai](https://grovik.ai) for pricing.

= Does this give Grovik my WordPress login? =

No. Grovik authenticates with a random API key this plugin generates, which
only works against this plugin's own `/wp-json/grovik/v1/*` endpoints and
can be revoked independently of any WordPress account at any time from
this plugin's settings screen.

= What can Grovik change on my site? =

Grovik can create blog posts, and can update or trash posts by ID. It cannot
touch pages, media attachments or custom post types — those are out of reach
of the plugin's endpoints entirely.

In practice Grovik only ever acts on the articles it published itself. But the
plugin does not enforce that: anything holding your API key can update or trash
any blog post on the site. Treat the key as what it is — full publishing access
— and regenerate it from this plugin's settings screen if you ever suspect it
has leaked.

= Is the article content filtered before it is saved? =

Yes. All incoming article HTML is run through WordPress's own
`wp_kses_post()` before it is stored, so scripts, iframes, inline event
handlers and `javascript:` URLs cannot reach your site — while the ordinary
article markup (headings, lists, tables, links, images) passes through
untouched.

= Why not WordPress's built-in Application Passwords? =

An earlier version of this plugin used them. In practice, security plugins
(Wordfence and others) can disable Application Passwords site-wide with no
obvious indication anywhere that this is why a connection fails — every
request gets rejected with the exact same generic error WordPress gives
for a wrong password. A key this plugin manages itself has no dependency
on that WordPress core feature being enabled at all.

= Does the settings screen contact Grovik? =

No. The connection status, the publish count and the timestamps are all
recorded by your own site as Grovik's requests arrive. Opening the screen
makes no outbound request at all.

= What happens if I deactivate the plugin? =

Deactivating does not revoke the existing key — it's meant for temporary
situations (a site update, debugging) where you don't want to lose the
connection. Uninstalling (fully deleting the plugin) removes the key and
all of this plugin's settings. Articles already published are left in place.

== Changelog ==

= 2.3.0 =
* New: the SEO title and meta description Grovik writes for an article are now published with it, into Yoast SEO (`_yoast_wpseo_title`, `_yoast_wpseo_metadesc`) or Rank Math (`rank_math_title`, `rank_math_description`), whichever is active. Previously they stopped at Grovik and the article arrived here with none. Editing them in Grovik and pushing the article again updates them too.
* If neither plugin is active, nothing is written: WordPress itself has no field for these, so the values would sit in the database unread. Install either plugin and republish to fill them in.
* Updating from an older version needs nothing: articles already published keep their content, and their SEO fields are filled in the next time Grovik pushes them.

= 2.2.1 =
* Security: publishing no longer signs a WordPress user in. Earlier versions called `wp_set_current_user()` around each publish and update, which made the whole request run as that user — an API key was effectively treated as proof of who was making the request. It no longer is: the routes run with no logged-in user, and the author is passed explicitly to WordPress instead. Articles are still attributed to the author chosen on the settings screen, and featured images still arrive in the Media Library owned by that same author.
* Republishing an article now keeps whichever author it currently has, so reassigning a Grovik article to another author in wp-admin sticks.
* Article content is now filtered by WordPress's own content filters as well as the plugin's `wp_kses_post()` call, a direct consequence of no longer running as an administrator. Ordinary article markup is unaffected.

= 2.2.0 =
* New: a connection status panel on the settings screen — whether Grovik has reached this site, when it last published an article, and how many it has published in total. Everything on it is recorded by this site as Grovik's own requests arrive, so opening the screen makes no outbound call.
* New: the API key is now masked by default, with a Show/Hide toggle, so it isn't exposed in screenshots or while screen-sharing. Copy still puts the real key on the clipboard in one click whether it's shown or hidden.
* Security: incoming article content is now filtered through `wp_kses_post()` before being stored. Previously it was saved verbatim, because WordPress only applies that filter for users without the `unfiltered_html` capability and this plugin publishes as an administrator. Scripts, iframes, inline event handlers and `javascript:` URLs can no longer reach the site.
* Security: featured image URLs are now validated and restricted to http/https before the image is fetched.
* The settings screen was rebuilt on WordPress's own admin components, with a service disclosure section and links to documentation and support.
* Uninstalling now also clears the per-post markers this plugin set. Published articles are left alone.
* Fixed: the minimum WordPress version is now correctly declared as 5.3 — the featured image code has always required it.

= 2.1.1 =
* Fixed: Unpublish, Delete and republishing failed on any article that was published before this site updated to 2.1.0 — the "was this post actually created by Grovik" safety check added in 2.1.0 only recognized posts tagged from that version onward, so every older post looked unrecognized and got rejected. Posts missing that tag are now recognized and tagged retroactively the first time Grovik touches them again, instead of being permanently locked out.

= 2.1.0 =
* New: `/wp-json/grovik/v1/posts/{id}` — lets Grovik unpublish (set back to draft), republish with edited content, or move to Trash a post it previously created, instead of only ever being able to create new ones. Every post Grovik creates is now tagged internally so these endpoints only ever act on posts Grovik itself made — never a post a site owner wrote by hand, even if the wrong ID were ever sent.
* Deleting from Grovik now moves the post to Trash (WordPress's own default, recoverable for the same window as deleting by hand in wp-admin), not a permanent delete.

= 2.0.0 =
* Rebuilt on a Grovik-specific API key and the plugin's own REST endpoints (`/wp-json/grovik/v1/ping`, `/wp-json/grovik/v1/publish`), replacing the previous WordPress Application Passwords-based approach entirely. No more WordPress username field, no dependency on WordPress core's Application Passwords being enabled, and no longer affected by security plugins that disable them.
* The settings screen now always shows the current key (with a Copy button), not just once immediately after generating it.
* The featured image is now downloaded and attached to the post directly by this plugin (via WordPress's own media_sideload_image()), from a single publish request — Grovik no longer needs a separate image-upload call.

= 1.0.1 =
* Fixed: the key is now generated for whichever admin activates the plugin (or clicks "Generate key"), instead of a separate, hidden "grovik" user — avoids a mismatch where the key silently belongs to a username the site owner never sees. Sites that already had a "grovik" user configured before this update keep using it.
* The settings screen now always shows the exact WordPress username the current key is bound to, with its own Copy button, so it's never a guess when connecting in Grovik.

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 2.2.1 =
Security update: publishing no longer signs a WordPress user in for the request. Articles and images are still attributed to your chosen author. Recommended for all sites.

= 2.2.0 =
Security update: article content is now filtered through wp_kses_post() before being saved. Adds a connection status panel and masks the API key on screen. Recommended for all sites.
