=== Comnive ===
Contributors: thegreatsage
Tags: monitoring, security, change detection, ssl, maintenance
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 0.2.7
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Know when your site changed. Comnive watches your pages and emails you when something changed that you didn't change.

== Description ==

Comnive watches a WordPress site and tells the owner when something changed that they did not change: injected scripts, unexpected iframes, new external domains, altered titles and meta tags, redirects, broken pages, stale content, and expiring certificates and renewals.

It is built for agencies that manage many client sites and for owners who rarely log in.

**What it does**

* **Source monitor** – fetches your homepage and up to 25 pages on a schedule, normalizes the HTML (nonces, timestamps, asset versions and other per-load noise are stripped), hashes it and compares it with the previous snapshot. Every change is classified, most severe first: script injected, iframe injected, external domain added, meta changed, redirect, structure changed, content changed, minor. You get a line-level diff.
* **Owner edits are not alerts** – changes made by a logged-in user within the last hour (configurable) are recorded as *owner edit* and auto-acknowledged. Injected scripts, iframes, new domains and redirects always alert.
* **Stale content monitor** – weekly list of published items not updated in over a year (configurable), with a review link.
* **Expiry monitor** – reads your TLS certificate automatically and reminds you 30, 14, 7, 3 and 1 days before it expires. Add your domain renewal date and up to ten other renewals (hosting, licenses) for the same reminders.
* **Notifications** – immediate HTML email (with plain-text part) for events at or above a severity you choose, with a personal one-click acknowledge link; optional webhook with Slack and Discord formatting; weekly digest.
* **Events screen** – filter by severity, type, status and URL; view diffs; acknowledge one, many or all; approve external domains you trust.

**What it is not**

Comnive is not an uptime pinger, not a backup tool and not a file scanner. It looks at what your visitors see.

**Free and private**

No accounts, no tracking, no data leaves your site except the emails and webhooks you configure.

== Installation ==

1. Upload the `comnive` folder to `/wp-content/plugins/` or install it from the Plugins screen.
2. Activate the plugin. Comnive starts watching your homepage and up to five pages from your primary menu (or your five most recent pages).
3. Open **Comnive → Settings** to set recipients, the scan schedule and the minimum severity for immediate alerts.
4. Optionally click **Run scan now** on the Comnive dashboard. The first scan stores a baseline; changes are reported from the second scan on.

Scans run through WP-Cron. If your site has little traffic, consider a real cron job that calls `wp-cron.php` every few minutes, or use WP-CLI: `wp cron event run comnive_scan`.

== Frequently Asked Questions ==

= I use a caching plugin. Does Comnive see the cached page or the live one? =

Comnive appends `?comnive_scan=1` to every fetch and sends `Cache-Control: no-cache`, so most page caches serve a fresh copy. That means Comnive sees the live page, which can differ from what a cached visitor sees for a while. If you would rather monitor exactly what visitors get, return an empty string from the `comnive_scan_query_arg` filter.

= I get alerts for changes that are not real changes. =

Comnive already strips nonces, timestamps, asset versions, hashed filenames, Jetpack stats, WooCommerce cart fragments, Elementor and Divi runtime IDs, analytics and reCAPTCHA tokens, comments and whitespace. For anything else, open **Watched URLs → Ignore selectors** on the affected URL and list the CSS selectors of the dynamic parts (a live ticker, a "recent comments" widget, an ad slot). Developers can add regex rules with the `comnive_normalize_patterns` filter.

= What counts as an "external domain"? =

Any hostname other than your site's host and its subdomains that appears in a `src`, `href`, `action` or similar attribute. Domains present on the first scan are treated as known. When a new one appears you get an alert and can approve it from the event; approved domains never alert again.

= Emails are not arriving. =

Comnive uses `wp_mail()`, so it depends on your site's mail setup. Test with any SMTP plugin's test button. Also check the minimum severity setting: events below it go to the weekly digest instead of an immediate email. Immediate emails are also limited to one per URL every 6 hours (configurable); a more severe event always goes through. Turn on the debug log under Settings → Advanced to see what was sent or suppressed.

= Does it work on multisite? =

Yes, per site. You can network-activate it; every site keeps its own watch list, events and settings and scans itself. New sites created after network activation are set up automatically. There is no network-wide dashboard in the free version.

= Why do I have to enter the domain expiry date by hand? =

WHOIS lookups are rate-limited, often blocked on shared hosting and increasingly redacted, so automatic detection would be unreliable and would fail silently. Copy the date from your registrar once; Comnive reminds you 30, 14, 7, 3 and 1 days ahead.

= Does scanning slow down my site? =

No scanning happens on frontend page loads. Fetches run from WP-Cron in batches of five URLs with a 20-second budget per run, or when you click Run scan now. The only frontend work is a tiny header tweak that tells caches not to store the scan request.

= What is stored, and how much? =

Up to 5 compressed snapshots per URL (configurable), the event log with diffs, and the list of external domains seen. Nothing is stored in `wp_options` except settings and small run logs. Deleting the plugin removes everything unless you turn on "Keep data on uninstall".

= What does Acknowledge do? =

It closes the event. The most recent snapshot is always the baseline, so once a change has been seen it will not be reported again; acknowledging simply marks that you looked at it. Approving a domain acknowledges the event that surfaced it.

= Can I add pages from another site? =

