@automattic/newspack-blocks 4.33.1 → 4.34.0-alpha.2

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/editor-rtl.css +4 -3
  3. package/dist/editor.asset.php +1 -1
  4. package/dist/editor.css +4 -3
  5. package/dist/editor.js +14 -14
  6. package/dist/modal.asset.php +1 -1
  7. package/dist/modal.js +1 -1
  8. package/includes/class-modal-checkout.php +248 -6
  9. package/includes/class-newspack-blocks-api.php +8 -0
  10. package/includes/class-newspack-blocks.php +38 -0
  11. package/languages/newspack-blocks-de_DE.po +124 -119
  12. package/languages/newspack-blocks-es_ES.po +124 -119
  13. package/languages/newspack-blocks-fr_BE.po +124 -119
  14. package/languages/newspack-blocks-nb_NO.po +124 -119
  15. package/languages/newspack-blocks-pt_PT.po +124 -119
  16. package/languages/newspack-blocks.pot +129 -125
  17. package/newspack-blocks.php +2 -2
  18. package/package.json +2 -2
  19. package/src/blocks/author-list/class-wp-rest-newspack-author-list-controller.php +6 -1
  20. package/src/blocks/author-profile/class-wp-rest-newspack-authors-controller.php +196 -48
  21. package/src/blocks/author-profile/edit.js +23 -65
  22. package/src/blocks/author-profile/single-author.js +7 -12
  23. package/src/blocks/author-profile/social-links.js +25 -0
  24. package/src/blocks/author-profile/social-links.test.js +42 -0
  25. package/src/blocks/checkout-button/view.php +4 -2
  26. package/src/blocks/homepage-articles/templates/article.php +1 -18
  27. package/src/modal-checkout/checkout-button-trigger.js +162 -24
  28. package/src/modal-checkout/checkout-button-trigger.test.js +149 -9
  29. package/src/modal-checkout/modal.js +31 -1
  30. package/src/shared/js/author-fetch.js +217 -0
  31. package/src/shared/js/author-fetch.test.js +230 -0
  32. package/vendor/composer/installed.php +2 -2
