=== Harvify Redirect Manager ===
Contributors: jethalal
Tags: redirect, 301, 404, seo, links
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.28
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Unlimited redirect rules, a 404 monitor and one-click import from Redirection. Pro adds conditional and scheduled redirects and chain detection.

== Description ==

Harvify Redirect Manager sends visitors and search engines from old addresses to new ones, logs every 404 so you can see which links are broken, and can import the rules you already have in the Redirection plugin.

**Free features:**

- **Unlimited redirect rules**
- 301, 302, 307, 308, **410 Gone** and **451 Unavailable For Legal Reasons**
- Exact, regex, and wildcard matching
- **404 monitor** — logs every hit — with one-click redirect creation
- Import from Redirection plugin · CSV import
- Export to CSV
- Hit counter per rule · enable/disable · bulk actions
- Tag a rule with a group and filter the list by it

**Pro features (Harvify Pro Bundle):**

- **Conditional redirects** — apply a rule only for logged-in/logged-out
  visitors, specific user roles, a referrer, or a user agent
- **Group browser and bulk group assignment** — see every group in use with its
  rule count, and move many rules into a group at once
- **Scheduled redirects** — (activate and expire on specific dates)
- **Auto-redirect on slug change** — (posts, pages, WooCommerce products)
- **Redirect chain detection** — find redirects that loop
- Email alerts on 404 spikes

== Installation ==

1. In your dashboard go to Plugins → Add New, search for "Harvify Redirect Manager",
   then install and activate it (or upload the ZIP under Plugins → Add New → Upload).
2. Open **Harvify → Redirect Manager**. The first time, you are asked whether to
   share usage data with Freemius; choose **Skip** to use every free feature without
   sending anything.

= Adding a redirect =

1. On the **Redirects** tab click **Add new**.
2. Enter the **Source URL** (the old address, for example `/old-page`) and the
   **Target URL** (where visitors should go: a path such as `/new-page`, or a full
   address).
3. Choose the **Redirect type** (301 for a permanent move, 302 or 307 for a
   temporary one, 410 when the page is gone for good) and the **Match** type:
   *Exact* for one address, *Wildcard* for a pattern such as `/blog/*`, or *Regex*.
4. Optionally add **Groups** (comma-separated) and **Notes**, then click **Create**.

