Title: Hafenstudios Ads – Ad Manager, AdSense &amp; Banner Ads
Author: hafenstudios
Published: <strong>ଜୁଲାଈ 30, 2026</strong>
Last modified: ଅଗଷ୍ଟ 28, 2026

---

Search plugins

![](https://ps.w.org/hafenstudios-ads/assets/banner-772x250.png?rev=3650300)

![](https://ps.w.org/hafenstudios-ads/assets/icon-256x256.png?rev=3628546)

# Hafenstudios Ads – Ad Manager, AdSense & Banner Ads

 By [hafenstudios](https://profiles.wordpress.org/hafenstudios/)

[Download](https://downloads.wordpress.org/plugin/hafenstudios-ads.2.5.0.zip)

 * [Details](https://ory.wordpress.org/plugins/hafenstudios-ads/#description)
 * [Reviews](https://ory.wordpress.org/plugins/hafenstudios-ads/#reviews)
 *  [Installation](https://ory.wordpress.org/plugins/hafenstudios-ads/#installation)
 * [Development](https://ory.wordpress.org/plugins/hafenstudios-ads/#developers)

 [Support](https://wordpress.org/support/plugin/hafenstudios-ads/)

## Description

Hafenstudios Ads is an ad manager for WordPress: place banner ads, AdSense units
and any ad code exactly where you want them, rotate them, target who sees them, 
and keep an eye on impressions, clicks and CTR — without sending any analytics to
an external server.

Create multiple ad blocks, insert them automatically before or after the content,
after paragraph N or by shortcode, widget and Gutenberg block. Weighted ad rotation,
split testing, device and post-type targeting, campaign scheduling and consent gating
are built in.

#### Highlights

 * Split test two ad variants against each other: every variant with impressions,
   clicks and CTR, a data progress gauge, and a mark on the one that is ahead.
 * Weighted ad rotation, cache-proof: blocks sharing a group name rotate in automatic
   placements and via `[adjet_ad_group name="header"]`; the winner is picked in 
   the visitor’s browser, so page caches cannot freeze the choice.
 * AdSense Wizard: Publisher-ID + Slot-ID are enough for responsive AdSense units,
   including in-article and multiplex formats.
 * Nothing leaves your server: no external calls, no phoning home, statistics stay
   in your own database.
 * Template gallery with 27 free templates: banners, native cards, testimonial, 
   book/course card, seasonal deals, events, sponsor logo wall, notification bars,
   popups and a cookie consent banner with selectable cookie images.
 * Automatic placements before content, after content, after paragraph N, in the
   middle of the content, before the last paragraph, after heading N or after the
   first image.
 * Manual placement via shortcode `[adjet_ad id="1"]`, widget or Gutenberg block.
 * Clean, focused admin interface with brand bar, weekly summary and clear navigation
   tabs.
 * Device targeting for desktop, tablet and mobile.
 * Post type targeting plus exclusions for posts, categories, tags and custom terms.
 * Optional “Advertisement” label with editable text.
 * Lazy loading via IntersectionObserver.
 * Consent-cookie gating for common consent tools.
 * Optional anonymous local impression and click statistics.
 * Campaign scheduling with optional start and end time.
 * One-click duplicate and pause/activate actions for faster workflow.
 * Code editor and admin-side live preview that does not execute scripts.
 * AdSense Wizard: Publisher-ID + Slot-ID are enough for responsive AdSense units.
 * Optional AdSense Auto Ads script loader with clear settings.
 * 30-day statistics chart (impressions and clicks) rendered inline, no external
   libraries.
 * Weekly summary above the ad block list: impressions, clicks and CTR since Monday,
   compared with the same weekday span of the previous week.
 * Least-privilege capability `manage_adjet` with an optional editor-access toggle.
 * Premium templates and features unlock with Pro.
 * REST API (`adjet/v1`) for ad blocks, stats and settings via Application Passwords.
 * Guided assistant with optional AI copy suggestions (bring your own Anthropic 
   Claude key).
 * Built-in cookie-consent banner template with Google Consent Mode v2 support.
 * Native newsletter opt-in for SendFox, MailerLite, Brevo, Mailchimp and Kit (ConvertKit),
   bring your own token, with double opt-in.
 * First-run onboarding that routes you to AdSense, a template or your own HTML.
 * JSON import and export with file-size/type checks.
 * Uninstall routine that keeps your data unless you explicitly ask for it to be
   deleted.

#### Privacy

The plugin does not contact hafenstudios servers from the WordPress admin area or
frontend. Optional statistics are stored locally in your own WordPress database.
Third-party ad code pasted into an ad block may contact external services; configure
your consent solution accordingly.

#### External services

The plugin works fully without any external service. Every integration below is 
optional and only ever runs when you explicitly enable it:

 * Google AdSense (frontend): if you configure an AdSense ad unit or enable Auto
   Ads, the frontend loads Google’s `adsbygoogle.js` from `pagead2.googlesyndication.
   com` to display ads. Terms: https://www.google.com/adsense/localized-terms — 
   Privacy: https://policies.google.com/privacy
 * Anthropic Claude (admin only, bring-your-own-key): the optional AI buttons send
   data to the Anthropic API (`api.anthropic.com`), each only after you enter your
   own Anthropic API key in the settings and click that button; no key, no request,
   never automatic. What each button sends: the “AI suggestions” button in the ad
   assistant sends the template’s field labels, your site name/description and any
   brief you type to generate draft ad copy; the “Suggest alt text” button sends
   the selected ad image (from your media library as encoded image data, otherwise
   as its URL) to describe it; the “Let the AI read the numbers” button on the statistics
   page sends aggregated daily totals, weekly totals and per-block impression/click
   counts. No visitor data, IP addresses or e-mail addresses are ever sent. The 
   key is stored encrypted and used server-side only. Terms: https://www.anthropic.
   com/legal/commercial-terms — Privacy: https://www.anthropic.com/legal/privacy
 * SendFox (bring-your-own-token): if you connect SendFox in the settings and use
   the “Newsletter (SendFox)” template, visitor email addresses submitted through
   that form are sent to the SendFox API (`api.sendfox.com`) to be added to your
   list. This happens only when you have connected a SendFox access token. The token
   is stored encrypted and used server-side only. Terms: https://sendfox.com/tos—
   Privacy: https://sendfox.com/privacy
 * MailerLite (bring-your-own-token): if you connect MailerLite in the settings 
   and use the “Newsletter (MailerLite)” template, visitor email addresses submitted
   through that form are sent to the MailerLite API (`connect.mailerlite.com`) to
   be added to your group. This happens only when you have connected a MailerLite
   API token. The token is stored encrypted and used server-side only. Terms: https://
   www.mailerlite.com/legal/terms-of-service — Privacy: https://www.mailerlite.com/
   legal/privacy-policy
 * Brevo (bring-your-own-token): if you connect Brevo in the settings and use the“
   Newsletter (Brevo)” template, visitor email addresses submitted through that 
   form are sent to the Brevo API (`api.brevo.com`). With a double opt-in template
   and redirect URL configured in the settings, the signup uses Brevo’s double opt-
   in endpoint (`/contacts/doubleOptinConfirmation`) and Brevo sends the confirmation
   mail; without them the contact is created directly and no confirmation mail is
   sent, which the form’s success message states honestly. This happens only when
   you have connected a Brevo API key. The key is stored encrypted and used server-
   side only. Terms: https://www.brevo.com/legal/termsofuse/ — Privacy: https://
   www.brevo.com/legal/privacypolicy/
 * Mailchimp (bring-your-own-token): if you connect Mailchimp in the settings and
   use the “Newsletter (Mailchimp)” template, visitor email addresses submitted 
   through that form are sent to the Mailchimp API (`<dc>.api.mailchimp.com`, the
   data center encoded in your API key) to be added to your audience with status“
   pending”, which triggers Mailchimp’s double opt-in. This happens only when you
   have connected a Mailchimp API key. The key is stored encrypted and used server-
   side only. Terms: https://mailchimp.com/legal/terms/ — Privacy: https://www.intuit.
   com/privacy/statement/
 * Kit, formerly ConvertKit (bring-your-own-token): if you connect Kit in the settings
   and use the “Newsletter (Kit)” template, visitor email addresses submitted through
   that form are sent to the Kit API (`api.kit.com`) to create or update the subscriber
   and add them to your chosen Kit form; if the form has double opt-in enabled, 
   Kit sends its confirmation email. This happens only when you have connected a
   Kit v4 API key. The key is stored encrypted and used server-side only. Terms:
   https://kit.com/terms — Privacy: https://kit.com/privacy

#### Security

The plugin uses capability checks, nonces for form actions, sanitization on save
and escaping on output. Raw ad code is only stored unchanged for users with the `
unfiltered_html` capability.

#### Localization

 * Source language: English.
 * Included translations: German, Spanish, French and Dutch — complete and shipped
   with the plugin.

#### Support

This plugin is developed and maintained by hafenstudios. For direct support you 
can reach us by e-mail at moin@hafenstudios.com or by phone at +49 174 3935796. 
You are also welcome to use the plugin support forum on WordPress.org.

## Screenshots

[⌊Every ad block at a glance: impressions, clicks and click rate, sortable by any
column.⌉⌊Every ad block at a glance: impressions, clicks and click rate, sortable
by any column.⌉[

Every ad block at a glance: impressions, clicks and click rate, sortable by any 
column.

[⌊Hold back third-party scripts until visitors consent. Every rule starts in trial
mode and only logs what it would block, so you see what runs on your site before
anything changes.⌉⌊Hold back third-party scripts until visitors consent. Every rule
starts in trial mode and only logs what it would block, so you see what runs on 
your site before anything changes.⌉[

Hold back third-party scripts until visitors consent. Every rule starts in trial
mode and only logs what it would block, so you see what runs on your site before
anything changes.

[⌊The consent banner assistant: text, cookie image, animation and Google Consent
Mode v2, without touching any code.⌉⌊The consent banner assistant: text, cookie 
image, animation and Google Consent Mode v2, without touching any code.⌉[

The consent banner assistant: text, cookie image, animation and Google Consent Mode
v2, without touching any code.

[⌊The template gallery with filter and search: pick a purpose, fill in the fields,
no HTML needed.⌉⌊The template gallery with filter and search: pick a purpose, fill
in the fields, no HTML needed.⌉[

The template gallery with filter and search: pick a purpose, fill in the fields,
no HTML needed.

[⌊Split test two variants against each other, free of charge, with an honest data
gauge instead of a made-up winner.⌉⌊Split test two variants against each other, 
free of charge, with an honest data gauge instead of a made-up winner.⌉[

Split test two variants against each other, free of charge, with an honest data 
gauge instead of a made-up winner.

[⌊Local statistics: 30 days, rendered on your own server, including the clicks that
click protection did not count.⌉⌊Local statistics: 30 days, rendered on your own
server, including the clicks that click protection did not count.⌉[

Local statistics: 30 days, rendered on your own server, including the clicks that
click protection did not count.

[⌊The AdSense assistant: publisher ID, slot and format, nothing else.⌉⌊The AdSense
assistant: publisher ID, slot and format, nothing else.⌉[

The AdSense assistant: publisher ID, slot and format, nothing else.

## Blocks

This plugin provides 1 block.

 *   Hafenstudios Ads

## Installation

 1. Upload the ZIP via Plugins > Add New > Upload Plugin.
 2. Activate the plugin.
 3. Open the new “Hafenstudios Ads” menu and create your first ad block.
 4. Optional: configure the ad label, consent-cookie settings and local statistics.

Upgrading from “AdEngine – Free Ad Inserter & Manager”? Just install this plugin—
your ad blocks, settings and statistics are migrated automatically on first load.

## FAQ

### Does this plugin work with AdSense?

Yes. You can either paste original AdSense code as custom code or use the AdSense
Wizard with your Publisher-ID and Slot-ID. The plugin then generates a responsive
ad unit and loads the AdSense script on the frontend when needed.

### Can I use it manually?

Yes. Use the shortcode `[adjet_ad id="1"]`, the shortcode `[adjet_ad_group name="
header"]`, the included widget or the Gutenberg block.

### Does it replace a consent tool?

No. The plugin can wait for a configured consent cookie, but it does not provide
legal advice or a cookie banner.

### Does this plugin track users externally?

No. The optional statistics feature stores anonymous aggregated counts locally in
your WordPress database.

### Does the AI feature send data anywhere?

Only when you use it. The AI is the one deliberate exception to “no external calls”:
it runs only after you store your own Anthropic API key and click a button – one
click, one request, never automatic. Depending on the button, the request carries
the template’s field labels, your site name and description, the brief you type,
the selected ad image (alt-text suggestion) or aggregated statistics totals (statistics
summary). It never sends visitor data, IP addresses, e-mail addresses or page content,
and your key is stored encrypted and never leaves your server.

### Can editors manage ads without being administrators?

Yes. Enable “Editor access” in Settings to grant the `manage_adjet` capability to
the editor role. Administrators always have access.

### What happens to my data when I uninstall the plugin?

Nothing is deleted unless you ask for it. The setting “Delete all data on uninstall”
is off by default, so removing the plugin leaves your ad blocks, settings and the
statistics table in place and a later reinstall picks them up again. Switch the 
setting on before uninstalling if you want the options, the statistics table and
the `manage_adjet` capability removed for good.

### Is there a REST API?

Yes. The `adjet/v1` namespace exposes ad blocks (`/blocks`, CRUD), statistics (`/
stats`) and settings (`/settings`). Authenticate with an Application Password; access
requires the `manage_adjet` capability.

## Reviews

![](https://secure.gravatar.com/avatar/12eb206f8b6eee390a264921c9e1c3a0312be1c3dab1976c97c8dea5a549d7a6?
s=60&d=retro&r=g)

### 󠀁[Muito bom!](https://wordpress.org/support/topic/muito-bom-2006/)󠁿

 [jotasilva](https://profiles.wordpress.org/jotasilva/) ଅଗଷ୍ଟ 18, 2026

Descobri o plugin agora, estou achando excelente

![](https://secure.gravatar.com/avatar/6bba3442f737b8cf2cdab61d90bc2877ea5177391ca1b529d865477947aa85fd?
s=60&d=retro&r=g)

### 󠀁[Super tool](https://wordpress.org/support/topic/super-tool-85/)󠁿

 [kfschuppo](https://profiles.wordpress.org/kfschuppo/) ଅଗଷ୍ଟ 17, 2026

Ein tolles tool

![](https://secure.gravatar.com/avatar/e8710c8b31ac5e463842065a3b11e3d2a2a00d37fe20db22e7b07644b8cdbb22?
s=60&d=retro&r=g)

### 󠀁[Great Stuff](https://wordpress.org/support/topic/great-stuff-464/)󠁿

 [marceliriecker](https://profiles.wordpress.org/marceliriecker/) ଅଗଷ୍ଟ 14, 2026

Automatic A-B Splittesting caught my attention. Really helpful and great stuff.

![](https://secure.gravatar.com/avatar/248c06251cfbf3bfd0e23312a9cd9b5301827f3ee764c82d609173ff879f4188?
s=60&d=retro&r=g)

### 󠀁[Top PlugIns+kostengünstig+effizient-Ein Muss!](https://wordpress.org/support/topic/top-pluginskostengunstigeffizient-ein-muss/)󠁿

 [pintemuc](https://profiles.wordpress.org/pintemuc/) ଅଗଷ୍ଟ 14, 2026

hervorragende effiziente und hilfreiche PlugIns. Selbst die Pro Version ist unfassbar
kostengünstig und wirklich super einfache und verständliche Handhabung. Kann ich
nur empfehlen. Mein spart Zeit und Geld und erhält direkt einen Mehrwert.

![](https://secure.gravatar.com/avatar/45fa9321a4607ec572da81465c67f4c663ef7690d3ced50abd4e248f522ebc49?
s=60&d=retro&r=g)

### 󠀁[Powerful free ad tool](https://wordpress.org/support/topic/powerful-free-ad-tool/)󠁿

 [rokrking](https://profiles.wordpress.org/rokrking/) ଅଗଷ୍ଟ 14, 2026

An excellent experience using this plugin for my niche site. Setting up Adsense 
is too simple.

![](https://secure.gravatar.com/avatar/36bd255c7dd04fd1b37b20c995d716f330f4e96e36507259d5f54cbf897ac6f6?
s=60&d=retro&r=g)

### 󠀁[Nice 4 managing ads](https://wordpress.org/support/topic/nice-4-managing-ads/)󠁿

 [papkeconsulting](https://profiles.wordpress.org/papkeconsulting/) ଅଗଷ୍ଟ 13, 2026

This Plugin ist Nice for managing ads in wordpress

 [ Read all 14 reviews ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/)

## Contributors & Developers

“Hafenstudios Ads – Ad Manager, AdSense & Banner Ads” is open source software. The
following people have contributed to this plugin.

Contributors

 *   [ hafenstudios ](https://profiles.wordpress.org/hafenstudios/)

“Hafenstudios Ads – Ad Manager, AdSense & Banner Ads” has been translated into 1
locale. Thank you to [the translators](https://translate.wordpress.org/projects/wp-plugins/hafenstudios-ads/contributors)
for their contributions.

[Translate “Hafenstudios Ads – Ad Manager, AdSense & Banner Ads” into your language.](https://translate.wordpress.org/projects/wp-plugins/hafenstudios-ads)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/hafenstudios-ads/),
check out the [SVN repository](https://plugins.svn.wordpress.org/hafenstudios-ads/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/hafenstudios-ads/)
by [RSS](https://plugins.trac.wordpress.org/log/hafenstudios-ads/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 2.5.0

 * Fixed: the templates now speak the language of your site. The close button, the
   consent banner’s screen-reader name and the e-mail placeholder were written into
   the markup in German, so a French site showed a German example address in its
   sign-up form despite seven bundled translations.
 * New: overlays can be operated by keyboard. Escape closes a pop-up or exit overlay,
   the focus stays inside while it is open and returns where it came from afterwards.
   Both are announced as dialogs. The consent banner is deliberately exempt: a consent
   decision must not be dismissed by accident.
 * New: click protection. The plugin caps how often one browser can click your ads:
   out of the box at most 3 clicks on the same block and 10 in total per visitor
   and 24 hours, both adjustable. Above the limit the click is either no longer 
   counted or the block stays away from that visitor, your choice. The statistics
   show how many clicks the protection did not count, so it never looks like a counting
   bug.
 * Nothing about your visitors is stored for this: no IP address, in clear text 
   or otherwise, only a shortened and salted hash, for at most 24 hours, inside 
   your own installation. Nothing is sent anywhere, no list of known bots is fetched
   from outside, and the decision falls while counting the click, so page caches
   never notice. Uninstalling takes this data with it either way.
 * Fixed: two older statistics helpers hashed visitor addresses without a salt. 
   They now use the same salted, shortened hash as everything else.
 * The free edition no longer shows the internal working name anywhere in the interface.
 * New: a “No automatic ads on this post” switch right in the editor, in the sidebar
   or as a meta box. It only removes the automatic placements: shortcode, widget
   and block stay, because someone placed those on purpose.
 * New: with WooCommerce you can now target product pages and the shop page directly.
   Cart and checkout stay free of ads until you tick them yourself, even for blocks
   that otherwise run everywhere.
 * New: two switches under “Advanced” for every ad with a link. “Mark as advertising”(
   rel=”sponsored nofollow”) is on by default, because that is Google’s requirement
   for paid links, and “Open in a new tab” always adds rel=”noopener”.
 * New: a whole rotation group can now stand in when AdSense leaves a slot empty,
   not just a single ad. The browser picks the variant, exactly one is counted.
 * New: per ad you can choose what happens when an ad blocker prevents it: quietly
   show another block instead of nothing. No plea to switch the ad blocker off, 
   and the default stays “show nothing”.
 * New: the ad list is sortable. Click Name, Status, Placement, Impressions, Clicks
   or CTR to order the table, click again to flip the direction. Impressions descending
   is always the starting point, and the choice is never remembered. Names with 
   an umlaut or accent sort where you look for them.
 * Stand-in ads follow the same rules as any other ad: scheduling, device selection
   and “logged-in users only” apply to them too, so an expired campaign no longer
   keeps running as a stand-in. A script inside a stand-in really runs after the
   swap.
 * Improved: for placements inside the content the editor only offers the page types
   that actually apply there. No more checkboxes that do nothing.
 * Improved: the diagnosis view (?adjet_debug=1) now also explains the new cases:
   the per-post switch, cart and checkout, and why no stand-in could be shown.
 * Improved: consent banners stay out of the ad ranking, and the split test data
   gauge says “Data threshold reached” instead of “442 of the 100 impressions it
   needs”.
 * Note: existing ads keep their ad code unchanged, so the two link switches take
   effect once you save the ad. The assistant says so as soon as you open it.
 * New: hold back third-party scripts such as tracking pixels until your visitors
   have given consent. You write every rule yourself, each one starts in trial mode
   and at first only logs what it would block, and you arm them one at a time. Scripts
   from your own domain and WordPress core scripts stay exempt, and an emergency
   brake releases everything again.
 * New: a consent traffic light on the dashboard. It tells you when ads are running
   without a banner, or when a banner exists but Consent Mode v2 is missing, and
   a button next to it creates the banner from the template.
 * New: consent sources. The plugin can exchange decisions with the WP Consent API
   and adopt the signals of an IAB TCF 2.x banner, so a banner you already run counts
   like the built-in one.
 * New for advanced setups, off by default: “preload Google tags” (advanced consent
   mode). It only switches on together with an explicit confirmation and carries
   a plain note on §25 TDDDG. Only pure Google tags load early; every other script
   that requires consent keeps waiting.
 * Consent banner: Decline is now just as prominent as Accept, same size and weight,
   only the colour differs. Banners you saved earlier are corrected as well.
 * Consent banner: optional entrance animation (switched off automatically for reduced
   motion), four bundled cookie images and four text suggestions from snappy to 
   elegant.
 * The consent default-state script can no longer be pushed behind your tracking
   tags by optimisation plugins, and a new check reports it when another snippet
   still loads first.
 * Without JavaScript the consent banner now disappears instead of standing there
   unusable.
 * Overlays: the frequency setting (once per session, once per day) is part of the
   free version now.
 * Blocks with a stored Pro trigger no longer fail silently: the block list and 
   the editor say that the template default applies instead.
 * The short date in the statistics follows your site language now; it always used
   the German format before.

#### 2.4.1

 * Clean plugin screens: promotional and notice banners from other plugins (e.g.
   security or shop plugins) no longer appear in the middle of the plugin’s admin
   pages – not above the form, not inside the settings or split-test screens. The
   plugin’s own messages such as “Saved” remain visible, of course. All other WordPress
   admin pages are left untouched.
 * URL fields in the assistant and settings now accept relative paths (e.g. /privacy/)
   and “#” – previously the browser silently blocked saving, even with the consent
   template’s own default value. If an invalid field ever blocks submission again,
   a red hint now appears right below the field and the page scrolls to it. The 
   active checkbox for the cookie consent banner is now labeled “Show the banner(
   active)” instead of “Serve this ad immediately (active)”.
 * Template gallery: the 38 template cards can now be filtered – a chip bar with
   every category (collected dynamically from the catalog, “All” preselected), live
   search across name and description, plus a “Free only” chip. All filters combine,
   run entirely client-side and are accessible (chips are real buttons with aria-
   pressed); zero matches show a friendly hint instead of an empty wall.
 * Cleaned up: the ad CSS (~3 KB) now only loads when your installation can actually
   serve anything – pages of an install without a single enabled block, without 
   Auto Ads and outside the diagnosis view skip it entirely. Faster: when AdSense
   loads without a consent gate, the browser now pre-connects to Google’s ad server(
   preconnect + dns-prefetch) so ads appear sooner; behind a consent banner the 
   early Google contact is deliberately skipped. Leaner: internal housekeeping options
   no longer travel with every page load (autoload off, with an automatic one-time
   migration for existing installs). Pro additionally: the recommendation card and
   the product box now hide empty image placeholders just like the other templates.

#### 2.4.0

 * Six new templates, all free: a testimonial ad, an in-feed native card for post
   lists, a book/course card with star rating and price note, a seasonal deal banner(
   Black Friday, Christmas, Easter, Summer) with a copy-to-clipboard code and optional
   countdown, an event announcement that hides itself after the start, and a sponsor
   logo wall. All use the assistant fields, the media picker and the date picker;
   empty optional images, codes and timers are hidden automatically.
 * New: ads.txt. Paste your ads.txt lines into the settings and the plugin serves
   them at /ads.txt (a physical file in the web root always wins). A suggested line
   is built from your AdSense Publisher ID. AdSense warns in your account when ads.
   txt is missing; now it is a text field.
 * New: reserve space against layout shift. Every block can reserve a minimum height
   before the ad loads, and the AdSense assistant suggests the usual heights per
   format. Lazy loading no longer costs you Core Web Vitals.
 * New: ads without consent, your call. An AdSense setting serves non-personalised
   ads while consent is missing or declined (Google’s NPA flag, Consent Mode v2 
   stays as it is). Off by default; the setting text says what it means in the EU.
 * New: fallback for empty AdSense slots. Pick another block that appears when Google
   leaves the slot unfilled; the swap happens in the browser when AdSense reports
   it.
 * New: load ad scripts on first interaction (scroll, tap, key press, at the latest
   after 5 seconds). Off by default.
 * New: page-type targeting for overlays, manual placements and in-feed ads: front
   page, blog index, archives, search, 404, author pages. Empty means everywhere,
   as before.
 * New: visibility by login state and role. “Everyone”, “logged-out visitors only”
   or “logged-in users only”, plus a list of roles to hide the block for. The old“
   logged-out only” switch carries over.
 * New: three content positions, middle of the content, before the last paragraph,
   and after heading N.
 * New: sticky option for manual placements (widget, shortcode, block): the ad keeps
   its position while the visitor scrolls, with an adjustable top offset.
 * New: “Why isn’t the ad showing here?” Open any page of your site with ?adjet_debug
   =1 while logged in, and wherever a block is not shown you (and only you) see 
   a note with the first reason: post type, page type, schedule, word count, consent,
   device and so on. Nothing of this reaches visitors or page caches.
 * New: statistics export as CSV (semicolon-separated, Excel-friendly) for the selected
   period.
 * New: import from Ad Inserter and Advanced Ads on the Tools page. Blocks, names
   and placements are carried over; rules without a counterpart are listed after
   the import; everything arrives paused; a second import creates no duplicates.

#### 2.3.2

 * New: pick images from the media library. The image field of the image banner 
   template gets a “Choose from media library” button with a thumbnail and a remove
   link; the URL field stays for external images, and the library’s alt text fills
   the alt field while it is empty. Suggested by the WordPress 103 video review.
 * New: real date pickers. The countdown’s target date is a date-and-time field 
   instead of a text box with a format hint, and scheduling (start and end) is now
   available inside the template assistant under “Advanced”, with the site’s timezone
   spelled out; the end can no longer be set before the start. Stored values keep
   their format, existing ads are unaffected.
 * New: more design without leaving the template. “Advanced” in the assistant now
   holds alignment, maximum width, margin and an optional “Custom CSS” field whose
   selectors are limited to that one block automatically, media queries included,
   so nothing else on the site changes. The same fields sit in the full editor.
 * Changed: the way from a template to your own HTML. The old “Edit the HTML yourself”
   link dropped the template and its fields for good. It is now a visible card that
   opens a copy of the ad in the HTML editor (or the expert editor for AdSense);
   the template ad stays exactly as it is and the copy starts paused. The assistant’s
   header says so up front.
 * Changed: “Left” and “Right” alignment now also move a template’s centred root
   element to that side; before, it only changed the text alignment inside.
 * Fixed: the “Recommended” badge on the AdSense Wizard card was hard-coded as German“
   Empfohlen” inside the stylesheet and therefore showed in German on every site.
   It is now translatable markup, translated in all seven bundled languages.
 * Housekeeping: the changelog had grown past the 5,000 words WordPress.org displays.
   Entries up to 2.1.1 moved to changelog.txt inside the plugin folder.

#### 2.3.1

 * Fixed: the cookie consent banner flashed on every page view, even for visitors
   who had decided long ago. The banner markup ships with every page on purpose –
   a page cache serves the same HTML to everybody, so the server cannot know the
   cookie – and frontend.js removes it in the browser. The starting state was the
   wrong way round, though: the banner carries an inline display:flex and sits far
   ahead of the script that takes it away (measured on a live shop: banner at 69%
   of the document, frontend.js at 94 %, no defer, some 100 KB of HTML and several
   hundred KB of scripts in between). Hafenstudios Ads now prints a tiny inline 
   snippet at the very top of the head that hides the banner right away when a decision
   is already stored. The banner itself stays visible by default on purpose: hiding
   it in the template and revealing it by script would look shorter, but frontend.
   js sits under plugins/hafenstudios-ads/ and ad blockers reliably block that path–
   the banner would never appear for exactly those visitors who care most about 
   privacy, leaving them no way to consent at all.
 * Fixed: the flash also hit installations that do not use the consent template.
   A banner can just as well run as a plain HTML block – copied from the template
   once, maintained by hand since, or several versions running against each other
   in a split test. Hafenstudios Ads now recognises banner markup in block code 
   too, so those installations get the fix as well.

#### 2.3.0

 * Fixed, and this one changes your numbers: impressions are no longer booked for
   overlays nobody saw. The visibility check used to fall back to the block’s invisible
   zero-height wrapper whenever overlay code starts with a style tag. In 2.1.x that
   booked thousands of impressions for popups that never opened; since 2.2.0 it 
   booked none at all, even when they did open, which is why overlay blocks could
   show more clicks than impressions. The observer now finds the fixed overlay element
   itself and never counts a target without a visible area. Expect overlay impression
   counts to drop where they were phantom counts and to come back where they had
   vanished; from now on they mean “the overlay was actually on screen”.
 * Fixed: clicking into an opt-in form’s e-mail field, correcting a typo or closing
   a popup no longer counts as an ad click. Only links, buttons and submit controls
   count, and at most one click per block and page view. Opt-in blocks used to reach
   a “CTR” above 100 percent this way; expect click counts to drop and the rate 
   to become meaningful.
 * Fixed: a split test now knows when it started. Every rotation group gets a start
   date the day it is formed, and the split test page counts from that day, never
   earlier, so numbers a block collected before it became a variant no longer distort
   the comparison. Tests that already existed are stamped with today’s date the 
   first time the page is opened, and the page states the date it counts from.
 * Safety net for rotation groups: an undecided group can no longer book an impression
   on any code path; only the variant the browser picked counts.
 * New on the split test page: a data gauge. The needle shows how much data the 
   test has collected, measured by the weakest running variant against the 100-impression
   threshold. The confidence zones stay greyed out with a lock; whether the lead
   is solid is what Hafenstudios Ads Pro works out, and the free line keeps refusing
   to claim significance it cannot check.
 * Changed: consent banners moved out of the ad statistics into their own “System”
   section on the ad list and the statistics page, with the columns “Decisions” 
   and “Decision rate”. A banner is answered, not clicked: its 27-percent “CTR” 
   was a consent quote wearing the wrong label, and as the only site-wide block 
   it dominated every total. The weekly summary and the top block now count real
   ads only. Free counts accepting and declining as the same decision; the actual
   consent rate remains part of Pro’s consent statistics.
 * New: an honest warning on overlay blocks that can never appear. Custom overlay
   code that starts hidden and carries none of the free triggers used to run invisibly
   for weeks without a word. The block list and the editor now say so, with the 
   two attributes (data-adjet-popup, data-adjet-exit) that fix it. Popup and exit
   templates keep their trigger attribute on the root element, even through “edit
   the HTML yourself”.
 * New: a frequency cap for overlays, stored per day in the visitor’s browser. A
   popup or exit overlay shows at most once per day, and a closed overlay, bars 
   included, stays away for the rest of the day. The close button now also works
   inside overlays built from custom code.
 * New: two cards in the moments system. When two or more active blocks share a 
   placement without a rotation group, one click lets them compete, which is all
   it takes to start a split test. And when the evaluated test has collected enough
   data, a card names the leading variant, the gap, and what the Pro autopilot would
   do now.
 * Fixed for Google Consent Mode v2: while the built-in consent banner is active,
   the consent DEFAULT (denied) is now printed early in the head, before any gtag.
   js, and an already stored decision is replayed on every page view. Until now 
   the only signal was the update pushed by the banner’s buttons: GA4 ran unrestricted
   from page load, Google’s Tag Assistant reported the update as arriving before
   a default, and a visitor’s decision lasted exactly one page view.
 * Brevo signups can now use Brevo’s real double opt-in: store the ID of a Brevo
   double opt-in template plus a redirect URL in the settings and signups run through
   Brevo’s DOI flow, confirmation mail included. Without those fields the contact
   is created directly, exactly as before, but the form now answers “You are signed
   up.” instead of promising a confirmation mail that never existed. Both paths 
   keep the 2.2.0 rule that the answer never reveals whether an address is already
   on your list.

#### 2.2.0

 * New: a “Split-Tests” page that reads one of your rotation groups as an A/B test.
   Ad blocks sharing a group name have been rotating and counting per block for 
   a while, but nowhere could you see the variants side by side. The page lists 
   every variant of the group with its status, weight, impressions, clicks and CTR,
   and marks the one that is ahead. Nothing new is measured, nothing is sent anywhere,
   and no API key of any kind is involved.
 * “Ahead right now” appears only once two running variants have at least 100 impressions
   each in the selected period and their rates actually differ. One variant over
   the threshold while the other has three impressions names nobody, and neither
   does a tie. The size of the lead is printed underneath in percentage points, 
   because a lead of one single click looks exactly like a lead of five points otherwise.
   Whether that lead will hold is a question of significance, which is what Pro 
   answers, together with the uplift, taking the winner over with one click and 
   an AI suggestion for the next variant.
 * A group counts as a test when its blocks share a group name AND a placement. 
   That is how the rotation works: in automatic placements only blocks with the 
   same placement take turns, everything else appears on the page at the same time.
   Two blocks of one group in different placements are therefore not competing, 
   and putting them side by side as variants would compare positions rather than
   variants. The shortcode `[adjet_ad_group name="header"]` is unaffected, it rotates
   the whole group, and those blocks all carry the placement “manual”.
 * You can run as many rotation groups as you like, as always. One of them is evaluated
   on the page, and you pick which one with a single click. Without a pick it is
   the test you created first, which cannot move under you when a group is renamed.
 * Rotation groups that contain a cookie banner are shown but not judged: the banner’s
   buttons set a cookie instead of counting as a click, so its CTR would report 
   a perfectly good banner as the loser. The page says so instead of pretending 
   otherwise.
 * Paused variants stay in their group with their numbers, so pausing one does not
   delete half the test from view. They cannot be “ahead right now”, though: a variant
   that is not being served is not running against anything, and its numbers stop
   while the others keep counting.
 * Changed, please read this one: an address that is already on your newsletter 
   list now gets exactly the same confirmation as a brand new one. Until now the
   form printed the answer of your newsletter provider word for word, and that answer
   says out loud whether an address is already a member. Anyone could have typed
   addresses into your form one after another and read off who is on your list. 
   The form no longer tells the two cases apart at all, which is also all that a
   provider with double opt-in reveals to the outside. What that costs you: a visitor
   who mistypes and hits someone else’s address still reads “please confirm your
   signup”. The message now means “we handed this over to your provider”, not “this
   address is new”.
 * Fixed: the signup form no longer shows a single word written by your newsletter
   provider. Whatever SendFox, MailerLite, Brevo, Mailchimp or Kit answers stays
   on your server. Visitors read your own sentence, in the language of your site,
   instead of an English developer message such as “is already a list member. Use
   PUT to insert or update list members.”
 * Fixed: connection problems no longer put technical detail in front of visitors.
   A failed lookup used to show the cURL error and the host name of your provider
   inside the form.
 * Changed: the same neutral answer covers every rejection your provider sends back
   about a submission, not only the two status codes Mailchimp happens to use for
   a duplicate. A rule that neutralises 400 and 422 alone re-opens the same hole
   the day a provider answers “already a member” with 409 instead. The deliberate
   price: a genuinely broken setup, for example a required merge field your form
   does not send or a list deleted at the provider, now also looks like a success
   from the front. That is why every one of those cases is written to the log described
   below and shown as a warning on the ad block overview. Throttling by your provider(
   429), a provider outage and a rejected token stay errors, because none of them
   depend on the address that was entered.
 * Fixed: the status code of the signup endpoint now says what actually happened.
   Everything the provider answers about a submission is a normal 200. There are
   three error states and they mean what they say: 503 the provider answered but
   cannot deliver right now, 502 the request never reached the provider at all, 
   and 500 something in your own setup is wrong (no token, no list picked, token
   rejected) and will not fix itself by waiting. If you monitor 502 responses, expect
   them to nearly disappear.
 * New: the ad block overview shows the last signup that did not go through, with
   the date, the provider, the status code and the provider’s own words. That is
   where the detail went that visitors no longer see, so a broken connection cannot
   stay hidden behind a friendly confirmation. E-mail addresses in that message 
   are masked. The duplicate case is deliberately not listed there: it is not a 
   failure, it is the most frequent thing that happens to a public form, and it 
   would push the rare configuration error out of that single slot.
 * Fixed: with Kit, an address that was already known could end the signup halfway.
   Kit is told about the subscriber first and only then about the form, and only
   that second step sends the confirmation mail. A known address stopped the first
   step, so the visitor got an error and no mail. Both steps now run, and a real
   problem in that first step is written to the log instead of disappearing. Kit’s
   own wording arrives there too: Kit reports its reasons in a field the plugin 
   did not read, so every Kit problem used to be logged as a bare status code.
 * Fixed for Brevo: a signup with an address Brevo already had would quietly add
   that person to the list you configured, including someone who had unsubscribed
   from exactly that list, and Brevo sends no confirmation mail at this step. The
   plugin no longer updates existing contacts. New contacts are created as before,
   and a known address is answered by Brevo with an error that counts as a success
   towards the visitor, so nothing changes for them.
 * Fixed: the honeypot answer. A submission caught by the hidden anti-bot field 
   was answered with a slightly different body than a real signup, which made the
   trap detectable in a single request. Both answers are now byte for byte identical.
 * Fixed: the three fallback texts of the signup form (“Thank you!”, “Something 
   went wrong.”, “Connection failed. Please try again later.”) were built into the
   JavaScript file and could never be translated. They now come from the server,
   translated like every other text.

Older entries (2.1.1 and earlier) live in changelog.txt inside the plugin folder.

## Meta

 *  Version **2.5.0**
 *  Last updated **2 days ago**
 *  Active installations **100+**
 *  WordPress version ** 6.2 or higher **
 *  Tested up to **7.1**
 *  PHP version ** 7.4 or higher **
 *  Languages
 * [English (US)](https://wordpress.org/plugins/hafenstudios-ads/) and [German](https://de.wordpress.org/plugins/hafenstudios-ads/).
 *  [Translate into your language](https://translate.wordpress.org/projects/wp-plugins/hafenstudios-ads)
 * Tags
 * [adsense](https://ory.wordpress.org/plugins/tags/adsense/)[consent](https://ory.wordpress.org/plugins/tags/consent/)
   [dsgvo](https://ory.wordpress.org/plugins/tags/dsgvo/)
 *  [Advanced View](https://ory.wordpress.org/plugins/hafenstudios-ads/advanced/)

## Ratings

 5 out of 5 stars.

 *  [  14 5-star reviews     ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/?filter=5)
 *  [  0 4-star reviews     ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/?filter=4)
 *  [  0 3-star reviews     ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/?filter=3)
 *  [  0 2-star reviews     ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/?filter=2)
 *  [  0 1-star reviews     ](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/?filter=1)

[Your review](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/hafenstudios-ads/reviews/)

## Contributors

 *   [ hafenstudios ](https://profiles.wordpress.org/hafenstudios/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/hafenstudios-ads/)