@automattic/newspack-blocks 4.28.1-hotfix-blocks-input-validation.2 → 4.28.1-hotfix-blocks-input-validation.4
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/AGENTS.md +2 -2
- package/CHANGELOG.md +4 -2
- package/dist/modal.asset.php +1 -1
- package/dist/modal.js +1 -1
- package/includes/class-modal-checkout.php +286 -16
- package/newspack-blocks.php +2 -2
- package/package.json +1 -1
- package/src/blocks/checkout-button/view.php +4 -0
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-base.php +10 -0
- package/src/modal-checkout/checkout-button-trigger.js +1 -0
- package/src/modal-checkout/modal.js +5 -10
- package/src/modal-checkout/templates/thankyou.php +4 -1
- package/vendor/composer/installed.php +2 -2
package/AGENTS.md
CHANGED
|
@@ -207,7 +207,7 @@ REST controllers are instantiated via wrapper functions hooked to `rest_api_init
|
|
|
207
207
|
- **Functions**: `newspack_blocks_*` prefix (e.g., `newspack_blocks_render_block_homepage_articles`)
|
|
208
208
|
- **Classes**: `Newspack_Blocks*` or `WP_REST_Newspack_*` for REST controllers
|
|
209
209
|
- **Constants**: `NEWSPACK_BLOCKS__*` (double underscore)
|
|
210
|
-
- **Hooks**: `newspack_blocks_*` prefix; modal-specific use `
|
|
210
|
+
- **Hooks**: `newspack_blocks_*` prefix; modal-specific use `newspack_blocks_modal_checkout_*`
|
|
211
211
|
- **Text domain**: `newspack-blocks`
|
|
212
212
|
- **Block names**: Short slugs in `block.json`, namespaced as `newspack-blocks/<slug>` in PHP/JS
|
|
213
213
|
|
|
@@ -268,7 +268,7 @@ Partial adoption. Some blocks use `.ts`/`.tsx` (homepage-articles `edit.tsx`, do
|
|
|
268
268
|
The plugin exposes many hooks. Rather than listing them all here (they change over time), use `grep -r 'apply_filters\|do_action' src/ includes/` to find current hooks. The key hook prefixes are:
|
|
269
269
|
|
|
270
270
|
- **`newspack_blocks_*`**: General block hooks (query building, deduplication, registration, author data)
|
|
271
|
-
- **`
|
|
271
|
+
- **`newspack_blocks_modal_checkout_*`**: Modal checkout specific hooks (labels, gateways, billing fields, HTML output)
|
|
272
272
|
|
|
273
273
|
## CI/CD
|
|
274
274
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
## @automattic/newspack-blocks [4.28.1-hotfix-blocks-input-validation.
|
|
1
|
+
## @automattic/newspack-blocks [4.28.1-hotfix-blocks-input-validation.4](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.28.1-hotfix-blocks-input-validation.3...newspack-blocks@4.28.1-hotfix-blocks-input-validation.4) (2026-08-06)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
* **blocks:**
|
|
6
|
+
* **blocks:** bind post-checkout destination tokens to published posts ([f4bf13e](https://github.com/Automattic/newspack-workspace/commit/f4bf13e95da3dbe3fc9430c5f3aa06758c81ba34))
|
|
7
|
+
* **blocks:** keep protocol-relative post-checkout destinations intact ([2fa64cc](https://github.com/Automattic/newspack-workspace/commit/2fa64cc9f09a9f2a5bd48de28aba9ed298be4572))
|
|
8
|
+
* **blocks:** sign publisher-configured post-checkout destinations ([3ec364b](https://github.com/Automattic/newspack-workspace/commit/3ec364b021b321e7732f564c7a18f706985a8544))
|
|
7
9
|
|
|
8
10
|
# @automattic/newspack-blocks [4.28.0](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.27.1...newspack-blocks@4.28.0) (2026-07-20)
|
|
9
11
|
|
package/dist/modal.asset.php
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<?php return array('dependencies' => array(), 'version' => '
|
|
1
|
+
<?php return array('dependencies' => array(), 'version' => 'f9760843d53d18537bf6');
|
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={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");if("custom"===t)window.location.href=e;else if("referrer"===t){const e=document.referrer;let t=!1;if(e)try{new URL(e).origin===window.location.origin&&(window.location.href=e,t=!0)}catch(e){}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())})();
|
|
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","after_success_token","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 h=document.querySelectorAll(`.${w}`);if(h.forEach(e=>{(C()||n)&&S(e)}),u.is_grouped||u.is_variable&&!u.variation_id){const n=[...h].find(e=>e.dataset.productId===u.product_id);if(n)return n.querySelectorAll(`form[target="${_}"]`).forEach(e=>{d.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");if("custom"===t)window.location.href=e;else if("referrer"===t){const e=document.referrer;let t=!1;if(e)try{new URL(e).origin===window.location.origin&&(window.location.href=e,t=!0)}catch(e){}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())})();
|
|
@@ -377,6 +377,7 @@ final class Modal_Checkout {
|
|
|
377
377
|
$after_success_behavior = filter_input( INPUT_GET, 'after_success_behavior', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
378
378
|
$after_success_url = filter_input( INPUT_GET, 'after_success_url', FILTER_SANITIZE_URL );
|
|
379
379
|
$after_success_button_label = filter_input( INPUT_GET, 'after_success_button_label', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
380
|
+
$after_success_token = filter_input( INPUT_GET, 'after_success_token', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
380
381
|
|
|
381
382
|
if ( $variation_id ) {
|
|
382
383
|
$product_id = $variation_id;
|
|
@@ -395,7 +396,7 @@ final class Modal_Checkout {
|
|
|
395
396
|
wp_parse_str( $parsed_url['query'], $params );
|
|
396
397
|
}
|
|
397
398
|
|
|
398
|
-
$params = array_merge( $params, compact( 'after_success_behavior', 'after_success_url', 'after_success_button_label' ) );
|
|
399
|
+
$params = array_merge( $params, compact( 'after_success_behavior', 'after_success_url', 'after_success_button_label', 'after_success_token' ) );
|
|
399
400
|
|
|
400
401
|
if ( function_exists( 'wpcom_vip_url_to_postid' ) ) {
|
|
401
402
|
$referer_post_id = wpcom_vip_url_to_postid( $referer );
|
|
@@ -1198,35 +1199,300 @@ final class Modal_Checkout {
|
|
|
1198
1199
|
*/
|
|
1199
1200
|
const AFTER_SUCCESS_BEHAVIORS = [ 'custom', 'referrer' ];
|
|
1200
1201
|
|
|
1202
|
+
/**
|
|
1203
|
+
* Reduce a post-checkout destination to a single comparable form.
|
|
1204
|
+
*
|
|
1205
|
+
* Signing and verifying have to agree on the exact string, and the value passes through
|
|
1206
|
+
* sanitising on its way between them, so both sides normalise here rather than each
|
|
1207
|
+
* doing their own.
|
|
1208
|
+
*
|
|
1209
|
+
* @param string $url The requested destination.
|
|
1210
|
+
*
|
|
1211
|
+
* @return string The normalised destination, or an empty string.
|
|
1212
|
+
*/
|
|
1213
|
+
public static function normalize_after_success_url( $url ) {
|
|
1214
|
+
$url = sanitize_url( (string) $url );
|
|
1215
|
+
|
|
1216
|
+
if ( empty( $url ) ) {
|
|
1217
|
+
return '';
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// Core compares hosts case-sensitively; host names aren't. Rebuild from the parsed
|
|
1221
|
+
// parts rather than replacing the host in the string: the host can appear again
|
|
1222
|
+
// inside a query parameter, and a `user@host` authority never matches `://host` at
|
|
1223
|
+
// all, so a string replacement either rewrites too much or nothing.
|
|
1224
|
+
$parts = wp_parse_url( $url );
|
|
1225
|
+
if ( ! empty( $parts['host'] ) && strtolower( $parts['host'] ) !== $parts['host'] ) {
|
|
1226
|
+
$parts['host'] = strtolower( $parts['host'] );
|
|
1227
|
+
$url = self::build_url( $parts );
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
return $url;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Reassemble a URL from `wp_parse_url()` parts.
|
|
1235
|
+
*
|
|
1236
|
+
* @param array $parts Parsed URL parts.
|
|
1237
|
+
*
|
|
1238
|
+
* @return string
|
|
1239
|
+
*/
|
|
1240
|
+
private static function build_url( $parts ) {
|
|
1241
|
+
$user = $parts['user'] ?? '';
|
|
1242
|
+
$pass = isset( $parts['pass'] ) ? ':' . $parts['pass'] : '';
|
|
1243
|
+
$auth = $user ? $user . $pass . '@' : '';
|
|
1244
|
+
|
|
1245
|
+
// A destination with a host but no scheme is protocol-relative. Losing the `//` here
|
|
1246
|
+
// would turn it into a relative path, which changes where the reader lands and makes
|
|
1247
|
+
// this function non-idempotent — and the token signs a normalised value at mint and
|
|
1248
|
+
// normalises again at read, so idempotence is what makes it verify.
|
|
1249
|
+
$prefix = isset( $parts['scheme'] )
|
|
1250
|
+
? $parts['scheme'] . '://'
|
|
1251
|
+
: ( isset( $parts['host'] ) ? '//' : '' );
|
|
1252
|
+
|
|
1253
|
+
return $prefix
|
|
1254
|
+
. $auth
|
|
1255
|
+
. ( $parts['host'] ?? '' )
|
|
1256
|
+
. ( isset( $parts['port'] ) ? ':' . $parts['port'] : '' )
|
|
1257
|
+
. ( $parts['path'] ?? '' )
|
|
1258
|
+
. ( isset( $parts['query'] ) ? '?' . $parts['query'] : '' )
|
|
1259
|
+
. ( isset( $parts['fragment'] ) ? '#' . $parts['fragment'] : '' );
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Whether a post is published, read from the stored status.
|
|
1264
|
+
*
|
|
1265
|
+
* `get_post_status()` reports an attachment as `publish` whatever its stored status, so a
|
|
1266
|
+
* token could be minted from one and could not be revoked by unpublishing. Reading the
|
|
1267
|
+
* field directly returns the real status, and also steps around the `get_post_status`
|
|
1268
|
+
* filter, which would otherwise let any plugin move this gate.
|
|
1269
|
+
*
|
|
1270
|
+
* @param int $post_id The post to check.
|
|
1271
|
+
*
|
|
1272
|
+
* @return boolean
|
|
1273
|
+
*/
|
|
1274
|
+
private static function is_published_post( $post_id ) {
|
|
1275
|
+
return 'publish' === get_post_field( 'post_status', (int) $post_id );
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* The post a block is being rendered for.
|
|
1280
|
+
*
|
|
1281
|
+
* `get_the_ID()` is empty outside the loop, which is where a block in a widget or a footer
|
|
1282
|
+
* template part renders. The queried object covers that, but only when it is a post: on an
|
|
1283
|
+
* archive it is a term, whose ID would otherwise be read as an unrelated post's.
|
|
1284
|
+
*
|
|
1285
|
+
* @return int Post ID, or 0.
|
|
1286
|
+
*/
|
|
1287
|
+
private static function get_after_success_post_id() {
|
|
1288
|
+
$post_id = (int) get_the_ID();
|
|
1289
|
+
|
|
1290
|
+
if ( $post_id ) {
|
|
1291
|
+
return $post_id;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
$queried = get_queried_object();
|
|
1295
|
+
|
|
1296
|
+
return $queried instanceof WP_Post ? (int) $queried->ID : 0;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Sign a value for the post-checkout destination it belongs to.
|
|
1301
|
+
*
|
|
1302
|
+
* Namespaced so this never produces the same digest as another use of the same key —
|
|
1303
|
+
* `wp_hash()` with the auth salt also backs the magic-link and email-change secrets, and
|
|
1304
|
+
* these signatures are published in page HTML.
|
|
1305
|
+
*
|
|
1306
|
+
* @param string $payload The value to sign.
|
|
1307
|
+
*
|
|
1308
|
+
* @return string
|
|
1309
|
+
*/
|
|
1310
|
+
private static function sign_after_success_payload( $payload ) {
|
|
1311
|
+
// The namespace prefix is what separates this from every other use of the same key and
|
|
1312
|
+
// algorithm. `Reader_Registration::get_frontend_registration_key()` also produces
|
|
1313
|
+
// `hash_hmac( 'sha256', …, wp_salt( 'auth' ) )` and publishes the result to the front
|
|
1314
|
+
// end, so nothing but this prefix distinguishes the two. Never register an integration
|
|
1315
|
+
// ID that begins with it.
|
|
1316
|
+
//
|
|
1317
|
+
// The blog ID is included because `wp_salt()` is network-scoped: without it, a token
|
|
1318
|
+
// minted on one site of a network verifies on every other site in that network.
|
|
1319
|
+
$namespace = 'newspack_blocks_after_success|' . get_current_blog_id() . '|';
|
|
1320
|
+
|
|
1321
|
+
return hash_hmac( 'sha256', $namespace . $payload, wp_salt( 'auth' ) );
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Mint a token vouching for a post-checkout destination a block was configured with.
|
|
1326
|
+
*
|
|
1327
|
+
* Minted where the block renders, which is the last point this site knows the destination
|
|
1328
|
+
* came from its own content rather than from the request. Two properties matter:
|
|
1329
|
+
*
|
|
1330
|
+
* The destination travels *inside* the token rather than beside it. The token's alphabet
|
|
1331
|
+
* is URL-safe base64 plus a dot, so the sanitising the value meets in transit — which
|
|
1332
|
+
* variously deletes percent-encoded octets, drops non-ASCII bytes and HTML-encodes `&`
|
|
1333
|
+
* and `'` — cannot alter it. Signing the bare URL and hoping every transit point leaves
|
|
1334
|
+
* it alone is what this avoids.
|
|
1335
|
+
*
|
|
1336
|
+
* The token is bound to the post being rendered, and only published posts are signed, so
|
|
1337
|
+
* a token cannot be minted through the block-renderer REST route or a draft preview by
|
|
1338
|
+
* someone who can edit posts but not publish them.
|
|
1339
|
+
*
|
|
1340
|
+
* `hash_hmac` rather than a nonce: the token has to survive page caching and a reader who
|
|
1341
|
+
* signs in partway through checkout, and a nonce is bound to a user and a time window.
|
|
1342
|
+
*
|
|
1343
|
+
* @param string $url The destination to vouch for.
|
|
1344
|
+
* @param int $post_id The post being rendered. Defaults to the current post.
|
|
1345
|
+
*
|
|
1346
|
+
* @return string The token, or an empty string if there is nothing to vouch for.
|
|
1347
|
+
*/
|
|
1348
|
+
public static function get_after_success_token( $url, $post_id = 0 ) {
|
|
1349
|
+
$url = self::normalize_after_success_url( $url );
|
|
1350
|
+
|
|
1351
|
+
if ( '' === $url ) {
|
|
1352
|
+
return '';
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
$post_id = $post_id ? (int) $post_id : self::get_after_success_post_id();
|
|
1356
|
+
|
|
1357
|
+
if ( ! $post_id || ! self::is_published_post( $post_id ) ) {
|
|
1358
|
+
return '';
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
$payload = self::encode_after_success_payload(
|
|
1362
|
+
[
|
|
1363
|
+
'u' => $url,
|
|
1364
|
+
'p' => $post_id,
|
|
1365
|
+
]
|
|
1366
|
+
);
|
|
1367
|
+
|
|
1368
|
+
return $payload . '.' . self::sign_after_success_payload( $payload );
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/**
|
|
1372
|
+
* Read a destination back out of a token, if this site vouched for it.
|
|
1373
|
+
*
|
|
1374
|
+
* @param string $token The token offered with the request.
|
|
1375
|
+
*
|
|
1376
|
+
* @return string The destination, or an empty string if the token is not this site's.
|
|
1377
|
+
*/
|
|
1378
|
+
public static function parse_after_success_token( $token ) {
|
|
1379
|
+
$token = (string) $token;
|
|
1380
|
+
|
|
1381
|
+
if ( '' === $token || false === strpos( $token, '.' ) ) {
|
|
1382
|
+
return '';
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
list( $payload, $signature ) = explode( '.', $token, 2 );
|
|
1386
|
+
|
|
1387
|
+
if ( '' === $payload || '' === $signature ) {
|
|
1388
|
+
return '';
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if ( ! hash_equals( self::sign_after_success_payload( $payload ), $signature ) ) {
|
|
1392
|
+
return '';
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
$claims = self::decode_after_success_payload( $payload );
|
|
1396
|
+
|
|
1397
|
+
if ( empty( $claims['u'] ) || empty( $claims['p'] ) ) {
|
|
1398
|
+
return '';
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// Checked at read time as well as at mint time: a post that has since been
|
|
1402
|
+
// unpublished should stop vouching for its destination.
|
|
1403
|
+
if ( ! self::is_published_post( (int) $claims['p'] ) ) {
|
|
1404
|
+
return '';
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
return self::normalize_after_success_url( $claims['u'] );
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Encode token claims into a form transit cannot alter.
|
|
1412
|
+
*
|
|
1413
|
+
* @param array $claims The claims to encode.
|
|
1414
|
+
*
|
|
1415
|
+
* @return string URL-safe base64.
|
|
1416
|
+
*/
|
|
1417
|
+
private static function encode_after_success_payload( $claims ) {
|
|
1418
|
+
return rtrim( strtr( base64_encode( (string) wp_json_encode( $claims ) ), '+/', '-_' ), '=' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* Decode token claims.
|
|
1423
|
+
*
|
|
1424
|
+
* @param string $payload URL-safe base64.
|
|
1425
|
+
*
|
|
1426
|
+
* @return array The claims, or an empty array if the payload is unreadable.
|
|
1427
|
+
*/
|
|
1428
|
+
private static function decode_after_success_payload( $payload ) {
|
|
1429
|
+
$json = base64_decode( strtr( $payload, '-_', '+/' ), true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
|
1430
|
+
|
|
1431
|
+
if ( false === $json ) {
|
|
1432
|
+
return [];
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
$claims = json_decode( $json, true );
|
|
1436
|
+
|
|
1437
|
+
return is_array( $claims ) ? $claims : [];
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1201
1440
|
/**
|
|
1202
1441
|
* Reduce a post-checkout destination to one this site is willing to send readers to.
|
|
1203
1442
|
*
|
|
1204
1443
|
* The destination reaches the thank-you page through the request, whether it came from
|
|
1205
1444
|
* the block's own settings or from the link the reader followed, and by that point the
|
|
1206
|
-
* two
|
|
1207
|
-
*
|
|
1208
|
-
* own
|
|
1209
|
-
* plugin has added (`Newspack\NRH` registers one).
|
|
1445
|
+
* two look alike. A signature tells them apart: one is minted when a block renders a
|
|
1446
|
+
* destination a publisher configured, so a destination carrying a valid one is this
|
|
1447
|
+
* site's own and is honoured wherever it points.
|
|
1210
1448
|
*
|
|
1211
|
-
*
|
|
1449
|
+
* Everything else falls to core's redirect validation, which accepts what
|
|
1450
|
+
* `allowed_redirect_hosts` reports — this site's own host, plus whatever a publisher
|
|
1451
|
+
* adds through that filter, plus anything another plugin has added (`Newspack\NRH`
|
|
1452
|
+
* registers one). A destination arriving in a link with no signature has to clear that
|
|
1453
|
+
* bar, which is what keeps a crafted link from choosing where a reader lands.
|
|
1454
|
+
*
|
|
1455
|
+
* @param string $url The requested destination.
|
|
1456
|
+
* @param string $token Token offered with the request, if any.
|
|
1212
1457
|
*
|
|
1213
1458
|
* @return string The destination, or an empty string if it is not allowed.
|
|
1214
1459
|
*/
|
|
1215
|
-
public static function sanitize_after_success_url( $url ) {
|
|
1216
|
-
|
|
1460
|
+
public static function sanitize_after_success_url( $url, $token = '' ) {
|
|
1461
|
+
// A token carries its own destination, so a mutated `after_success_url` alongside it
|
|
1462
|
+
// is ignored rather than compared against.
|
|
1463
|
+
$vouched = self::parse_after_success_token( $token );
|
|
1464
|
+
|
|
1465
|
+
if ( '' !== $vouched ) {
|
|
1466
|
+
// Returned as verified. `wp_sanitize_redirect()` is deliberately not applied to
|
|
1467
|
+
// this branch: it strips `'` and percent-encodes non-ASCII, so it would rewrite a
|
|
1468
|
+
// destination this site has already established is the publisher's own — the same
|
|
1469
|
+
// drift the token exists to prevent. The untrusted branch below still gets it, via
|
|
1470
|
+
// `wp_validate_redirect()`. Both have been through `sanitize_url()` in normalising.
|
|
1471
|
+
return $vouched;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
$url = self::normalize_after_success_url( $url );
|
|
1217
1475
|
|
|
1218
1476
|
if ( empty( $url ) ) {
|
|
1219
1477
|
return '';
|
|
1220
1478
|
}
|
|
1221
1479
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1480
|
+
$validated = (string) wp_validate_redirect( $url, '' );
|
|
1481
|
+
|
|
1482
|
+
if ( '' === $validated ) {
|
|
1483
|
+
/**
|
|
1484
|
+
* Fires when a post-checkout destination is refused.
|
|
1485
|
+
*
|
|
1486
|
+
* The reader is sent nowhere and the modal simply closes, which looks the same
|
|
1487
|
+
* as a publisher not configuring a destination at all. This is the hook to
|
|
1488
|
+
* watch if you need to tell those two apart.
|
|
1489
|
+
*
|
|
1490
|
+
* @param string $url The refused destination.
|
|
1491
|
+
*/
|
|
1492
|
+
do_action( 'newspack_blocks_modal_checkout_after_success_url_rejected', $url );
|
|
1227
1493
|
}
|
|
1228
1494
|
|
|
1229
|
-
return
|
|
1495
|
+
return $validated;
|
|
1230
1496
|
}
|
|
1231
1497
|
|
|
1232
1498
|
/**
|
|
@@ -1255,7 +1521,8 @@ final class Modal_Checkout {
|
|
|
1255
1521
|
unset(
|
|
1256
1522
|
$params['after_success_behavior'],
|
|
1257
1523
|
$params['after_success_url'],
|
|
1258
|
-
$params['after_success_button_label']
|
|
1524
|
+
$params['after_success_button_label'],
|
|
1525
|
+
$params['after_success_token']
|
|
1259
1526
|
);
|
|
1260
1527
|
}
|
|
1261
1528
|
|
|
@@ -1275,11 +1542,14 @@ final class Modal_Checkout {
|
|
|
1275
1542
|
\wp_parse_str( $referrer_query, $request_params );
|
|
1276
1543
|
}
|
|
1277
1544
|
}
|
|
1545
|
+
$token = isset( $request_params['after_success_token'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_token'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1546
|
+
|
|
1278
1547
|
$params = array_filter(
|
|
1279
1548
|
[
|
|
1280
1549
|
'after_success_behavior' => isset( $request_params['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_behavior'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1281
|
-
'after_success_url' => isset( $request_params['after_success_url'] ) ? self::sanitize_after_success_url( wp_unslash( $request_params['after_success_url'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1550
|
+
'after_success_url' => isset( $request_params['after_success_url'] ) ? self::sanitize_after_success_url( wp_unslash( $request_params['after_success_url'] ), $token ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1282
1551
|
'after_success_button_label' => isset( $request_params['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_button_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1552
|
+
'after_success_token' => $token,
|
|
1283
1553
|
'action_type' => isset( $request_params['action_type'] ) ? sanitize_text_field( wp_unslash( $request_params['action_type'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1284
1554
|
]
|
|
1285
1555
|
);
|
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.28.1-hotfix-blocks-input-validation.
|
|
10
|
+
* Version: 4.28.1-hotfix-blocks-input-validation.4
|
|
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.28.1-hotfix-blocks-input-validation.
|
|
18
|
+
define( 'NEWSPACK_BLOCKS__VERSION', '4.28.1-hotfix-blocks-input-validation.4' );
|
|
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.28.1-hotfix-blocks-input-validation.
|
|
3
|
+
"version": "4.28.1-hotfix-blocks-input-validation.4",
|
|
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": {
|
|
@@ -113,6 +113,10 @@ function render_callback( $attributes ) {
|
|
|
113
113
|
$hidden_fields .= $after_success_behavior ? '<input type="hidden" name="after_success_behavior" value="' . esc_attr( $after_success_behavior ) . '" />' : '';
|
|
114
114
|
$hidden_fields .= $after_success_button_label ? '<input type="hidden" name="after_success_button_label" value="' . esc_attr( $after_success_button_label ) . '" />' : '';
|
|
115
115
|
$hidden_fields .= $after_success_url ? '<input type="hidden" name="after_success_url" value="' . esc_attr( $after_success_url ) . '" />' : '';
|
|
116
|
+
// Vouched for here because this is the last point the destination is known to come
|
|
117
|
+
// from the block's own settings rather than from the request.
|
|
118
|
+
$after_success_token = $after_success_url ? Modal_Checkout::get_after_success_token( $after_success_url ) : '';
|
|
119
|
+
$hidden_fields .= $after_success_token ? '<input type="hidden" name="after_success_token" value="' . esc_attr( $after_success_token ) . '" />' : '';
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
ob_start();
|
|
@@ -212,6 +212,16 @@ abstract class Newspack_Blocks_Donate_Renderer_Base {
|
|
|
212
212
|
<input type='hidden' name='<?php echo esc_attr( $param_name ); ?>' value='<?php echo esc_attr( $value ); ?>' />
|
|
213
213
|
<?php
|
|
214
214
|
}
|
|
215
|
+
|
|
216
|
+
// Vouched for here because this is the last point the destination is known to come
|
|
217
|
+
// from the block's own settings rather than from the request.
|
|
218
|
+
$after_success_url = isset( $attributes['afterSuccessURL'] ) ? $attributes['afterSuccessURL'] : '';
|
|
219
|
+
$after_success_token = $after_success_url ? \Newspack_Blocks\Modal_Checkout::get_after_success_token( $after_success_url ) : '';
|
|
220
|
+
if ( $after_success_token ) {
|
|
221
|
+
?>
|
|
222
|
+
<input type='hidden' name='after_success_token' value='<?php echo esc_attr( $after_success_token ); ?>' />
|
|
223
|
+
<?php
|
|
224
|
+
}
|
|
215
225
|
}
|
|
216
226
|
return ob_get_clean();
|
|
217
227
|
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
getCheckoutData,
|
|
25
25
|
getFormattedAmount,
|
|
26
26
|
} from './utils';
|
|
27
|
-
import { resolveCheckoutButtonForm, readCheckoutData } from './checkout-button-trigger';
|
|
27
|
+
import { resolveCheckoutButtonForm, readCheckoutData, PICKER_CONTEXT_FIELDS } from './checkout-button-trigger';
|
|
28
28
|
import { applyCtaAttribution } from '../shared/js/cta-attribution';
|
|
29
29
|
|
|
30
30
|
const CLASS_PREFIX = newspackBlocksModal.newspack_class_prefix;
|
|
@@ -369,15 +369,10 @@ domReady( () => {
|
|
|
369
369
|
const variationModal = [ ...variationModals ].find( modal => modal.dataset.productId === checkoutData.product_id );
|
|
370
370
|
if ( variationModal ) {
|
|
371
371
|
variationModal.querySelectorAll( `form[target="${ IFRAME_NAME }"]` ).forEach( singleVariationForm => {
|
|
372
|
-
// Fill in the hidden params in the variation modal.
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
'after_success_button_label',
|
|
377
|
-
'gate_post_id',
|
|
378
|
-
'newspack_popup_id',
|
|
379
|
-
'prompt_title',
|
|
380
|
-
].forEach( hiddenParam => {
|
|
372
|
+
// Fill in the hidden params in the variation modal. Shares one list with
|
|
373
|
+
// copyContextFields() so the two cannot drift: a field missing here is a
|
|
374
|
+
// field the variation path silently drops.
|
|
375
|
+
PICKER_CONTEXT_FIELDS.forEach( hiddenParam => {
|
|
381
376
|
const existingInputs = singleVariationForm.querySelectorAll( 'input[name="' + hiddenParam + '"]' );
|
|
382
377
|
if ( 0 === existingInputs.length ) {
|
|
383
378
|
singleVariationForm.prepend( createHiddenInput( hiddenParam, checkoutData[ hiddenParam ] ) );
|
|
@@ -47,7 +47,10 @@ if ( ! $is_valid ) {
|
|
|
47
47
|
|
|
48
48
|
$is_success = ! $order->has_status( 'failed' );
|
|
49
49
|
$after_success_behavior = isset( $_GET['after_success_behavior'] ) ? \sanitize_text_field( \wp_unslash( $_GET['after_success_behavior'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
50
|
-
$
|
|
50
|
+
$after_success_token = isset( $_GET['after_success_token'] ) ? \sanitize_text_field( \wp_unslash( $_GET['after_success_token'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
51
|
+
// Not escaped here: the value is escaped where it is output, and escaping it into the
|
|
52
|
+
// variable would leave it holding something other than the destination that was verified.
|
|
53
|
+
$after_success_url = isset( $_GET['after_success_url'] ) ? \Newspack_Blocks\Modal_Checkout::sanitize_after_success_url( \sanitize_url( \wp_unslash( $_GET['after_success_url'] ) ), $after_success_token ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
51
54
|
$after_success_label = isset( $_GET['after_success_button_label'] ) ? \sanitize_text_field( \wp_unslash( $_GET['after_success_button_label'] ) ) : \Newspack_Blocks\Modal_Checkout::get_modal_checkout_labels( 'after_success' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
52
55
|
$checkout_data = Checkout_Data::get_checkout_data( $order );
|
|
53
56
|
|
|
@@ -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' => 'cadf9db7f24b87094470dcebc368c87e8f5cda36',
|
|
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' => 'cadf9db7f24b87094470dcebc368c87e8f5cda36',
|
|
17
17
|
'type' => 'wordpress-plugin',
|
|
18
18
|
'install_path' => __DIR__ . '/../../',
|
|
19
19
|
'aliases' => array(),
|