GWiz IT Content Locker

Description

Turn your WordPress content and downloads into leads.

GWiz IT Content Locker lets you place pages, downloads, sections of content, or individual page elements behind a customizable signup form.

Visitors enter their information to unlock your content, giving you a simple way to grow your email list, offer lead magnets, protect downloads, and measure conversions directly from WordPress.

The plugin is free and self-hosted. No third-party SaaS service is required to use the content locker or store your signups.

Want to use an existing email marketing platform? Confirmed subscribers can optionally be synced automatically to Mailchimp, Brevo, ConvertKit, ActiveCampaign, or phpList.

Watch It In Action

GWiz IT Content Locker — demo video

What Can You Lock?

  • Pages and Posts — Gate an entire WordPress page or post by URL.
  • File Downloads — Require visitors to sign up before accessing protected files.
  • Sections of Content — Wrap selected content in a simple shortcode.
  • Page Elements — Lock specific elements using CSS selectors.
  • Popup Offers — Open a signup gate from a custom link anywhere on your site.

Great For

  • Lead magnets
  • PDF and document downloads
  • Free guides and checklists
  • Resource libraries
  • Bonus content
  • Email list building
  • Gated articles or page sections
  • Downloadable marketing materials
  • Members-only style resources without requiring a full membership plugin

How It Works

  1. Create a Restricted Area in WordPress.
  2. Choose what you want to protect.
  3. Customize your signup form and unlock message.
  4. Visitors complete the form to gain access.
  5. View signups and conversion statistics in WordPress or optionally sync subscribers to your email marketing platform.

You can create multiple Restricted Areas, each with its own protected content, form, styling, settings, integrations, and subscriber list.

Lead Capture & Content Gating

  • Multiple Restricted Areas — Create separate gates for different downloads, pages, campaigns, or content.
  • Custom Form Builder — Build signup forms with drag-and-drop fields and 9 available field types. The email field is always required.
  • Inline Shortcodes — Gate only part of a page using [gwiz_it_content_locker].
  • Full-Page Gating — Protect an entire page or post by URL.
  • Protected Downloads — Require signup before visitors can access gated files.
  • CSS Selector Gating — Lock specific page elements without changing your page layout: show a customisable sign-up placeholder, or keep the classic visual lock.
  • Popup Trigger Links — Open a content-locker popup from a custom anchor link.
  • Double Opt-In — Optionally require email confirmation before granting access.
  • Already Signed Up Verification — Returning subscribers can verify their email and regain access.

Forms & Styling

  • Visual Form Builder — Create custom signup forms without coding.
  • Custom Email Templates — Edit confirmation and congratulations emails.
  • Custom Popup Templates — Control the message visitors see before unlocking content.
  • Style Presets — Quickly apply predefined form and popup styles.
  • Custom Colors & Typography — Adjust form appearance to match your website.
  • Custom Borders — Configure form and popup border width and color.
  • Custom CSS — Add styles scoped specifically to an individual form or popup.
  • Built-In Preview — Preview form and popup states before publishing.

Subscriber Management & Analytics

  • Signups Viewer — View and search collected subscribers from WordPress.
  • Customizable Columns — Choose which signup information is displayed.
  • CSV Export — Export subscriber information for Excel or other tools. Large lists stream in batches.
  • Data Retention — Automatically anonymise visitor IPs and purge old statistics on a daily schedule.
  • Conversion Statistics — Track views, submissions, confirmations, and conversion performance.
  • Date Filtering — Review statistics for specific date ranges.
  • Clone Restricted Areas — Duplicate an existing campaign with one click.
  • Export & Import — Back up or move Restricted Area settings between WordPress sites.
  • Optional Contact Migration — Include subscriber records when cloning, exporting, or importing Restricted Areas.

Email Marketing Integrations

Confirmed signups can optionally be sent automatically to:

  • ActiveCampaign — Add contacts to a list with optional tags.
  • Brevo (formerly Sendinblue) — Add contacts to a list.
  • ConvertKit — Add subscribers to a sequence or tag.
  • Mailchimp — Add subscribers to an audience with optional tags.
  • phpList — Add subscribers to a self-hosted phpList mailing list.

These integrations are optional.

You can use GWiz IT Content Locker entirely within WordPress without connecting an external email marketing service.

Spam Protection

Choose the spam-protection method that works best for your site:

  • Google reCAPTCHA v2 — Traditional checkbox CAPTCHA.
  • Google reCAPTCHA v3 — Invisible score-based spam protection.
  • ALTCHA — Self-hosted, privacy-friendly proof-of-work CAPTCHA with no external API calls.

Works With Popular Page Builders

GWiz IT Content Locker supports content created with:

  • Elementor
  • Divi
  • Beaver Builder
  • Standard WordPress content

