@automattic/newspack-blocks 4.32.0-alpha.2 → 4.32.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,9 +1,16 @@
1
- # @automattic/newspack-blocks [4.32.0-alpha.2](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.32.0-alpha.1...newspack-blocks@4.32.0-alpha.2) (2026-09-09)
1
+ # @automattic/newspack-blocks [4.32.0-alpha.3](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.32.0-alpha.2...newspack-blocks@4.32.0-alpha.3) (2026-09-10)
2
2
 
3
3
 
4
4
  ### Bug Fixes
5
5
 
6
- * **homepage-articles:** reset dedup state per render pass (NPLAUNC-242) ([#1019](https://github.com/Automattic/newspack-workspace/issues/1019)) ([0ecdc9b](https://github.com/Automattic/newspack-workspace/commit/0ecdc9b7e9511799df668738a732ef6f0d808cb4))
6
+ * **iframe:** keep Back working on iframe block pages (NPPM-3180) ([#1042](https://github.com/Automattic/newspack-workspace/issues/1042)) ([6a87cb2](https://github.com/Automattic/newspack-workspace/commit/6a87cb2c6dcab735a81b54e87fb11b93769baac1))
7
+
8
+ ## @automattic/newspack-blocks [4.31.2](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.31.1...newspack-blocks@4.31.2) (2026-09-10)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **iframe:** keep Back working on iframe block pages (NPPM-3180) ([#1042](https://github.com/Automattic/newspack-workspace/issues/1042)) ([6a87cb2](https://github.com/Automattic/newspack-workspace/commit/6a87cb2c6dcab735a81b54e87fb11b93769baac1))
7
14
 
8
15
  ## @automattic/newspack-blocks [4.31.1](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.31.0...newspack-blocks@4.31.1) (2026-09-09)
9
16
 
@@ -1 +1 @@
1
- <?php return array('dependencies' => array('wp-dom-ready'), 'version' => 'b237b52924e68e8bf7a5');
1
+ <?php return array('dependencies' => array('wp-dom-ready'), 'version' => '0adcb9c939693718d723');
@@ -1 +1 @@
1
- (()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.domReady;e.n(t)()(()=>{Array.from(document.querySelectorAll(".wp-block-newspack-blocks-iframe iframe")).forEach(e=>{const t=setInterval(function(){e.src=e.src},2e3);e.onload=function(){clearInterval(t)},window.addEventListener("message",function(t){if(t.origin!==new URL(e.src).origin||e.contentWindow!==t.source)return;let n=0;t.data&&t.data.height&&("number"==typeof t.data.height?n=t.data.height:"string"==typeof t.data.height&&(n=Number(t.data.height))),!isNaN(n)&&n>0&&(e.parentElement&&"auto"!==e.parentElement.style.height&&(e.parentElement.style.height="auto"),e.style.height=n+"px")})})})})();
1
+ (()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.domReady;e.n(t)()(()=>{Array.from(document.querySelectorAll(".wp-block-newspack-blocks-iframe iframe")).forEach(e=>{let t=0;const n=setInterval(()=>{!(e=>{const t=e.contentDocument;return null!==t&&"about:blank"===t.URL})(e)||t>=10?clearInterval(n):(t++,e.contentWindow.location.replace(e.src))},2e3);window.addEventListener("message",function(t){if(t.origin!==new URL(e.src).origin||e.contentWindow!==t.source)return;let n=0;t.data&&t.data.height&&("number"==typeof t.data.height?n=t.data.height:"string"==typeof t.data.height&&(n=Number(t.data.height))),!isNaN(n)&&n>0&&(e.parentElement&&"auto"!==e.parentElement.style.height&&(e.parentElement.style.height="auto"),e.style.height=n+"px")})})})})();
@@ -2,7 +2,7 @@ msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Newspack Blocks\n"
4
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
5
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
5
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
6
6
  "PO-Revision-Date: 2024-08-30 08:45-0700\n"
7
7
  "Last-Translator: \n"
8
8
  "Language-Team: \n"
@@ -2,7 +2,7 @@ msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Newspack Blocks 1.0.0-alpha.20\n"
4
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
5
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
5
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
6
6
  "PO-Revision-Date: 2025-08-12T14:56:45+00:00\n"
7
7
  "Last-Translator: \n"
8
8
  "Language-Team: \n"
@@ -2,7 +2,7 @@ msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Newspack Blocks 1.0.0-alpha.25\n"
4
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
5
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
5
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
6
6
  "PO-Revision-Date: 2024-08-30 08:46-0700\n"
7
7
  "Last-Translator: \n"
8
8
  "Language-Team: \n"
@@ -2,7 +2,7 @@ msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Newspack Blocks 1.0.0-alpha.20\n"
4
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
5
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
5
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
6
6
  "PO-Revision-Date: 2024-08-30 08:46-0700\n"
7
7
  "Last-Translator: \n"
8
8
  "Language-Team: \n"
@@ -2,7 +2,7 @@ msgid ""
2
2
  msgstr ""
3
3
  "Project-Id-Version: Newspack Blocks 1.0.0-alpha.25\n"
4
4
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
5
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
5
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
6
6
  "PO-Revision-Date: 2024-08-30 08:46-0700\n"
7
7
  "Last-Translator: \n"
8
8
  "Language-Team: \n"
@@ -2,14 +2,14 @@
2
2
  # This file is distributed under the same license as the Newspack Blocks plugin.
3
3
  msgid ""
4
4
  msgstr ""
5
- "Project-Id-Version: Newspack Blocks 4.31.1\n"
5
+ "Project-Id-Version: Newspack Blocks 4.31.2\n"
6
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/newspack-blocks\n"
7
7
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
8
8
  "Language-Team: LANGUAGE <LL@li.org>\n"
9
9
  "MIME-Version: 1.0\n"
10
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2026-09-09T14:06:40+00:00\n"
12
+ "POT-Creation-Date: 2026-09-10T19:25:39+00:00\n"
13
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
14
  "X-Generator: WP-CLI 2.12.0\n"
15
15
  "X-Domain: newspack-blocks\n"
@@ -7,7 +7,7 @@
7
7
  * Author URI: https://newspack.com/
8
8
  * Text Domain: newspack-blocks
9
9
  * Domain Path: /languages
10
- * Version: 4.32.0-alpha.2
10
+ * Version: 4.32.0-alpha.3
11
11
  *
12
12
  * @package Newspack_Blocks
13
13
  */
@@ -15,7 +15,7 @@
15
15
  define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
16
16
  define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
17
17
  define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
18
- define( 'NEWSPACK_BLOCKS__VERSION', '4.32.0-alpha.2' );
18
+ define( 'NEWSPACK_BLOCKS__VERSION', '4.32.0-alpha.3' );
19
19
 
20
20
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
21
21
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/newspack-blocks",
3
- "version": "4.32.0-alpha.2",
3
+ "version": "4.32.0-alpha.3",
4
4
  "author": "Automattic",
5
5
  "description": "=== Newspack Blocks === Contributors: (this should be a list of wordpress.org userid's) Donate link: https://example.com/ Tags: comments, spam Requires at least: 4.5 Tested up to: 5.1.1 Stable tag: 0.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html",
6
6
  "repository": {
@@ -9,17 +9,47 @@ import domReady from '@wordpress/dom-ready';
9
9
 
10
10
  import './view.scss';
11
11
 
12
+ /**
13
+ * Whether the frame still shows its initial about:blank, so it has loaded nothing.
14
+ * Google Docs Viewer intermittently answers HTTP 204, which leaves the frame blank
15
+ * with no load event. That is the case the retry exists for.
16
+ *
17
+ * contentDocument is null for a loaded cross-origin document, a detached frame, and
18
+ * a sandboxed frame without allow-same-origin (from the first tick, so such a frame
19
+ * would never retry; this block renders no sandbox attribute).
20
+ *
21
+ * @param {HTMLIFrameElement} iframe The iframe.
22
+ * @return {boolean} Whether the frame is still on its initial about:blank.
23
+ */
24
+ const isStillBlank = iframe => {
25
+ const doc = iframe.contentDocument;
26
+ return doc !== null && doc.URL === 'about:blank';
27
+ };
28
+
29
+ /**
30
+ * Re-navigations before giving up on a frame that never loads. A 204 resolves in a
31
+ * retry or two; without a bound, a permanently blank embed keeps requesting for as
32
+ * long as the page is open.
33
+ */
34
+ const MAX_RETRIES = 10;
35
+
12
36
  domReady( () => {
13
37
  const iframes = Array.from( document.querySelectorAll( '.wp-block-newspack-blocks-iframe iframe' ) );
14
38
  iframes.forEach( iframe => {
15
- const timerId = setInterval( function () {
16
- iframe.src = iframe.src;
39
+ // Don't wait for the load event: it may have fired before this script ran
40
+ // (delayed JS). Navigate with location.replace(), since resetting src on a
41
+ // loaded frame adds a history entry and makes readers press Back twice
42
+ // (NPPM-3180).
43
+ let attempts = 0;
44
+ const retry = setInterval( () => {
45
+ if ( ! isStillBlank( iframe ) || attempts >= MAX_RETRIES ) {
46
+ clearInterval( retry );
47
+ return;
48
+ }
49
+ attempts++;
50
+ iframe.contentWindow.location.replace( iframe.src );
17
51
  }, 2000 );
18
52
 
19
- iframe.onload = function () {
20
- clearInterval( timerId );
21
- };
22
-
23
53
  // Add a listener for dynamic resizing if the iframe supports it.
24
54
  window.addEventListener( 'message', function ( event ) {
25
55
  // Reject messages from untrusted origins.
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The iframe block's retry (NPPM-3180) must leave a frame that already holds a
3
+ * document alone, and must never reset `src`, which adds a history entry.
4
+ */
5
+
6
+ const SRC = 'https://embed.example.test/widget';
7
+
8
+ /**
9
+ * Render one iframe block and stub the frame state jsdom cannot provide.
10
+ *
11
+ * @param {Object|null} contentDocument What the attached frame reports: the initial
12
+ * about:blank document while a navigation is in
13
+ * flight or was abandoned (cross-origin included),
14
+ * null once a cross-origin document has loaded.
15
+ * A detached frame reports null, as does its
16
+ * contentWindow.
17
+ * @return {Object} The iframe, its state holder, and the `replace` and `setSrc` spies.
18
+ */
19
+ function renderIframe( contentDocument ) {
20
+ document.body.innerHTML = `<figure class="wp-block-newspack-blocks-iframe"><div class="wp-block-embed__wrapper"><iframe src="${ SRC }"></iframe></div></figure>`;
21
+ const iframe = document.querySelector( 'iframe' );
22
+ const state = { contentDocument };
23
+ const replace = jest.fn();
24
+ const setSrc = jest.fn();
25
+ const contentWindow = { location: { replace } };
26
+ Object.defineProperty( iframe, 'contentDocument', { configurable: true, get: () => ( iframe.isConnected ? state.contentDocument : null ) } );
27
+ Object.defineProperty( iframe, 'contentWindow', { configurable: true, get: () => ( iframe.isConnected ? contentWindow : null ) } );
28
+ Object.defineProperty( iframe, 'src', { configurable: true, get: () => SRC, set: setSrc } );
29
+ jest.isolateModules( () => require( './view' ) );
30
+ return { iframe, state, replace, setSrc };
31
+ }
32
+
33
+ describe( 'iframe block view script', () => {
34
+ beforeEach( () => {
35
+ jest.useFakeTimers();
36
+ } );
37
+
38
+ afterEach( () => {
39
+ jest.clearAllTimers();
40
+ jest.useRealTimers();
41
+ document.body.innerHTML = '';
42
+ } );
43
+
44
+ it.each( [
45
+ // The delayed-script case: the frame loaded before this script ran.
46
+ [ 'cross-origin', null ],
47
+ [ 'same-origin', { URL: 'https://example.test/embed' } ],
48
+ ] )( 'leaves a frame that already holds a %s document alone', ( _, contentDocument ) => {
49
+ const { replace, setSrc } = renderIframe( contentDocument );
50
+ jest.advanceTimersByTime( 10000 );
51
+ expect( replace ).not.toHaveBeenCalled();
52
+ expect( setSrc ).not.toHaveBeenCalled();
53
+ expect( jest.getTimerCount() ).toBe( 0 );
54
+ } );
55
+
56
+ it( 'retries with location.replace while the frame is still blank, then stops', () => {
57
+ const { state, replace, setSrc } = renderIframe( { URL: 'about:blank' } );
58
+
59
+ jest.advanceTimersByTime( 2000 );
60
+ expect( replace ).toHaveBeenCalledTimes( 1 );
61
+ expect( replace ).toHaveBeenCalledWith( SRC );
62
+
63
+ jest.advanceTimersByTime( 2000 );
64
+ expect( replace ).toHaveBeenCalledTimes( 2 );
65
+
66
+ // The retry succeeded and a cross-origin document loaded.
67
+ state.contentDocument = null;
68
+ jest.advanceTimersByTime( 10000 );
69
+ expect( replace ).toHaveBeenCalledTimes( 2 );
70
+ expect( jest.getTimerCount() ).toBe( 0 );
71
+
72
+ // Resetting src is what adds the history entry.
73
+ expect( setSrc ).not.toHaveBeenCalled();
74
+ } );
75
+
76
+ it( 'gives up after 10 attempts on a frame that never loads', () => {
77
+ const { replace } = renderIframe( { URL: 'about:blank' } );
78
+ jest.advanceTimersByTime( 20000 );
79
+ expect( replace ).toHaveBeenCalledTimes( 10 );
80
+
81
+ jest.advanceTimersByTime( 20000 );
82
+ expect( replace ).toHaveBeenCalledTimes( 10 );
83
+ expect( jest.getTimerCount() ).toBe( 0 );
84
+ } );
85
+
86
+ it( 'checks the frame before touching contentWindow, so a removed frame does not throw', () => {
87
+ const { iframe, replace } = renderIframe( { URL: 'about:blank' } );
88
+ jest.advanceTimersByTime( 2000 );
89
+ expect( replace ).toHaveBeenCalledTimes( 1 );
90
+
91
+ // A detached frame has no contentWindow; dereferencing it would throw inside the tick.
92
+ iframe.remove();
93
+ expect( () => jest.advanceTimersByTime( 10000 ) ).not.toThrow();
94
+ expect( replace ).toHaveBeenCalledTimes( 1 );
95
+ expect( jest.getTimerCount() ).toBe( 0 );
96
+ } );
97
+ } );
@@ -3,7 +3,7 @@
3
3
  'name' => 'automattic/newspack-blocks',
4
4
  'pretty_version' => 'dev-main',
5
5
  'version' => 'dev-main',
6
- 'reference' => '1ab44fc4ccb393daa1e37f35ab80a9e9c3c7e2dc',
6
+ 'reference' => 'bfbd263f07c45fa202296d88920a2cdd5575a4e7',
7
7
  'type' => 'wordpress-plugin',
8
8
  'install_path' => __DIR__ . '/../../',
9
9
  'aliases' => array(),
@@ -13,7 +13,7 @@
13
13
  'automattic/newspack-blocks' => array(
14
14
  'pretty_version' => 'dev-main',
15
15
  'version' => 'dev-main',
16
- 'reference' => '1ab44fc4ccb393daa1e37f35ab80a9e9c3c7e2dc',
16
+ 'reference' => 'bfbd263f07c45fa202296d88920a2cdd5575a4e7',
17
17
  'type' => 'wordpress-plugin',
18
18
  'install_path' => __DIR__ . '/../../',
19
19
  'aliases' => array(),