@automattic/newspack-blocks 1.0.0-hotfix-cap-count-user-posts-dedup.1
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/.eslintrc.js +3 -0
- package/.hooks/pre-push +8 -0
- package/.nvmrc +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc.js +5 -0
- package/.stylelintrc.js +3 -0
- package/AGENTS.md +275 -0
- package/CHANGELOG.md +3971 -0
- package/CLAUDE.md +1 -0
- package/README.md +43 -0
- package/babel.config.js +6 -0
- package/bin/install-wp-tests.sh +155 -0
- package/bin/update-translations.sh +13 -0
- package/block-list.json +12 -0
- package/composer.json +46 -0
- package/composer.lock +3632 -0
- package/dist/author-list/view-rtl.css +1 -0
- package/dist/author-list/view.asset.php +1 -0
- package/dist/author-list/view.css +1 -0
- package/dist/author-list/view.js +0 -0
- package/dist/author-profile/view-rtl.css +1 -0
- package/dist/author-profile/view.asset.php +1 -0
- package/dist/author-profile/view.css +1 -0
- package/dist/author-profile/view.js +0 -0
- package/dist/block_styles-rtl.css +2 -0
- package/dist/block_styles.asset.php +1 -0
- package/dist/block_styles.css +2 -0
- package/dist/block_styles.js +0 -0
- package/dist/blocks/author-list/block.json +89 -0
- package/dist/blocks/author-profile/block.json +80 -0
- package/dist/blocks/carousel/block.json +125 -0
- package/dist/blocks/checkout-button/block.json +117 -0
- package/dist/blocks/donate/block.json +103 -0
- package/dist/blocks/homepage-articles/block.json +260 -0
- package/dist/blocks/iframe/block.json +36 -0
- package/dist/carousel/view-rtl.css +2 -0
- package/dist/carousel/view.asset.php +1 -0
- package/dist/carousel/view.css +2 -0
- package/dist/carousel/view.js +3 -0
- package/dist/checkout-button/view-rtl.css +1 -0
- package/dist/checkout-button/view.asset.php +1 -0
- package/dist/checkout-button/view.css +1 -0
- package/dist/checkout-button/view.js +0 -0
- package/dist/donate/view-rtl.css +1 -0
- package/dist/donate/view.asset.php +1 -0
- package/dist/donate/view.css +1 -0
- package/dist/donate/view.js +1 -0
- package/dist/editor-rtl.css +66 -0
- package/dist/editor.asset.php +1 -0
- package/dist/editor.css +66 -0
- package/dist/editor.js +57 -0
- package/dist/frequencyBased-rtl.css +1 -0
- package/dist/frequencyBased.asset.php +1 -0
- package/dist/frequencyBased.css +1 -0
- package/dist/frequencyBased.js +1 -0
- package/dist/homepage-articles/view-rtl.css +1 -0
- package/dist/homepage-articles/view.asset.php +1 -0
- package/dist/homepage-articles/view.css +1 -0
- package/dist/homepage-articles/view.js +1 -0
- package/dist/iframe/view-rtl.css +1 -0
- package/dist/iframe/view.asset.php +1 -0
- package/dist/iframe/view.css +1 -0
- package/dist/iframe/view.js +1 -0
- package/dist/modal-rtl.css +1 -0
- package/dist/modal.asset.php +1 -0
- package/dist/modal.css +1 -0
- package/dist/modal.js +1 -0
- package/dist/modalCheckout-rtl.css +1 -0
- package/dist/modalCheckout.asset.php +1 -0
- package/dist/modalCheckout.css +1 -0
- package/dist/modalCheckout.js +1 -0
- package/dist/placeholder_blocks.asset.php +1 -0
- package/dist/placeholder_blocks.js +4 -0
- package/dist/tiersBased-rtl.css +1 -0
- package/dist/tiersBased.asset.php +1 -0
- package/dist/tiersBased.css +1 -0
- package/dist/tiersBased.js +1 -0
- package/includes/class-modal-checkout.php +2324 -0
- package/includes/class-newspack-blocks-api.php +347 -0
- package/includes/class-newspack-blocks-caching.php +291 -0
- package/includes/class-newspack-blocks-patterns.php +167 -0
- package/includes/class-newspack-blocks.php +1581 -0
- package/includes/modal-checkout/class-change-payment-gateway.php +86 -0
- package/includes/modal-checkout/class-checkout-data.php +406 -0
- package/includes/plugins/class-the-events-calendar.php +84 -0
- package/includes/tracking/class-data-events.php +83 -0
- package/languages/newspack-blocks-de_DE-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
- package/languages/newspack-blocks-de_DE-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
- package/languages/newspack-blocks-de_DE-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
- package/languages/newspack-blocks-de_DE-10754bc02d28d4301c103f26dbf519ce.json +1 -0
- package/languages/newspack-blocks-de_DE-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
- package/languages/newspack-blocks-de_DE-34e5c64f90b1444f3fc735376442eada.json +1 -0
- package/languages/newspack-blocks-de_DE-351fd022e077061b5796bf7042446bfc.json +1 -0
- package/languages/newspack-blocks-de_DE-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
- package/languages/newspack-blocks-de_DE-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
- package/languages/newspack-blocks-de_DE-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
- package/languages/newspack-blocks-de_DE-4f16e21047908d19937bc10ced63acd1.json +1 -0
- package/languages/newspack-blocks-de_DE-4fdea541976076f02d56139fb35e5b42.json +1 -0
- package/languages/newspack-blocks-de_DE-501b38ac90d35730a620fb0d483702fa.json +1 -0
- package/languages/newspack-blocks-de_DE-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
- package/languages/newspack-blocks-de_DE-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
- package/languages/newspack-blocks-de_DE-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
- package/languages/newspack-blocks-de_DE-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
- package/languages/newspack-blocks-de_DE-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
- package/languages/newspack-blocks-de_DE-727631509ad8eec8e2cbe740c6dad199.json +1 -0
- package/languages/newspack-blocks-de_DE-73c6d3bde805172d1993f75397e9832d.json +1 -0
- package/languages/newspack-blocks-de_DE-78456b164809d080adecb4d2b3895802.json +1 -0
- package/languages/newspack-blocks-de_DE-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
- package/languages/newspack-blocks-de_DE-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
- package/languages/newspack-blocks-de_DE-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
- package/languages/newspack-blocks-de_DE-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
- package/languages/newspack-blocks-de_DE-969286d51bb0afe10983b9aec317b5ee.json +1 -0
- package/languages/newspack-blocks-de_DE-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
- package/languages/newspack-blocks-de_DE-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
- package/languages/newspack-blocks-de_DE-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
- package/languages/newspack-blocks-de_DE-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
- package/languages/newspack-blocks-de_DE-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
- package/languages/newspack-blocks-de_DE-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
- package/languages/newspack-blocks-de_DE-bb66d96d450663284550bed5a3e9113e.json +1 -0
- package/languages/newspack-blocks-de_DE-c810378e74f20906b8193ea76adb6bc0.json +1 -0
- package/languages/newspack-blocks-de_DE-d3a1c55a07efd1a65e227bf120840752.json +1 -0
- package/languages/newspack-blocks-de_DE-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
- package/languages/newspack-blocks-de_DE-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
- package/languages/newspack-blocks-de_DE-dd56360b115d1b39c48033c1e0749a11.json +1 -0
- package/languages/newspack-blocks-de_DE-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
- package/languages/newspack-blocks-de_DE-e58126c278611ed6c17684ba8e7459b4.json +1 -0
- package/languages/newspack-blocks-de_DE-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
- package/languages/newspack-blocks-de_DE-eccbc51a43c04f59165364eda71e0be7.json +1 -0
- package/languages/newspack-blocks-de_DE-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
- package/languages/newspack-blocks-de_DE-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
- package/languages/newspack-blocks-de_DE-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
- package/languages/newspack-blocks-de_DE-f5f8db76788e4079ddfa743333708b88.json +1 -0
- package/languages/newspack-blocks-de_DE-f8b1589c450689398f90b179f47e74ee.json +1 -0
- package/languages/newspack-blocks-de_DE-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
- package/languages/newspack-blocks-de_DE-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
- package/languages/newspack-blocks-de_DE-fcc93143c1f2b74671f595454b971f44.json +1 -0
- package/languages/newspack-blocks-de_DE.mo +0 -0
- package/languages/newspack-blocks-de_DE.po +2088 -0
- package/languages/newspack-blocks-es_ES-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
- package/languages/newspack-blocks-es_ES-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
- package/languages/newspack-blocks-es_ES-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
- package/languages/newspack-blocks-es_ES-10754bc02d28d4301c103f26dbf519ce.json +1 -0
- package/languages/newspack-blocks-es_ES-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
- package/languages/newspack-blocks-es_ES-34e5c64f90b1444f3fc735376442eada.json +1 -0
- package/languages/newspack-blocks-es_ES-351fd022e077061b5796bf7042446bfc.json +1 -0
- package/languages/newspack-blocks-es_ES-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
- package/languages/newspack-blocks-es_ES-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
- package/languages/newspack-blocks-es_ES-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
- package/languages/newspack-blocks-es_ES-4f16e21047908d19937bc10ced63acd1.json +1 -0
- package/languages/newspack-blocks-es_ES-4fdea541976076f02d56139fb35e5b42.json +1 -0
- package/languages/newspack-blocks-es_ES-501b38ac90d35730a620fb0d483702fa.json +1 -0
- package/languages/newspack-blocks-es_ES-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
- package/languages/newspack-blocks-es_ES-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
- package/languages/newspack-blocks-es_ES-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
- package/languages/newspack-blocks-es_ES-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
- package/languages/newspack-blocks-es_ES-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
- package/languages/newspack-blocks-es_ES-727631509ad8eec8e2cbe740c6dad199.json +1 -0
- package/languages/newspack-blocks-es_ES-73c6d3bde805172d1993f75397e9832d.json +1 -0
- package/languages/newspack-blocks-es_ES-78456b164809d080adecb4d2b3895802.json +1 -0
- package/languages/newspack-blocks-es_ES-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
- package/languages/newspack-blocks-es_ES-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
- package/languages/newspack-blocks-es_ES-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
- package/languages/newspack-blocks-es_ES-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
- package/languages/newspack-blocks-es_ES-969286d51bb0afe10983b9aec317b5ee.json +1 -0
- package/languages/newspack-blocks-es_ES-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
- package/languages/newspack-blocks-es_ES-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
- package/languages/newspack-blocks-es_ES-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
- package/languages/newspack-blocks-es_ES-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
- package/languages/newspack-blocks-es_ES-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
- package/languages/newspack-blocks-es_ES-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
- package/languages/newspack-blocks-es_ES-bb66d96d450663284550bed5a3e9113e.json +1 -0
- package/languages/newspack-blocks-es_ES-c810378e74f20906b8193ea76adb6bc0.json +1 -0
- package/languages/newspack-blocks-es_ES-d3a1c55a07efd1a65e227bf120840752.json +1 -0
- package/languages/newspack-blocks-es_ES-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
- package/languages/newspack-blocks-es_ES-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
- package/languages/newspack-blocks-es_ES-dd56360b115d1b39c48033c1e0749a11.json +1 -0
- package/languages/newspack-blocks-es_ES-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
- package/languages/newspack-blocks-es_ES-e58126c278611ed6c17684ba8e7459b4.json +1 -0
- package/languages/newspack-blocks-es_ES-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
- package/languages/newspack-blocks-es_ES-eccbc51a43c04f59165364eda71e0be7.json +1 -0
- package/languages/newspack-blocks-es_ES-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
- package/languages/newspack-blocks-es_ES-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
- package/languages/newspack-blocks-es_ES-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
- package/languages/newspack-blocks-es_ES-f5f8db76788e4079ddfa743333708b88.json +1 -0
- package/languages/newspack-blocks-es_ES-f8b1589c450689398f90b179f47e74ee.json +1 -0
- package/languages/newspack-blocks-es_ES-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
- package/languages/newspack-blocks-es_ES-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
- package/languages/newspack-blocks-es_ES-fcc93143c1f2b74671f595454b971f44.json +1 -0
- package/languages/newspack-blocks-es_ES.mo +0 -0
- package/languages/newspack-blocks-es_ES.po +2080 -0
- package/languages/newspack-blocks-fr_BE-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
- package/languages/newspack-blocks-fr_BE-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
- package/languages/newspack-blocks-fr_BE-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
- package/languages/newspack-blocks-fr_BE-10754bc02d28d4301c103f26dbf519ce.json +1 -0
- package/languages/newspack-blocks-fr_BE-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
- package/languages/newspack-blocks-fr_BE-34e5c64f90b1444f3fc735376442eada.json +1 -0
- package/languages/newspack-blocks-fr_BE-351fd022e077061b5796bf7042446bfc.json +1 -0
- package/languages/newspack-blocks-fr_BE-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
- package/languages/newspack-blocks-fr_BE-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
- package/languages/newspack-blocks-fr_BE-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
- package/languages/newspack-blocks-fr_BE-4f16e21047908d19937bc10ced63acd1.json +1 -0
- package/languages/newspack-blocks-fr_BE-4fdea541976076f02d56139fb35e5b42.json +1 -0
- package/languages/newspack-blocks-fr_BE-501b38ac90d35730a620fb0d483702fa.json +1 -0
- package/languages/newspack-blocks-fr_BE-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
- package/languages/newspack-blocks-fr_BE-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
- package/languages/newspack-blocks-fr_BE-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
- package/languages/newspack-blocks-fr_BE-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
- package/languages/newspack-blocks-fr_BE-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
- package/languages/newspack-blocks-fr_BE-727631509ad8eec8e2cbe740c6dad199.json +1 -0
- package/languages/newspack-blocks-fr_BE-73c6d3bde805172d1993f75397e9832d.json +1 -0
- package/languages/newspack-blocks-fr_BE-78456b164809d080adecb4d2b3895802.json +1 -0
- package/languages/newspack-blocks-fr_BE-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
- package/languages/newspack-blocks-fr_BE-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
- package/languages/newspack-blocks-fr_BE-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
- package/languages/newspack-blocks-fr_BE-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
- package/languages/newspack-blocks-fr_BE-969286d51bb0afe10983b9aec317b5ee.json +1 -0
- package/languages/newspack-blocks-fr_BE-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
- package/languages/newspack-blocks-fr_BE-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
- package/languages/newspack-blocks-fr_BE-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
- package/languages/newspack-blocks-fr_BE-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
- package/languages/newspack-blocks-fr_BE-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
- package/languages/newspack-blocks-fr_BE-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
- package/languages/newspack-blocks-fr_BE-bb66d96d450663284550bed5a3e9113e.json +1 -0
- package/languages/newspack-blocks-fr_BE-c810378e74f20906b8193ea76adb6bc0.json +1 -0
- package/languages/newspack-blocks-fr_BE-d3a1c55a07efd1a65e227bf120840752.json +1 -0
- package/languages/newspack-blocks-fr_BE-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
- package/languages/newspack-blocks-fr_BE-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
- package/languages/newspack-blocks-fr_BE-dd56360b115d1b39c48033c1e0749a11.json +1 -0
- package/languages/newspack-blocks-fr_BE-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
- package/languages/newspack-blocks-fr_BE-e58126c278611ed6c17684ba8e7459b4.json +1 -0
- package/languages/newspack-blocks-fr_BE-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
- package/languages/newspack-blocks-fr_BE-eccbc51a43c04f59165364eda71e0be7.json +1 -0
- package/languages/newspack-blocks-fr_BE-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
- package/languages/newspack-blocks-fr_BE-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
- package/languages/newspack-blocks-fr_BE-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
- package/languages/newspack-blocks-fr_BE-f5f8db76788e4079ddfa743333708b88.json +1 -0
- package/languages/newspack-blocks-fr_BE-f8b1589c450689398f90b179f47e74ee.json +1 -0
- package/languages/newspack-blocks-fr_BE-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
- package/languages/newspack-blocks-fr_BE-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
- package/languages/newspack-blocks-fr_BE-fcc93143c1f2b74671f595454b971f44.json +1 -0
- package/languages/newspack-blocks-fr_BE.mo +0 -0
- package/languages/newspack-blocks-fr_BE.po +2079 -0
- package/languages/newspack-blocks-nb_NO-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
- package/languages/newspack-blocks-nb_NO-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
- package/languages/newspack-blocks-nb_NO-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
- package/languages/newspack-blocks-nb_NO-10754bc02d28d4301c103f26dbf519ce.json +1 -0
- package/languages/newspack-blocks-nb_NO-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
- package/languages/newspack-blocks-nb_NO-34e5c64f90b1444f3fc735376442eada.json +1 -0
- package/languages/newspack-blocks-nb_NO-351fd022e077061b5796bf7042446bfc.json +1 -0
- package/languages/newspack-blocks-nb_NO-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
- package/languages/newspack-blocks-nb_NO-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
- package/languages/newspack-blocks-nb_NO-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
- package/languages/newspack-blocks-nb_NO-4f16e21047908d19937bc10ced63acd1.json +1 -0
- package/languages/newspack-blocks-nb_NO-4fdea541976076f02d56139fb35e5b42.json +1 -0
- package/languages/newspack-blocks-nb_NO-501b38ac90d35730a620fb0d483702fa.json +1 -0
- package/languages/newspack-blocks-nb_NO-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
- package/languages/newspack-blocks-nb_NO-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
- package/languages/newspack-blocks-nb_NO-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
- package/languages/newspack-blocks-nb_NO-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
- package/languages/newspack-blocks-nb_NO-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
- package/languages/newspack-blocks-nb_NO-73c6d3bde805172d1993f75397e9832d.json +1 -0
- package/languages/newspack-blocks-nb_NO-78456b164809d080adecb4d2b3895802.json +1 -0
- package/languages/newspack-blocks-nb_NO-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
- package/languages/newspack-blocks-nb_NO-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
- package/languages/newspack-blocks-nb_NO-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
- package/languages/newspack-blocks-nb_NO-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
- package/languages/newspack-blocks-nb_NO-969286d51bb0afe10983b9aec317b5ee.json +1 -0
- package/languages/newspack-blocks-nb_NO-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
- package/languages/newspack-blocks-nb_NO-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
- package/languages/newspack-blocks-nb_NO-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
- package/languages/newspack-blocks-nb_NO-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
- package/languages/newspack-blocks-nb_NO-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
- package/languages/newspack-blocks-nb_NO-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
- package/languages/newspack-blocks-nb_NO-bb66d96d450663284550bed5a3e9113e.json +1 -0
- package/languages/newspack-blocks-nb_NO-c810378e74f20906b8193ea76adb6bc0.json +1 -0
- package/languages/newspack-blocks-nb_NO-d3a1c55a07efd1a65e227bf120840752.json +1 -0
- package/languages/newspack-blocks-nb_NO-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
- package/languages/newspack-blocks-nb_NO-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
- package/languages/newspack-blocks-nb_NO-dd56360b115d1b39c48033c1e0749a11.json +1 -0
- package/languages/newspack-blocks-nb_NO-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
- package/languages/newspack-blocks-nb_NO-e58126c278611ed6c17684ba8e7459b4.json +1 -0
- package/languages/newspack-blocks-nb_NO-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
- package/languages/newspack-blocks-nb_NO-eccbc51a43c04f59165364eda71e0be7.json +1 -0
- package/languages/newspack-blocks-nb_NO-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
- package/languages/newspack-blocks-nb_NO-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
- package/languages/newspack-blocks-nb_NO-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
- package/languages/newspack-blocks-nb_NO-f5f8db76788e4079ddfa743333708b88.json +1 -0
- package/languages/newspack-blocks-nb_NO-f8b1589c450689398f90b179f47e74ee.json +1 -0
- package/languages/newspack-blocks-nb_NO-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
- package/languages/newspack-blocks-nb_NO-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
- package/languages/newspack-blocks-nb_NO-fcc93143c1f2b74671f595454b971f44.json +1 -0
- package/languages/newspack-blocks-nb_NO.mo +0 -0
- package/languages/newspack-blocks-nb_NO.po +2078 -0
- package/languages/newspack-blocks-pt_PT-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
- package/languages/newspack-blocks-pt_PT-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
- package/languages/newspack-blocks-pt_PT-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
- package/languages/newspack-blocks-pt_PT-10754bc02d28d4301c103f26dbf519ce.json +1 -0
- package/languages/newspack-blocks-pt_PT-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
- package/languages/newspack-blocks-pt_PT-34e5c64f90b1444f3fc735376442eada.json +1 -0
- package/languages/newspack-blocks-pt_PT-351fd022e077061b5796bf7042446bfc.json +1 -0
- package/languages/newspack-blocks-pt_PT-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
- package/languages/newspack-blocks-pt_PT-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
- package/languages/newspack-blocks-pt_PT-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
- package/languages/newspack-blocks-pt_PT-4f16e21047908d19937bc10ced63acd1.json +1 -0
- package/languages/newspack-blocks-pt_PT-4fdea541976076f02d56139fb35e5b42.json +1 -0
- package/languages/newspack-blocks-pt_PT-501b38ac90d35730a620fb0d483702fa.json +1 -0
- package/languages/newspack-blocks-pt_PT-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
- package/languages/newspack-blocks-pt_PT-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
- package/languages/newspack-blocks-pt_PT-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
- package/languages/newspack-blocks-pt_PT-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
- package/languages/newspack-blocks-pt_PT-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
- package/languages/newspack-blocks-pt_PT-727631509ad8eec8e2cbe740c6dad199.json +1 -0
- package/languages/newspack-blocks-pt_PT-73c6d3bde805172d1993f75397e9832d.json +1 -0
- package/languages/newspack-blocks-pt_PT-78456b164809d080adecb4d2b3895802.json +1 -0
- package/languages/newspack-blocks-pt_PT-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
- package/languages/newspack-blocks-pt_PT-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
- package/languages/newspack-blocks-pt_PT-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
- package/languages/newspack-blocks-pt_PT-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
- package/languages/newspack-blocks-pt_PT-969286d51bb0afe10983b9aec317b5ee.json +1 -0
- package/languages/newspack-blocks-pt_PT-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
- package/languages/newspack-blocks-pt_PT-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
- package/languages/newspack-blocks-pt_PT-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
- package/languages/newspack-blocks-pt_PT-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
- package/languages/newspack-blocks-pt_PT-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
- package/languages/newspack-blocks-pt_PT-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
- package/languages/newspack-blocks-pt_PT-bb66d96d450663284550bed5a3e9113e.json +1 -0
- package/languages/newspack-blocks-pt_PT-c810378e74f20906b8193ea76adb6bc0.json +1 -0
- package/languages/newspack-blocks-pt_PT-d3a1c55a07efd1a65e227bf120840752.json +1 -0
- package/languages/newspack-blocks-pt_PT-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
- package/languages/newspack-blocks-pt_PT-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
- package/languages/newspack-blocks-pt_PT-dd56360b115d1b39c48033c1e0749a11.json +1 -0
- package/languages/newspack-blocks-pt_PT-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
- package/languages/newspack-blocks-pt_PT-e58126c278611ed6c17684ba8e7459b4.json +1 -0
- package/languages/newspack-blocks-pt_PT-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
- package/languages/newspack-blocks-pt_PT-eccbc51a43c04f59165364eda71e0be7.json +1 -0
- package/languages/newspack-blocks-pt_PT-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
- package/languages/newspack-blocks-pt_PT-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
- package/languages/newspack-blocks-pt_PT-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
- package/languages/newspack-blocks-pt_PT-f5f8db76788e4079ddfa743333708b88.json +1 -0
- package/languages/newspack-blocks-pt_PT-f8b1589c450689398f90b179f47e74ee.json +1 -0
- package/languages/newspack-blocks-pt_PT-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
- package/languages/newspack-blocks-pt_PT-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
- package/languages/newspack-blocks-pt_PT-fcc93143c1f2b74671f595454b971f44.json +1 -0
- package/languages/newspack-blocks-pt_PT.mo +0 -0
- package/languages/newspack-blocks-pt_PT.po +2078 -0
- package/languages/newspack-blocks.pot +2370 -0
- package/newspack-blocks.php +96 -0
- package/package.json +64 -0
- package/phpcs.xml +38 -0
- package/release.config.js +1 -0
- package/src/assets/placeholder-1024x536.jpg +0 -0
- package/src/assets/placeholder-600x800.jpg +0 -0
- package/src/assets/placeholder-800x600.jpg +0 -0
- package/src/assets/placeholder-800x800.jpg +0 -0
- package/src/assets/placeholder-donations-cover.jpg +0 -0
- package/src/assets/placeholder-donations-image.jpg +0 -0
- package/src/assets/placeholder-subscribe-cover.jpg +0 -0
- package/src/assets/placeholder-subscribe-image.jpg +0 -0
- package/src/block-patterns/donations-1.php +13 -0
- package/src/block-patterns/donations-2.php +13 -0
- package/src/block-patterns/donations-3.php +13 -0
- package/src/block-patterns/donations-4.php +13 -0
- package/src/block-patterns/donations-5.php +13 -0
- package/src/block-patterns/homepage-posts-1.php +13 -0
- package/src/block-patterns/homepage-posts-10.php +13 -0
- package/src/block-patterns/homepage-posts-11.php +13 -0
- package/src/block-patterns/homepage-posts-12.php +13 -0
- package/src/block-patterns/homepage-posts-13.php +13 -0
- package/src/block-patterns/homepage-posts-14.php +13 -0
- package/src/block-patterns/homepage-posts-15.php +13 -0
- package/src/block-patterns/homepage-posts-16.php +13 -0
- package/src/block-patterns/homepage-posts-17.php +13 -0
- package/src/block-patterns/homepage-posts-18.php +13 -0
- package/src/block-patterns/homepage-posts-19.php +13 -0
- package/src/block-patterns/homepage-posts-2.php +13 -0
- package/src/block-patterns/homepage-posts-20.php +13 -0
- package/src/block-patterns/homepage-posts-21.php +13 -0
- package/src/block-patterns/homepage-posts-22.php +13 -0
- package/src/block-patterns/homepage-posts-23.php +13 -0
- package/src/block-patterns/homepage-posts-24.php +13 -0
- package/src/block-patterns/homepage-posts-25.php +13 -0
- package/src/block-patterns/homepage-posts-26.php +13 -0
- package/src/block-patterns/homepage-posts-27.php +13 -0
- package/src/block-patterns/homepage-posts-28.php +13 -0
- package/src/block-patterns/homepage-posts-29.php +13 -0
- package/src/block-patterns/homepage-posts-3.php +13 -0
- package/src/block-patterns/homepage-posts-30.php +13 -0
- package/src/block-patterns/homepage-posts-31.php +13 -0
- package/src/block-patterns/homepage-posts-4.php +13 -0
- package/src/block-patterns/homepage-posts-5.php +13 -0
- package/src/block-patterns/homepage-posts-6.php +13 -0
- package/src/block-patterns/homepage-posts-7.php +13 -0
- package/src/block-patterns/homepage-posts-8.php +13 -0
- package/src/block-patterns/homepage-posts-9.php +13 -0
- package/src/block-patterns/subscribe-1.php +13 -0
- package/src/block-patterns/subscribe-2.php +13 -0
- package/src/block-patterns/subscribe-3.php +13 -0
- package/src/block-patterns/subscribe-4.php +13 -0
- package/src/block-patterns/subscribe-5.php +13 -0
- package/src/block-patterns/subscribe-6.php +13 -0
- package/src/block-patterns/subscribe-7.php +13 -0
- package/src/block-styles/core/columns/editor.scss +90 -0
- package/src/block-styles/core/columns/index.js +20 -0
- package/src/block-styles/core/columns/view.scss +131 -0
- package/src/block-styles/core/group/editor.scss +24 -0
- package/src/block-styles/core/group/index.js +25 -0
- package/src/block-styles/core/group/view.scss +13 -0
- package/src/block-styles/view.js +5 -0
- package/src/blocks/author-list/block.json +84 -0
- package/src/blocks/author-list/class-wp-rest-newspack-author-list-controller.php +381 -0
- package/src/blocks/author-list/edit.js +456 -0
- package/src/blocks/author-list/editor.js +7 -0
- package/src/blocks/author-list/editor.scss +1 -0
- package/src/blocks/author-list/index.js +60 -0
- package/src/blocks/author-list/view.js +5 -0
- package/src/blocks/author-list/view.php +180 -0
- package/src/blocks/author-list/view.scss +46 -0
- package/src/blocks/author-profile/README.md +105 -0
- package/src/blocks/author-profile/block.json +77 -0
- package/src/blocks/author-profile/class-wp-rest-newspack-authors-controller.php +618 -0
- package/src/blocks/author-profile/context.js +26 -0
- package/src/blocks/author-profile/edit.js +1031 -0
- package/src/blocks/author-profile/editor.js +7 -0
- package/src/blocks/author-profile/editor.scss +61 -0
- package/src/blocks/author-profile/index.js +66 -0
- package/src/blocks/author-profile/single-author.js +106 -0
- package/src/blocks/author-profile/templates.js +263 -0
- package/src/blocks/author-profile/variations.js +86 -0
- package/src/blocks/author-profile/view.js +5 -0
- package/src/blocks/author-profile/view.php +501 -0
- package/src/blocks/author-profile/view.scss +159 -0
- package/src/blocks/carousel/block.json +121 -0
- package/src/blocks/carousel/create-swiper.js +230 -0
- package/src/blocks/carousel/edit.js +469 -0
- package/src/blocks/carousel/editor.js +7 -0
- package/src/blocks/carousel/editor.scss +54 -0
- package/src/blocks/carousel/index.js +55 -0
- package/src/blocks/carousel/view.js +49 -0
- package/src/blocks/carousel/view.php +417 -0
- package/src/blocks/carousel/view.scss +397 -0
- package/src/blocks/checkout-button/block.json +117 -0
- package/src/blocks/checkout-button/deprecated.js +81 -0
- package/src/blocks/checkout-button/edit.js +385 -0
- package/src/blocks/checkout-button/edit.scss +67 -0
- package/src/blocks/checkout-button/editor.js +19 -0
- package/src/blocks/checkout-button/index.js +32 -0
- package/src/blocks/checkout-button/view.js +4 -0
- package/src/blocks/checkout-button/view.php +178 -0
- package/src/blocks/checkout-button/view.scss +39 -0
- package/src/blocks/donate/block.json +103 -0
- package/src/blocks/donate/consts.ts +25 -0
- package/src/blocks/donate/edit/FrequencyBasedLayout.tsx +255 -0
- package/src/blocks/donate/edit/TierBasedLayout.tsx +133 -0
- package/src/blocks/donate/edit/components/AmountValueInput.tsx +62 -0
- package/src/blocks/donate/edit/components/index.tsx +1 -0
- package/src/blocks/donate/edit/index.tsx +445 -0
- package/src/blocks/donate/editor.js +7 -0
- package/src/blocks/donate/frequency-based/index.ts +135 -0
- package/src/blocks/donate/frequency-based/style.scss +245 -0
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-base.php +225 -0
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-frequency-based.php +341 -0
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-tiers-based.php +184 -0
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer.php +117 -0
- package/src/blocks/donate/index.js +72 -0
- package/src/blocks/donate/styles/editor.scss +230 -0
- package/src/blocks/donate/styles/style-variations.scss +792 -0
- package/src/blocks/donate/styles/view.scss +45 -0
- package/src/blocks/donate/tiers-based/index.ts +36 -0
- package/src/blocks/donate/tiers-based/slider.ts +64 -0
- package/src/blocks/donate/tiers-based/style.scss +185 -0
- package/src/blocks/donate/tiers-based/types.ts +3 -0
- package/src/blocks/donate/tiers-based/utils.test.js +38 -0
- package/src/blocks/donate/tiers-based/utils.ts +21 -0
- package/src/blocks/donate/tiers-based/view.ts +132 -0
- package/src/blocks/donate/types.ts +96 -0
- package/src/blocks/donate/utils.ts +108 -0
- package/src/blocks/donate/view.php +29 -0
- package/src/blocks/donate/view.ts +44 -0
- package/src/blocks/homepage-articles/block.json +260 -0
- package/src/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php +231 -0
- package/src/blocks/homepage-articles/edit.tsx +730 -0
- package/src/blocks/homepage-articles/editor.js +16 -0
- package/src/blocks/homepage-articles/editor.scss +226 -0
- package/src/blocks/homepage-articles/index.js +102 -0
- package/src/blocks/homepage-articles/store.js +193 -0
- package/src/blocks/homepage-articles/templates/article.php +290 -0
- package/src/blocks/homepage-articles/templates/articles-list.php +21 -0
- package/src/blocks/homepage-articles/templates/articles-loop.php +35 -0
- package/src/blocks/homepage-articles/utils.ts +270 -0
- package/src/blocks/homepage-articles/view.js +242 -0
- package/src/blocks/homepage-articles/view.php +561 -0
- package/src/blocks/homepage-articles/view.scss +784 -0
- package/src/blocks/iframe/block.json +36 -0
- package/src/blocks/iframe/class-wp-rest-newspack-iframe-controller.php +586 -0
- package/src/blocks/iframe/edit.js +232 -0
- package/src/blocks/iframe/editor.js +7 -0
- package/src/blocks/iframe/editor.scss +84 -0
- package/src/blocks/iframe/iframe-placeholder.js +166 -0
- package/src/blocks/iframe/index.js +54 -0
- package/src/blocks/iframe/view.js +49 -0
- package/src/blocks/iframe/view.php +116 -0
- package/src/blocks/iframe/view.scss +9 -0
- package/src/blocks/shared/author.js +47 -0
- package/src/blocks/video-playlist/edit.js +222 -0
- package/src/blocks/video-playlist/editor.js +7 -0
- package/src/blocks/video-playlist/editor.scss +23 -0
- package/src/blocks/video-playlist/index.js +54 -0
- package/src/blocks/video-playlist/view.php +188 -0
- package/src/components/autocomplete-tokenfield.js +189 -0
- package/src/components/autocomplete-tokenfield.scss +27 -0
- package/src/components/editor-panels.js +90 -0
- package/src/components/query-controls.js +450 -0
- package/src/components/redirect-after-success.tsx +50 -0
- package/src/modal-checkout/accessibility.js +73 -0
- package/src/modal-checkout/analytics/ga4/README.md +45 -0
- package/src/modal-checkout/analytics/ga4/checkout-attempt.js +18 -0
- package/src/modal-checkout/analytics/ga4/checkout-success.js +17 -0
- package/src/modal-checkout/analytics/ga4/dismissed.js +17 -0
- package/src/modal-checkout/analytics/ga4/loaded.js +17 -0
- package/src/modal-checkout/analytics/ga4/opened.js +37 -0
- package/src/modal-checkout/analytics/ga4/pagination.js +59 -0
- package/src/modal-checkout/analytics/ga4/utils/index.js +64 -0
- package/src/modal-checkout/analytics/index.js +6 -0
- package/src/modal-checkout/checkout.scss +1064 -0
- package/src/modal-checkout/index.js +929 -0
- package/src/modal-checkout/modal.js +983 -0
- package/src/modal-checkout/modal.scss +265 -0
- package/src/modal-checkout/templates/empty-html-add-recipient.php +15 -0
- package/src/modal-checkout/templates/empty-order-details.php +16 -0
- package/src/modal-checkout/templates/form-change-payment-method.php +99 -0
- package/src/modal-checkout/templates/form-checkout.php +74 -0
- package/src/modal-checkout/templates/form-coupon.php +22 -0
- package/src/modal-checkout/templates/form-gift-subscription.php +34 -0
- package/src/modal-checkout/templates/payment-method.php +29 -0
- package/src/modal-checkout/templates/thankyou.php +94 -0
- package/src/modal-checkout/utils.js +309 -0
- package/src/setup/block-styles.js +2 -0
- package/src/setup/category.js +18 -0
- package/src/setup/editor.js +7 -0
- package/src/setup/editor.scss +56 -0
- package/src/setup/newspack-logo.js +26 -0
- package/src/setup/placeholder-blocks.js +84 -0
- package/src/setup/unregister-blocks.js +14 -0
- package/src/shared/authors.php +63 -0
- package/src/shared/js/newspack-icon.js +31 -0
- package/src/shared/js/utils.js +50 -0
- package/src/shared/sass/_mixins.scss +42 -0
- package/src/shared/sass/_placeholder.scss +5 -0
- package/src/shared/sass/_preview.scss +12 -0
- package/src/shared/sass/_variables.scss +24 -0
- package/src/templates/author-profile-card.php +145 -0
- package/src/types/@wordpress/block-editor.d.ts +1 -0
- package/src/types/@wordpress/components.d.ts +1 -0
- package/src/types/index.d.ts +170 -0
- package/src/types/newspack-components.d.ts +7 -0
- package/tsconfig.json +7 -0
- package/vendor/autoload.php +22 -0
- package/vendor/composer/ClassLoader.php +579 -0
- package/vendor/composer/InstalledVersions.php +396 -0
- package/vendor/composer/LICENSE +21 -0
- package/vendor/composer/autoload_classmap.php +10 -0
- package/vendor/composer/autoload_namespaces.php +9 -0
- package/vendor/composer/autoload_psr4.php +9 -0
- package/vendor/composer/autoload_real.php +36 -0
- package/vendor/composer/autoload_static.php +20 -0
- package/vendor/composer/installed.json +5 -0
- package/vendor/composer/installed.php +23 -0
- package/webpack.config.js +82 -0
|
@@ -0,0 +1,2324 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Newspack Blocks Modal Checkout
|
|
4
|
+
*
|
|
5
|
+
* @package Newspack_Blocks
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
namespace Newspack_Blocks;
|
|
9
|
+
|
|
10
|
+
use Newspack_Blocks\Modal_Checkout\Checkout_Data;
|
|
11
|
+
|
|
12
|
+
defined( 'ABSPATH' ) || exit;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Modal Checkout Class.
|
|
16
|
+
*/
|
|
17
|
+
final class Modal_Checkout {
|
|
18
|
+
/**
|
|
19
|
+
* Checkout registration flag.
|
|
20
|
+
*
|
|
21
|
+
* @var string
|
|
22
|
+
*/
|
|
23
|
+
const CHECKOUT_REGISTRATION_FLAG = '_newspack_checkout_registration';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Checkout registration order meta key.
|
|
27
|
+
*
|
|
28
|
+
* @var string
|
|
29
|
+
*/
|
|
30
|
+
const CHECKOUT_REGISTRATION_ORDER_META_KEY = '_newspack_checkout_registration_meta';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Whether the modal checkout has been enqueued.
|
|
34
|
+
*
|
|
35
|
+
* @var boolean
|
|
36
|
+
*/
|
|
37
|
+
private static $has_modal = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Products that are being rendered a checkout modal for.
|
|
41
|
+
*
|
|
42
|
+
* @var true[] Product IDs as keys.
|
|
43
|
+
*/
|
|
44
|
+
private static $products = [];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Labels for the modal checkout UI.
|
|
48
|
+
*
|
|
49
|
+
* @var mixed[]
|
|
50
|
+
*/
|
|
51
|
+
private static $modal_checkout_labels = [];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Allowed assets for modal checkout.
|
|
55
|
+
*
|
|
56
|
+
* @var string[]
|
|
57
|
+
*/
|
|
58
|
+
private static $allowed_scripts = [
|
|
59
|
+
'jquery',
|
|
60
|
+
'google_gtagjs',
|
|
61
|
+
// Newspack.
|
|
62
|
+
'newspack_commons',
|
|
63
|
+
'newspack-newsletters-',
|
|
64
|
+
'newspack-blocks-modal',
|
|
65
|
+
'newspack-blocks-modal-checkout',
|
|
66
|
+
'newspack-wc',
|
|
67
|
+
'newspack-ui',
|
|
68
|
+
'newspack-style',
|
|
69
|
+
'newspack-recaptcha',
|
|
70
|
+
'newspack-woocommerce-style',
|
|
71
|
+
'newspack-reader-activation',
|
|
72
|
+
'newspack-my-account',
|
|
73
|
+
// Woo.
|
|
74
|
+
'woocommerce',
|
|
75
|
+
'WCPAY',
|
|
76
|
+
'Woo',
|
|
77
|
+
'wc-',
|
|
78
|
+
'wc_',
|
|
79
|
+
'wcs-',
|
|
80
|
+
'stripe',
|
|
81
|
+
'select2',
|
|
82
|
+
'selectWoo',
|
|
83
|
+
// Metorik.
|
|
84
|
+
'metorik',
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Allowed styles for modal checkout.
|
|
89
|
+
*
|
|
90
|
+
* @var string[]
|
|
91
|
+
*/
|
|
92
|
+
private static $allowed_styles = [
|
|
93
|
+
// Newspack.
|
|
94
|
+
'newspack-newsletters-',
|
|
95
|
+
'newspack-blocks-modal',
|
|
96
|
+
'newspack-blocks-modal-checkout',
|
|
97
|
+
'newspack-wc',
|
|
98
|
+
'newspack-ui',
|
|
99
|
+
'newspack-style',
|
|
100
|
+
'newspack-recaptcha',
|
|
101
|
+
'newspack-woocommerce-style',
|
|
102
|
+
// Woo.
|
|
103
|
+
'woocommerce',
|
|
104
|
+
'WCPAY',
|
|
105
|
+
'Woo',
|
|
106
|
+
'wc-',
|
|
107
|
+
'wc_',
|
|
108
|
+
'wcs-',
|
|
109
|
+
'stripe',
|
|
110
|
+
'select2',
|
|
111
|
+
'selectWoo',
|
|
112
|
+
// Metorik.
|
|
113
|
+
'metorik',
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Supported Payment Gateways
|
|
118
|
+
*
|
|
119
|
+
* @var string[]
|
|
120
|
+
*/
|
|
121
|
+
private static $supported_gateways = [
|
|
122
|
+
'bacs', // Direct bank transfer.
|
|
123
|
+
'cheque',
|
|
124
|
+
'cod', // Cash on delivery.
|
|
125
|
+
'ppcp-gateway', // PayPal Payments.
|
|
126
|
+
'stripe',
|
|
127
|
+
'stripe_link', // Stripe Link.
|
|
128
|
+
'stripe_amazon_pay', // Stripe Amazon Pay.
|
|
129
|
+
'woocommerce_payments',
|
|
130
|
+
'woocommerce_payments_apple_pay', // WooPayments Apple Pay.
|
|
131
|
+
'woocommerce_payments_google_pay', // WooPayments Google Pay.
|
|
132
|
+
'ppcp-axo-gateway', // PayPal Accelerated Checkout, used by WooPayments.
|
|
133
|
+
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Initialize hooks.
|
|
138
|
+
*/
|
|
139
|
+
public static function init() {
|
|
140
|
+
// Process checkout request.
|
|
141
|
+
add_action( 'wp_ajax_modal_checkout_request', [ __CLASS__, 'process_checkout_request' ] );
|
|
142
|
+
add_action( 'wp_ajax_nopriv_modal_checkout_request', [ __CLASS__, 'process_checkout_request' ] );
|
|
143
|
+
add_action( 'wp', [ __CLASS__, 'process_checkout_request' ] );
|
|
144
|
+
add_action( 'wp_ajax_abandon_modal_checkout', [ __CLASS__, 'process_abandon_checkout' ] );
|
|
145
|
+
add_action( 'wp_ajax_nopriv_abandon_modal_checkout', [ __CLASS__, 'process_abandon_checkout' ] );
|
|
146
|
+
add_action( 'wp_loaded', [ __CLASS__, 'process_checkout_action' ], 21 );
|
|
147
|
+
|
|
148
|
+
add_filter( 'wp_redirect', [ __CLASS__, 'pass_url_param_on_redirect' ] );
|
|
149
|
+
add_filter( 'woocommerce_cart_product_cannot_be_purchased_message', [ __CLASS__, 'woocommerce_cart_product_cannot_be_purchased_message' ], 10, 2 );
|
|
150
|
+
add_filter( 'woocommerce_add_error', [ __CLASS__, 'hide_expiry_message_shop_link' ] );
|
|
151
|
+
add_action( 'wp_footer', [ __CLASS__, 'render_modal_markup' ], 100 );
|
|
152
|
+
add_action( 'wp_footer', [ __CLASS__, 'render_variation_selection' ], 100 );
|
|
153
|
+
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_scripts' ] );
|
|
154
|
+
add_filter( 'show_admin_bar', [ __CLASS__, 'show_admin_bar' ] ); // phpcs:ignore WordPressVIPMinimum.UserExperience.AdminBarRemoval.RemovalDetected
|
|
155
|
+
add_action( 'template_include', [ __CLASS__, 'get_checkout_template' ] );
|
|
156
|
+
add_filter( 'woocommerce_get_return_url', [ __CLASS__, 'woocommerce_get_return_url' ], 10, 2 );
|
|
157
|
+
add_filter( 'woocommerce_get_checkout_order_received_url', [ __CLASS__, 'woocommerce_get_return_url' ], 10, 2 );
|
|
158
|
+
add_filter( 'wc_get_template', [ __CLASS__, 'wc_get_template' ], 10, 2 );
|
|
159
|
+
add_filter( 'woocommerce_checkout_fields', [ __CLASS__, 'woocommerce_checkout_fields' ] );
|
|
160
|
+
add_filter( 'woocommerce_update_order_review_fragments', [ __CLASS__, 'order_review_fragments' ] );
|
|
161
|
+
add_filter( 'woocommerce_cart_needs_payment', [ __CLASS__, 'cart_needs_payment' ] );
|
|
162
|
+
add_filter( 'newspack_recaptcha_verify_captcha', [ __CLASS__, 'recaptcha_verify_captcha' ], 10, 3 );
|
|
163
|
+
add_filter( 'woocommerce_enqueue_styles', [ __CLASS__, 'dequeue_woocommerce_styles' ] );
|
|
164
|
+
add_filter( 'wcs_place_subscription_order_text', [ __CLASS__, 'order_button_text' ], 5 );
|
|
165
|
+
add_filter( 'woocommerce_order_button_text', [ __CLASS__, 'order_button_text' ], 5 );
|
|
166
|
+
add_filter( 'option_woocommerce_subscriptions_order_button_text', [ __CLASS__, 'order_button_text' ], 5 );
|
|
167
|
+
add_action( 'woocommerce_before_checkout_form', [ __CLASS__, 'render_before_checkout_form' ] );
|
|
168
|
+
add_action( 'woocommerce_before_checkout_form', [ __CLASS__, 'render_name_your_price_form' ], 11 );
|
|
169
|
+
add_action( 'woocommerce_checkout_before_customer_details', [ __CLASS__, 'render_before_customer_details' ] );
|
|
170
|
+
add_filter( 'woocommerce_enable_order_notes_field', [ __CLASS__, 'enable_order_notes_field' ] );
|
|
171
|
+
add_action( 'woocommerce_checkout_process', [ __CLASS__, 'wcsg_apply_gift_subscription' ] );
|
|
172
|
+
add_filter( 'woocommerce_order_received_verify_known_shoppers', '__return_false' );
|
|
173
|
+
add_filter( 'woocommerce_order_button_html', [ __CLASS__, 'order_button_html' ], 10, 1 );
|
|
174
|
+
add_action( 'option_woocommerce_default_customer_address', [ __CLASS__, 'ensure_base_default_customer_address' ] );
|
|
175
|
+
add_action( 'default_option_woocommerce_default_customer_address', [ __CLASS__, 'ensure_base_default_customer_address' ] );
|
|
176
|
+
add_action( 'wp_ajax_process_name_your_price_request', [ __CLASS__, 'process_name_your_price_request' ] );
|
|
177
|
+
add_action( 'wp_ajax_nopriv_process_name_your_price_request', [ __CLASS__, 'process_name_your_price_request' ] );
|
|
178
|
+
add_filter( 'option_woocommerce_woocommerce_payments_settings', [ __CLASS__, 'filter_woocommerce_payments_settings' ] );
|
|
179
|
+
add_action( 'init', [ __CLASS__, 'unhook_woocommerce_payments_update_billing_fields' ] );
|
|
180
|
+
add_action( 'init', [ __CLASS__, 'unhook_woocommerce_payments_express_checkout_buttons' ], 20 );
|
|
181
|
+
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'update_password_strength_message' ], 9999 );
|
|
182
|
+
add_filter( 'woocommerce_enforce_password_strength_meter_on_checkout', '__return_true' );
|
|
183
|
+
|
|
184
|
+
/** Custom handling for registered users. */
|
|
185
|
+
add_filter( 'woocommerce_checkout_customer_id', [ __CLASS__, 'associate_existing_user' ] );
|
|
186
|
+
add_action( 'woocommerce_after_checkout_validation', [ __CLASS__, 'maybe_reset_checkout_registration_flag' ], 10, 2 );
|
|
187
|
+
add_filter( 'woocommerce_checkout_posted_data', [ __CLASS__, 'skip_account_creation' ], 11 );
|
|
188
|
+
add_action( 'woocommerce_checkout_create_order', [ __CLASS__, 'maybe_add_checkout_registration_order_meta' ], 10, 1 );
|
|
189
|
+
add_action( 'newpack_blocks_modal_checkout_thankyou', [ __CLASS__, 'reset_checkout_registration_flag' ] );
|
|
190
|
+
|
|
191
|
+
// Remove some stuff from the modal checkout page. It's displayed in an iframe, so it should not be treated as a separate page.
|
|
192
|
+
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'dequeue_scripts' ], PHP_INT_MAX );
|
|
193
|
+
add_filter( 'newspack_reader_activation_should_render_auth', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
194
|
+
add_filter( 'newspack_enqueue_reader_activation_block', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
195
|
+
add_filter( 'newspack_enqueue_memberships_block_patterns', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
196
|
+
add_filter( 'newspack_ads_should_show_ads', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
197
|
+
add_filter( 'newspack_theme_enqueue_js', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
198
|
+
add_filter( 'newspack_theme_enqueue_print_styles', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
199
|
+
add_filter( 'cmplz_site_needs_cookiewarning', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
200
|
+
add_filter( 'googlesitekit_adsense_tag_blocked', [ __CLASS__, 'is_modal_checkout' ] );
|
|
201
|
+
add_filter( 'jetpack_active_modules', [ __CLASS__, 'jetpack_active_modules' ] );
|
|
202
|
+
add_filter( 'woocommerce_checkout_update_order_review_expired', [ __CLASS__, 'is_not_modal_checkout_filter' ] );
|
|
203
|
+
add_filter( 'woocommerce_checkout_registration_enabled', [ __CLASS__, 'is_modal_checkout_filter' ] );
|
|
204
|
+
|
|
205
|
+
// Make the current cart price available to the JavaScript.
|
|
206
|
+
add_action( 'wp_ajax_get_cart_total', [ __CLASS__, 'get_cart_total_js' ] );
|
|
207
|
+
add_action( 'wp_ajax_nopriv_get_cart_total', [ __CLASS__, 'get_cart_total_js' ] );
|
|
208
|
+
|
|
209
|
+
// Wrap required checkbox text in a span so it works nicely with the Newspack UI grid layout.
|
|
210
|
+
add_filter( 'woocommerce_form_field_checkbox', [ __CLASS__, 'wrap_required_checkbox_text' ], 10, 4 );
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Ensure that options to limit the number of subscriptions per product are respected.
|
|
214
|
+
* Note: This is normally called only for regular checkout pages and REST API requests,
|
|
215
|
+
* so we need to add the filters for modal checkout.
|
|
216
|
+
*
|
|
217
|
+
* See: https://github.com/Automattic/woocommerce-subscriptions-core/blob/trunk/includes/class-wcs-limiter.php#L23
|
|
218
|
+
*/
|
|
219
|
+
if ( self::is_modal_checkout() && class_exists( 'WCS_Limiter' ) ) {
|
|
220
|
+
add_filter( 'woocommerce_subscription_is_purchasable', [ 'WCS_Limiter', 'is_purchasable_switch' ], 12, 2 );
|
|
221
|
+
add_filter( 'woocommerce_subscription_variation_is_purchasable', [ 'WCS_Limiter', 'is_purchasable_switch' ], 12, 2 );
|
|
222
|
+
add_filter( 'woocommerce_subscription_is_purchasable', [ 'WCS_Limiter', 'is_purchasable_renewal' ], 12, 2 );
|
|
223
|
+
add_filter( 'woocommerce_subscription_variation_is_purchasable', [ 'WCS_Limiter', 'is_purchasable_renewal' ], 12, 2 );
|
|
224
|
+
add_filter( 'woocommerce_valid_order_statuses_for_order_again', [ 'WCS_Limiter', 'filter_order_again_statuses_for_limited_subscriptions' ] );
|
|
225
|
+
}
|
|
226
|
+
add_filter( 'woocommerce_subscriptions_product_limited_for_user', [ __CLASS__, 'subscriptions_product_limited_for_user' ], 10, 3 );
|
|
227
|
+
add_filter( 'woocommerce_get_privacy_policy_text', [ __CLASS__, 'woocommerce_get_privacy_policy_text' ], 10, 2 );
|
|
228
|
+
|
|
229
|
+
// Remove any hooks that aren't supported by the modal checkout.
|
|
230
|
+
add_action( 'wp_loaded', [ __CLASS__, 'remove_hooks' ] );
|
|
231
|
+
|
|
232
|
+
// Exclude the modal checkout from 'Coming Soon' mode.
|
|
233
|
+
add_action( 'plugins_loaded', [ __CLASS__, 'disable_coming_soon' ] );
|
|
234
|
+
add_filter( 'woocommerce_coming_soon_exclude', [ __CLASS__, 'disable_coming_soon' ] );
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Add information about modal checkout to cart item data.
|
|
239
|
+
*
|
|
240
|
+
* @param array $cart_item_data Cart item data.
|
|
241
|
+
*/
|
|
242
|
+
public static function amend_cart_item_data( $cart_item_data ) {
|
|
243
|
+
if ( self::is_modal_checkout() ) {
|
|
244
|
+
$cart_item_data['newspack_modal_checkout_url'] = \home_url( \add_query_arg( null, null ) );
|
|
245
|
+
}
|
|
246
|
+
return $cart_item_data;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Dequeue WC styles if on modal checkout.
|
|
251
|
+
*
|
|
252
|
+
* @param array $enqueue_styles Array of styles to enqueue.
|
|
253
|
+
*/
|
|
254
|
+
public static function dequeue_woocommerce_styles( $enqueue_styles ) {
|
|
255
|
+
if ( ! self::is_modal_checkout() ) {
|
|
256
|
+
return $enqueue_styles;
|
|
257
|
+
}
|
|
258
|
+
unset( $enqueue_styles['woocommerce-general'] );
|
|
259
|
+
unset( $enqueue_styles['woocommerce-smallscreen'] );
|
|
260
|
+
return $enqueue_styles;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get list of supported payment gateways for Modal Checkout.
|
|
265
|
+
*
|
|
266
|
+
* @return string[] Supported payment gateways.
|
|
267
|
+
*/
|
|
268
|
+
public static function get_supported_payment_gateways() {
|
|
269
|
+
/**
|
|
270
|
+
* Filters the list of supported gateways in modal checkout.
|
|
271
|
+
*
|
|
272
|
+
* @param array $supported_gateways
|
|
273
|
+
*/
|
|
274
|
+
return apply_filters( 'newspack_blocks_modal_checkout_supported_gateways', self::$supported_gateways );
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Whether any enabled payment gateways are not supported in modal checkout.
|
|
279
|
+
*
|
|
280
|
+
* @return bool
|
|
281
|
+
*/
|
|
282
|
+
public static function has_unsupported_payment_gateway() {
|
|
283
|
+
if ( ! function_exists( 'WC' ) ) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
$supported_gateways = self::get_supported_payment_gateways();
|
|
288
|
+
$all_gateways = \WC()->payment_gateways()->payment_gateways();
|
|
289
|
+
|
|
290
|
+
// Check unsupported gateways directly against admin settings. Some gateways
|
|
291
|
+
// can be omitted from runtime availability due to constraints (like Wompi).
|
|
292
|
+
foreach ( array_keys( $all_gateways ) as $id ) {
|
|
293
|
+
if ( in_array( $id, $supported_gateways, true ) ) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
$settings = get_option( 'woocommerce_' . $id . '_settings', [] );
|
|
297
|
+
if ( is_array( $settings ) && isset( $settings['enabled'] ) && 'yes' === $settings['enabled'] ) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Process checkout handler for form validation and order complete.
|
|
307
|
+
*/
|
|
308
|
+
public static function process_checkout_action() {
|
|
309
|
+
if ( ! self::is_modal_checkout() || ! isset( $_POST['newspack_blocks_checkout_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
$nonce = isset( $_POST['newspack_checkout_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['newspack_checkout_nonce'] ) ) : '';
|
|
314
|
+
if ( ! wp_verify_nonce( $nonce, 'newspack_modal_checkout_nonce' ) ) {
|
|
315
|
+
wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'newspack-blocks' ) ] );
|
|
316
|
+
wp_die();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
wc_nocache_headers();
|
|
320
|
+
|
|
321
|
+
if ( \WC()->cart->is_empty() ) {
|
|
322
|
+
wp_safe_redirect( wc_get_cart_url() );
|
|
323
|
+
exit;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// If checkout is already defined as being processed, don't run process_checkout().
|
|
327
|
+
if ( defined( 'WOOCOMMERCE_CHECKOUT' ) && WOOCOMMERCE_CHECKOUT ) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
|
|
332
|
+
|
|
333
|
+
// Generate a fresh WC nonce so process_checkout() passes its internal verification.
|
|
334
|
+
// We take this approach to ensure compatibility with block theme which causes WC to no longer
|
|
335
|
+
// rely on this checkout nonce requried by process checkout.
|
|
336
|
+
$_REQUEST['woocommerce-process-checkout-nonce'] = wp_create_nonce( 'woocommerce-process_checkout' );
|
|
337
|
+
|
|
338
|
+
// If this is a validation-only request, set the flag that tells process_checkout() to only validate the order.
|
|
339
|
+
if ( isset( $_POST['is_validation_only'] ) ) {
|
|
340
|
+
$_POST['woocommerce_checkout_update_totals'] = '1';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
\WC()->checkout()->process_checkout();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Process checkout request for modal.
|
|
348
|
+
*/
|
|
349
|
+
public static function process_checkout_request() {
|
|
350
|
+
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
$is_newspack_checkout = filter_input( INPUT_GET, 'newspack_checkout', FILTER_SANITIZE_NUMBER_INT );
|
|
355
|
+
|
|
356
|
+
if ( ! $is_newspack_checkout ) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
$product_id = filter_input( INPUT_GET, 'product_id', FILTER_SANITIZE_NUMBER_INT );
|
|
361
|
+
$variation_id = filter_input( INPUT_GET, 'variation_id', FILTER_SANITIZE_NUMBER_INT );
|
|
362
|
+
$after_success_behavior = filter_input( INPUT_GET, 'after_success_behavior', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
363
|
+
$after_success_url = filter_input( INPUT_GET, 'after_success_url', FILTER_SANITIZE_URL );
|
|
364
|
+
$after_success_button_label = filter_input( INPUT_GET, 'after_success_button_label', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
365
|
+
|
|
366
|
+
if ( $variation_id ) {
|
|
367
|
+
$product_id = $variation_id;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if ( ! $product_id ) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
$referer = wp_get_referer();
|
|
375
|
+
$params = [];
|
|
376
|
+
$parsed_url = wp_parse_url( $referer );
|
|
377
|
+
|
|
378
|
+
// Get URL params appended to the referer URL.
|
|
379
|
+
if ( ! empty( $parsed_url['query'] ) ) {
|
|
380
|
+
wp_parse_str( $parsed_url['query'], $params );
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
$params = array_merge( $params, compact( 'after_success_behavior', 'after_success_url', 'after_success_button_label' ) );
|
|
384
|
+
|
|
385
|
+
if ( function_exists( 'wpcom_vip_url_to_postid' ) ) {
|
|
386
|
+
$referer_post_id = wpcom_vip_url_to_postid( $referer );
|
|
387
|
+
} else {
|
|
388
|
+
$referer_post_id = url_to_postid( $referer ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
$referer_tags = [];
|
|
392
|
+
$referer_categories = [];
|
|
393
|
+
$tags = get_the_tags( $referer_post_id );
|
|
394
|
+
if ( $tags && ! empty( $tags ) ) {
|
|
395
|
+
$referer_tags = array_map(
|
|
396
|
+
function ( $item ) {
|
|
397
|
+
return $item->slug;
|
|
398
|
+
},
|
|
399
|
+
$tags
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
$categories = get_the_category( $referer_post_id );
|
|
404
|
+
if ( $categories && ! empty( $categories ) ) {
|
|
405
|
+
$referer_categories = array_map(
|
|
406
|
+
function ( $item ) {
|
|
407
|
+
return $item->slug;
|
|
408
|
+
},
|
|
409
|
+
$categories
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
$cart_item_data = self::amend_cart_item_data( [ 'referer' => $referer ] );
|
|
414
|
+
|
|
415
|
+
/** Apply NYP custom price */
|
|
416
|
+
$price = filter_input( INPUT_GET, 'price', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
|
417
|
+
if ( \Newspack_Blocks::can_use_name_your_price() ? \WC_Name_Your_Price_Helpers::is_nyp( $product_id ) : false ) {
|
|
418
|
+
if ( empty( $price ) ) {
|
|
419
|
+
$price = \WC_Name_Your_Price_Helpers::get_suggested_price( $product_id );
|
|
420
|
+
}
|
|
421
|
+
$min_price = \WC_Name_Your_Price_Helpers::get_minimum_price( $product_id );
|
|
422
|
+
$max_price = \WC_Name_Your_Price_Helpers::get_maximum_price( $product_id );
|
|
423
|
+
$price = ! empty( $max_price ) ? min( $price, $max_price ) : $price;
|
|
424
|
+
$price = ! empty( $min_price ) ? max( $price, $min_price ) : $price;
|
|
425
|
+
|
|
426
|
+
$cart_item_data['nyp'] = (float) \WC_Name_Your_Price_Helpers::standardize_number( $price );
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Filters the cart item data for the modal checkout.
|
|
431
|
+
*
|
|
432
|
+
* @param array $cart_item_data Cart item data.
|
|
433
|
+
*/
|
|
434
|
+
$cart_item_data = apply_filters( 'newspack_blocks_modal_checkout_cart_item_data', $cart_item_data );
|
|
435
|
+
|
|
436
|
+
\WC()->cart->empty_cart();
|
|
437
|
+
\WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
438
|
+
|
|
439
|
+
// Set checkout registration flag if user is logged not logged in.
|
|
440
|
+
if ( ! is_user_logged_in() ) {
|
|
441
|
+
self::set_checkout_registration_flag();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
$query_args = [];
|
|
445
|
+
if ( ! empty( $referer_tags ) ) {
|
|
446
|
+
$query_args['referer_tags'] = implode( ',', $referer_tags );
|
|
447
|
+
}
|
|
448
|
+
if ( ! empty( $referer_categories ) ) {
|
|
449
|
+
$query_args['referer_categories'] = implode( ',', $referer_categories );
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if ( ! self::has_unsupported_payment_gateway() ) {
|
|
453
|
+
$query_args['modal_checkout'] = 1;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Pass through UTM and after_success params so they can be forwarded to the WooCommerce checkout flow.
|
|
457
|
+
foreach ( $params as $param => $value ) {
|
|
458
|
+
if ( 'utm' === substr( $param, 0, 3 ) || 'after_success' === substr( $param, 0, 13 ) ) {
|
|
459
|
+
if ( ! empty( $value ) ) {
|
|
460
|
+
$param = sanitize_text_field( $param );
|
|
461
|
+
$query_args[ $param ] = sanitize_text_field( $value );
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
$checkout_url = add_query_arg(
|
|
467
|
+
$query_args,
|
|
468
|
+
\wc_get_page_permalink( 'checkout' )
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
// Get data to send for this purchase.
|
|
472
|
+
$checkout_button_metadata = [
|
|
473
|
+
'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
|
|
474
|
+
'amount' => $price,
|
|
475
|
+
'product_id' => $product_id,
|
|
476
|
+
'referrer' => $referer,
|
|
477
|
+
];
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Action to fire for checkout button block modal.
|
|
481
|
+
*/
|
|
482
|
+
\do_action( 'newspack_blocks_checkout_button_modal', $checkout_button_metadata );
|
|
483
|
+
|
|
484
|
+
$checkout_url = apply_filters( 'newspack_blocks_checkout_url', $checkout_url );
|
|
485
|
+
|
|
486
|
+
if ( defined( 'DOING_AJAX' ) ) {
|
|
487
|
+
echo wp_json_encode( [ 'url' => $checkout_url ] );
|
|
488
|
+
exit;
|
|
489
|
+
} else {
|
|
490
|
+
// Redirect to checkout.
|
|
491
|
+
\wp_safe_redirect( $checkout_url );
|
|
492
|
+
exit;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Process abandon checkout for modal.
|
|
498
|
+
*/
|
|
499
|
+
public static function process_abandon_checkout() {
|
|
500
|
+
if ( ! defined( 'DOING_AJAX' ) ) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if ( ! self::is_modal_checkout() ) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if ( ! check_ajax_referer( 'newspack_modal_checkout_nonce' ) ) {
|
|
509
|
+
wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'newspack-blocks' ) ] );
|
|
510
|
+
wp_die();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
$cart = \WC()->cart;
|
|
514
|
+
if ( $cart && ! $cart->is_empty() ) {
|
|
515
|
+
$cart->empty_cart();
|
|
516
|
+
}
|
|
517
|
+
self::reset_checkout_registration_flag();
|
|
518
|
+
|
|
519
|
+
wp_send_json_success( [ 'message' => __( 'Cart has been emptied.', 'newspack-blocks' ) ] );
|
|
520
|
+
wp_die();
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Filter unsupported Woo Payments features.
|
|
525
|
+
*
|
|
526
|
+
* @param array $settings WooCommerce Payments settings.
|
|
527
|
+
*
|
|
528
|
+
* @return array Filtered WooCommerce Payments settings.
|
|
529
|
+
*/
|
|
530
|
+
public static function filter_woocommerce_payments_settings( $settings ) {
|
|
531
|
+
if ( ! self::is_modal_checkout() ) {
|
|
532
|
+
return $settings;
|
|
533
|
+
}
|
|
534
|
+
if ( isset( $settings['platform_checkout'] ) ) {
|
|
535
|
+
$settings['platform_checkout'] = 'no';
|
|
536
|
+
}
|
|
537
|
+
return $settings;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Unhook WooCommerce Payments billing fields update.
|
|
542
|
+
*
|
|
543
|
+
* The WC_Payment_Gateway_WCPay->checkout_update_email_field_priority() hook
|
|
544
|
+
* changes the position of the email address field in the checkout form and
|
|
545
|
+
* appends a broken Stripelink button to the email input.
|
|
546
|
+
*/
|
|
547
|
+
public static function unhook_woocommerce_payments_update_billing_fields() {
|
|
548
|
+
if ( ! self::is_modal_checkout() ) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if ( ! class_exists( 'WC_Payments' ) ) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
$gateway = \WC_Payments::get_gateway();
|
|
555
|
+
if ( ! $gateway ) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
$filters = $GLOBALS['wp_filter']['woocommerce_billing_fields'];
|
|
559
|
+
foreach ( $filters as $index => $filter ) {
|
|
560
|
+
$keys = array_keys( $filter );
|
|
561
|
+
foreach ( $keys as $key ) {
|
|
562
|
+
if ( strpos( $key, 'checkout_update_email_field_priority' ) !== false ) {
|
|
563
|
+
remove_filter( 'woocommerce_billing_fields', $key, $index );
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Unhook WooCommerce Payments' express checkout buttons during modal checkout.
|
|
571
|
+
*
|
|
572
|
+
* WooPayments 10.4 split Apple Pay / Google Pay into separate gateways. The display
|
|
573
|
+
* handler attaches display_express_checkout_buttons to woocommerce_checkout_before_customer_details
|
|
574
|
+
* at init priority 15; when Stripe's express checkout is also active the modal renders
|
|
575
|
+
* duplicate Apple Pay / Google Pay rows. Removing the hook here suppresses WooPayments'
|
|
576
|
+
* buttons while leaving Stripe's intact. Hooked on init at priority 20 so WooPayments'
|
|
577
|
+
* init callback has already attached its actions.
|
|
578
|
+
*/
|
|
579
|
+
public static function unhook_woocommerce_payments_express_checkout_buttons() {
|
|
580
|
+
if ( ! self::is_modal_checkout() ) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
if ( ! class_exists( 'WC_Payments' ) || ! class_exists( 'WC_Stripe' ) ) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
// Only suppress WooPayments when Stripe is also providing express checkout. Otherwise
|
|
587
|
+
// WooPayments is the only source of Apple Pay / Google Pay in the modal and must render.
|
|
588
|
+
$stripe_settings = get_option( 'woocommerce_stripe_settings', [] );
|
|
589
|
+
if ( 'yes' !== ( $stripe_settings['enabled'] ?? '' )
|
|
590
|
+
|| 'yes' !== ( $stripe_settings['express_checkout'] ?? '' ) ) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if ( ! isset( $GLOBALS['wp_filter']['woocommerce_checkout_before_customer_details'] ) ) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
$hook = $GLOBALS['wp_filter']['woocommerce_checkout_before_customer_details'];
|
|
597
|
+
$callbacks = $hook instanceof \WP_Hook ? $hook->callbacks : (array) $hook;
|
|
598
|
+
foreach ( $callbacks as $priority => $priority_callbacks ) {
|
|
599
|
+
foreach ( array_keys( $priority_callbacks ) as $key ) {
|
|
600
|
+
if ( strpos( $key, 'display_express_checkout_buttons' ) !== false ) {
|
|
601
|
+
remove_action( 'woocommerce_checkout_before_customer_details', $key, $priority );
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Process name your price request for modal.
|
|
609
|
+
*/
|
|
610
|
+
public static function process_name_your_price_request() {
|
|
611
|
+
if ( ! defined( 'DOING_AJAX' ) ) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if ( ! function_exists( 'WC' ) || ! \Newspack_Blocks::can_use_name_your_price() || ! method_exists( '\WC_Name_Your_Price_Helpers', 'is_nyp' ) ) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
check_ajax_referer( 'newspack_checkout_name_your_price' );
|
|
620
|
+
|
|
621
|
+
$is_newspack_checkout_nyp = filter_input( INPUT_POST, 'newspack_checkout_name_your_price', FILTER_SANITIZE_NUMBER_INT );
|
|
622
|
+
$product_id = filter_input( INPUT_POST, 'product_id', FILTER_SANITIZE_NUMBER_INT );
|
|
623
|
+
|
|
624
|
+
if ( ! $is_newspack_checkout_nyp || ! $product_id ) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
$price = \WC_Name_Your_Price_Helpers::standardize_number( filter_input( INPUT_POST, 'price', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION ) );
|
|
629
|
+
$max_price = \WC_Name_Your_Price_Helpers::get_maximum_price( $product_id );
|
|
630
|
+
|
|
631
|
+
if ( ! empty( $max_price ) && $price > $max_price ) {
|
|
632
|
+
wp_send_json_error(
|
|
633
|
+
[
|
|
634
|
+
'message' => sprintf(
|
|
635
|
+
// Translators: %s is the maximum price.
|
|
636
|
+
__( 'Adjusted price must be less than the maximum of %s.', 'newspack-blocks' ),
|
|
637
|
+
\wc_price( $max_price )
|
|
638
|
+
),
|
|
639
|
+
]
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
wp_die();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
$cart_item_data = self::amend_cart_item_data( [ 'referer' => wp_get_referer() ] );
|
|
646
|
+
|
|
647
|
+
foreach ( \WC()->cart->get_cart() as $cart_item_key => $cart_item ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
|
648
|
+
if ( $cart_item['product_id'] !== (int) $product_id && $cart_item['variation_id'] !== (int) $product_id ) {
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
$cart_item_data['nyp'] = $price;
|
|
653
|
+
$cart_item_data['base_price'] = isset( $cart_item['base_price'] ) ? $cart_item['base_price'] : $cart_item['nyp'];
|
|
654
|
+
|
|
655
|
+
if ( $price < $cart_item_data['base_price'] ) {
|
|
656
|
+
wp_send_json_error(
|
|
657
|
+
[
|
|
658
|
+
'message' => sprintf(
|
|
659
|
+
// Translators: %s is the name-your-price custom price.
|
|
660
|
+
__( 'Adjusted price must be greater than base price of %s.', 'newspack-blocks' ),
|
|
661
|
+
\wc_price( $cart_item_data['base_price'] )
|
|
662
|
+
),
|
|
663
|
+
]
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
wp_die();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
$coupons = \WC()->cart->get_applied_coupons();
|
|
671
|
+
|
|
672
|
+
\WC()->cart->empty_cart();
|
|
673
|
+
\WC()->cart->add_to_cart( $product_id, 1, 0, [], $cart_item_data );
|
|
674
|
+
|
|
675
|
+
if ( ! empty( $coupons ) ) {
|
|
676
|
+
foreach ( $coupons as $coupon ) {
|
|
677
|
+
\WC()->cart->apply_coupon( $coupon );
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
wp_send_json_success(
|
|
682
|
+
[
|
|
683
|
+
'message' => self::get_modal_checkout_labels( 'checkout_nyp_thankyou' ),
|
|
684
|
+
'price' => \wc_price( $price ),
|
|
685
|
+
]
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
wp_die();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Render the markup necessary for the modal checkout.
|
|
693
|
+
*/
|
|
694
|
+
public static function render_modal_markup() {
|
|
695
|
+
if ( ! self::$has_modal ) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Filters the header title for the modal checkout.
|
|
700
|
+
*
|
|
701
|
+
* @param string $title The title.
|
|
702
|
+
*/
|
|
703
|
+
$title = self::get_modal_checkout_labels( 'checkout_modal_title' );
|
|
704
|
+
$class_prefix = self::get_class_prefix();
|
|
705
|
+
?>
|
|
706
|
+
<div id="newspack_modal_checkout" class="<?php echo esc_attr( "$class_prefix {$class_prefix}__modal-container" ); ?>">
|
|
707
|
+
<div class="<?php echo esc_attr( "{$class_prefix}__modal-container__overlay" ); ?>"></div>
|
|
708
|
+
<div class="<?php echo esc_attr( "{$class_prefix}__modal" ); ?>" role="dialog" aria-modal="true" aria-labelledby="newspack-modal-checkout-label">
|
|
709
|
+
<header class="<?php echo esc_attr( "{$class_prefix}__modal__header" ); ?>">
|
|
710
|
+
<h2 id="newspack-modal-checkout-label"><?php echo esc_html( $title ); ?></h2>
|
|
711
|
+
<button class="<?php echo esc_attr( "{$class_prefix}__button {$class_prefix}__button--icon {$class_prefix}__button--ghost {$class_prefix}__modal__close" ); ?>">
|
|
712
|
+
<span class="screen-reader-text"><?php esc_html_e( 'Close', 'newspack-blocks' ); ?></span>
|
|
713
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">
|
|
714
|
+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
|
|
715
|
+
</svg>
|
|
716
|
+
</button>
|
|
717
|
+
</header>
|
|
718
|
+
<section class="<?php echo esc_attr( "{$class_prefix}__modal__content" ); ?>">
|
|
719
|
+
<div class="<?php echo esc_attr( "{$class_prefix}__spinner" ); ?>">
|
|
720
|
+
<span></span>
|
|
721
|
+
</div>
|
|
722
|
+
</section>
|
|
723
|
+
<?php
|
|
724
|
+
// Hacky way to help trap focus in the modal for accessibility, without involving the iframe.
|
|
725
|
+
echo '<span tabindex="0" id="newspack-a11y-last-element"></span>';
|
|
726
|
+
?>
|
|
727
|
+
</div>
|
|
728
|
+
</div>
|
|
729
|
+
<?php
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Update product price string for subscriptions to use "per" instead of "/".
|
|
734
|
+
*
|
|
735
|
+
* @param string $price_string The price string.
|
|
736
|
+
*/
|
|
737
|
+
public static function update_subscriptions_product_price_string( $price_string ) {
|
|
738
|
+
$price_string = str_replace( ' / ', ' ' . __( 'per', 'newspack-blocks' ) . ' ', $price_string );
|
|
739
|
+
return $price_string;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Update price to remove empty decimals (.00) if over three digits.
|
|
744
|
+
*
|
|
745
|
+
* @param string $price_string The price string.
|
|
746
|
+
*/
|
|
747
|
+
public static function maybe_remove_decimal_spaces( $price_string ) {
|
|
748
|
+
$decimal_separator = wc_get_price_decimal_separator();
|
|
749
|
+
$pattern = '/\b\d{3,}' . preg_quote( $decimal_separator, '/' ) . '00\b/';
|
|
750
|
+
preg_match( $pattern, $price_string, $matches );
|
|
751
|
+
if ( ! empty( $matches ) ) {
|
|
752
|
+
$replace_pattern = '/' . preg_quote( $decimal_separator, '/' ) . '00$/';
|
|
753
|
+
$price_string = preg_replace( $pattern, preg_replace( $replace_pattern, '', $matches[0] ), $price_string );
|
|
754
|
+
}
|
|
755
|
+
return $price_string;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Render variation selection modal for variable products.
|
|
760
|
+
*/
|
|
761
|
+
public static function render_variation_selection() {
|
|
762
|
+
if ( ! function_exists( 'WC' ) ) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if ( ! class_exists( 'Newspack\Subscriptions_Tiers' ) || ! method_exists( 'Newspack\Subscriptions_Tiers', 'render_form' ) ) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
add_filter( 'woocommerce_subscriptions_product_price_string', [ __CLASS__, 'update_subscriptions_product_price_string' ], 10, 1 );
|
|
770
|
+
add_filter( 'formatted_woocommerce_price', [ __CLASS__, 'maybe_remove_decimal_spaces' ], 10, 1 );
|
|
771
|
+
/**
|
|
772
|
+
* Filters the header title for the modal checkout.
|
|
773
|
+
*
|
|
774
|
+
* @param string $title The title.
|
|
775
|
+
*/
|
|
776
|
+
$title = self::get_modal_checkout_labels( 'variation_modal_title' );
|
|
777
|
+
$products = array_keys( self::$products );
|
|
778
|
+
$class_prefix = self::get_class_prefix();
|
|
779
|
+
|
|
780
|
+
$products = array_keys( self::$products );
|
|
781
|
+
foreach ( $products as $product_id ) {
|
|
782
|
+
$product = wc_get_product( $product_id );
|
|
783
|
+
if ( ! $product || ( ! $product->is_type( 'variable' ) && ! $product->is_type( 'grouped' ) ) ) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
?>
|
|
787
|
+
<div
|
|
788
|
+
class="<?php echo esc_attr( "$class_prefix {$class_prefix}__modal-container newspack-blocks__modal-variation" ); ?>"
|
|
789
|
+
data-product-id="<?php echo esc_attr( $product_id ); ?>"
|
|
790
|
+
>
|
|
791
|
+
<div class="<?php echo esc_attr( "{$class_prefix}__modal-container__overlay" ); ?>"></div>
|
|
792
|
+
<div class="<?php echo esc_attr( "{$class_prefix}__modal {$class_prefix}__modal--small" ); ?>" role="dialog" aria-modal="true" aria-labelledby="newspack-modal-checkout-label">
|
|
793
|
+
<header class="<?php echo esc_attr( "{$class_prefix}__modal__header" ); ?>">
|
|
794
|
+
<h2 id="newspack-modal-checkout-label"><?php echo esc_html( $title ); ?></h2>
|
|
795
|
+
<button class="<?php echo esc_attr( "{$class_prefix}__button {$class_prefix}__button--icon {$class_prefix}__button--ghost {$class_prefix}__modal__close" ); ?>">
|
|
796
|
+
<span class="screen-reader-text"><?php esc_html_e( 'Close', 'newspack-blocks' ); ?></span>
|
|
797
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">
|
|
798
|
+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
|
|
799
|
+
</svg>
|
|
800
|
+
</button>
|
|
801
|
+
</header>
|
|
802
|
+
<section class="<?php echo esc_attr( "{$class_prefix}__modal__content" ); ?>">
|
|
803
|
+
<?php \Newspack\Subscriptions_Tiers::render_form( $product ); ?>
|
|
804
|
+
</section>
|
|
805
|
+
</div>
|
|
806
|
+
</div>
|
|
807
|
+
<?php
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Enqueue scripts for the checkout page rendered in a modal.
|
|
813
|
+
*/
|
|
814
|
+
public static function enqueue_scripts() {
|
|
815
|
+
if (
|
|
816
|
+
( ! function_exists( 'is_checkout' ) || ! is_checkout() ) &&
|
|
817
|
+
( ! function_exists( 'is_cart' ) || ! is_cart() ) &&
|
|
818
|
+
( ! function_exists( 'is_order_received_page' ) || ! is_order_received_page() )
|
|
819
|
+
) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if ( ! self::is_modal_checkout() ) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
$dependencies = [ 'jquery', 'wc-checkout' ];
|
|
828
|
+
// Add support reCAPTCHA dependencies, if connected.
|
|
829
|
+
if ( class_exists( 'Newspack\Recaptcha' ) && \Newspack\Recaptcha::can_use_captcha() ) {
|
|
830
|
+
$dependencies[] = \Newspack\Recaptcha::SCRIPT_HANDLE;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
wp_enqueue_script(
|
|
834
|
+
'newspack-blocks-modal-checkout',
|
|
835
|
+
plugins_url( 'dist/modalCheckout.js', \NEWSPACK_BLOCKS__PLUGIN_FILE ),
|
|
836
|
+
$dependencies,
|
|
837
|
+
\NEWSPACK_BLOCKS__VERSION,
|
|
838
|
+
[
|
|
839
|
+
'strategy' => 'async',
|
|
840
|
+
'in_footer' => true,
|
|
841
|
+
]
|
|
842
|
+
);
|
|
843
|
+
wp_localize_script(
|
|
844
|
+
'newspack-blocks-modal-checkout',
|
|
845
|
+
'newspackBlocksModalCheckout',
|
|
846
|
+
[
|
|
847
|
+
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
|
848
|
+
'nyp_nonce' => wp_create_nonce( 'newspack_checkout_name_your_price' ),
|
|
849
|
+
'checkout_nonce' => wp_create_nonce( 'newspack_modal_checkout_nonce' ),
|
|
850
|
+
'newspack_class_prefix' => self::get_class_prefix(),
|
|
851
|
+
'is_checkout_complete' => function_exists( 'is_order_received_page' ) && is_order_received_page(),
|
|
852
|
+
'divider_text' => esc_html__( 'Or', 'newspack-blocks' ),
|
|
853
|
+
'is_error' => ! is_checkout() && ! is_order_received_page(),
|
|
854
|
+
'labels' => [
|
|
855
|
+
'billing_details' => self::get_modal_checkout_labels( 'billing_details' ),
|
|
856
|
+
'shipping_details' => self::get_modal_checkout_labels( 'shipping_details' ),
|
|
857
|
+
'gift_recipient' => self::get_modal_checkout_labels( 'gift_recipient' ),
|
|
858
|
+
'critical_error' => self::get_modal_checkout_labels( 'checkout_critical_error' ),
|
|
859
|
+
'complete_button' => self::order_button_text_with_price(),
|
|
860
|
+
],
|
|
861
|
+
]
|
|
862
|
+
);
|
|
863
|
+
wp_enqueue_style(
|
|
864
|
+
'newspack-blocks-modal-checkout',
|
|
865
|
+
plugins_url( 'dist/modalCheckout.css', \NEWSPACK_BLOCKS__PLUGIN_FILE ),
|
|
866
|
+
[],
|
|
867
|
+
\NEWSPACK_BLOCKS__VERSION
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* Dequeue scripts not needed in the modal checkout.
|
|
873
|
+
*/
|
|
874
|
+
public static function dequeue_scripts() {
|
|
875
|
+
/**
|
|
876
|
+
* Prevents dequeuing of scripts in modal checkout. By default,
|
|
877
|
+
* Newspack removes unnecessary scripts to improve modal checkout performance.
|
|
878
|
+
*
|
|
879
|
+
* @constant NEWSPACK_ALLOW_ALL_CHECKOUT_SCRIPTS
|
|
880
|
+
* @type bool
|
|
881
|
+
* @default Unnecessary scripts dequeued in modal checkout
|
|
882
|
+
* @status draft
|
|
883
|
+
*
|
|
884
|
+
* @example define( 'NEWSPACK_ALLOW_ALL_CHECKOUT_SCRIPTS', true );
|
|
885
|
+
*/
|
|
886
|
+
if (
|
|
887
|
+
! self::is_modal_checkout() ||
|
|
888
|
+
( defined( 'NEWSPACK_ALLOW_ALL_CHECKOUT_SCRIPTS' ) && NEWSPACK_ALLOW_ALL_CHECKOUT_SCRIPTS )
|
|
889
|
+
) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
global $wp_scripts, $wp_styles;
|
|
894
|
+
|
|
895
|
+
$payment_gateways = \WC()->payment_gateways->get_available_payment_gateways();
|
|
896
|
+
$allowed_gateway_assets = [];
|
|
897
|
+
if ( ! empty( $payment_gateways ) ) {
|
|
898
|
+
foreach ( array_keys( $payment_gateways ) as $gateway ) {
|
|
899
|
+
$class = get_class( $payment_gateways[ $gateway ] );
|
|
900
|
+
$plugin_file = ( new \ReflectionClass( $class ) )->getFileName();
|
|
901
|
+
$plugin_base = \plugin_basename( $plugin_file );
|
|
902
|
+
$plugin_slug = explode( '/', $plugin_base )[0];
|
|
903
|
+
$allowed_gateway_assets[] = $plugin_slug;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Filters the allowed styles to render in the modal checkout
|
|
909
|
+
*
|
|
910
|
+
* @param string[] $allowed_styles Array of allowed assets handles.
|
|
911
|
+
*/
|
|
912
|
+
$allowed_styles = apply_filters( 'newspack_blocks_modal_checkout_allowed_styles', self::$allowed_styles );
|
|
913
|
+
foreach ( $wp_styles->registered as $handle => $wp_style ) {
|
|
914
|
+
$allowed = false;
|
|
915
|
+
foreach ( $allowed_styles as $allowed_style ) {
|
|
916
|
+
if ( 0 === strpos( $handle, $allowed_style ) ) {
|
|
917
|
+
$allowed = true;
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if ( ! empty( $payment_gateways ) ) {
|
|
922
|
+
foreach ( $allowed_gateway_assets as $gateway ) {
|
|
923
|
+
if ( false !== strpos( $wp_style->src, $gateway ) ) {
|
|
924
|
+
$allowed = true;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if ( ! $allowed ) {
|
|
930
|
+
wp_dequeue_style( $handle );
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Filters the allowed scripts to render in the modal checkout
|
|
936
|
+
*
|
|
937
|
+
* @param string[] $allowed_scripts Array of allowed assets handles.
|
|
938
|
+
*/
|
|
939
|
+
$allowed_scripts = apply_filters( 'newspack_blocks_modal_checkout_allowed_scripts', self::$allowed_scripts );
|
|
940
|
+
foreach ( $wp_scripts->registered as $handle => $wp_script ) {
|
|
941
|
+
$allowed = false;
|
|
942
|
+
foreach ( $allowed_scripts as $allowed_script ) {
|
|
943
|
+
if ( 0 === strpos( $handle, $allowed_script ) ) {
|
|
944
|
+
$allowed = true;
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
foreach ( $allowed_gateway_assets as $gateway ) {
|
|
949
|
+
if ( $wp_script->src !== null && false !== strpos( $wp_script->src, $gateway ) ) {
|
|
950
|
+
$allowed = true;
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
if ( ! $allowed ) {
|
|
955
|
+
wp_dequeue_script( $handle );
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Remove any hooks that may not work nicely with the modal checkout.
|
|
962
|
+
*/
|
|
963
|
+
public static function remove_hooks() {
|
|
964
|
+
if ( ! self::is_modal_checkout() ) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
$remove_list = [];
|
|
969
|
+
|
|
970
|
+
// reCaptcha for WooCommerce.
|
|
971
|
+
if ( class_exists( 'I13_Woo_Recpatcha' ) ) {
|
|
972
|
+
global $i13_woo_recpatcha;
|
|
973
|
+
array_push(
|
|
974
|
+
$remove_list,
|
|
975
|
+
[
|
|
976
|
+
'hook' => 'woocommerce_review_order_before_payment',
|
|
977
|
+
'callback' => array( $i13_woo_recpatcha, 'i13woo_extra_checkout_fields' ),
|
|
978
|
+
],
|
|
979
|
+
[
|
|
980
|
+
'hook' => 'woocommerce_after_checkout_validation',
|
|
981
|
+
'callback' => array( $i13_woo_recpatcha, 'i13_woocomm_validate_checkout_captcha' ),
|
|
982
|
+
],
|
|
983
|
+
[
|
|
984
|
+
'hook' => 'woocommerce_pay_order_before_submit',
|
|
985
|
+
'callback' => array( $i13_woo_recpatcha, 'i13woo_extra_checkout_fields' ),
|
|
986
|
+
],
|
|
987
|
+
[
|
|
988
|
+
'hook' => 'woocommerce_review_order_before_submit',
|
|
989
|
+
'callback' => array( $i13_woo_recpatcha, 'i13woo_extra_checkout_fields' ),
|
|
990
|
+
],
|
|
991
|
+
[
|
|
992
|
+
'hook' => 'woocommerce_pay_order_before_submit',
|
|
993
|
+
'callback' => array( $i13_woo_recpatcha, 'i13woo_extra_checkout_fields_pay_order' ),
|
|
994
|
+
],
|
|
995
|
+
[
|
|
996
|
+
'hook' => 'woocommerce_proceed_to_checkout',
|
|
997
|
+
'callback' => array( $i13_woo_recpatcha, 'i13_woocommerce_payment_request_btn_captcha' ),
|
|
998
|
+
],
|
|
999
|
+
[
|
|
1000
|
+
'hook' => 'wp_head',
|
|
1001
|
+
'callback' => array( $i13_woo_recpatcha, 'i13_add_header_metadata' ),
|
|
1002
|
+
]
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
// OneSignal.
|
|
1006
|
+
if ( class_exists( 'OneSignal_Public' ) ) {
|
|
1007
|
+
array_push(
|
|
1008
|
+
$remove_list,
|
|
1009
|
+
[
|
|
1010
|
+
'hook' => 'wp_head',
|
|
1011
|
+
'callback' => 'onesignal_init', // V3.
|
|
1012
|
+
],
|
|
1013
|
+
[
|
|
1014
|
+
'hook' => 'wp_head',
|
|
1015
|
+
'callback' => array( 'OneSignal_Public', 'onesignal_header' ), // V2.
|
|
1016
|
+
]
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Filters the hooks to remove from the modal checkout.
|
|
1022
|
+
*
|
|
1023
|
+
* @param string[] $remove_list Array of hooks to remove.
|
|
1024
|
+
*/
|
|
1025
|
+
$remove_list = apply_filters( 'newspack_blocks_modal_checkout_remove_hooks', $remove_list );
|
|
1026
|
+
|
|
1027
|
+
foreach ( $remove_list as $remove ) {
|
|
1028
|
+
$priority = has_action( $remove['hook'], $remove['callback'] );
|
|
1029
|
+
remove_action( $remove['hook'], $remove['callback'], $priority );
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Exclude the Modal Checkout from 'Coming Soon' mode.
|
|
1035
|
+
*/
|
|
1036
|
+
public static function disable_coming_soon() {
|
|
1037
|
+
return self::is_modal_checkout();
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Enqueue script for triggering modal checkout.
|
|
1042
|
+
*
|
|
1043
|
+
* @param int $product_id Product ID (optional).
|
|
1044
|
+
*/
|
|
1045
|
+
public static function enqueue_modal( $product_id = null ) {
|
|
1046
|
+
// Don't enqueue the modal if WooCommerce is not available.
|
|
1047
|
+
if ( ! function_exists( 'WC' ) ) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
self::$has_modal = true;
|
|
1052
|
+
if ( ! empty( $product_id ) ) {
|
|
1053
|
+
self::$products[ $product_id ] = true;
|
|
1054
|
+
}
|
|
1055
|
+
wp_enqueue_script(
|
|
1056
|
+
'newspack-blocks-modal',
|
|
1057
|
+
plugins_url( 'dist/modal.js', \NEWSPACK_BLOCKS__PLUGIN_FILE ),
|
|
1058
|
+
[],
|
|
1059
|
+
\NEWSPACK_BLOCKS__VERSION,
|
|
1060
|
+
[
|
|
1061
|
+
'strategy' => 'async',
|
|
1062
|
+
'in_footer' => true,
|
|
1063
|
+
]
|
|
1064
|
+
);
|
|
1065
|
+
wp_localize_script(
|
|
1066
|
+
'newspack-blocks-modal',
|
|
1067
|
+
'newspackBlocksModal',
|
|
1068
|
+
[
|
|
1069
|
+
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
|
1070
|
+
'checkout_registration_flag' => self::CHECKOUT_REGISTRATION_FLAG,
|
|
1071
|
+
'newspack_class_prefix' => self::get_class_prefix(),
|
|
1072
|
+
'is_registration_required' => self::is_registration_required(),
|
|
1073
|
+
'has_unsupported_payment_gateway' => self::has_unsupported_payment_gateway(),
|
|
1074
|
+
'checkout_url' => remove_query_arg( 'my_account_checkout', add_query_arg( 'modal_checkout', '1', wc_get_checkout_url() ) ),
|
|
1075
|
+
'labels' => [
|
|
1076
|
+
'auth_modal_title' => self::get_modal_checkout_labels( 'auth_modal_title' ),
|
|
1077
|
+
'checkout_modal_title' => self::get_modal_checkout_labels( 'checkout_modal_title' ),
|
|
1078
|
+
'register_modal_title' => self::get_modal_checkout_labels( 'register_modal_title' ),
|
|
1079
|
+
'signin_modal_title' => self::get_modal_checkout_labels( 'signin_modal_title' ),
|
|
1080
|
+
'thankyou_modal_title' => self::get_modal_checkout_labels( 'checkout_success' ),
|
|
1081
|
+
'critical_error' => self::get_modal_checkout_labels( 'checkout_critical_error' ),
|
|
1082
|
+
],
|
|
1083
|
+
|
|
1084
|
+
'processing_payment_messages' => [
|
|
1085
|
+
[
|
|
1086
|
+
'text' => __( 'Processing payment...', 'newspack-blocks' ),
|
|
1087
|
+
'delay' => 0,
|
|
1088
|
+
],
|
|
1089
|
+
[
|
|
1090
|
+
'text' => __( 'Processing payment...', 'newspack-blocks' ),
|
|
1091
|
+
'delay' => 250,
|
|
1092
|
+
],
|
|
1093
|
+
[
|
|
1094
|
+
'text' => __( 'Verifying details...', 'newspack-blocks' ),
|
|
1095
|
+
'delay' => 8000,
|
|
1096
|
+
],
|
|
1097
|
+
[
|
|
1098
|
+
'text' => __( 'Finalizing transaction...', 'newspack-blocks' ),
|
|
1099
|
+
'delay' => 14000,
|
|
1100
|
+
],
|
|
1101
|
+
],
|
|
1102
|
+
]
|
|
1103
|
+
);
|
|
1104
|
+
wp_enqueue_style(
|
|
1105
|
+
'newspack-blocks-modal',
|
|
1106
|
+
plugins_url( 'dist/modal.css', \NEWSPACK_BLOCKS__PLUGIN_FILE ),
|
|
1107
|
+
[],
|
|
1108
|
+
\NEWSPACK_BLOCKS__VERSION
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Use stripped down template for modal checkout.
|
|
1114
|
+
*
|
|
1115
|
+
* @param string $template The template to render.
|
|
1116
|
+
*
|
|
1117
|
+
* @return string
|
|
1118
|
+
*/
|
|
1119
|
+
public static function get_checkout_template( $template ) {
|
|
1120
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1121
|
+
return $template;
|
|
1122
|
+
}
|
|
1123
|
+
// Ensure we are on a wc page or endpoint.
|
|
1124
|
+
if (
|
|
1125
|
+
( ! function_exists( 'is_checkout' ) && ! is_checkout() ) &&
|
|
1126
|
+
( ! function_exists( 'is_cart' ) && ! is_cart() ) &&
|
|
1127
|
+
( ! function_exists( 'is_wc_endpoint_url' ) && ! is_wc_endpoint_url() )
|
|
1128
|
+
) {
|
|
1129
|
+
return $template;
|
|
1130
|
+
}
|
|
1131
|
+
$class_prefix = self::get_class_prefix();
|
|
1132
|
+
$wc_errors = wc_get_notices( 'error' );
|
|
1133
|
+
ob_start();
|
|
1134
|
+
?>
|
|
1135
|
+
<!doctype html>
|
|
1136
|
+
<html <?php language_attributes(); ?>>
|
|
1137
|
+
<head>
|
|
1138
|
+
<meta charset="<?php bloginfo( 'charset' ); ?>" />
|
|
1139
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1140
|
+
<link rel="profile" href="https://gmpg.org/xfn/11" />
|
|
1141
|
+
<?php wp_head(); ?>
|
|
1142
|
+
</head>
|
|
1143
|
+
<body <?php body_class( "$class_prefix {$class_prefix}__modal__content" ); ?> id="newspack_modal_checkout_container">
|
|
1144
|
+
<?php
|
|
1145
|
+
if ( is_checkout() || is_order_received_page() ) {
|
|
1146
|
+
echo do_shortcode( '[woocommerce_checkout]' );
|
|
1147
|
+
} else {
|
|
1148
|
+
// If template is not checkout or order received we want to render an error and back button in modal checkout context.
|
|
1149
|
+
?>
|
|
1150
|
+
<div class="newspack-ui__notice newspack-ui__notice--error">
|
|
1151
|
+
<div>
|
|
1152
|
+
<p>
|
|
1153
|
+
<?php
|
|
1154
|
+
$message = __( "We're sorry, there was an unexpected error. Please try again in a few minutes.", 'newspack-blocks' );
|
|
1155
|
+
if ( ! empty( $wc_errors ) ) {
|
|
1156
|
+
$error = $wc_errors[0];
|
|
1157
|
+
if ( is_array( $error ) && isset( $error['notice'] ) ) {
|
|
1158
|
+
$message = $error['notice'];
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
echo esc_html( $message );
|
|
1162
|
+
?>
|
|
1163
|
+
</p>
|
|
1164
|
+
</div>
|
|
1165
|
+
</div>
|
|
1166
|
+
<button class="newspack-ui__button newspack-ui__button--primary newspack-ui__button--wide" id="checkout_error_back" type="submit"><?php esc_html_e( 'Go back', 'newspack-blocks' ); ?></button>
|
|
1167
|
+
<?php
|
|
1168
|
+
}
|
|
1169
|
+
wp_footer();
|
|
1170
|
+
?>
|
|
1171
|
+
</body>
|
|
1172
|
+
</html>
|
|
1173
|
+
<?php
|
|
1174
|
+
ob_end_flush();
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* Get after success button params.
|
|
1179
|
+
*/
|
|
1180
|
+
private static function get_after_success_params() {
|
|
1181
|
+
$request_params = $_REQUEST; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1182
|
+
if ( self::is_express_checkout() ) {
|
|
1183
|
+
$request_params = [];
|
|
1184
|
+
$referrer = isset( $_SERVER['HTTP_REFERER'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
1185
|
+
if ( $referrer ) {
|
|
1186
|
+
$referrer_query = \wp_parse_url( $referrer, PHP_URL_QUERY );
|
|
1187
|
+
\wp_parse_str( $referrer_query, $request_params );
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return array_filter(
|
|
1191
|
+
[
|
|
1192
|
+
'after_success_behavior' => isset( $request_params['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_behavior'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1193
|
+
'after_success_url' => isset( $request_params['after_success_url'] ) ? sanitize_url( wp_unslash( $request_params['after_success_url'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1194
|
+
'after_success_button_label' => isset( $request_params['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_button_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1195
|
+
'action_type' => isset( $request_params['action_type'] ) ? sanitize_text_field( wp_unslash( $request_params['action_type'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1196
|
+
]
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Render hidden inputs to pass some params along.
|
|
1202
|
+
*/
|
|
1203
|
+
private static function render_hidden_inputs() {
|
|
1204
|
+
foreach ( self::get_after_success_params() as $key => $value ) {
|
|
1205
|
+
?>
|
|
1206
|
+
<input type="hidden" name="<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $value ); ?>" />
|
|
1207
|
+
<?php
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* Return URL for modal checkout "thank you" page.
|
|
1213
|
+
*
|
|
1214
|
+
* @param string $url The URL to redirect to.
|
|
1215
|
+
* @param WC_Order $order The order related to the transaction.
|
|
1216
|
+
*
|
|
1217
|
+
* @return string
|
|
1218
|
+
*/
|
|
1219
|
+
public static function woocommerce_get_return_url( $url, $order ) {
|
|
1220
|
+
if ( ! self::is_modal_checkout() || self::has_unsupported_payment_gateway() ) {
|
|
1221
|
+
return $url;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
$args = array_merge(
|
|
1225
|
+
[
|
|
1226
|
+
'modal_checkout' => '1',
|
|
1227
|
+
'email' => isset( $_REQUEST['billing_email'] ) ? rawurlencode( \sanitize_email( \wp_unslash( $_REQUEST['billing_email'] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1228
|
+
],
|
|
1229
|
+
self::get_after_success_params()
|
|
1230
|
+
);
|
|
1231
|
+
|
|
1232
|
+
// Pass order ID for modal checkout templates.
|
|
1233
|
+
if ( $order && is_a( $order, 'WC_Order' ) ) {
|
|
1234
|
+
$args['order_id'] = $order->get_id();
|
|
1235
|
+
$args['key'] = $order->get_order_key();
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// Pass checkout registration flag.
|
|
1239
|
+
if ( isset( $_REQUEST[ self::CHECKOUT_REGISTRATION_FLAG ] ) && $_REQUEST[ self::CHECKOUT_REGISTRATION_FLAG ] ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
|
1240
|
+
$args[ self::CHECKOUT_REGISTRATION_FLAG ] = '1';
|
|
1241
|
+
}
|
|
1242
|
+
return add_query_arg(
|
|
1243
|
+
$args,
|
|
1244
|
+
$url
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Update the text used for the Password Strength message from WooCommerce.
|
|
1250
|
+
*/
|
|
1251
|
+
public static function update_password_strength_message() {
|
|
1252
|
+
wp_localize_script(
|
|
1253
|
+
'wc-password-strength-meter',
|
|
1254
|
+
'pwsL10n',
|
|
1255
|
+
array(
|
|
1256
|
+
'mismatch' => __( 'Password mismatch', 'newspack-blocks' ),
|
|
1257
|
+
'short' => __( 'Password strength: Very weak', 'newspack-blocks' ),
|
|
1258
|
+
'bad' => __( 'Password strength: Weak', 'newspack-blocks' ),
|
|
1259
|
+
'good' => __( 'Password strength: Medium', 'newspack-blocks' ),
|
|
1260
|
+
'strong' => __( 'Password strength: Strong', 'newspack-blocks' ),
|
|
1261
|
+
)
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* Use modal checkout template when rendering the checkout form.
|
|
1267
|
+
*
|
|
1268
|
+
* @param string $located Template file.
|
|
1269
|
+
* @param string $template_name Template name.
|
|
1270
|
+
*
|
|
1271
|
+
* @return string Template file.
|
|
1272
|
+
*/
|
|
1273
|
+
public static function wc_get_template( $located, $template_name ) {
|
|
1274
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1275
|
+
return $located;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
$custom_templates = [
|
|
1279
|
+
'checkout/form-coupon.php' => 'src/modal-checkout/templates/form-coupon.php',
|
|
1280
|
+
'checkout/form-gift-subscription.php' => 'src/modal-checkout/templates/form-gift-subscription.php',
|
|
1281
|
+
];
|
|
1282
|
+
|
|
1283
|
+
// If Newspack UI is present, use our templates.
|
|
1284
|
+
if ( self::get_class_prefix() === 'newspack-ui' ) {
|
|
1285
|
+
// Replace the login form with the order summary if using the modal checkout. This is
|
|
1286
|
+
// for the case where the reader used an existing email address.
|
|
1287
|
+
$custom_templates['global/form-login.php'] = 'src/modal-checkout/templates/thankyou.php';
|
|
1288
|
+
$custom_templates['checkout/form-checkout.php'] = 'src/modal-checkout/templates/form-checkout.php';
|
|
1289
|
+
$custom_templates['checkout/payment-method.php'] = 'src/modal-checkout/templates/payment-method.php';
|
|
1290
|
+
$custom_templates['checkout/form-change-payment-method.php'] = 'src/modal-checkout/templates/form-change-payment-method.php';
|
|
1291
|
+
$custom_templates['checkout/thankyou.php'] = 'src/modal-checkout/templates/thankyou.php';
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// Only show the woocommerce-subscriptions-gifting fields when we want to.
|
|
1295
|
+
if ( 'html-add-recipient.php' === $template_name ) {
|
|
1296
|
+
$cart_items = \WC()->cart->get_cart();
|
|
1297
|
+
|
|
1298
|
+
// If there's only one cart item, prefer our custom gift UI. Otherwise, use the default.
|
|
1299
|
+
if ( 1 === count( array_values( $cart_items ) ) && class_exists( 'WCS_Gifting' ) ) {
|
|
1300
|
+
$custom_templates['html-add-recipient.php'] = 'src/modal-checkout/templates/empty-html-add-recipient.php';
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
foreach ( $custom_templates as $original_template => $custom_template ) {
|
|
1305
|
+
if ( $template_name === $original_template ) {
|
|
1306
|
+
$located = NEWSPACK_BLOCKS__PLUGIN_DIR . $custom_template;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// This is for the initial display – the markup will be refetched on cart updates (e.g. applying a coupon).
|
|
1311
|
+
// Then it'd be handled by the `woocommerce_update_order_review_fragments` filter.
|
|
1312
|
+
if ( 'checkout/review-order.php' === $template_name && ! self::should_show_order_details() ) {
|
|
1313
|
+
$located = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/modal-checkout/templates/empty-order-details.php';
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
return $located;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* Disable admin bar for modal checkout.
|
|
1321
|
+
*
|
|
1322
|
+
* @param bool $show Whether to show the admin bar.
|
|
1323
|
+
*
|
|
1324
|
+
* @return bool
|
|
1325
|
+
*/
|
|
1326
|
+
public static function show_admin_bar( $show ) {
|
|
1327
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1328
|
+
return $show;
|
|
1329
|
+
}
|
|
1330
|
+
return false;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Modify fields for modal checkout.
|
|
1335
|
+
*
|
|
1336
|
+
* @param array $fields Checkout fields.
|
|
1337
|
+
*
|
|
1338
|
+
* @return array
|
|
1339
|
+
*/
|
|
1340
|
+
public static function woocommerce_checkout_fields( $fields ) {
|
|
1341
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1342
|
+
return $fields;
|
|
1343
|
+
}
|
|
1344
|
+
$cart = \WC()->cart;
|
|
1345
|
+
// Don't modify fields if shipping is required.
|
|
1346
|
+
if ( $cart->needs_shipping_address() ) {
|
|
1347
|
+
return $fields;
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Temporarily use the same fields as the donation checkout.
|
|
1351
|
+
*
|
|
1352
|
+
* This should soon be replaced with a logic that allows the customization
|
|
1353
|
+
* at the Checkout Button Block level.
|
|
1354
|
+
*/
|
|
1355
|
+
$billing_fields = apply_filters( 'newspack_blocks_donate_billing_fields_keys', [] );
|
|
1356
|
+
if ( empty( $billing_fields ) ) {
|
|
1357
|
+
return $fields;
|
|
1358
|
+
}
|
|
1359
|
+
$billing_keys = array_keys( $fields['billing'] );
|
|
1360
|
+
foreach ( $billing_keys as $key ) {
|
|
1361
|
+
if ( in_array( $key, $billing_fields, true ) ) {
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
unset( $fields['billing'][ $key ] );
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Add the form-row-last CSS class to billing phone field.
|
|
1369
|
+
*/
|
|
1370
|
+
if ( in_array( 'billing_phone', $billing_fields, true ) ) {
|
|
1371
|
+
$fields['billing']['billing_phone']['class'] = 'form-row-last';
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
return $fields;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* If WooCommerce Subscriptions Gifting extension is available, render its fields.
|
|
1379
|
+
*
|
|
1380
|
+
* @return string HTML for the WooCommerce Subscriptions Gifting fields.
|
|
1381
|
+
*/
|
|
1382
|
+
public static function maybe_show_wcs_gifting_fields() {
|
|
1383
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// Add custom Gift Subscriptions fields if needed.
|
|
1388
|
+
$cart_items = array_values( \WC()->cart->get_cart() );
|
|
1389
|
+
if (
|
|
1390
|
+
1 === count( $cart_items ) &&
|
|
1391
|
+
method_exists( 'WCSG_Cart', 'is_giftable_item' ) &&
|
|
1392
|
+
method_exists( 'WCSG_Cart', 'contains_gifted_renewal' ) &&
|
|
1393
|
+
function_exists( 'wcs_cart_contains_renewal' )
|
|
1394
|
+
) {
|
|
1395
|
+
$cart_item = reset( $cart_items );
|
|
1396
|
+
if ( \WCSG_Cart::is_giftable_item( $cart_item ) ) {
|
|
1397
|
+
$email = ( empty( $cart_item['wcsg_gift_recipients_email'] ) ) ? '' : $cart_item['wcsg_gift_recipients_email'];
|
|
1398
|
+
$args = [
|
|
1399
|
+
'email' => $email,
|
|
1400
|
+
'is_renewal' => false,
|
|
1401
|
+
];
|
|
1402
|
+
|
|
1403
|
+
if ( \WCSG_Cart::contains_gifted_renewal() ) {
|
|
1404
|
+
$recipient_user_id = \WCSG_Cart::get_recipient_from_cart_item( \wcs_cart_contains_renewal() );
|
|
1405
|
+
$recipient_user = \get_userdata( $recipient_user_id );
|
|
1406
|
+
if ( $recipient_user && isset( $recipient_user->email ) ) {
|
|
1407
|
+
$args['email'] = $recipient_user->user_email;
|
|
1408
|
+
$args['is_renewal'] = true;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
\wc_get_template( 'checkout/form-gift-subscription.php', $args );
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* If the WooCommerce Subscriptions Gifting extension is available, handle custom form inputs.
|
|
1419
|
+
*/
|
|
1420
|
+
public static function wcsg_apply_gift_subscription() {
|
|
1421
|
+
$cart_items = \WC()->cart->get_cart();
|
|
1422
|
+
if (
|
|
1423
|
+
1 === count( array_values( $cart_items ) ) &&
|
|
1424
|
+
method_exists( 'WCS_Gifting', 'email_belongs_to_current_user' ) &&
|
|
1425
|
+
method_exists( 'WCS_Gifting', 'update_cart_item_recipient' ) &&
|
|
1426
|
+
method_exists( 'WCSG_Cart', 'is_giftable_item' )
|
|
1427
|
+
) {
|
|
1428
|
+
$is_gift = ! empty( filter_input( INPUT_POST, 'newspack_wcsg_is_gift', FILTER_SANITIZE_SPECIAL_CHARS ) );
|
|
1429
|
+
$cart_item_key = array_keys( $cart_items )[0];
|
|
1430
|
+
$cart_item = array_values( $cart_items )[0];
|
|
1431
|
+
if ( $is_gift && \WCSG_Cart::is_giftable_item( $cart_item ) ) {
|
|
1432
|
+
$recipient_email = \sanitize_email( filter_input( INPUT_POST, 'wcsg_gift_recipients_email', FILTER_SANITIZE_EMAIL ) );
|
|
1433
|
+
$self_gifting = \WCS_Gifting::email_belongs_to_current_user( $recipient_email );
|
|
1434
|
+
$is_valid_email = ! $self_gifting && \is_email( $recipient_email );
|
|
1435
|
+
|
|
1436
|
+
// If no errors, attach the recipient's email address to the subscription item.
|
|
1437
|
+
if ( $is_valid_email ) {
|
|
1438
|
+
\WCS_Gifting::update_cart_item_recipient( $cart_item, $cart_item_key, $recipient_email );
|
|
1439
|
+
} else {
|
|
1440
|
+
$notice = $self_gifting
|
|
1441
|
+
? __( 'Please enter someone else\' email address to receive this gift.', 'newspack-blocks' )
|
|
1442
|
+
: __( 'Please enter a valid email address to receive this gift.', 'newspack-blocks' );
|
|
1443
|
+
|
|
1444
|
+
// Handle email validation errors.
|
|
1445
|
+
\wc_add_notice(
|
|
1446
|
+
$notice,
|
|
1447
|
+
'error',
|
|
1448
|
+
[ 'id' => 'wcsg_gift_recipients_email' ]
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* Whether to show order details table.
|
|
1457
|
+
*
|
|
1458
|
+
* @return bool
|
|
1459
|
+
*/
|
|
1460
|
+
public static function should_show_order_details() {
|
|
1461
|
+
$cart = \WC()->cart;
|
|
1462
|
+
if ( $cart->is_empty() ) {
|
|
1463
|
+
return false;
|
|
1464
|
+
}
|
|
1465
|
+
if ( ! empty( $cart->get_applied_coupons() ) ) {
|
|
1466
|
+
return true;
|
|
1467
|
+
}
|
|
1468
|
+
if ( \wc_tax_enabled() && ! $cart->display_prices_including_tax() ) {
|
|
1469
|
+
return true;
|
|
1470
|
+
}
|
|
1471
|
+
if ( 1 < $cart->get_cart_contents_count() ) {
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
if ( ! empty( $cart->get_fees() ) ) {
|
|
1475
|
+
return true;
|
|
1476
|
+
}
|
|
1477
|
+
if ( method_exists( 'WC_Subscriptions_Switcher', 'cart_contains_switches' ) && \WC_Subscriptions_Switcher::cart_contains_switches( 'any' ) ) {
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
if ( $cart->needs_shipping_address() ) {
|
|
1481
|
+
$shipping = \WC()->shipping;
|
|
1482
|
+
$packages = $shipping->get_packages();
|
|
1483
|
+
$totals = $cart->get_totals();
|
|
1484
|
+
$shipping_rates = [];
|
|
1485
|
+
|
|
1486
|
+
// Find all the shipping rates that apply to the current transaction.
|
|
1487
|
+
foreach ( $packages as $package ) {
|
|
1488
|
+
if ( ! empty( $package['rates'] ) ) {
|
|
1489
|
+
foreach ( $package['rates'] as $rate_key => $rate ) {
|
|
1490
|
+
$shipping_rates[ $rate_key ] = $rate;
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Show details if shipping requires a fee or if there are multiple shipping rates to choose from.
|
|
1496
|
+
if ( (float) $totals['total'] !== (float) $totals['subtotal'] || 1 < count( array_values( $shipping_rates ) ) ) {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
if ( class_exists( 'WC_Subscriptions_Cart' ) && \WC_Subscriptions_Cart::cart_contains_subscription() ) {
|
|
1502
|
+
return true;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
// Show details if the cart contains a subscription renewal.
|
|
1506
|
+
if ( function_exists( 'wcs_cart_contains_renewal' ) && \wcs_cart_contains_renewal() ) {
|
|
1507
|
+
return true;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
return false;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* Customize order review fragments on cart updates.
|
|
1515
|
+
*
|
|
1516
|
+
* @param array $fragments Fragments.
|
|
1517
|
+
*
|
|
1518
|
+
* @return array
|
|
1519
|
+
*/
|
|
1520
|
+
public static function order_review_fragments( $fragments ) {
|
|
1521
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1522
|
+
return $fragments;
|
|
1523
|
+
}
|
|
1524
|
+
if ( ! self::should_show_order_details() ) {
|
|
1525
|
+
// Render an empty table so WC knows how to replace it on updates.
|
|
1526
|
+
$fragments['.woocommerce-checkout-review-order-table'] = '<table class="shop_table woocommerce-checkout-review-order-table empty"></table>';
|
|
1527
|
+
}
|
|
1528
|
+
return $fragments;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* Render a generic button to close the modal.
|
|
1533
|
+
*
|
|
1534
|
+
* @param string $button_label The button label.
|
|
1535
|
+
*/
|
|
1536
|
+
private static function render_close_button( $button_label = '' ) {
|
|
1537
|
+
if ( ! $button_label ) {
|
|
1538
|
+
$button_label = __( 'Close window', 'newspack-blocks' );
|
|
1539
|
+
}
|
|
1540
|
+
?>
|
|
1541
|
+
<div class="button-container">
|
|
1542
|
+
<a
|
|
1543
|
+
onclick="parent.newspackCloseModalCheckout(this);"
|
|
1544
|
+
class="button close-button"
|
|
1545
|
+
>
|
|
1546
|
+
<?php echo esc_html( $button_label ); ?>
|
|
1547
|
+
</a>
|
|
1548
|
+
</div>
|
|
1549
|
+
<?php
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* Is the current request only to validate billing field inputs on the first modal screen?
|
|
1554
|
+
*
|
|
1555
|
+
* @return bool True if the request is for validation only.
|
|
1556
|
+
*/
|
|
1557
|
+
private static function is_validation_only() {
|
|
1558
|
+
return boolval( filter_input( INPUT_POST, 'is_validation_only', FILTER_SANITIZE_NUMBER_INT ) );
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Determine if the request needs payment.
|
|
1563
|
+
* If we're just validating billing fields at the first modal screen, this should always be false.
|
|
1564
|
+
*
|
|
1565
|
+
* @param bool $needs_payment Whether the cart needs payment.
|
|
1566
|
+
*
|
|
1567
|
+
* @return bool False if we're in modal checkout and validating billing fields.
|
|
1568
|
+
*/
|
|
1569
|
+
public static function cart_needs_payment( $needs_payment ) {
|
|
1570
|
+
if ( self::is_modal_checkout() && self::is_validation_only() ) {
|
|
1571
|
+
return false;
|
|
1572
|
+
}
|
|
1573
|
+
return $needs_payment;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* Prevent reCAPTCHA from being verified for AJAX checkout (e.g. Apple Pay).
|
|
1578
|
+
*
|
|
1579
|
+
* @param bool $should_verify Whether to verify the captcha.
|
|
1580
|
+
* @param string $url The URL from which the verification request originated.
|
|
1581
|
+
* @param string $context The context that triggered the verification request.
|
|
1582
|
+
*/
|
|
1583
|
+
public static function recaptcha_verify_captcha( $should_verify, $url, $context = 'unknown' ) {
|
|
1584
|
+
if ( 'checkout' !== $context ) {
|
|
1585
|
+
return $should_verify;
|
|
1586
|
+
}
|
|
1587
|
+
if ( self::is_validation_only() ) {
|
|
1588
|
+
return false;
|
|
1589
|
+
}
|
|
1590
|
+
return $should_verify;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Ensure that the modal_checkout param is passed if we get redirected while inside the modal.
|
|
1595
|
+
* This is so that we can continue hiding site elements that we don't want to show inside the modal.
|
|
1596
|
+
*
|
|
1597
|
+
* @param string $location The path or URL to redirect to.
|
|
1598
|
+
*
|
|
1599
|
+
* @return string
|
|
1600
|
+
*/
|
|
1601
|
+
public static function pass_url_param_on_redirect( $location ) {
|
|
1602
|
+
if ( self::is_modal_checkout() ) {
|
|
1603
|
+
$params = [ 'modal_checkout' => 1 ];
|
|
1604
|
+
$newspack_popup_id = filter_input( INPUT_GET, 'newspack_popup_id', FILTER_SANITIZE_NUMBER_INT );
|
|
1605
|
+
$prompt_title = filter_input( INPUT_GET, 'prompt_title', FILTER_SANITIZE_SPECIAL_CHARS );
|
|
1606
|
+
$gate_post_id = filter_input( INPUT_GET, 'gate_post_id', FILTER_SANITIZE_NUMBER_INT );
|
|
1607
|
+
if ( $newspack_popup_id ) {
|
|
1608
|
+
$params['newspack_popup_id'] = $newspack_popup_id;
|
|
1609
|
+
}
|
|
1610
|
+
if ( $prompt_title ) {
|
|
1611
|
+
$params['prompt_title'] = $prompt_title;
|
|
1612
|
+
}
|
|
1613
|
+
if ( $gate_post_id ) {
|
|
1614
|
+
$params['gate_post_id'] = $gate_post_id;
|
|
1615
|
+
}
|
|
1616
|
+
$location = \add_query_arg( $params, $location );
|
|
1617
|
+
}
|
|
1618
|
+
return $location;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
/**
|
|
1622
|
+
* Alternative error message to show when limiting a subscription product's purchase to only one active subscription.
|
|
1623
|
+
*
|
|
1624
|
+
* @return string
|
|
1625
|
+
*/
|
|
1626
|
+
public static function get_subscription_limited_message() {
|
|
1627
|
+
return sprintf(
|
|
1628
|
+
// translators: %s: Site name.
|
|
1629
|
+
__( "You're already a subscriber! You can only have one active subscription at a time. Thank you for supporting %s.", 'newspack-blocks' ),
|
|
1630
|
+
get_bloginfo( 'name' )
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
/**
|
|
1635
|
+
* Alternative error message to show when limiting a subscription product's purchase to one of any status.
|
|
1636
|
+
*
|
|
1637
|
+
* @return string
|
|
1638
|
+
*/
|
|
1639
|
+
public static function get_subscription_limited_message_any() {
|
|
1640
|
+
return __( "You're already a subscriber! You can only have one subscription at a time. If you wish to renew an expired subscription, please sign in and visit the subscriptions page on your account.", 'newspack-blocks' );
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* Filters the error message shown when a product can't be added to the cart.
|
|
1645
|
+
*
|
|
1646
|
+
* @param string $message Message.
|
|
1647
|
+
* @param WC_Product $product_data Product data.
|
|
1648
|
+
*
|
|
1649
|
+
* @return string
|
|
1650
|
+
*/
|
|
1651
|
+
public static function woocommerce_cart_product_cannot_be_purchased_message( $message, $product_data ) {
|
|
1652
|
+
if ( method_exists( 'WCS_Limiter', 'is_purchasable' ) ) {
|
|
1653
|
+
$product = \wc_get_product( $product_data->get_id() );
|
|
1654
|
+
$product_limitation = wcs_get_product_limitation( $product->get_id() );
|
|
1655
|
+
|
|
1656
|
+
if ( ! \WCS_Limiter::is_purchasable( false, $product ) ) {
|
|
1657
|
+
if ( 'active' === $product_limitation ) {
|
|
1658
|
+
$message = self::get_subscription_limited_message();
|
|
1659
|
+
} else {
|
|
1660
|
+
$message = self::get_subscription_limited_message_any();
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
return $message;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
/**
|
|
1669
|
+
* We don't want to show the Shop page link in modal checkout because the Shop page doesn't work well inside.
|
|
1670
|
+
* Unfortunately Woo doesn't provide a filter for this message, so we need to detect it by string matching.
|
|
1671
|
+
* May not work if the message has been translated or modified elsewhere.
|
|
1672
|
+
*
|
|
1673
|
+
* @param string $message The message.
|
|
1674
|
+
* @return string
|
|
1675
|
+
*/
|
|
1676
|
+
public static function hide_expiry_message_shop_link( $message ) {
|
|
1677
|
+
if ( self::is_modal_checkout() && strpos( $message, 'Sorry, your session has expired' ) !== false ) {
|
|
1678
|
+
return self::get_modal_checkout_labels( 'checkout_critical_error' );
|
|
1679
|
+
}
|
|
1680
|
+
return $message;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Is this request using the modal checkout?
|
|
1685
|
+
*/
|
|
1686
|
+
public static function is_modal_checkout() {
|
|
1687
|
+
// Until we use the modal checkout flow from My Account, we don't want to show the modal checkout thank you template for checkouts originating from My Account.
|
|
1688
|
+
if ( method_exists( 'Newspack\WooCommerce_My_Account', 'is_from_my_account' ) && \Newspack\WooCommerce_My_Account::is_from_my_account() ) {
|
|
1689
|
+
return false;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
$is_modal_checkout = isset( $_REQUEST['modal_checkout'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1693
|
+
if ( ! $is_modal_checkout && isset( $_REQUEST['post_data'] ) && is_string( $_REQUEST['post_data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1694
|
+
$is_modal_checkout = strpos( $_REQUEST['post_data'], 'modal_checkout=1' ) !== false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
if ( self::is_express_checkout() ) {
|
|
1698
|
+
$is_modal_checkout = true;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
return $is_modal_checkout;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
/**
|
|
1705
|
+
* Is this transaction using an express checkout method?
|
|
1706
|
+
*/
|
|
1707
|
+
public static function is_express_checkout() {
|
|
1708
|
+
// Get express_payment_type in a way that works for both Stripe and WooPayments.
|
|
1709
|
+
$express_payment_info = isset( $_POST['express_payment_type'] ) ? sanitize_text_field( wp_unslash( $_POST['express_payment_type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
|
|
1710
|
+
|
|
1711
|
+
$is_express_checkout = ! empty( $express_payment_info ) && in_array( $express_payment_info, [ 'apple_pay', 'google_pay', 'payment_request_api', 'link' ], true ); // Validate payment request types: https://github.com/woocommerce/woocommerce-gateway-stripe/blob/develop/includes/payment-methods/class-wc-stripe-payment-request.php#L557-L586.
|
|
1712
|
+
|
|
1713
|
+
if ( $is_express_checkout ) {
|
|
1714
|
+
$referrer = isset( $_SERVER['HTTP_REFERER'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
1715
|
+
if ( $referrer ) {
|
|
1716
|
+
$referrer_query = \wp_parse_url( $referrer, PHP_URL_QUERY );
|
|
1717
|
+
\wp_parse_str( $referrer_query, $referrer_query_params );
|
|
1718
|
+
if ( isset( $referrer_query_params['modal_checkout'] ) && $referrer_query_params['modal_checkout'] ) {
|
|
1719
|
+
return true;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return false;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
/**
|
|
1727
|
+
* Set the "Place order" button text.
|
|
1728
|
+
*
|
|
1729
|
+
* @param string $text The button text.
|
|
1730
|
+
*/
|
|
1731
|
+
public static function order_button_text( $text ) {
|
|
1732
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1733
|
+
return $text;
|
|
1734
|
+
}
|
|
1735
|
+
$cart = \WC()->cart;
|
|
1736
|
+
if ( ! $cart || $cart->is_empty() ) {
|
|
1737
|
+
return $text;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
return self::get_modal_checkout_labels( 'checkout_confirm' );
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Get the updated "Place order" button text for JS updates.
|
|
1745
|
+
*/
|
|
1746
|
+
public static function order_button_text_with_price() {
|
|
1747
|
+
$cart = \WC()->cart;
|
|
1748
|
+
$is_donation = method_exists( 'Newspack\Donations', 'is_donation_cart' ) && \Newspack\Donations::is_donation_cart();
|
|
1749
|
+
|
|
1750
|
+
// If this isn't a cart, if the cart is empty, or if this is a donation product, bail.
|
|
1751
|
+
if ( ! $cart || $cart->is_empty() || $is_donation ) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// Bail if this is a subscription switch.
|
|
1756
|
+
if ( method_exists( 'WC_Subscriptions_Switcher', 'cart_contains_switches' ) && \WC_Subscriptions_Switcher::cart_contains_switches( 'any' ) ) {
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
$total = \wp_strip_all_tags( \wc_price( $cart->total ) );
|
|
1761
|
+
|
|
1762
|
+
return sprintf(
|
|
1763
|
+
/* translators: 1: Checkout button confirmation text. 2: Order total. */
|
|
1764
|
+
__( '%1$s: %2$s', 'newspack-blocks' ),
|
|
1765
|
+
self::get_modal_checkout_labels( 'checkout_confirm' ),
|
|
1766
|
+
'<span class="cart-price">' . html_entity_decode( $total, ENT_COMPAT ) . '</span>'
|
|
1767
|
+
);
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
/**
|
|
1771
|
+
* Get the updated price for updating the "Place order" button.
|
|
1772
|
+
*/
|
|
1773
|
+
public static function get_cart_total_js() {
|
|
1774
|
+
$cart = \WC()->cart;
|
|
1775
|
+
if ( ! $cart || $cart->is_empty() ) {
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
$total = \wp_strip_all_tags( \wc_price( $cart->total ) );
|
|
1779
|
+
echo esc_html( html_entity_decode( $total, ENT_COMPAT ) );
|
|
1780
|
+
wp_die();
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
/**
|
|
1784
|
+
* Render before the checkout form.
|
|
1785
|
+
*
|
|
1786
|
+
* This will render the order summary card.
|
|
1787
|
+
*/
|
|
1788
|
+
public static function render_before_checkout_form() {
|
|
1789
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
$cart = \WC()->cart;
|
|
1793
|
+
if ( 1 !== $cart->get_cart_contents_count() ) {
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
$cart_item_key = array_key_first( $cart->get_cart() );
|
|
1797
|
+
$cart_item = $cart->get_cart_item( $cart_item_key );
|
|
1798
|
+
$product_id = $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'];
|
|
1799
|
+
$class_prefix = self::get_class_prefix();
|
|
1800
|
+
?>
|
|
1801
|
+
<div class="<?php echo esc_attr( "order-details-summary {$class_prefix}__box {$class_prefix}__box--text-center" ); ?>">
|
|
1802
|
+
<?php
|
|
1803
|
+
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
1804
|
+
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
|
|
1805
|
+
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key ) ) :
|
|
1806
|
+
?>
|
|
1807
|
+
<p id="modal-checkout-product-details" data-checkout='<?php echo wp_json_encode( Checkout_Data::get_checkout_data( $cart ) ); ?>'>
|
|
1808
|
+
<strong>
|
|
1809
|
+
<?php
|
|
1810
|
+
echo apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ': '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
1811
|
+
echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
1812
|
+
?>
|
|
1813
|
+
<?php echo apply_filters( 'woocommerce_cart_item_subtotal', $cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
1814
|
+
</strong>
|
|
1815
|
+
</p>
|
|
1816
|
+
<?php
|
|
1817
|
+
endif;
|
|
1818
|
+
// phpcs:enable
|
|
1819
|
+
?>
|
|
1820
|
+
</div>
|
|
1821
|
+
<?php
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Render name your price form if nyp is active and available.
|
|
1826
|
+
*/
|
|
1827
|
+
public static function render_name_your_price_form() {
|
|
1828
|
+
if ( ! self::is_modal_checkout() || ! function_exists( 'WC' ) || ! method_exists( '\WC_Name_Your_Price_Helpers', 'is_nyp' ) ) {
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
// Only show nyp form for checkout button modal checkout.
|
|
1833
|
+
$is_donation = method_exists( 'Newspack\Donations', 'is_donation_cart' ) && \Newspack\Donations::is_donation_cart();
|
|
1834
|
+
if ( $is_donation ) {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
$cart = \WC()->cart;
|
|
1839
|
+
if ( 1 !== $cart->get_cart_contents_count() ) {
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1842
|
+
$class_prefix = self::get_class_prefix();
|
|
1843
|
+
?>
|
|
1844
|
+
<div class="name-your-price">
|
|
1845
|
+
<?php
|
|
1846
|
+
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
1847
|
+
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) :
|
|
1848
|
+
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
|
|
1849
|
+
if ( ! $_product || ! $_product->exists() || $cart_item['quantity'] <= 0 || ! \WC_Name_Your_Price_Helpers::is_nyp( $_product ) || ! apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
|
|
1850
|
+
continue;
|
|
1851
|
+
}
|
|
1852
|
+
$currency_symbol = \get_woocommerce_currency_symbol();
|
|
1853
|
+
$product_id = $_product->get_id();
|
|
1854
|
+
$price = $_product->get_price();
|
|
1855
|
+
?>
|
|
1856
|
+
<form class="modal_checkout_nyp">
|
|
1857
|
+
<h3><?php echo esc_html( self::get_modal_checkout_labels( 'checkout_nyp_title' ) ); ?></h3>
|
|
1858
|
+
<input type="hidden" name="newspack_checkout_name_your_price" value="1" />
|
|
1859
|
+
<input type="hidden" name="product_id" value="<?php echo esc_attr( $product_id ); ?>" />
|
|
1860
|
+
<p class="input-price" >
|
|
1861
|
+
<label for="price">
|
|
1862
|
+
<span class="currency"><?php echo esc_html( $currency_symbol ); ?></span>
|
|
1863
|
+
<input type="number" min="0" step=".01" name="price" placeholder="<?php echo esc_attr( $price ); ?>" onwheel="return false" />
|
|
1864
|
+
</label>
|
|
1865
|
+
<button type="submit" class="<?php echo esc_attr( "{$class_prefix}__button {$class_prefix}__button--outline" ); ?>">
|
|
1866
|
+
<?php echo esc_html( self::get_modal_checkout_labels( 'checkout_nyp_apply' ) ); ?>
|
|
1867
|
+
</button>
|
|
1868
|
+
</p>
|
|
1869
|
+
<p class="result <?php echo esc_attr( "{$class_prefix}__helper-text" ); ?>">
|
|
1870
|
+
<?php echo esc_attr( self::get_modal_checkout_labels( 'checkout_nyp' ) ); ?>
|
|
1871
|
+
</p>
|
|
1872
|
+
</form>
|
|
1873
|
+
<?php
|
|
1874
|
+
endforeach;
|
|
1875
|
+
// phpcs:enable
|
|
1876
|
+
?>
|
|
1877
|
+
</div>
|
|
1878
|
+
<?php
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
/**
|
|
1882
|
+
* Render before customer details.
|
|
1883
|
+
*
|
|
1884
|
+
* This will render the hidden inputs necessary for the modal checkout.
|
|
1885
|
+
*/
|
|
1886
|
+
public static function render_before_customer_details() {
|
|
1887
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
?>
|
|
1891
|
+
<input type="hidden" name="modal_checkout" value="1" />
|
|
1892
|
+
<?php self::render_hidden_inputs(); ?>
|
|
1893
|
+
<?php
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
/**
|
|
1897
|
+
* Maybe disable order notes in the modal checkout.
|
|
1898
|
+
*
|
|
1899
|
+
* @param bool $enable Whether to enable the order notes field.
|
|
1900
|
+
*
|
|
1901
|
+
* @return bool
|
|
1902
|
+
*/
|
|
1903
|
+
public static function enable_order_notes_field( $enable ) {
|
|
1904
|
+
if ( self::is_modal_checkout() ) {
|
|
1905
|
+
$cart = \WC()->cart;
|
|
1906
|
+
$billing_fields = apply_filters( 'newspack_blocks_donate_billing_fields_keys', [], $cart );
|
|
1907
|
+
return in_array( 'order_comments', $billing_fields, true );
|
|
1908
|
+
}
|
|
1909
|
+
return $enable;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
/**
|
|
1913
|
+
* Force option for base country for new customers if unset and billing country optional while state is required
|
|
1914
|
+
* unless the NEWSPACK_PREVENT_FORCE_BASE_DEFAULT_CUSTOMER_ADDRESS constant is set.
|
|
1915
|
+
*
|
|
1916
|
+
* If this option is empty AND billing state is set as a required field AND billing country is not,
|
|
1917
|
+
* validation of the state value will fail during modal checkout.
|
|
1918
|
+
*
|
|
1919
|
+
* See Default Customer Location in: https://woo.com/document/configuring-woocommerce-settings/#general-options
|
|
1920
|
+
*
|
|
1921
|
+
* @param string $option_value The value of the default customer address option.
|
|
1922
|
+
*
|
|
1923
|
+
* @return string Option value.
|
|
1924
|
+
*/
|
|
1925
|
+
public static function ensure_base_default_customer_address( $option_value ) {
|
|
1926
|
+
// If the option is set, we're good.
|
|
1927
|
+
if ( ! empty( $option_value ) ) {
|
|
1928
|
+
return $option_value;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// Only in modal checkout.
|
|
1932
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1933
|
+
return $option_value;
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
/**
|
|
1937
|
+
* Prevents forcing the WooCommerce base location as the default
|
|
1938
|
+
* customer address in modal checkout. Use if you need standard
|
|
1939
|
+
* geolocation behavior.
|
|
1940
|
+
*
|
|
1941
|
+
* @constant NEWSPACK_PREVENT_FORCE_BASE_DEFAULT_CUSTOMER_ADDRESS
|
|
1942
|
+
* @type bool
|
|
1943
|
+
* @default Base address forced in modal checkout
|
|
1944
|
+
* @status draft
|
|
1945
|
+
*
|
|
1946
|
+
* @example define( 'NEWSPACK_PREVENT_FORCE_BASE_DEFAULT_CUSTOMER_ADDRESS', true );
|
|
1947
|
+
*/
|
|
1948
|
+
if ( defined( 'NEWSPACK_PREVENT_FORCE_BASE_DEFAULT_CUSTOMER_ADDRESS' ) && NEWSPACK_PREVENT_FORCE_BASE_DEFAULT_CUSTOMER_ADDRESS ) {
|
|
1949
|
+
return $option_value;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// If billing state is required but billing country is not, we need to ensure a default location is set.
|
|
1953
|
+
if ( defined( '\Newspack\Donations::DONATION_BILLING_FIELDS_OPTION' ) ) {
|
|
1954
|
+
$billing_fields = get_option( \Newspack\Donations::DONATION_BILLING_FIELDS_OPTION, [] );
|
|
1955
|
+
if ( ! in_array( 'billing_country', $billing_fields, true ) && in_array( 'billing_state', $billing_fields, true ) ) {
|
|
1956
|
+
return 'base';
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
return $option_value;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* Get user from email.
|
|
1965
|
+
*
|
|
1966
|
+
* @return false|int User ID if found by email address, false otherwise.
|
|
1967
|
+
*/
|
|
1968
|
+
public static function get_user_id_from_email() {
|
|
1969
|
+
$billing_email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
|
|
1970
|
+
if ( $billing_email ) {
|
|
1971
|
+
$customer = \get_user_by( 'email', $billing_email );
|
|
1972
|
+
if ( $customer ) {
|
|
1973
|
+
return $customer->ID;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return false;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
/**
|
|
1980
|
+
* If a reader tries to make a purchase with an email address that
|
|
1981
|
+
* has been previously registered, automatically associate the transaction
|
|
1982
|
+
* with the user.
|
|
1983
|
+
*
|
|
1984
|
+
* @param int $customer_id Current customer ID.
|
|
1985
|
+
*
|
|
1986
|
+
* @return int Modified $customer_id
|
|
1987
|
+
*/
|
|
1988
|
+
public static function associate_existing_user( $customer_id ) {
|
|
1989
|
+
if ( ! self::is_modal_checkout() ) {
|
|
1990
|
+
return $customer_id;
|
|
1991
|
+
}
|
|
1992
|
+
$id_from_email = self::get_user_id_from_email();
|
|
1993
|
+
if ( $id_from_email ) {
|
|
1994
|
+
return $id_from_email;
|
|
1995
|
+
}
|
|
1996
|
+
return $customer_id;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
/**
|
|
2000
|
+
* Don't force account registration/login on Woo purchases for existing users.
|
|
2001
|
+
*
|
|
2002
|
+
* @param array $data Array of Woo checkout data.
|
|
2003
|
+
*
|
|
2004
|
+
* @return array Modified $data.
|
|
2005
|
+
*/
|
|
2006
|
+
public static function skip_account_creation( $data ) {
|
|
2007
|
+
$should_skip_account_creation = false;
|
|
2008
|
+
|
|
2009
|
+
// Always skip account creation during validation-only requests.
|
|
2010
|
+
if ( self::is_validation_only() ) {
|
|
2011
|
+
$should_skip_account_creation = true;
|
|
2012
|
+
} elseif ( self::is_modal_checkout() && ! empty( $data['billing_email'] ) ) {
|
|
2013
|
+
$customer = \get_user_by( 'email', $data['billing_email'] );
|
|
2014
|
+
if ( $customer ) {
|
|
2015
|
+
$should_skip_account_creation = true;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
if ( $should_skip_account_creation ) {
|
|
2020
|
+
$data['createaccount'] = 0;
|
|
2021
|
+
\add_filter( 'woocommerce_checkout_registration_required', '__return_false', 9999 );
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
return $data;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
/**
|
|
2028
|
+
* The value for the custom WooCommerce Subscriptions Gifting Extension checkbox label.
|
|
2029
|
+
*
|
|
2030
|
+
* @return string Gift checkbox label.
|
|
2031
|
+
*/
|
|
2032
|
+
public static function subscriptions_gifting_label() {
|
|
2033
|
+
$is_donation = method_exists( 'Newspack\Donations', 'is_donation_cart' ) && \Newspack\Donations::is_donation_cart();
|
|
2034
|
+
$label = $is_donation ? self::get_modal_checkout_labels( 'donation_gift_details' ) : self::get_modal_checkout_labels( 'purchase_gift_details' );
|
|
2035
|
+
return \apply_filters( 'wcsg_enable_gifting_checkbox_label', $label ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
/**
|
|
2039
|
+
* Wrap required checkbox text in a span so it works nicely with the Newspack UI grid layout.
|
|
2040
|
+
*
|
|
2041
|
+
* @param string $field The field HTML.
|
|
2042
|
+
* @param string $key The field key.
|
|
2043
|
+
* @param array $args The field arguments.
|
|
2044
|
+
* @param string $value The field value.
|
|
2045
|
+
* @return string Modified field HTML.
|
|
2046
|
+
*/
|
|
2047
|
+
public static function wrap_required_checkbox_text( $field, $key, $args, $value ) {
|
|
2048
|
+
if ( ! self::is_modal_checkout() ) {
|
|
2049
|
+
return $field;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
if ( ! empty( $args['required'] ) && $args['type'] === 'checkbox' ) {
|
|
2053
|
+
// Wrap the label's text and required asterisk in a span.
|
|
2054
|
+
$field = preg_replace(
|
|
2055
|
+
'/(<label[^>]*>.*?<input[^>]*>)(.*?)(<\/label>)/s',
|
|
2056
|
+
'$1<span>$2</span>$3',
|
|
2057
|
+
$field
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
return $field;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
/**
|
|
2064
|
+
* Filter a value to true dependent on the page not being modal checkout.
|
|
2065
|
+
*
|
|
2066
|
+
* @param bool $value The value.
|
|
2067
|
+
*/
|
|
2068
|
+
public static function is_modal_checkout_filter( $value ) {
|
|
2069
|
+
if ( self::is_modal_checkout() ) {
|
|
2070
|
+
return true;
|
|
2071
|
+
}
|
|
2072
|
+
return $value;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
/**
|
|
2076
|
+
* Filter a value to false dependent on the page not being modal checkout.
|
|
2077
|
+
*
|
|
2078
|
+
* @param bool $value The value.
|
|
2079
|
+
*/
|
|
2080
|
+
public static function is_not_modal_checkout_filter( $value ) {
|
|
2081
|
+
if ( self::is_modal_checkout() ) {
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
2084
|
+
return $value;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
/**
|
|
2088
|
+
* Deactivate all Jetpack modules on the modal checkout.
|
|
2089
|
+
*
|
|
2090
|
+
* @param bool $modules JP modules.
|
|
2091
|
+
*/
|
|
2092
|
+
public static function jetpack_active_modules( $modules ) {
|
|
2093
|
+
if ( self::is_modal_checkout() ) {
|
|
2094
|
+
return [];
|
|
2095
|
+
}
|
|
2096
|
+
return $modules;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Get the relevant class prefix (newspack-blocks or newspack-ui) depending on whether Newpack plugin is active.
|
|
2101
|
+
*/
|
|
2102
|
+
private static function get_class_prefix() {
|
|
2103
|
+
return class_exists( '\Newspack\Newspack_UI' ) ? 'newspack-ui' : 'newspack-blocks';
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
/**
|
|
2107
|
+
* Add newspack ui classes to the "Place order" button html.
|
|
2108
|
+
*
|
|
2109
|
+
* @param string $html The button html.
|
|
2110
|
+
*
|
|
2111
|
+
* @return string The modified button html.
|
|
2112
|
+
*/
|
|
2113
|
+
public static function order_button_html( $html ) {
|
|
2114
|
+
if ( ! self::is_modal_checkout() ) {
|
|
2115
|
+
return $html;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
$class_prefix = self::get_class_prefix();
|
|
2119
|
+
$newspack_ui_html = preg_replace( '/class=".*?"/', "class='{$class_prefix}__button {$class_prefix}__button--primary {$class_prefix}__button--wide'", $html );
|
|
2120
|
+
|
|
2121
|
+
return $newspack_ui_html;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
/**
|
|
2125
|
+
* Get modal checkout flow labels.
|
|
2126
|
+
*
|
|
2127
|
+
* @param string|null $key Key of the label to return (optional).
|
|
2128
|
+
*
|
|
2129
|
+
* @return string[]|string The label string or an array of labels keyed by string.
|
|
2130
|
+
*/
|
|
2131
|
+
public static function get_modal_checkout_labels( $key = null ) {
|
|
2132
|
+
if ( empty( self::$modal_checkout_labels ) ) {
|
|
2133
|
+
$default_labels = [
|
|
2134
|
+
'billing_details' => __( 'Billing details', 'newspack-blocks' ),
|
|
2135
|
+
'shipping_details' => __( 'Shipping details', 'newspack-blocks' ),
|
|
2136
|
+
'gift_recipient' => __( 'Gift recipient', 'newspack-blocks' ),
|
|
2137
|
+
'checkout_modal_title' => __( 'Complete your transaction', 'newspack-blocks' ),
|
|
2138
|
+
'variation_modal_title' => __( 'Complete your transaction', 'newspack-blocks' ),
|
|
2139
|
+
'auth_modal_title' => __( 'Complete your transaction', 'newspack-blocks' ),
|
|
2140
|
+
'signin_modal_title' => _x(
|
|
2141
|
+
'Sign in to complete transaction',
|
|
2142
|
+
'Login modal title when logged out user attempts to checkout.',
|
|
2143
|
+
'newspack-blocks'
|
|
2144
|
+
),
|
|
2145
|
+
'register_modal_title' => _x(
|
|
2146
|
+
'Register to complete transaction',
|
|
2147
|
+
'Login modal title when unregistered user attempts to checkout',
|
|
2148
|
+
'newspack-blocks'
|
|
2149
|
+
),
|
|
2150
|
+
'after_success' => __( 'Continue browsing', 'newspack-blocks' ),
|
|
2151
|
+
'donation_gift_details' => __( 'This donation is a gift', 'newspack-blocks' ),
|
|
2152
|
+
'purchase_gift_details' => get_option(
|
|
2153
|
+
'woocommerce_subscriptions_gifting_gifting_checkbox_text',
|
|
2154
|
+
method_exists( 'Newspack\WooCommerce_Subscriptions_Gifting', 'default_gifting_checkbox_text' ) ?
|
|
2155
|
+
\Newspack\WooCommerce_Subscriptions_Gifting::default_gifting_checkbox_text() :
|
|
2156
|
+
__( 'This purchase is a gift', 'newspack-blocks' )
|
|
2157
|
+
),
|
|
2158
|
+
'checkout_confirm' => __( 'Complete transaction', 'newspack-blocks' ),
|
|
2159
|
+
'checkout_confirm_variation' => __( 'Purchase', 'newspack-blocks' ),
|
|
2160
|
+
'checkout_edit_billing' => __( 'Edit billing information', 'newspack-blocks' ),
|
|
2161
|
+
'checkout_cancel' => __( 'Cancel', 'newspack-blocks' ),
|
|
2162
|
+
'checkout_success' => __( 'Transaction successful', 'newspack-blocks' ),
|
|
2163
|
+
'checkout_nyp' => __( "Your contribution directly funds our work. If you're moved to do so, you can opt to pay more than the standard rate.", 'newspack-blocks' ),
|
|
2164
|
+
'checkout_nyp_thankyou' => __( "Thank you for your generosity! We couldn't do this without you!", 'newspack-blocks' ),
|
|
2165
|
+
'checkout_nyp_title' => __( 'Increase your support', 'newspack-blocks' ),
|
|
2166
|
+
'checkout_nyp_apply' => __( 'Apply', 'newspack-blocks' ),
|
|
2167
|
+
'checkout_critical_error' => __( 'We ran into a problem processing this request. Please try again.', 'newspack-blocks' ),
|
|
2168
|
+
];
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* Filters the global labels for modal checkout flow.
|
|
2172
|
+
*
|
|
2173
|
+
* @param mixed[] $labels Labels keyed by name.
|
|
2174
|
+
*/
|
|
2175
|
+
$filtered_labels = apply_filters( 'newspack_blocks_modal_checkout_labels', $default_labels );
|
|
2176
|
+
|
|
2177
|
+
// Merge the default and filtered labels to ensure there are no missing labels.
|
|
2178
|
+
self::$modal_checkout_labels = array_merge( $default_labels, $filtered_labels );
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
if ( ! $key ) {
|
|
2182
|
+
return self::$modal_checkout_labels;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
return self::$modal_checkout_labels[ $key ] ?? '';
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
/**
|
|
2189
|
+
* Set the checkout registration flag to WC session.
|
|
2190
|
+
*/
|
|
2191
|
+
public static function set_checkout_registration_flag() {
|
|
2192
|
+
\WC()->session->set( self::CHECKOUT_REGISTRATION_FLAG, true );
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
/**
|
|
2196
|
+
* Reset the checkout registration flag from WC session.
|
|
2197
|
+
*/
|
|
2198
|
+
public static function reset_checkout_registration_flag() {
|
|
2199
|
+
if ( self::is_checkout_registration() ) {
|
|
2200
|
+
\WC()->session->set( self::CHECKOUT_REGISTRATION_FLAG, null );
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
/**
|
|
2205
|
+
* Conditionally reset the checkout registration flag from WC session if user exists.
|
|
2206
|
+
*
|
|
2207
|
+
* @param array $data Checkout data.
|
|
2208
|
+
* @param WP_Error $error Checkout errors.
|
|
2209
|
+
*/
|
|
2210
|
+
public static function maybe_reset_checkout_registration_flag( $data, $error ) {
|
|
2211
|
+
if ( ! self::is_checkout_registration() || ! isset( $data['billing_email'] ) ) {
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
if ( get_user_by( 'email', $data['billing_email'] ) ) {
|
|
2216
|
+
self::reset_checkout_registration_flag();
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
/**
|
|
2221
|
+
* Whether the WC session is for checkout registration.
|
|
2222
|
+
*/
|
|
2223
|
+
public static function is_checkout_registration() {
|
|
2224
|
+
return \WC()->session->get( self::CHECKOUT_REGISTRATION_FLAG, false );
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
/**
|
|
2228
|
+
* Conditionally adds the checkout registration order meta flag.
|
|
2229
|
+
*
|
|
2230
|
+
* @param WC_Order $order The order object.
|
|
2231
|
+
*
|
|
2232
|
+
* @return void.
|
|
2233
|
+
*/
|
|
2234
|
+
public static function maybe_add_checkout_registration_order_meta( $order ) {
|
|
2235
|
+
if ( ! self::is_modal_checkout() ) {
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
if ( self::is_checkout_registration() ) {
|
|
2240
|
+
$order->add_meta_data( self::CHECKOUT_REGISTRATION_ORDER_META_KEY, true, true );
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
/**
|
|
2245
|
+
* Trigger the subscriptions-limiting logic, using the user gleaned from the email address.
|
|
2246
|
+
*
|
|
2247
|
+
* @param bool $is_limited_for_user If the subscription should be limited.
|
|
2248
|
+
* @param int|WC_Product $product A WC_Product object or the ID of a product.
|
|
2249
|
+
* @param int $user_id The user ID.
|
|
2250
|
+
*/
|
|
2251
|
+
public static function subscriptions_product_limited_for_user( $is_limited_for_user, $product, $user_id ) {
|
|
2252
|
+
if ( $user_id !== 0 ) {
|
|
2253
|
+
return $is_limited_for_user;
|
|
2254
|
+
}
|
|
2255
|
+
$id_from_email = self::get_user_id_from_email();
|
|
2256
|
+
if ( $id_from_email ) {
|
|
2257
|
+
$is_limited_for_user = wcs_is_product_limited_for_user( $product, $id_from_email );
|
|
2258
|
+
$product_limitation = wcs_get_product_limitation( $product->get_id() );
|
|
2259
|
+
$callback = 'active' === $product_limitation ? 'get_subscription_limited_message' : 'get_subscription_limited_message_any';
|
|
2260
|
+
if ( $is_limited_for_user ) {
|
|
2261
|
+
add_filter( 'woocommerce_cart_item_removed_message', [ __CLASS__, $callback ], 10, 2 );
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
return $is_limited_for_user;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
/**
|
|
2268
|
+
* Whether modal checkout requires registration.
|
|
2269
|
+
*
|
|
2270
|
+
* @return bool
|
|
2271
|
+
*/
|
|
2272
|
+
public static function is_registration_required() {
|
|
2273
|
+
if ( ! class_exists( '\Newspack\Reader_Activation' ) ) {
|
|
2274
|
+
return false;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
return \Newspack\Reader_Activation::is_woocommerce_registration_required();
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
/**
|
|
2281
|
+
* Filters the WooCommerce registration privacy policy text.
|
|
2282
|
+
*
|
|
2283
|
+
* @param string $text Privacy policy text.
|
|
2284
|
+
* @param string $type Privacy policy text type.
|
|
2285
|
+
*
|
|
2286
|
+
* @return string Privacy policy text.
|
|
2287
|
+
*/
|
|
2288
|
+
public static function woocommerce_get_privacy_policy_text( $text, $type ) {
|
|
2289
|
+
if ( ! self::is_modal_checkout() || ! class_exists( '\Newspack\Reader_Activation' ) ) {
|
|
2290
|
+
return $text;
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
return \Newspack\Reader_Activation::get_checkout_privacy_policy_text();
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
/**
|
|
2297
|
+
* Get post checkout success message text.
|
|
2298
|
+
*
|
|
2299
|
+
* @return string Post checkout success message text.
|
|
2300
|
+
*/
|
|
2301
|
+
public static function get_post_checkout_success_text() {
|
|
2302
|
+
$text = sprintf(
|
|
2303
|
+
// Translators: %s is the site name.
|
|
2304
|
+
__( 'Thank you for supporting %s. Your transaction was completed successfully.', 'newspack-blocks' ),
|
|
2305
|
+
get_option( 'blogname' )
|
|
2306
|
+
);
|
|
2307
|
+
|
|
2308
|
+
if ( class_exists( '\Newspack\Reader_Activation' ) && \Newspack\Reader_Activation::is_enabled() ) {
|
|
2309
|
+
if ( ! self::is_registration_required() && self::is_checkout_registration() ) {
|
|
2310
|
+
$text = \Newspack\Reader_Activation::get_post_checkout_registration_success_text();
|
|
2311
|
+
} else {
|
|
2312
|
+
$text = \Newspack\Reader_Activation::get_post_checkout_success_text();
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
/**
|
|
2317
|
+
* Filters the post checkout success message text.
|
|
2318
|
+
*
|
|
2319
|
+
* @param string $text The post checkout success message text.
|
|
2320
|
+
*/
|
|
2321
|
+
return apply_filters( 'newspack_modal_checkout_success_text', $text );
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
Modal_Checkout::init();
|