The plugin detects gated content inside supported page-builder data and only loads its frontend assets when they are needed.

Privacy & Self-Hosted Data

GWiz IT Content Locker stores signup information on your WordPress website.

No subscriber information is sent to an external email marketing service unless you configure and enable that integration.

The plugin integrates with the WordPress privacy tools: signups appear in Tools Export Personal Data, and Tools Erase Personal Data removes the visitor’s email, form answers, source URL and IP address (an anonymised record is kept so your statistics stay accurate) and asks each connected email service to delete the contact. Suggested privacy-policy text is provided under Tools Privacy.

Gate activity is kept bounded and privacy-friendly on an automatic schedule: visitor IP addresses are anonymised after 30 days and old events are deleted after 365 days by default (both configurable under Settings Data Retention).

If you prefer not to use an external CAPTCHA service, the built-in ALTCHA option is fully self-hosted and does not make external API calls.

Built for WordPress

  • Gated content is not sent to unauthorised visitors: shortcode content, CSS-selector elements, and protected files are withheld server-side and only delivered after eligibility is re-verified on the server. Nothing is “hidden with JavaScript only”.
  • File downloads require a short-lived, single-use download ticket that is issued only after the server confirms the visitor’s access — a download link on its own never serves the file.
  • Frontend JavaScript and CSS load only on pages where they are needed.
  • Visitor access cookies are HMAC-signed.
  • Each Restricted Area can have its own cookie expiration.
  • Logged-in users automatically bypass gates while editing the site. File downloads additionally require a role with edit capability (customizable via the gwiz_it_content_locker_bypass_logged_in filter).
  • Rate limiting and input size caps protect all visitor-facing signup, confirmation, verification, unlock, and download endpoints.
  • Debug Mode lets administrators preview and test gates while logged in.
  • Built-in help explains each major setting in plain English.
  • Restricted Areas can be exported and imported for backup or migration.
  • Developer filters are available for advanced integrations and customization.

Shortcode Usage

Gate content inline using the shortcode:

[gwiz_it_content_locker area="AreaName"]This content is hidden until the visitor signs up.[/gwiz_it_content_locker]

The area attribute uses the Restricted Area’s display name.

The exact shortcode for each area is shown in the area’s Settings modal with a Copy button.

If multiple areas share the same name, automatic name deduplication is applied: AreaName, AreaName2, AreaName3, etc.

Important — logged-in users normally do not see the gate.

If you are logged in as an administrator or another WordPress user, the plugin intentionally shows the unlocked content without requiring signup.

This prevents site administrators and editors from being locked out of their own content.

To test the gate as a normal visitor:

  1. Log out of WordPress, or
  2. Open the page in a private/incognito browser window.

Administrators can also enable Debug Mode in the Restricted Area settings to preview the gate while logged in.

Developers can adjust logged-in bypass behavior with the gwiz_it_content_locker_bypass_logged_in filter.

External Services

GWiz IT Content Locker optionally connects to third-party services when configured by the site administrator.

No data is sent to these services until the administrator explicitly enables the integration and provides the required credentials.

  • ActiveCampaign — Syncs confirmed subscriber email addresses to your ActiveCampaign account through its API. (ActiveCampaign Privacy Policy)

  • Brevo (formerly Sendinblue) — Syncs confirmed subscriber email addresses to your Brevo account through its API. (Brevo Privacy Policy)

  • ConvertKit — Syncs confirmed subscriber email addresses to your ConvertKit account through its API. (ConvertKit Privacy Policy)

  • Mailchimp — Syncs confirmed subscriber email addresses to your Mailchimp audience through its API. (Mailchimp Privacy Policy)

  • phpList — Syncs confirmed subscriber email addresses to your self-hosted phpList installation through its REST API.

  • Google reCAPTCHA — When enabled, loads Google reCAPTCHA to protect signup forms from spam. Google may receive information including the visitor’s IP address and browser information for verification. (Google Privacy Policy)

All external data transfers occur over HTTPS.

The ALTCHA CAPTCHA option is fully self-hosted and does not connect to an external CAPTCHA service.

Hooks

Filters

gwiz_it_content_locker_load_frontend

Controls whether GWiz IT Content Locker frontend assets load on the current page.

Example:

add_filter( 'gwiz_it_content_locker_load_frontend', function( $should_load, $post ) {

    // Force-load on a specific page template.
    if ( is_page_template( 'template-custom.php' ) ) {
        return true;
    }

    // Prevent loading on the shop page.
    if ( is_shop() ) {
        return false;
    }

    return $should_load;

}, 10, 2 );

Parameters:

  • $should_load (bool) — Whether frontend assets should load. The default is automatically determined based on shortcode or selector presence.
  • $post (WP_Post|null) — The current post object.

gwiz_it_content_locker_bypass_logged_in

Allows developers to modify the default behavior that lets logged-in WordPress users bypass content gates.

