=== GHL-WP Membership ===
Requires PHP: 8.3
Stable tag: 0.5.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

GHL tag membership with automatic retries and selectable page protection. Isolated Lab build.

== Author ==
Arifur Rahman
HighLevel | HubSpot | KEAP CRM Expert
Email: arif@earif.com
Website: https://earif.com
LinkedIn: https://www.linkedin.com/in/earif/
Upwork: https://www.upwork.com/freelancers/arifur

== Usage ==
Edit a WordPress page, find Membership access, check Require active membership, and save.
Settings > GHL-WP Membership shows sync status, retry counts, and author details.
The configured GHL tag grants access to all selected pages. Editors can preview protected pages.

== Sync retries ==
Authenticated, allowlisted webhooks are durably recorded before reconciliation. Transient errors retry after 1, 2, 4, 8, 16, 32 and 60 minutes (8 total attempts). A new event or administrator's Queue a fresh sync starts a new cycle. Identity/configuration conflicts require review instead of automatic retries.
Each attempt reads the current contact from GHL. Duplicate events coalesce. A generation check prevents an older worker from deleting newer work. The worker processes at most three jobs each minute.
WP-Cron needs traffic. Use a server cron every minute for predictable execution. Deactivation clears the scheduled worker but preserves data; reactivation resumes pending work.

== Security and scope ==
Page views use local membership state, not remote CRM requests. Credentials are server-only; no credentials or CRM payloads are stored in retry jobs. New accounts are Subscribers; existing email accounts are not silently linked.
Protected direct pages, core REST data, searches, feeds, comments and embeds are gated. Editorial users retain preview access. Protected responses and authenticated front-end responses use private/no-store headers.
Exclude protected URLs from external page caches/CDNs and purge any existing cached copies. Use Media > Member downloads to upload privately or migrate a local Media Library attachment. Configure GHLM_PRIVATE_DIR outside all web roots and web-server aliases. The directory must not be exposed by a web server, CDN or storage bucket. Old public originals and known generated variants are removed only after verified private backups. Purge external caches and copies separately. Public uploads not explicitly migrated, child pages, custom APIs/GraphQL and third-party indexes are not automatically protected. Administrators can preview private downloads. Previously downloaded bytes cannot be recalled; a stream authorized before revocation may finish.
During CRM outages the last confirmed membership state remains until reconciliation succeeds. Webhooks lost before reaching WordPress are not recovered by this queue. It is not a periodic full-CRM reconciliation service.
This build remains scoped to one configured Lab contact/location/tag, with server-side configuration. No payments, multi-plan UI, automatic welcome emails or production setup wizard.

== Changelog ==
= 0.5.0 =
Renamed GHL-WP Membership. Added private uploads outside web root, authenticated streaming/range downloads, existing-media migration and public plugin website.
= 0.4.0 =
Durable automatic retries; page-editor membership protection; administrator sync status; author details.
= 0.3.0 =
Automatic Subscriber creation and current-tag grant/revoke/restore reconciliation.
