@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,1031 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import apiFetch from '@wordpress/api-fetch';
5
+ import {
6
+ BlockControls,
7
+ InnerBlocks,
8
+ InspectorControls,
9
+ useBlockProps,
10
+ store as blockEditorStore,
11
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
12
+ __experimentalBlockVariationPicker as BlockVariationPicker,
13
+ } from '@wordpress/block-editor';
14
+ import { createBlocksFromInnerBlocksTemplate, getBlockType, registerBlockBindingsSource, store as blocksStore } from '@wordpress/blocks';
15
+ import {
16
+ Button,
17
+ Card,
18
+ CardBody,
19
+ Notice,
20
+ PanelBody,
21
+ Placeholder,
22
+ SelectControl,
23
+ Spinner,
24
+ ToggleControl,
25
+ Toolbar,
26
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
27
+ __experimentalUnitControl as UnitControl,
28
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
29
+ __experimentalToggleGroupControl as ToggleGroupControl,
30
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
31
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
32
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
33
+ __experimentalVStack as VStack,
34
+ } from '@wordpress/components';
35
+ import { store as coreStore } from '@wordpress/core-data';
36
+ import { useEffect, useState, useMemo } from '@wordpress/element';
37
+ import { useDispatch, useSelect } from '@wordpress/data';
38
+ import { decodeEntities } from '@wordpress/html-entities';
39
+ import { pencil, postAuthor, pullLeft, pullRight } from '@wordpress/icons';
40
+ import { __, sprintf } from '@wordpress/i18n';
41
+ import { addQueryArgs } from '@wordpress/url';
42
+
43
+ /**
44
+ * Register block bindings source for author data in the editor.
45
+ * This enables core blocks to display author data via bindings.
46
+ *
47
+ * Note: The binding reads from a global author object that is set by the
48
+ * AuthorContext.Provider. This is a workaround since bindings don't have
49
+ * direct access to React context.
50
+ */
51
+ // Per-instance author map for block bindings.
52
+ // Each Author Profile block registers its author here keyed by clientId,
53
+ // so multiple instances on the same page don't overwrite each other.
54
+ window.__newspackAuthorsByBlock = window.__newspackAuthorsByBlock || {};
55
+
56
+ if ( typeof registerBlockBindingsSource === 'function' ) {
57
+ registerBlockBindingsSource( {
58
+ name: 'newspack-blocks/author',
59
+ label: __( 'Author Profile', 'newspack-blocks' ),
60
+ getValues( { bindings, clientId, select } ) {
61
+ // Find the parent Author Profile block and look up its author.
62
+ const parents = select( 'core/block-editor' ).getBlockParents( clientId );
63
+ const authorMap = window.__newspackAuthorsByBlock;
64
+ const parentId = parents.find( id => authorMap[ id ] );
65
+ const author = ( parentId && authorMap[ parentId ] ) || {};
66
+ // Return empty for missing fields so WordPress core shows each block's
67
+ // own `placeholder` attribute in its native greyed-out style.
68
+ // Skip placeholder authors entirely (Site Editor template context).
69
+ const isPlaceholder = author.id === 'placeholder';
70
+ return Object.fromEntries(
71
+ Object.entries( bindings ).map( ( [ attribute, { args } ] ) => {
72
+ const key = args?.key;
73
+ if ( ! key || isPlaceholder ) {
74
+ return [ attribute, '' ];
75
+ }
76
+ // Handle special cases.
77
+ if ( key === 'url' || key === 'archive_url' ) {
78
+ return [ attribute, author.url || '' ];
79
+ }
80
+ // "More by Author Name" link text.
81
+ if ( key === 'archive_link_text' ) {
82
+ const linkText = author.name
83
+ ? sprintf(
84
+ /* translators: %s: author name */
85
+ __( 'More by %s', 'newspack-blocks' ),
86
+ author.name
87
+ )
88
+ : '';
89
+ // Return HTML with link tag for editor preview.
90
+ const linkUrl = author.url || '#';
91
+ return [ attribute, linkText ? `<a href="${ linkUrl }" class="no-op">${ linkText }</a>` : '' ];
92
+ }
93
+ return [ attribute, author[ key ] || '' ];
94
+ } )
95
+ );
96
+ },
97
+ } );
98
+ }
99
+
100
+ /**
101
+ * Internal dependencies
102
+ */
103
+ import { SingleAuthor } from './single-author';
104
+ import { AuthorDisplaySettings } from '../shared/author';
105
+ import { AuthorContext } from './context';
106
+
107
+ /**
108
+ * External dependencies
109
+ */
110
+ import { AutocompleteWithSuggestions } from 'newspack-components';
111
+
112
+ // Available units for avatarBorderRadius option.
113
+ export const units = [
114
+ {
115
+ value: '%',
116
+ label: '%',
117
+ },
118
+ {
119
+ value: 'px',
120
+ label: 'px',
121
+ },
122
+ {
123
+ value: 'em',
124
+ label: 'em',
125
+ },
126
+ {
127
+ value: 'rem',
128
+ label: 'rem',
129
+ },
130
+ ];
131
+
132
+ // Textsize options.
133
+ export const textSizeOptions = [
134
+ {
135
+ value: 'small',
136
+ label: /* translators: label for small text size option */ __( 'Small', 'newspack-blocks' ),
137
+ shortName: /* translators: abbreviation for small text size option */ __( 'S', 'newspack-blocks' ),
138
+ },
139
+ {
140
+ value: 'medium',
141
+ label: /* translators: label for medium text size option */ __( 'Medium', 'newspack-blocks' ),
142
+ shortName: /* translators: abbreviation for medium text size option */ __( 'M', 'newspack-blocks' ),
143
+ },
144
+ {
145
+ value: 'large',
146
+ label: /* translators: label for small text size option */ __( 'Large', 'newspack-blocks' ),
147
+ shortName: /* translators: abbreviation for large text size option */ __( 'L', 'newspack-blocks' ),
148
+ },
149
+ {
150
+ value: 'extra-large',
151
+ label: /* translators: label for extra-large text size option */ __( 'Extra Large', 'newspack-blocks' ),
152
+ shortName: /* translators: abbreviation for small text size option */ __( 'XL', 'newspack-blocks' ),
153
+ },
154
+ ];
155
+
156
+ // Avatar size options.
157
+ export const avatarSizeOptions = [
158
+ {
159
+ value: 72,
160
+ label: /* translators: label for small avatar size option */ __( 'Small', 'newspack-blocks' ),
161
+ shortName: /* translators: abbreviation for small avatar size option */ __( 'S', 'newspack-blocks' ),
162
+ },
163
+ {
164
+ value: 128,
165
+ label: /* translators: label for medium avatar size option */ __( 'Medium', 'newspack-blocks' ),
166
+ shortName: /* translators: abbreviation for medium avatar size option */ __( 'M', 'newspack-blocks' ),
167
+ },
168
+ {
169
+ value: 192,
170
+ label: /* translators: label for large avatar size option */ __( 'Large', 'newspack-blocks' ),
171
+ shortName: /* translators: abbreviation for large avatar size option */ __( 'L', 'newspack-blocks' ),
172
+ },
173
+ {
174
+ value: 256,
175
+ label: /* translators: label for extra-large avatar size option */ __( 'Extra-large', 'newspack-blocks' ),
176
+ shortName: /* translators: abbreviation for extra-large avatar size option */ __( 'XL', 'newspack-blocks' ),
177
+ },
178
+ ];
179
+
180
+ /**
181
+ * Variation picker shown when the block has no inner blocks.
182
+ * Follows the same pattern as the core Columns block.
183
+ */
184
+ function VariationPlaceholder( { clientId, name, setAttributes } ) {
185
+ const { blockType, defaultVariation, variations } = useSelect(
186
+ select => {
187
+ const { getBlockVariations, getBlockType: _getBlockType, getDefaultBlockVariation } = select( blocksStore );
188
+ return {
189
+ blockType: _getBlockType( name ),
190
+ defaultVariation: getDefaultBlockVariation( name, 'block' ),
191
+ variations: getBlockVariations( name, 'block' ),
192
+ };
193
+ },
194
+ [ name ]
195
+ );
196
+ const { replaceInnerBlocks } = useDispatch( blockEditorStore );
197
+ const blockProps = useBlockProps();
198
+
199
+ return (
200
+ <div { ...blockProps }>
201
+ <BlockVariationPicker
202
+ icon={ blockType?.icon?.src }
203
+ label={ blockType?.title }
204
+ variations={ variations }
205
+ instructions={ __( 'Select a layout to start with:', 'newspack-blocks' ) }
206
+ onSelect={ ( nextVariation = defaultVariation ) => {
207
+ setAttributes( { ...nextVariation.attributes, variation: nextVariation.name } );
208
+ if ( nextVariation.innerBlocks ) {
209
+ replaceInnerBlocks( clientId, createBlocksFromInnerBlocksTemplate( nextVariation.innerBlocks ), true );
210
+ }
211
+ } }
212
+ />
213
+ </div>
214
+ );
215
+ }
216
+
217
+ // Module-level cache for social icon SVGs so multiple block instances share one fetch.
218
+ let socialIconSvgsCache = null;
219
+ const fetchSocialIconSvgs = () => {
220
+ if ( ! socialIconSvgsCache ) {
221
+ socialIconSvgsCache = apiFetch( { path: '/newspack/v1/social-icons' } ).catch( () => ( {} ) );
222
+ }
223
+ return socialIconSvgsCache;
224
+ };
225
+
226
+ // Placeholder author for Site Editor template context.
227
+ // Builds the social entries from the SVG map so every supported service gets an
228
+ // inner block in the template. Publishers can then remove the ones they don't need.
229
+ const DEFAULT_PLACEHOLDER_AUTHOR = Object.freeze( {
230
+ id: 'placeholder',
231
+ url: '#',
232
+ avatar: '', // Empty triggers the avatar block's built-in placeholder rendering.
233
+ social: Object.freeze( {} ),
234
+ email: Object.freeze( { url: 'mailto:placeholder@example.com', svg: '' } ),
235
+ newspack_phone_number: Object.freeze( { url: 'tel:0000000000', svg: '' } ),
236
+ } );
237
+
238
+ const getPlaceholderAuthor = ( socialIconSvgs = {} ) => {
239
+ const hasSocialSvgs = Object.keys( socialIconSvgs ).length > 0;
240
+ if ( ! hasSocialSvgs ) {
241
+ return DEFAULT_PLACEHOLDER_AUTHOR;
242
+ }
243
+
244
+ const social = Object.fromEntries(
245
+ Object.entries( socialIconSvgs )
246
+ .filter( ( [ key ] ) => ! [ 'email', 'phone' ].includes( key ) ) // Exclude top-level properties on the author object.
247
+ .map( ( [ service, svg ] ) => [ service, { url: '#', svg: svg || '' } ] )
248
+ );
249
+
250
+ return {
251
+ ...DEFAULT_PLACEHOLDER_AUTHOR,
252
+ social,
253
+ email: { url: 'mailto:placeholder@example.com', svg: socialIconSvgs.email || '' },
254
+ newspack_phone_number: { url: 'tel:0000000000', svg: socialIconSvgs.phone || '' },
255
+ };
256
+ };
257
+
258
+ const AuthorProfile = ( { attributes, setAttributes, context, clientId } ) => {
259
+ const { replaceInnerBlocks } = useDispatch( blockEditorStore );
260
+
261
+ // ALL HOOKS MUST BE CALLED UNCONDITIONALLY (React rules of hooks)
262
+ const [ author, setAuthor ] = useState( null );
263
+ const [ contextualAuthors, setContextualAuthors ] = useState( [] );
264
+ const [ suggestions, setSuggestions ] = useState( null );
265
+ const [ error, setError ] = useState( null );
266
+ const [ isLoading, setIsLoading ] = useState( false );
267
+ const [ maxItemsToSuggest, setMaxItemsToSuggest ] = useState( 0 );
268
+ const [ showSpecificSelector, setShowSpecificSelector ] = useState( false );
269
+ const [ previewAuthorIndex, setPreviewAuthorIndex ] = useState( 0 );
270
+ const [ socialIconSvgs, setSocialIconSvgs ] = useState( {} );
271
+
272
+ const {
273
+ authorId,
274
+ isGuestAuthor,
275
+ isContextual,
276
+ layoutVersion,
277
+ showSocial,
278
+ showEmail,
279
+ textSize,
280
+ showAvatar,
281
+ avatarAlignment,
282
+ avatarBorderRadius,
283
+ avatarSize,
284
+ avatarHideDefault,
285
+ showEmptyBio,
286
+ variation,
287
+ } = attributes;
288
+ const blockProps = useBlockProps();
289
+
290
+ // Get post ID from block context or editor
291
+ const editorPostId = useSelect( select => select( 'core/editor' )?.getCurrentPostId?.(), [] );
292
+ const postId = context?.postId || editorPostId;
293
+
294
+ // Check if custom byline is active and extract referenced author IDs.
295
+ // Returns IDs as a comma-separated string to avoid new array references on each render.
296
+ const { customBylineActive, bylineAuthorIdsStr } = useSelect(
297
+ select => {
298
+ if ( ! isContextual ) {
299
+ return { customBylineActive: false, bylineAuthorIdsStr: '' };
300
+ }
301
+ const meta = select( 'core/editor' )?.getEditedPostAttribute?.( 'meta' );
302
+ const isActive = meta?._newspack_byline_active ?? false;
303
+ if ( ! isActive ) {
304
+ return { customBylineActive: false, bylineAuthorIdsStr: '' };
305
+ }
306
+ const byline = meta?._newspack_byline ?? '';
307
+ const ids = [ ...byline.matchAll( /\[Author\s+id\s*=\s*(\d+)\]/gi ) ].map( m => m[ 1 ] );
308
+ return { customBylineActive: true, bylineAuthorIdsStr: ids.join( ',' ) };
309
+ },
310
+ [ isContextual ]
311
+ );
312
+ const bylineAuthorIds = bylineAuthorIdsStr ? bylineAuthorIdsStr.split( ',' ).map( Number ) : [];
313
+
314
+ // Detect Site Editor template context where real author data is not meaningful.
315
+ const isTemplateLikeContext = useSelect( select => {
316
+ const postType = select( 'core/editor' )?.getCurrentPostType?.();
317
+ return postType === 'wp_template' || postType === 'wp_template_part';
318
+ }, [] );
319
+
320
+ // Fetch social icon SVGs for the placeholder in template context.
321
+ useEffect( () => {
322
+ if ( ! isTemplateLikeContext ) {
323
+ return;
324
+ }
325
+ fetchSocialIconSvgs().then( setSocialIconSvgs );
326
+ }, [ isTemplateLikeContext ] );
327
+
328
+ // Nested inner blocks mode is enabled automatically in block themes when
329
+ // Newspack Plugin is active (provides the avatar and social links blocks).
330
+ const isNestedMode = useSelect( select => {
331
+ const theme = select( coreStore ).getCurrentTheme();
332
+ return ( theme?.is_block_theme ?? false ) && !! getBlockType( 'newspack/avatar' ) && !! getBlockType( 'newspack/author-profile-social' );
333
+ }, [] );
334
+
335
+ // Check for inner blocks (pattern picker shows when empty).
336
+ const hasInnerBlocks = useSelect( select => !! select( blockEditorStore ).getBlocks( clientId ).length, [ clientId ] );
337
+
338
+ // Look up the active variation's template from the store.
339
+ const blockVariations = useSelect( select => select( blocksStore ).getBlockVariations( 'newspack-blocks/author-profile', 'block' ), [] );
340
+ const defaultVariation = useMemo( () => blockVariations?.find( v => v.isDefault ), [ blockVariations ] );
341
+ const activeVariationTemplate = useMemo( () => {
342
+ const match = blockVariations?.find( v => v.name === variation );
343
+ return match?.innerBlocks || defaultVariation?.innerBlocks;
344
+ }, [ blockVariations, variation, defaultVariation ] );
345
+
346
+ // Set layoutVersion to 2 for brand new blocks in block themes.
347
+ // This persists the mode choice and enables InnerBlocks-based layout.
348
+ // Only converts unconfigured blocks to preserve existing blocks created in classic themes.
349
+ const isUnconfiguredBlock = authorId === 0 && ! isContextual;
350
+ useEffect( () => {
351
+ if ( isNestedMode && layoutVersion === 1 && isUnconfiguredBlock ) {
352
+ setAttributes( { layoutVersion: 2 } );
353
+ }
354
+ }, [ isNestedMode, layoutVersion, isUnconfiguredBlock, setAttributes ] );
355
+
356
+ // Auto-populate inner blocks from variation attribute on mount (e.g., when inserted from a pattern).
357
+ // Only runs once; subsequent empty states show the variation picker instead of auto-repopulating.
358
+ // Initialized with hasInnerBlocks so existing blocks (after page reload) don't re-populate.
359
+ const [ didAutoPopulate, setDidAutoPopulate ] = useState( hasInnerBlocks );
360
+ useEffect( () => {
361
+ if ( ! didAutoPopulate && variation && ! hasInnerBlocks && activeVariationTemplate ) {
362
+ replaceInnerBlocks( clientId, createBlocksFromInnerBlocksTemplate( activeVariationTemplate ), true );
363
+ setDidAutoPopulate( true );
364
+ }
365
+ }, [ didAutoPopulate, variation, hasInnerBlocks, activeVariationTemplate, clientId, replaceInnerBlocks ] );
366
+
367
+ // Fetch author for specific mode
368
+ useEffect( () => {
369
+ if ( isContextual || 0 === authorId ) {
370
+ return;
371
+ }
372
+ getAuthorById();
373
+ }, [ authorId, avatarHideDefault, isGuestAuthor, isContextual ] );
374
+
375
+ // Fetch authors for contextual mode
376
+ useEffect( () => {
377
+ if ( ! isContextual || isTemplateLikeContext ) {
378
+ setContextualAuthors( [] );
379
+ return;
380
+ }
381
+ // When custom byline is active, fetch the specific byline authors.
382
+ if ( customBylineActive ) {
383
+ if ( bylineAuthorIds.length ) {
384
+ getBylineAuthors();
385
+ } else {
386
+ setContextualAuthors( [] );
387
+ }
388
+ return;
389
+ }
390
+ if ( ! postId ) {
391
+ setContextualAuthors( [] );
392
+ return;
393
+ }
394
+ getContextualAuthors();
395
+ }, [ isContextual, postId, avatarHideDefault, showEmail, customBylineActive, bylineAuthorIdsStr, isTemplateLikeContext ] );
396
+
397
+ const getAuthorById = async () => {
398
+ setError( null );
399
+ setIsLoading( true );
400
+ try {
401
+ const params = {
402
+ author_id: authorId,
403
+ is_guest_author: isGuestAuthor ? 1 : 0,
404
+ fields: 'id,name,bio,email,social,avatar,url',
405
+ };
406
+
407
+ if ( avatarHideDefault ) {
408
+ params.avatar_hide_default = 1;
409
+ }
410
+
411
+ const response = await apiFetch( {
412
+ path: addQueryArgs( '/newspack-blocks/v1/authors', params ),
413
+ } );
414
+
415
+ const _author = response.pop();
416
+
417
+ if ( ! _author ) {
418
+ throw sprintf(
419
+ /* translators: %s: error text for when no authors are found. */
420
+ __( 'No authors or guest authors found for ID %s.', 'newspack-blocks' ),
421
+ authorId
422
+ );
423
+ }
424
+ setAuthor( _author );
425
+ } catch ( e ) {
426
+ setError(
427
+ e.message ||
428
+ e ||
429
+ sprintf(
430
+ /* translators: %s: error text for when no authors are found. */
431
+ __( 'No authors or guest authors found for ID %s.', 'newspack-blocks' ),
432
+ authorId
433
+ )
434
+ );
435
+ }
436
+ setIsLoading( false );
437
+ };
438
+
439
+ const getContextualAuthors = async () => {
440
+ setError( null );
441
+ setIsLoading( true );
442
+ try {
443
+ // Only fetch email if showEmail is enabled (privacy consideration)
444
+ const fields = [ 'id', 'name', 'bio', 'social', 'avatar', 'url' ];
445
+ if ( showEmail ) {
446
+ fields.push( 'email' );
447
+ }
448
+
449
+ const params = {
450
+ post_id: postId,
451
+ fields: fields.join( ',' ),
452
+ };
453
+
454
+ if ( avatarHideDefault ) {
455
+ params.avatar_hide_default = 1;
456
+ }
457
+
458
+ const response = await apiFetch( {
459
+ path: addQueryArgs( '/newspack-blocks/v1/authors', params ),
460
+ } );
461
+
462
+ setContextualAuthors( response || [] );
463
+ } catch ( e ) {
464
+ setError( e.message || e || __( 'Error fetching authors for this post.', 'newspack-blocks' ) );
465
+ setContextualAuthors( [] );
466
+ }
467
+ setIsLoading( false );
468
+ };
469
+
470
+ const getBylineAuthors = async () => {
471
+ setError( null );
472
+ setIsLoading( true );
473
+ try {
474
+ const fields = [ 'id', 'name', 'bio', 'social', 'avatar', 'url' ];
475
+ if ( showEmail ) {
476
+ fields.push( 'email' );
477
+ }
478
+ const results = await Promise.all(
479
+ bylineAuthorIds.map( id => {
480
+ const params = {
481
+ author_id: id,
482
+ is_guest_author: 0,
483
+ fields: fields.join( ',' ),
484
+ };
485
+ if ( avatarHideDefault ) {
486
+ params.avatar_hide_default = 1;
487
+ }
488
+ return apiFetch( {
489
+ path: addQueryArgs( '/newspack-blocks/v1/authors', params ),
490
+ } );
491
+ } )
492
+ );
493
+ setContextualAuthors( results.flat().filter( Boolean ) );
494
+ } catch ( e ) {
495
+ setError( e.message || e || __( 'Error fetching byline authors.', 'newspack-blocks' ) );
496
+ setContextualAuthors( [] );
497
+ }
498
+ setIsLoading( false );
499
+ };
500
+
501
+ // Memoize authors for rendering based on mode
502
+ const authorsToRender = useMemo( () => {
503
+ let authors;
504
+ if ( isContextual ) {
505
+ if ( isTemplateLikeContext ) {
506
+ return [ getPlaceholderAuthor( socialIconSvgs ) ];
507
+ }
508
+ authors = contextualAuthors;
509
+ } else {
510
+ authors = author ? [ author ] : [];
511
+ }
512
+ if ( ! showEmptyBio ) {
513
+ authors = authors.filter( a => a.bio );
514
+ }
515
+ return authors;
516
+ }, [ isContextual, showEmptyBio, isTemplateLikeContext, socialIconSvgs, contextualAuthors, author ] );
517
+
518
+ // Reset preview index when authors list changes (e.g., switching posts)
519
+ useEffect( () => {
520
+ setPreviewAuthorIndex( 0 );
521
+ }, [ authorsToRender.length ] );
522
+
523
+ // Register author in the per-instance map for block bindings (nested mode only).
524
+ // Each Author Profile block stores its author keyed by clientId, so bindings
525
+ // in child blocks can look up the correct author via getBlockParents().
526
+ useEffect( () => {
527
+ if ( layoutVersion !== 2 ) {
528
+ return;
529
+ }
530
+ const safeIndex = Math.min( previewAuthorIndex, Math.max( 0, authorsToRender.length - 1 ) );
531
+ const previewAuthor = authorsToRender[ safeIndex ] || null;
532
+ window.__newspackAuthorsByBlock[ clientId ] = previewAuthor;
533
+ return () => {
534
+ delete window.__newspackAuthorsByBlock[ clientId ];
535
+ };
536
+ }, [ authorsToRender, previewAuthorIndex, layoutVersion, clientId ] );
537
+
538
+ // Combine social links and email, which are shown together.
539
+ const getSocialLinks = authorData => {
540
+ const socialLinks = ( showSocial && authorData?.social ) || {};
541
+ if ( showEmail && authorData?.email ) {
542
+ socialLinks.email = authorData.email;
543
+ } else {
544
+ delete socialLinks.email;
545
+ }
546
+ return socialLinks;
547
+ };
548
+
549
+ // Determine if we're in nested layout mode (publisher-controlled composition).
550
+ // In nested mode, hide field toggles since publishers control display by adding/removing blocks.
551
+ const isNestedLayout = layoutVersion === 2;
552
+
553
+ // Inspector controls for display settings
554
+ const inspectorControls = (
555
+ <InspectorControls>
556
+ { isNestedLayout && (
557
+ <PanelBody title={ __( 'Display', 'newspack-blocks' ) }>
558
+ <ToggleControl
559
+ label={ __( 'Show authors without bio', 'newspack-blocks' ) }
560
+ help={ __( 'Display author profiles even if their bio is empty.', 'newspack-blocks' ) }
561
+ checked={ showEmptyBio }
562
+ onChange={ () => setAttributes( { showEmptyBio: ! showEmptyBio } ) }
563
+ __nextHasNoMarginBottom
564
+ />
565
+ </PanelBody>
566
+ ) }
567
+ { ! isNestedLayout && (
568
+ <PanelBody title={ __( 'Settings', 'newspack-blocks' ) }>
569
+ <ToggleGroupControl
570
+ label={ __( 'Text size', 'newspack-blocks' ) }
571
+ value={ textSize }
572
+ onChange={ value => setAttributes( { textSize: value } ) }
573
+ isBlock
574
+ __next40pxDefaultSize
575
+ >
576
+ { textSizeOptions.map( option => (
577
+ <ToggleGroupControlOption key={ option.value } label={ option.shortName } value={ option.value } />
578
+ ) ) }
579
+ </ToggleGroupControl>
580
+ <AuthorDisplaySettings attributes={ attributes } setAttributes={ setAttributes } />
581
+ </PanelBody>
582
+ ) }
583
+ { /* In nested mode, avatar is controlled via the inner newspack/avatar block */ }
584
+ { ! isNestedLayout && (
585
+ <PanelBody title={ __( 'Avatar', 'newspack-blocks' ) }>
586
+ <ToggleControl
587
+ label={ __( 'Display avatar', 'newspack-blocks' ) }
588
+ checked={ showAvatar }
589
+ onChange={ () => setAttributes( { showAvatar: ! showAvatar } ) }
590
+ __nextHasNoMarginBottom
591
+ />
592
+ { showAvatar && (
593
+ <ToggleControl
594
+ label={ __( 'Hide default avatar', 'newspack-blocks' ) }
595
+ checked={ avatarHideDefault }
596
+ onChange={ () => setAttributes( { avatarHideDefault: ! avatarHideDefault } ) }
597
+ __nextHasNoMarginBottom
598
+ />
599
+ ) }
600
+ { showAvatar && (
601
+ <ToggleGroupControl
602
+ label={ __( 'Size', 'newspack-blocks' ) }
603
+ aria-label={ __( 'Avatar size', 'newspack-blocks' ) }
604
+ value={ avatarSize }
605
+ onChange={ value => setAttributes( { avatarSize: value } ) }
606
+ isBlock
607
+ __next40pxDefaultSize
608
+ >
609
+ { avatarSizeOptions.map( option => (
610
+ <ToggleGroupControlOption key={ option.value } label={ option.shortName } value={ option.value } />
611
+ ) ) }
612
+ </ToggleGroupControl>
613
+ ) }
614
+ { showAvatar && (
615
+ <UnitControl
616
+ label={ __( 'Border radius', 'newspack-blocks' ) }
617
+ aria-label={ __( 'Avatar border radius', 'newspack-blocks' ) }
618
+ labelPosition="edge"
619
+ __next40pxDefaultSize
620
+ __unstableInputWidth="80px"
621
+ units={ units }
622
+ value={ avatarBorderRadius }
623
+ onChange={ value => setAttributes( { avatarBorderRadius: 0 > parseFloat( value ) ? '0' : value } ) }
624
+ />
625
+ ) }
626
+ </PanelBody>
627
+ ) }
628
+ </InspectorControls>
629
+ );
630
+
631
+ // Loading placeholder shared between nested and flat mode.
632
+ const loadingPlaceholder = (
633
+ <div { ...blockProps }>
634
+ { inspectorControls }
635
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
636
+ <VStack alignment="center" style={ { width: '100%' } }>
637
+ <Spinner style={ { margin: '0' } } />
638
+ <span style={ { fontWeight: '500' } }>{ __( 'Fetching authors…', 'newspack-blocks' ) }</span>
639
+ </VStack>
640
+ </Placeholder>
641
+ </div>
642
+ );
643
+
644
+ // Block controls for avatar alignment and edit button
645
+ const blockControls = authorsToRender.length > 0 && (
646
+ <BlockControls>
647
+ { ! isNestedLayout && showAvatar && ! attributes.className?.includes( 'is-style-center' ) && (
648
+ <Toolbar
649
+ controls={ [
650
+ {
651
+ icon: pullLeft,
652
+ title: __( 'Show avatar on left', 'newspack-blocks' ),
653
+ isActive: avatarAlignment === 'left',
654
+ onClick: () => setAttributes( { avatarAlignment: 'left' } ),
655
+ },
656
+ {
657
+ icon: pullRight,
658
+ title: __( 'Show avatar on right', 'newspack-blocks' ),
659
+ isActive: avatarAlignment === 'right',
660
+ onClick: () => setAttributes( { avatarAlignment: 'right' } ),
661
+ },
662
+ ] }
663
+ />
664
+ ) }
665
+ { ! isContextual && (
666
+ <Toolbar
667
+ controls={ [
668
+ {
669
+ icon: pencil,
670
+ title: __( 'Edit selection', 'newspack-blocks' ),
671
+ onClick: () => {
672
+ setAttributes( { authorId: 0 } );
673
+ setAuthor( null );
674
+ },
675
+ },
676
+ ] }
677
+ />
678
+ ) }
679
+ </BlockControls>
680
+ );
681
+
682
+ // Mode selection placeholder for new blocks (shared by nested and flat modes).
683
+ const modeSelectionPlaceholder = (
684
+ <div { ...blockProps }>
685
+ { inspectorControls }
686
+ <Placeholder
687
+ className="newspack-blocks-author-profile"
688
+ icon={ postAuthor }
689
+ label={ __( 'Author Profile', 'newspack-blocks' ) }
690
+ instructions={ __( 'Select a type:', 'newspack-blocks' ) }
691
+ >
692
+ <Button variant="primary" onClick={ () => setAttributes( { isContextual: true } ) }>
693
+ { __( 'Contextual', 'newspack-blocks' ) }
694
+ </Button>
695
+ <Button variant="secondary" onClick={ () => setShowSpecificSelector( true ) }>
696
+ { __( 'Specific', 'newspack-blocks' ) }
697
+ </Button>
698
+ </Placeholder>
699
+ </div>
700
+ );
701
+
702
+ // NESTED MODE: Use InnerBlocks for publisher-controlled layout (layoutVersion 2)
703
+ // This respects the block's saved mode regardless of current theme
704
+ if ( isNestedLayout ) {
705
+ // A v2 block opened in a classic theme can't render its inner blocks properly.
706
+ if ( ! isNestedMode ) {
707
+ return (
708
+ <div { ...blockProps }>
709
+ { inspectorControls }
710
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
711
+ <Notice status="warning" isDismissible={ false }>
712
+ { __(
713
+ 'This block was created with a block theme and is not supported in the current theme. It will render using the classic layout on the frontend.',
714
+ 'newspack-blocks'
715
+ ) }
716
+ </Notice>
717
+ </Placeholder>
718
+ </div>
719
+ );
720
+ }
721
+
722
+ // Variation picker: shown when block has no inner blocks.
723
+ if ( ! hasInnerBlocks ) {
724
+ return <VariationPlaceholder clientId={ clientId } name="newspack-blocks/author-profile" setAttributes={ setAttributes } />;
725
+ }
726
+
727
+ // Mode selection for new blocks in nested mode
728
+ if ( ! authorId && ! isContextual && ! showSpecificSelector ) {
729
+ return modeSelectionPlaceholder;
730
+ }
731
+
732
+ // Loading state
733
+ if ( isLoading ) {
734
+ return loadingPlaceholder;
735
+ }
736
+
737
+ // Custom byline with no real authors referenced
738
+ if ( isContextual && customBylineActive && ! bylineAuthorIds.length ) {
739
+ return (
740
+ <div { ...blockProps }>
741
+ { inspectorControls }
742
+ <div className="newspack-author-profile-disabled">
743
+ <Notice status="warning" isDismissible={ false }>
744
+ { __( 'Author bio is hidden because Custom Byline is active on this post.', 'newspack-blocks' ) }
745
+ </Notice>
746
+ </div>
747
+ </div>
748
+ );
749
+ }
750
+
751
+ // Specific mode: show author search when no author selected
752
+ if ( ! isContextual && ! authorId ) {
753
+ return (
754
+ <div { ...blockProps }>
755
+ { inspectorControls }
756
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
757
+ { error && (
758
+ <Notice status="error" isDismissible={ false }>
759
+ { error }
760
+ </Notice>
761
+ ) }
762
+ <AutocompleteWithSuggestions
763
+ label={ __( 'Search for an author to display', 'newspack-blocks' ) }
764
+ help={ __( 'Begin typing name, click autocomplete result to select.', 'newspack-blocks' ) }
765
+ fetchSuggestions={ async ( search = null, offset = 0 ) => {
766
+ setSuggestions( null );
767
+ if ( authorId && ! error ) {
768
+ return [];
769
+ }
770
+ const response = await apiFetch( {
771
+ parse: false,
772
+ path: addQueryArgs( '/newspack-blocks/v1/authors', {
773
+ search,
774
+ offset,
775
+ fields: 'id,name',
776
+ } ),
777
+ } );
778
+ const total = parseInt( response.headers.get( 'x-wp-total' ) || 0, 10 );
779
+ const authors = await response.json();
780
+ if ( ! maxItemsToSuggest && ! search ) {
781
+ setMaxItemsToSuggest( total );
782
+ }
783
+ const _suggestions = authors.map( _author => ( {
784
+ value: _author.id,
785
+ label: decodeEntities( _author.name ) || __( '(no name)', 'newspack-blocks' ),
786
+ isGuestAuthor: _author.is_guest,
787
+ } ) );
788
+ setSuggestions( _suggestions );
789
+ return _suggestions;
790
+ } }
791
+ maxItemsToSuggest={ maxItemsToSuggest }
792
+ onChange={ items => {
793
+ let selectionIsGuest = false;
794
+ const selection = items[ 0 ];
795
+ if ( suggestions ) {
796
+ suggestions.forEach( suggestion => {
797
+ if ( parseInt( selection?.value, 10 ) === parseInt( suggestion?.value, 10 ) && suggestion?.isGuestAuthor ) {
798
+ selectionIsGuest = true;
799
+ }
800
+ } );
801
+ }
802
+ setAttributes( {
803
+ authorId: parseInt( selection?.value || 0, 10 ),
804
+ isGuestAuthor: selectionIsGuest,
805
+ } );
806
+ } }
807
+ postTypeLabel={ __( 'author', 'newspack-blocks' ) }
808
+ postTypeLabelPlural={ __( 'authors', 'newspack-blocks' ) }
809
+ selectedItems={ [] }
810
+ />
811
+ </Placeholder>
812
+ </div>
813
+ );
814
+ }
815
+
816
+ // Contextual mode: no authors found
817
+ if ( isContextual && ! authorsToRender.length ) {
818
+ return (
819
+ <div { ...blockProps }>
820
+ { inspectorControls }
821
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
822
+ { __( 'No authors found for this post.', 'newspack-blocks' ) }
823
+ </Placeholder>
824
+ </div>
825
+ );
826
+ }
827
+
828
+ // Get preview author (bounds-checked)
829
+ const safeIndex = Math.min( previewAuthorIndex, authorsToRender.length - 1 );
830
+ const previewAuthor = authorsToRender[ safeIndex ];
831
+
832
+ // Set in the per-instance map synchronously so bindings have access on first render.
833
+ // The useEffect handles cleanup when component unmounts.
834
+ window.__newspackAuthorsByBlock[ clientId ] = previewAuthor;
835
+
836
+ const nestedBlockProps = {
837
+ ...blockProps,
838
+ className: `${ blockProps.className } wp-block-newspack-blocks-author-profile is-nested-mode`,
839
+ };
840
+
841
+ return (
842
+ <AuthorContext.Provider value={ previewAuthor }>
843
+ <div { ...nestedBlockProps }>
844
+ { inspectorControls }
845
+ { blockControls }
846
+ { /* Author selector: only shown in contextual mode with multiple authors */ }
847
+ { isContextual && authorsToRender.length > 1 && (
848
+ <Card isRounded={ false } size="small" style={ { marginBottom: '32px' } } variant="secondary">
849
+ <CardBody>
850
+ <SelectControl
851
+ label={ __( 'Preview author', 'newspack-blocks' ) }
852
+ value={ safeIndex }
853
+ options={ authorsToRender.map( ( a, index ) => ( {
854
+ label: a.name,
855
+ value: index,
856
+ } ) ) }
857
+ onChange={ value => setPreviewAuthorIndex( parseInt( value, 10 ) ) }
858
+ help={ sprintf(
859
+ /* translators: %d: number of authors */
860
+ __( 'Previewing 1 of %d authors. All authors display on frontend.', 'newspack-blocks' ),
861
+ authorsToRender.length
862
+ ) }
863
+ __next40pxDefaultSize
864
+ __nextHasNoMarginBottom
865
+ />
866
+ </CardBody>
867
+ </Card>
868
+ ) }
869
+ { /* Key forces re-render when author changes, which re-evaluates bindings */ }
870
+ <InnerBlocks
871
+ key={ `author-${ previewAuthor?.id || 'none' }` }
872
+ template={ activeVariationTemplate }
873
+ templateLock="insert"
874
+ allowedBlocks={ [ 'core/columns', 'core/group' ] }
875
+ />
876
+ </div>
877
+ </AuthorContext.Provider>
878
+ );
879
+ }
880
+
881
+ // MODE SELECTION: Show mode selector for NEW blocks (no authorId and not contextual)
882
+ if ( ! authorId && ! isContextual && ! showSpecificSelector ) {
883
+ return modeSelectionPlaceholder;
884
+ }
885
+
886
+ // CONTEXTUAL MODE
887
+ if ( isContextual ) {
888
+ // Loading state
889
+ if ( isLoading ) {
890
+ return loadingPlaceholder;
891
+ }
892
+
893
+ // Custom byline with no real authors referenced
894
+ if ( customBylineActive && ! bylineAuthorIds.length ) {
895
+ return (
896
+ <div { ...blockProps }>
897
+ { inspectorControls }
898
+ <div className="newspack-author-profile-disabled">
899
+ <Notice status="warning" isDismissible={ false }>
900
+ { __( 'Author bio is hidden because Custom Byline is active on this post.', 'newspack-blocks' ) }
901
+ </Notice>
902
+ </div>
903
+ </div>
904
+ );
905
+ }
906
+
907
+ // No authors found
908
+ if ( ! authorsToRender.length ) {
909
+ return (
910
+ <div { ...blockProps }>
911
+ { inspectorControls }
912
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
913
+ { __( 'No authors found for this post.', 'newspack-blocks' ) }
914
+ </Placeholder>
915
+ </div>
916
+ );
917
+ }
918
+
919
+ // Render contextual authors
920
+ return (
921
+ <div { ...blockProps }>
922
+ { inspectorControls }
923
+ { blockControls }
924
+ { authorsToRender.map( authorData => (
925
+ <SingleAuthor
926
+ key={ authorData.id }
927
+ author={ { ...authorData, social: getSocialLinks( authorData ) } }
928
+ attributes={ attributes }
929
+ />
930
+ ) ) }
931
+ </div>
932
+ );
933
+ }
934
+
935
+ // SPECIFIC MODE: Author selected - render it
936
+ if ( author ) {
937
+ return (
938
+ <div { ...blockProps }>
939
+ { inspectorControls }
940
+ { blockControls }
941
+ <SingleAuthor author={ { ...author, social: getSocialLinks( author ) } } attributes={ attributes } />
942
+ </div>
943
+ );
944
+ }
945
+
946
+ // SPECIFIC MODE: No author selected - show search
947
+ return (
948
+ <div { ...blockProps }>
949
+ { inspectorControls }
950
+ <Placeholder className="newspack-blocks-author-profile" icon={ postAuthor } label={ __( 'Author Profile', 'newspack-blocks' ) }>
951
+ { error && (
952
+ <Notice status="error" isDismissible={ false }>
953
+ { error }
954
+ </Notice>
955
+ ) }
956
+ { isLoading && (
957
+ <VStack alignment="center" style={ { width: '100%' } }>
958
+ <Spinner style={ { margin: '0' } } />
959
+ <span style={ { fontWeight: '500' } }>{ __( 'Fetching authors…', 'newspack-blocks' ) }</span>
960
+ </VStack>
961
+ ) }
962
+ { ! isLoading && (
963
+ <AutocompleteWithSuggestions
964
+ label={ __( 'Search for an author to display', 'newspack-blocks' ) }
965
+ help={ __( 'Begin typing name, click autocomplete result to select.', 'newspack-blocks' ) }
966
+ fetchSuggestions={ async ( search = null, offset = 0 ) => {
967
+ // Reset suggestions in state.
968
+ setSuggestions( null );
969
+
970
+ // If we already have a selected author, no need to fetch suggestions.
971
+ if ( authorId && ! error ) {
972
+ return [];
973
+ }
974
+
975
+ const response = await apiFetch( {
976
+ parse: false,
977
+ path: addQueryArgs( '/newspack-blocks/v1/authors', {
978
+ search,
979
+ offset,
980
+ fields: 'id,name',
981
+ } ),
982
+ } );
983
+
984
+ const total = parseInt( response.headers.get( 'x-wp-total' ) || 0, 10 );
985
+ const authors = await response.json();
986
+
987
+ // Set max items for "load more" functionality in suggestions list.
988
+ if ( ! maxItemsToSuggest && ! search ) {
989
+ setMaxItemsToSuggest( total );
990
+ }
991
+
992
+ const _suggestions = authors.map( _author => ( {
993
+ value: _author.id,
994
+ label: decodeEntities( _author.name ) || __( '(no name)', 'newspack-blocks' ),
995
+ isGuestAuthor: _author.is_guest,
996
+ } ) );
997
+
998
+ setSuggestions( _suggestions );
999
+
1000
+ return _suggestions;
1001
+ } }
1002
+ maxItemsToSuggest={ maxItemsToSuggest }
1003
+ onChange={ items => {
1004
+ let selectionIsGuest = false;
1005
+ const selection = items[ 0 ];
1006
+
1007
+ // We need to check whether the selected author is a guest author or not.
1008
+ if ( suggestions ) {
1009
+ suggestions.forEach( suggestion => {
1010
+ if ( parseInt( selection?.value, 10 ) === parseInt( suggestion?.value, 10 ) && suggestion?.isGuestAuthor ) {
1011
+ selectionIsGuest = true;
1012
+ }
1013
+ } );
1014
+ }
1015
+
1016
+ setAttributes( {
1017
+ authorId: parseInt( selection?.value || 0, 10 ),
1018
+ isGuestAuthor: selectionIsGuest,
1019
+ } );
1020
+ } }
1021
+ postTypeLabel={ __( 'author', 'newspack-blocks' ) }
1022
+ postTypeLabelPlural={ __( 'authors', 'newspack-blocks' ) }
1023
+ selectedItems={ [] }
1024
+ />
1025
+ ) }
1026
+ </Placeholder>
1027
+ </div>
1028
+ );
1029
+ };
1030
+
1031
+ export default AuthorProfile;