From 8c2b4966a3d56816a9b2ae9e51c8c14e900ebbf5 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Fri, 21 Aug 2026 03:16:16 +1000 Subject: [PATCH 1/2] fix(adsense): support in-feed layout keys --- docs/content/scripts/google-adsense.md | 20 +++++++++- packages/script/src/registry-types.json | 9 ++++- .../components/ScriptGoogleAdsense.vue | 4 +- test/nuxt-runtime/google-adsense.nuxt.test.ts | 38 +++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 test/nuxt-runtime/google-adsense.nuxt.test.ts diff --git a/docs/content/scripts/google-adsense.md b/docs/content/scripts/google-adsense.md index 540af456a..ed5b76a8b 100644 --- a/docs/content/scripts/google-adsense.md +++ b/docs/content/scripts/google-adsense.md @@ -145,12 +145,13 @@ An `ads.txt` file does not replace AdSense's site review. After publishing it, c | `data-ad-client` | Your **Google AdSense publisher ID** (`ca-pub-XXXXXXXXXX`). | | `data-ad-slot` | Your **Ad Slot ID** (available in AdSense dashboard). | | `data-ad-format` | Ad format type (`auto`, `rectangle`, `horizontal`, `vertical`, `fluid`, `autorelaxed`). | -| `data-ad-layout` | Layout (`in-article`, `in-feed`, `fixed`). | +| `data-ad-layout` | In-article layout (`in-article`). | +| `data-ad-layout-key` | Layout key generated by AdSense for an in-feed unit. | | `data-full-width-responsive` | **Set to `true`** to make the ad responsive. | #### Example using `data-ad-layout` -Set `data-ad-layout` for layouts such as `in-article`: +Set `data-ad-layout` for an in-article unit: ```vue ``` +#### Example using `data-ad-layout-key` + +Copy the layout key from the in-feed unit generated by AdSense: + +```vue + +``` + ## Handling ad blockers Use the `error` slot for visitors whose ad blocker stops the script: diff --git a/packages/script/src/registry-types.json b/packages/script/src/registry-types.json index 636917236..f8b5a3ed1 100644 --- a/packages/script/src/registry-types.json +++ b/packages/script/src/registry-types.json @@ -306,7 +306,7 @@ { "name": "ScriptGoogleAdsenseProps", "kind": "interface", - "code": "interface ScriptGoogleAdsenseProps {\n dataAdClient: string\n dataAdSlot: string\n dataAdFormat?: 'auto' | 'rectangle' | 'vertical' | 'horizontal' | 'fluid' | 'autorelaxed'\n dataAdLayout?: 'in-article' | 'in-feed' | 'fixed'\n dataFullWidthResponsive?: boolean\n /**\n * Defines the trigger event to load the script.\n */\n trigger?: ElementScriptTrigger\n}" + "code": "interface ScriptGoogleAdsenseProps {\n dataAdClient: string\n dataAdSlot: string\n dataAdFormat?: 'auto' | 'rectangle' | 'vertical' | 'horizontal' | 'fluid' | 'autorelaxed'\n dataAdLayout?: 'in-article'\n dataAdLayoutKey?: string\n dataFullWidthResponsive?: boolean\n /**\n * Defines the trigger event to load the script.\n */\n trigger?: ElementScriptTrigger\n}" }, { "name": "ScriptGoogleAdsenseEvents", @@ -4545,7 +4545,12 @@ }, { "name": "dataAdLayout", - "type": "'in-article' | 'in-feed' | 'fixed'", + "type": "'in-article'", + "required": false + }, + { + "name": "dataAdLayoutKey", + "type": "string", "required": false }, { diff --git a/packages/script/src/runtime/components/ScriptGoogleAdsense.vue b/packages/script/src/runtime/components/ScriptGoogleAdsense.vue index 7da2914de..4cb9284d7 100644 --- a/packages/script/src/runtime/components/ScriptGoogleAdsense.vue +++ b/packages/script/src/runtime/components/ScriptGoogleAdsense.vue @@ -10,7 +10,8 @@ const props = withDefaults(defineProps<{ dataAdClient: string dataAdSlot: string dataAdFormat?: 'auto' | 'rectangle' | 'vertical' | 'horizontal' | 'fluid' | 'autorelaxed' - dataAdLayout?: 'in-article' | 'in-feed' | 'fixed' + dataAdLayout?: 'in-article' + dataAdLayoutKey?: string dataFullWidthResponsive?: boolean /** * Defines the trigger event to load the script. @@ -89,6 +90,7 @@ const rootAttrs = computed(() => { :data-ad-slot="dataAdSlot" :data-ad-format="dataAdFormat" :data-ad-layout="dataAdLayout" + :data-ad-layout-key="dataAdLayoutKey" :data-full-width-responsive="dataFullWidthResponsive" v-bind="rootAttrs" /> diff --git a/test/nuxt-runtime/google-adsense.nuxt.test.ts b/test/nuxt-runtime/google-adsense.nuxt.test.ts new file mode 100644 index 000000000..1409e938c --- /dev/null +++ b/test/nuxt-runtime/google-adsense.nuxt.test.ts @@ -0,0 +1,38 @@ +import { mountSuspended } from '@nuxt/test-utils/runtime' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import ScriptGoogleAdsense from '../../packages/script/src/runtime/components/ScriptGoogleAdsense.vue' + +const mocks = vi.hoisted(() => ({ + status: { __v_isRef: true, value: 'loaded' }, + useScriptGoogleAdsense: vi.fn(), + useScriptTriggerElement: vi.fn(() => () => {}), +})) + +vi.mock('../../packages/script/src/runtime/composables/useScriptTriggerElement', () => ({ + useScriptTriggerElement: mocks.useScriptTriggerElement, +})) + +vi.mock('../../packages/script/src/runtime/registry/google-adsense', () => ({ + useScriptGoogleAdsense: mocks.useScriptGoogleAdsense, +})) + +describe('google adsense component', () => { + beforeEach(() => { + vi.clearAllMocks() + mocks.useScriptGoogleAdsense.mockReturnValue({ status: mocks.status }) + window.adsbygoogle = [] + }) + + it('renders the in-feed layout key on the ad unit', async () => { + const wrapper = await mountSuspended(ScriptGoogleAdsense, { + props: { + dataAdClient: 'ca-pub-123', + dataAdSlot: '456', + dataAdFormat: 'fluid', + dataAdLayoutKey: '-6t+ed+2i-1n-4w', + }, + }) + + expect(wrapper.get('ins').attributes('data-ad-layout-key')).toBe('-6t+ed+2i-1n-4w') + }) +}) From 4873d7d1bf28c3e5125738959b9b2cfa86f244a8 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Fri, 21 Aug 2026 03:24:24 +1000 Subject: [PATCH 2/2] test(adsense): cover layout key fallthrough --- test/nuxt-runtime/google-adsense.nuxt.test.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/nuxt-runtime/google-adsense.nuxt.test.ts b/test/nuxt-runtime/google-adsense.nuxt.test.ts index 1409e938c..e38609f3c 100644 --- a/test/nuxt-runtime/google-adsense.nuxt.test.ts +++ b/test/nuxt-runtime/google-adsense.nuxt.test.ts @@ -33,6 +33,12 @@ describe('google adsense component', () => { }, }) - expect(wrapper.get('ins').attributes('data-ad-layout-key')).toBe('-6t+ed+2i-1n-4w') + expect({ + adUnit: wrapper.get('ins').attributes('data-ad-layout-key'), + wrapper: wrapper.attributes('data-ad-layout-key'), + }).toEqual({ + adUnit: '-6t+ed+2i-1n-4w', + wrapper: undefined, + }) }) })