@automattic/newspack-blocks 4.28.0 → 4.29.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.
- package/CHANGELOG.md +7 -0
- package/dist/blocks/checkout-button/block.json +3 -0
- package/dist/editor-rtl.css +16 -13
- package/dist/editor.asset.php +1 -1
- package/dist/editor.css +16 -13
- package/dist/editor.js +30 -25
- package/dist/modal.asset.php +1 -1
- package/dist/modal.js +1 -1
- package/dist/modalCheckout-rtl.css +1 -1
- package/dist/modalCheckout.asset.php +1 -1
- package/dist/modalCheckout.css +1 -1
- package/dist/modalCheckout.js +1 -1
- package/includes/class-modal-checkout.php +131 -168
- package/includes/class-newspack-blocks.php +1 -0
- package/includes/modal-checkout/class-checkout-data.php +23 -0
- package/newspack-blocks.php +2 -2
- package/package.json +5 -5
- package/src/blocks/checkout-button/block.json +3 -0
- package/src/blocks/checkout-button/coupon-control.js +150 -0
- package/src/blocks/checkout-button/edit.js +35 -2
- package/src/blocks/checkout-button/edit.scss +3 -2
- package/src/blocks/checkout-button/view.php +41 -2
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-frequency-based.php +2 -2
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-tiers-based.php +1 -1
- package/src/modal-checkout/checkout-button-trigger.js +91 -6
- package/src/modal-checkout/checkout-button-trigger.test.js +143 -1
- package/src/modal-checkout/checkout.scss +1 -53
- package/src/modal-checkout/index.js +7 -89
- package/src/modal-checkout/modal.js +5 -27
- package/src/modal-checkout/templates/form-checkout.php +10 -20
- package/src/modal-checkout/templates/form-coupon.php +9 -0
- package/src/modal-checkout/templates/thankyou.php +1 -1
- package/vendor/composer/installed.php +2 -2
- package/webpack.config.js +6 -12
package/dist/modalCheckout.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";const e=(e,t={})=>({...t,action:e}),t=["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,o="np_modal_checkout_interaction")=>{if("function"==typeof window.gtag&&e){const c={};for(const o of t)e[o]&&("boolean"==typeof e[o]?e[o]=e[o]?"yes":"no":"true"===e[o]?e[o]="yes":"false"===e[o]&&(e[o]="no"),c[o]=e[o].toString());window.gtag("event",o,c)}};function c(e){"undefined"!=typeof document&&"function"==typeof e&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",e):e())}function n(e){const t="string"==typeof e?document.getElementById(e):e;if(!t)return console.warn("No container found for checkout data"),{};let o={};if("FORM"===t.tagName){const e=new FormData(t);o=Object.fromEntries(e)}const c=t.dataset.checkout;if(!c)return console.warn("No checkout data found"),o;try{o={...o,...JSON.parse(c)}}catch(e){console.warn("Error parsing checkout data")}const n=new URL(t.ownerDocument.defaultView.location.href);return n.searchParams.get("action_type")&&(o.action_type=n.searchParams.get("action_type")),o}const r=(t="continue")=>{if("function"!=typeof window.gtag)return;const{action_type:c,amount:r,currency:i,product_id:a,product_type:s,recurrence:d,referrer:u,variation_id:l="",gate_post_id:p="",newspack_popup_id:_="",prompt_title:h=""}=n("modal-checkout-product-details"),m={action_type:c,amount:r,currency:i,product_id:a,product_type:s,recurrence:d,referrer:u};l&&(m.variation_id=l),p&&(m.gate_post_id=p),_&&(m.newspack_popup_id=_),h&&(m.prompt_title=h);const f=e(t,m);o(f)};var i;i=jQuery,c(()=>{if(!i)return void console.warn("jQuery is not available.");const t=document.querySelector("#newspack_modal_checkout_container"),a=newspackBlocksModalCheckout.newspack_class_prefix,s=new CustomEvent("checkout-ready"),d=new CustomEvent("checkout-complete"),u=new CustomEvent("checkout-cancel"),l=new CustomEvent("checkout-place-order-start"),p=new CustomEvent("checkout-place-order-success"),_=new CustomEvent("checkout-place-order-error"),h=new CustomEvent("checkout-place-order-critical-error");function m(){i(".woocommerce-notices-wrapper").empty(),i(`.woocommerce-NoticeGroup-checkout, .${a}__inline-error, .woocommerce-error, .woocommerce-message, .wc-block-components-notice-banner`).remove()}function f(r=!0){t.checkoutReady=!0,t.dispatchEvent(s),r&&c(function(){if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("loaded",t);o(c)})}if(newspackBlocksModalCheckout.is_checkout_complete)(()=>{if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("form_submission_success",t);o(c)})(),t&&(t.checkoutComplete=!0,t.dispatchEvent(d));else{function g(){i("#wcpay-express-checkout-button-separator, #wc-stripe-payment-request-button-separator, #wc-stripe-express-checkout-button-separator").after('<div class="newspack-ui__word-divider">'+newspackBlocksModalCheckout.divider_text+"</div>");let c=[];const s=i("form.checkout"),d=i("#checkout_cancel");if(d.length&&d.on("click",function(){t.dispatchEvent(u)}),!s.length)return console.warn("Checkout form is not available"),void f();const g=i("form.modal_checkout_coupon"),w=i("form.modal_checkout_nyp"),v=i("#checkout_continue"),b=i("#customer_details"),y=i("#after_customer_details"),C=i(".newspack-wcsg--wrapper");function x(){const e=i('input[name="payment_method"]:checked').val();i(".wc_payment_method").removeClass("selected"),i(".wc_payment_method.payment_method_"+e).addClass("selected")}i('input[name="payment_method"]').change(x),i(document).on("payment_method_selected",x),i(document).on("updated_checkout",x),x();let E=!1;function M(e,t=!0){const o=i("#modal-checkout-product-details strong");return!(!o.length||!e||(t&&o.html()!==e?o.html(e):t||o.text()===e||o.text(e),0))}s.on("checkout_place_order",function(){E||(E=!0,t.dispatchEvent(l))}),function(e,t){e.checkoutPlaceOrderProcessing?t():e.addEventListener("checkout-place-order-processing",t)}(t,function(){E&&(s.is(".processing")||(E=!1,t.dispatchEvent(_)))}),s.on("checkout_place_order_success",function(){E=!1,t.dispatchEvent(p)}),i(document.body).on("checkout_error",function(e,o){E&&(E=!1,o&&o.indexOf(newspackBlocksModalCheckout.labels.critical_error)>=0?t.dispatchEvent(h):t.dispatchEvent(_))}),s.on("update_checkout",function(){E&&(E=!1,t.dispatchEvent(_))}),i(document).on("updated_checkout",function(){i("#payment .wc_payment_methods").length?i("#after_customer_details > h3").show():i("#after_customer_details > h3").hide()}),i(document).on("updated_checkout",function(){const e=i(".order-review-wrapper");if(!e.length)return;const t=e.find("table");t.is(".empty")?e.addClass("hidden"):(t.unblock(),e.removeClass("hidden"));const o=i("#after_customer_details").hasClass("transaction-details-expanded"),c=i(".payment_methods");if(c.length){const t=e.clone();o&&i('[id="order_review_heading"]',t).attr("aria-expanded","true"),i(".order-review-wrapper").remove(),c.after(t)}else o||e.find("#order_review_heading").trigger("click")});let $=!1;function O(){const e=i("form.checkout");return e.length?e.serialize():""}i(document).on("updated_checkout",function(){!function(){const e=i(".order-review-wrapper .woocommerce-checkout-review-order-table tr.cart_item").first();if(!e.length)return!1;const t=e.find(".product-name").clone();t.find(".product-quantity").remove();const o=t.text().replace(/\s+/g," ").trim(),c=e.find(".product-total").text().replace(/\s+/g," ").trim();return!(!o||!c)&&M(`${o}: ${c}`,!1)}()?function(){$&&$.abort();const e=i.ajax({url:newspackBlocksModalCheckout.ajax_url,method:"POST",data:{action:"get_cart_product_summary",modal_checkout:1,post_data:O()},success:t=>{$===e&&M(t)},complete:()=>{$===e&&($=!1)}});$=e}():$&&($.abort(),$=!1)}),i(document).on("click","#order_review_heading",function(){i(this).attr("aria-expanded",function(e,t){return"false"===t?"true":"false"}),i("#after_customer_details").toggleClass("transaction-details-expanded")});let B=!1;function N(e=function(){return i(".order-review-wrapper tr.order-total:not(.recurring-total) .amount").first().text().replace(/\s+/g," ").trim()}()){let t=newspackBlocksModalCheckout.labels.complete_button;if(t){if(e&&i("#place_order").has(i("span.cart-price"))){const o=i("<div>"+t+"</div>");o.find(".cart-price").html(e),t=o.html()}i("#place_order").html(t),i("#place_order_clone").html(t),e||function(e){B&&B.abort();const t=i.ajax({url:newspackBlocksModalCheckout.ajax_url,method:"POST",data:{action:"get_cart_total",modal_checkout:1,post_data:O()},success:o=>{o&&B===t&&e(o)},complete:()=>{B===t&&(B=!1)}});B=t}(N)}}if(i(document).on("updated_checkout",function(){N()}),C.length){const e=C.find(".newspack-wcsg--gift-toggle input"),t=C.find(".newspack-wcsg--gift-email");e.on("change",function(){e.is(":checked")?t.addClass("visible"):t.removeClass("visible")})}function j(e){s.find(".input-text, select, input:checkbox").trigger("validate").trigger("blur");let t=!1;const o=[],c=e=>{const c=i("#"+e.data("id")+"_field");if(c?.length){t||(t=c);const o=c.find(".woocommerce-error");o.length&&o.remove(),c.addClass("woocommerce-invalid").removeClass("woocommerce-valid"),c.append(`<span class="${a}__inline-error">`+e.text()+"</span>"),e.remove()}else e.is("li")||(e=i("<li />").append(e)),o.push(e)};if(m(),0!==e.trimStart().indexOf("<")?c(i("<li />").append(e)):e.includes("<li")?i(e).find("li").each(function(){c(i(this))}):c(i(e)),o.length){t=!1;const e=i('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout"/>').append(i('<ul class="woocommerce-error" role="alert" />').append(o));s.prepend(e),e.get(0).scrollIntoView({behavior:"smooth"})}t?.length&&(window.scroll({top:t.offset().top-100,left:0,behavior:"smooth"}),t.find("input.input-text, select, input:checkbox").trigger("focus")),T(s),i(document.body).trigger("update_checkout"),i(document.body).trigger("checkout_error",[e])}function P(e){e.preventDefault(),e.stopImmediatePropagation(),L(),r("continue")}function S(e){const t=window.newspack_grecaptcha||{};if(m(),i("#checkout_details").remove(),e)s.attr("data-skip-recaptcha","1"),s.append('<input name="is_validation_only" type="hidden" value="1" />'),"v3"===t?.version&&t.destroy(s.get()),g.length&&g.hide(),w.length&&w.hide(),b.show(),y.hide(),b.find("input").first().focus(),c=function(e,t){const o=i._data(e,"events");return o?t?o[t]||[]:o:[]}(s[0],"submit").slice(0),c.forEach(e=>{s.off("submit",e.handler)}),s.on("submit",P);else{s.removeAttr("data-skip-recaptcha");const e=s.find('[name="is_validation_only"]');if(e.length&&e.remove(),t?.render){s.data("newspack-recaptcha","newspack_modal_checkout");const e=()=>{m(),s.get(0).scrollIntoView({behavior:"smooth"})},o=e=>j(e);t.render(s.get(),e,o),i(document).on("updated_checkout",()=>t.render(s.get(),e,o)),i(document.body).on("checkout_error",()=>t.render(s.get(),e,o))}g.length&&g.show(),w.length&&w.show(),b.hide(),y.show(),function(){i("#checkout_details").remove();const e={};s.serializeArray().forEach(t=>{e[t.name]=t.value});const t=`${newspackBlocksModalCheckout.newspack_class_prefix}__font--xs`,o=[];o.push('<div class="billing-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.billing_details+"</h3>"),(e.billing_first_name||e.billing_last_name)&&o.push(`<p class="${t}">`+e.billing_first_name+" "+e.billing_last_name+"</p>"),e.billing_company&&o.push(`<p class="${t}">`+e.billing_company+"</p>");let c="";if((e.billing_address_1||e.billing_address_2)&&(c=`<p class="${t}">`,e.billing_address_1&&(c+=e.billing_address_1),e.billing_address_2&&(c+=" "+e.billing_address_2),c+="<br>",e.billing_city&&(c+=e.billing_city),e.billing_state&&(c+=", "+e.billing_state),e.billing_postcode&&(c+=" "+e.billing_postcode),c+="<br>",e.billing_country&&(c+=e.billing_country)),o.push(c),e.billing_email&&o.push(`<p class="${t}">`+e.billing_email+"</p>"),o.push("</div>"),e.hasOwnProperty("shipping_address_1")){o.push('<div class="shipping-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.shipping_details+"</h3>");let n="";e.ship_to_different_address?(n=`<p class="${t}">`,e.shipping_address_1&&(n+=e.shipping_address_1),e.shipping_address_2&&(n+=" "+e.shipping_address_2),n+="<br>",e.shipping_city&&(n+=e.shipping_city),e.shipping_state&&(n+=", "+e.shipping_state),e.shipping_postcode&&(n+=" "+e.shipping_postcode),n+="<br>",e.shipping_country&&(n+=e.shipping_country)):n=c,o.push(n),o.push("</div>")}e.hasOwnProperty("newspack_wcsg_is_gift")&&e.hasOwnProperty("wcsg_gift_recipients_email")&&e.newspack_wcsg_is_gift&&e.wcsg_gift_recipients_email&&(o.push('<div class="gift-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.gift_recipient+"</h3>"),o.push(`<p class="${t}">`+e.wcsg_gift_recipients_email+"</p>")),i(".order-details-summary").after('<div id="checkout_details">'+o.join("")+"</div>")}(),s.off("submit",P),c.forEach(e=>{s.on("submit",e.handler)}),k(),i(document.body).trigger("update_checkout",{update_shipping_method:!1})}s.triggerHandler("editing_details",[e]),window.scroll({top:0,left:0,behavior:"smooth"})}function L(e=!1,t=()=>{}){if(!D(s))return console.warn("Unable to block the form"),t(),!1;m();const o=s.find(".woocommerce-NoticeGroup.woocommerce-NoticeGroup-checkout");o.length&&o.remove();const c=["save_user_in_woopay"],n=s.serializeArray().filter(e=>!c.includes(e.name));n.push({name:"newspack_blocks_checkout_action",value:"1"}),i.ajax({type:"POST",url:wc_checkout_params.checkout_url,data:n,dataType:"html",success:o=>{let c;try{c=JSON.parse(o)}catch(e){c={messages:'<div class="woocommerce-error">'+wc_checkout_params.i18n_checkout_error+"</div>"}}e||!0!==c.reload?(T(s),c.messages?e||(c.messages?j(c.messages):j(`<div class="${a}__inline-error">`+wc_checkout_params.i18n_checkout_error+"</div>")):(S(!1),i._data(s[0],"events")?.click?.some(e=>"#checkout_edit_billing"===e.selector)||s.on("click","#checkout_edit_billing",function(e){e.preventDefault(),S(!0),r("back")})),t(c)):window.location.reload()},error:(o,c,n)=>{let r="";e||(r='<div class="woocommerce-error">'+(n||wc_checkout_params.i18n_checkout_error)+"</div>",j(r)),t({messages:r})}})}function D(e){return!e.is(".modal-processing")&&(e.find("button[type=submit]").each((e,t)=>{i(t).attr("disabled",!0)}),e.addClass("modal-processing"),!0)}function T(e){return!!e.is(".modal-processing")&&(e.find("button[type=submit]").each((e,t)=>{i(t).attr("disabled",!1)}),e.removeClass("modal-processing"),!0)}v.length?(S(!0),C.length?f():L(!0,f)):f(),g.length&&(g.on("submit",function(e){if(e.preventDefault(),!D(g))return!1;const t={security:wc_checkout_params.apply_coupon_nonce,coupon_code:g.find('input[name="coupon_code"]').val()};i.ajax({type:"POST",url:wc_checkout_params.wc_ajax_url.toString().replace("%%endpoint%%","apply_coupon"),data:t,dataType:"html",success:e=>{if(m(),g.find(".result").remove(),e){const o=e.includes("error");g.append(`<p class="result ${a}__helper-text ${o?a+"__inline-error":""}">`+i(e).text()+"</p>"),o?(g.find('input[name="coupon_code"]').focus(),g.find('h3, input[name="coupon_code"]').addClass("newspack-ui__field-error")):(g.find('input[name="coupon_code"]').focus(),g.find('h3, input[name="coupon_code"]').removeClass("newspack-ui__field-error")),i(document.body).trigger("applied_coupon_in_checkout",[t.coupon_code]),i(document.body).trigger("update_checkout",{update_shipping_method:!1})}},complete:()=>{T(g)}})}),i(document.body).on("removed_coupon_in_checkout",()=>{m(),g.find(".result").remove(),g.find('input[name="coupon_code"]').val("").focus()})),w.length&&w.on("submit",function(e){if(e.preventDefault(),!D(w))return!1;const t=w.find('input[name="price"]');t.attr("disabled",!0);const o={_ajax_nonce:newspackBlocksModalCheckout.nyp_nonce,action:"process_name_your_price_request",price:w.find('input[name="price"]').val(),product_id:w.find('input[name="product_id"]').val(),newspack_checkout_name_your_price:w.find('input[name="newspack_checkout_name_your_price"]').val()};i.ajax({type:"POST",url:newspackBlocksModalCheckout.ajax_url,data:o,success:({success:e,data:t})=>{m(),w.find(".result").remove(),w.append(`<p class="result ${a}__helper-text ${e?"":a+"__inline-error"}">`+t.message+"</p>"),e?w.find('h3, input[name="price"]').removeClass("newspack-ui__field-error"):(w.find('input[name="price"]').focus(),w.find('h3, input[name="price"]').addClass("newspack-ui__field-error")),i(document.body).trigger("update_checkout",{update_shipping_method:!1})},complete:()=>{T(w),t.attr("disabled",!1),t.focus()}})}),s.on("click","#place_order",function(){(()=>{if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("form_submission",t);o(c)})()});const G=function(){if(!t)return;const e="data-newspack-error-handled",o=o=>{o.hasAttribute(e)||(o.setAttribute(e,"true"),i(o).addClass(`${a}__notice ${a}__notice--error`),t.dispatchEvent(_),o.scrollIntoView({behavior:"smooth",block:"center"}))},c=e=>!!e.classList?.contains("woocommerce-error")||!(!e.classList?.contains("wc-block-components-notice-banner")||!e.classList?.contains("is-error")),n=new MutationObserver(e=>{for(const t of e)for(const e of t.addedNodes){if(e.nodeType!==Node.ELEMENT_NODE)continue;if(c(e))return void o(e);const t=e.querySelector?.(".woocommerce-error, .wc-block-components-notice-banner.is-error");if(t)return void o(t)}});return n.observe(t,{childList:!0,subtree:!0}),n}();if(G){const e=()=>G.disconnect();t.addEventListener("checkout-complete",e),t.addEventListener("checkout-cancel",e),window.addEventListener("beforeunload",e)}}g()}function k(){const e=i("#newspack_subscription_terms_confirmation, #newspack_subscription_confirmation");if(e.length){const t=i("form.checkout"),o=t.find("button#place_order, button#place_order_clone");function c(){const t=e.is(":checked");o.each((e,o)=>{i(o).attr("disabled",!t)})}c(),e.on("change",c),t.on("submit",function(t){if(!e.is(":checked"))return t.preventDefault(),t.stopPropagation(),!1})}}i(document.body).on("updated_checkout payment_method_selected checkout_error",k),i(document).ready(k),i(document.body).on("checkout_error",function(){const e=i(".woocommerce-NoticeGroup-checkout, .woocommerce-notices-wrapper:not(:empty)");e.length&&e.each((e,t)=>i(t).addClass(`${a}__notice ${a}__notice--error`));const t=i("#checkout_error_back");t.length&&t.on("click",e=>{e.preventDefault(),parent.newspackCloseModalCheckout()}),f(!1)}),document.addEventListener("keydown",function(e){"Escape"===e.key&&parent.newspackCloseModalCheckout()}),newspackBlocksModalCheckout.is_error&&i(document.body).trigger("checkout_error")})})();
|
|
1
|
+
(()=>{"use strict";const e=(e,t={})=>({...t,action:e}),t=["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,o="np_modal_checkout_interaction")=>{if("function"==typeof window.gtag&&e){const c={};for(const o of t)e[o]&&("boolean"==typeof e[o]?e[o]=e[o]?"yes":"no":"true"===e[o]?e[o]="yes":"false"===e[o]&&(e[o]="no"),c[o]=e[o].toString());window.gtag("event",o,c)}};function c(e){"undefined"!=typeof document&&"function"==typeof e&&("complete"!==document.readyState&&"interactive"!==document.readyState?document.addEventListener("DOMContentLoaded",e):e())}function n(e){const t="string"==typeof e?document.getElementById(e):e;if(!t)return console.warn("No container found for checkout data"),{};let o={};if("FORM"===t.tagName){const e=new FormData(t);o=Object.fromEntries(e)}const c=t.dataset.checkout;if(!c)return console.warn("No checkout data found"),o;try{o={...o,...JSON.parse(c)}}catch(e){console.warn("Error parsing checkout data")}const n=new URL(t.ownerDocument.defaultView.location.href);return n.searchParams.get("action_type")&&(o.action_type=n.searchParams.get("action_type")),o}const i=(t="continue")=>{if("function"!=typeof window.gtag)return;const{action_type:c,amount:i,currency:r,product_id:s,product_type:a,recurrence:d,referrer:u,variation_id:p="",gate_post_id:l="",newspack_popup_id:_="",prompt_title:h=""}=n("modal-checkout-product-details"),m={action_type:c,amount:i,currency:r,product_id:s,product_type:a,recurrence:d,referrer:u};p&&(m.variation_id=p),l&&(m.gate_post_id=l),_&&(m.newspack_popup_id=_),h&&(m.prompt_title=h);const f=e(t,m);o(f)};var r;r=jQuery,c(()=>{if(!r)return void console.warn("jQuery is not available.");const t=document.querySelector("#newspack_modal_checkout_container"),s=newspackBlocksModalCheckout.newspack_class_prefix,a=new CustomEvent("checkout-ready"),d=new CustomEvent("checkout-complete"),u=new CustomEvent("checkout-cancel"),p=new CustomEvent("checkout-place-order-start"),l=new CustomEvent("checkout-place-order-success"),_=new CustomEvent("checkout-place-order-error"),h=new CustomEvent("checkout-place-order-critical-error");function m(){r(".woocommerce-notices-wrapper").empty(),r(`.woocommerce-NoticeGroup-checkout, .${s}__inline-error, .woocommerce-error, .woocommerce-message, .wc-block-components-notice-banner`).remove()}function f(i=!0){t.checkoutReady=!0,t.dispatchEvent(a),i&&c(function(){if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("loaded",t);o(c)})}if(newspackBlocksModalCheckout.is_checkout_complete)(()=>{if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("form_submission_success",t);o(c)})(),t&&(t.checkoutComplete=!0,t.dispatchEvent(d));else{function g(){r("#wcpay-express-checkout-button-separator, #wc-stripe-payment-request-button-separator, #wc-stripe-express-checkout-button-separator").after('<div class="newspack-ui__word-divider">'+newspackBlocksModalCheckout.divider_text+"</div>");let c=[];const a=r("form.checkout"),d=r("#checkout_cancel");if(d.length&&d.on("click",function(){t.dispatchEvent(u)}),!a.length)return console.warn("Checkout form is not available"),void f();const g=r("form.modal_checkout_coupon"),w=r("form.modal_checkout_nyp"),v=r("#checkout_continue"),b=r("#customer_details"),y=r("#after_customer_details"),C=r(".newspack-wcsg--wrapper");function E(){const e=r('input[name="payment_method"]:checked').val();r(".wc_payment_method").removeClass("selected"),r(".wc_payment_method.payment_method_"+e).addClass("selected")}r('input[name="payment_method"]').change(E),r(document).on("payment_method_selected",E),r(document).on("updated_checkout",E),E();let x=!1;function M(){const e=r("form.checkout");return e.length?e.serialize():""}a.on("checkout_place_order",function(){x||(x=!0,t.dispatchEvent(p))}),function(e,t){e.checkoutPlaceOrderProcessing?t():e.addEventListener("checkout-place-order-processing",t)}(t,function(){x&&(a.is(".processing")||(x=!1,t.dispatchEvent(_)))}),a.on("checkout_place_order_success",function(){x=!1,t.dispatchEvent(l)}),r(document.body).on("checkout_error",function(e,o){x&&(x=!1,o&&o.indexOf(newspackBlocksModalCheckout.labels.critical_error)>=0?t.dispatchEvent(h):t.dispatchEvent(_))}),a.on("update_checkout",function(){x&&(x=!1,t.dispatchEvent(_))}),r(document).on("updated_checkout",function(){r("#payment .wc_payment_methods").length?r("#after_customer_details > h3").show():r("#after_customer_details > h3").hide()}),r(document).on("updated_checkout",function(){const e=r(".order-review-wrapper");if(!e.length)return;const t=e.find("table");t.is(".empty")?e.addClass("hidden"):(t.unblock(),e.removeClass("hidden"));const o=r(".payment_methods");if(o.length){const t=e.clone();r(".order-review-wrapper").remove(),o.after(t)}});let $=!1;function O(e=function(){return r(".order-review-wrapper tr.order-total:not(.recurring-total) .amount").first().text().replace(/\s+/g," ").trim()}()){let t=newspackBlocksModalCheckout.labels.complete_button;if(t){if(e&&r("#place_order").has(r("span.cart-price"))){const o=r("<div>"+t+"</div>");o.find(".cart-price").html(e),t=o.html()}r("#place_order").html(t),r("#place_order_clone").html(t),e||function(e){$&&$.abort();const t=r.ajax({url:newspackBlocksModalCheckout.ajax_url,method:"POST",data:{action:"get_cart_total",modal_checkout:1,post_data:M()},success:o=>{o&&$===t&&e(o)},complete:()=>{$===t&&($=!1)}});$=t}(O)}}if(r(document).on("updated_checkout",function(){O()}),C.length){const e=C.find(".newspack-wcsg--gift-toggle input"),t=C.find(".newspack-wcsg--gift-email");e.on("change",function(){e.is(":checked")?t.addClass("visible"):t.removeClass("visible")})}function N(e){a.find(".input-text, select, input:checkbox").trigger("validate").trigger("blur");let t=!1;const o=[],c=e=>{const c=r("#"+e.data("id")+"_field");if(c?.length){t||(t=c);const o=c.find(".woocommerce-error");o.length&&o.remove(),c.addClass("woocommerce-invalid").removeClass("woocommerce-valid"),c.append(`<span class="${s}__inline-error">`+e.text()+"</span>"),e.remove()}else e.is("li")||(e=r("<li />").append(e)),o.push(e)};if(m(),0!==e.trimStart().indexOf("<")?c(r("<li />").append(e)):e.includes("<li")?r(e).find("li").each(function(){c(r(this))}):c(r(e)),o.length){t=!1;const e=r('<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout"/>').append(r('<ul class="woocommerce-error" role="alert" />').append(o));a.prepend(e),e.get(0).scrollIntoView({behavior:"smooth"})}t?.length&&(window.scroll({top:t.offset().top-100,left:0,behavior:"smooth"}),t.find("input.input-text, select, input:checkbox").trigger("focus")),j(a),r(document.body).trigger("update_checkout"),r(document.body).trigger("checkout_error",[e])}function B(e){e.preventDefault(),e.stopImmediatePropagation(),P(),i("continue")}function L(e){const t=window.newspack_grecaptcha||{};if(m(),r("#checkout_details").remove(),e)a.attr("data-skip-recaptcha","1"),a.append('<input name="is_validation_only" type="hidden" value="1" />'),"v3"===t?.version&&t.destroy(a.get()),g.length&&g.hide(),w.length&&w.hide(),b.show(),y.hide(),b.find("input").first().focus(),c=function(e,t){const o=r._data(e,"events");return o?t?o[t]||[]:o:[]}(a[0],"submit").slice(0),c.forEach(e=>{a.off("submit",e.handler)}),a.on("submit",B);else{a.removeAttr("data-skip-recaptcha");const e=a.find('[name="is_validation_only"]');if(e.length&&e.remove(),t?.render){a.data("newspack-recaptcha","newspack_modal_checkout");const e=()=>{m(),a.get(0).scrollIntoView({behavior:"smooth"})},o=e=>N(e);t.render(a.get(),e,o),r(document).on("updated_checkout",()=>t.render(a.get(),e,o)),r(document.body).on("checkout_error",()=>t.render(a.get(),e,o))}g.length&&g.show(),w.length&&w.show(),b.hide(),y.show(),function(){r("#checkout_details").remove();const e={};a.serializeArray().forEach(t=>{e[t.name]=t.value});const t=`${newspackBlocksModalCheckout.newspack_class_prefix}__font--xs`,o=[];o.push('<div class="billing-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.billing_details+"</h3>"),(e.billing_first_name||e.billing_last_name)&&o.push(`<p class="${t}">`+e.billing_first_name+" "+e.billing_last_name+"</p>"),e.billing_company&&o.push(`<p class="${t}">`+e.billing_company+"</p>");let c="";if((e.billing_address_1||e.billing_address_2)&&(c=`<p class="${t}">`,e.billing_address_1&&(c+=e.billing_address_1),e.billing_address_2&&(c+=" "+e.billing_address_2),c+="<br>",e.billing_city&&(c+=e.billing_city),e.billing_state&&(c+=", "+e.billing_state),e.billing_postcode&&(c+=" "+e.billing_postcode),c+="<br>",e.billing_country&&(c+=e.billing_country)),o.push(c),e.billing_email&&o.push(`<p class="${t}">`+e.billing_email+"</p>"),o.push("</div>"),e.hasOwnProperty("shipping_address_1")){o.push('<div class="shipping-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.shipping_details+"</h3>");let n="";e.ship_to_different_address?(n=`<p class="${t}">`,e.shipping_address_1&&(n+=e.shipping_address_1),e.shipping_address_2&&(n+=" "+e.shipping_address_2),n+="<br>",e.shipping_city&&(n+=e.shipping_city),e.shipping_state&&(n+=", "+e.shipping_state),e.shipping_postcode&&(n+=" "+e.shipping_postcode),n+="<br>",e.shipping_country&&(n+=e.shipping_country)):n=c,o.push(n),o.push("</div>")}e.hasOwnProperty("newspack_wcsg_is_gift")&&e.hasOwnProperty("wcsg_gift_recipients_email")&&e.newspack_wcsg_is_gift&&e.wcsg_gift_recipients_email&&(o.push('<div class="gift-details">'),o.push("<h3>"+newspackBlocksModalCheckout.labels.gift_recipient+"</h3>"),o.push(`<p class="${t}">`+e.wcsg_gift_recipients_email+"</p>")),(r("#modal-checkout-product-details").length?r("#modal-checkout-product-details"):r("#after_customer_details")).after('<div id="checkout_details">'+o.join("")+"</div>")}(),a.off("submit",B),c.forEach(e=>{a.on("submit",e.handler)}),k(),r(document.body).trigger("update_checkout",{update_shipping_method:!1})}a.triggerHandler("editing_details",[e]),window.scroll({top:0,left:0,behavior:"smooth"})}function P(e=!1,t=()=>{}){if(!S(a))return console.warn("Unable to block the form"),t(),!1;m();const o=a.find(".woocommerce-NoticeGroup.woocommerce-NoticeGroup-checkout");o.length&&o.remove();const c=["save_user_in_woopay"],n=a.serializeArray().filter(e=>!c.includes(e.name));n.push({name:"newspack_blocks_checkout_action",value:"1"}),r.ajax({type:"POST",url:wc_checkout_params.checkout_url,data:n,dataType:"html",success:o=>{let c;try{c=JSON.parse(o)}catch(e){c={messages:'<div class="woocommerce-error">'+wc_checkout_params.i18n_checkout_error+"</div>"}}e||!0!==c.reload?(j(a),c.messages?e||(c.messages?N(c.messages):N(`<div class="${s}__inline-error">`+wc_checkout_params.i18n_checkout_error+"</div>")):(L(!1),r._data(a[0],"events")?.click?.some(e=>"#checkout_edit_billing"===e.selector)||a.on("click","#checkout_edit_billing",function(e){e.preventDefault(),L(!0),i("back")})),t(c)):window.location.reload()},error:(o,c,n)=>{let i="";e||(i='<div class="woocommerce-error">'+(n||wc_checkout_params.i18n_checkout_error)+"</div>",N(i)),t({messages:i})}})}function S(e){return!e.is(".modal-processing")&&(e.find("button[type=submit]").each((e,t)=>{r(t).attr("disabled",!0)}),e.addClass("modal-processing"),!0)}function j(e){return!!e.is(".modal-processing")&&(e.find("button[type=submit]").each((e,t)=>{r(t).attr("disabled",!1)}),e.removeClass("modal-processing"),!0)}v.length?(L(!0),C.length?f():P(!0,f)):f(),g.length&&(g.on("submit",function(e){if(e.preventDefault(),!S(g))return!1;const t={security:wc_checkout_params.apply_coupon_nonce,coupon_code:g.find('input[name="coupon_code"]').val()};r.ajax({type:"POST",url:wc_checkout_params.wc_ajax_url.toString().replace("%%endpoint%%","apply_coupon"),data:t,dataType:"html",success:e=>{if(m(),g.find(".result").remove(),e){const o=e.includes("error");g.append(`<p class="result ${s}__helper-text ${o?s+"__inline-error":""}">`+r(e).text()+"</p>"),o?(g.find('input[name="coupon_code"]').focus(),g.find('h3, input[name="coupon_code"]').addClass("newspack-ui__field-error")):(g.find('input[name="coupon_code"]').focus(),g.find('h3, input[name="coupon_code"]').removeClass("newspack-ui__field-error")),r(document.body).trigger("applied_coupon_in_checkout",[t.coupon_code]),r(document.body).trigger("update_checkout",{update_shipping_method:!1})}},complete:()=>{j(g)}})}),r(document.body).on("removed_coupon_in_checkout",()=>{m(),g.find(".result").remove(),g.find('input[name="coupon_code"]').val("").focus()})),w.length&&w.on("submit",function(e){if(e.preventDefault(),!S(w))return!1;const t=w.find('input[name="price"]');t.attr("disabled",!0);const o={_ajax_nonce:newspackBlocksModalCheckout.nyp_nonce,action:"process_name_your_price_request",price:w.find('input[name="price"]').val(),product_id:w.find('input[name="product_id"]').val(),newspack_checkout_name_your_price:w.find('input[name="newspack_checkout_name_your_price"]').val()};r.ajax({type:"POST",url:newspackBlocksModalCheckout.ajax_url,data:o,success:({success:e,data:t})=>{m(),w.find(".result").remove(),w.append(`<p class="result ${s}__helper-text ${e?"":s+"__inline-error"}">`+t.message+"</p>"),e?w.find('h3, input[name="price"]').removeClass("newspack-ui__field-error"):(w.find('input[name="price"]').focus(),w.find('h3, input[name="price"]').addClass("newspack-ui__field-error")),r(document.body).trigger("update_checkout",{update_shipping_method:!1})},complete:()=>{j(w),t.attr("disabled",!1),t.focus()}})}),a.on("click","#place_order",function(){(()=>{if("function"!=typeof window.gtag)return;const t=n("modal-checkout-product-details"),c=e("form_submission",t);o(c)})()});const D=function(){if(!t)return;const e="data-newspack-error-handled",o=o=>{o.hasAttribute(e)||(o.setAttribute(e,"true"),r(o).addClass(`${s}__notice ${s}__notice--error`),t.dispatchEvent(_),o.scrollIntoView({behavior:"smooth",block:"center"}))},c=e=>!!e.classList?.contains("woocommerce-error")||!(!e.classList?.contains("wc-block-components-notice-banner")||!e.classList?.contains("is-error")),n=new MutationObserver(e=>{for(const t of e)for(const e of t.addedNodes){if(e.nodeType!==Node.ELEMENT_NODE)continue;if(c(e))return void o(e);const t=e.querySelector?.(".woocommerce-error, .wc-block-components-notice-banner.is-error");if(t)return void o(t)}});return n.observe(t,{childList:!0,subtree:!0}),n}();if(D){const e=()=>D.disconnect();t.addEventListener("checkout-complete",e),t.addEventListener("checkout-cancel",e),window.addEventListener("beforeunload",e)}}g()}function k(){const e=r("#newspack_subscription_terms_confirmation, #newspack_subscription_confirmation");if(e.length){const t=r("form.checkout"),o=t.find("button#place_order, button#place_order_clone");function c(){const t=e.is(":checked");o.each((e,o)=>{r(o).attr("disabled",!t)})}c(),e.on("change",c),t.on("submit",function(t){if(!e.is(":checked"))return t.preventDefault(),t.stopPropagation(),!1})}}r(document.body).on("updated_checkout payment_method_selected checkout_error",k),r(document).ready(k),r(document.body).on("checkout_error",function(){const e=r(".woocommerce-NoticeGroup-checkout, .woocommerce-notices-wrapper:not(:empty)");e.length&&e.each((e,t)=>r(t).addClass(`${s}__notice ${s}__notice--error`));const t=r("#checkout_error_back");t.length&&t.on("click",e=>{e.preventDefault(),parent.newspackCloseModalCheckout()}),f(!1)}),document.addEventListener("keydown",function(e){"Escape"===e.key&&parent.newspackCloseModalCheckout()}),newspackBlocksModalCheckout.is_error&&r(document.body).trigger("checkout_error")})})();
|
|
@@ -29,6 +29,14 @@ final class Modal_Checkout {
|
|
|
29
29
|
*/
|
|
30
30
|
const CHECKOUT_REGISTRATION_ORDER_META_KEY = '_newspack_checkout_registration_meta';
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Session key tracking a coupon auto-applied from a Checkout Button block,
|
|
34
|
+
* used to hide the in-modal coupon form for that coupon.
|
|
35
|
+
*
|
|
36
|
+
* @var string
|
|
37
|
+
*/
|
|
38
|
+
const AUTO_APPLIED_COUPON_SESSION_KEY = 'newspack_blocks_auto_applied_coupon';
|
|
39
|
+
|
|
32
40
|
/**
|
|
33
41
|
* Billing fields with server-side format validation in the Store API,
|
|
34
42
|
* mapped from their classic checkout keys to Store API address keys.
|
|
@@ -218,8 +226,6 @@ final class Modal_Checkout {
|
|
|
218
226
|
// Make the current cart price available to the JavaScript.
|
|
219
227
|
add_action( 'wp_ajax_get_cart_total', [ __CLASS__, 'get_cart_total_js' ] );
|
|
220
228
|
add_action( 'wp_ajax_nopriv_get_cart_total', [ __CLASS__, 'get_cart_total_js' ] );
|
|
221
|
-
add_action( 'wp_ajax_get_cart_product_summary', [ __CLASS__, 'get_cart_product_summary_js' ] );
|
|
222
|
-
add_action( 'wp_ajax_nopriv_get_cart_product_summary', [ __CLASS__, 'get_cart_product_summary_js' ] );
|
|
223
229
|
|
|
224
230
|
// Wrap required checkbox text in a span so it works nicely with the Newspack UI grid layout.
|
|
225
231
|
add_filter( 'woocommerce_form_field_checkbox', [ __CLASS__, 'wrap_required_checkbox_text' ], 10, 4 );
|
|
@@ -449,7 +455,14 @@ final class Modal_Checkout {
|
|
|
449
455
|
$cart_item_data = apply_filters( 'newspack_blocks_modal_checkout_cart_item_data', $cart_item_data );
|
|
450
456
|
|
|
451
457
|
\WC()->cart->empty_cart();
|
|
452
|
-
\WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
458
|
+
$cart_item_key = \WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
459
|
+
|
|
460
|
+
// Auto-apply a coupon attached to the Checkout Button block, if present and
|
|
461
|
+
// valid. Read with a sanitizing filter (satisfies input-sanitization
|
|
462
|
+
// checks); the validate-and-apply gate lives in maybe_auto_apply_coupon()
|
|
463
|
+
// so it can be unit-tested in isolation.
|
|
464
|
+
$coupon_code = (string) filter_input( INPUT_GET, 'coupon', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
|
465
|
+
self::maybe_auto_apply_coupon( $coupon_code );
|
|
453
466
|
|
|
454
467
|
// Set checkout registration flag if user is logged not logged in.
|
|
455
468
|
if ( ! is_user_logged_in() ) {
|
|
@@ -491,13 +504,31 @@ final class Modal_Checkout {
|
|
|
491
504
|
'referrer' => $referer,
|
|
492
505
|
];
|
|
493
506
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
507
|
+
if ( $cart_item_key ) {
|
|
508
|
+
/**
|
|
509
|
+
* Action to fire for checkout button block modal.
|
|
510
|
+
*
|
|
511
|
+
* Fires only when the product actually entered the cart, so consumers
|
|
512
|
+
* recording checkout-initiated events stay in step with adds rejected
|
|
513
|
+
* by an add-to-cart guard.
|
|
514
|
+
*/
|
|
515
|
+
\do_action( 'newspack_blocks_checkout_button_modal', $checkout_button_metadata );
|
|
516
|
+
}
|
|
498
517
|
|
|
499
518
|
$checkout_url = apply_filters( 'newspack_blocks_checkout_url', $checkout_url );
|
|
500
519
|
|
|
520
|
+
// If the product could not be added (e.g. rejected by an add-to-cart guard),
|
|
521
|
+
// the cart is empty and the checkout would render blank: point the modal at
|
|
522
|
+
// its error screen, which prints the queued error notice and a back button.
|
|
523
|
+
// Like the success path above, an unsupported payment gateway means a
|
|
524
|
+
// full-page rather than iframed checkout, so modal_checkout is omitted.
|
|
525
|
+
if ( ! $cart_item_key ) {
|
|
526
|
+
$checkout_url = \wc_get_cart_url();
|
|
527
|
+
if ( ! self::has_unsupported_payment_gateway() ) {
|
|
528
|
+
$checkout_url = add_query_arg( 'modal_checkout', 1, $checkout_url );
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
501
532
|
if ( defined( 'DOING_AJAX' ) ) {
|
|
502
533
|
echo wp_json_encode( [ 'url' => $checkout_url ] );
|
|
503
534
|
exit;
|
|
@@ -685,7 +716,26 @@ final class Modal_Checkout {
|
|
|
685
716
|
$coupons = \WC()->cart->get_applied_coupons();
|
|
686
717
|
|
|
687
718
|
\WC()->cart->empty_cart();
|
|
688
|
-
\WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
719
|
+
$cart_item_key = \WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
720
|
+
|
|
721
|
+
// A rejected add (e.g. an add-to-cart guard) must not report success: surface
|
|
722
|
+
// the error notice the cart queued for it instead of a thank-you message.
|
|
723
|
+
// The consumer appends this message as an HTML string, and unlike template-
|
|
724
|
+
// rendered notices it never passes through kses on output — so filter any
|
|
725
|
+
// third-party notice content here.
|
|
726
|
+
if ( ! $cart_item_key ) {
|
|
727
|
+
$error_notices = \wc_get_notices( 'error' );
|
|
728
|
+
\wc_clear_notices();
|
|
729
|
+
wp_send_json_error(
|
|
730
|
+
[
|
|
731
|
+
'message' => ! empty( $error_notices[0]['notice'] )
|
|
732
|
+
? wp_kses_post( $error_notices[0]['notice'] )
|
|
733
|
+
: __( 'This product could not be added to the cart.', 'newspack-blocks' ),
|
|
734
|
+
]
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
wp_die();
|
|
738
|
+
}
|
|
689
739
|
|
|
690
740
|
if ( ! empty( $coupons ) ) {
|
|
691
741
|
foreach ( $coupons as $coupon ) {
|
|
@@ -1666,61 +1716,79 @@ final class Modal_Checkout {
|
|
|
1666
1716
|
}
|
|
1667
1717
|
|
|
1668
1718
|
/**
|
|
1669
|
-
*
|
|
1719
|
+
* Auto-apply a coupon attached to a Checkout Button block to the current
|
|
1720
|
+
* cart, gated on validation.
|
|
1670
1721
|
*
|
|
1671
|
-
*
|
|
1722
|
+
* The reader never typed the code, so anything that would surface it is kept
|
|
1723
|
+
* silent: an invalid, expired, restricted or usage-capped coupon is skipped
|
|
1724
|
+
* with no error notice (validation runs before apply), and the "applied
|
|
1725
|
+
* successfully" success notice that WC_Cart::apply_coupon() queues is
|
|
1726
|
+
* cleared. A successful application is tracked in the session so the modal
|
|
1727
|
+
* can hide its coupon form for that coupon (see should_hide_coupon_form());
|
|
1728
|
+
* any prior marker is reset first.
|
|
1729
|
+
*
|
|
1730
|
+
* @param string $coupon_code Raw coupon code from the request (already
|
|
1731
|
+
* sanitized by the caller, e.g. via filter_input()).
|
|
1732
|
+
*
|
|
1733
|
+
* @return void
|
|
1672
1734
|
*/
|
|
1673
|
-
public static function
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
return false;
|
|
1677
|
-
}
|
|
1678
|
-
if ( ! empty( $cart->get_applied_coupons() ) ) {
|
|
1679
|
-
return true;
|
|
1680
|
-
}
|
|
1681
|
-
if ( \wc_tax_enabled() && ! $cart->display_prices_including_tax() ) {
|
|
1682
|
-
return true;
|
|
1683
|
-
}
|
|
1684
|
-
if ( 1 < $cart->get_cart_contents_count() ) {
|
|
1685
|
-
return true;
|
|
1735
|
+
public static function maybe_auto_apply_coupon( $coupon_code ) {
|
|
1736
|
+
if ( ! function_exists( 'WC' ) || ! \WC()->cart ) {
|
|
1737
|
+
return;
|
|
1686
1738
|
}
|
|
1687
|
-
if (
|
|
1688
|
-
|
|
1739
|
+
if ( \WC()->session ) {
|
|
1740
|
+
\WC()->session->set( self::AUTO_APPLIED_COUPON_SESSION_KEY, null );
|
|
1689
1741
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1742
|
+
// Decode entities so a literal code (e.g. one containing "&") still
|
|
1743
|
+
// matches. The strict empty-string check keeps a coupon code of "0" valid.
|
|
1744
|
+
$coupon_code = html_entity_decode( (string) $coupon_code, ENT_QUOTES );
|
|
1745
|
+
if ( '' === $coupon_code || ! function_exists( 'wc_coupons_enabled' ) || ! \wc_coupons_enabled() ) {
|
|
1746
|
+
return;
|
|
1692
1747
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
foreach ( $packages as $package ) {
|
|
1701
|
-
if ( ! empty( $package['rates'] ) ) {
|
|
1702
|
-
foreach ( $package['rates'] as $rate_key => $rate ) {
|
|
1703
|
-
$shipping_rates[ $rate_key ] = $rate;
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1748
|
+
$coupon = new \WC_Coupon( $coupon_code );
|
|
1749
|
+
$discounts = new \WC_Discounts( \WC()->cart );
|
|
1750
|
+
if ( true === $discounts->is_coupon_valid( $coupon ) && \WC()->cart->apply_coupon( $coupon_code ) ) {
|
|
1751
|
+
// apply_coupon() queues a "Coupon code applied successfully." success
|
|
1752
|
+
// notice; clear it so the auto-apply stays silent for the reader.
|
|
1753
|
+
if ( function_exists( 'wc_clear_notices' ) ) {
|
|
1754
|
+
\wc_clear_notices();
|
|
1706
1755
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
if ( (float) $totals['total'] !== (float) $totals['subtotal'] || 1 < count( array_values( $shipping_rates ) ) ) {
|
|
1710
|
-
return true;
|
|
1756
|
+
if ( \WC()->session ) {
|
|
1757
|
+
\WC()->session->set( self::AUTO_APPLIED_COUPON_SESSION_KEY, \wc_format_coupon_code( $coupon_code ) );
|
|
1711
1758
|
}
|
|
1712
1759
|
}
|
|
1760
|
+
}
|
|
1713
1761
|
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1762
|
+
/**
|
|
1763
|
+
* Whether the in-modal coupon form should be hidden.
|
|
1764
|
+
*
|
|
1765
|
+
* True when a coupon was auto-applied from a Checkout Button block (tracked
|
|
1766
|
+
* in the session) and is still applied to the cart. The reader never entered
|
|
1767
|
+
* the code, so they should not be prompted to add or stack coupons. If they
|
|
1768
|
+
* remove the auto-applied coupon, the form is shown again.
|
|
1769
|
+
*
|
|
1770
|
+
* @return bool
|
|
1771
|
+
*/
|
|
1772
|
+
public static function should_hide_coupon_form() {
|
|
1773
|
+
if ( ! function_exists( 'WC' ) || ! \WC()->session || ! \WC()->cart ) {
|
|
1774
|
+
return false;
|
|
1721
1775
|
}
|
|
1776
|
+
$auto_applied = \WC()->session->get( self::AUTO_APPLIED_COUPON_SESSION_KEY );
|
|
1777
|
+
return ! empty( $auto_applied ) && in_array( $auto_applied, \WC()->cart->get_applied_coupons(), true );
|
|
1778
|
+
}
|
|
1722
1779
|
|
|
1723
|
-
|
|
1780
|
+
/**
|
|
1781
|
+
* Whether to show order details table.
|
|
1782
|
+
*
|
|
1783
|
+
* @return bool
|
|
1784
|
+
*/
|
|
1785
|
+
public static function should_show_order_details() {
|
|
1786
|
+
// The transaction details table is always shown for any non-empty cart. Simple
|
|
1787
|
+
// single-item carts previously hid it and relied on the static price-summary card
|
|
1788
|
+
// above the form; that card was removed, so the real, deal-accurate order details
|
|
1789
|
+
// must always be visible. Guard against a missing cart (early hooks / edge AJAX).
|
|
1790
|
+
$cart = \WC()->cart;
|
|
1791
|
+
return $cart && ! $cart->is_empty();
|
|
1724
1792
|
}
|
|
1725
1793
|
|
|
1726
1794
|
/**
|
|
@@ -1980,112 +2048,6 @@ final class Modal_Checkout {
|
|
|
1980
2048
|
);
|
|
1981
2049
|
}
|
|
1982
2050
|
|
|
1983
|
-
/**
|
|
1984
|
-
* Get validated cart item context for the modal checkout product summary.
|
|
1985
|
-
*
|
|
1986
|
-
* @param \WC_Cart $cart Cart object.
|
|
1987
|
-
*
|
|
1988
|
-
* @return array|null
|
|
1989
|
-
*/
|
|
1990
|
-
private static function get_cart_product_summary_context( $cart ) {
|
|
1991
|
-
if ( ! $cart || 1 !== $cart->get_cart_contents_count() ) {
|
|
1992
|
-
return null;
|
|
1993
|
-
}
|
|
1994
|
-
$cart_item_key = array_key_first( $cart->get_cart() );
|
|
1995
|
-
$cart_item = $cart->get_cart_item( $cart_item_key );
|
|
1996
|
-
|
|
1997
|
-
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
1998
|
-
$product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
|
|
1999
|
-
$is_visible = $product && $product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key );
|
|
2000
|
-
// phpcs:enable
|
|
2001
|
-
|
|
2002
|
-
return [
|
|
2003
|
-
'cart_item_key' => $cart_item_key,
|
|
2004
|
-
'cart_item' => $cart_item,
|
|
2005
|
-
'product' => $product,
|
|
2006
|
-
'is_visible' => $is_visible,
|
|
2007
|
-
];
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
/**
|
|
2011
|
-
* Get the cart product summary shown at the top of modal checkout.
|
|
2012
|
-
*
|
|
2013
|
-
* @param \WC_Cart|null $cart Cart object.
|
|
2014
|
-
* @param array|null $context Validated cart item context.
|
|
2015
|
-
*/
|
|
2016
|
-
private static function get_cart_product_summary( $cart = null, $context = null ) {
|
|
2017
|
-
if ( ! $cart ) {
|
|
2018
|
-
if ( ! function_exists( 'WC' ) ) {
|
|
2019
|
-
return '';
|
|
2020
|
-
}
|
|
2021
|
-
$cart = \WC()->cart;
|
|
2022
|
-
}
|
|
2023
|
-
$context = $context ? $context : self::get_cart_product_summary_context( $cart );
|
|
2024
|
-
if ( ! $context || ! $context['is_visible'] ) {
|
|
2025
|
-
return '';
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2028
|
-
$cart_item_key = $context['cart_item_key'];
|
|
2029
|
-
$cart_item = $context['cart_item'];
|
|
2030
|
-
$product = $context['product'];
|
|
2031
|
-
$allowed_html = self::get_cart_product_summary_allowed_html();
|
|
2032
|
-
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
2033
|
-
$product_name = apply_filters(
|
|
2034
|
-
'woocommerce_cart_item_name',
|
|
2035
|
-
$product->get_name(),
|
|
2036
|
-
$cart_item,
|
|
2037
|
-
$cart_item_key
|
|
2038
|
-
);
|
|
2039
|
-
$product_subtotal = apply_filters(
|
|
2040
|
-
'woocommerce_cart_item_subtotal',
|
|
2041
|
-
$cart->get_product_subtotal( $product, $cart_item['quantity'] ),
|
|
2042
|
-
$cart_item,
|
|
2043
|
-
$cart_item_key
|
|
2044
|
-
);
|
|
2045
|
-
// phpcs:enable
|
|
2046
|
-
|
|
2047
|
-
$summary = $product_name . ': ';
|
|
2048
|
-
if ( function_exists( 'wc_get_formatted_cart_item_data' ) ) {
|
|
2049
|
-
$summary .= wc_get_formatted_cart_item_data( $cart_item );
|
|
2050
|
-
}
|
|
2051
|
-
$summary .= $product_subtotal;
|
|
2052
|
-
return wp_kses( $summary, $allowed_html );
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
/**
|
|
2056
|
-
* Get allowed HTML for the modal checkout product summary.
|
|
2057
|
-
*
|
|
2058
|
-
* @return array Allowed HTML tags and attributes.
|
|
2059
|
-
*/
|
|
2060
|
-
private static function get_cart_product_summary_allowed_html() {
|
|
2061
|
-
$allowed_html = wp_kses_allowed_html( 'post' );
|
|
2062
|
-
|
|
2063
|
-
$allowed_html['bdi'] = [
|
|
2064
|
-
'class' => true,
|
|
2065
|
-
'dir' => true,
|
|
2066
|
-
];
|
|
2067
|
-
|
|
2068
|
-
if ( ! isset( $allowed_html['span'] ) ) {
|
|
2069
|
-
$allowed_html['span'] = [];
|
|
2070
|
-
}
|
|
2071
|
-
$allowed_html['span']['class'] = true;
|
|
2072
|
-
|
|
2073
|
-
if ( ! isset( $allowed_html['small'] ) ) {
|
|
2074
|
-
$allowed_html['small'] = [];
|
|
2075
|
-
}
|
|
2076
|
-
$allowed_html['small']['class'] = true;
|
|
2077
|
-
|
|
2078
|
-
return $allowed_html;
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
/**
|
|
2082
|
-
* Get the updated cart product summary for JavaScript.
|
|
2083
|
-
*/
|
|
2084
|
-
public static function get_cart_product_summary_js() {
|
|
2085
|
-
echo self::get_cart_product_summary(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
2086
|
-
wp_die();
|
|
2087
|
-
}
|
|
2088
|
-
|
|
2089
2051
|
/**
|
|
2090
2052
|
* Get the updated price for updating the "Place order" button.
|
|
2091
2053
|
*/
|
|
@@ -2112,22 +2074,23 @@ final class Modal_Checkout {
|
|
|
2112
2074
|
if ( 1 !== $cart->get_cart_contents_count() ) {
|
|
2113
2075
|
return;
|
|
2114
2076
|
}
|
|
2115
|
-
$
|
|
2116
|
-
$
|
|
2077
|
+
$cart_item_key = array_key_first( $cart->get_cart() );
|
|
2078
|
+
$cart_item = $cart->get_cart_item( $cart_item_key );
|
|
2117
2079
|
?>
|
|
2118
|
-
<div class="<?php echo esc_attr( "order-details-summary {$class_prefix}__box {$class_prefix}__box--text-center" ); ?>">
|
|
2119
2080
|
<?php
|
|
2120
|
-
|
|
2081
|
+
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
2082
|
+
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
|
|
2083
|
+
// Hidden data carrier only — the visible price-summary card was removed. The modal
|
|
2084
|
+
// dialog (modal.js) still reads this element's data-checkout for the RAS
|
|
2085
|
+
// checkout_completed event and post-auth checkout routing. It is intentionally not
|
|
2086
|
+
// gated on woocommerce_checkout_cart_item_visible (it carries data, not a visible
|
|
2087
|
+
// row), so the JS anchor and analytics survive a plugin hiding the cart item.
|
|
2088
|
+
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 ) :
|
|
2121
2089
|
?>
|
|
2122
|
-
<p id="modal-checkout-product-details"
|
|
2123
|
-
<strong>
|
|
2124
|
-
<?php echo self::get_cart_product_summary( $cart, $summary_context ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
2125
|
-
</strong>
|
|
2126
|
-
</p>
|
|
2090
|
+
<p id="modal-checkout-product-details" <?php Checkout_Data::print_data_checkout_attr( Checkout_Data::get_checkout_data( $cart ) ); ?> hidden></p>
|
|
2127
2091
|
<?php
|
|
2128
2092
|
endif;
|
|
2129
2093
|
?>
|
|
2130
|
-
</div>
|
|
2131
2094
|
<?php
|
|
2132
2095
|
}
|
|
2133
2096
|
|
|
@@ -240,6 +240,7 @@ class Newspack_Blocks {
|
|
|
240
240
|
'recaptcha_url' => admin_url( 'admin.php?page=newspack-settings' ),
|
|
241
241
|
'custom_taxonomies' => self::get_custom_taxonomies(),
|
|
242
242
|
'can_use_name_your_price' => self::can_use_name_your_price(),
|
|
243
|
+
'coupons_enabled' => function_exists( 'wc_coupons_enabled' ) && \wc_coupons_enabled(),
|
|
243
244
|
'tier_amounts_template' => self::get_formatted_amount(),
|
|
244
245
|
'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
|
|
245
246
|
];
|
|
@@ -231,6 +231,29 @@ final class Checkout_Data {
|
|
|
231
231
|
return $children;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Build a `data-checkout` HTML attribute for a checkout-data payload.
|
|
236
|
+
*
|
|
237
|
+
* Centralizes wp_json_encode + esc_attr so the encoding and escaping live in a
|
|
238
|
+
* single place and can't be omitted by callers. Mirrors the JS getCheckoutData()
|
|
239
|
+
* reader in src/modal-checkout/utils.js.
|
|
240
|
+
*
|
|
241
|
+
* @param array $data Checkout-data payload (e.g. from get_checkout_data()).
|
|
242
|
+
* @return string Escaped attribute, e.g. data-checkout='{...}'.
|
|
243
|
+
*/
|
|
244
|
+
public static function data_checkout_attr( array $data ) {
|
|
245
|
+
return sprintf( "data-checkout='%s'", esc_attr( wp_json_encode( $data ) ) );
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Echo a `data-checkout` HTML attribute for a checkout-data payload.
|
|
250
|
+
*
|
|
251
|
+
* @param array $data Checkout-data payload.
|
|
252
|
+
*/
|
|
253
|
+
public static function print_data_checkout_attr( array $data ) {
|
|
254
|
+
echo self::data_checkout_attr( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- data_checkout_attr() escapes via esc_attr().
|
|
255
|
+
}
|
|
256
|
+
|
|
234
257
|
/**
|
|
235
258
|
* Returns checkout data given a product, product variation, cart or order object.
|
|
236
259
|
*
|
package/newspack-blocks.php
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Author URI: https://newspack.com/
|
|
8
8
|
* Text Domain: newspack-blocks
|
|
9
9
|
* Domain Path: /languages
|
|
10
|
-
* Version: 4.
|
|
10
|
+
* Version: 4.29.0-alpha.2
|
|
11
11
|
*
|
|
12
12
|
* @package Newspack_Blocks
|
|
13
13
|
*/
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
|
|
16
16
|
define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
|
|
17
17
|
define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
|
|
18
|
-
define( 'NEWSPACK_BLOCKS__VERSION', '4.
|
|
18
|
+
define( 'NEWSPACK_BLOCKS__VERSION', '4.29.0-alpha.2' );
|
|
19
19
|
|
|
20
20
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
|
|
21
21
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/newspack-blocks",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.29.0-alpha.2",
|
|
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": {
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"classnames": "^2.5.1",
|
|
48
48
|
"lodash": "^4.17.21",
|
|
49
|
-
"newspack-colors": "1.1.
|
|
50
|
-
"newspack-icons": "1.0.
|
|
49
|
+
"newspack-colors": "1.1.1-alpha.1",
|
|
50
|
+
"newspack-icons": "1.1.0-alpha.1",
|
|
51
51
|
"redux": "^5.0.0",
|
|
52
52
|
"redux-saga": "^1.5.0",
|
|
53
53
|
"regenerator-runtime": "^0.14.1",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/lodash": "^4.17.23",
|
|
58
|
-
"newspack-components": "4.
|
|
59
|
-
"newspack-scripts": "5.
|
|
58
|
+
"newspack-components": "4.6.0-alpha.1",
|
|
59
|
+
"newspack-scripts": "5.10.0-alpha.1"
|
|
60
60
|
},
|
|
61
61
|
"overrides": {
|
|
62
62
|
"path-to-regexp": "1.7.0"
|