A checkout page, login screen, private account area, or quiet “thank you” page has a different job from an article. Forcing an ad into that moment can distract the reader, weaken trust, or create low-value inventory. The clean solution depends on how the ad arrived: use AdSense page exclusions for Auto ads, and use a server-side WordPress condition for ad code or units that your theme, plugin, or template inserts.

Choose the right path in thirty seconds

  • Auto ads enabled in AdSense and no explicit slot in the template → create an AdSense page exclusion.

  • A plugin, widget, shortcode, block, hook, or template prints the ad → add its own display condition or remove that placement.

  • The global AdSense loader and manual slots are custom code → guard both with one WordPress function.

  • A consent platform controls loading → keep consent enforcement intact; a page exclusion is not a consent mechanism.

  • Ads appear through another network or Google Ad Manager → configure that product or placement, not an AdSense Auto ads rule.

Make a small inventory before touching production

  • Record the exact canonical URLs and whether the rule applies to one page or an entire URL section.

  • View page source and search for pagead2.googlesyndication.com, adsbygoogle, data-ad-client, and data-ad-slot.

  • Inspect WordPress plugins, widgets, Site Editor patterns, reusable blocks, theme hooks, child-theme files, and tag-manager containers.

  • Note page cache, CDN cache, full-page optimization, consent/CMP, and any A/B testing layer.

  • Take a configuration backup or commit before editing PHP; test on staging when possible.

Option 1: exclude a page in AdSense Auto ads

In AdSense, open Ads, select Edit beside the site, open Page exclusions, and choose Manage. Add the URL, select either the exact-page option or the entire-section option, return to Ad settings, and apply the change to the site. Google says an applied exclusion can take up to an hour to propagate.

Exact page or entire section?

  • Use “This page only” when one canonical URL should be ad-free.

  • Use “All pages under this section” for a stable prefix such as /account/; review every route that shares it.

  • Google’s Auto ads exclusions do not support URLs containing query parameters or fragments. Match the clean canonical URL instead.

  • A section match is prefix-based and can cover more pages than expected, so test sibling paths.

  • Subdomains are separate routing contexts; verify the domain shown in AdSense and the live hostname.

Why an Auto ads exclusion may seem to fail

  • The change is still propagating; Google documents a delay of up to one hour.

  • The excluded URL differs by scheme, hostname, trailing slash, canonical redirect, or path.

  • A manually placed unit remains even though Auto ads are excluded.

  • A WordPress cache, CDN, browser cache, service worker, or optimization plugin serves an earlier document.

  • The visible placement belongs to another ad platform or a hard-coded fallback.

  • A tag manager or plugin injects code after the page is rendered.

Option 2: suppress custom WordPress ad code

For code you own, make one decision function and call it before both the AdSense loader and every manual slot. Put this in a small site plugin or child theme—not a parent theme that an update will overwrite.

wp-content/mu-plugins/site-ad-rules.phpphp
<?php
/**
 * Plugin Name: Site ad display rules
 */
 
function lynxbee_should_show_ads(): bool {
    if ( is_admin() || is_feed() || is_preview() || is_404() || is_search() ) {
        return false;
    }
 
    if ( is_page( array( 'checkout', 'cart', 'my-account', 'thank-you' ) ) ) {
        return false;
    }
 
    $post_id = get_queried_object_id();
    if ( $post_id && '1' === get_post_meta( $post_id, '_disable_ads', true ) ) {
        return false;
    }
 
    return true;
}

What this gate is actually deciding

  • WordPress conditional tags are evaluated after the main query; call this from rendering/enqueue hooks, not during plugin file loading.

  • is_page() accepts IDs, titles, slugs, or arrays; stable IDs are safest if editors may rename slugs.

  • get_queried_object_id() identifies the current singular object without relying on a global post variable.

  • The _disable_ads metadata check creates a scalable per-post switch once an admin UI or deployment process sets it.

  • The function returns one boolean so the loader and slots cannot drift into contradictory rule sets.

wp-content/mu-plugins/site-ad-rules.phpphp
add_action( 'wp_head', function (): void {
    if ( ! lynxbee_should_show_ads() ) {
        return;
    }
    ?>
    <script async
        src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-REPLACE_WITH_YOUR_ID"
        crossorigin="anonymous"></script>
    <?php
}, 20 );

Details worth keeping deliberate

  • Replace the publisher placeholder with the exact client ID from your own AdSense code.

  • wp_head runs late enough for conditional query tags and keeps the loader in the document head.

  • async prevents the external script from blocking HTML parsing; crossorigin="anonymous" matches Google’s supplied loader form.

  • Print the loader once. Duplicate theme, plugin, Site Kit, and tag-manager injections are a common source of confusion.

  • Do not alter Google’s supplied ad code beyond documented integration choices.

Guard every manual ad slot too

