@automattic/newspack-blocks 1.67.0 → 1.68.0

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 (103) hide show
  1. package/.cache/babel/078314f1ffd302d32bbe1124c797c4a8.json.gz +0 -0
  2. package/.cache/babel/08bd669298cd26a7d3a62aadcf637516.json.gz +0 -0
  3. package/.cache/babel/0988afa42fd3fe14da7ae43c9d02661e.json.gz +0 -0
  4. package/.cache/babel/0d164bb53cdb3442a8c8ab37dde2e4ce.json.gz +0 -0
  5. package/.cache/babel/0f96392a3b96da0b4dce7a77edef76ca.json.gz +0 -0
  6. package/.cache/babel/2dc630cecd79488c7912540ac3a1ae93.json.gz +0 -0
  7. package/.cache/babel/3807c3306deecdbdb91968cb3c978235.json.gz +0 -0
  8. package/.cache/babel/45308b31d062a1fb08079849840aaa43.json.gz +0 -0
  9. package/.cache/babel/48df6fe3b45d872e1ded6f33a70e3176.json.gz +0 -0
  10. package/.cache/babel/58350a62e3ef63157722789bf187a8d1.json.gz +0 -0
  11. package/.cache/babel/5ac50f37a9913d9f63c8751f5c415ba4.json.gz +0 -0
  12. package/.cache/babel/6170ac021bca94b65aaf9d91313c47a9.json.gz +0 -0
  13. package/.cache/babel/66c747a8bdec1ed403f703e47256fa03.json.gz +0 -0
  14. package/.cache/babel/695780d53e2d31de09fc42456ad05cff.json.gz +0 -0
  15. package/.cache/babel/6bc92299b6332d48bcc944e155ce08cd.json.gz +0 -0
  16. package/.cache/babel/900ca42963bd0a74c1498a6d1212d82f.json.gz +0 -0
  17. package/.cache/babel/91e706536d45a88f098e9394344dbeb9.json.gz +0 -0
  18. package/.cache/babel/ab39cbb804689d063293f37fa4485487.json.gz +0 -0
  19. package/.cache/babel/c0e75e9017dcf69507da774f93b23422.json.gz +0 -0
  20. package/.cache/babel/c917c2bc027ccb946305c9305b05755e.json.gz +0 -0
  21. package/.cache/babel/cf24b1c63d0cf0e037eb598706a79f88.json.gz +0 -0
  22. package/.cache/babel/e452902bef688c901938b578c6834c50.json.gz +0 -0
  23. package/.cache/babel/e499e66d1cc40fb9b6c4238bf3dd2e6a.json.gz +0 -0
  24. package/.cache/babel/f7fd26614549b5cbb31416d632c38ccd.json.gz +0 -0
  25. package/.cache/babel/fa8281f6c9d0ec08fd8106dcfff2b6ba.json.gz +0 -0
  26. package/CHANGELOG.md +42 -0
  27. package/block-list.json +10 -1
  28. package/composer.lock +7 -7
  29. package/dist/carousel/view.asset.php +1 -1
  30. package/dist/carousel/view.js +1 -1
  31. package/dist/{donateCheckoutBlock.asset.php → checkout-button/view.asset.php} +1 -1
  32. package/dist/checkout-button/view.css +1 -0
  33. package/dist/checkout-button/view.rtl.css +1 -0
  34. package/dist/donate/view.asset.php +1 -1
  35. package/dist/donate/view.css +1 -1
  36. package/dist/donate/view.rtl.css +1 -1
  37. package/dist/editor.asset.php +1 -1
  38. package/dist/editor.css +1 -1
  39. package/dist/editor.js +3 -3
  40. package/dist/editor.rtl.css +1 -1
  41. package/dist/{donateCheckoutModal.asset.php → modal.asset.php} +1 -1
  42. package/dist/modal.css +1 -0
  43. package/dist/modal.js +1 -0
  44. package/dist/modal.rtl.css +1 -0
  45. package/dist/modalCheckout.asset.php +1 -0
  46. package/dist/modalCheckout.js +1 -0
  47. package/includes/class-modal-checkout.php +383 -0
  48. package/includes/class-newspack-blocks.php +30 -6
  49. package/newspack-blocks.php +3 -2
  50. package/package.json +3 -3
  51. package/src/blocks/carousel/edit.js +21 -0
  52. package/src/blocks/carousel/index.js +3 -0
  53. package/src/blocks/carousel/view.php +7 -0
  54. package/src/blocks/checkout-button/block.json +79 -0
  55. package/src/blocks/checkout-button/edit.js +247 -0
  56. package/src/blocks/checkout-button/edit.scss +40 -0
  57. package/src/blocks/checkout-button/editor.js +23 -0
  58. package/src/blocks/checkout-button/index.js +27 -0
  59. package/src/blocks/checkout-button/save.js +64 -0
  60. package/src/blocks/{donate/checkout-modal/index.js → checkout-button/view.js} +1 -1
  61. package/src/blocks/checkout-button/view.php +35 -0
  62. package/src/blocks/checkout-button/view.scss +18 -0
  63. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer.php +1 -233
  64. package/src/blocks/donate/styles/view.scss +0 -95
  65. package/src/blocks/homepage-articles/block.json +5 -0
  66. package/src/blocks/homepage-articles/edit.js +18 -0
  67. package/src/blocks/homepage-articles/utils.ts +4 -0
  68. package/src/components/query-controls.js +60 -0
  69. package/src/{blocks/donate/checkout-modal/view.scss → modal-checkout/checkout.scss} +1 -1
  70. package/src/modal-checkout/index.js +4 -0
  71. package/src/{blocks/donate/checkout-modal/block.js → modal-checkout/modal.js} +14 -11
  72. package/src/modal-checkout/modal.scss +97 -0
  73. package/src/{blocks/donate → modal-checkout}/templates/checkout-form.php +3 -3
  74. package/src/types/index.d.ts +1 -0
  75. package/vendor/autoload.php +1 -1
  76. package/vendor/composer/autoload_real.php +4 -4
  77. package/vendor/composer/autoload_static.php +2 -2
  78. package/vendor/composer/installed.php +2 -2
  79. package/webpack.config.js +2 -2
  80. package/.cache/babel/1d8b42985da54f10a9bfd0a9f87b5844.json.gz +0 -0
  81. package/.cache/babel/37bd7f90c2e7ea1e10bf840775d1b262.json.gz +0 -0
  82. package/.cache/babel/3a66da0fe7ab175effa6a338812e46cb.json.gz +0 -0
  83. package/.cache/babel/4ba56fc2684f5bebdd2c8c488ea03683.json.gz +0 -0
  84. package/.cache/babel/60ac312fdf07fb7730b1a8a9c1b5bd5a.json.gz +0 -0
  85. package/.cache/babel/61d00fc8add441f0b915e3af4b518ead.json.gz +0 -0
  86. package/.cache/babel/646a7267e14986e70c74dc9c32ca6a14.json.gz +0 -0
  87. package/.cache/babel/7464c382b8a939e4e43f9349d76843a8.json.gz +0 -0
  88. package/.cache/babel/917cc52662d270e7c529afbf210a2703.json.gz +0 -0
  89. package/.cache/babel/a1dde270d38efa30dfbbfe2b97be9e51.json.gz +0 -0
  90. package/.cache/babel/a5447d9807699029636883e96c6aa4c6.json.gz +0 -0
  91. package/.cache/babel/a7575c7f77cb736dbfe8a4d01910cc79.json.gz +0 -0
  92. package/.cache/babel/b13e3fd47c6307f8c1f8786edc053ed9.json.gz +0 -0
  93. package/.cache/babel/b38122e026094b152ef69677468e4415.json.gz +0 -0
  94. package/.cache/babel/bb3ca1de54603d2730484164ed55902b.json.gz +0 -0
  95. package/.cache/babel/c762aee66625f48b1de4e3b329d8c9fe.json.gz +0 -0
  96. package/.cache/babel/c9d601b83fd7c6412dd9ac187c06d7c1.json.gz +0 -0
  97. package/.cache/babel/fa5e94ee19268ccad7790a312d6fca4e.json.gz +0 -0
  98. package/.cache/babel/fe8f3849250ae54c53096ec8db55a8d6.json.gz +0 -0
  99. package/.cache/babel/fe99fe0bebf3e9d74bb240487620bdd4.json.gz +0 -0
  100. package/dist/donateCheckoutBlock.js +0 -1
  101. /package/dist/{donateCheckoutModal.js → checkout-button/view.js} +0 -0
  102. /package/dist/{donateCheckoutModal.css → modalCheckout.css} +0 -0
  103. /package/dist/{donateCheckoutModal.rtl.css → modalCheckout.rtl.css} +0 -0
