Build an add-on
Wire any third-party technology into the Kjeks consent layer, using the Google Consent Mode add-on (kjeks-google) as the worked example.
A Kjeks add-on is just a normal WordPress plugin that declares its technologies to the core plugin. Kjeks then holds those scripts back until the visitor grants the matching consent category. You never write the blocking yourself — you describe what runs and which category it belongs to. Everything below maps to real code inkjeks-google.
1 · Anatomy of an add-on
Plugin header
Declare a dependency on the core plugin so WordPress itself warns when it's missing, and mark it network-capable:
<?php
/**
* Plugin Name: Kjeks Google
* Description: Google Tag Manager / GA4 for Kjeks via Consent Mode v2.
* Requires at least: 6.8
* Requires PHP: 8.3
* Requires Plugins: kjeks // WordPress warns if Kjeks is missing
* Network: true // multisite-friendly, like the core plugin
*/Boot only when Kjeks is present
The Requires Plugins: kjeks header already stops WordPress from activating your add-on without Kjeks (and from deactivating Kjeks while yours is active). So you don't need a dependency class — a one-linefunction_exists() guard on the core plugin's public API is enough insurance for the rare “active but not loaded” edge:
add_action(
'plugins_loaded',
static function (): void {
// The Requires Plugins header prevents activation without Kjeks; this
// one-liner is cheap insurance for the "active but API not loaded" edge.
if ( ! function_exists( 'kjeks_register_integration' ) ) {
return;
}
Plugin::instance()->boot();
}
);kjeks_register_integrations action, whichonly the core plugin fires — so even without the guard you can't fatal by calling kjeks_register_integration() when Kjeks is absent. Kjeks loads its API on init (priority 20 fires that hook), and booting on plugins_loaded keeps the ordering correct.2 · Register your technology
This is the heart of every add-on. Hook thekjeks_register_integrations action and callkjeks_register_integration( $id, $args ). Kjeks blocks the scripts until the category is granted:
add_action( 'kjeks_register_integrations', function (): void {
kjeks_register_integration(
'google-tags', // unique integration id
array(
'category' => 'analytics', // gate: runs only when this is granted
'label' => 'Google Tag Manager / Analytics',
'src_scripts' => array(
'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX',
),
'inline' => array(
"gtag('js', new Date()); gtag('config', 'G-XXXXXXX');",
),
// 'handles' => array( 'my-registered-handle' ), // or gate an already-enqueued script
)
);
} );The arguments
| Key | What it does |
|---|---|
category | The gate: preferences, analytics, or marketing. Unknown or necessary falls back to marketing. |
label | Human name shown in the cookie declaration. |
src_scripts | External scripts to inject after consent (a URL string, or { src, attrs }). |
inline | Inline JS snippets to run after consent. |
handles | Registered script handles to hold back — gate a script another plugin/theme enqueued. |
kjeks_enqueue_script(),kjeks_add_inline_script(), and kjeks_embed() — see thecore 201 guide.3 · React to consent on the front end
Registration is enough for most add-ons — Kjeks loads your scripts when consent is granted. But some technologies (like Google Consent Mode) must alsosignal on every change. Kjeks gives you a small JS surface:window.kjeks.isGranted( category ) and thekjeks:granted / kjeks:withdrawn events.
// Consent Mode v2 defaults — printed in wp_head BEFORE anything Google loads.
gtag( 'consent', 'default', {
ad_storage: 'denied', ad_user_data: 'denied',
ad_personalization: 'denied', analytics_storage: 'denied',
wait_for_update: 500,
} );
// Sync to Kjeks now and on every change.
function granted( c ) {
return window.kjeks ? window.kjeks.isGranted( c ) : false;
}
function apply() {
if ( typeof gtag !== 'function' ) return;
gtag( 'consent', 'update', {
analytics_storage: granted( 'analytics' ) ? 'granted' : 'denied',
ad_storage: granted( 'marketing' ) ? 'granted' : 'denied',
} );
}
window.addEventListener( 'kjeks:granted', apply );
window.addEventListener( 'kjeks:withdrawn', apply );
document.addEventListener( 'DOMContentLoaded', apply );kjeks-google prints the first block (defaults denied) in wp_head at priority 1, and the sync block at priority 2 — so Google's own state isdenied until Kjeks says otherwise, a second layer on top of the gate.
4 · Settings, config & updates
Store configuration
kjeks-google keeps a network default (kjeks_google_network) and a per-site override (kjeks_google), resolved so a site's own value wins. Expose a settings page on network_admin_menu (capabilitymanage_network_options) and admin_menu (capabilitymanage_options), mirroring how the core plugin adapts to single-site vs multisite.
Offer a filter
Let other code adjust your resolved config at runtime:
add_filter( 'kjeks_google_config', function ( $config, $blog_id ) {
// $config = [ 'gtm_id' => '', 'ga4_id' => 'G-XXXX', 'gating_category' => 'analytics' ]
return $config;
}, 10, 2 );Ship self-updates (optional)
Add soderlind/wordpress-github-updater via Composer and callGitHubUpdater::init() in your main file, exactly like the rest of the family — see any add-on's bootstrap for the pattern.
Requires Plugins: kjeks header · ② one-line function_exists() guard · ③ register onkjeks_register_integrations · ④ (if needed) sync via kjeks:granted/kjeks:withdrawn · ⑤ settings + a config filter · ⑥ verify with thescanner that nothing loads before consent.Study the full example in the kjeks-google repository, and see the core developer guide for the complete integration API.