wp-content/mu-plugins/site-ad-rules.phpphp
function lynxbee_render_article_ad(): void {
    if ( ! lynxbee_should_show_ads() ) {
        return;
    }
    ?>
    <ins class="adsbygoogle"
         style="display:block"
         data-ad-client="ca-pub-REPLACE_WITH_YOUR_ID"
         data-ad-slot="REPLACE_WITH_YOUR_SLOT_ID"
         data-ad-format="auto"
         data-full-width-responsive="true"></ins>
    <script>
        (adsbygoogle = window.adsbygoogle || []).push({});
    </script>
    <?php
}

Why guarding only the loader is fragile

  • The manual <ins> element is the placement; the loader discovers and fills it. Keep both under the same decision.

  • The client ID identifies the publisher and the slot ID identifies the ad unit; copy both from AdSense rather than guessing.

  • A template calls lynxbee_render_article_ad() where the placement belongs, instead of scattering markup through posts.

  • A missing loader can leave empty slot markup and layout gaps; a missing slot can still leave Auto ads active.

  • Reserve sensible layout space only on pages that render a slot to reduce cumulative layout shift.

Use an explicit allowlist when mistakes are expensive

A denylist says “show ads everywhere except these pages.” An allowlist says “show ads only on approved content types.” For membership sites, shops, tools, user dashboards, or mixed public/private products, the allowlist is often easier to audit.

wp-content/mu-plugins/site-ad-rules.phpphp
function lynxbee_should_show_ads(): bool {
    if ( ! is_singular( array( 'post', 'tutorial' ) ) ) {
        return false;
    }
 
    $post_id = get_queried_object_id();
    return $post_id > 0
        && '1' !== get_post_meta( $post_id, '_disable_ads', true );
}

The trade-off is intentional

  • New page types remain ad-free until someone deliberately approves them.

  • is_singular() limits inventory to named public content types.

  • An individual article can still opt out through metadata.

  • The example assumes a custom tutorial post type; remove or replace it to match the site.

  • Document ownership of the rule so monetization and editorial teams know how a new content type is reviewed.

Pages commonly reviewed for exclusion

  • Login, logout, password-reset, account, profile, and private-message screens.

  • Cart, checkout, payment, order status, and transactional confirmation flows.

  • 404, empty search, maintenance, redirect, alert, navigation-only, and thin utility screens.

  • Preview, staging, development, editorial review, and internal tools.

  • Pages with restricted content, little original publisher content, or an experience where ads overwhelm the useful content.

  • Any placement that distracts from a sensitive task—even when exclusion is a UX choice rather than a categorical policy requirement.

Policy and privacy boundaries

  • Google Publisher Policies prohibit Google-served ads on screens without publisher content or with low-value content, and on screens used mainly for alerts, navigation, or behavioral purposes.

  • Publishers remain responsible for every page showing ads and for current AdSense program and placement policies.

  • Page exclusion does not replace consent collection, regional privacy obligations, a certified CMP where required, or consent-mode configuration.

  • Do not use CSS, overlays, or DOM tricks to conceal an ad while its code continues to request inventory.

  • Never encourage clicks, label ads deceptively, place more promotions than publisher content, or test by interacting with live ads.

Caching can make a correct rule look wrong

  • Purge WordPress page cache and CDN cache after changing templates, hooks, or rule arrays.

  • A URL-deterministic server-side decision caches safely when each URL has one outcome; user-role or consent-dependent HTML needs correct cache variation or edge-side handling.

  • Do not cache a logged-in ad-free response and serve it to anonymous visitors, or the reverse.

  • Optimization plugins may delay, combine, or reinsert scripts; temporarily disable one feature at a time during diagnosis.

  • A service worker can serve an old document after the CDN is purged; update its cache version and retest.

Verify the browser, not just the dashboard

terminalbash
curl -sL https://example.com/checkout/ | grep -E 'adsbygoogle|pagead2.googlesyndication.com|data-ad-slot' || true
curl -sL https://example.com/an-approved-article/ | grep -E 'adsbygoogle|pagead2.googlesyndication.com|data-ad-slot' || true
# Excluded page: no matching output
# Approved article: loader and/or slot markup appears

This is a useful first check, not the whole proof

  • Replace example URLs with pages you control; -L follows canonical redirects.

  • No source match proves server HTML omitted known strings, but client-side tag injection can still occur.

  • In browser DevTools, inspect Elements and Network for requests to Google ad hosts after consent choices settle.

  • Test signed-out and relevant signed-in states, mobile and desktop layouts, canonical variants, and a neighboring URL outside the exclusion.

  • Wait for the documented Auto ads propagation window before concluding that a dashboard rule failed.

A practical release checklist

  • Confirm whether each placement is Auto ads, manual AdSense, a plugin, tag manager, or another network.

  • Back up configuration and deploy PHP through a child theme or site plugin with syntax/CI checks.

  • Apply exact or section Auto ads exclusions and record the rule owner and reason.

  • Purge caches without disabling security, consent, or policy controls.

  • Verify excluded and allowed pages in source, DOM, Network, and responsive layouts.

  • Watch revenue and page-experience changes without clicking ads; review unexpected coverage after new routes launch.

Primary references