@@ -1 +1 @@
1
- <?php return array('dependencies' => array(), 'version' => '8fb8b74fcbccebc97dfe');
1
+ <?php return array('dependencies' => array(), 'version' => 'ad0265d8573d5220c5fe');
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","quantity","variation_id","variation_ids","is_variable","is_grouped","child_ids","price_summary","newspack_popup_id","prompt_title","gate_post_id","contextual_prompt_post_id","contextual_prompt_placement","contextual_prompt_condition","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","contextual_prompt_post_id","contextual_prompt_placement","contextual_prompt_condition","coupon","quantity"];const p=["tiered","frequency","untiered"],m=["once","month","year"];const h={gate:"gate_post_id",prompt:"newspack_popup_id"};const f=newspackBlocksModal.newspack_class_prefix,y="newspack_modal_checkout_iframe",_="newspack_modal_checkout_container",w=`${f}__modal`,k="newspack-blocks__modal-variation",g=`${f}__processing-payment-text`,v=newspackBlocksModal.processing_payment_messages;let b=!1,S=newspackBlocksModal.labels.checkout_modal_title,E=null;const q=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(`.${w}-container`).forEach(e=>q(e)))};const A=new CustomEvent("checkout-closed");var L;window.newspackRAS=window.newspackRAS||[],L=()=>{const t=document.querySelector("#newspack_modal_checkout");if(!t)return;const n=t.querySelector(`.${w}__content`),o=a("modal_checkout","1"),L=n.querySelector(`.${f}__spinner`);let $=document.querySelector(".newspack-reader__account-link")?.[0];const R="600px",M=document.createElement("iframe");M.name=y,M.style.height=R,M.style.visibility="hidden";const x=e=>{D.observe(e),"none"!==L.style.display&&(L.style.display="none"),"visible"!==M.style.visibility&&(M.style.visibility="visible"),M._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()}(M,function(){const n=M.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=M?.contentDocument?.querySelector(`#${_}`);if(!o)return;const c=i(o.querySelector("#modal-checkout-product-details")),a=document.createElement("p");a.classList.add(g);let r=[];const s=()=>{r.forEach(e=>clearTimeout(e)),r=[]},l=()=>{L.style.display="none",s(),L.querySelectorAll(`.${g}`).forEach(e=>e.remove())};!function(e,t){e.checkoutCancel?t():e.addEventListener("checkout-cancel",t)}(o,()=>{I()}),function(e,t){e.checkoutPlaceOrderStart?t():e.addEventListener("checkout-place-order-start",t)}(o,e=>{L.querySelectorAll(`.${g}`).forEach(e=>e.remove()),L.style.display="flex",s(),a.textContent=v[0]?.text??"",v.slice(1).forEach(({text:t,delay:n})=>{const o=setTimeout(()=>{e.target.dispatchEvent(new CustomEvent("checkout-place-order-processing")),a.textContent=t},n);r.push(o)}),L.appendChild(a)}),function(e,t){e.checkoutPlaceOrderError?t():e.addEventListener("checkout-place-order-error",t)}(o,l),function(e,t){e.checkoutReady?t():e.addEventListener("checkout-ready",t)}(o,()=>{if(t.initialErrors){const e=document.createElement("div");e.classList.add("woocommerce-error"),e.textContent=t.initialErrors,o.prepend(e),delete t.initialErrors}j(),U(S),M.contentWindow?.newspackBlocksModalCheckout?.checkout_nonce&&(t.checkout_nonce=M.contentWindow.newspackBlocksModalCheckout.checkout_nonce),x(o)}),function(e,t){e.checkoutComplete?t():e.addEventListener("checkout-complete",t)}(o,()=>{window.newspackRAS.push(["checkout_completed",c]),window?.newspackReaderActivation?.refreshNewslettersSignupModal&&window?.newspackReaderActivation?.getReader()?.email&&window.newspackReaderActivation.refreshNewslettersSignupModal(window.newspackReaderActivation.getReader().email),j("small"),U(newspackBlocksModal.labels.thankyou_modal_title),x(o),e(t.querySelector(`.${w}`)),l()}),function(e,t){e.checkoutPlaceOrderCriticalError?t():e.addEventListener("checkout-place-order-critical-error",t)}(o,()=>{var e;(e=E)&&(I(),L.style.display="none",t.initialErrors=newspackBlocksModal.labels.critical_error,e.requestSubmit(e.querySelector('button[type="submit"]')),l())})},()=>{L.style.display="flex"});const C=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)}),B=()=>"undefined"!=typeof newspack_ras_config&&!newspack_ras_config?.is_logged_in&&!window?.newspackReaderActivation?.getReader?.()?.authenticated&&newspackBlocksModal?.is_registration_required&&window?.newspackReaderActivation?.openAuthModal,P=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&&h[t.type]&&t.id?"number"!=typeof t.ts||Date.now()-t.ts>18e5?null:t:null}();if(!t)return!1;const n=h[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||($=t.submitter);const p=document.querySelectorAll(`.${k}`);if(p.forEach(e=>{(B()||n)&&q(e)}),u.is_grouped||u.is_variable&&!u.variation_id){const n=[...p].find(e=>e.dataset.productId===u.product_id);if(n)return n.querySelectorAll(`form[target="${y}"]`).forEach(e=>{!function(e,t,n=d){if(!e||!t)return;const o=e.ownerDocument;n.forEach(n=>{if(e.querySelectorAll(`input[type="hidden"][name="${n}"]`).forEach(e=>e.remove()),function(e,t){return!!e.querySelector(`input[name="${t}"]:not([type="hidden"])`)}(e,n))return;const c=t[n],a=null==c?"":String(c);if(!a)return;const r=o.createElement("input");r.type="hidden",r.name=n,r.value=a,e.prepend(r)})}(e,u);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),b||c(u),void document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u))}if(n||B()){if(o.classList.remove("modal-processing"),b||c(u),b=!0,B()){t.preventDefault();const e=C(u);e.then(e=>{window.newspackReaderActivation?.setPendingCheckout?.(e)}),window.newspackReaderActivation.openAuthModal({title:newspackBlocksModal.labels.auth_modal_title,onSuccess:(t,o)=>{e.then(e=>{o?.registered&&n&&(e+=`&${newspackBlocksModal.checkout_registration_flag}=1`),n?r(T(e)):C(u).then(window.location.href=e)}).catch(e=>{console.warn("Unable to generate cart:",e),I()})},onError:()=>{I()},onDismiss:()=>{s(u),b=!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}},trigger:t.submitter,closeOnSuccess:n})}else N(),document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u));E=o}else C(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>"})},T=e=>{const t=document.createElement("form");t.method="POST",t.action=e,t.target=y,t.style.display="none";const n=document.createElement("button");return n.setAttribute("type","submit"),t.appendChild(n),document.body.appendChild(t),t.addEventListener("submit",P),t},D=new ResizeObserver(e=>{if(!e||!e.length)return;if(!M.contentDocument)return;const o=e[0].contentRect;if(o){const e=.01*Math.max(document.documentElement.clientHeight,window.innerHeight||0)*90-(t.querySelector(`.${w}__header`)?.offsetHeight||0),c=o.top+o.bottom,a=Math.min(c,e);if(0===a)return void(M.style.visibility="hidden");n.style.height=a+"px",M.style.height=a+"px"}}),I=()=>{const e=M?.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=!(M.contentDocument&&o&&c&&e?.checkoutComplete);if((l||a)&&(L.style.display="flex",M&&n.contains(M)&&(M._ready=!1,M.src="about:blank",M.style.height=R,M.style.visibility="hidden",n.style.height=R,n.removeChild(M)),D&&D.disconnect(),document.querySelectorAll(`.${w}-container`).forEach(e=>q(e)),$&&$.focus(),document.dispatchEvent(A)),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?.(),b=!1};"subscription_switch"!==r.action_type&&window?.newspackReaderActivation?.openNewslettersSignupModal?window.newspackReaderActivation.openNewslettersSignupModal({onSuccess:e,onError:e,closeOnSuccess:l}):e(),l&&(S=newspackBlocksModal.labels.checkout_modal_title,j(),U(S))}else window?.newspackReaderActivation?.setPendingCheckout?.(),s(),b=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout");document.removeEventListener("keydown",W)},N=o=>{o&&(M.src=o),L.style.display="flex",O(t),n.appendChild(M),t.addEventListener("click",e=>{e.target===t&&I()}),e(t,M),document.addEventListener("keydown",W)},O=e=>{window.newspackReaderActivation?.overlays&&(e.overlayId=window.newspackReaderActivation?.overlays.add()),e.setAttribute("data-state","open"),document.body.style.overflow="hidden"},U=e=>{const n=t.querySelector(`.${w}__header h2`);n&&(n.innerText=e)},j=(e="default")=>{const n=t.querySelector(`.${w}`);n&&("small"===e?n.classList.add(`${w}--small`):n.classList.remove(`${w}--small`))};t.querySelectorAll(`.${w}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),I()})}),document.querySelectorAll(".newspack-blocks__modal-variation").forEach(e=>{e.addEventListener("click",t=>{t.target===e&&I()}),e.querySelectorAll(`.${w}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),I()})})});const W=e=>{"Escape"===e.key&&I()};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=y,e.addEventListener("submit",P)})});const F=["checkout","type","layout","frequency","amount","other","product_id","variation_id"],H=()=>{const e=new URL(window.location.href);F.forEach(t=>e.searchParams.delete(t)),window.history.replaceState(null,null,e.href)},J=(e,t,n,o=null)=>{const c=function(e,{layout:t,frequency:n,amount:o}){if(!function(e,t,n){return!(!p.includes(e)||!m.includes(t))&&("other"===n?"frequency"===e:/^\d+(\.\d+)?$/.test(n))}(t,n,o))return{status:"invalid-params"};let c=null;for(const a of e.querySelectorAll(".wpbnbd.wpbnbd--platform-wc form")){const e=a.closest(".wpbnbd--tiers-based");if("tiered"===t){if(!e)continue;const t=a.querySelector(`.wpbnbd__tiers__amount [data-frequency-slug="${n}"][data-amount="${o}"]`);if(!t)continue;const r=parseInt(t.getAttribute("data-tier-index"));if(isNaN(r))continue;const i=a.querySelector(`button[data-frequency-slug="${n}"]`);if(!i&&!a.querySelector(`input[name="donation_frequency"][value="${n}"]`))continue;if(!e.hasAttribute("data-tiers-based-ready")){c||(c=a);continue}return{status:"tiered",form:a,frequencyButton:i,tierIndex:r}}if(e)continue;const r=a.querySelector(`input[name="donation_frequency"][value="${n}"]`);if(!r)continue;const i="untiered"===t?a.querySelector(`input[name="donation_value_${n}_untiered"]`):a.querySelector(`input[name="donation_value_${n}"][value="${o}"]`);if(i)return{status:t,form:a,frequencyInput:r,amountInput:i}}return c?{status:"not-ready",form:c}:{status:"no-match"}}(document,{layout:e,frequency:t,amount:n}),a=`layout "${e}", frequency "${t}" and amount "${n}"`;if("invalid-params"===c.status)return console.warn(`Newspack modal checkout: invalid donate trigger parameters (${a}). The checkout was not triggered.`),!1;if("no-match"===c.status)return console.warn(`Newspack modal checkout: no donate form matches ${a}. The checkout was not triggered.`),!1;if("not-ready"===c.status){const c=setTimeout(()=>{console.warn(`Newspack modal checkout: the donate form matching ${a} never finished initializing. The checkout was not triggered; the URL params were kept so a reload can retry.`)},5e3);return document.addEventListener("newspack-tiers-based-ready",()=>{clearTimeout(c),J(e,t,n,o)&&H()},{once:!0}),!1}const{form:i}=c;if("tiered"===c.status){c.frequencyButton&&c.frequencyButton.click();const e=i.querySelector(`button[type="submit"][data-tier-index="${c.tierIndex}"]`);return e?(e.click(),!0):(console.warn(`Newspack modal checkout: no tier submit button matches ${a}. The checkout was not triggered.`),!1)}if(c.frequencyInput.checked=!0,"untiered"===c.status)c.amountInput.value=n;else if("other"===n){c.amountInput.click();const e=i.querySelector(`input[name="donation_value_${t}_other"]`);e&&o&&(e.value=o)}else c.amountInput.checked=!0;return i.checkValidity()?(r(i),!0):(console.warn(`Newspack modal checkout: the donate form rejected the values for ${a}. The checkout was not triggered.`),!1)};(()=>{const e=new URLSearchParams(window.location.search);if(!e.has("checkout"))return;let t=!0;const n=e.get("type");if("donate"===n){const n=e.get("layout"),o=e.get("frequency"),c=e.get("amount"),a=e.get("other");n&&o&&c?t=J(n,o,c,a):(t=!1,console.warn("Newspack modal checkout: donate trigger is missing layout, frequency or amount. The checkout was not triggered."))}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)})}(function(e,t){const n=e.querySelectorAll(".wp-block-newspack-blocks-checkout-button");let o=null,c=null;return n.forEach(e=>{if(c)return;const n=e.querySelector("form"),a=l(n);a&&String(a.product_id)===String(t)&&(a.variation_id?o=o||n:c=n)}),c||o}(e,t),r),r):c?u(e,t,null):null}(document,e,t,{variationModalClassPrefix:k,iframeName:y});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(T(e))}t&&H()})(),window.newspackOpenModalCheckout=({url:e=null,title:t=null,actionType:n=null,afterSuccess:o={},quantity:c=null,onCheckoutComplete:a=null,onClose:r=null})=>{if(S=t||newspackBlocksModal.labels.checkout_modal_title,U(S),(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),c&&parseInt(c,10)>1&&e.searchParams.set("quantity",String(parseInt(c,10))),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),a){const e=({detail:{action:e,data:t}})=>{"checkout_completed"===e&&a(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(r){const e=()=>{r(),document.removeEventListener("checkout-closed",e)};document.addEventListener("checkout-closed",e)}N(e.toString())},window.newspackCloseModalCheckout=I},"undefined"!=typeof document&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",L):L())})();
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","quantity","variation_id","variation_ids","is_variable","is_grouped","child_ids","price_summary","newspack_popup_id","prompt_title","gate_post_id","contextual_prompt_post_id","contextual_prompt_placement","contextual_prompt_condition","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:r="",is_grouped:a="",price:i="",variation_id:s=""}=e,l={...e};(c||i)&&(l.amount=c||i),r&&!s&&(n="opened_variations"),a&&(n="opened_grouped");const u=t(n,l);o(u)};function r(e,t=null){const n=document.createElement("input");return n.type="hidden",n.name=e,t&&(n.value=t),n}function a(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}}const u=e=>Boolean(e.closest(".newspack-blocks__url-triggered-checkout"));function d(e,t,n=null,o={}){const{synthesized:c=null}=o,r=e.querySelectorAll(".wp-block-newspack-blocks-checkout-button"),a=null!=n&&""!==String(n);let i=null;return r.forEach(e=>{if(i)return;if(null!==c&&u(e)!==c)return;const o=e.querySelector("form"),r=l(o);r&&String(r.product_id)===String(t)&&(a&&String(r.variation_id)!==String(n)||!a&&r.variation_id||(i=o))}),i}function p(e,t,n={}){const{synthesized:o=null}=n,c=e.querySelectorAll(".wp-block-newspack-blocks-checkout-button");let r=null,a=null;return c.forEach(e=>{if(a)return;if(null!==o&&u(e)!==o)return;const n=e.querySelector("form"),c=l(n);c&&String(c.product_id)===String(t)&&(c.variation_id?r=r||n:a=n)}),a||r}function m(e,t,n,o={}){const{variationModalClassPrefix:c,iframeName:r}=o,a=[...e.querySelectorAll(`.${c}`)].find(e=>String(e.dataset.productId)===String(t));if(!a)return null;const i=a.querySelectorAll("form"),s=r?[...i].find(e=>e.getAttribute("target")===r):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}const h=["after_success_behavior","after_success_url","after_success_button_label","after_success_token","gate_post_id","newspack_popup_id","prompt_title","contextual_prompt_post_id","contextual_prompt_placement","contextual_prompt_condition","coupon","quantity"];function f(e,t,n=h){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 r=o.createElement("input");r.type="hidden",r.name=e,r.value=n[n.length-1],t.prepend(r)})}const y=["coupon","after_success_behavior","after_success_url","after_success_button_label"],_=["tiered","frequency","untiered"],w=["once","month","year"];const k={gate:"gate_post_id",prompt:"newspack_popup_id"};const g=newspackBlocksModal.newspack_class_prefix,v="newspack_modal_checkout_iframe",b="newspack_modal_checkout_container",S=`${g}__modal`,E="newspack-blocks__modal-variation",q=`${g}__processing-payment-text`,A=newspackBlocksModal.processing_payment_messages;let L=!1,$=newspackBlocksModal.labels.checkout_modal_title,R=null;const M=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(`.${S}-container`).forEach(e=>M(e)))};const x=new CustomEvent("checkout-closed");var C;window.newspackRAS=window.newspackRAS||[],C=()=>{const t=document.querySelector("#newspack_modal_checkout");if(!t)return;const n=t.querySelector(`.${S}__content`),o=r("modal_checkout","1"),u=n.querySelector(`.${g}__spinner`);let C=document.querySelector(".newspack-reader__account-link")?.[0];const B="600px",P=document.createElement("iframe");P.name=v,P.style.height=B,P.style.visibility="hidden";const T=e=>{j.observe(e),"none"!==u.style.display&&(u.style.display="none"),"visible"!==P.style.visibility&&(P.style.visibility="visible"),P._ready=!0};!function(e,t,n){e._ready=!1,e._readyTimer&&clearTimeout(e._readyTimer);let o=!1,c="";function r(){o||(o=!0,clearTimeout(e._readyTimer),t.call(this))}function a(){"complete"===this.readyState&&r.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",r),t.removeEventListener("readystatechange",a))}function s(){if(e._ready)return void i();const t=e.contentDocument||e.contentWindow?.document;t&&0!==t.URL.indexOf("about:")?"complete"===t?.readyState?r.call(t):(t.addEventListener("DOMContentLoaded",r),t.addEventListener("readystatechange",a)):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()}(P,function(){const n=P.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=P?.contentDocument?.querySelector(`#${b}`);if(!o)return;const c=i(o.querySelector("#modal-checkout-product-details")),r=document.createElement("p");r.classList.add(q);let a=[];const s=()=>{a.forEach(e=>clearTimeout(e)),a=[]},l=()=>{u.style.display="none",s(),u.querySelectorAll(`.${q}`).forEach(e=>e.remove())};!function(e,t){e.checkoutCancel?t():e.addEventListener("checkout-cancel",t)}(o,()=>{z()}),function(e,t){e.checkoutPlaceOrderStart?t():e.addEventListener("checkout-place-order-start",t)}(o,e=>{u.querySelectorAll(`.${q}`).forEach(e=>e.remove()),u.style.display="flex",s(),r.textContent=A[0]?.text??"",A.slice(1).forEach(({text:t,delay:n})=>{const o=setTimeout(()=>{e.target.dispatchEvent(new CustomEvent("checkout-place-order-processing")),r.textContent=t},n);a.push(o)}),u.appendChild(r)}),function(e,t){e.checkoutPlaceOrderError?t():e.addEventListener("checkout-place-order-error",t)}(o,l),function(e,t){e.checkoutReady?t():e.addEventListener("checkout-ready",t)}(o,()=>{if(t.initialErrors){const e=document.createElement("div");e.classList.add("woocommerce-error"),e.textContent=t.initialErrors,o.prepend(e),delete t.initialErrors}J(),H($),P.contentWindow?.newspackBlocksModalCheckout?.checkout_nonce&&(t.checkout_nonce=P.contentWindow.newspackBlocksModalCheckout.checkout_nonce),T(o)}),function(e,t){e.checkoutComplete?t():e.addEventListener("checkout-complete",t)}(o,()=>{window.newspackRAS.push(["checkout_completed",c]),window?.newspackReaderActivation?.refreshNewslettersSignupModal&&window?.newspackReaderActivation?.getReader()?.email&&window.newspackReaderActivation.refreshNewslettersSignupModal(window.newspackReaderActivation.getReader().email),J("small"),H(newspackBlocksModal.labels.thankyou_modal_title),T(o),e(t.querySelector(`.${S}`)),l()}),function(e,t){e.checkoutPlaceOrderCriticalError?t():e.addEventListener("checkout-place-order-critical-error",t)}(o,()=>{var e;(e=R)&&(z(),u.style.display="none",t.initialErrors=newspackBlocksModal.labels.critical_error,e.requestSubmit(e.querySelector('button[type="submit"]')),l())})},()=>{u.style.display="flex"});const D=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)}),I=()=>"undefined"!=typeof newspack_ras_config&&!newspack_ras_config?.is_logged_in&&!window?.newspackReaderActivation?.getReader?.()?.authenticated&&newspackBlocksModal?.is_registration_required&&window?.newspackReaderActivation?.openAuthModal,N=function(e){const t={};return new URLSearchParams(e).forEach((e,n)=>{n.startsWith("utm")&&e&&(t[n]=e)}),t}(window.location.search),O=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&&k[t.type]&&t.id?"number"!=typeof t.ts||Date.now()-t.ts>18e5?null:t:null}();if(!t)return!1;const n=k[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),function(e,t){if(!e||!t)return;const n=e.ownerDocument;Object.keys(t).forEach(o=>{if(!t[o]||e.elements.namedItem(o))return;const c=n.createElement("input");c.type="hidden",c.name=o,c.value=t[o],e.prepend(c)})}(o,N);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,r;n?(c=t[n],r=u[`donation_value_${e}`]):(c=t[0],u[`donation_value_${e}_untiered`]?r=u[`donation_value_${e}_untiered`]:(r=u[`donation_value_${e}`],"other"===r&&(r=u[`donation_value_${e}_other`])));const a=i(c);for(const e in a)u[e]=a[e];u.amount=r,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(r(e,u[e]))}),u.variation_id||(C=t.submitter);const d=document.querySelectorAll(`.${E}`);if(d.forEach(e=>{(I()||n)&&M(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="${v}"]`).forEach(e=>{!function(e,t,n=h){if(!e||!t)return;const o=e.ownerDocument;n.forEach(n=>{if(e.querySelectorAll(`input[type="hidden"][name="${n}"]`).forEach(e=>e.remove()),function(e,t){return!!e.querySelector(`input[name="${t}"]:not([type="hidden"])`)}(e,n))return;const c=t[n],r=null==c?"":String(c);if(!r)return;const a=o.createElement("input");a.type="hidden",a.name=n,a.value=r,e.prepend(a)})}(e,u);const t=l(e);t&&Object.keys(t).forEach(n=>{0===e.querySelectorAll('input[name="'+n+'"]').length&&e.prepend(r(n,t[n]))})}),t.preventDefault(),o.classList.remove("modal-processing"),F(n),e(n,!1),L||c(u),void document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u))}if(n||I()){if(o.classList.remove("modal-processing"),L||c(u),L=!0,I()){t.preventDefault();const e=D(u);e.then(e=>{window.newspackReaderActivation?.setPendingCheckout?.(e)}),window.newspackReaderActivation.openAuthModal({title:newspackBlocksModal.labels.auth_modal_title,onSuccess:(t,o)=>{e.then(e=>{o?.registered&&n&&(e+=`&${newspackBlocksModal.checkout_registration_flag}=1`),n?a(U(e)):D(u).then(window.location.href=e)}).catch(e=>{console.warn("Unable to generate cart:",e),z()})},onError:()=>{z()},onDismiss:()=>{s(u),L=!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}},trigger:t.submitter,closeOnSuccess:n})}else W(),document.getElementById("newspack_modal_checkout").setAttribute("data-checkout",JSON.stringify(u));R=o}else D(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>"})},U=e=>{const t=document.createElement("form");t.method="POST",t.action=e,t.target=v,t.style.display="none";const n=document.createElement("button");return n.setAttribute("type","submit"),t.appendChild(n),document.body.appendChild(t),t.addEventListener("submit",O),t},j=new ResizeObserver(e=>{if(!e||!e.length)return;if(!P.contentDocument)return;const o=e[0].contentRect;if(o){const e=.01*Math.max(document.documentElement.clientHeight,window.innerHeight||0)*90-(t.querySelector(`.${S}__header`)?.offsetHeight||0),c=o.top+o.bottom,r=Math.min(c,e);if(0===r)return void(P.style.visibility="hidden");n.style.height=r+"px",P.style.height=r+"px"}}),z=()=>{const e=P?.contentDocument?.querySelector(`#${b}`),o=e?.querySelector('input[name="after_success_url"]'),c=e?.querySelector('input[name="after_success_behavior"]'),r=document?.querySelector(".newspack-newsletters-signup-modal"),a=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=!(P.contentDocument&&o&&c&&e?.checkoutComplete);if((l||r)&&(u.style.display="flex",P&&n.contains(P)&&(P._ready=!1,P.src="about:blank",P.style.height=B,P.style.visibility="hidden",n.style.height=B,n.removeChild(P)),j&&j.disconnect(),document.querySelectorAll(`.${S}-container`).forEach(e=>M(e)),C&&C.focus(),document.dispatchEvent(x)),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?.(),L=!1};"subscription_switch"!==a.action_type&&window?.newspackReaderActivation?.openNewslettersSignupModal?window.newspackReaderActivation.openNewslettersSignupModal({onSuccess:e,onError:e,closeOnSuccess:l}):e(),l&&($=newspackBlocksModal.labels.checkout_modal_title,J(),H($))}else window?.newspackReaderActivation?.setPendingCheckout?.(),s(),L=!1,document.getElementById("newspack_modal_checkout").removeAttribute("data-checkout");document.removeEventListener("keydown",K)},W=o=>{o&&(P.src=o),u.style.display="flex",F(t),n.appendChild(P),t.addEventListener("click",e=>{e.target===t&&z()}),e(t,P),document.addEventListener("keydown",K)},F=e=>{window.newspackReaderActivation?.overlays&&(e.overlayId=window.newspackReaderActivation?.overlays.add()),e.setAttribute("data-state","open"),document.body.style.overflow="hidden"},H=e=>{const n=t.querySelector(`.${S}__header h2`);n&&(n.innerText=e)},J=(e="default")=>{const n=t.querySelector(`.${S}`);n&&("small"===e?n.classList.add(`${S}--small`):n.classList.remove(`${S}--small`))};t.querySelectorAll(`.${S}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),z()})}),document.querySelectorAll(".newspack-blocks__modal-variation").forEach(e=>{e.addEventListener("click",t=>{t.target===e&&z()}),e.querySelectorAll(`.${S}__close`).forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),z()})})});const K=e=>{"Escape"===e.key&&z()};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=v,e.addEventListener("submit",O)})});const V=["checkout","type","layout","frequency","amount","other","product_id","variation_id"],G=()=>{const e=new URL(window.location.href);V.forEach(t=>e.searchParams.delete(t)),window.history.replaceState(null,null,e.href)},Q=(e,t,n,o=null)=>{const c=function(e,{layout:t,frequency:n,amount:o}){if(!function(e,t,n){return!(!_.includes(e)||!w.includes(t))&&("other"===n?"frequency"===e:/^\d+(\.\d+)?$/.test(n))}(t,n,o))return{status:"invalid-params"};let c=null;for(const r of e.querySelectorAll(".wpbnbd.wpbnbd--platform-wc form")){const e=r.closest(".wpbnbd--tiers-based");if("tiered"===t){if(!e)continue;const t=r.querySelector(`.wpbnbd__tiers__amount [data-frequency-slug="${n}"][data-amount="${o}"]`);if(!t)continue;const a=parseInt(t.getAttribute("data-tier-index"));if(isNaN(a))continue;const i=r.querySelector(`button[data-frequency-slug="${n}"]`);if(!i&&!r.querySelector(`input[name="donation_frequency"][value="${n}"]`))continue;if(!e.hasAttribute("data-tiers-based-ready")){c||(c=r);continue}return{status:"tiered",form:r,frequencyButton:i,tierIndex:a}}if(e)continue;const a=r.querySelector(`input[name="donation_frequency"][value="${n}"]`);if(!a)continue;const i="untiered"===t?r.querySelector(`input[name="donation_value_${n}_untiered"]`):r.querySelector(`input[name="donation_value_${n}"][value="${o}"]`);if(i)return{status:t,form:r,frequencyInput:a,amountInput:i}}return c?{status:"not-ready",form:c}:{status:"no-match"}}(document,{layout:e,frequency:t,amount:n}),r=`layout "${e}", frequency "${t}" and amount "${n}"`;if("invalid-params"===c.status)return console.warn(`Newspack modal checkout: invalid donate trigger parameters (${r}). The checkout was not triggered.`),!1;if("no-match"===c.status)return console.warn(`Newspack modal checkout: no donate form matches ${r}. The checkout was not triggered.`),!1;if("not-ready"===c.status){const c=setTimeout(()=>{console.warn(`Newspack modal checkout: the donate form matching ${r} never finished initializing. The checkout was not triggered; the URL params were kept so a reload can retry.`)},5e3);return document.addEventListener("newspack-tiers-based-ready",()=>{clearTimeout(c),Q(e,t,n,o)&&G()},{once:!0}),!1}const{form:i}=c;if("tiered"===c.status){c.frequencyButton&&c.frequencyButton.click();const e=i.querySelector(`button[type="submit"][data-tier-index="${c.tierIndex}"]`);return e?(e.click(),!0):(console.warn(`Newspack modal checkout: no tier submit button matches ${r}. The checkout was not triggered.`),!1)}if(c.frequencyInput.checked=!0,"untiered"===c.status)c.amountInput.value=n;else if("other"===n){c.amountInput.click();const e=i.querySelector(`input[name="donation_value_${t}_other"]`);e&&o&&(e.value=o)}else c.amountInput.checked=!0;return i.checkValidity()?(a(i),!0):(console.warn(`Newspack modal checkout: the donate form rejected the values for ${r}. The checkout was not triggered.`),!1)};(()=>{const e=new URLSearchParams(window.location.search);if(!e.has("checkout"))return;let t=!0;const n=e.get("type");if("donate"===n){const n=e.get("layout"),o=e.get("frequency"),c=e.get("amount"),r=e.get("other");n&&o&&c?t=Q(n,o,c,r):(t=!1,console.warn("Newspack modal checkout: donate trigger is missing layout, frequency or amount. The checkout was not triggered."))}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={}){if(null==n||""===String(n))return d(e,t,null,{synthesized:!1})||d(e,t,null,{synthesized:!0});const c=d(e,t,n,{synthesized:!1});if(c)return c;const r=p(e,t,{synthesized:!1});if(r){const c=m(e,t,n,o);if(c)return f(r,c),c}const a=d(e,t,n,{synthesized:!0});if(a)return a;const i=m(e,t,n,o);return i?(f(p(e,t),i),i):null}(document,e,t,{variationModalClassPrefix:E,iframeName:v});if(n){const e=function(e,t){const n=new URLSearchParams(t);return y.filter(t=>n.get(t)&&!(e&&e.elements.namedItem(t)))}(n,window.location.search);return e.length&&console.warn(`Newspack modal checkout: the resolved checkout form does not carry ${e.join(", ")} from the URL. The page block's own settings apply instead.`),a(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&&a(U(e))}t&&G()})(),window.newspackOpenModalCheckout=({url:e=null,title:t=null,actionType:n=null,afterSuccess:o={},quantity:c=null,onCheckoutComplete:r=null,onClose:a=null})=>{if($=t||newspackBlocksModal.labels.checkout_modal_title,H($),(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),c&&parseInt(c,10)>1&&e.searchParams.set("quantity",String(parseInt(c,10))),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),r){const e=({detail:{action:e,data:t}})=>{"checkout_completed"===e&&r(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)}W(e.toString())},window.newspackCloseModalCheckout=z},"undefined"!=typeof document&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",C):C())})();
@@ -119,6 +119,14 @@ final class Modal_Checkout {
119
119
  */
120
120
  private static $has_modal = false;
121
121
 
122
+ /**
123
+ * Block markup synthesized from URL trigger params, echoed (hidden) in the
124
+ * footer. Empty when the request carries no valid trigger.
125
+ *
126
+ * @var string
127
+ */
128
+ private static $url_triggered_block_html = '';
129
+
122
130
  /**
123
131
  * Products that are being rendered a checkout modal for.
124
132
  *
@@ -231,6 +239,7 @@ final class Modal_Checkout {
231
239
  add_filter( 'wp_redirect', [ __CLASS__, 'pass_url_param_on_redirect' ] );
232
240
  add_filter( 'woocommerce_cart_product_cannot_be_purchased_message', [ __CLASS__, 'woocommerce_cart_product_cannot_be_purchased_message' ], 10, 2 );
233
241
  add_filter( 'woocommerce_add_error', [ __CLASS__, 'hide_expiry_message_shop_link' ] );
242
+ add_action( 'wp', [ __CLASS__, 'maybe_setup_url_triggered_checkout' ], 11 );
234
243
  add_action( 'wp_footer', [ __CLASS__, 'render_modal_markup' ], 100 );
235
244
  add_action( 'wp_footer', [ __CLASS__, 'render_variation_selection' ], 100 );
236
245
  add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_scripts' ] );
@@ -524,6 +533,7 @@ final class Modal_Checkout {
524
533
  }
525
534
 
526
535
  $params = array_merge( $params, compact( 'after_success_behavior', 'after_success_url', 'after_success_button_label', 'after_success_token' ) );
536
+ $params = self::merge_request_utm_params( $params );
527
537
 
528
538
  if ( function_exists( 'wpcom_vip_url_to_postid' ) ) {
529
539
  $referer_post_id = wpcom_vip_url_to_postid( $referer );
@@ -604,11 +614,14 @@ final class Modal_Checkout {
604
614
  }
605
615
 
606
616
  // Pass through UTM and after_success params so they can be forwarded to the WooCommerce checkout flow.
617
+ // Values are encoded here because add_query_arg() does not encode them:
618
+ // an ampersand or space in a campaign name would otherwise split into a
619
+ // stray param or be dropped by the redirect sanitizer.
607
620
  foreach ( $params as $param => $value ) {
608
621
  if ( 'utm' === substr( $param, 0, 3 ) || 'after_success' === substr( $param, 0, 13 ) ) {
609
622
  if ( ! empty( $value ) ) {
610
623
  $param = sanitize_text_field( $param );
611
- $query_args[ $param ] = sanitize_text_field( $value );
624
+ $query_args[ $param ] = rawurlencode( sanitize_text_field( $value ) );
612
625
  }
613
626
  }
614
627
  }
@@ -661,6 +674,215 @@ final class Modal_Checkout {
661
674
  }
662
675
  }
663
676
 
677
+ /**
678
+ * Merge utm_* parameters from the current request into a params array.
679
+ *
680
+ * The modal form's own submission is what carries a promo link's values here:
681
+ * appendUtmFields() in modal.js copies the landing page's utm params onto the
682
+ * form as hidden fields before it GET-submits into the checkout iframe, so
683
+ * they arrive in this request's $_GET rather than depending on the referer.
684
+ * Request params win over referer params.
685
+ *
686
+ * @param array $params Params parsed from the referer query string.
687
+ * @return array Params with the request's utm_* params merged in.
688
+ */
689
+ public static function merge_request_utm_params( $params ) {
690
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
691
+ foreach ( wp_unslash( $_GET ) as $key => $value ) {
692
+ if ( 'utm' === substr( $key, 0, 3 ) && is_string( $value ) && '' !== $value ) {
693
+ $params[ sanitize_text_field( $key ) ] = sanitize_text_field( $value );
694
+ }
695
+ }
696
+ return $params;
697
+ }
698
+
699
+ /**
700
+ * Serve a `?checkout=1&type=…` trigger on any front-end URL by rendering the
701
+ * block it needs into the footer (hidden), so no page has to carry one.
702
+ * Rendering the real block brings everything the trigger relies on: the form
703
+ * it submits, the variation/tiers picker modals, and the modal assets. A page
704
+ * that does carry a matching block still wins — its form comes first in DOM
705
+ * order, so block-level context such as a coupon keeps applying.
706
+ *
707
+ * Runs on `wp` so the render-time asset enqueues land in the normal queue.
708
+ */
709
+ public static function maybe_setup_url_triggered_checkout() {
710
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
711
+ // The trigger-param test is the cheapest and most selective guard, so it
712
+ // runs first: nearly all traffic carries no trigger, and is_checkout()
713
+ // below is the one call here that touches WooCommerce page-type state
714
+ // and its filters.
715
+ if ( ! isset( $_GET['checkout'] ) || ! isset( $_GET['type'] ) || ! is_string( $_GET['type'] ) ) {
716
+ return;
717
+ }
718
+ if ( is_admin() || wp_doing_ajax() || is_feed() || ( function_exists( 'is_checkout' ) && is_checkout() ) ) {
719
+ return;
720
+ }
721
+ if ( ! function_exists( 'wc_get_product' ) ) {
722
+ return;
723
+ }
724
+ $type = sanitize_text_field( wp_unslash( $_GET['type'] ) );
725
+ if ( 'donate' === $type ) {
726
+ // The trigger script only fires when layout, frequency and amount are
727
+ // all present, so a request missing any of them would render a form
728
+ // nothing ever submits. Donations must also be on the WooCommerce
729
+ // platform for the block to produce a servable form.
730
+ if ( empty( $_GET['layout'] ) || empty( $_GET['frequency'] ) || empty( $_GET['amount'] ) ) {
731
+ return;
732
+ }
733
+ if ( ! method_exists( '\Newspack\Donations', 'is_platform_wc' ) || ! \Newspack\Donations::is_platform_wc() ) {
734
+ return;
735
+ }
736
+ // Defaults resolve to the site's donation settings, which is what the
737
+ // generator derived its frequency/amount options from.
738
+ self::$url_triggered_block_html = do_blocks( '<!-- wp:newspack-blocks/donate /-->' );
739
+ } elseif ( 'checkout_button' === $type ) {
740
+ $attrs = self::build_url_triggered_button_attrs_from_request();
741
+ if ( empty( $attrs ) ) {
742
+ return;
743
+ }
744
+ self::$url_triggered_block_html = do_blocks( '<!-- wp:newspack-blocks/checkout-button ' . serialize_block_attributes( $attrs ) . ' /-->' );
745
+ } else {
746
+ return;
747
+ }
748
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
749
+ if ( '' !== self::$url_triggered_block_html ) {
750
+ add_action( 'wp_footer', [ __CLASS__, 'render_url_triggered_block' ], 1 );
751
+ }
752
+ }
753
+
754
+ /**
755
+ * Resolve checkout button attributes from the current request, validating the
756
+ * product and variation. Returns [] when the request can't be served.
757
+ *
758
+ * Reads $_GET rather than filter_input(): the guard in
759
+ * maybe_setup_url_triggered_checkout() tests $_GET, and filter_input()
760
+ * consults PHP's request snapshot instead — anything that adjusts the
761
+ * superglobal after parsing (a test, a mu-plugin rewriting the query) would
762
+ * pass the guard and read back empty.
763
+ *
764
+ * @return array Block attributes.
765
+ */
766
+ public static function build_url_triggered_button_attrs_from_request() {
767
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
768
+ $product_id = isset( $_GET['product_id'] ) && is_scalar( $_GET['product_id'] ) ? absint( $_GET['product_id'] ) : 0;
769
+ $variation_id = isset( $_GET['variation_id'] ) && is_scalar( $_GET['variation_id'] ) ? absint( $_GET['variation_id'] ) : 0;
770
+ if ( ! $product_id ) {
771
+ return [];
772
+ }
773
+ $product = wc_get_product( $product_id );
774
+ if ( ! $product || 'publish' !== $product->get_status() ) {
775
+ return [];
776
+ }
777
+ if ( $variation_id ) {
778
+ $variation = wc_get_product( $variation_id );
779
+ if ( ! $variation || $variation->get_parent_id() !== $product_id || 'publish' !== $variation->get_status() ) {
780
+ return [];
781
+ }
782
+ }
783
+ // The coupon and label are non-HTML text values: sanitize_text_field()
784
+ // keeps their raw characters, where an entity-encoding filter would break
785
+ // the coupon's title lookup and show readers an encoded label. Escaping
786
+ // happens at output (view.php / the thank-you template). The destination
787
+ // is a URL: esc_url_raw() keeps its query intact and drops disallowed
788
+ // schemes before sanitize_after_success_url() validates the host.
789
+ $coupon = isset( $_GET['coupon'] ) && is_string( $_GET['coupon'] ) ? sanitize_text_field( wp_unslash( $_GET['coupon'] ) ) : '';
790
+ $button_label = isset( $_GET['after_success_button_label'] ) && is_string( $_GET['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $_GET['after_success_button_label'] ) ) : '';
791
+ $behavior = isset( $_GET['after_success_behavior'] ) && is_string( $_GET['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $_GET['after_success_behavior'] ) ) : '';
792
+ $after_url = isset( $_GET['after_success_url'] ) && is_string( $_GET['after_success_url'] ) ? esc_url_raw( wp_unslash( $_GET['after_success_url'] ) ) : '';
793
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
794
+ return self::build_url_triggered_button_attrs(
795
+ $product->get_type(),
796
+ $product_id,
797
+ $variation_id,
798
+ $coupon,
799
+ [
800
+ 'behavior' => $behavior,
801
+ 'url' => $after_url,
802
+ 'button_label' => $button_label,
803
+ ]
804
+ );
805
+ }
806
+
807
+ /**
808
+ * Block attributes serving a URL trigger for the given product shape.
809
+ *
810
+ * Mirrors what the block editor stores: a variable product carries
811
+ * `is_variable` with the parent as `product` and any lock as `variation`
812
+ * (view.php collapses the pair onto the variation), while grouped parents
813
+ * and specific products are `product` alone. A variation lock on a
814
+ * non-variable product has no serving form, so it is rejected.
815
+ *
816
+ * A coupon and after-success settings become block attributes, so they ride to
817
+ * the checkout as hidden fields exactly as block-configured ones do.
818
+ *
819
+ * Only `custom` after-success is accepted: `referrer` returns the reader where
820
+ * they came from, which a link opened from an email or a QR code has no
821
+ * referrer or history entry to satisfy.
822
+ *
823
+ * @param string $product_type Product type slug from WC_Product::get_type().
824
+ * @param int $product_id Requested product ID.
825
+ * @param int $variation_id Requested variation ID (0 for none).
826
+ * @param string $coupon Requested coupon code ('' for none).
827
+ * @param array $after_success {
828
+ * Optional. Requested after-checkout behavior.
829
+ * @type string $behavior 'custom' to send the reader onward; anything
830
+ * else leaves the thank-you screen alone.
831
+ * @type string $url Destination for the 'custom' behavior.
832
+ * @type string $button_label Label for the continue button.
833
+ * }
834
+ * @return array Block attributes, or [] when the combination can't be served.
835
+ */
836
+ public static function build_url_triggered_button_attrs( $product_type, $product_id, $variation_id = 0, $coupon = '', $after_success = [] ) {
837
+ $is_variable = in_array( $product_type, [ 'variable', 'variable-subscription' ], true );
838
+ if ( $variation_id && ! $is_variable ) {
839
+ return [];
840
+ }
841
+ $attrs = [
842
+ 'product' => (string) $product_id,
843
+ // The button is submitted programmatically and never shown.
844
+ 'text' => __( 'Complete your purchase', 'newspack-blocks' ),
845
+ ];
846
+ if ( $is_variable ) {
847
+ $attrs['is_variable'] = true;
848
+ if ( $variation_id ) {
849
+ $attrs['variation'] = (string) $variation_id;
850
+ }
851
+ }
852
+ // Strict check so a coupon code of "0" still rides along.
853
+ if ( '' !== $coupon ) {
854
+ $attrs['coupon'] = $coupon;
855
+ }
856
+ // The destination is restricted to allowed hosts here (sanitize_after_success_url()
857
+ // with no token), before it becomes a block attribute. view.php mints an
858
+ // after_success_token for any afterSuccessURL it renders — including this
859
+ // synthesized one — so that token only ever vouches for a destination this
860
+ // pre-validation already accepts. Loosening the check here would widen what
861
+ // the minted token blesses; an off-site destination still has to come from
862
+ // a block an editor authored.
863
+ $after_success_url = isset( $after_success['url'] ) ? self::sanitize_after_success_url( $after_success['url'] ) : '';
864
+ if ( isset( $after_success['behavior'] ) && 'custom' === $after_success['behavior'] && '' !== $after_success_url ) {
865
+ $attrs['afterSuccessBehavior'] = 'custom';
866
+ $attrs['afterSuccessURL'] = $after_success_url;
867
+ if ( ! empty( $after_success['button_label'] ) ) {
868
+ $attrs['afterSuccessButtonLabel'] = $after_success['button_label'];
869
+ }
870
+ }
871
+ return $attrs;
872
+ }
873
+
874
+ /**
875
+ * Output the synthesized block, hidden. The URL trigger drives it
876
+ * programmatically; any picker modals render separately via
877
+ * render_variation_selection(), outside this hidden wrapper.
878
+ */
879
+ public static function render_url_triggered_block() {
880
+ if ( '' === self::$url_triggered_block_html ) {
881
+ return;
882
+ }
883
+ echo '<div class="newspack-blocks__url-triggered-checkout" style="display:none">' . self::$url_triggered_block_html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
884
+ }
885
+
664
886
  /**
665
887
  * Process abandon checkout for modal.
666
888
  */
@@ -1648,7 +1870,7 @@ final class Modal_Checkout {
1648
1870
 
1649
1871
  $queried = get_queried_object();
1650
1872
 
1651
- return $queried instanceof WP_Post ? (int) $queried->ID : 0;
1873
+ return $queried instanceof \WP_Post ? (int) $queried->ID : 0;
1652
1874
  }
1653
1875
 
1654
1876
  /**
@@ -1941,12 +2163,15 @@ final class Modal_Checkout {
1941
2163
  return $url;
1942
2164
  }
1943
2165
 
2166
+ // Encoded because add_query_arg() does not encode what it is given: a
2167
+ // destination carrying its own query string would otherwise split, and
2168
+ // its second param would become a param of the thank-you URL.
1944
2169
  $args = array_merge(
1945
2170
  [
1946
2171
  'modal_checkout' => '1',
1947
2172
  'email' => isset( $_REQUEST['billing_email'] ) ? rawurlencode( \sanitize_email( \wp_unslash( $_REQUEST['billing_email'] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1948
2173
  ],
1949
- self::get_after_success_params()
2174
+ array_map( 'rawurlencode', self::get_after_success_params() )
1950
2175
  );
1951
2176
 
1952
2177
  // Pass order ID for modal checkout templates.
@@ -2401,9 +2626,26 @@ final class Modal_Checkout {
2401
2626
  if ( '' === $coupon_code || ! function_exists( 'wc_coupons_enabled' ) || ! \wc_coupons_enabled() ) {
2402
2627
  return;
2403
2628
  }
2404
- $coupon = new \WC_Coupon( $coupon_code );
2405
- $discounts = new \WC_Discounts( \WC()->cart );
2406
- if ( true === $discounts->is_coupon_valid( $coupon ) && \WC()->cart->apply_coupon( $coupon_code ) ) {
2629
+ try {
2630
+ $coupon = new \WC_Coupon( $coupon_code );
2631
+ $discounts = new \WC_Discounts( \WC()->cart );
2632
+ $applied = true === $discounts->is_coupon_valid( $coupon ) && \WC()->cart->apply_coupon( $coupon_code );
2633
+ } catch ( \Exception $e ) {
2634
+ // A persistent object cache can hold a code-to-ID mapping that
2635
+ // outlives the coupon post, and WooCommerce's data store throws
2636
+ // when it reads the missing post. Skip the coupon rather than
2637
+ // fataling the checkout the reader is standing on — but leave a
2638
+ // trail: without it, a cache stuck in this state silently charges
2639
+ // every reader on the promo link full price.
2640
+ if ( function_exists( 'wc_get_logger' ) ) {
2641
+ wc_get_logger()->warning(
2642
+ sprintf( 'Modal checkout: skipped auto-applying coupon "%s": %s', $coupon_code, $e->getMessage() ),
2643
+ [ 'source' => 'newspack-blocks' ]
2644
+ );
2645
+ }
2646
+ return;
2647
+ }
2648
+ if ( $applied ) {
2407
2649
  // apply_coupon() queues a "Coupon code applied successfully." success
2408
2650
  // notice; clear it so the auto-apply stays silent for the reader.
2409
2651
  if ( function_exists( 'wc_clear_notices' ) ) {
@@ -292,6 +292,14 @@ class Newspack_Blocks_API {
292
292
  ],
293
293
  ];
294
294
 
295
+ // The meta bag is returned verbatim, and the Homepage Posts editor component
296
+ // assigns the subtitle with RawHTML. A value stored before the theme gained a
297
+ // sanitize_callback is still raw, so it is filtered here rather than at that
298
+ // sink -- this endpoint is the only thing between the two.
299
+ if ( isset( $data['meta']['newspack_post_subtitle'] ) ) {
300
+ $data['meta']['newspack_post_subtitle'] = Newspack_Blocks::sanitize_post_subtitle( $data['meta']['newspack_post_subtitle'] );
301
+ }
302
+
295
303
  $sponsors = Newspack_Blocks::get_all_sponsors( $post->ID );
296
304
  $author_info = Newspack_Blocks::prepare_authors();
297
305
  $add_ons = [
@@ -1804,5 +1804,43 @@ class Newspack_Blocks {
1804
1804
 
1805
1805
  return $combined_caption;
1806
1806
  }
1807
+
1808
+ /**
1809
+ * Inline tags this plugin allows in a post subtitle.
1810
+ *
1811
+ * The theme owns the subtitle and sanitizes it on write, but a value stored before
1812
+ * that was in place is still raw, so the plugin filters it on the way out rather
1813
+ * than trusting the meta.
1814
+ *
1815
+ * @return array Allowed tags in wp_kses() form.
1816
+ */
1817
+ public static function get_post_subtitle_allowed_tags() {
1818
+ return array(
1819
+ 'b' => true,
1820
+ 'strong' => true,
1821
+ 'i' => true,
1822
+ 'em' => true,
1823
+ 'mark' => true,
1824
+ 'u' => true,
1825
+ 'small' => true,
1826
+ 'sub' => true,
1827
+ 'sup' => true,
1828
+ 'a' => array(
1829
+ 'href' => true,
1830
+ 'target' => true,
1831
+ 'rel' => true,
1832
+ ),
1833
+ );
1834
+ }
1835
+
1836
+ /**
1837
+ * Limit a post subtitle to the inline tags this plugin renders.
1838
+ *
1839
+ * @param string $subtitle Raw subtitle.
1840
+ * @return string Sanitized subtitle.
1841
+ */
1842
+ public static function sanitize_post_subtitle( $subtitle ) {
1843
+ return wp_kses( (string) $subtitle, self::get_post_subtitle_allowed_tags() );
1844
+ }
1807
1845
  }
1808
1846
  Newspack_Blocks::init();