By default, logged-in users are not required to complete signup forms. File downloads are stricter: the default there requires a role with edit capability, so ordinary subscribers do not receive gated files.

Parameters:

  • $bypass (bool) — Whether logged-in users bypass the gate (the download endpoint passes current_user_can( 'edit_posts' ) as this default).
  • $area_id (int) — The Restricted Area ID.
  • $settings (array) — The area’s parsed settings.

Actions

gwiz_it_content_locker_caches_cleared

Fires after the plugin cleared site caches following a Restricted Area save (see Settings Cache Clearing).

  • $cleared (bool) — Whether a known cache plugin or host cache was cleared. Use this to hook in your own cache/CDN purge.

gwiz_it_content_locker_retention_run

Fires after a daily data-retention pass (see Settings Data Retention).

  • $stats (array) — Rows processed in the pass: tickets_purged, ips_anonymised, events_deleted.

Screenshots

Installation

  1. Install GWiz IT Content Locker from the WordPress Plugins screen, or upload the g-wiz-it-content-locker folder to the /wp-content/plugins/ directory.
  2. Activate GWiz IT Content Locker through the Plugins screen in WordPress.
  3. Click GWiz IT Content Locker in the WordPress admin sidebar.
  4. Create your first Restricted Area.
  5. Choose the page, download, shortcode content, or page element you want to protect.
  6. Customize your signup form and settings.
  7. Activate the Restricted Area.
  8. Test the gate while logged out or in a private/incognito browser window.

Global templates and security settings can be configured under GWiz IT Content Locker Settings.

FAQ

Is GWiz IT Content Locker free?

Yes.

GWiz IT Content Locker can be installed and used for free to gate content, collect subscribers, manage signups, and track conversions directly from WordPress.

Do I need Mailchimp or another email marketing service?

No.

External email marketing integrations are optional.

Signups can be collected and managed directly from your WordPress website without connecting Mailchimp, Brevo, ConvertKit, ActiveCampaign, phpList, or another third-party marketing service.

What types of content can I lock?

You can protect:

  • Entire pages or posts
  • File downloads
  • Sections of page content
  • Individual page elements using CSS selectors

You can also trigger a content-locker popup from a custom anchor link.

Can I use the plugin for lead magnets?

Yes.

You can require visitors to complete a signup form before accessing PDFs, guides, checklists, documents, downloads, bonus content, resource libraries, or other gated material.

Can I protect downloadable files?

Yes.

GWiz IT Content Locker includes a protected file-download system that can require visitors to complete the signup process before accessing a gated file. The file is stored outside the public web directory, and its download link never serves the file on its own — after the visitor’s access is confirmed on the server, a short-lived single-use download token is issued for that specific download.

Can I connect signups to my email marketing platform?

Yes.

Confirmed subscribers can optionally be synced automatically to:

  • ActiveCampaign
  • Brevo
  • ConvertKit
  • Mailchimp
  • phpList

Can I use double opt-in?

Yes.

Double opt-in can be enabled individually for each Restricted Area.

When enabled, visitors must confirm their email address before receiving access: they get a confirmation email at signup, and the welcome email is sent once they click the confirmation link. With double opt-in disabled, a single welcome email is sent right after signup.

Does the plugin work with Elementor or Divi?

Yes.

The plugin pre-scans Elementor (_elementor_data), Divi (_et_pb_post_content), and Beaver Builder (_fl_builder_data) content for shortcodes and configured selector class names.

Does the plugin work with Beaver Builder?

Yes.

Beaver Builder content is supported along with Elementor, Divi, and standard WordPress content.

Where are subscriber details stored?

Subscriber information is stored on your WordPress website.

Data is only sent to an external email marketing service if you explicitly configure and enable that integration.

Signups are included in the WordPress personal-data export and erasure tools (Tools Export Personal Data / Tools Erase Personal Data), so you can respond to visitor privacy requests directly from the WordPress admin.

How do I find the shortcode for my Restricted Area?

Click the Settings button on any Restricted Area card.

The shortcode is displayed near the top of the settings window with a Copy button.

Why do I see my content without a signup form?

You are most likely logged into WordPress.

Logged-in users normally receive the unlocked content without seeing the signup form.

This is intentional so administrators and editors are not gated on their own website.

To test the gate as a visitor, log out or open the page in a private/incognito browser window.

Administrators can also enable Debug Mode to preview the gate while logged in.

How do I hide elements by CSS selector?

Open the Restricted Area’s Settings modal and enter CSS selectors in the Hide by Selector field, one selector per line.

For example:

div.exampleclass

or:

span.highlight

