@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.
Files changed (568) hide show
  1. package/.eslintrc.js +3 -0
  2. package/.hooks/pre-push +8 -0
  3. package/.nvmrc +1 -0
  4. package/.prettierignore +4 -0
  5. package/.prettierrc.js +5 -0
  6. package/.stylelintrc.js +3 -0
  7. package/AGENTS.md +275 -0
  8. package/CHANGELOG.md +3971 -0
  9. package/CLAUDE.md +1 -0
  10. package/README.md +43 -0
  11. package/babel.config.js +6 -0
  12. package/bin/install-wp-tests.sh +155 -0
  13. package/bin/update-translations.sh +13 -0
  14. package/block-list.json +12 -0
  15. package/composer.json +46 -0
  16. package/composer.lock +3632 -0
  17. package/dist/author-list/view-rtl.css +1 -0
  18. package/dist/author-list/view.asset.php +1 -0
  19. package/dist/author-list/view.css +1 -0
  20. package/dist/author-list/view.js +0 -0
  21. package/dist/author-profile/view-rtl.css +1 -0
  22. package/dist/author-profile/view.asset.php +1 -0
  23. package/dist/author-profile/view.css +1 -0
  24. package/dist/author-profile/view.js +0 -0
  25. package/dist/block_styles-rtl.css +2 -0
  26. package/dist/block_styles.asset.php +1 -0
  27. package/dist/block_styles.css +2 -0
  28. package/dist/block_styles.js +0 -0
  29. package/dist/blocks/author-list/block.json +89 -0
  30. package/dist/blocks/author-profile/block.json +80 -0
  31. package/dist/blocks/carousel/block.json +125 -0
  32. package/dist/blocks/checkout-button/block.json +117 -0
  33. package/dist/blocks/donate/block.json +103 -0
  34. package/dist/blocks/homepage-articles/block.json +260 -0
  35. package/dist/blocks/iframe/block.json +36 -0
  36. package/dist/carousel/view-rtl.css +2 -0
  37. package/dist/carousel/view.asset.php +1 -0
  38. package/dist/carousel/view.css +2 -0
  39. package/dist/carousel/view.js +3 -0
  40. package/dist/checkout-button/view-rtl.css +1 -0
  41. package/dist/checkout-button/view.asset.php +1 -0
  42. package/dist/checkout-button/view.css +1 -0
  43. package/dist/checkout-button/view.js +0 -0
  44. package/dist/donate/view-rtl.css +1 -0
  45. package/dist/donate/view.asset.php +1 -0
  46. package/dist/donate/view.css +1 -0
  47. package/dist/donate/view.js +1 -0
  48. package/dist/editor-rtl.css +66 -0
  49. package/dist/editor.asset.php +1 -0
  50. package/dist/editor.css +66 -0
  51. package/dist/editor.js +57 -0
  52. package/dist/frequencyBased-rtl.css +1 -0
  53. package/dist/frequencyBased.asset.php +1 -0
  54. package/dist/frequencyBased.css +1 -0
  55. package/dist/frequencyBased.js +1 -0
  56. package/dist/homepage-articles/view-rtl.css +1 -0
  57. package/dist/homepage-articles/view.asset.php +1 -0
  58. package/dist/homepage-articles/view.css +1 -0
  59. package/dist/homepage-articles/view.js +1 -0
  60. package/dist/iframe/view-rtl.css +1 -0
  61. package/dist/iframe/view.asset.php +1 -0
  62. package/dist/iframe/view.css +1 -0
  63. package/dist/iframe/view.js +1 -0
  64. package/dist/modal-rtl.css +1 -0
  65. package/dist/modal.asset.php +1 -0
  66. package/dist/modal.css +1 -0
  67. package/dist/modal.js +1 -0
  68. package/dist/modalCheckout-rtl.css +1 -0
  69. package/dist/modalCheckout.asset.php +1 -0
  70. package/dist/modalCheckout.css +1 -0
  71. package/dist/modalCheckout.js +1 -0
  72. package/dist/placeholder_blocks.asset.php +1 -0
  73. package/dist/placeholder_blocks.js +4 -0
  74. package/dist/tiersBased-rtl.css +1 -0
  75. package/dist/tiersBased.asset.php +1 -0
  76. package/dist/tiersBased.css +1 -0
  77. package/dist/tiersBased.js +1 -0
  78. package/includes/class-modal-checkout.php +2324 -0
  79. package/includes/class-newspack-blocks-api.php +347 -0
  80. package/includes/class-newspack-blocks-caching.php +291 -0
  81. package/includes/class-newspack-blocks-patterns.php +167 -0
  82. package/includes/class-newspack-blocks.php +1581 -0
  83. package/includes/modal-checkout/class-change-payment-gateway.php +86 -0
  84. package/includes/modal-checkout/class-checkout-data.php +406 -0
  85. package/includes/plugins/class-the-events-calendar.php +84 -0
  86. package/includes/tracking/class-data-events.php +83 -0
  87. package/languages/newspack-blocks-de_DE-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
  88. package/languages/newspack-blocks-de_DE-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
  89. package/languages/newspack-blocks-de_DE-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
  90. package/languages/newspack-blocks-de_DE-10754bc02d28d4301c103f26dbf519ce.json +1 -0
  91. package/languages/newspack-blocks-de_DE-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
  92. package/languages/newspack-blocks-de_DE-34e5c64f90b1444f3fc735376442eada.json +1 -0
  93. package/languages/newspack-blocks-de_DE-351fd022e077061b5796bf7042446bfc.json +1 -0
  94. package/languages/newspack-blocks-de_DE-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
  95. package/languages/newspack-blocks-de_DE-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
  96. package/languages/newspack-blocks-de_DE-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
  97. package/languages/newspack-blocks-de_DE-4f16e21047908d19937bc10ced63acd1.json +1 -0
  98. package/languages/newspack-blocks-de_DE-4fdea541976076f02d56139fb35e5b42.json +1 -0
  99. package/languages/newspack-blocks-de_DE-501b38ac90d35730a620fb0d483702fa.json +1 -0
  100. package/languages/newspack-blocks-de_DE-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
  101. package/languages/newspack-blocks-de_DE-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
  102. package/languages/newspack-blocks-de_DE-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
  103. package/languages/newspack-blocks-de_DE-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
  104. package/languages/newspack-blocks-de_DE-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
  105. package/languages/newspack-blocks-de_DE-727631509ad8eec8e2cbe740c6dad199.json +1 -0
  106. package/languages/newspack-blocks-de_DE-73c6d3bde805172d1993f75397e9832d.json +1 -0
  107. package/languages/newspack-blocks-de_DE-78456b164809d080adecb4d2b3895802.json +1 -0
  108. package/languages/newspack-blocks-de_DE-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
  109. package/languages/newspack-blocks-de_DE-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
  110. package/languages/newspack-blocks-de_DE-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
  111. package/languages/newspack-blocks-de_DE-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
  112. package/languages/newspack-blocks-de_DE-969286d51bb0afe10983b9aec317b5ee.json +1 -0
  113. package/languages/newspack-blocks-de_DE-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
  114. package/languages/newspack-blocks-de_DE-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
  115. package/languages/newspack-blocks-de_DE-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
  116. package/languages/newspack-blocks-de_DE-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
  117. package/languages/newspack-blocks-de_DE-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
  118. package/languages/newspack-blocks-de_DE-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
  119. package/languages/newspack-blocks-de_DE-bb66d96d450663284550bed5a3e9113e.json +1 -0
  120. package/languages/newspack-blocks-de_DE-c810378e74f20906b8193ea76adb6bc0.json +1 -0
  121. package/languages/newspack-blocks-de_DE-d3a1c55a07efd1a65e227bf120840752.json +1 -0
  122. package/languages/newspack-blocks-de_DE-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
  123. package/languages/newspack-blocks-de_DE-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
  124. package/languages/newspack-blocks-de_DE-dd56360b115d1b39c48033c1e0749a11.json +1 -0
  125. package/languages/newspack-blocks-de_DE-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
  126. package/languages/newspack-blocks-de_DE-e58126c278611ed6c17684ba8e7459b4.json +1 -0
  127. package/languages/newspack-blocks-de_DE-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
  128. package/languages/newspack-blocks-de_DE-eccbc51a43c04f59165364eda71e0be7.json +1 -0
  129. package/languages/newspack-blocks-de_DE-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
  130. package/languages/newspack-blocks-de_DE-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
  131. package/languages/newspack-blocks-de_DE-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
  132. package/languages/newspack-blocks-de_DE-f5f8db76788e4079ddfa743333708b88.json +1 -0
  133. package/languages/newspack-blocks-de_DE-f8b1589c450689398f90b179f47e74ee.json +1 -0
  134. package/languages/newspack-blocks-de_DE-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
  135. package/languages/newspack-blocks-de_DE-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
  136. package/languages/newspack-blocks-de_DE-fcc93143c1f2b74671f595454b971f44.json +1 -0
  137. package/languages/newspack-blocks-de_DE.mo +0 -0
  138. package/languages/newspack-blocks-de_DE.po +2088 -0
  139. package/languages/newspack-blocks-es_ES-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
  140. package/languages/newspack-blocks-es_ES-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
  141. package/languages/newspack-blocks-es_ES-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
  142. package/languages/newspack-blocks-es_ES-10754bc02d28d4301c103f26dbf519ce.json +1 -0
  143. package/languages/newspack-blocks-es_ES-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
  144. package/languages/newspack-blocks-es_ES-34e5c64f90b1444f3fc735376442eada.json +1 -0
  145. package/languages/newspack-blocks-es_ES-351fd022e077061b5796bf7042446bfc.json +1 -0
  146. package/languages/newspack-blocks-es_ES-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
  147. package/languages/newspack-blocks-es_ES-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
  148. package/languages/newspack-blocks-es_ES-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
  149. package/languages/newspack-blocks-es_ES-4f16e21047908d19937bc10ced63acd1.json +1 -0
  150. package/languages/newspack-blocks-es_ES-4fdea541976076f02d56139fb35e5b42.json +1 -0
  151. package/languages/newspack-blocks-es_ES-501b38ac90d35730a620fb0d483702fa.json +1 -0
  152. package/languages/newspack-blocks-es_ES-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
  153. package/languages/newspack-blocks-es_ES-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
  154. package/languages/newspack-blocks-es_ES-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
  155. package/languages/newspack-blocks-es_ES-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
  156. package/languages/newspack-blocks-es_ES-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
  157. package/languages/newspack-blocks-es_ES-727631509ad8eec8e2cbe740c6dad199.json +1 -0
  158. package/languages/newspack-blocks-es_ES-73c6d3bde805172d1993f75397e9832d.json +1 -0
  159. package/languages/newspack-blocks-es_ES-78456b164809d080adecb4d2b3895802.json +1 -0
  160. package/languages/newspack-blocks-es_ES-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
  161. package/languages/newspack-blocks-es_ES-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
  162. package/languages/newspack-blocks-es_ES-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
  163. package/languages/newspack-blocks-es_ES-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
  164. package/languages/newspack-blocks-es_ES-969286d51bb0afe10983b9aec317b5ee.json +1 -0
  165. package/languages/newspack-blocks-es_ES-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
  166. package/languages/newspack-blocks-es_ES-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
  167. package/languages/newspack-blocks-es_ES-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
  168. package/languages/newspack-blocks-es_ES-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
  169. package/languages/newspack-blocks-es_ES-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
  170. package/languages/newspack-blocks-es_ES-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
  171. package/languages/newspack-blocks-es_ES-bb66d96d450663284550bed5a3e9113e.json +1 -0
  172. package/languages/newspack-blocks-es_ES-c810378e74f20906b8193ea76adb6bc0.json +1 -0
  173. package/languages/newspack-blocks-es_ES-d3a1c55a07efd1a65e227bf120840752.json +1 -0
  174. package/languages/newspack-blocks-es_ES-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
  175. package/languages/newspack-blocks-es_ES-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
  176. package/languages/newspack-blocks-es_ES-dd56360b115d1b39c48033c1e0749a11.json +1 -0
  177. package/languages/newspack-blocks-es_ES-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
  178. package/languages/newspack-blocks-es_ES-e58126c278611ed6c17684ba8e7459b4.json +1 -0
  179. package/languages/newspack-blocks-es_ES-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
  180. package/languages/newspack-blocks-es_ES-eccbc51a43c04f59165364eda71e0be7.json +1 -0
  181. package/languages/newspack-blocks-es_ES-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
  182. package/languages/newspack-blocks-es_ES-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
  183. package/languages/newspack-blocks-es_ES-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
  184. package/languages/newspack-blocks-es_ES-f5f8db76788e4079ddfa743333708b88.json +1 -0
  185. package/languages/newspack-blocks-es_ES-f8b1589c450689398f90b179f47e74ee.json +1 -0
  186. package/languages/newspack-blocks-es_ES-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
  187. package/languages/newspack-blocks-es_ES-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
  188. package/languages/newspack-blocks-es_ES-fcc93143c1f2b74671f595454b971f44.json +1 -0
  189. package/languages/newspack-blocks-es_ES.mo +0 -0
  190. package/languages/newspack-blocks-es_ES.po +2080 -0
  191. package/languages/newspack-blocks-fr_BE-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
  192. package/languages/newspack-blocks-fr_BE-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
  193. package/languages/newspack-blocks-fr_BE-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
  194. package/languages/newspack-blocks-fr_BE-10754bc02d28d4301c103f26dbf519ce.json +1 -0
  195. package/languages/newspack-blocks-fr_BE-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
  196. package/languages/newspack-blocks-fr_BE-34e5c64f90b1444f3fc735376442eada.json +1 -0
  197. package/languages/newspack-blocks-fr_BE-351fd022e077061b5796bf7042446bfc.json +1 -0
  198. package/languages/newspack-blocks-fr_BE-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
  199. package/languages/newspack-blocks-fr_BE-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
  200. package/languages/newspack-blocks-fr_BE-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
  201. package/languages/newspack-blocks-fr_BE-4f16e21047908d19937bc10ced63acd1.json +1 -0
  202. package/languages/newspack-blocks-fr_BE-4fdea541976076f02d56139fb35e5b42.json +1 -0
  203. package/languages/newspack-blocks-fr_BE-501b38ac90d35730a620fb0d483702fa.json +1 -0
  204. package/languages/newspack-blocks-fr_BE-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
  205. package/languages/newspack-blocks-fr_BE-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
  206. package/languages/newspack-blocks-fr_BE-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
  207. package/languages/newspack-blocks-fr_BE-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
  208. package/languages/newspack-blocks-fr_BE-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
  209. package/languages/newspack-blocks-fr_BE-727631509ad8eec8e2cbe740c6dad199.json +1 -0
  210. package/languages/newspack-blocks-fr_BE-73c6d3bde805172d1993f75397e9832d.json +1 -0
  211. package/languages/newspack-blocks-fr_BE-78456b164809d080adecb4d2b3895802.json +1 -0
  212. package/languages/newspack-blocks-fr_BE-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
  213. package/languages/newspack-blocks-fr_BE-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
  214. package/languages/newspack-blocks-fr_BE-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
  215. package/languages/newspack-blocks-fr_BE-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
  216. package/languages/newspack-blocks-fr_BE-969286d51bb0afe10983b9aec317b5ee.json +1 -0
  217. package/languages/newspack-blocks-fr_BE-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
  218. package/languages/newspack-blocks-fr_BE-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
  219. package/languages/newspack-blocks-fr_BE-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
  220. package/languages/newspack-blocks-fr_BE-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
  221. package/languages/newspack-blocks-fr_BE-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
  222. package/languages/newspack-blocks-fr_BE-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
  223. package/languages/newspack-blocks-fr_BE-bb66d96d450663284550bed5a3e9113e.json +1 -0
  224. package/languages/newspack-blocks-fr_BE-c810378e74f20906b8193ea76adb6bc0.json +1 -0
  225. package/languages/newspack-blocks-fr_BE-d3a1c55a07efd1a65e227bf120840752.json +1 -0
  226. package/languages/newspack-blocks-fr_BE-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
  227. package/languages/newspack-blocks-fr_BE-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
  228. package/languages/newspack-blocks-fr_BE-dd56360b115d1b39c48033c1e0749a11.json +1 -0
  229. package/languages/newspack-blocks-fr_BE-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
  230. package/languages/newspack-blocks-fr_BE-e58126c278611ed6c17684ba8e7459b4.json +1 -0
  231. package/languages/newspack-blocks-fr_BE-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
  232. package/languages/newspack-blocks-fr_BE-eccbc51a43c04f59165364eda71e0be7.json +1 -0
  233. package/languages/newspack-blocks-fr_BE-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
  234. package/languages/newspack-blocks-fr_BE-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
  235. package/languages/newspack-blocks-fr_BE-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
  236. package/languages/newspack-blocks-fr_BE-f5f8db76788e4079ddfa743333708b88.json +1 -0
  237. package/languages/newspack-blocks-fr_BE-f8b1589c450689398f90b179f47e74ee.json +1 -0
  238. package/languages/newspack-blocks-fr_BE-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
  239. package/languages/newspack-blocks-fr_BE-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
  240. package/languages/newspack-blocks-fr_BE-fcc93143c1f2b74671f595454b971f44.json +1 -0
  241. package/languages/newspack-blocks-fr_BE.mo +0 -0
  242. package/languages/newspack-blocks-fr_BE.po +2079 -0
  243. package/languages/newspack-blocks-nb_NO-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
  244. package/languages/newspack-blocks-nb_NO-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
  245. package/languages/newspack-blocks-nb_NO-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
  246. package/languages/newspack-blocks-nb_NO-10754bc02d28d4301c103f26dbf519ce.json +1 -0
  247. package/languages/newspack-blocks-nb_NO-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
  248. package/languages/newspack-blocks-nb_NO-34e5c64f90b1444f3fc735376442eada.json +1 -0
  249. package/languages/newspack-blocks-nb_NO-351fd022e077061b5796bf7042446bfc.json +1 -0
  250. package/languages/newspack-blocks-nb_NO-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
  251. package/languages/newspack-blocks-nb_NO-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
  252. package/languages/newspack-blocks-nb_NO-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
  253. package/languages/newspack-blocks-nb_NO-4f16e21047908d19937bc10ced63acd1.json +1 -0
  254. package/languages/newspack-blocks-nb_NO-4fdea541976076f02d56139fb35e5b42.json +1 -0
  255. package/languages/newspack-blocks-nb_NO-501b38ac90d35730a620fb0d483702fa.json +1 -0
  256. package/languages/newspack-blocks-nb_NO-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
  257. package/languages/newspack-blocks-nb_NO-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
  258. package/languages/newspack-blocks-nb_NO-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
  259. package/languages/newspack-blocks-nb_NO-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
  260. package/languages/newspack-blocks-nb_NO-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
  261. package/languages/newspack-blocks-nb_NO-73c6d3bde805172d1993f75397e9832d.json +1 -0
  262. package/languages/newspack-blocks-nb_NO-78456b164809d080adecb4d2b3895802.json +1 -0
  263. package/languages/newspack-blocks-nb_NO-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
  264. package/languages/newspack-blocks-nb_NO-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
  265. package/languages/newspack-blocks-nb_NO-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
  266. package/languages/newspack-blocks-nb_NO-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
  267. package/languages/newspack-blocks-nb_NO-969286d51bb0afe10983b9aec317b5ee.json +1 -0
  268. package/languages/newspack-blocks-nb_NO-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
  269. package/languages/newspack-blocks-nb_NO-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
  270. package/languages/newspack-blocks-nb_NO-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
  271. package/languages/newspack-blocks-nb_NO-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
  272. package/languages/newspack-blocks-nb_NO-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
  273. package/languages/newspack-blocks-nb_NO-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
  274. package/languages/newspack-blocks-nb_NO-bb66d96d450663284550bed5a3e9113e.json +1 -0
  275. package/languages/newspack-blocks-nb_NO-c810378e74f20906b8193ea76adb6bc0.json +1 -0
  276. package/languages/newspack-blocks-nb_NO-d3a1c55a07efd1a65e227bf120840752.json +1 -0
  277. package/languages/newspack-blocks-nb_NO-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
  278. package/languages/newspack-blocks-nb_NO-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
  279. package/languages/newspack-blocks-nb_NO-dd56360b115d1b39c48033c1e0749a11.json +1 -0
  280. package/languages/newspack-blocks-nb_NO-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
  281. package/languages/newspack-blocks-nb_NO-e58126c278611ed6c17684ba8e7459b4.json +1 -0
  282. package/languages/newspack-blocks-nb_NO-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
  283. package/languages/newspack-blocks-nb_NO-eccbc51a43c04f59165364eda71e0be7.json +1 -0
  284. package/languages/newspack-blocks-nb_NO-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
  285. package/languages/newspack-blocks-nb_NO-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
  286. package/languages/newspack-blocks-nb_NO-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
  287. package/languages/newspack-blocks-nb_NO-f5f8db76788e4079ddfa743333708b88.json +1 -0
  288. package/languages/newspack-blocks-nb_NO-f8b1589c450689398f90b179f47e74ee.json +1 -0
  289. package/languages/newspack-blocks-nb_NO-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
  290. package/languages/newspack-blocks-nb_NO-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
  291. package/languages/newspack-blocks-nb_NO-fcc93143c1f2b74671f595454b971f44.json +1 -0
  292. package/languages/newspack-blocks-nb_NO.mo +0 -0
  293. package/languages/newspack-blocks-nb_NO.po +2078 -0
  294. package/languages/newspack-blocks-pt_PT-01a5b44b8bc8d20f62541de420aa61ab.json +1 -0
  295. package/languages/newspack-blocks-pt_PT-0662222bf15e7a1a7b74db2dabb48d6c.json +1 -0
  296. package/languages/newspack-blocks-pt_PT-0c8dad524e2a57cee4f8efb6e35387c1.json +1 -0
  297. package/languages/newspack-blocks-pt_PT-10754bc02d28d4301c103f26dbf519ce.json +1 -0
  298. package/languages/newspack-blocks-pt_PT-2d52b39fdbc5d6c94b3514803f3720b8.json +1 -0
  299. package/languages/newspack-blocks-pt_PT-34e5c64f90b1444f3fc735376442eada.json +1 -0
  300. package/languages/newspack-blocks-pt_PT-351fd022e077061b5796bf7042446bfc.json +1 -0
  301. package/languages/newspack-blocks-pt_PT-37552bb09e2a9fceec1970e3c6d46557.json +1 -0
  302. package/languages/newspack-blocks-pt_PT-4b2ccb4e4dc8b3491228b2feb54872f2.json +1 -0
  303. package/languages/newspack-blocks-pt_PT-4cecf783e091d36284a3e0cdafcd0fd5.json +1 -0
  304. package/languages/newspack-blocks-pt_PT-4f16e21047908d19937bc10ced63acd1.json +1 -0
  305. package/languages/newspack-blocks-pt_PT-4fdea541976076f02d56139fb35e5b42.json +1 -0
  306. package/languages/newspack-blocks-pt_PT-501b38ac90d35730a620fb0d483702fa.json +1 -0
  307. package/languages/newspack-blocks-pt_PT-53e2a1d5945b8d2b1c35e81ae1e532f3.json +1 -0
  308. package/languages/newspack-blocks-pt_PT-5d4055f484eeb00e3ea0f9d8aace0897.json +1 -0
  309. package/languages/newspack-blocks-pt_PT-5f70538e0223bc8a05b922cba67da6fb.json +1 -0
  310. package/languages/newspack-blocks-pt_PT-6c2e53bab28419c30e1eaee70ba599cf.json +1 -0
  311. package/languages/newspack-blocks-pt_PT-6ed95fb4873e6e2b81351177a44995f6.json +1 -0
  312. package/languages/newspack-blocks-pt_PT-727631509ad8eec8e2cbe740c6dad199.json +1 -0
  313. package/languages/newspack-blocks-pt_PT-73c6d3bde805172d1993f75397e9832d.json +1 -0
  314. package/languages/newspack-blocks-pt_PT-78456b164809d080adecb4d2b3895802.json +1 -0
  315. package/languages/newspack-blocks-pt_PT-7b1aa64ce2d962decc04666ab86c53de.json +1 -0
  316. package/languages/newspack-blocks-pt_PT-7c29764d5ef91723f5ce454f66431b9e.json +1 -0
  317. package/languages/newspack-blocks-pt_PT-912a2876091ef0dca9b26f3cfc01fc9c.json +1 -0
  318. package/languages/newspack-blocks-pt_PT-91a7ac8017d6e2159be1c5a3c1e372e4.json +1 -0
  319. package/languages/newspack-blocks-pt_PT-969286d51bb0afe10983b9aec317b5ee.json +1 -0
  320. package/languages/newspack-blocks-pt_PT-9ef9b2c60c897ad79f92951e6e9949a1.json +1 -0
  321. package/languages/newspack-blocks-pt_PT-a822c3d210c89af3cb7da28eaaef929c.json +1 -0
  322. package/languages/newspack-blocks-pt_PT-aa9f9057c77a46b31d7e325a4322f2da.json +1 -0
  323. package/languages/newspack-blocks-pt_PT-b6d3cfc30bb16d88d7bc5384bc775543.json +1 -0
  324. package/languages/newspack-blocks-pt_PT-b712270cd4eb3cae7899b50b57bdd576.json +1 -0
  325. package/languages/newspack-blocks-pt_PT-babcc0ca24e7f0145b1c8f647049f085.json +1 -0
  326. package/languages/newspack-blocks-pt_PT-bb66d96d450663284550bed5a3e9113e.json +1 -0
  327. package/languages/newspack-blocks-pt_PT-c810378e74f20906b8193ea76adb6bc0.json +1 -0
  328. package/languages/newspack-blocks-pt_PT-d3a1c55a07efd1a65e227bf120840752.json +1 -0
  329. package/languages/newspack-blocks-pt_PT-d5f23a52ecbfd492ebf819c14206a9e2.json +1 -0
  330. package/languages/newspack-blocks-pt_PT-d684e5c5ac51934ba20811c2f588e1d5.json +1 -0
  331. package/languages/newspack-blocks-pt_PT-dd56360b115d1b39c48033c1e0749a11.json +1 -0
  332. package/languages/newspack-blocks-pt_PT-e0e4434aee4db01e71268ce3edf1dd97.json +1 -0
  333. package/languages/newspack-blocks-pt_PT-e58126c278611ed6c17684ba8e7459b4.json +1 -0
  334. package/languages/newspack-blocks-pt_PT-ea3e2a660753c7bfa13b5bbd8a46bdd0.json +1 -0
  335. package/languages/newspack-blocks-pt_PT-eccbc51a43c04f59165364eda71e0be7.json +1 -0
  336. package/languages/newspack-blocks-pt_PT-eeb28f99adedd5fad3081d2756d6f4a4.json +1 -0
  337. package/languages/newspack-blocks-pt_PT-f03802d9ac1ae8f3b85caee4347b93a7.json +1 -0
  338. package/languages/newspack-blocks-pt_PT-f32a4d8bd8f1f1e03b6523dfaa4c9f73.json +1 -0
  339. package/languages/newspack-blocks-pt_PT-f5f8db76788e4079ddfa743333708b88.json +1 -0
  340. package/languages/newspack-blocks-pt_PT-f8b1589c450689398f90b179f47e74ee.json +1 -0
  341. package/languages/newspack-blocks-pt_PT-f9d0b05d4d6ddd3273f1f3fb2eb2ca50.json +1 -0
  342. package/languages/newspack-blocks-pt_PT-fbe7f8c598cf05d4603ba49fec909ded.json +1 -0
  343. package/languages/newspack-blocks-pt_PT-fcc93143c1f2b74671f595454b971f44.json +1 -0
  344. package/languages/newspack-blocks-pt_PT.mo +0 -0
  345. package/languages/newspack-blocks-pt_PT.po +2078 -0
  346. package/languages/newspack-blocks.pot +2370 -0
  347. package/newspack-blocks.php +96 -0
  348. package/package.json +64 -0
  349. package/phpcs.xml +38 -0
  350. package/release.config.js +1 -0
  351. package/src/assets/placeholder-1024x536.jpg +0 -0
  352. package/src/assets/placeholder-600x800.jpg +0 -0
  353. package/src/assets/placeholder-800x600.jpg +0 -0
  354. package/src/assets/placeholder-800x800.jpg +0 -0
  355. package/src/assets/placeholder-donations-cover.jpg +0 -0
  356. package/src/assets/placeholder-donations-image.jpg +0 -0
  357. package/src/assets/placeholder-subscribe-cover.jpg +0 -0
  358. package/src/assets/placeholder-subscribe-image.jpg +0 -0
  359. package/src/block-patterns/donations-1.php +13 -0
  360. package/src/block-patterns/donations-2.php +13 -0
  361. package/src/block-patterns/donations-3.php +13 -0
  362. package/src/block-patterns/donations-4.php +13 -0
  363. package/src/block-patterns/donations-5.php +13 -0
  364. package/src/block-patterns/homepage-posts-1.php +13 -0
  365. package/src/block-patterns/homepage-posts-10.php +13 -0
  366. package/src/block-patterns/homepage-posts-11.php +13 -0
  367. package/src/block-patterns/homepage-posts-12.php +13 -0
  368. package/src/block-patterns/homepage-posts-13.php +13 -0
  369. package/src/block-patterns/homepage-posts-14.php +13 -0
  370. package/src/block-patterns/homepage-posts-15.php +13 -0
  371. package/src/block-patterns/homepage-posts-16.php +13 -0
  372. package/src/block-patterns/homepage-posts-17.php +13 -0
  373. package/src/block-patterns/homepage-posts-18.php +13 -0
  374. package/src/block-patterns/homepage-posts-19.php +13 -0
  375. package/src/block-patterns/homepage-posts-2.php +13 -0
  376. package/src/block-patterns/homepage-posts-20.php +13 -0
  377. package/src/block-patterns/homepage-posts-21.php +13 -0
  378. package/src/block-patterns/homepage-posts-22.php +13 -0
  379. package/src/block-patterns/homepage-posts-23.php +13 -0
  380. package/src/block-patterns/homepage-posts-24.php +13 -0
  381. package/src/block-patterns/homepage-posts-25.php +13 -0
  382. package/src/block-patterns/homepage-posts-26.php +13 -0
  383. package/src/block-patterns/homepage-posts-27.php +13 -0
  384. package/src/block-patterns/homepage-posts-28.php +13 -0
  385. package/src/block-patterns/homepage-posts-29.php +13 -0
  386. package/src/block-patterns/homepage-posts-3.php +13 -0
  387. package/src/block-patterns/homepage-posts-30.php +13 -0
  388. package/src/block-patterns/homepage-posts-31.php +13 -0
  389. package/src/block-patterns/homepage-posts-4.php +13 -0
  390. package/src/block-patterns/homepage-posts-5.php +13 -0
  391. package/src/block-patterns/homepage-posts-6.php +13 -0
  392. package/src/block-patterns/homepage-posts-7.php +13 -0
  393. package/src/block-patterns/homepage-posts-8.php +13 -0
  394. package/src/block-patterns/homepage-posts-9.php +13 -0
  395. package/src/block-patterns/subscribe-1.php +13 -0
  396. package/src/block-patterns/subscribe-2.php +13 -0
  397. package/src/block-patterns/subscribe-3.php +13 -0
  398. package/src/block-patterns/subscribe-4.php +13 -0
  399. package/src/block-patterns/subscribe-5.php +13 -0
  400. package/src/block-patterns/subscribe-6.php +13 -0
  401. package/src/block-patterns/subscribe-7.php +13 -0
  402. package/src/block-styles/core/columns/editor.scss +90 -0
  403. package/src/block-styles/core/columns/index.js +20 -0
  404. package/src/block-styles/core/columns/view.scss +131 -0
  405. package/src/block-styles/core/group/editor.scss +24 -0
  406. package/src/block-styles/core/group/index.js +25 -0
  407. package/src/block-styles/core/group/view.scss +13 -0
  408. package/src/block-styles/view.js +5 -0
  409. package/src/blocks/author-list/block.json +84 -0
  410. package/src/blocks/author-list/class-wp-rest-newspack-author-list-controller.php +381 -0
  411. package/src/blocks/author-list/edit.js +456 -0
  412. package/src/blocks/author-list/editor.js +7 -0
  413. package/src/blocks/author-list/editor.scss +1 -0
  414. package/src/blocks/author-list/index.js +60 -0
  415. package/src/blocks/author-list/view.js +5 -0
  416. package/src/blocks/author-list/view.php +180 -0
  417. package/src/blocks/author-list/view.scss +46 -0
  418. package/src/blocks/author-profile/README.md +105 -0
  419. package/src/blocks/author-profile/block.json +77 -0
  420. package/src/blocks/author-profile/class-wp-rest-newspack-authors-controller.php +618 -0
  421. package/src/blocks/author-profile/context.js +26 -0
  422. package/src/blocks/author-profile/edit.js +1031 -0
  423. package/src/blocks/author-profile/editor.js +7 -0
  424. package/src/blocks/author-profile/editor.scss +61 -0
  425. package/src/blocks/author-profile/index.js +66 -0
  426. package/src/blocks/author-profile/single-author.js +106 -0
  427. package/src/blocks/author-profile/templates.js +263 -0
  428. package/src/blocks/author-profile/variations.js +86 -0
  429. package/src/blocks/author-profile/view.js +5 -0
  430. package/src/blocks/author-profile/view.php +501 -0
  431. package/src/blocks/author-profile/view.scss +159 -0
  432. package/src/blocks/carousel/block.json +121 -0
  433. package/src/blocks/carousel/create-swiper.js +230 -0
  434. package/src/blocks/carousel/edit.js +469 -0
  435. package/src/blocks/carousel/editor.js +7 -0
  436. package/src/blocks/carousel/editor.scss +54 -0
  437. package/src/blocks/carousel/index.js +55 -0
  438. package/src/blocks/carousel/view.js +49 -0
  439. package/src/blocks/carousel/view.php +417 -0
  440. package/src/blocks/carousel/view.scss +397 -0
  441. package/src/blocks/checkout-button/block.json +117 -0
  442. package/src/blocks/checkout-button/deprecated.js +81 -0
  443. package/src/blocks/checkout-button/edit.js +385 -0
  444. package/src/blocks/checkout-button/edit.scss +67 -0
  445. package/src/blocks/checkout-button/editor.js +19 -0
  446. package/src/blocks/checkout-button/index.js +32 -0
  447. package/src/blocks/checkout-button/view.js +4 -0
  448. package/src/blocks/checkout-button/view.php +178 -0
  449. package/src/blocks/checkout-button/view.scss +39 -0
  450. package/src/blocks/donate/block.json +103 -0
  451. package/src/blocks/donate/consts.ts +25 -0
  452. package/src/blocks/donate/edit/FrequencyBasedLayout.tsx +255 -0
  453. package/src/blocks/donate/edit/TierBasedLayout.tsx +133 -0
  454. package/src/blocks/donate/edit/components/AmountValueInput.tsx +62 -0
  455. package/src/blocks/donate/edit/components/index.tsx +1 -0
  456. package/src/blocks/donate/edit/index.tsx +445 -0
  457. package/src/blocks/donate/editor.js +7 -0
  458. package/src/blocks/donate/frequency-based/index.ts +135 -0
  459. package/src/blocks/donate/frequency-based/style.scss +245 -0
  460. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-base.php +225 -0
  461. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-frequency-based.php +341 -0
  462. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-tiers-based.php +184 -0
  463. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer.php +117 -0
  464. package/src/blocks/donate/index.js +72 -0
  465. package/src/blocks/donate/styles/editor.scss +230 -0
  466. package/src/blocks/donate/styles/style-variations.scss +792 -0
  467. package/src/blocks/donate/styles/view.scss +45 -0
  468. package/src/blocks/donate/tiers-based/index.ts +36 -0
  469. package/src/blocks/donate/tiers-based/slider.ts +64 -0
  470. package/src/blocks/donate/tiers-based/style.scss +185 -0
  471. package/src/blocks/donate/tiers-based/types.ts +3 -0
  472. package/src/blocks/donate/tiers-based/utils.test.js +38 -0
  473. package/src/blocks/donate/tiers-based/utils.ts +21 -0
  474. package/src/blocks/donate/tiers-based/view.ts +132 -0
  475. package/src/blocks/donate/types.ts +96 -0
  476. package/src/blocks/donate/utils.ts +108 -0
  477. package/src/blocks/donate/view.php +29 -0
  478. package/src/blocks/donate/view.ts +44 -0
  479. package/src/blocks/homepage-articles/block.json +260 -0
  480. package/src/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php +231 -0
  481. package/src/blocks/homepage-articles/edit.tsx +730 -0
  482. package/src/blocks/homepage-articles/editor.js +16 -0
  483. package/src/blocks/homepage-articles/editor.scss +226 -0
  484. package/src/blocks/homepage-articles/index.js +102 -0
  485. package/src/blocks/homepage-articles/store.js +193 -0
  486. package/src/blocks/homepage-articles/templates/article.php +290 -0
  487. package/src/blocks/homepage-articles/templates/articles-list.php +21 -0
  488. package/src/blocks/homepage-articles/templates/articles-loop.php +35 -0
  489. package/src/blocks/homepage-articles/utils.ts +270 -0
  490. package/src/blocks/homepage-articles/view.js +242 -0
  491. package/src/blocks/homepage-articles/view.php +561 -0
  492. package/src/blocks/homepage-articles/view.scss +784 -0
  493. package/src/blocks/iframe/block.json +36 -0
  494. package/src/blocks/iframe/class-wp-rest-newspack-iframe-controller.php +586 -0
  495. package/src/blocks/iframe/edit.js +232 -0
  496. package/src/blocks/iframe/editor.js +7 -0
  497. package/src/blocks/iframe/editor.scss +84 -0
  498. package/src/blocks/iframe/iframe-placeholder.js +166 -0
  499. package/src/blocks/iframe/index.js +54 -0
  500. package/src/blocks/iframe/view.js +49 -0
  501. package/src/blocks/iframe/view.php +116 -0
  502. package/src/blocks/iframe/view.scss +9 -0
  503. package/src/blocks/shared/author.js +47 -0
  504. package/src/blocks/video-playlist/edit.js +222 -0
  505. package/src/blocks/video-playlist/editor.js +7 -0
  506. package/src/blocks/video-playlist/editor.scss +23 -0
  507. package/src/blocks/video-playlist/index.js +54 -0
  508. package/src/blocks/video-playlist/view.php +188 -0
  509. package/src/components/autocomplete-tokenfield.js +189 -0
  510. package/src/components/autocomplete-tokenfield.scss +27 -0
  511. package/src/components/editor-panels.js +90 -0
  512. package/src/components/query-controls.js +450 -0
  513. package/src/components/redirect-after-success.tsx +50 -0
  514. package/src/modal-checkout/accessibility.js +73 -0
  515. package/src/modal-checkout/analytics/ga4/README.md +45 -0
  516. package/src/modal-checkout/analytics/ga4/checkout-attempt.js +18 -0
  517. package/src/modal-checkout/analytics/ga4/checkout-success.js +17 -0
  518. package/src/modal-checkout/analytics/ga4/dismissed.js +17 -0
  519. package/src/modal-checkout/analytics/ga4/loaded.js +17 -0
  520. package/src/modal-checkout/analytics/ga4/opened.js +37 -0
  521. package/src/modal-checkout/analytics/ga4/pagination.js +59 -0
  522. package/src/modal-checkout/analytics/ga4/utils/index.js +64 -0
  523. package/src/modal-checkout/analytics/index.js +6 -0
  524. package/src/modal-checkout/checkout.scss +1064 -0
  525. package/src/modal-checkout/index.js +929 -0
  526. package/src/modal-checkout/modal.js +983 -0
  527. package/src/modal-checkout/modal.scss +265 -0
  528. package/src/modal-checkout/templates/empty-html-add-recipient.php +15 -0
  529. package/src/modal-checkout/templates/empty-order-details.php +16 -0
  530. package/src/modal-checkout/templates/form-change-payment-method.php +99 -0
  531. package/src/modal-checkout/templates/form-checkout.php +74 -0
  532. package/src/modal-checkout/templates/form-coupon.php +22 -0
  533. package/src/modal-checkout/templates/form-gift-subscription.php +34 -0
  534. package/src/modal-checkout/templates/payment-method.php +29 -0
  535. package/src/modal-checkout/templates/thankyou.php +94 -0
  536. package/src/modal-checkout/utils.js +309 -0
  537. package/src/setup/block-styles.js +2 -0
  538. package/src/setup/category.js +18 -0
  539. package/src/setup/editor.js +7 -0
  540. package/src/setup/editor.scss +56 -0
  541. package/src/setup/newspack-logo.js +26 -0
  542. package/src/setup/placeholder-blocks.js +84 -0
  543. package/src/setup/unregister-blocks.js +14 -0
  544. package/src/shared/authors.php +63 -0
  545. package/src/shared/js/newspack-icon.js +31 -0
  546. package/src/shared/js/utils.js +50 -0
  547. package/src/shared/sass/_mixins.scss +42 -0
  548. package/src/shared/sass/_placeholder.scss +5 -0
  549. package/src/shared/sass/_preview.scss +12 -0
  550. package/src/shared/sass/_variables.scss +24 -0
  551. package/src/templates/author-profile-card.php +145 -0
  552. package/src/types/@wordpress/block-editor.d.ts +1 -0
  553. package/src/types/@wordpress/components.d.ts +1 -0
  554. package/src/types/index.d.ts +170 -0
  555. package/src/types/newspack-components.d.ts +7 -0
  556. package/tsconfig.json +7 -0
  557. package/vendor/autoload.php +22 -0
  558. package/vendor/composer/ClassLoader.php +579 -0
  559. package/vendor/composer/InstalledVersions.php +396 -0
  560. package/vendor/composer/LICENSE +21 -0
  561. package/vendor/composer/autoload_classmap.php +10 -0
  562. package/vendor/composer/autoload_namespaces.php +9 -0
  563. package/vendor/composer/autoload_psr4.php +9 -0
  564. package/vendor/composer/autoload_real.php +36 -0
  565. package/vendor/composer/autoload_static.php +20 -0
  566. package/vendor/composer/installed.json +5 -0
  567. package/vendor/composer/installed.php +23 -0
  568. package/webpack.config.js +82 -0
