@automattic/newspack-blocks 4.26.8 → 4.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/modal.asset.php +1 -1
- package/dist/modal.js +1 -1
- package/newspack-blocks.php +2 -2
- package/package.json +1 -1
- package/src/modal-checkout/modal.js +8 -0
- package/src/shared/js/cta-attribution.js +130 -0
- package/src/shared/js/cta-attribution.test.js +165 -0
- package/vendor/composer/installed.php +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# @automattic/newspack-blocks [4.27.0](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.26.8...newspack-blocks@4.27.0) (2026-07-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **gates:** capture gate id on landing-page conversions (NPPD-1887) ([#575](https://github.com/Automattic/newspack-workspace/issues/575)) ([20e84f8](https://github.com/Automattic/newspack-workspace/commit/20e84f87dc1be96b5575548593fd0f7e77da52e6))
|
|
7
|
+
|
|
1
8
|
## @automattic/newspack-blocks [4.26.8](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.26.7...newspack-blocks@4.26.8) (2026-07-02)
|
|
2
9
|
|
|
3
10
|
|
package/dist/modal.asset.php
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<?php return array('dependencies' => array(), 'version' => '
|
|
1
|
+
<?php return array('dependencies' => array(), 'version' => '9ede98c6b50c49ec1720');
|
package/dist/modal.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";function e(e,t=!1){const n=e.querySelectorAll('button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])');if(0===n.length)return!1;const o=n?.[0];let c;o.focus(),t?(document.addEventListener("keydown",function(e){if(("Tab"===e.key||9===e.keyCode)&&e.shiftKey&&document.activeElement===o){const n=t.contentWindow.document,o=n.getElementById("checkout-after-success");c=null!==o?o:n.getElementById("checkout_cancel"),c.focus(),e.preventDefault()}}),document.getElementById("newspack-a11y-last-element").addEventListener("focus",()=>{o.focus()})):(c=n[n.length-1],document.addEventListener("keydown",function(e){("Tab"===e.key||9===e.keyCode)&&(e.shiftKey?document.activeElement===o&&(c.focus(),e.preventDefault()):document.activeElement===c&&(o.focus(),e.preventDefault()))}))}const t=(e,t={})=>({...t,action:e}),n=["action","action_type","amount","currency","product_id","product_type","variation_id","variation_ids","is_variable","is_grouped","child_ids","price_summary","newspack_popup_id","prompt_title","gate_post_id","recurrence","referrer"],o=(e,t="np_modal_checkout_interaction")=>{if("function"==typeof window.gtag&&e){const o={};for(const t of n)e[t]&&("boolean"==typeof e[t]?e[t]=e[t]?"yes":"no":"true"===e[t]?e[t]="yes":"false"===e[t]&&(e[t]="no"),o[t]=e[t].toString());window.gtag("event",t,o)}},c=e=>{if("function"!=typeof window.gtag)return;let n="opened";const{amount:c="",is_variable:a="",is_grouped:r="",price:i="",variation_id:s=""}=e,l={...e};(c||i)&&(l.amount=c||i),a&&!s&&(n="opened_variations"),r&&(n="opened_grouped");const u=t(n,l);o(u)};function a(e,t=null){const n=document.createElement("input");return n.type="hidden",n.name=e,t&&(n.value=t),n}function r(e){e.requestSubmit(e.querySelector('button[type="submit"]'))}function i(e){const t="string"==typeof e?document.getElementById(e):e;if(!t)return console.warn("No container found for checkout data"),{};let n={};if("FORM"===t.tagName){const e=new FormData(t);n=Object.fromEntries(e)}const o=t.dataset.checkout;if(!o)return console.warn("No checkout data found"),n;try{n={...n,...JSON.parse(o)}}catch(e){console.warn("Error parsing checkout data")}const c=new URL(t.ownerDocument.defaultView.location.href);return c.searchParams.get("action_type")&&(n.action_type=c.searchParams.get("action_type")),n}const s=e=>{if("function"!=typeof window.gtag)return;e=e||i("newspack_modal_checkout");const n=t("dismissed",e);o(n)};function l(e){const t=e&&e.dataset?e.dataset.checkout:null;if(!t)return null;try{return JSON.parse(t)}catch(e){return null}}function u(e,t,n=null){const o=e.querySelectorAll(".wp-block-newspack-blocks-checkout-button"),c=null!=n&&""!==String(n);let a=null;return o.forEach(e=>{if(a)return;const o=e.querySelector("form"),r=l(o);r&&String(r.product_id)===String(t)&&(c&&String(r.variation_id)!==String(n)||(a=o))}),a}const d=["after_success_behavior","after_success_url","after_success_button_label","gate_post_id","newspack_popup_id","prompt_title"];const p=newspackBlocksModal.newspack_class_prefix,m="newspack_modal_checkout_iframe",_="newspack_modal_checkout_container",h=`${p}__modal`,k="newspack-blocks__modal-variation",y=`${p}__processing-payment-text`,w=newspackBlocksModal.processing_payment_messages;let f=!1,v=newspackBlocksModal.labels.checkout_modal_title,g=null;const b=e=>{e.overlayId&&window.newspackReaderActivation?.overlays&&window.newspackReaderActivation?.overlays.remove(e.overlayId),e.setAttribute("data-state","closed"),document.body.style.overflow="auto"};window.onpageshow=e=>{e.persisted&&(document.querySelectorAll(".modal-processing").forEach(e=>e.classList.remove("modal-processing")),document.querySelectorAll(".non-modal-checkout-loading").forEach(e=>e.classList.remove("non-modal-checkout-loading")),document.querySelectorAll(`.${h}-container`).forEach(e=>b(e)))};const S=new CustomEvent("checkout-closed");var E;window.newspackRAS=window.newspackRAS||[],E=()=>{const t=document.querySelector("#newspack_modal_checkout");if(!t)return;const n=t.querySelector(`.${h}__content`),o=a("modal_checkout","1"),E=n.querySelector(`.${p}__spinner`);let A=document.querySelector(".newspack-reader__account-link")?.[0];const q="600px",L=document.createElement("iframe");L.name=m,L.style.height=q,L.style.visibility="hidden";const $=e=>{B.observe(e),"none"!==E.style.display&&(E.style.display="none"),"visible"!==L.style.visibility&&(L.style.visibility="visible"),L._ready=!0};!function(e,t,n){e._ready=!1,e._readyTimer&&clearTimeout(e._readyTimer);let o=!1,c="";function a(){o||(o=!0,clearTimeout(e._readyTimer),t.call(this))}function r(){"complete"===this.readyState&&a.call(this)}function i(){e._ready=!1,n&&n(),e._readyTimer&&clearTimeout(e._readyTimer);const t=e.contentDocument||e.contentWindow?.document;t&&(t.removeEventListener("DOMContentLoaded",a),t.removeEventListener("readystatechange",r))}function s(){if(e._ready)return void i();const t=e.contentDocument||e.contentWindow?.document;t&&0!==t.URL.indexOf("about:")?"complete"===t?.readyState?a.call(t):(t.addEventListener("DOMContentLoaded",a),t.addEventListener("readystatechange",r)):e._readyTimer=setTimeout(s,10)}e._observer||(e._observer=new MutationObserver(e=>{e.forEach(e=>{"attributes"===e.type&&"src"===e.attributeName&&(o=!1,i(),s())})}),e._observer.observe(e,{attributes:!0})),e._locationObserver||(e._locationObserver=setInterval(function(){const t=e.contentDocument||e.contentWindow?.document;t&&t.URL!==c&&(c=t.URL,o=!1,i(),s())},50)),s()}(L,function(){const n=L.contentWindow?.location;if(window.newspackReaderActivation&&n?.href?.includes("order-received")){const e=window.newspackReaderActivation,t=new Proxy(new URLSearchParams(n.search),{get:(e,t)=>e.get(t)});t.email&&(e.setReaderEmail(t.email),e.setAuthenticated(!0))}const o=L?.contentDocument?.querySelector(`#${_}`);if(!o)return;const c=o.querySelector("#modal-checkout-product-details"),a=i(c),r=document.createElement("p");r.classList.add(y);let s=[];const l=()=>{s.forEach(e=>clearTimeout(e)),s=[]},u=()=>{E.style.display="none",l(),E.querySelectorAll(`.${y}`).forEach(e=>e.remove())};!function(e,t){e.checkoutCancel?t():e.addEventListener("checkout-cancel",t)}(o,()=>{P()}),function(e,t){e.checkoutPlaceOrderStart?t():e.addEventListener("checkout-place-order-start",t)}(o,e=>{E.querySelectorAll(`.${y}`).forEach(e=>e.remove()),E.style.display="flex",l(),r.textContent=w[0]?.text??"",w.slice(1).forEach(({text:t,delay:n})=>{const o=setTimeout(()=>{e.target.dispatchEvent(new CustomEvent("checkout-place-order-processing")),r.textContent=t},n);s.push(o)}),E.appendChild(r)}),function(e,t){e.checkoutPlaceOrderError?t():e.addEventListener("checkout-place-order-error",t)}(o,u),function(e,t){e.checkoutReady?t():e.addEventListener("checkout-ready",t)}(o,()=>{const e=c?.querySelector("strong");if(e&&(e.textContent=a.price_summary),t.initialErrors){const e=document.createElement("div");e.classList.add("woocommerce-error"),e.textContent=t.initialErrors,o.prepend(e),delete t.initialErrors}N(),T(v),L.contentWindow?.newspackBlocksModalCheckout?.checkout_nonce&&(t.checkout_nonce=L.contentWindow.newspackBlocksModalCheckout.checkout_nonce),$(o)}),function(e,t){e.checkoutComplete?t():e.addEventListener("checkout-complete",t)}(o,()=>{window.newspackRAS.push(["checkout_completed",a]),window?.newspackReaderActivation?.refreshNewslettersSignupModal&&window?.newspackReaderActivation?.getReader()?.email&&window.newspackReaderActivation.refreshNewslettersSignupModal(window.newspackReaderActivation.getReader().email),N("small"),T(newspackBlocksModal.labels.thankyou_modal_title),$(o),e(t.querySelector(`.${h}`)),u()}),function(e,t){e.checkoutPlaceOrderCriticalError?t():e.addEventListener("checkout-place-order-critical-error",t)}(o,()=>{var e;(e=g)&&(P(),E.style.display="none",t.initialErrors=newspackBlocksModal.labels.critical_error,e.requestSubmit(e.querySelector('button[type="submit"]')),u())})},()=>{E.style.display="flex"});const R=e=>new Promise((t,n)=>{const o=new URLSearchParams(e);o.append("action","modal_checkout_request"),fetch(newspackBlocksModal.ajax_url+"?"+o.toString()).then(e=>{e.ok||n(e),e.json().then(e=>{t(e.url)}).catch(n)}).catch(n)}),M=()=>"undefined"!=typeof newspack_ras_config&&!newspack_ras_config?.is_logged_in&&!window?.newspackReaderActivation?.getReader?.()?.authenticated&&newspackBlocksModal?.is_registration_required&&window?.newspackReaderActivation?.openAuthModal,C=t=>{const n=!newspackBlocksModal.has_unsupported_payment_gateway;n||t.preventDefault();const o=t.target;o.classList.add("modal-processing");const u=i(o);if(u.newspack_donate){const e=u.donation_frequency,t=[...o.querySelectorAll(`.donation-tier__${e}, .donation-frequency__${e}`)],n=u.donation_tier_index;let c,a;n?(c=t[n],a=u[`donation_value_${e}`]):(c=t[0],u[`donation_value_${e}_untiered`]?a=u[`donation_value_${e}_untiered`]:(a=u[`donation_value_${e}`],"other"===a&&(a=u[`donation_value_${e}_other`])));const r=i(c);for(const e in r)u[e]=r[e];u.amount=a,u.price_summary=u.summary_template.replace("{{PRICE}}",function(e,t="USD"){return parseFloat(e).toLocaleString(document.documentElement.lang,{style:"currency",currency:t,currencyDisplay:"narrowSymbol"})}(u.amount,u.currency))}u&&Object.keys(u).forEach(e=>{0===o.querySelectorAll('input[name="'+e+'"]').length&&o.prepend(a(e,u[e]))}),u.variation_id||(A=t.submitter);const d=document.querySelectorAll(`.${k}`);if(d.forEach(e=>{(M()||n)&&b(e)}),u.is_grouped||u.is_variable&&!u.variation_id){const n=[...d].find(e=>e.dataset.productId===u.product_id);if(n)return n.querySelectorAll(`form[target="${m}"]`).forEach(e=>{["after_success_behavior","after_success_url","after_success_button_label","gate_post_id","newspack_popup_id","prompt_title"].forEach(t=>{0===e.querySelectorAll('input[name="'+t+'"]').length&&e.prepend(a(t,u[t]))});const t=l(e);t&&Object.keys(t).forEach(n=>{0===e.querySelectorAll('input[name="'+n+'"]').length&&e.prepend(a(n,t[n]))})}),t.preventDefault(),o.classList.remove("modal-processing"),O(n),e(n,!1),f||c(u),void document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u))}if(n||M()){if(o.classList.remove("modal-processing"),f||c(u),f=!0,M()){t.preventDefault();const e=u.price_summary,o=e?`<div class="order-details-summary ${p}__box ${p}__box--text-center"><p><strong>${e}</strong></p></div>`:"",c=R(u);c.then(e=>{window.newspackReaderActivation?.setPendingCheckout?.(e)}),window.newspackReaderActivation.openAuthModal({title:newspackBlocksModal.labels.auth_modal_title,onSuccess:(e,t)=>{c.then(e=>{t?.registered&&n&&(e+=`&${newspackBlocksModal.checkout_registration_flag}=1`),n?r(x(e)):R(u).then(window.location.href=e)}).catch(e=>{console.warn("Unable to generate cart:",e),P()})},onError:()=>{P()},onDismiss:()=>{s(u),f=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout")},skipSuccess:!0,skipNewslettersSignup:!0,labels:{signin:{title:newspackBlocksModal.labels.signin_modal_title},register:{title:newspackBlocksModal.labels.register_modal_title}},content:o,trigger:t.submitter,closeOnSuccess:n})}else D(),document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u));g=o}else R(u).then(e=>{window.location.href=e}),(!u.is_variable||u.variation_id)&&o.querySelectorAll("button[type=submit]:focus").forEach(e=>{e.classList.add("non-modal-checkout-loading");const t=e.innerHTML;e.innerHTML="<span>"+t+"</span>"})},x=e=>{const t=document.createElement("form");t.method="POST",t.action=e,t.target=m,t.style.display="none";const n=document.createElement("button");return n.setAttribute("type","submit"),t.appendChild(n),document.body.appendChild(t),t.addEventListener("submit",C),t},B=new ResizeObserver(e=>{if(!e||!e.length)return;if(!L.contentDocument)return;const o=e[0].contentRect;if(o){const e=.01*Math.max(document.documentElement.clientHeight,window.innerHeight||0)*90-(t.querySelector(`.${h}__header`)?.offsetHeight||0),c=o.top+o.bottom,a=Math.min(c,e);if(0===a)return void(L.style.visibility="hidden");n.style.height=a+"px",L.style.height=a+"px"}}),P=()=>{const e=L?.contentDocument?.querySelector(`#${_}`),o=e?.querySelector('input[name="after_success_url"]'),c=e?.querySelector('input[name="after_success_behavior"]'),a=document?.querySelector(".newspack-newsletters-signup-modal"),r=i(e?.querySelector("#modal-checkout-product-details"));e?.checkoutComplete||(async()=>{const e=new FormData;newspackBlocksModal.has_unsupported_payment_gateway||e.append("modal_checkout","1"),e.append("action","abandon_modal_checkout"),e.append("_wpnonce",t.checkout_nonce),t.checkout_nonce=null;try{await fetch(newspackBlocksModal.ajax_url,{method:"POST",body:e})}catch(e){console.warn("Unable to empty cart:",e)}})();const l=!(L.contentDocument&&o&&c&&e?.checkoutComplete);if((l||a)&&(E.style.display="flex",L&&n.contains(L)&&(L._ready=!1,L.src="about:blank",L.style.height=q,L.style.visibility="hidden",n.style.height=q,n.removeChild(L)),B&&B.disconnect(),document.querySelectorAll(`.${h}-container`).forEach(e=>b(e)),A&&A.focus(),document.dispatchEvent(S)),e?.checkoutComplete){const e=()=>{if(o&&c){const e=o.getAttribute("value"),t=c.getAttribute("value");"custom"===t?window.location.href=e:"referrer"===t&&window.history.back()}window?.newspackReaderActivation?.setPendingCheckout?.(),f=!1};"subscription_switch"!==r.action_type&&window?.newspackReaderActivation?.openNewslettersSignupModal?window.newspackReaderActivation.openNewslettersSignupModal({onSuccess:e,onError:e,closeOnSuccess:l}):e(),l&&(v=newspackBlocksModal.labels.checkout_modal_title,N(),T(v))}else window?.newspackReaderActivation?.setPendingCheckout?.(),s(),f=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout");document.removeEventListener("keydown",I)},D=o=>{o&&(L.src=o),E.style.display="flex",O(t),n.appendChild(L),t.addEventListener("click",e=>{e.target===t&&P()}),e(t,L),document.addEventListener("keydown",I)},O=e=>{window.newspackReaderActivation?.overlays&&(e.overlayId=window.newspackReaderActivation?.overlays.add()),e.setAttribute("data-state","open"),document.body.style.overflow="hidden"},T=e=>{const n=t.querySelector(`.${h}__header h2`);n&&(n.innerText=e)},N=(e="default")=>{const n=t.querySelector(`.${h}`);n&&("small"===e?n.classList.add(`${h}--small`):n.classList.remove(`${h}--small`))};t.querySelectorAll(`.${h}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),P()})}),document.querySelectorAll(".newspack-blocks__modal-variation").forEach(e=>{e.addEventListener("click",t=>{t.target===e&&P()}),e.querySelectorAll(`.${h}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),P()})})});const I=e=>{"Escape"===e.key&&P()};document.querySelectorAll(".wpbnbd.wpbnbd--platform-wc, .wp-block-newspack-blocks-checkout-button, .newspack-blocks__modal-variation").forEach(e=>{e.querySelectorAll("form").forEach(e=>{newspackBlocksModal.has_unsupported_payment_gateway||e.prepend(o.cloneNode()),e.target=m,e.addEventListener("submit",C)})}),(()=>{const e=new URLSearchParams(window.location.search);if(!e.has("checkout"))return;let t=!0;const n=e.get("type");if("donate"===n){const t=e.get("layout"),n=e.get("frequency"),o=e.get("amount"),c=e.get("other");t&&n&&o&&((e,t,n,o=null)=>{let c;document.querySelectorAll(".wpbnbd.wpbnbd--platform-wc form").forEach(a=>{const r=a.querySelector(`input[name="donation_frequency"][value="${t}"]`);if(r)if("tiered"===e){const e=document.querySelector(`button[data-frequency-slug="${t}"]`);if(!e)return;e.click();const o=a.querySelector(`button[type="submit"][name="donation_value_${t}"][value="${n}"]`);if(!o)return;o.click()}else{const i="untiered"===e?a.querySelector(`input[name="donation_value_${t}_untiered"]`):a.querySelector(`input[name="donation_value_${t}"][value="${n}"]`);if(r&&i){if(r.checked=!0,"untiered"===e)i.value=n;else if("other"===n){i.click();const e=a.querySelector(`input[name="donation_value_${t}_other"]`);e&&o&&(e.value=o)}else i.checked=!0;c=a}}}),c&&r(c)})(t,n,o,c)}else if("checkout_button"===n){const n=e.get("product_id"),o=e.get("variation_id");n?t=((e,t=null)=>{const n=function(e,t,n,o={}){const{allowProductOnlyFallback:c=!1}=o;if(null==n||""===String(n))return u(e,t,null);const a=u(e,t,n);if(a)return a;const r=function(e,t,n,o={}){const{variationModalClassPrefix:c,iframeName:a}=o,r=[...e.querySelectorAll(`.${c}`)].find(e=>String(e.dataset.productId)===String(t));if(!r)return null;const i=r.querySelectorAll("form"),s=a?[...i].find(e=>e.getAttribute("target")===a):i[0];if(!s)return null;const l=[...s.querySelectorAll('input[type="radio"][name="product_id"]')].find(e=>String(e.value)===String(n));return l?(l.checked=!0,s):null}(e,t,n,o);return r?(function(e,t,n=d){if(!e||!t)return;const o=t.ownerDocument,c=new FormData(e);n.forEach(e=>{if(t.querySelector(`input[name="${e}"]`))return;const n=c.getAll(e).filter(e=>"string"==typeof e&&e);if(!n.length)return;const a=o.createElement("input");a.type="hidden",a.name=e,a.value=n[n.length-1],t.prepend(a)})}(u(e,t,null),r),r):c?u(e,t,null):null}(document,e,t,{variationModalClassPrefix:k,iframeName:m});if(n)return r(n),!0;const o=`Newspack modal checkout: no checkout form found for product_id "${e}"`+(t?` and variation_id "${t}"`:"")+". The checkout was not triggered.";return console.warn(o),!1})(n,o):(t=!1,console.warn("Newspack modal checkout: checkout_button trigger is missing product_id. The checkout was not triggered."))}else{const e=window.newspackReaderActivation?.getPendingCheckout?.();e&&r(x(e))}t&&window.history.replaceState(null,null,window.location.pathname)})(),window.newspackOpenModalCheckout=({url:e=null,title:t=null,actionType:n=null,afterSuccess:o={},onCheckoutComplete:c=null,onClose:a=null})=>{if(v=t||newspackBlocksModal.labels.checkout_modal_title,T(v),(e=new URL(e||newspackBlocksModal.checkout_url)).searchParams.has("my_account_checkout")&&e.searchParams.delete("my_account_checkout"),e.searchParams.has("modal_checkout")||e.searchParams.set("modal_checkout","1"),n&&e.searchParams.set("action_type",n),o?.url&&e.searchParams.set("after_success_url",o.url),(o?.behavior||o?.url)&&e.searchParams.set("after_success_behavior",o.behavior||"custom"),o?.buttonLabel&&e.searchParams.set("after_success_button_label",o.buttonLabel),c){const e=({detail:{action:e,data:t}})=>{"checkout_completed"===e&&c(t)};window.newspackRAS.push(t=>{t.on("activity",e);const n=()=>{t.off("activity",e),document.removeEventListener("checkout-closed",n)};document.addEventListener("checkout-closed",n)})}if(a){const e=()=>{a(),document.removeEventListener("checkout-closed",e)};document.addEventListener("checkout-closed",e)}D(e.toString())},window.newspackCloseModalCheckout=P},"undefined"!=typeof document&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",E):E())})();
|
|
1
|
+
(()=>{"use strict";function e(e,t=!1){const n=e.querySelectorAll('button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])');if(0===n.length)return!1;const o=n?.[0];let c;o.focus(),t?(document.addEventListener("keydown",function(e){if(("Tab"===e.key||9===e.keyCode)&&e.shiftKey&&document.activeElement===o){const n=t.contentWindow.document,o=n.getElementById("checkout-after-success");c=null!==o?o:n.getElementById("checkout_cancel"),c.focus(),e.preventDefault()}}),document.getElementById("newspack-a11y-last-element").addEventListener("focus",()=>{o.focus()})):(c=n[n.length-1],document.addEventListener("keydown",function(e){("Tab"===e.key||9===e.keyCode)&&(e.shiftKey?document.activeElement===o&&(c.focus(),e.preventDefault()):document.activeElement===c&&(o.focus(),e.preventDefault()))}))}const t=(e,t={})=>({...t,action:e}),n=["action","action_type","amount","currency","product_id","product_type","variation_id","variation_ids","is_variable","is_grouped","child_ids","price_summary","newspack_popup_id","prompt_title","gate_post_id","recurrence","referrer"],o=(e,t="np_modal_checkout_interaction")=>{if("function"==typeof window.gtag&&e){const o={};for(const t of n)e[t]&&("boolean"==typeof e[t]?e[t]=e[t]?"yes":"no":"true"===e[t]?e[t]="yes":"false"===e[t]&&(e[t]="no"),o[t]=e[t].toString());window.gtag("event",t,o)}},c=e=>{if("function"!=typeof window.gtag)return;let n="opened";const{amount:c="",is_variable:a="",is_grouped:r="",price:i="",variation_id:s=""}=e,l={...e};(c||i)&&(l.amount=c||i),a&&!s&&(n="opened_variations"),r&&(n="opened_grouped");const u=t(n,l);o(u)};function a(e,t=null){const n=document.createElement("input");return n.type="hidden",n.name=e,t&&(n.value=t),n}function r(e){e.requestSubmit(e.querySelector('button[type="submit"]'))}function i(e){const t="string"==typeof e?document.getElementById(e):e;if(!t)return console.warn("No container found for checkout data"),{};let n={};if("FORM"===t.tagName){const e=new FormData(t);n=Object.fromEntries(e)}const o=t.dataset.checkout;if(!o)return console.warn("No checkout data found"),n;try{n={...n,...JSON.parse(o)}}catch(e){console.warn("Error parsing checkout data")}const c=new URL(t.ownerDocument.defaultView.location.href);return c.searchParams.get("action_type")&&(n.action_type=c.searchParams.get("action_type")),n}const s=e=>{if("function"!=typeof window.gtag)return;e=e||i("newspack_modal_checkout");const n=t("dismissed",e);o(n)};function l(e){const t=e&&e.dataset?e.dataset.checkout:null;if(!t)return null;try{return JSON.parse(t)}catch(e){return null}}function u(e,t,n=null){const o=e.querySelectorAll(".wp-block-newspack-blocks-checkout-button"),c=null!=n&&""!==String(n);let a=null;return o.forEach(e=>{if(a)return;const o=e.querySelector("form"),r=l(o);r&&String(r.product_id)===String(t)&&(c&&String(r.variation_id)!==String(n)||(a=o))}),a}const d=["after_success_behavior","after_success_url","after_success_button_label","gate_post_id","newspack_popup_id","prompt_title"];const p={gate:"gate_post_id",prompt:"newspack_popup_id"};const m=newspackBlocksModal.newspack_class_prefix,_="newspack_modal_checkout_iframe",h="newspack_modal_checkout_container",y=`${m}__modal`,w="newspack-blocks__modal-variation",f=`${m}__processing-payment-text`,k=newspackBlocksModal.processing_payment_messages;let v=!1,g=newspackBlocksModal.labels.checkout_modal_title,b=null;const S=e=>{e.overlayId&&window.newspackReaderActivation?.overlays&&window.newspackReaderActivation?.overlays.remove(e.overlayId),e.setAttribute("data-state","closed"),document.body.style.overflow="auto"};window.onpageshow=e=>{e.persisted&&(document.querySelectorAll(".modal-processing").forEach(e=>e.classList.remove("modal-processing")),document.querySelectorAll(".non-modal-checkout-loading").forEach(e=>e.classList.remove("non-modal-checkout-loading")),document.querySelectorAll(`.${y}-container`).forEach(e=>S(e)))};const E=new CustomEvent("checkout-closed");var q;window.newspackRAS=window.newspackRAS||[],q=()=>{const t=document.querySelector("#newspack_modal_checkout");if(!t)return;const n=t.querySelector(`.${y}__content`),o=a("modal_checkout","1"),q=n.querySelector(`.${m}__spinner`);let A=document.querySelector(".newspack-reader__account-link")?.[0];const L="600px",$=document.createElement("iframe");$.name=_,$.style.height=L,$.style.visibility="hidden";const R=e=>{P.observe(e),"none"!==q.style.display&&(q.style.display="none"),"visible"!==$.style.visibility&&($.style.visibility="visible"),$._ready=!0};!function(e,t,n){e._ready=!1,e._readyTimer&&clearTimeout(e._readyTimer);let o=!1,c="";function a(){o||(o=!0,clearTimeout(e._readyTimer),t.call(this))}function r(){"complete"===this.readyState&&a.call(this)}function i(){e._ready=!1,n&&n(),e._readyTimer&&clearTimeout(e._readyTimer);const t=e.contentDocument||e.contentWindow?.document;t&&(t.removeEventListener("DOMContentLoaded",a),t.removeEventListener("readystatechange",r))}function s(){if(e._ready)return void i();const t=e.contentDocument||e.contentWindow?.document;t&&0!==t.URL.indexOf("about:")?"complete"===t?.readyState?a.call(t):(t.addEventListener("DOMContentLoaded",a),t.addEventListener("readystatechange",r)):e._readyTimer=setTimeout(s,10)}e._observer||(e._observer=new MutationObserver(e=>{e.forEach(e=>{"attributes"===e.type&&"src"===e.attributeName&&(o=!1,i(),s())})}),e._observer.observe(e,{attributes:!0})),e._locationObserver||(e._locationObserver=setInterval(function(){const t=e.contentDocument||e.contentWindow?.document;t&&t.URL!==c&&(c=t.URL,o=!1,i(),s())},50)),s()}($,function(){const n=$.contentWindow?.location;if(window.newspackReaderActivation&&n?.href?.includes("order-received")){const e=window.newspackReaderActivation,t=new Proxy(new URLSearchParams(n.search),{get:(e,t)=>e.get(t)});t.email&&(e.setReaderEmail(t.email),e.setAuthenticated(!0))}const o=$?.contentDocument?.querySelector(`#${h}`);if(!o)return;const c=o.querySelector("#modal-checkout-product-details"),a=i(c),r=document.createElement("p");r.classList.add(f);let s=[];const l=()=>{s.forEach(e=>clearTimeout(e)),s=[]},u=()=>{q.style.display="none",l(),q.querySelectorAll(`.${f}`).forEach(e=>e.remove())};!function(e,t){e.checkoutCancel?t():e.addEventListener("checkout-cancel",t)}(o,()=>{D()}),function(e,t){e.checkoutPlaceOrderStart?t():e.addEventListener("checkout-place-order-start",t)}(o,e=>{q.querySelectorAll(`.${f}`).forEach(e=>e.remove()),q.style.display="flex",l(),r.textContent=k[0]?.text??"",k.slice(1).forEach(({text:t,delay:n})=>{const o=setTimeout(()=>{e.target.dispatchEvent(new CustomEvent("checkout-place-order-processing")),r.textContent=t},n);s.push(o)}),q.appendChild(r)}),function(e,t){e.checkoutPlaceOrderError?t():e.addEventListener("checkout-place-order-error",t)}(o,u),function(e,t){e.checkoutReady?t():e.addEventListener("checkout-ready",t)}(o,()=>{const e=c?.querySelector("strong");if(e&&(e.textContent=a.price_summary),t.initialErrors){const e=document.createElement("div");e.classList.add("woocommerce-error"),e.textContent=t.initialErrors,o.prepend(e),delete t.initialErrors}I(),N(g),$.contentWindow?.newspackBlocksModalCheckout?.checkout_nonce&&(t.checkout_nonce=$.contentWindow.newspackBlocksModalCheckout.checkout_nonce),R(o)}),function(e,t){e.checkoutComplete?t():e.addEventListener("checkout-complete",t)}(o,()=>{window.newspackRAS.push(["checkout_completed",a]),window?.newspackReaderActivation?.refreshNewslettersSignupModal&&window?.newspackReaderActivation?.getReader()?.email&&window.newspackReaderActivation.refreshNewslettersSignupModal(window.newspackReaderActivation.getReader().email),I("small"),N(newspackBlocksModal.labels.thankyou_modal_title),R(o),e(t.querySelector(`.${y}`)),u()}),function(e,t){e.checkoutPlaceOrderCriticalError?t():e.addEventListener("checkout-place-order-critical-error",t)}(o,()=>{var e;(e=b)&&(D(),q.style.display="none",t.initialErrors=newspackBlocksModal.labels.critical_error,e.requestSubmit(e.querySelector('button[type="submit"]')),u())})},()=>{q.style.display="flex"});const M=e=>new Promise((t,n)=>{const o=new URLSearchParams(e);o.append("action","modal_checkout_request"),fetch(newspackBlocksModal.ajax_url+"?"+o.toString()).then(e=>{e.ok||n(e),e.json().then(e=>{t(e.url)}).catch(n)}).catch(n)}),C=()=>"undefined"!=typeof newspack_ras_config&&!newspack_ras_config?.is_logged_in&&!window?.newspackReaderActivation?.getReader?.()?.authenticated&&newspackBlocksModal?.is_registration_required&&window?.newspackReaderActivation?.openAuthModal,x=t=>{const n=!newspackBlocksModal.has_unsupported_payment_gateway;n||t.preventDefault();const o=t.target;o.classList.add("modal-processing"),function(e){if(!e||"function"!=typeof e.querySelector)return!1;if(e.closest(".newspack-content-gate__gate"))return!1;const t=function(){let e,t;try{e=window.sessionStorage.getItem("newspack_cta_attribution")}catch(e){return null}if(!e)return null;try{t=JSON.parse(e)}catch(e){return null}return t&&1===t.v&&p[t.type]&&t.id?"number"!=typeof t.ts||Date.now()-t.ts>18e5?null:t:null}();if(!t)return!1;const n=p[t.type];if(e.querySelector(`input[name="${n}"]`))return!1;const o=document.createElement("input");o.type="hidden",o.name=n,o.value=t.id,e.prepend(o)}(o);const u=i(o);if(u.newspack_donate){const e=u.donation_frequency,t=[...o.querySelectorAll(`.donation-tier__${e}, .donation-frequency__${e}`)],n=u.donation_tier_index;let c,a;n?(c=t[n],a=u[`donation_value_${e}`]):(c=t[0],u[`donation_value_${e}_untiered`]?a=u[`donation_value_${e}_untiered`]:(a=u[`donation_value_${e}`],"other"===a&&(a=u[`donation_value_${e}_other`])));const r=i(c);for(const e in r)u[e]=r[e];u.amount=a,u.price_summary=u.summary_template.replace("{{PRICE}}",function(e,t="USD"){return parseFloat(e).toLocaleString(document.documentElement.lang,{style:"currency",currency:t,currencyDisplay:"narrowSymbol"})}(u.amount,u.currency))}u&&Object.keys(u).forEach(e=>{0===o.querySelectorAll('input[name="'+e+'"]').length&&o.prepend(a(e,u[e]))}),u.variation_id||(A=t.submitter);const d=document.querySelectorAll(`.${w}`);if(d.forEach(e=>{(C()||n)&&S(e)}),u.is_grouped||u.is_variable&&!u.variation_id){const n=[...d].find(e=>e.dataset.productId===u.product_id);if(n)return n.querySelectorAll(`form[target="${_}"]`).forEach(e=>{["after_success_behavior","after_success_url","after_success_button_label","gate_post_id","newspack_popup_id","prompt_title"].forEach(t=>{0===e.querySelectorAll('input[name="'+t+'"]').length&&e.prepend(a(t,u[t]))});const t=l(e);t&&Object.keys(t).forEach(n=>{0===e.querySelectorAll('input[name="'+n+'"]').length&&e.prepend(a(n,t[n]))})}),t.preventDefault(),o.classList.remove("modal-processing"),T(n),e(n,!1),v||c(u),void document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u))}if(n||C()){if(o.classList.remove("modal-processing"),v||c(u),v=!0,C()){t.preventDefault();const e=u.price_summary,o=e?`<div class="order-details-summary ${m}__box ${m}__box--text-center"><p><strong>${e}</strong></p></div>`:"",c=M(u);c.then(e=>{window.newspackReaderActivation?.setPendingCheckout?.(e)}),window.newspackReaderActivation.openAuthModal({title:newspackBlocksModal.labels.auth_modal_title,onSuccess:(e,t)=>{c.then(e=>{t?.registered&&n&&(e+=`&${newspackBlocksModal.checkout_registration_flag}=1`),n?r(B(e)):M(u).then(window.location.href=e)}).catch(e=>{console.warn("Unable to generate cart:",e),D()})},onError:()=>{D()},onDismiss:()=>{s(u),v=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout")},skipSuccess:!0,skipNewslettersSignup:!0,labels:{signin:{title:newspackBlocksModal.labels.signin_modal_title},register:{title:newspackBlocksModal.labels.register_modal_title}},content:o,trigger:t.submitter,closeOnSuccess:n})}else O(),document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u));b=o}else M(u).then(e=>{window.location.href=e}),(!u.is_variable||u.variation_id)&&o.querySelectorAll("button[type=submit]:focus").forEach(e=>{e.classList.add("non-modal-checkout-loading");const t=e.innerHTML;e.innerHTML="<span>"+t+"</span>"})},B=e=>{const t=document.createElement("form");t.method="POST",t.action=e,t.target=_,t.style.display="none";const n=document.createElement("button");return n.setAttribute("type","submit"),t.appendChild(n),document.body.appendChild(t),t.addEventListener("submit",x),t},P=new ResizeObserver(e=>{if(!e||!e.length)return;if(!$.contentDocument)return;const o=e[0].contentRect;if(o){const e=.01*Math.max(document.documentElement.clientHeight,window.innerHeight||0)*90-(t.querySelector(`.${y}__header`)?.offsetHeight||0),c=o.top+o.bottom,a=Math.min(c,e);if(0===a)return void($.style.visibility="hidden");n.style.height=a+"px",$.style.height=a+"px"}}),D=()=>{const e=$?.contentDocument?.querySelector(`#${h}`),o=e?.querySelector('input[name="after_success_url"]'),c=e?.querySelector('input[name="after_success_behavior"]'),a=document?.querySelector(".newspack-newsletters-signup-modal"),r=i(e?.querySelector("#modal-checkout-product-details"));e?.checkoutComplete||(async()=>{const e=new FormData;newspackBlocksModal.has_unsupported_payment_gateway||e.append("modal_checkout","1"),e.append("action","abandon_modal_checkout"),e.append("_wpnonce",t.checkout_nonce),t.checkout_nonce=null;try{await fetch(newspackBlocksModal.ajax_url,{method:"POST",body:e})}catch(e){console.warn("Unable to empty cart:",e)}})();const l=!($.contentDocument&&o&&c&&e?.checkoutComplete);if((l||a)&&(q.style.display="flex",$&&n.contains($)&&($._ready=!1,$.src="about:blank",$.style.height=L,$.style.visibility="hidden",n.style.height=L,n.removeChild($)),P&&P.disconnect(),document.querySelectorAll(`.${y}-container`).forEach(e=>S(e)),A&&A.focus(),document.dispatchEvent(E)),e?.checkoutComplete){const e=()=>{if(o&&c){const e=o.getAttribute("value"),t=c.getAttribute("value");"custom"===t?window.location.href=e:"referrer"===t&&window.history.back()}window?.newspackReaderActivation?.setPendingCheckout?.(),v=!1};"subscription_switch"!==r.action_type&&window?.newspackReaderActivation?.openNewslettersSignupModal?window.newspackReaderActivation.openNewslettersSignupModal({onSuccess:e,onError:e,closeOnSuccess:l}):e(),l&&(g=newspackBlocksModal.labels.checkout_modal_title,I(),N(g))}else window?.newspackReaderActivation?.setPendingCheckout?.(),s(),v=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout");document.removeEventListener("keydown",U)},O=o=>{o&&($.src=o),q.style.display="flex",T(t),n.appendChild($),t.addEventListener("click",e=>{e.target===t&&D()}),e(t,$),document.addEventListener("keydown",U)},T=e=>{window.newspackReaderActivation?.overlays&&(e.overlayId=window.newspackReaderActivation?.overlays.add()),e.setAttribute("data-state","open"),document.body.style.overflow="hidden"},N=e=>{const n=t.querySelector(`.${y}__header h2`);n&&(n.innerText=e)},I=(e="default")=>{const n=t.querySelector(`.${y}`);n&&("small"===e?n.classList.add(`${y}--small`):n.classList.remove(`${y}--small`))};t.querySelectorAll(`.${y}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),D()})}),document.querySelectorAll(".newspack-blocks__modal-variation").forEach(e=>{e.addEventListener("click",t=>{t.target===e&&D()}),e.querySelectorAll(`.${y}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),D()})})});const U=e=>{"Escape"===e.key&&D()};document.querySelectorAll(".wpbnbd.wpbnbd--platform-wc, .wp-block-newspack-blocks-checkout-button, .newspack-blocks__modal-variation").forEach(e=>{e.querySelectorAll("form").forEach(e=>{newspackBlocksModal.has_unsupported_payment_gateway||e.prepend(o.cloneNode()),e.target=_,e.addEventListener("submit",x)})}),(()=>{const e=new URLSearchParams(window.location.search);if(!e.has("checkout"))return;let t=!0;const n=e.get("type");if("donate"===n){const t=e.get("layout"),n=e.get("frequency"),o=e.get("amount"),c=e.get("other");t&&n&&o&&((e,t,n,o=null)=>{let c;document.querySelectorAll(".wpbnbd.wpbnbd--platform-wc form").forEach(a=>{const r=a.querySelector(`input[name="donation_frequency"][value="${t}"]`);if(r)if("tiered"===e){const e=document.querySelector(`button[data-frequency-slug="${t}"]`);if(!e)return;e.click();const o=a.querySelector(`button[type="submit"][name="donation_value_${t}"][value="${n}"]`);if(!o)return;o.click()}else{const i="untiered"===e?a.querySelector(`input[name="donation_value_${t}_untiered"]`):a.querySelector(`input[name="donation_value_${t}"][value="${n}"]`);if(r&&i){if(r.checked=!0,"untiered"===e)i.value=n;else if("other"===n){i.click();const e=a.querySelector(`input[name="donation_value_${t}_other"]`);e&&o&&(e.value=o)}else i.checked=!0;c=a}}}),c&&r(c)})(t,n,o,c)}else if("checkout_button"===n){const n=e.get("product_id"),o=e.get("variation_id");n?t=((e,t=null)=>{const n=function(e,t,n,o={}){const{allowProductOnlyFallback:c=!1}=o;if(null==n||""===String(n))return u(e,t,null);const a=u(e,t,n);if(a)return a;const r=function(e,t,n,o={}){const{variationModalClassPrefix:c,iframeName:a}=o,r=[...e.querySelectorAll(`.${c}`)].find(e=>String(e.dataset.productId)===String(t));if(!r)return null;const i=r.querySelectorAll("form"),s=a?[...i].find(e=>e.getAttribute("target")===a):i[0];if(!s)return null;const l=[...s.querySelectorAll('input[type="radio"][name="product_id"]')].find(e=>String(e.value)===String(n));return l?(l.checked=!0,s):null}(e,t,n,o);return r?(function(e,t,n=d){if(!e||!t)return;const o=t.ownerDocument,c=new FormData(e);n.forEach(e=>{if(t.querySelector(`input[name="${e}"]`))return;const n=c.getAll(e).filter(e=>"string"==typeof e&&e);if(!n.length)return;const a=o.createElement("input");a.type="hidden",a.name=e,a.value=n[n.length-1],t.prepend(a)})}(u(e,t,null),r),r):c?u(e,t,null):null}(document,e,t,{variationModalClassPrefix:w,iframeName:_});if(n)return r(n),!0;const o=`Newspack modal checkout: no checkout form found for product_id "${e}"`+(t?` and variation_id "${t}"`:"")+". The checkout was not triggered.";return console.warn(o),!1})(n,o):(t=!1,console.warn("Newspack modal checkout: checkout_button trigger is missing product_id. The checkout was not triggered."))}else{const e=window.newspackReaderActivation?.getPendingCheckout?.();e&&r(B(e))}t&&window.history.replaceState(null,null,window.location.pathname)})(),window.newspackOpenModalCheckout=({url:e=null,title:t=null,actionType:n=null,afterSuccess:o={},onCheckoutComplete:c=null,onClose:a=null})=>{if(g=t||newspackBlocksModal.labels.checkout_modal_title,N(g),(e=new URL(e||newspackBlocksModal.checkout_url)).searchParams.has("my_account_checkout")&&e.searchParams.delete("my_account_checkout"),e.searchParams.has("modal_checkout")||e.searchParams.set("modal_checkout","1"),n&&e.searchParams.set("action_type",n),o?.url&&e.searchParams.set("after_success_url",o.url),(o?.behavior||o?.url)&&e.searchParams.set("after_success_behavior",o.behavior||"custom"),o?.buttonLabel&&e.searchParams.set("after_success_button_label",o.buttonLabel),c){const e=({detail:{action:e,data:t}})=>{"checkout_completed"===e&&c(t)};window.newspackRAS.push(t=>{t.on("activity",e);const n=()=>{t.off("activity",e),document.removeEventListener("checkout-closed",n)};document.addEventListener("checkout-closed",n)})}if(a){const e=()=>{a(),document.removeEventListener("checkout-closed",e)};document.addEventListener("checkout-closed",e)}O(e.toString())},window.newspackCloseModalCheckout=D},"undefined"!=typeof document&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",q):q())})();
|
package/newspack-blocks.php
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Author URI: https://newspack.com/
|
|
8
8
|
* Text Domain: newspack-blocks
|
|
9
9
|
* Domain Path: /languages
|
|
10
|
-
* Version: 4.
|
|
10
|
+
* Version: 4.27.0
|
|
11
11
|
*
|
|
12
12
|
* @package Newspack_Blocks
|
|
13
13
|
*/
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
|
|
16
16
|
define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
|
|
17
17
|
define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
|
|
18
|
-
define( 'NEWSPACK_BLOCKS__VERSION', '4.
|
|
18
|
+
define( 'NEWSPACK_BLOCKS__VERSION', '4.27.0' );
|
|
19
19
|
|
|
20
20
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
|
|
21
21
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/newspack-blocks",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.27.0",
|
|
4
4
|
"author": "Automattic",
|
|
5
5
|
"description": "=== Newspack Blocks === Contributors: (this should be a list of wordpress.org userid's) Donate link: https://example.com/ Tags: comments, spam Requires at least: 4.5 Tested up to: 5.1.1 Stable tag: 0.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html",
|
|
6
6
|
"repository": {
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
getFormattedAmount,
|
|
26
26
|
} from './utils';
|
|
27
27
|
import { resolveCheckoutButtonForm, readCheckoutData } from './checkout-button-trigger';
|
|
28
|
+
import { applyCtaAttribution } from '../shared/js/cta-attribution';
|
|
28
29
|
|
|
29
30
|
const CLASS_PREFIX = newspackBlocksModal.newspack_class_prefix;
|
|
30
31
|
const IFRAME_NAME = 'newspack_modal_checkout_iframe';
|
|
@@ -301,6 +302,13 @@ domReady( () => {
|
|
|
301
302
|
const form = ev.target;
|
|
302
303
|
form.classList.add( 'modal-processing' );
|
|
303
304
|
|
|
305
|
+
// NPPD-1887: if the reader arrived here by clicking a paid-intent CTA in a gate
|
|
306
|
+
// or prompt, replay that surface's id as a hidden field so the order carries
|
|
307
|
+
// `_gate_post_id` / `_newspack_popup_id`. No-ops when the form already has one
|
|
308
|
+
// (a form rendered inside the surface itself always wins) or when the form is
|
|
309
|
+
// inside a gate. Must run BEFORE getCheckoutData(), which snapshots the form.
|
|
310
|
+
applyCtaAttribution( form );
|
|
311
|
+
|
|
304
312
|
const checkoutData = getCheckoutData( form );
|
|
305
313
|
|
|
306
314
|
const isDonateBlock = checkoutData.newspack_donate;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CTA attribution replay (NPPD-1887).
|
|
3
|
+
*
|
|
4
|
+
* The consumer half of the hand-off written by newspack-plugin when a reader clicks a
|
|
5
|
+
* paid-intent CTA inside a gate or prompt and is sent to a landing page. We re-inject
|
|
6
|
+
* the surface's id as a hidden form field, so the existing server chain
|
|
7
|
+
* (`INPUT_GET` -> cart item data -> `_gate_post_id` / `_newspack_popup_id` order meta)
|
|
8
|
+
* fires exactly as it does for a form rendered inside the gate itself.
|
|
9
|
+
*
|
|
10
|
+
* Two cart paths exist, and they apply DIFFERENT filters. Checkout buttons go through
|
|
11
|
+
* `Modal_Checkout::add_to_cart_and_redirect()` -> `newspack_blocks_modal_checkout_cart_item_data`;
|
|
12
|
+
* donations go through `Donations::process_donation_request()` -> `newspack_donations_cart_item_data`.
|
|
13
|
+
* Injecting the field here is necessary but not sufficient — a listener must exist on
|
|
14
|
+
* whichever filter the target form uses, or the id rides all the way into `INPUT_GET`
|
|
15
|
+
* and is then dropped.
|
|
16
|
+
*
|
|
17
|
+
* ── Storage contract ────────────────────────────────────────────────────────────
|
|
18
|
+
* DUPLICATED from newspack-plugin (`src/shared/js/cta-attribution.js`). The two
|
|
19
|
+
* plugins ship independently and share no JS package. Change one, change the other.
|
|
20
|
+
*
|
|
21
|
+
* sessionStorage[ 'newspack_cta_attribution' ] = JSON.stringify( {
|
|
22
|
+
* v: 1,
|
|
23
|
+
* type: 'gate' | 'prompt',
|
|
24
|
+
* id: '123',
|
|
25
|
+
* ts: 1751932800000,
|
|
26
|
+
* } )
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Storage key. Shared with newspack-plugin. */
|
|
30
|
+
export const STORAGE_KEY = 'newspack_cta_attribution';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Storage-record schema version. Must match the writer's in newspack-plugin. A record
|
|
34
|
+
* whose `v` differs is treated as absent rather than trusted, so a drift between the two
|
|
35
|
+
* duplicated copies (e.g. one changes the record shape or TTL) fails safe instead of
|
|
36
|
+
* silently honoring a stale record. (dkoo review, #575.)
|
|
37
|
+
*/
|
|
38
|
+
export const SCHEMA = 1;
|
|
39
|
+
|
|
40
|
+
/** Attribution lifetime, in ms. Kept in sync with newspack-plugin. */
|
|
41
|
+
export const TTL_MS = 30 * 60 * 1000;
|
|
42
|
+
|
|
43
|
+
/** Surface type -> the form field the server reads. */
|
|
44
|
+
const FIELD_BY_TYPE = {
|
|
45
|
+
gate: 'gate_post_id',
|
|
46
|
+
prompt: 'newspack_popup_id',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Read a fresh attribution record, or null.
|
|
51
|
+
*
|
|
52
|
+
* Never throws: `sessionStorage` access raises in Safari private mode, and the stored
|
|
53
|
+
* value is user-writable so `JSON.parse` can fail. Attribution is best-effort — a bad
|
|
54
|
+
* record must never block a checkout.
|
|
55
|
+
*
|
|
56
|
+
* @return {{type: string, id: string, ts: number}|null} The record, or null.
|
|
57
|
+
*/
|
|
58
|
+
export function readCtaAttribution() {
|
|
59
|
+
let raw;
|
|
60
|
+
try {
|
|
61
|
+
raw = window.sessionStorage.getItem( STORAGE_KEY );
|
|
62
|
+
} catch ( e ) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if ( ! raw ) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
let record;
|
|
69
|
+
try {
|
|
70
|
+
record = JSON.parse( raw );
|
|
71
|
+
} catch ( e ) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// Reject records written by a different schema version (drift fail-safe).
|
|
75
|
+
if ( ! record || record.v !== SCHEMA || ! FIELD_BY_TYPE[ record.type ] || ! record.id ) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
// Session-scoped AND time-bounded (NPPD-1887 product decision). A reader who clicks
|
|
79
|
+
// the CTA, wanders off, and converts two hours later in the same tab gets no credit.
|
|
80
|
+
if ( 'number' !== typeof record.ts || Date.now() - record.ts > TTL_MS ) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return record;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Inject the persisted surface id into a checkout/donate form, if it needs one.
|
|
88
|
+
*
|
|
89
|
+
* Two guards, both load-bearing:
|
|
90
|
+
*
|
|
91
|
+
* 1. A form that ALREADY carries the field wins. That is a form rendered inside the
|
|
92
|
+
* gate or prompt itself, whose id was stamped server-side (prompts) or by
|
|
93
|
+
* `gate.js::addFormInputs()` (gates). A replayed value must never overwrite the
|
|
94
|
+
* surface the reader is actually looking at. Same precedence rule that
|
|
95
|
+
* `copyContextFields()` applies to PICKER_CONTEXT_FIELDS.
|
|
96
|
+
*
|
|
97
|
+
* 2. A form inside a gate is never replayed into. `gate.js` owns attribution there,
|
|
98
|
+
* and it binds on the gate's 'seen' event — which may not have fired yet when
|
|
99
|
+
* this runs. Without this guard, a stale id from a gate on a PREVIOUS page could
|
|
100
|
+
* beat the current page's gate to the field.
|
|
101
|
+
*
|
|
102
|
+
* Called from the submit handler rather than at DOM-ready, so it observes the final
|
|
103
|
+
* state of the form after every other script has had its turn.
|
|
104
|
+
*
|
|
105
|
+
* @param {HTMLFormElement} form The form about to be submitted.
|
|
106
|
+
*
|
|
107
|
+
* @return {boolean} Whether a field was injected.
|
|
108
|
+
*/
|
|
109
|
+
export function applyCtaAttribution( form ) {
|
|
110
|
+
if ( ! form || 'function' !== typeof form.querySelector ) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if ( form.closest( '.newspack-content-gate__gate' ) ) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const record = readCtaAttribution();
|
|
117
|
+
if ( ! record ) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const name = FIELD_BY_TYPE[ record.type ];
|
|
121
|
+
if ( form.querySelector( `input[name="${ name }"]` ) ) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
const input = document.createElement( 'input' );
|
|
125
|
+
input.type = 'hidden';
|
|
126
|
+
input.name = name;
|
|
127
|
+
input.value = record.id;
|
|
128
|
+
form.prepend( input );
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the CTA attribution replay (NPPD-1887).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { STORAGE_KEY, SCHEMA, TTL_MS, readCtaAttribution, applyCtaAttribution } from './cta-attribution';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Write a raw value into sessionStorage.
|
|
9
|
+
*
|
|
10
|
+
* Object records are stamped with the current SCHEMA unless they specify their own `v`,
|
|
11
|
+
* mirroring how persistCtaAttribution actually writes — so tests read realistic records,
|
|
12
|
+
* while the version-mismatch test can still supply a drifted `v`.
|
|
13
|
+
*
|
|
14
|
+
* @param {*} value Value to store (stringified unless already a string).
|
|
15
|
+
*/
|
|
16
|
+
function store( value ) {
|
|
17
|
+
if ( value && 'object' === typeof value && undefined === value.v ) {
|
|
18
|
+
value = { v: SCHEMA, ...value };
|
|
19
|
+
}
|
|
20
|
+
window.sessionStorage.setItem( STORAGE_KEY, 'string' === typeof value ? value : JSON.stringify( value ) );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build a detached form, optionally with a pre-existing hidden input.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} options Options.
|
|
27
|
+
* @param {string} options.existing Name of a hidden input to pre-add.
|
|
28
|
+
* @param {string} options.wrapper Class name for a wrapping element.
|
|
29
|
+
* @return {HTMLFormElement} The form (attached to document.body).
|
|
30
|
+
*/
|
|
31
|
+
function makeForm( { existing = null, wrapper = null } = {} ) {
|
|
32
|
+
const form = document.createElement( 'form' );
|
|
33
|
+
if ( existing ) {
|
|
34
|
+
const input = document.createElement( 'input' );
|
|
35
|
+
input.type = 'hidden';
|
|
36
|
+
input.name = existing;
|
|
37
|
+
input.value = 'original';
|
|
38
|
+
form.appendChild( input );
|
|
39
|
+
}
|
|
40
|
+
if ( wrapper ) {
|
|
41
|
+
const el = document.createElement( 'div' );
|
|
42
|
+
el.className = wrapper;
|
|
43
|
+
el.appendChild( form );
|
|
44
|
+
document.body.appendChild( el );
|
|
45
|
+
} else {
|
|
46
|
+
document.body.appendChild( form );
|
|
47
|
+
}
|
|
48
|
+
return form;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe( 'cta-attribution', () => {
|
|
52
|
+
beforeEach( () => {
|
|
53
|
+
window.sessionStorage.clear();
|
|
54
|
+
document.body.innerHTML = '';
|
|
55
|
+
} );
|
|
56
|
+
|
|
57
|
+
describe( 'readCtaAttribution', () => {
|
|
58
|
+
it( 'returns null when nothing is stored', () => {
|
|
59
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
60
|
+
} );
|
|
61
|
+
|
|
62
|
+
it( 'returns a fresh gate record', () => {
|
|
63
|
+
store( { type: 'gate', id: '42', ts: Date.now() } );
|
|
64
|
+
expect( readCtaAttribution() ).toEqual( { v: SCHEMA, type: 'gate', id: '42', ts: expect.any( Number ) } );
|
|
65
|
+
} );
|
|
66
|
+
|
|
67
|
+
// Drift fail-safe: the storage contract is duplicated across newspack-plugin and
|
|
68
|
+
// newspack-blocks. A record written by a different schema version must be ignored,
|
|
69
|
+
// not silently honored. (dkoo review, #575.)
|
|
70
|
+
it( 'rejects a record written by a different schema version', () => {
|
|
71
|
+
store( { v: SCHEMA + 1, type: 'gate', id: '42', ts: Date.now() } );
|
|
72
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
73
|
+
} );
|
|
74
|
+
|
|
75
|
+
it( 'rejects a record older than the TTL', () => {
|
|
76
|
+
store( { type: 'gate', id: '42', ts: Date.now() - TTL_MS - 1000 } );
|
|
77
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
78
|
+
} );
|
|
79
|
+
|
|
80
|
+
it( 'accepts a record right at the TTL boundary', () => {
|
|
81
|
+
store( { type: 'gate', id: '42', ts: Date.now() - TTL_MS + 5000 } );
|
|
82
|
+
expect( readCtaAttribution() ).not.toBeNull();
|
|
83
|
+
} );
|
|
84
|
+
|
|
85
|
+
it( 'rejects an unknown surface type', () => {
|
|
86
|
+
store( { type: 'banner', id: '42', ts: Date.now() } );
|
|
87
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
it( 'rejects a record with no id', () => {
|
|
91
|
+
store( { type: 'gate', ts: Date.now() } );
|
|
92
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
it( 'rejects a non-numeric timestamp rather than treating it as fresh', () => {
|
|
96
|
+
store( { type: 'gate', id: '42', ts: 'now' } );
|
|
97
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
98
|
+
} );
|
|
99
|
+
|
|
100
|
+
it( 'survives malformed JSON', () => {
|
|
101
|
+
store( '{not json' );
|
|
102
|
+
expect( readCtaAttribution() ).toBeNull();
|
|
103
|
+
} );
|
|
104
|
+
} );
|
|
105
|
+
|
|
106
|
+
describe( 'applyCtaAttribution', () => {
|
|
107
|
+
it( 'injects gate_post_id on a bare landing-page form', () => {
|
|
108
|
+
store( { type: 'gate', id: '42', ts: Date.now() } );
|
|
109
|
+
const form = makeForm();
|
|
110
|
+
|
|
111
|
+
expect( applyCtaAttribution( form ) ).toBe( true );
|
|
112
|
+
expect( form.querySelector( 'input[name="gate_post_id"]' ).value ).toBe( '42' );
|
|
113
|
+
} );
|
|
114
|
+
|
|
115
|
+
it( 'injects newspack_popup_id for a prompt record', () => {
|
|
116
|
+
store( { type: 'prompt', id: '7', ts: Date.now() } );
|
|
117
|
+
const form = makeForm();
|
|
118
|
+
|
|
119
|
+
expect( applyCtaAttribution( form ) ).toBe( true );
|
|
120
|
+
expect( form.querySelector( 'input[name="newspack_popup_id"]' ).value ).toBe( '7' );
|
|
121
|
+
} );
|
|
122
|
+
|
|
123
|
+
// Precedence: a form rendered inside the surface itself already carries the id,
|
|
124
|
+
// stamped server-side (prompts) or by gate.js::addFormInputs (gates). A replayed
|
|
125
|
+
// value must never overwrite the surface the reader is actually looking at.
|
|
126
|
+
it( 'never overwrites an existing hidden input', () => {
|
|
127
|
+
store( { type: 'gate', id: '42', ts: Date.now() } );
|
|
128
|
+
const form = makeForm( { existing: 'gate_post_id' } );
|
|
129
|
+
|
|
130
|
+
expect( applyCtaAttribution( form ) ).toBe( false );
|
|
131
|
+
expect( form.querySelector( 'input[name="gate_post_id"]' ).value ).toBe( 'original' );
|
|
132
|
+
expect( form.querySelectorAll( 'input[name="gate_post_id"]' ) ).toHaveLength( 1 );
|
|
133
|
+
} );
|
|
134
|
+
|
|
135
|
+
// gate.js owns attribution inside a gate, and it binds on the gate's 'seen'
|
|
136
|
+
// event, which may not have fired yet. Without this guard a stale id from a gate
|
|
137
|
+
// on a PREVIOUS page could beat the current page's gate to the field.
|
|
138
|
+
it( 'never injects into a form inside a gate', () => {
|
|
139
|
+
store( { type: 'gate', id: '42', ts: Date.now() } );
|
|
140
|
+
const form = makeForm( { wrapper: 'newspack-content-gate__gate' } );
|
|
141
|
+
|
|
142
|
+
expect( applyCtaAttribution( form ) ).toBe( false );
|
|
143
|
+
expect( form.querySelector( 'input[name="gate_post_id"]' ) ).toBeNull();
|
|
144
|
+
} );
|
|
145
|
+
|
|
146
|
+
it( 'does nothing when the record is stale', () => {
|
|
147
|
+
store( { type: 'gate', id: '42', ts: Date.now() - TTL_MS - 1 } );
|
|
148
|
+
const form = makeForm();
|
|
149
|
+
|
|
150
|
+
expect( applyCtaAttribution( form ) ).toBe( false );
|
|
151
|
+
expect( form.querySelector( 'input[name="gate_post_id"]' ) ).toBeNull();
|
|
152
|
+
} );
|
|
153
|
+
|
|
154
|
+
it( 'does nothing when nothing is stored', () => {
|
|
155
|
+
const form = makeForm();
|
|
156
|
+
expect( applyCtaAttribution( form ) ).toBe( false );
|
|
157
|
+
} );
|
|
158
|
+
|
|
159
|
+
it( 'tolerates a missing form', () => {
|
|
160
|
+
store( { type: 'gate', id: '42', ts: Date.now() } );
|
|
161
|
+
expect( applyCtaAttribution( null ) ).toBe( false );
|
|
162
|
+
expect( applyCtaAttribution( undefined ) ).toBe( false );
|
|
163
|
+
} );
|
|
164
|
+
} );
|
|
165
|
+
} );
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
'name' => 'automattic/newspack-blocks',
|
|
4
4
|
'pretty_version' => 'dev-main',
|
|
5
5
|
'version' => 'dev-main',
|
|
6
|
-
'reference' => '
|
|
6
|
+
'reference' => '20e84f87dc1be96b5575548593fd0f7e77da52e6',
|
|
7
7
|
'type' => 'wordpress-plugin',
|
|
8
8
|
'install_path' => __DIR__ . '/../../',
|
|
9
9
|
'aliases' => array(),
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
'automattic/newspack-blocks' => array(
|
|
14
14
|
'pretty_version' => 'dev-main',
|
|
15
15
|
'version' => 'dev-main',
|
|
16
|
-
'reference' => '
|
|
16
|
+
'reference' => '20e84f87dc1be96b5575548593fd0f7e77da52e6',
|
|
17
17
|
'type' => 'wordpress-plugin',
|
|
18
18
|
'install_path' => __DIR__ . '/../../',
|
|
19
19
|
'aliases' => array(),
|