No. Only URLs on this site can be watched. Agencies install Comnive on each client site.

= Which URLs are watched by default? =

The homepage plus up to five pages from your primary navigation menu, topped up with the most recently published pages. Change the list under **Comnive → Watched URLs** (25 URLs maximum; developers can raise it with `comnive_max_urls`).

== Screenshots ==

1. Dashboard: status, open events by severity, upcoming expiries, recent events.
2. Events list with severity badges, filters and bulk acknowledge.
3. Event detail with the colored diff of normalized HTML.
4. Watched URLs with per-URL ignore selectors.
5. Renewals: SSL certificate, domain date, custom reminders.
6. Settings.
7. Alert email with one-click acknowledge.
8. Weekly digest email.

== Changelog ==

= 0.2.7 =
* Fixed: when a page changed after going unchanged for longer than the snapshot age limit (or with retention set to 1), pruning deleted the snapshot the change had just been compared with, leaving nothing to compare. The two newest snapshots of a URL are now always kept, whatever their age or the retention setting. Alert emails and the diff stored on each event were not affected.

= 0.2.6 =
* Fixed: a page that redirects to a login screen logged a new event on every scan. Repeats of the same problem on the same URL now count up on one event instead of adding rows, and only the first one emails. The list shows "x3" with the time it was last seen. Separate content edits stay separate events.
* Fixed: the dashboard counted only active URLs while the quota counted all of them, so "Watching 5 URLs" sat next to "6 of 25 URLs used". Everything now counts the same way and the dashboard says how many are paused.
* Fixed: pausing a URL left its open events with no way to resolve them. They are now held while the URL is paused, shown under their own status, and reopened when it is resumed. Existing installs are corrected on update.
* Added: a page that changes on every scan now gets one "changes on every scan" notice suggesting an ignore selector or pausing, instead of an event every time. Further content events for that URL wait until you acknowledge the notice.

= 0.2.5 =
* Changed: readme tags and plugin header description aligned for the WordPress.org listing. No code changes.

= 0.2.4 =
* Fixed: uninstall removed every option starting with `comnive_`, including options owned by add-ons such as Comnive Pro. It now deletes only the options and transients the free plugin writes.

= 0.2.3 =
* Added: `comnive_event_detail` action on the event detail screen and `Comnive_Snapshot::list_for_url()` for add-ons (Comnive Pro's snapshot diff viewer and change correlation display).

= 0.2.2 =
* Added: `comnive_event_types` filter so add-ons can register event types with a severity and label (Comnive Pro records site activity as events).

= 0.2.1 =
* Fixed: a `comnive_urls_due` filter that skipped URLs ahead of a due one in scan order could leave a run open forever. Candidates are now filtered before the batch is cut.
* Fixed: a `comnive_event_summary` filter broke repeat collapsing because the lookup used the unfiltered summary. The filter now runs exactly once and both use the same text.

= 0.2.0 =
* Added: extension hooks for add-ons: `comnive_digest_sections`, `comnive_email_branding`, `comnive_event_summary`, `comnive_register_cli_commands`, `comnive_admin_submenus`, `comnive_urls_due`, `comnive_event_retention_days`, `comnive_snapshot_max_age_days`, and `Comnive_Differ::diff_snapshots()`.
* Added: acknowledged events older than 30 days are now pruned during the weekly run (filterable, 0 disables).
* Added: alert and digest emails accept a From name and address, a logo, and footer text through the branding filter. Output is unchanged unless a filter sets them.
* Fixed: the dashboard said "Running now…" indefinitely when a scan was overdue but WP-Cron had not fired. It now shows "Overdue — waiting for cron" and the scan lock expires after 5 minutes.

= 0.1.1 =
* Fixed: a page that always redirected (for example a login-gated page) raised a "redirect" event on every scan. Redirect events now fire only when the destination changes compared with the baseline.
* Fixed: repeated redirect, metadata and structure changes created duplicate events. They now collapse into the existing open event with an occurrence count, like HTTP errors.
* Added: the Watched URLs screen warns when a URL redirects to a login page and offers to pause it.

= 0.1.0 =
* Initial release: source monitor with normalizer, differ and classifier; stale content monitor; SSL/domain/renewal expiry monitor; email, webhook and weekly digest notifications; admin dashboard, events, watched URLs, renewals and settings screens; dashboard widget.

== Upgrade Notice ==

= 0.2.7 =
Stops pruning from deleting the snapshot the latest change was compared with. No database update.

= 0.2.6 =
Fixes duplicate events, the URL count mismatch and events stranded on paused URLs. Updates the database on first load.

= 0.2.5 =
Listing metadata only. No behaviour change.

= 0.2.4 =
Uninstall no longer deletes add-on options. Recommended if you run Comnive Pro.

= 0.2.3 =
Small add-on hooks for Comnive Pro. No behaviour change on its own.

= 0.2.2 =
Adds the event-type registration hook Comnive Pro needs. No behaviour change on its own.

= 0.2.1 =
Fixes two edge cases in the new add-on hooks. Comnive Pro requires 0.2.1.

= 0.2.0 =
Adds the hooks Comnive Pro builds on. Note: the first weekly run after upgrading deletes acknowledged events older than 30 days (set the comnive_event_retention_days filter to 0 to keep them).

= 0.1.1 =
Fixes repeated redirect alerts on login-gated pages. No settings or database changes.

= 0.1.0 =
First release.