Use **Test** on a rule to check where it sends visitors and **Edit** to change it.
Click the **Yes**/**No** in a rule's **Enabled** column to switch that rule off or on;
**Enable all** and **Disable all** switch every rule at once.

= Other tabs and tools =

* **404 Monitor** — every address that returned "not found", with a hit count.
  **Create redirect** turns one into a rule.
* **Import from Redirection** and **Import CSV** — bring existing rules in. A CSV
  needs one rule per line: `source, target, type` (a header row is fine).
* **Export CSV** — download all your rules.
* **Insights** — your busiest redirects and most frequent 404s at a glance.

== Frequently Asked Questions ==

= Can I import from the Redirection plugin? =

Yes. Click **Import from Redirection** on the Redirects tab. Ordinary and regex
redirects are copied with their status code and whether they were enabled.
Redirection's conditional rules (login state, referrer, role and similar) and
actions that are not redirects, such as error pages, are not imported; the import
tells you how many it skipped and why. Addresses that already have a rule are
left alone, so running it twice adds nothing.

= Do redirects slow my site down? =

Rules are checked only on the front end, and only when a page is requested. The
404 monitor records a miss after WordPress has already decided the page is not
found.

== Screenshots ==

1. Your redirect rules, with a hit counter on each so you can see which ones
   matter.
2. The 404 monitor logs every miss and offers one-click redirect creation.
3. The Plan tab: everything the free tier includes, and what a licence adds.

== External services ==

This plugin connects to Freemius, the licensing and update service Harvify uses to
sell and deliver the Pro tier of its plugins.

Nothing is sent to Freemius unless you choose to send it. On activation you are shown
Freemius's standard opt-in screen. Until you answer it a fresh install makes no
outbound request at all, and if you choose Skip the free tier stays fully usable
and still sends nothing. Data is transmitted only when you take one of these
actions:

* **You click "Allow & Continue" on the Freemius opt-in screen.** This sends your
  site address, your administrator email address, and your WordPress, PHP and active
  plugin/theme details, so Harvify can provide support and know which environments to
  test against. Skipping that screen sends nothing and leaves the plugin working
  normally.
* **You enter a Pro Bundle licence key.** This sends the key together with your site
  address so the licence can be activated for that site. While a licence is active the
  site also re-checks periodically that it is still valid and whether a Pro update is
  available.

Service provided by Freemius, Inc. - https://freemius.com/
Terms of service: https://freemius.com/terms/
Privacy policy: https://freemius.com/privacy/

== Changelog ==

= 1.0.28 =

* **New: switch a single redirect off or on** by clicking the Yes/No in its
  Enabled column. Until now only "Enable all" and "Disable all" existed, so a rule
  could be deleted but not paused.
* Readme: step-by-step setup and usage instructions, and an accurate description of
  what the Redirection import brings across.

= 1.0.27 =

* **Fixed: "Import from Redirection" now imports your Redirection rules.** It
  expected a format Redirection does not use, so ordinary URL redirects were
  skipped as having no target. It now keeps each rule's status code, its regex
  setting, and whether it was enabled or disabled in Redirection.
* The import tells you what it did not bring across, and why: conditional rules
  (login state, referrer, role and similar), which would change meaning without
  their conditions; actions that are not redirects, such as error pages; and
  addresses that already have a rule here. Running it twice adds nothing.
* **Fixed: regex rules now put what they captured into the target.** A target
  such as `/new/$1` used to send visitors to a literal "/new/$1".

= 1.0.26 =

* **Fixed: rules created in the editor, imported from Redirection or made by the
  Pro slug-change redirect were saved DISABLED,** so they never redirected, and
  editing any rule disabled it. None of those paths sends an on/off value, and a
  missing value was read as "off". A new rule is now enabled unless you turn it
  off, and editing a rule keeps its on/off state. Rules already saved as disabled
  stay as they are: switch them on from the list.
* **Fixed: editing a rule no longer wipes fields the editor did not show.** A save
  from a free or lapsed screen cleared the rule's schedule dates and its groups.
  Only the fields a save actually sends are changed now.
* **Tagging a rule with a group is back in the free editor,** with the Group
  column and tags in the list, as the free feature list has said since 1.0.24.
* **Fixed: clicking a group tag in the list now filters the list to that group.**
  The tags have been links since 1.0.23, but a click only jumped to the top of
  the page. A "Show all groups" button now clears the filter in every tier.
* Changed: scheduled redirects are supplied by the separately distributed Pro
  plugin. This download no longer contains the date check, so on a free site a
  rule's stored schedule is kept but not applied, and the rule redirects whenever
  it is enabled.
* Fixed: the Plan tab listed unlimited rules, 410/451 and group tagging as Pro,
  although all three have been free since 1.0.24, and did not list conditional
  redirects. The upgrade cards no longer imply a rule limit.
* Changed: the External services section now describes the Freemius opt-in screen
  shown on activation. Until you answer it a fresh install makes no outbound
  request, and choosing Skip keeps the free tier fully usable and sends nothing.
* Internal: a loop variable in the main file is now prefixed.

= 1.0.25 =

* **The free tier is no longer capped.** The 500-rule limit is gone from rule
  creation and from CSV import. There is no upgrade prompt standing between you
  and a redirect any more.
* **410 Gone and 451 are now free.** They used to be forced down to a 301 unless
  a licence was active, even though the code that serves them shipped in every
  download.
* Changed: conditional redirects and the group browser / bulk group assignment
  are supplied by the separately distributed Pro plugin rather than being
  present-but-inactive in this download. Rules you already tagged with a group
  keep their tag, stay filterable, and are never rewritten.
* **Changed: every identifier this plugin owns has been renamed** off its old
  three-character `hrm_` prefix, which is shorter than WordPress.org accepts.
  Functions, options, cron hooks and the plugin's own actions and filters are
  now `harvify_redirect_*`; global constants are `HARVIFY_REDIRECT_*`; classes
  are `Harvify_Redirect_*`.
* **Developers: the REST namespace is now `harvify-redirect/v1`. The old
  `hrm/v1` namespace is GONE and there is no compatibility alias** — any code
  calling it will 404 until updated. Also renamed: the admin script and style
  handle `hrm-admin` is now `harvify-redirect-admin`, and the localized
  JavaScript object `hrmSettings` is now `harvifyRedirectSettings`.
* Your data is carried across for you on the first page load after updating:
  the schema marker, your uninstall-data preference, the scheduled 404-alert
  check and the slug-backup post meta all move to the new names. Your redirect
  rules and 404 log are untouched — those tables never changed.





= 1.0.23 =

* Added: a single **Support** entry in the Harvify menu, so you can reach us from
  inside WordPress. Until now no plugin offered a contact route at all. One entry for
  the whole suite rather than one per plugin.
* No behaviour changes.

= 1.0.22 =

* Added: an **External services** section to this readme, naming every third-party
  service the plugin can contact, exactly what is sent, when, and each provider's terms
  and privacy policy. Required for WordPress.org submission.
* Changed: the `Contributors` field now names the correct WordPress.org account.
* Added: the `License URI` header, which the readme was missing.
* No behaviour changes.

= 1.0.21 =

* Rebuild: the published 1.0.20 package predated the blank-source validation and was
  generated from an earlier tree. This release carries it: a redirect rule saved with no
  source URL is refused, so it can no longer match — and capture — the front page.
= 1.0.20 =
* Added: a single **Manage licence** link on the Plan screen, so an active customer can
  deactivate this site, change their licence key or re-check their licence without
  needing a URL from support. No per-plugin Account tab is added.
= 1.0.19 =
* Fixed: opting in to "delete all data on uninstall" now removes hrm_db_version.
  It was written at runtime but never included in the cleanup, so a user who
  asked for their data to be deleted kept it.
= 1.0.18 =
* **Fixed: updating the plugin did not update its database.** WordPress only runs a plugin's
  setup routine when you *activate* it, never when it updates — so a change to the plugin's own
  tables never reached sites that had simply updated. On those sites some features failed with a
  database error. The update now applies itself on the next page load.
* **Fixed: a malformed API request returned a PHP error** instead of a normal "bad request"
  response.
* **One upgrade link instead of one per plugin.** With several Harvify plugins active the
  menu showed a row called "Upgrade" for each of them, all identically labelled, and it kept
  saying Upgrade to people who had already bought. They are replaced by a single **Plan**
  screen that says what the bundle costs, what it covers, and whether your licence is active.
* **The dashboard is quiet again.** Each plugin used to add its own "opt in to make this
  better" notice to the main WordPress dashboard, so five plugins meant five notices. Harvify
  plugins now share one queue: promotional notices appear only on Harvify's own screens, and
  only one at a time. Licence and account messages are never held back.
* **Fixed: the "Data & uninstall" box covered the page.** It was being drawn into the admin
  footer, which WordPress pins to the bottom of the screen, so it floated on top of whatever was
  underneath it. It now sits in the page like any other card. Saving it also tells you what it
  saved, instead of just reloading.
* **Fixed: the upgrade screen advertised the wrong number of sites.** Several plugins listed
  the Freelancer and Agency plans as covering 5 and 25 sites. They cover 3 and 10.

= 1.0.17 =
* **Uninstall no longer destroys your data by default.** Deleting the plugin used to remove
  everything it had stored, with no way to stop it -- so deleting it to troubleshoot destroyed
  the lot. Now the default is to KEEP your data, and a new **Data & uninstall** control on the
  plugin's own screen lets you opt in to a full wipe if you actually want one. Scheduled jobs
  are always tidied up either way, and the wipe works with no internet connection.

= 1.0.16 =
* **Deleting the plugin left its two database tables behind, on every site, since 1.0.0.** The
  main plugin file used a variable named `$file` while loading its includes. WordPress runs
  `include_once` on that file from INSIDE its own `uninstall_plugin()` function, so the
  assignment overwrote WordPress's `$file` -- core then fired its uninstall action under a
  nonsense name, the cleanup callback was never reached, and `wp_harvify_redirects`,
  `wp_harvify_404_log` and the daily-alert cron survived deletion forever. The loader variable is
  now prefixed. Cleanup is verified by a committed gate that deletes the plugin with the network
  cut and then checks the tables are gone.
* **The published free ZIP failed Plugin Check even though the source passed.** Freemius's code
  preprocessor rewrites the main plugin file and drops block comments that sit inside an
  expression, which deleted a `translators:` comment and produced a MissingTranslatorsComment
  ERROR -- a rejected submission -- in the artifact nobody had ever checked. The comment now sits
  above a statement, where the rewrite preserves it.

= 1.0.15 =
* **Fixed a WordPress.org submission blocker.** Plugin Check flagged the HTTP status passed to
  wp_die() on the 410/451 terminal-response path as unescaped output -- an ERROR, which means a
  rejected submission. It is now passed through absint(), which is the honest cast for an HTTP
  status as well as the one the check accepts. No behaviour change.
* Tested up to WordPress 7.1.

= 1.0.14 =
* **Redirect groups and tags are now a real feature.** The Groups field was saved and then read
  by nothing -- there was no way to filter by it, no column showing it, nothing in the export and
  no bulk action. You can now tag a rule with one or more groups, filter the list to a group
  (click a tag to jump straight to it), sort and see the Group column, assign or clear a group
  across a selection in bulk, and the CSV export carries it. Searching also matches group names.

= 1.0.13 =
* **Fixed: choosing the 451 redirect type broke the URL.** 451 answers a request rather than
  redirecting it, and WordPress refuses any non-redirect status in a redirect -- so instead of a
  451 the visitor got a WordPress error page. 451 now returns a proper 451 with an explanatory
  page, and (per RFC 7725) a `Link: ...; rel="blocked-by"` header pointing at the rule's target.
  The dispatcher now asks "is this a redirect?" rather than "is this 410?", so no future status
  can repeat this.
* Fixed: 410 and 451 are Pro types, and the CSV importer enforced that while the add/edit form
  did not. Both roads now go through the same check.
* **Fixed: redirects to another site sent visitors to your admin screen instead.** A rule
  pointing at an external URL was being rewritten to /wp-admin/, because the redirect used
  WordPress's "safe" variant, which refuses any host but your own. Pointing at another site is a
  core reason to use a redirect plugin, so the destination you configured is now honoured -- and
  only that one: no other host is allowed, so this is not an open redirect.
* The Pro feature list mentions 451 again, now that it works.

= 1.0.12 =
* Marketing accuracy: the Pro feature list no longer advertises "451 redirect types" or
  "Redirect groups and tags". Selecting 451 does not currently return a 451 (WordPress
  refuses any non-3xx status in wp_redirect), and the Groups field is stored but nothing
  filters, lists or exports by it yet. Both remain on the roadmap; the copy will return
  with the features.

= 1.0.11 =
* Your licence is now manageable from the plugin itself. The Account screen was previously
  hidden, which also hid **Deactivate License** — so a licence could not be released from one
  site to move it to another without contacting support. It is visible again, along with the
  licence key, plan, Sync and Change License.
* **Harvify → Tools** now opens with a **Your licences** table: every installed Harvify plugin,
  the plan it is on, whether Pro features are actually running, and a link to its Account screen.
  Freemius gives each product its own separate Account page, so this is the one place that
  answers "what am I on" across the whole bundle.
* The repeated *"Opt in to make … better!"* admin notice no longer appears. Licence, plan and
  update notices are unaffected — only the opt-in prompt is suppressed.

= 1.0.10 =
* Change: License activation now uses per-plugin key entry — enter your bundle license key on each Pro plugin to unlock Pro. Improves activation reliability.

= 1.0.9 =
* New: CSV import. Import redirects from any spreadsheet as source,target,type (header row optional; type defaults to 301). Rows are validated, duplicates — against your existing rules and within the file — are skipped, and the free-tier rule limit is respected.

= 1.0.8 =
* New (Pro): conditional redirects. A rule can optionally require login state (logged in / logged out), any of a set of user roles, a referrer substring, or a user-agent substring — all set conditions must match. Rules without conditions behave exactly as before, and existing rules are untouched. Conditional rules are marked in the rules table.

= 1.0.7 =
* Free tier now allows up to 500 redirect rules (was 50) so you can migrate a full Redirection install without hitting the cap. Pro remains unlimited.

= 1.0.6 =
* New admin design system (Harvify Admin Kit): branded header, first-run onboarding, section navigation (Redirects, 404 Monitor, Insights), skeleton loader, coaching empty states, an at-a-glance Insights panel (redirect rules, redirect hits, 404 URLs & hits, most-used redirects, top 404s to fix), and a contextual, dismissible upgrade card. UI layer only — redirect handling, the 404 monitor and free/Pro gating are unchanged.

= 1.0.5 =
* Fix: Pro features now unlock only on the premium build with a valid license (per-plugin gate). Previously a shared bundle flag could make the free build report Pro when another Harvify plugin was licensed.

= 1.0.4 =
* Internal: uninstall cleanup now runs on Freemius's after_uninstall hook (removed uninstall.php) for Freemius Deployment compatibility. What gets removed on uninstall is unchanged.

= 1.0.3 =
* The free 404 monitor now logs every hit (previously sampled 1-in-5). Full 404 logging is no longer a Pro-only differentiator.

= 1.0.2 =
* Fixed redirects table failing to create on MySQL 8 (the `groups` column is a reserved word; renamed to `redirect_group`).
* Admin menu now registers on init (fixes a "translation loaded too early" notice under WordPress 6.7+).

= 1.0.1 =
* Pro features (scheduled redirects, chain detection, slug-change auto-redirect, 404 alerts) now load only in the premium build (Freemius is__premium_only model).
* Pricing now sourced from the shared bundle-license package; upgrade prompts link to the pricing page.

= 1.0.0 =
* Initial release.