@@ -0,0 +1,1581 @@
1
+ <?php
2
+ /**
3
+ * Newspack blocks functionality
4
+ *
5
+ * @package Newspack_Blocks
6
+ */
7
+
8
+ /**
9
+ * Newspack blocks functionality
10
+ */
11
+ class Newspack_Blocks {
12
+
13
+ /**
14
+ * Script handles.
15
+ */
16
+ const SCRIPT_HANDLES = [
17
+ 'modal-checkout' => 'newspack-blocks-donate-modal-checkout',
18
+ 'modal-checkout-block' => 'newspack-blocks-donate-modal-checkout-block',
19
+ 'frequency-based' => 'newspack-blocks-donate-frequency-based',
20
+ 'tiers-based' => 'newspack-blocks-donate-tiers-based',
21
+ ];
22
+
23
+ /**
24
+ * Add hooks and filters.
25
+ */
26
+ public static function init() {
27
+ add_action( 'after_setup_theme', [ __CLASS__, 'add_image_sizes' ] );
28
+ add_post_type_support( 'post', 'newspack_blocks' );
29
+ add_post_type_support( 'page', 'newspack_blocks' );
30
+ add_action( 'jetpack_register_gutenberg_extensions', [ __CLASS__, 'disable_jetpack_donate' ], 99 );
31
+ add_filter( 'the_content', [ __CLASS__, 'hide_post_content_when_iframe_block_is_fullscreen' ] );
32
+ add_filter( 'body_class', [ __CLASS__, 'add_body_classes' ] );
33
+ add_filter( 'admin_body_class', [ __CLASS__, 'add_body_classes' ] );
34
+
35
+ /**
36
+ * Disable NextGEN's `C_NextGen_Shortcode_Manager`.
37
+ *
38
+ * The way it currently parses `the_content` conflicts with the REST API
39
+ * request to save a post containing a Homepage Posts block. This is due to
40
+ * how it uses output buffering through `ob_start()` on REST requests.
41
+ *
42
+ * @link https://plugins.trac.wordpress.org/browser/nextgen-gallery/tags/3.23/non_pope/class.nextgen_shortcode_manager.php#L193.
43
+ */
44
+ if ( ! defined( 'NGG_DISABLE_SHORTCODE_MANAGER' ) ) {
45
+ define( 'NGG_DISABLE_SHORTCODE_MANAGER', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Hide the post content when it contains an iframe block that is set to fullscreen mode.
51
+ *
52
+ * @param string $content post content from the_content hook.
53
+ * @return string the post content.
54
+ */
55
+ public static function hide_post_content_when_iframe_block_is_fullscreen( $content ) {
56
+ if ( has_block( 'newspack-blocks/iframe' ) ) {
57
+ $blocks = parse_blocks( get_post()->post_content );
58
+
59
+ foreach ( $blocks as $block ) {
60
+ if ( 'newspack-blocks/iframe' === $block['blockName']
61
+ && is_array( $block['attrs'] )
62
+ && array_key_exists( 'isFullScreen', $block['attrs'] )
63
+ && $block['attrs']['isFullScreen']
64
+ ) {
65
+ // we don't need the post content since the iframe will be fullscreen.
66
+ $content = render_block( $block );
67
+
68
+ add_filter(
69
+ 'body_class',
70
+ function( $classes ) {
71
+ $classes[] = 'newspack-post-with-fullscreen-iframe';
72
+ return $classes;
73
+ }
74
+ );
75
+
76
+ // we don't need to show Newspack popups since the iframe will take over them.
77
+ add_filter( 'newspack_popups_assess_has_disabled_popups', '__return_true' );
78
+ }
79
+ }
80
+ }
81
+
82
+ return $content;
83
+ }
84
+
85
+ /**
86
+ * Body class.
87
+ *
88
+ * @param string|array $classes Array or string of body class names.
89
+ * @return string|array Modified array or string of body class names.
90
+ */
91
+ public static function add_body_classes( $classes ) {
92
+ if ( wp_is_block_theme() ) {
93
+ // Handle string (admin) vs array (frontend) cases.
94
+ if ( is_string( $classes ) ) {
95
+ $classes .= ' is-block-theme ';
96
+ } else {
97
+ $classes[] = 'is-block-theme';
98
+ }
99
+ }
100
+
101
+ return $classes;
102
+ }
103
+
104
+ /**
105
+ * Gather dependencies and paths needed for script enqueuing.
106
+ *
107
+ * @param string $script_path Path to the script relative to plugin root.
108
+ *
109
+ * @return array Associative array including dependency array, version, and web path to the script. Returns false if script doesn't exist.
110
+ */
111
+ public static function script_enqueue_helper( $script_path ) {
112
+ $local_path = NEWSPACK_BLOCKS__PLUGIN_DIR . $script_path;
113
+ if ( ! file_exists( $local_path ) ) {
114
+ return false;
115
+ }
116
+
117
+ $path_info = pathinfo( $local_path );
118
+ $asset_path = $path_info['dirname'] . '/' . $path_info['filename'] . '.asset.php';
119
+ $script_data = file_exists( $asset_path )
120
+ ? require $asset_path
121
+ : array(
122
+ 'dependencies' => [ 'wp-a11y', 'wp-escape-html', 'wp-i18n', 'wp-polyfill' ],
123
+ 'version' => filemtime( $local_path ),
124
+ );
125
+
126
+ $script_data['script_path'] = plugins_url( $script_path, NEWSPACK_BLOCKS__PLUGIN_FILE );
127
+ return $script_data;
128
+ }
129
+
130
+ /**
131
+ * Enqueue placeholder blocks assets.
132
+ */
133
+ public static function enqueue_placeholder_blocks_assets() {
134
+ if ( ! is_admin() ) {
135
+ // In non-editor environment, do nothing.
136
+ return;
137
+ }
138
+ $script_data = self::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'placeholder_blocks.js' );
139
+ if ( $script_data ) {
140
+ wp_enqueue_script(
141
+ 'newspack-blocks-placeholder-blocks',
142
+ $script_data['script_path'],
143
+ $script_data['dependencies'],
144
+ $script_data['version'],
145
+ true
146
+ );
147
+ wp_set_script_translations(
148
+ 'newspack-blocks-placeholder-blocks',
149
+ 'newspack-blocks',
150
+ plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) . 'languages'
151
+ );
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Gets the list of custom taxonomies that will be available for filtering in the blocks
157
+ *
158
+ * @return array Array of custom taxonomies where each taxonomy is an array with slug and label keys.
159
+ */
160
+ public static function get_custom_taxonomies() {
161
+ $custom_taxonomies = array_map(
162
+ function( $tax ) {
163
+ if ( ! empty( array_intersect( [ 'post', 'page' ], $tax->object_type ) ) ) {
164
+ return [
165
+ 'slug' => $tax->name,
166
+ 'label' => $tax->label,
167
+ ];
168
+ }
169
+ },
170
+ get_taxonomies(
171
+ [
172
+ 'public' => true,
173
+ '_builtin' => false,
174
+ 'show_in_rest' => true,
175
+ ],
176
+ 'objects'
177
+ )
178
+ );
179
+ $custom_taxonomies = array_values(
180
+ array_filter(
181
+ $custom_taxonomies,
182
+ function( $tax ) {
183
+ return ! empty( $tax );
184
+ }
185
+ )
186
+ );
187
+
188
+ /**
189
+ * Filters the custom taxonomies that will be available in the Home Page block.
190
+ *
191
+ * By default, on the top of category and tags, will display any public taxonomy applied to post or pages
192
+ *
193
+ * @param array $custom_taxonomies Array of custom taxonomies where each taxonomy is an array with slug and label keys.
194
+ */
195
+ return apply_filters( 'newspack_blocks_home_page_block_custom_taxonomies', $custom_taxonomies );
196
+ }
197
+
198
+ /**
199
+ * Check if the Name Your Price extension is available.
200
+ *
201
+ * @return bool True if available, false if not.
202
+ */
203
+ public static function can_use_name_your_price() {
204
+ // If the donation platform is NRH, the Donate block should behave as if Name Your Price is available.
205
+ if ( method_exists( 'Newspack\Donations', 'is_platform_nrh' ) && \Newspack\Donations::is_platform_nrh() ) {
206
+ return true;
207
+ }
208
+ return class_exists( 'WC_Name_Your_Price_Helpers' );
209
+ }
210
+
211
+ /**
212
+ * Enqueue block scripts and styles for editor.
213
+ */
214
+ public static function enqueue_block_assets() {
215
+ if ( ! is_admin() ) {
216
+ // In non-editor environment, do nothing.
217
+ return;
218
+ }
219
+ $script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.js' );
220
+ if ( $script_data ) {
221
+ wp_enqueue_script(
222
+ 'newspack-blocks-editor',
223
+ $script_data['script_path'],
224
+ $script_data['dependencies'],
225
+ $script_data['version'],
226
+ true
227
+ );
228
+
229
+ $localized_data = [
230
+ 'patterns' => self::get_patterns_for_post_type( get_post_type() ),
231
+ 'posts_rest_url' => rest_url( 'newspack-blocks/v1/newspack-blocks-posts' ),
232
+ 'specific_posts_rest_url' => rest_url( 'newspack-blocks/v1/newspack-blocks-specific-posts' ),
233
+ 'authors_rest_url' => rest_url( 'newspack-blocks/v1/authors' ),
234
+ 'assets_path' => plugins_url( '/src/assets', NEWSPACK_BLOCKS__PLUGIN_FILE ),
235
+ 'post_subtitle' => get_theme_support( 'post-subtitle' ),
236
+ 'iframe_accepted_file_mimes' => WP_REST_Newspack_Iframe_Controller::iframe_accepted_file_mimes(),
237
+ 'iframe_can_upload_archives' => WP_REST_Newspack_Iframe_Controller::can_upload_archives(),
238
+ 'supports_recaptcha' => class_exists( 'Newspack\Recaptcha' ),
239
+ 'has_recaptcha' => class_exists( 'Newspack\Recaptcha' ) && \Newspack\Recaptcha::can_use_captcha(),
240
+ 'recaptcha_url' => admin_url( 'admin.php?page=newspack-settings' ),
241
+ 'custom_taxonomies' => self::get_custom_taxonomies(),
242
+ 'can_use_name_your_price' => self::can_use_name_your_price(),
243
+ 'tier_amounts_template' => self::get_formatted_amount(),
244
+ 'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
245
+ ];
246
+
247
+ if ( class_exists( 'WP_REST_Newspack_Author_List_Controller' ) ) {
248
+ $localized_data['can_use_cap'] = class_exists( 'CoAuthors_Guest_Authors' );
249
+ $localized_data['editable_roles'] = Newspack_Blocks\get_authors_roles();
250
+ }
251
+
252
+ if ( class_exists( '\Newspack\Authors_Custom_Fields' ) ) {
253
+ $localized_data['author_custom_fields'] = \Newspack\Authors_Custom_Fields::get_custom_fields();
254
+ }
255
+
256
+ wp_localize_script(
257
+ 'newspack-blocks-editor',
258
+ 'newspack_blocks_data',
259
+ $localized_data
260
+ );
261
+
262
+ wp_set_script_translations(
263
+ 'newspack-blocks-editor',
264
+ 'newspack-blocks',
265
+ plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) . 'languages'
266
+ );
267
+ }
268
+
269
+ $editor_style = plugins_url( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.css', NEWSPACK_BLOCKS__PLUGIN_FILE );
270
+ $handle = 'newspack-blocks-editor';
271
+ wp_enqueue_style(
272
+ $handle,
273
+ $editor_style,
274
+ array(),
275
+ NEWSPACK_BLOCKS__VERSION
276
+ );
277
+ wp_style_add_data( $handle, 'rtl', 'replace' );
278
+ }
279
+
280
+ /**
281
+ * Enqueue block scripts and styles for view.
282
+ */
283
+ public static function manage_view_scripts() {
284
+ $src_directory = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/blocks/';
285
+ $dist_directory = NEWSPACK_BLOCKS__PLUGIN_DIR . 'dist/';
286
+ $iterator = new DirectoryIterator( $src_directory );
287
+ foreach ( $iterator as $block_directory ) {
288
+ if ( ! $block_directory->isDir() || $block_directory->isDot() ) {
289
+ continue;
290
+ }
291
+ $type = $block_directory->getFilename();
292
+
293
+ /* If view.php is found, include it and use for block rendering. */
294
+ $view_php_path = $src_directory . $type . '/view.php';
295
+
296
+ if ( file_exists( $view_php_path ) ) {
297
+ include_once $view_php_path;
298
+ continue;
299
+ }
300
+
301
+ // Skip remaining logic in admin - only needed for frontend asset loading.
302
+ if ( is_admin() ) {
303
+ continue;
304
+ }
305
+
306
+ /* If view.php is missing but view Javascript file is found, do generic view asset loading. */
307
+ $view_js_path = $dist_directory . $type . '/view.js';
308
+ if ( file_exists( $view_js_path ) ) {
309
+ register_block_type(
310
+ "newspack-blocks/{$type}",
311
+ array(
312
+ 'render_callback' => function( $attributes, $content ) use ( $type ) {
313
+ self::enqueue_view_assets( $type );
314
+ return $content;
315
+ },
316
+ )
317
+ );
318
+ }
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Enqueue block styles stylesheet.
324
+ */
325
+ public static function enqueue_block_styles_assets() {
326
+ $style_path = NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'block_styles.css';
327
+ if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) {
328
+ $handle = 'newspack-blocks-block-styles-stylesheet';
329
+ wp_enqueue_style(
330
+ $handle,
331
+ plugins_url( $style_path, NEWSPACK_BLOCKS__PLUGIN_FILE ),
332
+ array(),
333
+ NEWSPACK_BLOCKS__VERSION
334
+ );
335
+ wp_style_add_data( $handle, 'rtl', 'replace' );
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Enqueue view scripts and styles for a single block.
341
+ *
342
+ * @param string $type The block's type.
343
+ */
344
+ public static function enqueue_view_assets( $type ) {
345
+ $style_path = apply_filters(
346
+ 'newspack_blocks_enqueue_view_assets',
347
+ NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view.css',
348
+ $type,
349
+ is_rtl()
350
+ );
351
+
352
+ if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) {
353
+ $handle = "newspack-blocks-{$type}";
354
+ wp_enqueue_style(
355
+ $handle,
356
+ plugins_url( $style_path, NEWSPACK_BLOCKS__PLUGIN_FILE ),
357
+ array(),
358
+ NEWSPACK_BLOCKS__VERSION
359
+ );
360
+ wp_style_add_data( $handle, 'rtl', 'replace' );
361
+ }
362
+ $script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view.js' );
363
+ if ( $script_data ) {
364
+ wp_enqueue_script(
365
+ "newspack-blocks-{$type}",
366
+ $script_data['script_path'],
367
+ $script_data['dependencies'],
368
+ $script_data['version'],
369
+ true
370
+ );
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Utility to assemble the class for a server-side rendered block.
376
+ *
377
+ * @param string $type The block type.
378
+ * @param array $attributes Block attributes.
379
+ * @param array $extra Additional classes to be added to the class list.
380
+ *
381
+ * @return string Class list separated by spaces.
382
+ */
383
+ public static function block_classes( $type, $attributes = array(), $extra = array() ) {
384
+ $classes = [ "wp-block-newspack-blocks-{$type}" ];
385
+
386
+ if ( ! empty( $attributes['align'] ) ) {
387
+ $classes[] = 'align' . $attributes['align'];
388
+ }
389
+ if ( ! empty( $attributes['hideControls'] ) ) {
390
+ $classes[] = 'hide-controls';
391
+ }
392
+ if ( isset( $attributes['className'] ) ) {
393
+ array_push( $classes, $attributes['className'] );
394
+ }
395
+ if ( is_array( $extra ) && ! empty( $extra ) ) {
396
+ $classes = array_merge( $classes, $extra );
397
+ }
398
+
399
+ return implode( ' ', array_filter( $classes, 'strlen' ) );
400
+ }
401
+
402
+ /**
403
+ * Utility to assemble the styles for a server-side rendered block.
404
+ *
405
+ * @param array $attributes Block attributes.
406
+ * @param array $extra Additional styles to be added to the style list.
407
+ *
408
+ * @return string style list.
409
+ */
410
+ public static function block_styles( $attributes = [], $extra = [] ) {
411
+ $styles = [];
412
+ if ( isset( $attributes['style'] ) && is_array( $attributes['style'] ) ) {
413
+ $engine_styles = wp_style_engine_get_styles( $attributes['style'], [ 'context' => 'block-supports' ] );
414
+ if ( isset( $engine_styles['css'] ) ) {
415
+ $styles[] = $engine_styles['css'];
416
+ }
417
+ }
418
+
419
+ if ( is_array( $extra ) && ! empty( $extra ) ) {
420
+ $styles = array_merge( $styles, $extra );
421
+ }
422
+
423
+ return implode( '', $styles );
424
+ }
425
+
426
+ /**
427
+ * Return the most appropriate thumbnail size to display.
428
+ *
429
+ * @param string $orientation The block's orientation settings: landscape|portrait|square.
430
+ *
431
+ * @return string Returns the thumbnail key to use.
432
+ */
433
+ public static function image_size_for_orientation( $orientation = 'landscape' ) {
434
+ $sizes = array(
435
+ 'landscape' => array(
436
+ 'large' => array(
437
+ 1200,
438
+ 900,
439
+ ),
440
+ 'medium' => array(
441
+ 800,
442
+ 600,
443
+ ),
444
+ 'intermediate' => array(
445
+ 600,
446
+ 450,
447
+ ),
448
+ 'small' => array(
449
+ 400,
450
+ 300,
451
+ ),
452
+ 'tiny' => array(
453
+ 200,
454
+ 150,
455
+ ),
456
+ ),
457
+ 'portrait' => array(
458
+ 'large' => array(
459
+ 900,
460
+ 1200,
461
+ ),
462
+ 'medium' => array(
463
+ 600,
464
+ 800,
465
+ ),
466
+ 'intermediate' => array(
467
+ 450,
468
+ 600,
469
+ ),
470
+ 'small' => array(
471
+ 300,
472
+ 400,
473
+ ),
474
+ 'tiny' => array(
475
+ 150,
476
+ 200,
477
+ ),
478
+ ),
479
+ 'square' => array(
480
+ 'large' => array(
481
+ 1200,
482
+ 1200,
483
+ ),
484
+ 'medium' => array(
485
+ 800,
486
+ 800,
487
+ ),
488
+ 'intermediate' => array(
489
+ 600,
490
+ 600,
491
+ ),
492
+ 'small' => array(
493
+ 400,
494
+ 400,
495
+ ),
496
+ 'tiny' => array(
497
+ 200,
498
+ 200,
499
+ ),
500
+ ),
501
+ );
502
+
503
+ if ( isset( $sizes[ $orientation ] ) ) {
504
+ foreach ( $sizes[ $orientation ] as $key => $dimensions ) {
505
+ $attachment = wp_get_attachment_image_src(
506
+ get_post_thumbnail_id( get_the_ID() ),
507
+ 'newspack-article-block-' . $orientation . '-' . $key
508
+ );
509
+ if ( ! empty( $attachment ) && $dimensions[0] === $attachment[1] && $dimensions[1] === $attachment[2] ) {
510
+ return 'newspack-article-block-' . $orientation . '-' . $key;
511
+ }
512
+ }
513
+ }
514
+
515
+ return 'large';
516
+ }
517
+
518
+ /**
519
+ * Registers image sizes required for Newspack Blocks.
520
+ */
521
+ public static function add_image_sizes() {
522
+ add_image_size( 'newspack-article-block-landscape-large', 1200, 900, true );
523
+ add_image_size( 'newspack-article-block-portrait-large', 900, 1200, true );
524
+ add_image_size( 'newspack-article-block-square-large', 1200, 1200, true );
525
+
526
+ add_image_size( 'newspack-article-block-landscape-medium', 800, 600, true );
527
+ add_image_size( 'newspack-article-block-portrait-medium', 600, 800, true );
528
+ add_image_size( 'newspack-article-block-square-medium', 800, 800, true );
529
+
530
+ add_image_size( 'newspack-article-block-landscape-intermediate', 600, 450, true );
531
+ add_image_size( 'newspack-article-block-portrait-intermediate', 450, 600, true );
532
+ add_image_size( 'newspack-article-block-square-intermediate', 600, 600, true );
533
+
534
+ add_image_size( 'newspack-article-block-landscape-small', 400, 300, true );
535
+ add_image_size( 'newspack-article-block-portrait-small', 300, 400, true );
536
+ add_image_size( 'newspack-article-block-square-small', 400, 400, true );
537
+
538
+ add_image_size( 'newspack-article-block-landscape-tiny', 200, 150, true );
539
+ add_image_size( 'newspack-article-block-portrait-tiny', 150, 200, true );
540
+ add_image_size( 'newspack-article-block-square-tiny', 200, 200, true );
541
+
542
+ add_image_size( 'newspack-article-block-uncropped', 1200, 9999, false );
543
+ }
544
+
545
+ /**
546
+ * Whether the block should be included in the deduplication logic.
547
+ *
548
+ * @param array $attributes Block attributes.
549
+ *
550
+ * @return bool
551
+ */
552
+ public static function should_deduplicate_block( $attributes ) {
553
+ /**
554
+ * Filters whether to use deduplication while rendering the given block.
555
+ *
556
+ * @param bool $deduplicate Whether to deduplicate.
557
+ * @param array $attributes The block attributes.
558
+ */
559
+ return apply_filters( 'newspack_blocks_should_deduplicate', $attributes['deduplicate'] ?? true, $attributes );
560
+ }
561
+
562
+ /**
563
+ * Get all "specificPosts" ids from given blocks.
564
+ *
565
+ * @param array $blocks An array of blocks.
566
+ * @param string $block_name Name of the block requesting the query.
567
+ *
568
+ * @return array All "specificPosts" ids from all eligible blocks.
569
+ */
570
+ private static function get_specific_posts_from_blocks( $blocks, $block_name ) {
571
+ $specific_posts = [];
572
+ foreach ( $blocks as $block ) {
573
+ if ( ! empty( $block['innerBlocks'] ) ) {
574
+ $specific_posts = array_merge(
575
+ $specific_posts,
576
+ self::get_specific_posts_from_blocks( $block['innerBlocks'], $block_name )
577
+ );
578
+ continue;
579
+ }
580
+ if (
581
+ $block_name === $block['blockName'] &&
582
+ self::should_deduplicate_block( $block['attrs'] ) &&
583
+ ! empty( $block['attrs']['specificMode'] ) &&
584
+ ! empty( $block['attrs']['specificPosts'] )
585
+ ) {
586
+ $specific_posts = array_merge(
587
+ $specific_posts,
588
+ $block['attrs']['specificPosts']
589
+ );
590
+ }
591
+ }
592
+ return $specific_posts;
593
+ }
594
+
595
+ /**
596
+ * Builds and returns query args based on block attributes.
597
+ *
598
+ * @param array $attributes An array of block attributes.
599
+ * @param array $block_name Name of the block requesting the query.
600
+ *
601
+ * @return array
602
+ */
603
+ public static function build_articles_query( $attributes, $block_name ) {
604
+ global $newspack_blocks_post_id;
605
+ if ( ! $newspack_blocks_post_id ) {
606
+ $newspack_blocks_post_id = array();
607
+ }
608
+
609
+ // Get all blocks and gather specificPosts ids of all eligible blocks.
610
+ global $newspack_blocks_all_specific_posts_ids;
611
+ if ( ! is_array( $newspack_blocks_all_specific_posts_ids ) ) {
612
+ $blocks = parse_blocks( get_the_content() );
613
+ $newspack_blocks_all_specific_posts_ids = self::get_specific_posts_from_blocks( $blocks, $block_name );
614
+ }
615
+
616
+ $post_type = isset( $attributes['postType'] ) ? $attributes['postType'] : [ 'post' ];
617
+ $included_post_statuses = [ 'publish' ];
618
+ if ( current_user_can( 'edit_others_posts' ) && isset( $attributes['includedPostStatuses'] ) ) {
619
+ $included_post_statuses = $attributes['includedPostStatuses'];
620
+ }
621
+ $authors = isset( $attributes['authors'] ) ? $attributes['authors'] : array();
622
+ $categories = isset( $attributes['categories'] ) ? $attributes['categories'] : array();
623
+ $include_subcategories = isset( $attributes['includeSubcategories'] ) ? intval( $attributes['includeSubcategories'] ) : false;
624
+ $category_join = isset( $attributes['categoryJoinType'] ) ? $attributes['categoryJoinType'] : 'or';
625
+ $tags = isset( $attributes['tags'] ) ? $attributes['tags'] : array();
626
+ $custom_taxonomies = isset( $attributes['customTaxonomies'] ) ? $attributes['customTaxonomies'] : array();
627
+ $tag_exclusions = isset( $attributes['tagExclusions'] ) ? $attributes['tagExclusions'] : array();
628
+ $category_exclusions = isset( $attributes['categoryExclusions'] ) ? $attributes['categoryExclusions'] : array();
629
+ $custom_taxonomy_exclusions = isset( $attributes['customTaxonomyExclusions'] ) ? $attributes['customTaxonomyExclusions'] : array();
630
+ $specific_posts = isset( $attributes['specificPosts'] ) ? $attributes['specificPosts'] : array();
631
+ $posts_to_show = intval( $attributes['postsToShow'] );
632
+ $specific_mode = isset( $attributes['specificMode'] ) ? intval( $attributes['specificMode'] ) : false;
633
+ $args = array(
634
+ 'post_type' => $post_type,
635
+ 'post_status' => $included_post_statuses,
636
+ 'suppress_filters' => false,
637
+ 'ignore_sticky_posts' => true,
638
+ 'has_password' => false,
639
+ 'is_newspack_query' => true,
640
+ 'tax_query' => [], // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
641
+ );
642
+ if ( $specific_mode && $specific_posts ) {
643
+ $args['posts_per_page'] = count( $specific_posts );
644
+ $args['post__in'] = $specific_posts;
645
+ $args['orderby'] = 'post__in';
646
+ } else {
647
+ $args['posts_per_page'] = $posts_to_show;
648
+ if ( self::should_deduplicate_block( $attributes ) ) {
649
+ if ( count( $newspack_blocks_all_specific_posts_ids ) ) {
650
+ $args['post__not_in'] = $newspack_blocks_all_specific_posts_ids; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
651
+ }
652
+ $current_post_id = get_the_ID();
653
+ $args['post__not_in'] = array_merge( // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
654
+ $args['post__not_in'] ?? [],
655
+ array_keys( $newspack_blocks_post_id ),
656
+ is_singular() && $current_post_id ? [ $current_post_id ] : []
657
+ );
658
+ }
659
+ if ( $categories && count( $categories ) ) {
660
+ if ( 'or' === $category_join && 1 === $include_subcategories ) {
661
+ $children = [];
662
+ foreach ( $categories as $parent ) {
663
+ $children = array_merge( $children, get_categories( [ 'child_of' => $parent ] ) );
664
+ foreach ( $children as $child ) {
665
+ $categories[] = $child->term_id;
666
+ }
667
+ }
668
+ }
669
+ if ( 'or' === $category_join ) {
670
+ $args['category__in'] = $categories;
671
+ } else {
672
+ $args['category__and'] = $categories;
673
+ }
674
+ }
675
+ if ( $tags && count( $tags ) ) {
676
+ $args['tag__in'] = $tags;
677
+ }
678
+ if ( $tag_exclusions && count( $tag_exclusions ) ) {
679
+ $args['tag__not_in'] = $tag_exclusions;
680
+ }
681
+ if ( $category_exclusions && count( $category_exclusions ) ) {
682
+ $args['category__not_in'] = $category_exclusions;
683
+ }
684
+ if ( ! empty( $custom_taxonomies ) ) {
685
+ foreach ( $custom_taxonomies as $taxonomy ) {
686
+ if ( ! empty( $taxonomy['slug'] ) && ! empty( $taxonomy['terms'] ) ) {
687
+ $args['tax_query'][] = [
688
+ 'taxonomy' => $taxonomy['slug'],
689
+ 'field' => 'term_id',
690
+ 'terms' => $taxonomy['terms'],
691
+ 'include_children' => false,
692
+ ];
693
+ }
694
+ }
695
+ }
696
+ if ( $custom_taxonomy_exclusions && count( $custom_taxonomy_exclusions ) ) {
697
+ foreach ( $custom_taxonomy_exclusions as $exclusion ) {
698
+ $args['tax_query'][] = [
699
+ 'field' => 'term_id',
700
+ 'include_children' => false,
701
+ 'operator' => 'NOT IN',
702
+ 'taxonomy' => $exclusion['slug'],
703
+ 'terms' => $exclusion['terms'],
704
+ ];
705
+ }
706
+ }
707
+
708
+ if ( $authors && count( $authors ) ) {
709
+ global $coauthors_plus;
710
+ $is_co_authors_plus_active = is_object( $coauthors_plus ) && method_exists( $coauthors_plus, 'get_coauthor_by' );
711
+
712
+ if ( ! $is_co_authors_plus_active ) {
713
+ $args['author__in'] = $authors;
714
+ } else {
715
+ /**
716
+ * When CoAuthors Plus is active, we ignore the 'author__in' parameter and search only by the author taxonomy.
717
+ *
718
+ * If CAP has been activated recently, the author taxonomy may not have been populated yet. You'll need to run
719
+ * wp co-authors-plus create-author-terms-for-posts to make sure all posts have the author terms in place.
720
+ */
721
+ $authors_term_ids = [];
722
+ foreach ( $authors as $author_id ) {
723
+ $co_author = $coauthors_plus->get_coauthor_by( 'id', $author_id );
724
+ if ( is_object( $co_author ) ) {
725
+ $term = $coauthors_plus->get_author_term( $co_author );
726
+ if ( $term ) {
727
+ $authors_term_ids[] = $term->term_id;
728
+ } else {
729
+ // If the author term does not exist, force a non-match, otherwise all posts will be returned.
730
+ // CAP's cli command to create author terms will only create terms for users that have authored posts.
731
+ $authors_term_ids[] = -1;
732
+ }
733
+
734
+ // If it's a guest author, also check the linked author.
735
+ if ( 'guest-author' === $co_author->type && ! empty( $co_author->wp_user ) && $co_author->wp_user instanceof \WP_User ) {
736
+ $term = $coauthors_plus->get_author_term( $co_author->wp_user );
737
+ if ( $term ) {
738
+ $authors_term_ids[] = $term->term_id;
739
+ }
740
+ }
741
+
742
+ // If it's a regular wp user, check and include any linked guest authors.
743
+ if ( 'wpuser' === $co_author->type ) {
744
+ $authors_controller = new WP_REST_Newspack_Authors_Controller();
745
+ $linked_guest_author_post = $authors_controller->get_linked_guest_author( $co_author->user_login );
746
+ if ( $linked_guest_author_post ) {
747
+ $linked_guest_author_object = $coauthors_plus->get_coauthor_by( 'id', $author_id );
748
+ if ( is_object( $linked_guest_author_object ) ) {
749
+ $term = $coauthors_plus->get_author_term( $linked_guest_author_object );
750
+ if ( $term ) {
751
+ $authors_term_ids[] = $term->term_id;
752
+ }
753
+ }
754
+ }
755
+ }
756
+ }
757
+ }
758
+ if ( count( $authors_term_ids ) ) {
759
+ $args['tax_query'][] = [
760
+ 'taxonomy' => 'author',
761
+ 'field' => 'term_id',
762
+ 'terms' => $authors_term_ids,
763
+ ];
764
+ }
765
+ }
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Customize the WP_Query arguments to fetch post articles before the actual query is executed.
771
+ *
772
+ * The filter is called after the build_articles_query() function is called by a Newspack block to
773
+ * build the WP_Query arguments based on the given attributes and block requesting the query.
774
+ *
775
+ * @param array $args WP_Query arguments as created by build_articles_query()
776
+ * @param array $attributes The attributes initial passed to build_articles_query()
777
+ * @param string $block_name The name of the requesting block to create the query args for
778
+ */
779
+ return apply_filters( 'newspack_blocks_build_articles_query', $args, $attributes, $block_name );
780
+ }
781
+
782
+ /**
783
+ * Loads a template with given data in scope.
784
+ *
785
+ * @param string $template full Path to the template to be included.
786
+ * @param array $data Data to be passed into the template to be included.
787
+ * @return string
788
+ */
789
+ public static function template_inc( $template, $data = array() ) { //phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
790
+ if ( ! strpos( $template, '.php' ) ) {
791
+ $template = $template . '.php';
792
+ }
793
+ if ( ! is_file( $template ) ) {
794
+ return '';
795
+ }
796
+ ob_start();
797
+ include $template;
798
+ $contents = ob_get_contents();
799
+ ob_end_clean();
800
+ return $contents;
801
+ }
802
+
803
+ /**
804
+ * Prepare an array of authors, taking presence of CoAuthors Plus into account.
805
+ *
806
+ * @return object[] Array of user objects.
807
+ */
808
+ public static function prepare_authors() {
809
+ $authors = [];
810
+
811
+ if ( function_exists( 'get_coauthors' ) ) {
812
+ $authors = get_coauthors();
813
+ foreach ( $authors as $author ) {
814
+ $author->avatar = coauthors_get_avatar( $author, 48 );
815
+ $author->url = get_author_posts_url( $author->ID, $author->user_nicename );
816
+ }
817
+ }
818
+
819
+ if ( empty( $authors ) ) {
820
+ $id = get_the_author_meta( 'ID' );
821
+ $authors = array(
822
+ (object) array(
823
+ 'ID' => $id,
824
+ 'avatar' => get_avatar( $id, 48 ),
825
+ 'url' => get_author_posts_url( $id ),
826
+ 'user_nicename' => get_the_author(),
827
+ 'display_name' => get_the_author_meta( 'display_name' ),
828
+ ),
829
+ );
830
+ }
831
+
832
+ /**
833
+ * Filters the authors array.
834
+ *
835
+ * @param object[] $authors Array of user objects.
836
+ */
837
+ return apply_filters( 'newspack_blocks_post_authors', $authors );
838
+ }
839
+
840
+ /**
841
+ * Prepare a list of classes based on assigned tags, categories, post formats and types.
842
+ *
843
+ * @param string $post_id Post ID.
844
+ * @return string CSS classes.
845
+ */
846
+ public static function get_term_classes( $post_id ) {
847
+ $classes = [];
848
+
849
+ $tags = get_the_terms( $post_id, 'post_tag' );
850
+ if ( ! empty( $tags ) ) {
851
+ foreach ( $tags as $tag ) {
852
+ if ( ! empty( $tag->slug ) ) {
853
+ $classes[] = 'tag-' . $tag->slug;
854
+ }
855
+ }
856
+ }
857
+
858
+ $categories = get_the_terms( $post_id, 'category' );
859
+ if ( ! empty( $categories ) ) {
860
+ foreach ( $categories as $cat ) {
861
+ if ( ! empty( $cat->slug ) ) {
862
+ $classes[] = 'category-' . $cat->slug;
863
+ }
864
+ }
865
+ }
866
+
867
+ foreach ( self::get_custom_taxonomies() as $tax ) {
868
+ $terms = get_the_terms( $post_id, $tax['slug'] );
869
+ if ( ! empty( $terms ) ) {
870
+ foreach ( $terms as $term ) {
871
+ if ( ! empty( $term->taxonomy ) && ! empty( $term->slug ) ) {
872
+ $classes[] = $term->taxonomy . '-' . $term->slug;
873
+ }
874
+ }
875
+ }
876
+ }
877
+
878
+ $post_type = get_post_type( $post_id );
879
+ if ( false !== $post_type ) {
880
+ $classes[] = 'type-' . $post_type;
881
+ }
882
+
883
+ /**
884
+ * Filter the array of class names before applying them to the HTML.
885
+ *
886
+ * @param array $classes Array of term class names.
887
+ *
888
+ * @return array Filtered array of term class names.
889
+ */
890
+ $classes = apply_filters( 'newspack_blocks_term_classes', $classes );
891
+
892
+ return implode( ' ', $classes );
893
+ }
894
+
895
+ /**
896
+ * Get patterns for post type.
897
+ *
898
+ * @param string $post_type Post type.
899
+ * @return array Array of patterns.
900
+ */
901
+ public static function get_patterns_for_post_type( $post_type = null ) {
902
+ $patterns = apply_filters( 'newspack_blocks_patterns', [], $post_type );
903
+ $categorized = [];
904
+ $clean = [];
905
+ foreach ( $patterns as $pattern ) {
906
+ if ( ! isset( $pattern['image'] ) || ! $pattern['image'] ) {
907
+ continue;
908
+ }
909
+ $category = isset( $pattern['category'] ) ? $pattern['category'] : __( 'Common', 'newspack-blocks' );
910
+ if ( ! isset( $categorized[ $category ] ) ) {
911
+ $categorized[ $category ] = [];
912
+ }
913
+ $categorized[ $category ][] = $pattern;
914
+ }
915
+ $categories = array_keys( $categorized );
916
+ sort( $categories );
917
+ foreach ( $categories as $category ) {
918
+ $clean[] = [
919
+ 'title' => $category,
920
+ 'items' => $categorized[ $category ],
921
+ ];
922
+ }
923
+ return $clean;
924
+ }
925
+
926
+ /**
927
+ * Function to check if plugin is enabled, and if there are sponsors.
928
+ *
929
+ * @see https://github.com/Automattic/newspack-sponsors/blob/8ebf72ec4fe744bca405a1f6fe8cd5bce3a29e6a/includes/newspack-sponsors-theme-helpers.php#L35
930
+ *
931
+ * @param int|null $id ID of the post or archive term to get sponsors for.
932
+ * If not provided, we will try to guess based on context.
933
+ * @param string|null $scope Scope of the sponsors to get. Can be 'native' or
934
+ * 'underwritten'. If provided, only sponsors with the
935
+ * matching scope will be returned. If not, all sponsors
936
+ * will be returned regardless of scope.
937
+ * @param string|null $type Type of the $id given: 'post' or 'archive'. If not
938
+ * provided, we will try to guess based on context.
939
+ * @param array $logo_options Optional array of logo options. Valid options:
940
+ * maxwidth: max width of the logo image, in pixels.
941
+ * maxheight: max height of the logo image, in pixels.
942
+ * @return array Array of sponsors.
943
+ */
944
+ public static function get_all_sponsors( $id = null, $scope = 'native', $type = 'post', $logo_options = array(
945
+ 'maxwidth' => 80,
946
+ 'maxheight' => 40,
947
+ ) ) {
948
+ if ( function_exists( '\Newspack_Sponsors\get_sponsors_for_post' ) ) {
949
+ if ( is_singular() ) {
950
+ $scope_override = get_post_meta( $id, 'newspack_sponsor_sponsorship_scope', true );
951
+
952
+ // Scope override: if post is set to display as native-sponsored, return all sponsors.
953
+ if ( 'native' === $scope_override ) {
954
+ $scope = null;
955
+ }
956
+
957
+ // Scope override: if post is set to display as underwritten, return nothing.
958
+ if ( 'underwritten' === $scope_override ) {
959
+ return [];
960
+ }
961
+ }
962
+
963
+ return \Newspack_Sponsors\get_all_sponsors( $id, $scope, $type, $logo_options ); // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
964
+ }
965
+
966
+ return false;
967
+ }
968
+
969
+ /**
970
+ * Function to return sponsor 'flag' from first sponsor.
971
+ *
972
+ * @param array $sponsors Array of sponsors.
973
+ * @param string $id Post ID.
974
+ * @return string|boolean Sponsor flag label, or false if none found.
975
+ */
976
+ public static function get_sponsor_label( $sponsors = null, $id = null ) {
977
+ if ( null === $sponsors && ! empty( $id ) ) {
978
+ $sponsors = self::get_all_sponsors( $id );
979
+ }
980
+
981
+ if ( ! empty( $sponsors ) ) {
982
+ $sponsor_flag = $sponsors[0]['sponsor_flag'];
983
+ return $sponsor_flag;
984
+ }
985
+
986
+ return false;
987
+ }
988
+
989
+ /**
990
+ * Outputs the sponsor byline markup for the theme.
991
+ *
992
+ * @param array $sponsors Array of sponsors.
993
+ * @param string $id Post ID.
994
+ * @return array|boolean Array of Sponsor byline information, or false if none found.
995
+ */
996
+ public static function get_sponsor_byline( $sponsors = null, $id = null ) {
997
+ if ( null === $sponsors & ! empty( $id ) ) {
998
+ $sponsors = self::get_all_sponsors( $id );
999
+ }
1000
+
1001
+ if ( ! empty( $sponsors ) ) {
1002
+ $sponsor_count = count( $sponsors );
1003
+ $i = 1;
1004
+ $sponsor_list = [];
1005
+
1006
+ foreach ( $sponsors as $sponsor ) {
1007
+ $i++;
1008
+ if ( $sponsor_count === $i ) :
1009
+ /* translators: separates last two sponsor names; needs a space on either side. */
1010
+ $sep = esc_html__( ' and ', 'newspack-blocks' );
1011
+ elseif ( $sponsor_count > $i ) :
1012
+ /* translators: separates all but the last two sponsor names; needs a space at the end. */
1013
+ $sep = esc_html__( ', ', 'newspack-blocks' );
1014
+ else :
1015
+ $sep = '';
1016
+ endif;
1017
+
1018
+ $sponsor_list[] = array(
1019
+ 'byline' => $sponsor['sponsor_byline'],
1020
+ 'url' => $sponsor['sponsor_url'],
1021
+ 'name' => $sponsor['sponsor_name'],
1022
+ 'sep' => $sep,
1023
+ );
1024
+ }
1025
+ return $sponsor_list;
1026
+ }
1027
+
1028
+ return false;
1029
+ }
1030
+
1031
+ /**
1032
+ * Outputs set of sponsor logos with links.
1033
+ *
1034
+ * @param array $sponsors Array of sponsors.
1035
+ * @param string $id Post ID.
1036
+ * @return array Array of sponsor logo images, or false if none found.
1037
+ */
1038
+ public static function get_sponsor_logos( $sponsors = null, $id = null ) {
1039
+ if ( null === $sponsors && ! empty( $id ) ) {
1040
+ $sponsors = self::get_all_sponsors(
1041
+ $id,
1042
+ 'native',
1043
+ 'post',
1044
+ array(
1045
+ 'maxwidth' => 80,
1046
+ 'maxheight' => 40,
1047
+ )
1048
+ );
1049
+ }
1050
+
1051
+ if ( ! empty( $sponsors ) ) {
1052
+ $sponsor_logos = [];
1053
+ foreach ( $sponsors as $sponsor ) {
1054
+ if ( ! empty( $sponsor['sponsor_logo'] ) ) :
1055
+ $sponsor_logos[] = array(
1056
+ 'url' => $sponsor['sponsor_url'],
1057
+ 'src' => esc_url( $sponsor['sponsor_logo']['src'] ),
1058
+ 'alt' => esc_attr( $sponsor['sponsor_name'] ),
1059
+ 'width' => esc_attr( $sponsor['sponsor_logo']['img_width'] ),
1060
+ 'height' => esc_attr( $sponsor['sponsor_logo']['img_height'] ),
1061
+ );
1062
+ endif;
1063
+ }
1064
+
1065
+ return $sponsor_logos;
1066
+ }
1067
+
1068
+ return false;
1069
+ }
1070
+
1071
+ /**
1072
+ * If at least one native sponsor is set to display both sponsors and authors, show the authors.
1073
+ *
1074
+ * @param array $sponsors Array of sponsors.
1075
+ *
1076
+ * @return boolean True if we should display both sponsors and categories, false if we should display only sponsors.
1077
+ */
1078
+ public static function newspack_display_sponsors_and_authors( $sponsors ) {
1079
+ if ( function_exists( '\Newspack_Sponsors\newspack_display_sponsors_and_authors' ) ) {
1080
+ return \Newspack_Sponsors\newspack_display_sponsors_and_authors( $sponsors );
1081
+ }
1082
+ return false;
1083
+ }
1084
+
1085
+ /**
1086
+ * If at least one native sponsor is set to display both sponsors and categories, show the categories.
1087
+ *
1088
+ * @param array $sponsors Array of sponsors.
1089
+ *
1090
+ * @return boolean True if we should display both sponsors and categories, false if we should display only sponsors.
1091
+ */
1092
+ public static function newspack_display_sponsors_and_categories( $sponsors ) {
1093
+ if ( function_exists( '\Newspack_Sponsors\newspack_display_sponsors_and_categories' ) ) {
1094
+ return \Newspack_Sponsors\newspack_display_sponsors_and_categories( $sponsors );
1095
+ }
1096
+ return false;
1097
+ }
1098
+
1099
+ /**
1100
+ * Closure for excerpt filtering that can be added and removed.
1101
+ *
1102
+ * @var Closure
1103
+ */
1104
+ public static $newspack_blocks_excerpt_closure = null;
1105
+
1106
+ /**
1107
+ * Closure for excerpt length filtering that can be added and removed.
1108
+ *
1109
+ * @var Closure
1110
+ * @deprecated
1111
+ */
1112
+ public static $newspack_blocks_excerpt_length_closure = null;
1113
+
1114
+ /**
1115
+ * Function to override WooCommerce Membership's Excerpt Length filter.
1116
+ *
1117
+ * @return string Current post's original excerpt.
1118
+ */
1119
+ public static function remove_wc_memberships_excerpt_limit() {
1120
+ $excerpt = get_the_excerpt( get_the_id() );
1121
+ return $excerpt;
1122
+ }
1123
+
1124
+ /**
1125
+ * Filter for excerpt length.
1126
+ *
1127
+ * @param array $attributes The block's attributes.
1128
+ */
1129
+ public static function filter_excerpt( $attributes ) {
1130
+ if ( empty( $attributes['excerptLength'] ) || ! $attributes['showExcerpt'] ) {
1131
+ return;
1132
+ }
1133
+
1134
+ self::$newspack_blocks_excerpt_closure = function( $text = '', $post = null ) use ( $attributes ) {
1135
+ // If we have a manually entered excerpt, use that and allow some tags.
1136
+ if ( ! empty( $post->post_excerpt ) ) {
1137
+ $excerpt = $post->post_excerpt;
1138
+ $allowed_tags = '<em>,<i>,<strong>,<b>,<u>,<ul>,<ol>,<li>,<h1>,<h2>,<h3>,<h4>,<h5>,<h6>,<img>,<a>,<p>';
1139
+ } else {
1140
+ // If we don't, built an excerpt but allow no tags.
1141
+ $excerpt = $post->post_content;
1142
+ $allowed_tags = '';
1143
+ }
1144
+
1145
+ // Recreate logic from wp_trim_excerpt (https://developer.wordpress.org/reference/functions/wp_trim_excerpt/).
1146
+ $excerpt = strip_shortcodes( $excerpt );
1147
+ $excerpt = excerpt_remove_blocks( $excerpt );
1148
+ $excerpt = wpautop( $excerpt );
1149
+ $excerpt = str_replace( ']]>', ']]&gt;', $excerpt );
1150
+
1151
+ // Strip HTML tags except for the explicitly allowed tags.
1152
+ $excerpt = strip_tags( $excerpt, $allowed_tags ); // phpcs:ignore WordPressVIPMinimum.Functions.StripTags.StripTagsTwoParameters
1153
+
1154
+ // Get excerpt length. If not provided a valid length, use the default excerpt length.
1155
+ if ( empty( $attributes['excerptLength'] ) || ! is_numeric( $attributes['excerptLength'] ) ) {
1156
+ $excerpt_length = 55;
1157
+ } else {
1158
+ $excerpt_length = $attributes['excerptLength'];
1159
+ }
1160
+
1161
+ // Set excerpt length (https://core.trac.wordpress.org/ticket/29533#comment:3).
1162
+ $excerpt = force_balance_tags( html_entity_decode( wp_trim_words( htmlentities( $excerpt, ENT_COMPAT ), $excerpt_length, static::more_excerpt(), ENT_COMPAT ) ) );
1163
+
1164
+ return $excerpt;
1165
+ };
1166
+ add_filter( 'get_the_excerpt', self::$newspack_blocks_excerpt_closure, 11, 2 );
1167
+ }
1168
+
1169
+ /**
1170
+ * Remove excerpt filter after Homepage Posts block loop.
1171
+ */
1172
+ public static function remove_excerpt_filter() {
1173
+ if ( static::$newspack_blocks_excerpt_closure ) {
1174
+ remove_filter( 'get_the_excerpt', static::$newspack_blocks_excerpt_closure, 11 );
1175
+ }
1176
+ }
1177
+
1178
+ /**
1179
+ * Filter for excerpt length.
1180
+ *
1181
+ * @deprecated
1182
+ * @param array $attributes The block's attributes.
1183
+ */
1184
+ public static function filter_excerpt_length( $attributes ) {
1185
+ // If showing excerpt, filter the length using the block attribute.
1186
+ if ( isset( $attributes['excerptLength'] ) && $attributes['showExcerpt'] ) {
1187
+ self::$newspack_blocks_excerpt_length_closure = add_filter(
1188
+ 'excerpt_length',
1189
+ function() use ( $attributes ) {
1190
+ if ( $attributes['excerptLength'] ) {
1191
+ return $attributes['excerptLength'];
1192
+ }
1193
+ return 55;
1194
+ },
1195
+ 999
1196
+ );
1197
+ add_filter( 'wc_memberships_trimmed_restricted_excerpt', [ 'Newspack_Blocks', 'remove_wc_memberships_excerpt_limit' ], 999 );
1198
+ }
1199
+ }
1200
+
1201
+ /**
1202
+ * Remove excerpt length filter after Homepage Posts block loop.
1203
+ *
1204
+ * @deprecated
1205
+ */
1206
+ public static function remove_excerpt_length_filter() {
1207
+ if ( self::$newspack_blocks_excerpt_length_closure ) {
1208
+ remove_filter(
1209
+ 'excerpt_length',
1210
+ self::$newspack_blocks_excerpt_length_closure,
1211
+ 999
1212
+ );
1213
+ remove_filter( 'wc_memberships_trimmed_restricted_excerpt', [ 'Newspack_Blocks', 'remove_wc_memberships_excerpt_limit' ] );
1214
+ }
1215
+ }
1216
+
1217
+ /**
1218
+ * Return a excerpt more replacement when using the 'Read More' link.
1219
+ */
1220
+ public static function more_excerpt() {
1221
+ return '…';
1222
+ }
1223
+
1224
+ /**
1225
+ * Filter for excerpt ellipsis.
1226
+ *
1227
+ * @deprecated
1228
+ * @param array $attributes The block's attributes.
1229
+ */
1230
+ public static function filter_excerpt_more( $attributes ) {
1231
+ // If showing the 'Read More' link, modify the ellipsis.
1232
+ if ( $attributes['showReadMore'] ) {
1233
+ add_filter( 'excerpt_more', [ __CLASS__, 'more_excerpt' ], 999 );
1234
+ }
1235
+ }
1236
+
1237
+ /**
1238
+ * Remove excerpt ellipsis filter after Homepage Posts block loop.
1239
+ *
1240
+ * @deprecated
1241
+ */
1242
+ public static function remove_excerpt_more_filter() {
1243
+ remove_filter( 'excerpt_more', [ __CLASS__, 'more_excerpt' ], 999 );
1244
+ }
1245
+
1246
+ /**
1247
+ * Utility to get the link for the given post ID. If the post has an external URL meta value, use that.
1248
+ * Otherwise, use the permalink. But if the post type doesn't have a public singular view, don't link.
1249
+ *
1250
+ * @param int $post_id Post ID for which to get the link. Will default to current post if none given.
1251
+ * @return string|boolean The URL for the post, or false if it can't be linked to.
1252
+ */
1253
+ public static function get_post_link( $post_id = null ) {
1254
+ if ( null === $post_id ) {
1255
+ $post_id = get_the_ID();
1256
+ }
1257
+
1258
+ $post_type = get_post_type( $post_id );
1259
+ $sponsor_url = get_post_meta( $post_id, 'newspack_sponsor_url', true );
1260
+ $supporter_url = get_post_meta( $post_id, 'newspack_supporter_url', true );
1261
+ $external_url = ! empty( $sponsor_url ) ? $sponsor_url : $supporter_url;
1262
+ $post_type_info = get_post_type_object( $post_type );
1263
+ $link = ! empty( $external_url ) ? $external_url : get_permalink();
1264
+ $should_have_link = ! empty( $post_type_info->public ) || ! empty( $external_url ); // False if a sponsor or supporter without an external URL.
1265
+
1266
+ return $should_have_link ? $link : false;
1267
+ }
1268
+
1269
+ /**
1270
+ * Sanitize SVG markup for front-end display.
1271
+ *
1272
+ * @param string $svg SVG markup to sanitize.
1273
+ * @return string Sanitized markup.
1274
+ */
1275
+ public static function sanitize_svg( $svg = '' ) {
1276
+ $allowed_html = [
1277
+ 'svg' => [
1278
+ 'xmlns' => [],
1279
+ 'fill' => [],
1280
+ 'viewbox' => [],
1281
+ 'role' => [],
1282
+ 'aria-hidden' => [],
1283
+ 'focusable' => [],
1284
+ 'height' => [],
1285
+ 'width' => [],
1286
+ ],
1287
+ 'path' => [
1288
+ 'd' => [],
1289
+ 'fill' => [],
1290
+ ],
1291
+ ];
1292
+
1293
+ return wp_kses( $svg, $allowed_html );
1294
+ }
1295
+
1296
+ /**
1297
+ * Disable Jetpack's donate block when using Newspack donations.
1298
+ */
1299
+ public static function disable_jetpack_donate() {
1300
+ // Do nothing if Jetpack's blocks or Newspack aren't being used.
1301
+ if ( ! class_exists( 'Jetpack_Gutenberg' ) || ! class_exists( 'Newspack' ) ) {
1302
+ return;
1303
+ }
1304
+
1305
+ // Allow Jetpack donations if Newspack donations isn't set up.
1306
+ $donate_settings = Newspack\Donations::get_donation_settings();
1307
+ if ( is_wp_error( $donate_settings ) ) {
1308
+ return;
1309
+ }
1310
+
1311
+ // Tell Jetpack to mark the donations feature as unavailable.
1312
+ Jetpack_Gutenberg::set_extension_unavailable(
1313
+ 'jetpack/donations',
1314
+ esc_html__( 'Jetpack donations is disabled in favour of Newspack donations.', 'newspack-blocks' )
1315
+ );
1316
+ }
1317
+
1318
+ /**
1319
+ * Loads a template with given data in scope.
1320
+ *
1321
+ * @param string $template Name of the template to be included.
1322
+ * @param array $data Data to be passed into the template to be included.
1323
+ * @param string $path (Optional) Path to the folder containing the template.
1324
+ * @return string
1325
+ */
1326
+ public static function template_include( $template, $data = [], $path = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/templates/' ) {
1327
+ if ( ! strpos( $template, '.php' ) ) {
1328
+ $template = $template . '.php';
1329
+ }
1330
+ $path .= $template;
1331
+ if ( ! is_file( $path ) ) {
1332
+ return '';
1333
+ }
1334
+ ob_start();
1335
+ include $path;
1336
+ $contents = ob_get_contents();
1337
+ ob_end_clean();
1338
+ return $contents;
1339
+ }
1340
+
1341
+ /**
1342
+ * Get post status label.
1343
+ */
1344
+ public static function get_post_status_label() {
1345
+ $post_status = get_post_status();
1346
+ $post_statuses_labels = [
1347
+ 'draft' => __( 'Draft', 'newspack-blocks' ),
1348
+ 'future' => __( 'Scheduled', 'newspack-blocks' ),
1349
+ ];
1350
+ if ( 'publish' !== $post_status ) {
1351
+ ob_start();
1352
+ ?>
1353
+ <div class="newspack-preview-label"><?php echo esc_html( $post_statuses_labels[ $post_status ] ); ?></div>
1354
+ <?php
1355
+ return ob_get_clean();
1356
+ }
1357
+ }
1358
+
1359
+ /**
1360
+ * Pick either white or black, whatever has sufficient contrast with the color being passed to it.
1361
+ * From Newspack Theme functions.
1362
+ *
1363
+ * @param string $hex Hexidecimal value of the color to adjust.
1364
+ * @return string Either black or white hexidecimal values.
1365
+ *
1366
+ * @ref https://stackoverflow.com/questions/1331591/given-a-background-color-black-or-white-text
1367
+ */
1368
+ public static function get_color_for_contrast( $hex ) {
1369
+ // Hex RGB.
1370
+ $r1 = hexdec( substr( $hex, 1, 2 ) );
1371
+ $g1 = hexdec( substr( $hex, 3, 2 ) );
1372
+ $b1 = hexdec( substr( $hex, 5, 2 ) );
1373
+ // Black RGB.
1374
+ $black_color = '#000';
1375
+ $r2_black_color = hexdec( substr( $black_color, 1, 2 ) );
1376
+ $g2_black_color = hexdec( substr( $black_color, 3, 2 ) );
1377
+ $b2_black_color = hexdec( substr( $black_color, 5, 2 ) );
1378
+ // Calc contrast ratio.
1379
+ $l1 = 0.2126 * pow( $r1 / 255, 2.2 ) +
1380
+ 0.7152 * pow( $g1 / 255, 2.2 ) +
1381
+ 0.0722 * pow( $b1 / 255, 2.2 );
1382
+ $l2 = 0.2126 * pow( $r2_black_color / 255, 2.2 ) +
1383
+ 0.7152 * pow( $g2_black_color / 255, 2.2 ) +
1384
+ 0.0722 * pow( $b2_black_color / 255, 2.2 );
1385
+ $contrast_ratio = 0;
1386
+ if ( $l1 > $l2 ) {
1387
+ $contrast_ratio = (int) ( ( $l1 + 0.05 ) / ( $l2 + 0.05 ) );
1388
+ } else {
1389
+ $contrast_ratio = (int) ( ( $l2 + 0.05 ) / ( $l1 + 0.05 ) );
1390
+ }
1391
+ if ( $contrast_ratio > 5 ) {
1392
+ // If contrast is more than 5, return black color.
1393
+ return 'black';
1394
+ } else {
1395
+ // if not, return white color.
1396
+ return 'white';
1397
+ }
1398
+ }
1399
+
1400
+ /**
1401
+ * Get an array of allowed HTML attributes for sanitizing image markup.
1402
+ * For use with wp_kses: https://developer.wordpress.org/reference/functions/wp_kses/
1403
+ *
1404
+ * @return array
1405
+ */
1406
+ public static function get_sanitized_image_attributes() {
1407
+ return [
1408
+ 'img' => [
1409
+ 'alt' => true,
1410
+ 'class' => true,
1411
+ 'data-*' => true,
1412
+ 'decoding' => true,
1413
+ 'height' => true,
1414
+ 'loading' => true,
1415
+ 'sizes' => true,
1416
+ 'src' => true,
1417
+ 'srcset' => true,
1418
+ 'width' => true,
1419
+ ],
1420
+ 'noscript' => [],
1421
+ 'a' => [
1422
+ 'href' => true,
1423
+ ],
1424
+ ];
1425
+ }
1426
+
1427
+ /**
1428
+ * Get post date to be displayed.
1429
+ *
1430
+ * @param WP_Post $post Post object.
1431
+ * @return string Date string.
1432
+ */
1433
+ public static function get_displayed_post_date( $post = null ) {
1434
+ if ( $post === null ) {
1435
+ $post = get_post();
1436
+ }
1437
+ return apply_filters( 'newspack_blocks_displayed_post_date', mysql_to_rfc3339( $post->post_date ), $post );
1438
+ }
1439
+
1440
+ /**
1441
+ * Get post date in ISO-8601 format to be used in the datetime attribute.
1442
+ *
1443
+ * @param WP_Post $post Post object.
1444
+ * @return string Date string in ISO-8601 format.
1445
+ */
1446
+ public static function get_datetime_post_date( $post = null ) {
1447
+ if ( $post === null ) {
1448
+ $post = get_post();
1449
+ }
1450
+ /**
1451
+ * Filters the post date used for the datetime attribute.
1452
+ *
1453
+ * @param string Date string in a format appropriate for datetime attributes.
1454
+ */
1455
+ return apply_filters( 'newspack_blocks_displayed_post_date', get_post_datetime( $post )->format( 'c' ), $post );
1456
+ }
1457
+
1458
+ /**
1459
+ * Get post date to be displayed, formatted.
1460
+ *
1461
+ * @param WP_Post $post Post object.
1462
+ * @return string Formatted date.
1463
+ */
1464
+ public static function get_formatted_displayed_post_date( $post = null ) {
1465
+ if ( $post === null ) {
1466
+ $post = get_post();
1467
+ }
1468
+ $date = self::get_displayed_post_date( $post );
1469
+ $date = new DateTime( $date );
1470
+ $date_format = get_option( 'date_format' );
1471
+ $date_formatted = date_i18n( $date_format, $date->getTimestamp() );
1472
+ return apply_filters( 'newspack_blocks_formatted_displayed_post_date', $date_formatted, $post );
1473
+ }
1474
+
1475
+ /**
1476
+ * Get article meta footer.
1477
+ *
1478
+ * @param WP_Post $post Post object.
1479
+ */
1480
+ public static function get_article_meta_footer( $post = null ) {
1481
+ if ( $post === null ) {
1482
+ $post = get_post();
1483
+ }
1484
+ $meta_footer = apply_filters( 'newspack_blocks_article_meta_footer', '', $post );
1485
+ if ( strlen( $meta_footer ) > 0 ) {
1486
+ return '<span style="margin: 0 6px;" class="newspack_blocks__article-meta-footer__separator">|</span>' . $meta_footer;
1487
+ }
1488
+ }
1489
+
1490
+ /**
1491
+ * Get a formatted HTML string containing amount and frequency of a donation.
1492
+ *
1493
+ * @param float $amount Amount.
1494
+ * @param string $frequency Frequency.
1495
+ * @param bool $hide_once_label Whether to hide the "once" label.
1496
+ *
1497
+ * @return string
1498
+ */
1499
+ public static function get_formatted_amount( $amount = null, $frequency = null, $hide_once_label = false ) {
1500
+ if ( ! function_exists( 'wc_price' ) || ( method_exists( 'Newspack\Donations', 'is_platform_wc' ) && ! \Newspack\Donations::is_platform_wc() ) ) {
1501
+ if ( empty( $amount ) ) {
1502
+ return false;
1503
+ }
1504
+
1505
+ // Translators: %s is the %s is the frequency.
1506
+ $frequency_string = 'once' === $frequency ? $frequency : sprintf( __( 'per %s', 'newspack-blocks' ), $frequency );
1507
+ $formatter = new NumberFormatter( \get_locale(), NumberFormatter::CURRENCY );
1508
+ $formatted_price = '<span class="price-amount">' . $formatter->formatCurrency( $amount, 'USD' ) . '</span> <span class="tier-frequency">' . $frequency_string . '</span>';
1509
+ return str_replace( '.00', '', $formatted_price );
1510
+ }
1511
+
1512
+ $wc_formatted_amount = '';
1513
+ if ( null === $amount && null === $frequency ) {
1514
+ $currency_symbol = function_exists( 'get_woocommerce_currency_symbol' ) ? \get_woocommerce_currency_symbol() : '&#36;';
1515
+ $wc_formatted_amount = '<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">' . $currency_symbol . '</span>AMOUNT_PLACEHOLDER</bdi></span> FREQUENCY_PLACEHOLDER';
1516
+ } else {
1517
+ // If it's a float but with no decimal value, treat it as an int.
1518
+ if ( is_float( $amount ) && floor( $amount ) == $amount ) {
1519
+ $amount = (int) $amount;
1520
+ }
1521
+ // Format the amount with currency symbol and separators.
1522
+ $amount_string = \wc_price(
1523
+ $amount,
1524
+ [ 'decimals' => is_int( $amount ) ? 0 : 2 ]
1525
+ );
1526
+
1527
+ if ( ! function_exists( 'wcs_price_string' ) ) {
1528
+ return $amount_string;
1529
+ }
1530
+ $price_args = [
1531
+ 'recurring_amount' => $amount_string,
1532
+ 'subscription_period' => 'once' === $frequency ? 'day' : $frequency,
1533
+ ];
1534
+ $wc_formatted_amount = \wcs_price_string( $price_args );
1535
+
1536
+ if ( 'once' === $frequency ) {
1537
+ $once_label = $hide_once_label ? '' : __( ' once', 'newspack-blocks' );
1538
+ $wc_formatted_amount = preg_replace( '/ \/ ?.*/', $once_label, $wc_formatted_amount );
1539
+ }
1540
+ $wc_formatted_amount = str_replace( ' / ', __( ' per ', 'newspack-blocks' ), $wc_formatted_amount );
1541
+ }
1542
+
1543
+ return '<span class="wpbnbd__tiers__amount__value">' . $wc_formatted_amount . '</span>';
1544
+ }
1545
+
1546
+ /**
1547
+ * Get an image caption, optionally with credit appended.
1548
+ *
1549
+ * @param int $attachment_id Attachment ID of the image.
1550
+ * @param bool $include_caption Whether to include the caption.
1551
+ * @param bool $include_credit Whether to include the credit.
1552
+ *
1553
+ * @return string
1554
+ */
1555
+ public static function get_image_caption( $attachment_id = null, $include_caption = true, $include_credit = false ) {
1556
+ if ( ! $attachment_id || ( ! $include_caption && ! $include_credit ) ) {
1557
+ return '';
1558
+ }
1559
+
1560
+ $caption = $include_caption ? wp_get_attachment_caption( $attachment_id ) : '';
1561
+ $credit = '';
1562
+
1563
+ if ( $include_credit && method_exists( 'Newspack\Newspack_Image_Credits', 'get_media_credit_string' ) ) {
1564
+ $credit = \Newspack\Newspack_Image_Credits::get_media_credit_string( $attachment_id );
1565
+ }
1566
+
1567
+ $full_caption = trim( $caption . ' ' . $credit );
1568
+ if ( empty( $full_caption ) ) {
1569
+ return '';
1570
+ }
1571
+
1572
+ $combined_caption = sprintf(
1573
+ '<figcaption%1$s>%2$s</figcaption>',
1574
+ ! empty( $credit ) ? ' class="has-credit"' : '',
1575
+ $full_caption
1576
+ );
1577
+
1578
+ return $combined_caption;
1579
+ }
1580
+ }
1581
+ Newspack_Blocks::init();