@@ -14,25 +14,11 @@ require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/blocks/donate/frontend/class-new
14
14
  * Server-side rendering of the `newspack-blocks/donate` block.
15
15
  */
16
16
  class Newspack_Blocks_Donate_Renderer {
17
- /**
18
- * Whether the modal checkout is used by donate any block.
19
- *
20
- * @var boolean
21
- */
22
- private static $has_modal_checkout = false;
23
-
24
17
  /**
25
18
  * Constructor.
26
19
  */
27
20
  public function __construct() {
28
21
  add_filter( 'woocommerce_checkout_fields', [ __CLASS__, 'woocommerce_checkout_fields' ] );
29
- add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_modal_checkout_scripts' ] );
30
- add_action( 'wp_footer', [ __CLASS__, 'render_modal_checkout_markup' ] );
31
- add_action( 'template_include', [ __CLASS__, 'get_modal_checkout_template' ] );
32
- add_filter( 'wc_get_template', [ __CLASS__, 'wc_get_template' ], 10, 2 );
33
- add_filter( 'show_admin_bar', [ __CLASS__, 'show_admin_bar' ] );
34
- add_filter( 'woocommerce_checkout_get_value', [ __CLASS__, 'woocommerce_checkout_get_value' ], 10, 2 );
35
- add_filter( 'woocommerce_get_return_url', [ __CLASS__, 'woocommerce_get_return_url' ], 10, 2 );
36
22
  }
37
23
 
38
24
  /**
@@ -82,19 +68,6 @@ class Newspack_Blocks_Donate_Renderer {
82
68
  return $fields;
83
69
  }
84
70
 
85
- /**
86
- * Enqueue scripts for the checkout page rendered in a modal.
87
- */
88
- public static function enqueue_modal_checkout_scripts() {
89
- if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
90
- return;
91
- }
92
- if ( ! isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
93
- return;
94
- }
95
- self::enqueue_scripts( 'modal-checkout', [] );
96
- }
97
-
98
71
  /**
99
72
  * Enqueue frontend scripts and styles.
100
73
  *
@@ -119,13 +92,6 @@ class Newspack_Blocks_Donate_Renderer {
119
92
  case 'tiers-based':
120
93
  $filename = 'tiersBased';
121
94
  break;
122
- case 'modal-checkout':
123
- $filename = 'donateCheckoutModal';
124
- break;
125
- case 'modal-checkout-block':
126
- $filename = 'donateCheckoutBlock';
127
- $has_css = false;
128
- break;
129
95
  default:
130
96
  $filename = false;
131
97
  break;
@@ -183,8 +149,7 @@ class Newspack_Blocks_Donate_Renderer {
183
149
  wp_script_add_data( 'newspack-blocks-donate', 'amp-plus', true );
184
150
 
185
151
  if ( true === $attributes['useModalCheckout'] && ! $configuration['is_rendering_stripe_payment_form'] ) {
186
- self::enqueue_scripts( 'modal-checkout-block' );
187
- self::$has_modal_checkout = true;
152
+ \Newspack_Blocks\Modal_Checkout::enqueue_modal();
188
153
  }
189
154
 
190
155
  if ( $configuration['is_tier_based_layout'] ) {
@@ -195,202 +160,5 @@ class Newspack_Blocks_Donate_Renderer {
195
160
  return Newspack_Blocks_Donate_Renderer_Frequency_Based::render( $attributes );
196
161
  }
197
162
  }
198
-
199
- /**
200
- * Render the markup necessary for the modal checkout.
201
- */
202
- public static function render_modal_checkout_markup() {
203
- if ( ! self::$has_modal_checkout ) {
204
- return;
205
- }
206
- ?>
207
- <div class="newspack-blocks-donate-checkout-modal" style="display: none;">
208
- <div class="newspack-blocks-donate-checkout-modal__content">
209
- <a href="#" class="newspack-blocks-donate-checkout-modal__close">
210
- <span class="screen-reader-text"><?php esc_html_e( 'Close', 'newspack-blocks' ); ?></span>
211
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">
212
- <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
213
- </svg>
214
- </a>
215
- <div class="newspack-blocks-donate-checkout-modal__spinner">
216
- <span></span>
217
- </div>
218
- </div>
219
- </div>
220
- <?php
221
- }
222
-
223
- /**
224
- * Return URL for modal checkout "thank you" page.
225
- *
226
- * @param string $url The URL to redirect to.
227
- *
228
- * @return string
229
- */
230
- public static function woocommerce_get_return_url( $url ) {
231
- if ( ! isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
232
- return $url;
233
- }
234
- return add_query_arg(
235
- [
236
- 'modal_checkout' => '1',
237
- 'email' => isset( $_REQUEST['billing_email'] ) ? rawurlencode( sanitize_email( wp_unslash( $_REQUEST['billing_email'] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
238
- ],
239
- $url
240
- );
241
- }
242
-
243
- /**
244
- * Disable admin bar for modal checkout.
245
- *
246
- * @param bool $show Whether to show the admin bar.
247
- *
248
- * @return bool
249
- */
250
- public static function show_admin_bar( $show ) {
251
- if ( ! isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
252
- return $show;
253
- }
254
- return false;
255
- }
256
-
257
- /**
258
- * Use stripped down template for modal checkout.
259
- *
260
- * @param string $template The template to render.
261
- *
262
- * @return string
263
- */
264
- public static function get_modal_checkout_template( $template ) {
265
- if ( ! function_exists( 'is_checkout' ) || ! function_exists( 'is_order_received_page' ) ) {
266
- return $template;
267
- }
268
- if ( ! is_checkout() && ! is_order_received_page() ) {
269
- return $template;
270
- }
271
- if ( ! isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
272
- return $template;
273
- }
274
- ob_start();
275
- wp_head();
276
- while ( have_posts() ) {
277
- the_post();
278
- echo '<div id="newspack_modal_checkout">';
279
- the_content();
280
- echo '</div>';
281
- }
282
- wp_footer();
283
- ob_end_flush();
284
- }
285
-
286
- /**
287
- * Check the nonce for the edit billing request.
288
- *
289
- * @return bool
290
- */
291
- private static function validate_edit_billing_request() {
292
- if ( ! isset( $_REQUEST['newspack_donate_edit_billing_nonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
293
- return false;
294
- }
295
- if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['newspack_donate_edit_billing_nonce'] ), 'newspack_donate_edit_billing' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
296
- return false;
297
- }
298
- return true;
299
- }
300
-
301
- /**
302
- * Get the prefilled values for billing fields.
303
- *
304
- * @return array
305
- */
306
- public static function get_prefilled_fields() {
307
- $checkout = WC()->checkout();
308
- $fields = $checkout->get_checkout_fields( 'billing' );
309
- $customer = new WC_Customer( get_current_user_id() );
310
- $customer_fields = $customer->get_billing();
311
- // If the user is logged in and there's no billing email, use the user's email.
312
- if ( is_user_logged_in() && empty( $customer_fields['email'] ) ) {
313
- $customer_fields['email'] = $customer->get_email();
314
- }
315
- $valid_request = self::validate_edit_billing_request();
316
- $prefilled_fields = [];
317
- foreach ( $fields as $key => $field ) {
318
- $key = str_replace( 'billing_', '', $key );
319
- if ( $valid_request && isset( $_REQUEST[ 'billing_' . $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
320
- $value = sanitize_text_field( wp_unslash( $_REQUEST[ 'billing_' . $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
321
- } elseif ( isset( $customer_fields[ $key ] ) ) {
322
- $value = $customer_fields[ $key ];
323
- }
324
- $prefilled_fields[ $key ] = $value;
325
- }
326
- return $prefilled_fields;
327
- }
328
-
329
- /**
330
- * Whether the current checkout session has all required billing fields filled.
331
- *
332
- * @return bool
333
- */
334
- public static function has_filled_required_fields() {
335
- $checkout = WC()->checkout();
336
- $fields = $checkout->get_checkout_fields( 'billing' );
337
- $required = array_filter(
338
- $fields,
339
- function( $field ) {
340
- return isset( $field['required'] ) && $field['required'];
341
- }
342
- );
343
- $required_keys = array_keys( $required );
344
- $customer_fields = self::get_prefilled_fields();
345
- $is_request = self::validate_edit_billing_request();
346
- foreach ( $required_keys as $key ) {
347
- $key = str_replace( 'billing_', '', $key );
348
- if ( empty( $customer_fields[ $key ] ) ) {
349
- if ( $is_request ) {
350
- /* translators: %s: field name */
351
- wc_add_notice( sprintf( __( '%s is a required field.', 'newspack-blocks' ), $fields[ 'billing_' . $key ]['label'] ), 'error' );
352
- }
353
- return false;
354
- }
355
- }
356
- return true;
357
- }
358
-
359
- /**
360
- * Modify WC checkout field value.
361
- *
362
- * @param null $value Value.
363
- * @param string $input Input name.
364
- *
365
- * @return string|null Value or null if unaltered.
366
- */
367
- public static function woocommerce_checkout_get_value( $value, $input ) {
368
- if ( ! isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
369
- return $value;
370
- }
371
- $valid_request = self::validate_edit_billing_request(); // This performs nonce verification.
372
- if ( ! $valid_request ) {
373
- return $value;
374
- }
375
- if ( isset( $_REQUEST[ $input ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
376
- $value = sanitize_text_field( wp_unslash( $_REQUEST[ $input ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
377
- }
378
- return $value;
379
- }
380
-
381
- /**
382
- * Use modal checkout template when rendering the checkout form.
383
- *
384
- * @param string $located Template file.
385
- * @param string $template_name Template name.
386
- *
387
- * @return string Template file.
388
- */
389
- public static function wc_get_template( $located, $template_name ) {
390
- if ( 'checkout/form-checkout.php' === $template_name && isset( $_REQUEST['modal_checkout'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
391
- $located = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/blocks/donate/templates/checkout-form.php';
392
- }
393
- return $located;
394
- }
395
163
  }
396
164
  new Newspack_Blocks_Donate_Renderer();
@@ -3,18 +3,6 @@
3
3
 
4
4
  @use './style-variations';
5
5
 
6
- @keyframes spin {
7
- 0% {
8
- transform: rotate( 0deg );
9
- }
10
- 50% {
11
- transform: rotate( 180deg );
12
- }
13
- 100% {
14
- transform: rotate( 360deg );
15
- }
16
- }
17
-
18
6
  .wpbnbd {
19
7
  &__button {
20
8
  border: 0 solid variables.$color__border;
@@ -34,86 +22,3 @@
34
22
  background-color: transparent;
35
23
  }
36
24
  }
37
-
38
- .newspack-blocks-donate-checkout-modal {
39
- position: fixed;
40
- top: 0;
41
- left: 0;
42
- width: 100%;
43
- height: 100%;
44
- background: rgba( 0, 0, 0, 0.75 );
45
- z-index: 99999;
46
- &__content {
47
- position: absolute;
48
- top: 50%;
49
- left: 50%;
50
- transform: translate( -50%, -50% );
51
- width: calc( 100vw - 32px );
52
- max-width: 580px;
53
- min-height: 200px;
54
- max-height: calc( 100vh - 32px );
55
- background: colors.$color__background-body;
56
- border-radius: 5px;
57
- > *:not( .newspack-blocks-donate-checkout-modal__close ) {
58
- width: 100%;
59
- height: 100%;
60
- border: 0;
61
- border-radius: 5px;
62
- }
63
- }
64
- &__spinner {
65
- position: absolute;
66
- top: 50%;
67
- left: 50%;
68
- transform: translate( -50%, -50% );
69
- width: 100%;
70
- height: 100%;
71
- display: flex;
72
- align-items: center;
73
- justify-content: center;
74
- background: #fff;
75
- border-radius: 5px;
76
- > span {
77
- width: 25px;
78
- height: 25px;
79
- border: 2px solid colors.$color__background-body;
80
- border-top-color: colors.$color__text-light;
81
- border-radius: 50%;
82
- animation: spin 1s infinite linear;
83
- }
84
- }
85
- &__close {
86
- position: absolute;
87
- top: 0;
88
- right: 0;
89
- padding: 8px;
90
- border: 0;
91
- background: transparent;
92
- color: colors.$color__text-main;
93
- cursor: pointer;
94
- &:focus,
95
- &:hover {
96
- color: colors.$color__text-light;
97
- }
98
- svg {
99
- display: block;
100
- }
101
- }
102
- }
103
-
104
- @media ( max-width: 600px ) {
105
- .newspack-blocks-donate-checkout-modal {
106
- &__content {
107
- max-width: 100%;
108
- width: 100%;
109
- border-radius: 0;
110
- top: auto;
111
- bottom: 0;
112
- left: 0;
113
- transform: none;
114
- > *:not( .newspack-blocks-donate-checkout-modal__close ) {
115
- border-radius: 0;
116
- }
117
- }
118
- }
119
- }
@@ -105,6 +105,11 @@
105
105
  "default": [],
106
106
  "items": { "type": "integer" }
107
107
  },
108
+ "brands": {
109
+ "type": "array",
110
+ "default": [],
111
+ "items": { "type": "integer" }
112
+ },
108
113
  "tagExclusions": {
109
114
  "type": "array",
110
115
  "default": [],
@@ -72,6 +72,15 @@ if (
72
72
  IS_SUBTITLE_SUPPORTED_IN_THEME = true;
73
73
  }
74
74
 
75
+ let IS_MULTIBRANDED_SITE;
76
+ if (
77
+ typeof window === 'object' &&
78
+ window.newspack_blocks_data &&
79
+ window.newspack_blocks_data.multibranded_sites_enabled
80
+ ) {
81
+ IS_MULTIBRANDED_SITE = true;
82
+ }
83
+
75
84
  const landscapeIcon = (
76
85
  <SVG xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
77
86
  <Path
@@ -266,6 +275,7 @@ class Edit extends Component {
266
275
  specificPosts,
267
276
  postsToShow,
268
277
  categories,
278
+ brands,
269
279
  columns,
270
280
  colGap,
271
281
  postType,
@@ -342,6 +352,13 @@ class Edit extends Component {
342
352
 
343
353
  const handleAttributeChange = key => value => setAttributes( { [ key ]: value } );
344
354
 
355
+ const brandProps = IS_MULTIBRANDED_SITE
356
+ ? {
357
+ brands,
358
+ onBrandsChange: handleAttributeChange( 'brands' ),
359
+ }
360
+ : '';
361
+
345
362
  return (
346
363
  <Fragment>
347
364
  <PanelBody title={ __( 'Display Settings', 'newspack-blocks' ) } initialOpen={ true }>
@@ -360,6 +377,7 @@ class Edit extends Component {
360
377
  onCategoriesChange={ handleAttributeChange( 'categories' ) }
361
378
  tags={ tags }
362
379
  onTagsChange={ handleAttributeChange( 'tags' ) }
380
+ { ...brandProps }
363
381
  tagExclusions={ tagExclusions }
364
382
  onTagExclusionsChange={ handleAttributeChange( 'tagExclusions' ) }
365
383
  categoryExclusions={ categoryExclusions }
@@ -29,6 +29,7 @@ const POST_QUERY_ATTRIBUTES = [
29
29
  'categories',
30
30
  'excerptLength',
31
31
  'tags',
32
+ 'brands',
32
33
  'showExcerpt',
33
34
  'specificPosts',
34
35
  'specificMode',
@@ -46,6 +47,7 @@ type HomepageArticlesAttributes = {
46
47
  postType: PostType[];
47
48
  showExcerpt: boolean;
48
49
  tags: TagId[];
50
+ brands: BrandId[];
49
51
  specificPosts: string[];
50
52
  specificMode: boolean;
51
53
  tagExclusions: TagId[];
@@ -89,6 +91,7 @@ export const queryCriteriaFromAttributes = ( attributes: Block[ 'attributes' ] )
89
91
  postType,
90
92
  showExcerpt,
91
93
  tags,
94
+ brands,
92
95
  specificPosts = [],
93
96
  specificMode,
94
97
  tagExclusions,
@@ -112,6 +115,7 @@ export const queryCriteriaFromAttributes = ( attributes: Block[ 'attributes' ] )
112
115
  tags,
113
116
  tagExclusions,
114
117
  categoryExclusions,
118
+ brands,
115
119
  postType,
116
120
  includedPostStatuses,
117
121
  },
@@ -16,6 +16,9 @@ import AutocompleteTokenField from './autocomplete-tokenfield';
16
16
  const getCategoryTitle = category =>
17
17
  decodeEntities( category.name ) || __( '(no title)', 'newspack-blocks' );
18
18
 
19
+ const getBrandTitle = brand =>
20
+ decodeEntities( brand.name ) || __( '(no title)', 'newspack-blocks' );
21
+
19
22
  class QueryControls extends Component {
20
23
  state = {
21
24
  showAdvancedFilters: false,
@@ -166,6 +169,51 @@ class QueryControls extends Component {
166
169
  } );
167
170
  };
168
171
 
172
+ fetchBrandSuggestions = search => {
173
+ return apiFetch( {
174
+ path: addQueryArgs( '/wp/v2/brand', {
175
+ search,
176
+ per_page: 20,
177
+ _fields: 'id,name,parent',
178
+ orderby: 'count',
179
+ order: 'desc',
180
+ } ),
181
+ } ).then( brands =>
182
+ Promise.all(
183
+ brands.map( brand => {
184
+ if ( brand.parent > 0 ) {
185
+ return apiFetch( {
186
+ path: addQueryArgs( `/wp/v2/brand/${ brand.parent }`, {
187
+ _fields: 'name',
188
+ } ),
189
+ } ).then( parentBrand => ( {
190
+ value: brand.id,
191
+ label: `${ getBrandTitle( brand ) } – ${ getBrandTitle( parentBrand ) }`,
192
+ } ) );
193
+ }
194
+ return Promise.resolve( {
195
+ value: brand.id,
196
+ label: getBrandTitle( brand ),
197
+ } );
198
+ } )
199
+ )
200
+ );
201
+ };
202
+ fetchSavedBrands = brandIDs => {
203
+ return apiFetch( {
204
+ path: addQueryArgs( '/wp/v2/brand', {
205
+ per_page: 100,
206
+ _fields: 'id,name',
207
+ include: brandIDs.join( ',' ),
208
+ } ),
209
+ } ).then( function ( brands ) {
210
+ return brands.map( brand => ( {
211
+ value: brand.id,
212
+ label: decodeEntities( brand.name ) || __( '(no title)', 'newspack-blocks' ),
213
+ } ) );
214
+ } );
215
+ };
216
+
169
217
  render = () => {
170
218
  const {
171
219
  specificMode,
@@ -178,6 +226,8 @@ class QueryControls extends Component {
178
226
  onCategoriesChange,
179
227
  tags,
180
228
  onTagsChange,
229
+ brands,
230
+ onBrandsChange,
181
231
  tagExclusions,
182
232
  onTagExclusionsChange,
183
233
  categoryExclusions,
@@ -237,6 +287,15 @@ class QueryControls extends Component {
237
287
  label={ __( 'Tags', 'newspack-blocks' ) }
238
288
  />
239
289
  ) }
290
+ { onBrandsChange && (
291
+ <AutocompleteTokenField
292
+ tokens={ brands || [] }
293
+ onChange={ onBrandsChange }
294
+ fetchSuggestions={ this.fetchBrandSuggestions }
295
+ fetchSavedInfo={ this.fetchSavedBrands }
296
+ label={ __( 'Brands', 'newspack-blocks' ) }
297
+ />
298
+ ) }
240
299
  { onTagExclusionsChange && (
241
300
  <p>
242
301
  <Button
@@ -284,6 +343,7 @@ QueryControls.defaultProps = {
284
343
  authors: [],
285
344
  categories: [],
286
345
  tags: [],
346
+ brands: [],
287
347
  tagExclusions: [],
288
348
  };
289
349
 
@@ -1,4 +1,4 @@
1
- @use '../../../shared/sass/colors';
1
+ @use '../shared/sass/colors';
2
2
 
3
3
  #newspack_modal_checkout { /* stylelint-disable-line */
4
4
  padding: 32px;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Style dependencies
3
+ */
4
+ import './checkout.scss';
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import './modal.scss';
5
+
1
6
  /**
2
7
  * Specify a function to execute when the DOM is fully loaded.
3
8
  *
@@ -20,6 +25,8 @@ function domReady( callback ) {
20
25
  document.addEventListener( 'DOMContentLoaded', callback );
21
26
  }
22
27
 
28
+ const triggers = '.wpbnbd.wpbnbd--platform-wc,.wp-block-newspack-blocks-checkout-button';
29
+
23
30
  let iframeResizeObserver;
24
31
 
25
32
  function closeCheckout( element ) {
@@ -33,25 +40,23 @@ function closeCheckout( element ) {
33
40
  }
34
41
 
35
42
  domReady( () => {
36
- const modalCheckout = document.querySelector( '.newspack-blocks-donate-checkout-modal' );
43
+ const modalCheckout = document.querySelector( '.newspack-blocks-checkout-modal' );
37
44
  if ( ! modalCheckout ) {
38
45
  return;
39
46
  }
40
- const spinner = document.querySelector( '.newspack-blocks-donate-checkout-modal__spinner' );
47
+ const spinner = document.querySelector( '.newspack-blocks-checkout-modal__spinner' );
41
48
  const iframeName = 'newspack_modal_checkout';
42
49
  const modalCheckoutInput = document.createElement( 'input' );
43
50
  modalCheckoutInput.type = 'hidden';
44
51
  modalCheckoutInput.name = 'modal_checkout';
45
52
  modalCheckoutInput.value = '1';
46
- const modalContent = modalCheckout.querySelector(
47
- '.newspack-blocks-donate-checkout-modal__content'
48
- );
53
+ const modalContent = modalCheckout.querySelector( '.newspack-blocks-checkout-modal__content' );
49
54
  const iframe = document.createElement( 'iframe' );
50
55
  iframe.name = iframeName;
51
56
  modalContent.appendChild( iframe );
52
- const blocks = document.querySelectorAll( '.wpbnbd.wpbnbd--platform-wc' );
53
- blocks.forEach( block => {
54
- const forms = block.querySelectorAll( 'form' );
57
+ const elements = document.querySelectorAll( triggers );
58
+ elements.forEach( element => {
59
+ const forms = element.querySelectorAll( 'form' );
55
60
  forms.forEach( form => {
56
61
  form.appendChild( modalCheckoutInput.cloneNode() );
57
62
  form.target = iframeName;
@@ -95,9 +100,7 @@ domReady( () => {
95
100
  closeCheckout( modalCheckout );
96
101
  }
97
102
  } );
98
- const closeButtons = modalCheckout.querySelectorAll(
99
- '.newspack-blocks-donate-checkout-modal__close'
100
- );
103
+ const closeButtons = modalCheckout.querySelectorAll( '.newspack-blocks-checkout-modal__close' );
101
104
  closeButtons.forEach( button => {
102
105
  button.addEventListener( 'click', ev => {
103
106
  ev.preventDefault();