初始設定 比較跳脫一般經驗法則的是,在載入 script 之後,服務仍然不是可用狀態,因此,此時不可呼叫相關服務 API。
譬如,以下是錯誤做法:
1 2 3 4 $.getScript('//www.googletagservices.com/tag/js/gpt.js' ).then(function ( ) { window .googletag.pubads().enableSingleRequest(); window .googletag.enableServices(); });
不論是透過直接在 html 中埋入 script tag 的方式載入,或是以上面的方式動態載入 DFP script,都不可以直接呼叫 DFP 的 API。
正確的做法,須將命令以函數的形式,推到 window.googletag.cmd
陣列中。注意,此時 googletag
和 googletag.cmd
可以只是普通物件和陣列。待 DFP 服務啟動後,會在 googletag
中添加功能,然後逐一呼叫被推入 googletag.cmd
陣列的函數。也就是說,在該函數中才能保證 DFP 的服務已備妥,並且才能呼叫 API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var adUnitPath = 'pub-id/slot-id' ;var adSize = [300 , 25 ];var adElementId = 'id-to-html-element' ;$.getScript('//www.googletagservices.com/tag/js/gpt.js' ).then(function ( ) { var googletag = window .googletag || (window .googletag = []); googletag.cmd = (googletag.cmd || []); googletag.cmd.push(function ( ) { initDfp(); googletag.defineSlot(adUnitPath, adSize, adElementId) .addService(googletag.pubads()); googletag.display(adElementId); }); }); function initDfp ( ) { googletag.pubads().enableSingleRequest(); googletag.enableServices(); }
上面的 adElementId
,雖然在 DFP 上使用 generate tag 時,會產生一個 div-gpt-ad-1234567890123-0
格式的字串,要我們填在 html 元素作為 id 使用,但其實只要保握 html 的基本原則:id 不要重複,在這裡使用任意 id 皆可,並不影響廣告呈現。不過 DFP 仍然建議,id 最好能反映廣告版位,以方便投廣告的客戶確認。
多個廣告版位 上面的做法,如果直接套用在多個廣告上,雖然不會有什麼問題,但是重複執行 DFP 的設定,還是讓人渾身不舒服。
可以將 $.getScript()
和 initDfp()
的處理包裝起來,讓它們永遠只會執行一次:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function once (fn ) { var promise; return function ( ) { var args; if (!promise) { args = Array .prototype.slice.call(arguments ); promise = Promise .resolve(fn.apply(null , args)); } return promise; }; } var loadDfp = once(function ( ) { return $.getScript('//www.googletagservices.com/tag/js/gpt.js' ).then(function ( ) { window .googletag = window .googletag || {}; window .googletag.cmd = window .googletag.cmd || []; return window .googletag; }); }); var initDfp = once(function (googletag ) { googletag.pubads().enableSingleRequest(); googletag.enableServices(); });
然後,每個要新增版位的地方,都這樣呼叫:
1 2 3 4 5 6 7 8 loadDfp().then(function (googletag ) { googletag.cmd.push(function ( ) { initDfp(googletag); googletag.defineSlot(adUnitPath, adSize, adElementId) .addService(googletag.pubads()); googletag.display(adElementId); }); });
注意到,initDfp()
的呼叫,不能併到 loadDfp()
中執行,只能在 googletag.cmd.push()
的函數中執行,否則就又犯了一開始的錯誤。
上面的寫法,還是有點囉唆,於是,我們還可以進一步包裝成這樣:
1 2 3 4 5 6 7 8 function dfp (fn ) { loadDfp().then(function (googletag ) { initDfp(googletag); googletag.cmd.push(function ( ) { fn(googletag); }); }); }
1 2 3 4 5 dfp(function(googletag) { googletag.defineSlot(adUnitPath, adSize, adElementId) .addService(googletag.pubads()); googletag.display(adElementId); });
動態新增廣告 上面的做法,適用於內容不會變動的頁面。如果是無限捲動列表形式的頁面,可能需要每隔幾個項目就顯示一則廣告。官方建議的做法,是透過呼叫 disableInitialLoad()
函數禁止初始廣告載入,然後於版面備妥時,再呼叫 refresh()
更新廣告內容。
1 2 3 4 5 function initDfp (googletag ) { googletag.pubads().enableSingleRequest(); googletag.pubads().disableInitialLoad(); googletag.enableServices(); }
注意上面 googletag.pubads().disableInitialLoad()
的呼叫。此呼叫將改變 display()
函數的行為,使 display()
函數只註冊廣告版位,而不進行顯示。
在動態插入廣告之後,再呼叫 refresh()
函數,更新廣告:
1 2 3 4 5 6 dfp(function(googletag) { var slot = googletag.defineSlot(adUnitPath, adSize, adElementId) .addService(googletag.pubads()); googletag.display(adElementId); googletag.pubads().refresh([slot]); });
注意上面如何儲存 slot
,然後用以呼叫 refresh()
函數。
自動縮合沒有廣告的版面 也許我們的版位不是非常熱門,經常開天窗(希望不是)。一旦廣告版位沒有人投遞廣告,該廣告版位就會顯示成空白。如果這是所有的版面的常態的話,可以考慮直接在初始化的時候,設定所有的版面在沒有廣告的時候,自動縮合。
1 2 3 4 5 6 function initDfp (googletag ) { googletag.pubads().enableSingleRequest(); googletag.pubads().disableInitialLoad(); googletag.pubads().collapseEmptyDivs(); googletag.enableServices(); }
或者,也可以根據需要,依據版面別進行個別設定:
1 2 3 4 5 6 7 8 9 10 var adCollapse = false ;dfp(function (googletag ) { const slot = googletag.defineSlot(adUnitPath, adSize, adElementId) .addService(googletag.pubads()) .setCollapseEmptyDiv(adCollapse); googletag.display(adElementId); googletag.pubads().refresh([slot]); });
React Component 範例 最後,測試的過程中寫了一簡單的 React 範例程式 ,提供給大家參考。
參考資料