Elements matching those selectors are locked until the visitor signs up. How they look is your choice per Restricted Area (the Locked Element Style setting):

  • Locked section (default) — the content is removed from the page before it is sent to the visitor’s browser (it is not in the page source or the DOM) and replaced with a visible, customisable placeholder: background and text colors, message text, and button text, colors and CSS class. Clicking the element opens the signup form in a popup modal.
  • Visual lock (classic) — the element keeps its place in your page and is styled with your Custom Lock Style and an optional hover tooltip. Two checkboxes control what happens to the content server-side: Strip Locked Content removes the matched element entirely from the page source (most secure), and Remove Child Elements keeps the styled element shell but removes its children (images and other embeds are removed entirely, since their content is their source URL). With neither checked, the content stays in the page and is only hidden visually — like the original version of this feature.

In every mode the removed content is restored into the page after the visitor signs up (and confirms, when double opt-in is enabled).

Supported selectors: tag names, *, #id, .class, attribute selectors ([href], [type="text"], [class*="x"], [href^="https"], [href$=".pdf"], [rel~="x"], [lang|="en"]), the descendant/child/sibling combinators (space, >, +, ~), comma-separated lists, and :first-child, :last-child, :nth-child(n|odd|even). Any other pseudo-class (for example :hover or :has()) is applied as a visual lock only — for those selectors the plugin falls back to locking the element client-side, which hides it visually but does not remove it from the page source.

Can I show the signup form on only one section of the page?

Yes.

Place the shortcode around the content where you want the signup form to appear.

If you need to protect additional elements without displaying additional forms, use CSS selectors to lock those elements.

Will my caching plugin be cleared when I save?

Yes — by default the plugin clears popular caching plugins (WP Rocket, WP Super Cache, W3 Total Cache, LiteSpeed Cache, WP Fastest Cache, Cache Enabler, Comet Cache, SG Optimizer, WP-Optimize, Swift Performance, Autoptimize, Nginx Helper and Hummingbird) and host-level caches on GoDaddy Managed WordPress, WP Engine, Kinsta, Pantheon and Cloudways whenever anything in a Restricted Area is saved, so gating changes appear immediately. You can turn this off under GWiz IT Content Locker Settings Cache Clearing. If your host also runs a WAF/CDN cache (for example GoDaddy’s WAF), that layer may still need a manual clear from your hosting dashboard.

Does the plugin load JavaScript and CSS on every page?

No.

The plugin checks the current page content, including supported page-builder data, and only loads frontend assets when a shortcode or relevant selector is detected.

Can I clone a Restricted Area?

Yes.

Click the Clone button on a Restricted Area.

You can choose whether subscriber/contact records should also be included.

The duplicated area is created as a disabled copy with a unique name.

Can I export and import Restricted Areas?

Yes.

Click Export on a Restricted Area to download a ZIP backup.

To import a backup, use Import Settings on an existing Restricted Area or Import Area to create a new one.

You can optionally include subscriber/contact records.

Backup files contain plugin version information so older backups can be handled safely as the plugin evolves.

Can I transfer contacts between Restricted Areas?

Yes.

When cloning, exporting, or importing an area, you can choose to include contacts.

Imported contacts are added as new signup records and are not automatically de-duplicated by email address.

Is the CSV export compatible with Excel?

Yes.

CSV exports include a UTF-8 BOM so applications such as Microsoft Excel correctly recognize UTF-8 text, including accented and non-English characters.

How do I force frontend assets to load on a specific page?

Developers can use the gwiz_it_content_locker_load_frontend filter documented in the Hooks section below.

What email placeholders are available?

Confirmation Email

  • {{confirm_link}}
  • {{site_name}}
  • {{email}}
  • {{area_name}}
  • {{source_url}}

Congratulations Email

  • {{site_name}}
  • {{email}}
  • {{area_name}}
  • {{source_url}}

Popup Template

  • {{form}}
  • {{already_signed_up_link}}
  • {{site_name}}
  • {{area_name}}
  • {{file_name}}

How does the “I have already signed up” link work?

The popup template includes an {{already_signed_up_link}} placeholder.

When visitors click it, they are shown an email verification form.

If the email exists as a confirmed signup for that Restricted Area, the visitor receives an access cookie and the protected content is unlocked.

If the address is not found, a generic response is shown to help prevent email enumeration.

Where can I find help for each button and setting?

Click the Help button at the top of the Restricted Areas page.

The plugin includes a detailed plain-English guide explaining the available buttons, settings, and options.

Reviews

There are no reviews for this plugin.

ডেভেলপার এবং কন্ট্রিবিউটর

“GWiz IT Content Locker” is open source software. The following people have contributed to this plugin.

কন্ট্রিবিউটর

Translate “GWiz IT Content Locker” into your language.

