Core Privacy Consent Manager
Lightweight opt-out cookie consent banner for WordPress: Google Consent Mode v2 + Meta Pixel, GPC honoring, [cookie_preferences] shortcode.
by olegtymo · github.com/olegtymo/core-privacy-consent-manager
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/olegtymo/core-privacy-consent-manager/archive/refs/heads/main.zipReadme
Core Privacy Consent Manager
A lightweight, reusable opt-out cookie consent banner for our WordPress sites.
It stores the visitor's choice, blocks non-essential tracking after opt-out,
signals Google Consent Mode v2 and Meta Pixel, and exposes a
[cookie_preferences] shortcode so visitors can change their mind.
Legal model: opt-out (US, non-CA contractor sites). Tracking loads by default and stops after a visitor opts out. This is not GDPR opt-in.
1. Install & configure
- Activate Core Privacy Consent Manager.
- Go to Settings → Cookie Consent and fill in:
- Notice text, button labels, Privacy Policy URL.
- Colors.
- Emit Google Consent Mode v2 signals (leave on if you use GA4 / Google Ads / GTM).
- Remember choice for (days) — default
365. - Consent version — bump this number to re-prompt every visitor (e.g. after a policy change).
That's the whole setup for a new site — no code edits required.
2. How script gating works (hybrid model)
| Service | Mechanism | What you do |
|---|---|---|
| GA4 / Google Ads / GTM | Consent Mode v2 signals (ad_storage, analytics_storage, ad_user_data, ad_personalization) |
Nothing — the plugin emits gtag('consent', ...) automatically. Keep your GTM/GA snippet in WP Code as-is. |
| Meta Pixel | fbq('consent', 'grant'|'revoke') |
Add the one-line guard below to your Pixel snippet. |
| Other pixels / non-Google scripts | JS guard window.CPCM.allows() |
Wrap the snippet body in the guard below. |
The plugin prints the Consent Mode default state at the very top of <head>
(before your GTM/GA snippet), so Google tags respect consent even though they
still load. For visitors who already opted out, it immediately sends an
update → denied. It also sets url_passthrough and ads_data_redaction so
Google Ads keeps measuring conversions when storage is denied.
Global Privacy Control (GPC): if a visitor's browser sends a GPC signal
(navigator.globalPrivacyControl) and they have no explicit choice yet, the
plugin honors it as an opt-out — CPCM.allows() returns false and a
denied update is sent. Under CCPA/CPRA a GPC signal is a valid opt-out.
Closing the notice = implied acceptance: the banner has a close (×) button, and Escape does the same. In this opt-out model that records "accept" so the notice isn't shown again (tracking was already active). Explicit Opt Out still blocks tracking.
3. WP Code snippet templates
3a. Google (GA4 / GTM / Google Ads)
No change needed. Keep your existing snippet. The plugin handles consent via Consent Mode v2. Just make sure Emit Google Consent Mode v2 signals is enabled.
3b. Meta Pixel
Add the last line to your existing Pixel snippet (opt-out model: granted by default, revoked when the visitor opts out):
<script>
!function(f,b,e,v,n,t,s){/* standard Meta Pixel loader */}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
// CPCM: revoke if this visitor has opted out.
if (window.CPCM && !CPCM.allows()) { fbq('consent', 'revoke'); }
</script>
3c. Any other non-essential script (Hotjar, LinkedIn, TikTok, call tracking…)
Wrap the snippet body so it only runs when consent allows it:
<script>
(function () {
function load() {
// --- paste the third-party snippet body here ---
}
if (!window.CPCM || CPCM.allows()) {
load(); // opt-out model: load by default unless opted out
} else {
// optional: load later if the visitor accepts during this session
CPCM.onChange(function (granted) { if (granted) load(); });
}
})();
</script>
4. Cookie Preferences link (let visitors change their choice)
- Shortcode anywhere:
[cookie_preferences]or[cookie_preferences label="Manage cookies"] - Manual / theme link:
<a href="#" onclick="window.CPCM.openSettings(); return false;">Cookie Preferences</a>
5. JavaScript API (window.CPCM)
| Method | Returns | Purpose |
|---|---|---|
CPCM.getChoice() |
'accepted' | 'opted_out' | null |
Current stored choice. |
CPCM.hasChoice() |
boolean |
Whether a valid choice exists. |
CPCM.allows() |
boolean |
True when non-essential scripts may run. |
CPCM.accept() |
— | Persist "accept" + resume tracking. |
CPCM.optOut() |
— | Persist "opt out" + block tracking. |
CPCM.dismiss() |
— | Implied acceptance (close/Esc): records "accept" so the notice isn't shown again. |
CPCM.reset() |
— | Forget the choice. |
CPCM.onChange(cb) |
unsubscribe fn | cb(granted, choice) on every change. |
CPCM.openSettings() |
— | Re-open the banner. |
6. Storage & lifetime
- First-party cookie
cpcm_consent={"choice":"accepted|opted_out","ts":<ms>,"v":<version>},SameSite=Lax(source of truth). - Mirrored to
localStorage.cookieConsent(accepted/opted_out) for compatibility with the classic patternlocalStorage.getItem("cookieConsent") !== "opted_out". - Default lifetime 365 days (configurable). After expiry, or when Consent version changes, the banner re-appears.
7. Architecture
core-privacy-consent-manager.php Bootstrap: constants, autoloader, activation
includes/class-plugin.php Orchestrator (composition root)
includes/class-settings.php Settings model (defaults + read) + cookie/choice constants
admin/class-settings-page.php Settings API page + input sanitization
frontend/class-banner-renderer.php Asset enqueue + banner markup
frontend/class-consent-mode.php Google Consent Mode v2 default/update
frontend/class-shortcode.php [cookie_preferences] shortcode
assets/js/consent-sdk.js window.CPCM (state, storage, signals)
assets/js/banner.js Banner UI
assets/css/banner.css Fluid styles (CSS vars + clamp())
8. QA checklist
- First visit (no choice): banner shows; GA4/GTM load;
consent default = granted. - Accept: banner hides; cookie
choice = accepted; tracking continues; reload → no banner. - Opt Out: banner hides; cookie
choice = opted_out; Consent Modeupdate → deniedindataLayer; no new GA/Ads cookies; Metafbq consent revoke(no new Pixel requests). - Persistence/expiry: choice survives reload; clearing cookie or bumping Consent version re-shows the banner.
- Preferences:
[cookie_preferences]re-opens the banner. - Performance/a11y: scripts are deferred (footer); no layout shift; keyboard navigable; visible focus.