ডেভেলপমেন্ট এ আগ্রহী?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.12.0

  • Fixed: the ALTCHA checkbox appeared to solve but every submission still failed with “Please complete the captcha verification to continue.” — the page read the solution from a property the ALTCHA v2 widget does not have (a v1 API), so no solution was ever sent to the server. The payload is now read from the widget’s actual API (getState().payload and the hidden input it creates on solve). The challenge URL also carries a version tag so host or page caches (e.g. GoDaddy Varnish, WP Rocket) can never serve a challenge issued by an older plugin release.
  • Fixed: reCAPTCHA v2 retries could fail forever with “Please complete the captcha verification to continue.” while the box still looked checked. reCAPTCHA tokens are single-use at Google, so any request rejected after verification (a validation error, rate limit, or hiccup) burned the token. Input validation now runs before captcha verification, and the widget is automatically reset after any failed submit so retries work. reCAPTCHA v2 widgets are now rendered explicitly with tracked ids (works in popups and multi-form pages).
  • Improved: the reCAPTCHA v3 Score Threshold help text now warns that 0.5 is strict — real visitors on simple pages often score 0.3–0.6, so 0.3–0.4 is the recommended starting point.

1.11.0

  • Fixed: the ALTCHA (self-hosted) captcha always failed with “Please complete the captcha verification to continue.” even after the widget was solved — the widget never returns an expires field in its solution, but the server required one, so every submission was rejected. The expiry timestamp now travels inside the signed salt (which the widget does return), verification accepts the widget’s actual payload format, a solution number of 0 is now accepted, and challenge responses are marked no-store so page caches can’t serve stale, already-expired challenges. Note: challenges issued by 1.10.0 and earlier stop verifying after this update (they live only 5 minutes) — visitors simply solve the fresh widget.
  • Added: the three default-template boxes on the Settings page (Confirm Notice / Already Signed Up / Not Signed Up) are now visual/code editors — the same TinyMCE editor with a “Text” tab used in the Restricted Areas dialogs — so templates can be edited visually or as HTML. The plain textareas remain as a no-JavaScript fallback.
  • Fixed: with double opt-in enabled, the welcome email after clicking the confirmation link was skipped when an area’s Congrats Template was empty (e.g. areas imported from older backups). Both signup flows now always send the welcome email and share the same built-in fallback template.
  • Fixed: the plugin now passes the WordPress Plugin Check cleanly (prefixed a global variable in uninstall.php; documented the third-party LiteSpeed Cache hook name used by the cache clearer).
  • Added: a demo walkthrough video (see Watch It In Action at the top of this readme) covering signup, confirmation and download access.

1.10.0

  • Fixed: saving in a Restricted Area’s settings dialog could show a save error even though the save had succeeded (and a save with no changes answered with a request error). Two causes: “nothing changed” was misread as a failed database write, and cache-clearing code from caching plugins/hosts — which can emit PHP notices or run slowly, e.g. GoDaddy’s Varnish flush — ran inside the save request and corrupted its JSON response. Saves now respond cleanly first; cache clearing runs afterwards, fully quarantined (no output, no exceptions), and every cache/host purge call is individually isolated so one broken integration cannot affect the rest.
  • Added: Clear cache on save setting (on by default) — whenever anything in a Restricted Area is saved (settings, styles, templates, URLs, areas), the plugin now clears caches automatically: caching plugins (WP Rocket, WP Super Cache, W3 Total Cache, LiteSpeed Cache, WP Fastest Cache, Cache Enabler, Comet Cache, SG Optimizer, WP-Optimize, Swift Performance, Autoptimize, Nginx Helper, Hummingbird) and hosting caches on GoDaddy Managed WordPress, WP Engine, Kinsta, Pantheon and Cloudways. This means gating changes show up immediately instead of after the cache expires — no more manual flushes in the GoDaddy dashboard. Can be turned off under GWiz IT Content Locker Settings; host WAF/CDN caches may still need a manual clear.
  • Added: Locked Element Style setting for CSS Selector gates — choose per area between “Locked section (sign-up placeholder)” and “Visual lock (classic)”. Visual mode adds two checkboxes: strip the locked content out of the page source entirely, or keep the element shell and remove only its child elements. Removed content is always restored after signup. Settings travel with area export/import backups.
  • Fixed: CSS-selector locked elements no longer appear as an empty, faded box. When content is removed server-side the element now shows a visible “locked” placeholder with a sign-up button (clicking it opens the signup popup), and the Custom Lock Style is no longer applied over the placeholder — it still styles visual locks, where the real content remains on the page.
  • Fixed: the Custom Lock Style setting was not saved when the settings dialog was closed (it was sent to the server but silently ignored). It now saves correctly.
  • Fixed: replaced all uses of the deprecated jQuery.trim (removed in jQuery 4) with a local equivalent, so lock styling and admin saves keep working on sites that upgrade jQuery.
  • Added: WordPress privacy tools integration — signups (email, custom form fields, source page, IP, timestamps) appear in Tools Export Personal Data, together with which third-party services received the signup and the visitor’s gate activity.
  • Added: Tools Erase Personal Data support — erasure deletes the visitor’s email, form answers, source URL and IP address (an anonymised record is kept so submission/confirmation statistics stay accurate, shown with an “Erased” badge), removes the integration records, anonymises the gate-activity IPs, and asks each connected email service (Mailchimp, Brevo, ConvertKit, ActiveCampaign, phpList) to delete the contact. If a service cannot be reached, the privacy request log tells you to remove the contact there manually.
  • Added: Data Retention settings with a daily cleanup cron — visitor IPs in gate activity are anonymised after 30 days and old events deleted after 365 days by default (both configurable, 0 = keep forever; signups are never deleted automatically). Runs in small indexed batches via WP-Cron, so large statistics tables are never processed in one request.
  • Added: suggested privacy-policy text under Tools Privacy describing what the plugin collects, what is sent to each integration, the access cookies, and how long data is kept.
  • Improved: deleting the plugin now restores protected files to their original locations (instead of leaving them in the private folder) and removes all plugin options and the scheduled cleanup event.
  • Improved: the signups CSV export streams from the server in indexed batches, so large lists export reliably instead of loading every signup into a single request.
  • Improved: the translation template (languages/g-wiz-it-content-locker.pot) has been regenerated with every current string and translator comment. A WP-CLI-free generator (tools/make-pot.php, development files, not shipped in the zip) reproduces it with php tools/make-pot.php.

1.9.0

  • Security: gated shortcode content and CSS-selector elements are now removed from the page SERVER-SIDE before it reaches the browser — previously they were only hidden with JavaScript and were readable in the page source and DOM. Locked markup is stored server-side and delivered only after the visitor’s access is re-verified, through a dedicated unlock endpoint. Cached pages continue to work: every visitor receives the same stripped page, and eligible visitors’ content is inserted after the access check.
  • Security: protected file downloads now require a short-lived, single-use download ticket issued only after server-side eligibility is confirmed. Previously the file URL plus an access cookie was enough. A nonce-checked form fallback keeps downloads working without JavaScript.
  • Security: the download endpoint no longer serves files to any logged-in user — a role with edit capability is now required (customizable via the gwiz_it_content_locker_bypass_logged_in filter).
  • Security: gated files with active content types (HTML, SVG, XML, …) are now served as attachments instead of inline, closing a stored-XSS vector for gated uploads.
  • Security: fixed a bypass where appending ?gwiz_it_bg_preview=1 to a gated URL skipped the page gate entirely. The background preview (and the blurred gated-page background behind the gate overlay) is now rendered for privileged users only.
  • Security: gated page content no longer leaks through the REST API (content.rendered) or RSS feeds.
  • Security: rate limiting on the confirmation link, pending-status, resend, unlock, and download endpoints (signup and verification were already limited), plus hard size caps on all submitted form fields.
  • Improved: re-submitting while pending double opt-in now reuses the existing signup record (same confirmation token) instead of creating duplicate rows and emails; a UNIQUE (area, email) key with automatic deduplication of old duplicates backs this up at the database level.
  • Improved: double opt-in continues to hold content and downloads until the confirmation link is clicked; confirming is idempotent.
  • Improved: CSV export and analytics tables are unaffected in this release; a batched export, retention cleanup, and WordPress privacy exporter/eraser are planned next.
  • Note for CSS Selector users: unsupported selector syntax (pseudo-classes such as :hover or :has()) falls back to the previous visual-only lock. The supported server-side subset is documented in the FAQ.

1.8.1

  • Fixed: statistics now track every popup/form display — popups opened from CSS/HTML elements and from the Popup Trigger Link now count as Views in the restricted area’s statistics (previously only the Add/Edit URL gate and the inline shortcode form were counted). Popup views are recorded when the popup actually opens, so they are counted correctly even on cached pages.
  • Fixed: submitting the form with an email that has already signed up now counts as a Submission (previously repeat submissions were not counted). The signup itself stays idempotent — no duplicate signups or emails.

1.8.0

  • Added: Popup Trigger Link (Settings page) — define a custom anchor link (e.g. #gwiz_it_content_locker) that opens a content-locker popup when clicked, just like clicking a locked element. The link opens the FIRST popup available on the page (an inline shortcode form, then a CSS/element selector area, then an Add/Edit URL popup). Any active area with CSS selectors configured makes its popup available through this link on every page of the site — even where its selectors match nothing — so the link can double as a site-wide “Unlock” button. Only when no active area uses CSS selectors and the page has no shortcode or URL rule does clicking do nothing.
  • Added: Form/Popup Styles — input/textarea background and text colors (inputs are no longer transparent; defaults are white background / black text), available for both inline forms and full-page popups, with defaults in every style preset.
  • Added: Form/Popup Styles — background and text color pickers for the Google reCAPTCHA and ALTCHA (local) captcha widgets (defaults: white background, black text). Both captcha widgets respect the Text Align setting.
  • Added: Form/Popup Styles — Border Width and Border Color for the form card / popup dialog (set the width to 0 to remove the border, e.g. a thin light line around the popup).
  • Added: Form/Popup Styles — Custom CSS box per form/popup. Every selector is automatically scoped to that form or popup, so the styles can never bleed into other elements on the page.
  • Added: ALTCHA self-hosted captcha option (proof-of-work, no external service required).
  • Fixed: the popup dialog now follows the “Full-Page Popup” styles instead of the “Inline Form” styles — the two style columns are fully independent (“Inline Form” styles the inline shortcode form; “Full-Page Popup” styles every popup dialog and the URL-gate popup).
  • Fixed: captcha widget labels (e.g. ALTCHA’s checkbox label) now follow the Captcha Text Color instead of being forced to the form’s Text Color.

1.7.3

  • Fixed: restricted area rename — pressing Enter or clicking outside the name field now saves the change, and Escape cancels it.
  • Fixed: the area color picker no longer crashes with a JavaScript error and opens correctly.
  • Fixed: form and email template editors no longer open blank for newly created areas — they are pre-filled with the default templates.
  • Improved: the logged-in bypass is now documented where users look for shortcode help (area settings modal, help page, and readme FAQ).

1.7.2

  • Fixed: scripts and styles are now registered and enqueued via the WordPress scripts and styles API.
  • Fixed: shortcode callback output is now escaped with wp_kses and an explicit allowlist.
  • Fixed: text domain renamed to g-wiz-it-content-locker to match the plugin slug.

1.7.0

  • Breaking: plugin renamed from “GWiz GWiz IT” to “GWiz IT Content Locker” to avoid trademark confusion with Gravity Wiz.
  • Breaking: shortcode changed from [gwiz_leadgate] to [gwiz_it_content_locker]. Update any existing pages/posts using the old shortcode.
  • Breaking: all internal prefixes renamed (text domain, function names, option names, database table names, CSS classes, JS variables).
  • Breaking: database tables renamed from wp_gwiz_gwiz_it_* to wp_gwiz_it_content_locker_*.
  • If upgrading from 1.6.x: export your areas first, uninstall the old version, install the new version, then import your areas from backup.
  • Improved: WordPress coding standards compliance — resolved all PHPCS errors and warnings.

1.6.2

  • Improved: WordPress coding standards compliance — resolved all PHPCS errors and warnings from the WordPress Plugin Checker.
  • Improved: added missing translators comments for all translatable strings with placeholders.
  • Improved: nonce verification annotations for all AJAX handlers (nonce checks were already present via verify_ajax()).
  • Improved: replaced deprecated functions — unlink() with wp_delete_file(), parse_url() with wp_parse_url().
  • Improved: input sanitization and validation for cookie values and server variables.
  • Improved: database query annotations for custom table operations (DirectDatabaseQuery, InterpolatedNotPrepared).
  • Improved: moved HTML tags outside translatable strings for proper i18n compliance.
  • Improved: added isset() checks for $_SERVER superglobal access.
  • No functional changes or database schema updates.

1.6.1

  • Fixed: the debug-mode “temporarily close” button now respects the “Keep inline signup forms visible after popup is dismissed” setting. Previously, closing the popup with debug mode enabled did not set the session flag, so inline forms remained visible on subsequent page loads even when the setting was unchecked.

1.6.0

  • Added Clone feature: duplicate any restricted area with one click. The clone is created disabled with a unique name suffix (-1, -2, -3, etc.) and a different color. Optionally include contacts in the clone.
  • Added Export feature: download a ZIP backup of any restricted area containing all settings, templates, URLs, and optionally contacts. The backup includes a manifest with plugin version metadata for forward-compatible restores.
  • Added Import feature: restore area settings from a ZIP backup. Import creates a new area (with automatic name deduplication) or overwrites an existing area’s settings with a confirmation warning. Version mismatch warnings are shown when importing backups from older plugin versions.
  • Added top-of-page “Import Area” button alongside “Add New Area” for creating new areas from backup files.
  • Added “Include contacts/users?” option to all clone, export, and import operations (defaults to No for clone/export, No for import).
  • Backup files use a ZIP format with separate JSON files (manifest.json, area.json, urls.json, signups.json) for maximum compatibility and readability.

1.5.1

  • Added background colors to the new Form Template, Form/Popup Styles, and Preview buttons.
  • Stacked the Inline Form and Full-Page Popup style sections vertically instead of side-by-side columns.
  • Added a title above the preview showing which form/popup state is currently displayed.

1.5.0

  • Renamed “Popup Template” to “Form Template” and moved the Confirm Notice template under it (removed the separate Confirm Notice button).
  • Added a “Form/Popup Styles” option with presets (Default, Modern, Dark, Rounded, Minimal) plus per-field controls for font, colors, size, radius, alignment, and position — separately for inline forms and full-page popups.
  • Added a “Preview” button that opens a modal previewing every form/popup state, with prev/next arrows to navigate and non-interactive forms.
  • Styles are applied via CSS variables to both the inline form card and the full-page popup overlay.

1.4.1

  • Debug mode banner is now always pinned to the bottom of the inline form and full-page popup, below any AJAX views.
  • Added a green/red cookie status line above the debug banner showing whether the area access cookie is currently valid.
  • Admin modals are now constrained to the browser window with an internal vertical scroll bar, so they stay on screen at high zoom levels.

1.4.0

  • Added a “Not Signed Up” template shown (via AJAX) when a visitor verifies an email on the “already signed up” form that has not signed up, with a link back to the signup form.
  • The “Already Signed Up” template now includes a close button by default (new {{close_label}} placeholder).
  • Moved the “Already Signed Up” template editor into the Popup Template modal (Popup / Already Signed Up / Not Signed Up) and removed the separate button on each restricted area.
  • The “already signed up” email check is now fully AJAX on inline forms — no page refresh; closing the already-signed-up view reveals the content immediately.
  • Added global defaults for the new templates on the Settings page.
  • Added the not_signedup_template database column (automatic migration).

1.3.2

  • Fixed: the “Already signed up” link in popup templates that use the older gwiz-it-already-signed-up class now opens the verification form instead of refreshing the page.
  • Fixed: the default popup templates no longer nest an anchor inside the {{already_signed_up_link}} placeholder (invalid HTML).
  • Fixed: no duplicate “already signed up” link is appended when the template already contains one.

1.3.1

  • Fixed: elements matched by the CSS Selector setting were not hidden because the generated hide class never matched the stylesheet rule (attribute selector now matches classes anywhere in the class list, plus a data-attribute fallback).
  • Fixed: selector-matched elements are now hidden with an inline style as well, so the gate still blocks content when the stylesheet is served from cache.
  • Fixed: selector gates are injected immediately at script parse time (no flash of unprotected content) and can no longer be injected twice.
  • Added: with Debug Mode enabled on an area, logged-in administrators now see the gate so they can preview it on the frontend.
  • Added: gwiz_it_content_locker_bypass_logged_in filter for controlling the logged-in bypass.

1.3.0

  • Added [gwiz_it_content_locker] shortcode for inline content gating with Windows-style area name deduplication.
  • Added hide-by-CSS-selector feature with first/all display modes.
  • Added lead-capture form builder with drag-and-drop fields (9 field types).
  • Added email templates (confirmation + congratulations) with TinyMCE visual editors.
  • Added popup template editor with form and already-signed-up placeholders.
  • Added signups viewer with expandable detail rows, customizable columns, and form snapshot storage.
  • Added CSV export with UTF-8 BOM for Excel compatibility and field selection.
  • Added statistics modal with date-range filtering (views, submissions, confirmations, conversion rate).
  • Added per-area settings: debug mode, cookie expiration, double opt-in.
  • Added HMAC-signed per-area visitor cookies with configurable expiration.
  • Added confirmation link handler for double opt-in flow.
  • Added “I have already signed up” verification flow.
  • Added frontend builder support (Elementor, Divi, Beaver Builder shortcode detection).
  • Added performance optimization: frontend assets only load when shortcode or hide selectors are detected on the page.
  • Added gwiz_it_content_locker_load_frontend filter for developer control over asset loading.
  • Added new database tables for signups and analytics.
  • Security: all visitor-facing AJAX endpoints use nonce verification, input sanitization, and SameSite cookies.

1.2.0

  • Removed global enable toggle — each restricted area now has its own on/off toggle.
  • Added per-area settings: rename, color picker with preset colors, save button.
  • New areas spawn with a random color and inactive by default.
  • Areas store settings as JSON in the database (extensible for future features).
  • Frontend gating now only enforces active areas (is_active = 1).
  • Database migration runs automatically on version upgrade.
  • Area cards show active/inactive state with visual opacity and toggle switch.

1.1.0

  • Added custom database tables for restricted areas, URLs, and gated files.
  • Added Restricted Areas admin page with expandable area cards, URL management, and autocomplete.
  • Added Settings page with “Enable Lead Gating” toggle.
  • Added frontend gate overlay for restricted page/post URLs.
  • Added gated file download system with tokenized URLs and private file storage.
  • Added confirmation modals for destructive actions.

1.0.0

  • Initial plugin foundation.
  • Added the GWiz IT Content Locker administration dashboard.
  • Added translation-ready and GPL-licensed plugin structure.