diff --git a/src/Component/Post/BlockAttributes/BlockAttributes.php b/src/Component/Post/BlockAttributes/BlockAttributes.php
index 2c760cec..f41276b3 100644
--- a/src/Component/Post/BlockAttributes/BlockAttributes.php
+++ b/src/Component/Post/BlockAttributes/BlockAttributes.php
@@ -13,15 +13,12 @@
namespace Beyondwords\Wordpress\Component\Post\BlockAttributes;
-use Beyondwords\Wordpress\Component\Post\PostContentUtils;
-use Beyondwords\Wordpress\Component\Post\PostMetaUtils;
-use Beyondwords\Wordpress\Component\Settings\Fields\PlayerUI\PlayerUI;
-
/**
* BlockAttributes
*
* @since 3.7.0
- * @since 4.0.0 Renamed from BlockAudioAttribute to BlockAttributes to support multiple attributes
+ * @since 4.0.0 Renamed from BlockAudioAttribute to BlockAttributes to support multiple attributes.
+ * @since 6.0.0 Stop adding beyondwordsMarker attribute to blocks.
*/
class BlockAttributes
{
@@ -29,13 +26,12 @@ class BlockAttributes
* Init.
*
* @since 4.0.0
- * @since 6.0.0 Make static.
+ * @since 6.0.0 Make static and remove renderBlock registration.
*/
public static function init()
{
add_filter('register_block_type_args', [self::class, 'registerAudioAttribute']);
add_filter('register_block_type_args', [self::class, 'registerMarkerAttribute']);
- add_filter('render_block', [self::class, 'renderBlock'], 10, 2);
}
/**
@@ -63,6 +59,8 @@ public static function registerAudioAttribute($args)
/**
* Register "Segment marker" attribute for Gutenberg blocks.
*
+ * @deprecated This attribute is no longer used as of 6.0.0, but kept for backward compatibility.
+ *
* @since 6.0.0 Make static.
*/
public static function registerMarkerAttribute($args)
@@ -81,45 +79,4 @@ public static function registerMarkerAttribute($args)
return $args;
}
-
- /**
- * Render block as HTML.
- *
- * Performs some checks and then attempts to add data-beyondwords-marker
- * attribute to the root element of Gutenberg blocks.
- *
- * @since 4.0.0
- * @since 4.2.2 Rename method to renderBlock.
- * @since 6.0.0 Make static and update for Magic Embed.
- *
- * @param string $blockContent The block content (HTML).
- * @param string $block The full block, including name and attributes.
- *
- * @return string Block Content (HTML).
- */
- public static function renderBlock($blockContent, $block)
- {
- // Skip adding marker if player UI is disabled
- if (get_option(PlayerUI::OPTION_NAME) === PlayerUI::DISABLED) {
- return $blockContent;
- }
-
- $postId = get_the_ID();
-
- if (! $postId) {
- return $blockContent;
- }
-
- // Skip adding marker if no content exists
- if (! PostMetaUtils::hasContent($postId)) {
- return $blockContent;
- }
-
- $marker = $block['attrs']['beyondwordsMarker'] ?? '';
-
- return PostContentUtils::addMarkerAttribute(
- $blockContent,
- $marker
- );
- }
}
diff --git a/src/Component/Post/BlockAttributes/addAttributes.js b/src/Component/Post/BlockAttributes/addAttributes.js
index e79a4960..fe43983b 100644
--- a/src/Component/Post/BlockAttributes/addAttributes.js
+++ b/src/Component/Post/BlockAttributes/addAttributes.js
@@ -4,20 +4,27 @@
import { addFilter } from '@wordpress/hooks';
/**
- * External dependencies
+ * Internal dependencies
*/
-import getBlockMarkerAttribute from './helpers/getBlockMarkerAttribute';
+import { isBeyondwordsSupportedBlock } from './isBeyondwordsSupportedBlock';
/**
* Register custom block attributes for BeyondWords.
*
* @since 4.0.4 Remove settings.attributes undefined check, to match official docs.
+ * @since 6.0.1 Skip internal/UI blocks to prevent breaking the block inserter.
*
* @param {Object} settings Settings for the block.
+ * @param {string} name Block name.
*
* @return {Object} settings Modified settings.
*/
-function addAttributes( settings ) {
+function addAttributes( settings, name ) {
+ // Only add attributes to content blocks
+ if ( ! isBeyondwordsSupportedBlock( name ) ) {
+ return settings;
+ }
+
return {
...settings,
attributes: {
@@ -39,27 +46,3 @@ addFilter(
'beyondwords/beyondwords-block-attributes',
addAttributes
);
-
-/**
- * Set a unique BeyondWords marker for each block that doesn't already have one.
- *
- * @param {Object} attributes Attributes for the block.
- *
- * @return {Object} attributes Modified attributes.
- */
-function setMarkerAttribute( attributes ) {
- const marker = getBlockMarkerAttribute( attributes );
-
- attributes = {
- ...attributes,
- beyondwordsMarker: marker,
- };
-
- return attributes;
-}
-
-addFilter(
- 'blocks.getBlockAttributes',
- 'beyondwords/set-marker-attribute',
- setMarkerAttribute
-);
diff --git a/src/Component/Post/BlockAttributes/addControls.js b/src/Component/Post/BlockAttributes/addControls.js
index c277ffce..53172b3e 100644
--- a/src/Component/Post/BlockAttributes/addControls.js
+++ b/src/Component/Post/BlockAttributes/addControls.js
@@ -6,28 +6,23 @@ import { InspectorControls, BlockControls } from '@wordpress/block-editor';
import {
PanelBody,
PanelRow,
- TextControl,
ToggleControl,
ToolbarButton,
ToolbarGroup,
} from '@wordpress/components';
import { createHigherOrderComponent } from '@wordpress/compose';
-import { useEffect } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
-/**
- * External dependencies
- */
-import getBlockMarkerAttribute from './helpers/getBlockMarkerAttribute';
-
/**
* Internal dependencies
*/
-import BlockAttributesCheck from './check';
+import { isBeyondwordsSupportedBlock } from './isBeyondwordsSupportedBlock';
/**
* Add BeyondWords controls to Gutenberg Blocks.
*
+ * @since 6.0.1 Skip internal/UI blocks to prevent breaking the block inserter.
+ *
* @param {Function} BlockEdit Block edit component.
*
* @return {Function} BlockEdit Modified block edit component.
@@ -35,15 +30,16 @@ import BlockAttributesCheck from './check';
const withBeyondwordsBlockControls = createHigherOrderComponent(
( BlockEdit ) => {
return ( props ) => {
- const { attributes, setAttributes } = props;
+ const { name } = props;
- useEffect( () => {
- setAttributes( {
- beyondwordsMarker: getBlockMarkerAttribute( attributes ),
- } );
- }, [] );
+ // Skip blocks that shouldn't have controls
+ // Do this check BEFORE accessing attributes to avoid unnecessary processing
+ if ( ! isBeyondwordsSupportedBlock( name ) ) {
+ return ;
+ }
- const { beyondwordsAudio, beyondwordsMarker } = attributes;
+ const { attributes, setAttributes } = props;
+ const { beyondwordsAudio } = attributes;
const icon = !! beyondwordsAudio
? 'controls-volumeon'
@@ -57,56 +53,41 @@ const withBeyondwordsBlockControls = createHigherOrderComponent(
? __( 'Audio processing enabled', 'speechkit' )
: __( 'Audio processing disabled', 'speechkit' );
- const toggleBeyondwordsAudio = () =>
+ const toggleBeyondwordsAudio = () => {
setAttributes( { beyondwordsAudio: ! beyondwordsAudio } );
+ };
return (
<>
-
-
-
-
-
-
- { !! beyondwordsAudio && (
-
-
-
- ) }
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
>
);
};
diff --git a/src/Component/Post/BlockAttributes/helpers/getBlockMarkerAttribute.js b/src/Component/Post/BlockAttributes/helpers/getBlockMarkerAttribute.js
deleted file mode 100644
index 85195750..00000000
--- a/src/Component/Post/BlockAttributes/helpers/getBlockMarkerAttribute.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * WordPress Dependencies
- */
-import { select } from '@wordpress/data';
-
-/**
- * External dependencies
- */
-import { v4 as uuidv4 } from 'uuid';
-
-/**
- * Get a beyondwordsMarker attribute for a block.
- *
- * Using the "Duplicate" button in the Block toolbar duplicates the marker
- * attribute too, so we attempt to handle this by getting all the markers in the
- * current Post and assinging new UUIDs to markers that already exist.
- *
- * @since 4.0.0
- *
- * @param {Object} attributes Attributes for the block.
- *
- * @return {string} marker The block marker (segment marker in BeyondWords API).
- */
-const getBlockMarkerAttribute = ( attributes ) => {
- const { beyondwordsMarker } = attributes;
-
- if ( ! beyondwordsMarker ) {
- return uuidv4();
- }
-
- const existingMarkers = getExistingBlockMarkers();
-
- if ( countInArray( existingMarkers, beyondwordsMarker ) > 1 ) {
- // Return a new UUID if this marker is a duplicate
- return uuidv4();
- }
-
- // Return the existing marker only if it is not a duplicate
- return beyondwordsMarker;
-};
-
-/**
- * Get all existing Block markers for the currently-edited post.
- *
- * If using `getBlocks()` proves to be too respource-intensive then further work
- * will be required to optimise this.
- *
- * @since 4.0.0
- *
- * @return {string[]} markers The block markers for the current Post.
- */
-const getExistingBlockMarkers = () => {
- // Get all Blocks in current Post
- const blocks = select( 'core/block-editor' ).getBlocks();
-
- // Return all non-empty markers of the Blocks
- return blocks
- .map( ( block ) => block?.attributes?.beyondwordsMarker )
- .filter( ( marker ) => marker );
-};
-
-/**
- * Count the number of times an item is in an array.
- *
- * @param array
- * @param item
- * @since 4.0.0
- * @since 4.4.0 Ensure param is array
- *
- * @return {number} count The number of times the item occurs.
- */
-function countInArray( array, item ) {
- if ( ! Array.isArray( array ) ) {
- return 0;
- }
-
- let count = 0;
-
- for ( let i = 0; i < array.length; i++ ) {
- if ( array[ i ] === item ) {
- count++;
- }
- }
-
- return count;
-}
-
-export default getBlockMarkerAttribute;
diff --git a/src/Component/Post/BlockAttributes/isBeyondwordsSupportedBlock.js b/src/Component/Post/BlockAttributes/isBeyondwordsSupportedBlock.js
new file mode 100644
index 00000000..502fee8f
--- /dev/null
+++ b/src/Component/Post/BlockAttributes/isBeyondwordsSupportedBlock.js
@@ -0,0 +1,45 @@
+/**
+ * Check if a block is supported by BeyondWords.
+ * Only content blocks that can be read aloud should have BeyondWords attributes and controls.
+ *
+ * @param {string} name Block name.
+ * @return {boolean} Whether the block is supported by BeyondWords.
+ */
+export function isBeyondwordsSupportedBlock( name ) {
+ // Skip blocks without a name
+ if ( ! name ) {
+ return false;
+ }
+
+ // Skip internal/UI blocks
+ if ( name.startsWith( '__' ) ) {
+ return false;
+ }
+
+ // Skip reusable blocks and template parts (these are containers)
+ if (
+ name.startsWith( 'core/block' ) ||
+ name.startsWith( 'core/template' )
+ ) {
+ return false;
+ }
+
+ // Skip editor UI blocks
+ const excludedBlocks = [
+ 'core/freeform', // Classic editor
+ 'core/legacy-widget',
+ 'core/widget-area',
+ 'core/navigation',
+ 'core/navigation-link',
+ 'core/navigation-submenu',
+ 'core/site-logo',
+ 'core/site-title',
+ 'core/site-tagline',
+ ];
+
+ if ( excludedBlocks.includes( name ) ) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/Component/Post/PostContentUtils.php b/src/Component/Post/PostContentUtils.php
index 26074503..e92bea55 100755
--- a/src/Component/Post/PostContentUtils.php
+++ b/src/Component/Post/PostContentUtils.php
@@ -84,6 +84,7 @@ public static function getPostBody(int|\WP_Post $post): string|null
}
// Apply the_content filters to handle shortcodes etc
+ // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Applying core WordPress filter
$content = apply_filters('the_content', $content);
// Trim to remove trailing newlines – common for WordPress content
@@ -146,6 +147,7 @@ public static function getPostSummary(int|\WP_Post $post): string|null
// Escape characters
$summary = htmlentities($post->post_excerpt, ENT_QUOTES | ENT_XHTML);
// Apply WordPress filters
+ // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Applying core WordPress filter
$summary = apply_filters('get_the_excerpt', $summary);
// Convert line breaks into paragraphs
$summary = trim(wpautop($summary));
@@ -154,59 +156,6 @@ public static function getPostSummary(int|\WP_Post $post): string|null
return $summary;
}
- /**
- * Get the segments for the audio content, ready to be sent to the BeyondWords API.
- *
- * @codeCoverageIgnore
- * THIS METHOD IS CURRENTLY NOT IN USE. Segments cannot currently include HTML
- * formatting tags such as and so we do not pass segments, we pass
- * a HTML string as the body param instead.
- *
- * @param int|\WP_Post $post The WordPress post ID, or post object.
- *
- * @since 4.0.0
- */
- public static function getSegments(int|\WP_Post $post): array
- {
- if (! has_blocks($post)) {
- return [];
- }
-
- $titleSegment = (object) [
- 'section' => 'title',
- 'text' => get_the_title($post),
- ];
-
- $summarySegment = (object) [
- 'section' => 'summary',
- 'text' => PostContentUtils::getPostSummary($post),
- ];
-
- $blocks = PostContentUtils::getAudioEnabledBlocks($post);
-
- $bodySegments = array_map(function ($block) {
- $marker = null;
-
- if (isset($block['attrs']) && isset($block['attrs']['beyondwordsMarker'])) {
- $marker = $block['attrs']['beyondwordsMarker'];
- }
-
- return (object) [
- 'section' => 'body',
- 'marker' => $marker,
- 'text' => trim(render_block($block)),
- ];
- }, $blocks);
-
- // Merge title, summary and body segments
- $segments = array_values(array_merge([$titleSegment], [$summarySegment], $bodySegments));
-
- // Remove any segments with empty text
- $segments = array_values(array_filter($segments, fn($segment) => ! empty($segment::text)));
-
- return $segments;
- }
-
/**
* Get the post content without blocks which have been filtered.
*
@@ -219,6 +168,7 @@ public static function getSegments(int|\WP_Post $post): array
*
* @since 3.8.0
* @since 4.0.0 Replace for loop with array_reduce
+ * @since 6.0.0 Remove beyondwordsMarker attribute from rendered blocks.
*
* @return string The post body without excluded blocks.
*/
@@ -234,12 +184,7 @@ public static function getContentWithoutExcludedBlocks(int|\WP_Post $post): stri
$blocks = PostContentUtils::getAudioEnabledBlocks($post);
foreach ($blocks as $block) {
- $marker = $block['attrs']['beyondwordsMarker'] ?? '';
-
- $output .= PostContentUtils::addMarkerAttribute(
- render_block($block),
- $marker
- );
+ $output .= render_block($block);
}
return $output;
@@ -452,131 +397,4 @@ public static function getAuthorName(int $postId): string
return get_the_author_meta('display_name', $authorId);
}
-
- /**
- * Add data-beyondwords-marker attribute to the root elements in a HTML
- * string (typically the rendered HTML of a single block).
- *
- * Checks to see whether we can use WP_HTML_Tag_Processor, or whether we
- * fall back to using DOMDocument to add the marker.
- *
- * @since 4.2.2
- *
- * @param string $html HTML.
- * @param string $marker Marker UUID.
- *
- * @return string HTML.
- */
- public static function addMarkerAttribute(string $html, string $marker): string
- {
- if (! $marker) {
- return $html;
- }
-
- // Prefer WP_HTML_Tag_Processor, introduced in WordPress 6.2
- if (class_exists('WP_HTML_Tag_Processor')) {
- return PostContentUtils::addMarkerAttributeWithHTMLTagProcessor($html, $marker);
- } else {
- return PostContentUtils::addMarkerAttributeWithDOMDocument($html, $marker);
- }
- }
-
- /**
- * Add data-beyondwords-marker attribute to the root elements in a HTML
- * string using WP_HTML_Tag_Processor.
- *
- * @since 4.0.0
- * @since 4.2.2 Moved from src/Component/Post/BlockAttributes/BlockAttributes.php
- * to src/Component/Post/PostContentUtils.php
- * @since 4.7.0 Prevent empty data-beyondwords-marker attributes.
- *
- * @param string $html HTML.
- * @param string $marker Marker UUID.
- *
- * @return string HTML.
- */
- public static function addMarkerAttributeWithHTMLTagProcessor(string $html, string $marker): string
- {
- if (! $marker) {
- return $html;
- }
-
- // https://github.com/WordPress/gutenberg/pull/42485
- $tags = new \WP_HTML_Tag_Processor($html);
-
- if ($tags->next_tag()) {
- $tags->set_attribute('data-beyondwords-marker', $marker);
- }
-
- return strval($tags);
- }
-
- /**
- * Add data-beyondwords-marker attribute to the root elements in a HTML
- * string using DOMDocument.
- *
- * This is a fallback, since WP_HTML_Tag_Processor was only shipped with
- * WordPress 6.2 on 19 April 2023.
- *
- * https://make.wordpress.org/core/2022/10/13/whats-new-in-gutenberg-14-3-12-october/
- *
- * Note: It is not ideal to do all the $bodyElement/$fullHtml processing
- * in this method, but without it DOMDocument does not work as expected if
- * there is more than 1 root element. The approach here has been taken from
- * some historic Gutenberg code before they implemented WP_HTML_Tag_Processor:
- *
- * https://github.com/WordPress/gutenberg/blob/6671cef1179412a2bbd4969cbbc82705c7f69bac/lib/block-supports/index.php
- *
- * @since 4.0.0
- * @since 4.2.2 Moved from src/Component/Post/BlockAttributes/BlockAttributes.php
- * to src/Component/Post/PostContentUtils.php
- * @since 4.7.0 Prevent empty data-beyondwords-marker attributes.
- *
- * @param string $html HTML.
- * @param string $marker Marker UUID.
- *
- * @return string HTML.
- */
- public static function addMarkerAttributeWithDOMDocument(string $html, string $marker): string
- {
- if (! $marker) {
- return $html;
- }
-
- $dom = new \DOMDocument('1.0', 'utf-8');
-
- $wrappedHtml =
- ''
- . $html
- . '';
-
- $success = $dom->loadHTML($wrappedHtml, LIBXML_HTML_NODEFDTD | LIBXML_COMPACT);
-
- if (! $success) {
- return $html;
- }
-
- // Structure is like ``, so body is the `lastChild` of our document.
- $bodyElement = $dom->documentElement->lastChild;
-
- $xpath = new \DOMXPath($dom);
- $blockRoot = $xpath->query('./*', $bodyElement)[0];
-
- if (empty($blockRoot)) {
- return $html;
- }
-
- $blockRoot->setAttribute('data-beyondwords-marker', $marker);
-
- // Avoid using `$dom->saveHtml( $node )` because the node results may not produce consistent
- // whitespace. Saving the root HTML `$dom->saveHtml()` prevents this behavior.
- $fullHtml = $dom->saveHtml();
-
- // Find the
open/close tags. The open tag needs to be adjusted so we get inside the tag
- // and not the tag itself.
- $start = strpos($fullHtml, '', 0) + strlen('');
- $end = strpos($fullHtml, '', $start);
-
- return trim(substr($fullHtml, $start, $end - $start));
- }
}
diff --git a/tests/cypress/e2e/block-editor/segment-markers.cy.js b/tests/cypress/e2e/block-editor/segment-markers.cy.js
deleted file mode 100644
index 61bc0489..00000000
--- a/tests/cypress/e2e/block-editor/segment-markers.cy.js
+++ /dev/null
@@ -1,355 +0,0 @@
-/* global Cypress, cy, beforeEach, context, expect, it */
-
-context( 'Block Editor: Segment markers', () => {
- beforeEach( () => {
- cy.login();
- } );
-
- const markerRegex =
- /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
-
- const postTypes = require( '../../../../tests/fixtures/post-types.json' );
-
- const testCases = [
- {
- id: 1,
- // eslint-disable-next-line max-len
- text: 'Latin symbols: á, é, í, ó, ú, ü, ñ, ¡, !, ¿, ?, Ä, ä, Ö, ö, Ü, ü, ẞ, ß, Æ, æ, Ø, ø, Å, å',
- },
- { id: 2, text: 'Kanji: 任天堂' },
- { id: 3, text: 'Katana: イリノイ州シカゴにて' },
- {
- id: 4,
- // eslint-disable-next-line max-len
- text: 'Mathematical symbols: αβγδεζηθικλμνξοπρσςτυφχψω ΓΔΘΛΞΠΣΦΨΩ ∫∑∏−±∞≈∝=≡≠≤≥×·⋅÷∂′″∇‰°∴∅ ∈∉∩∪⊂⊃⊆⊇¬∧∨∃∀⇒⇔→↔↑↓ℵ',
- },
- ];
-
- // Test priority post types
- postTypes
- .filter( ( x ) => x.priority )
- .forEach( ( postType ) => {
- it( `A ${ postType.name } without audio should not have segment markers`, () => {
- cy.createPost( {
- postType,
- title: `I can add a ${ postType.name } without segment markers`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.uncheckGenerateAudio( postType );
-
- // Add paragraphs
- cy.addParagraphBlock( 'One.' );
- cy.addParagraphBlock( 'Two.' );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'not.exist' );
- cy.hasNoBeyondwordsWindowObject();
-
- cy.contains( 'p', 'One.' ).should(
- 'not.have.attr',
- 'data-beyondwords-marker'
- );
- cy.contains( 'p', 'Two.' ).should(
- 'not.have.attr',
- 'data-beyondwords-marker'
- );
- } );
-
- it( `can add a ${ postType.name } with segment markers`, () => {
- cy.createPost( {
- postType,
- title: `I can add a ${ postType.name } with segment markers`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.checkGenerateAudio( postType );
-
- /**
- * Ensure the marker is persistent (it DOES NOT change while typing)
- */
- cy.get( '.wp-block-post-content p:last-of-type' ).click();
- // Type a letter
- cy.get( 'body' ).type( `O` );
- // Check the marker
- cy.contains( 'label', 'Segment marker' )
- .siblings( 'input' )
- .first()
- .invoke( 'val' )
- .then( ( originalMarker ) => {
- // Type another letter
- cy.get( 'body' ).type( `K` ).wait( 200 );
- // Get marker value again and check it hasn't changed
- cy.contains( 'label', 'Segment marker' )
- .siblings( 'input' )
- .first()
- .invoke( 'val' )
- .should( 'equal', originalMarker );
- cy.get( 'body' ).type( `{enter}` ).wait( 200 );
- } );
-
- /**
- * Various test cases check we handle UTF-8 correctly
- */
- testCases.forEach( ( testCase ) => {
- // Add paragraph
- cy.addParagraphBlock( testCase.text );
-
- // Grab assigned marker from UI input
- cy.contains( 'label', 'Segment marker' )
- .siblings( 'input' )
- .first()
- .invoke( 'val' )
- .should( 'match', markerRegex ) // Check regex
- .as( `marker${ testCase.id }` );
- } );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'exist' );
- cy.hasPlayerInstances( 1 );
-
- testCases.forEach( ( testCase ) => {
- cy.get( `@marker${ testCase.id }` ).then( ( marker ) => {
- cy.contains( 'p', testCase.text )
- .invoke( 'attr', 'data-beyondwords-marker' )
- .should( 'not.be.empty' ); // @todo check marker
- } );
- } );
-
- cy.task( 'deactivatePlugin', 'speechkit' );
- cy.reload();
-
- // Check content on page again, after deactivating the plugin
- testCases.forEach( ( testCase ) => {
- cy.contains( 'p', testCase.text ) // Text should be an exact UTF-8 match
- .should( 'not.have.attr', 'data-beyondwords-marker' );
- } );
-
- cy.task( 'activatePlugin', 'speechkit' );
- } );
-
- it( `assigns unique markers for duplicated blocks in a ${ postType.name }`, () => {
- cy.createPost( {
- postType,
- title: `I see unique markers for duplicated blocks in a ${ postType.name }`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.checkGenerateAudio( postType );
-
- // Add paragraph
- cy.addParagraphBlock( 'Test.' );
-
- // Grab assigned marker from UI input
- cy.contains( 'label', 'Segment marker' )
- .siblings( 'input' )
- .first()
- .invoke( 'val' )
- .as( 'marker1' );
-
- // Add first paragraph
- cy.get( '.editor-post-title' ).click();
- cy.contains( 'p.wp-block-paragraph', 'Test.' ).click();
-
- // Duplicate paragraph
- cy.get( '.block-editor-block-settings-menu' ).click();
- cy.contains(
- '.components-menu-item__item',
- 'Duplicate'
- ).click();
-
- cy.get( 'p:contains(Test.)' ).should( 'have.length', 2 );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'exist' );
- cy.hasPlayerInstances( 1 );
-
- cy.get( '.entry-content p:not(:empty)' )
- .should( 'have.length', 2 )
- .mapInvoke( 'getAttribute', 'data-beyondwords-marker' )
- .then( ( markers ) => {
- // Markers must be unique
- const unique = Cypress._.uniq( markers );
- expect(
- unique,
- 'all markers are unique'
- ).to.have.length( markers.length );
-
- // All markers must be UUIDs
- expect( markers[ 0 ] ).to.match( markerRegex );
- expect( markers[ 1 ] ).to.match( markerRegex );
- } );
- } );
-
- it( 'assigns markers when blocks are added programatically', () => {
- cy.createPost( {
- title: `I see markers when blocks are added programatically`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.checkGenerateAudio( postType );
-
- // Add paragraph
- cy.createBlockProgramatically( 'core/paragraph', {
- content: 'One.',
- } );
-
- // Add paragraph
- cy.createBlockProgramatically( 'core/paragraph', {
- content: 'Two.',
- } );
-
- cy.get( 'p:contains(One.)' ).should( 'have.length', 1 );
- cy.get( 'p:contains(Two.)' ).should( 'have.length', 1 );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'exist' );
- cy.hasPlayerInstances( 1 );
-
- cy.get( '.entry-content p:not(:empty)' )
- .should( 'have.length', 2 )
- .mapInvoke( 'getAttribute', 'data-beyondwords-marker' )
- .then( ( markers ) => {
- // Markers must be unique
- const unique = Cypress._.uniq( markers );
- expect(
- unique,
- 'all markers are unique'
- ).to.have.length( markers.length );
-
- // All markers must be UUIDs
- expect( markers[ 0 ] ).to.match( markerRegex );
- expect( markers[ 1 ] ).to.match( markerRegex );
- } );
- } );
-
- // So far unable to write tests for pasted content, all attempts have failed :(
- it( 'assigns markers when content is pasted', () => {
- cy.createPost( {
- title: `I see markers for pasted content`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.checkGenerateAudio( postType );
-
- // Click "+ block" button
- cy.get(
- '.block-editor-default-block-appender__content'
- ).click();
-
- cy.get( '.wp-block.is-selected' ).paste( 'One.\n\nTwo.' );
-
- cy.get( 'p:contains(One.)' ).should( 'have.length', 1 );
- cy.get( 'p:contains(Two.)' ).should( 'have.length', 1 );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'exist' );
- cy.hasPlayerInstances( 1 );
-
- cy.get( '.entry-content p:not(:empty)' )
- .should( 'have.length', 2 )
- .mapInvoke( 'getAttribute', 'data-beyondwords-marker' )
- .then( ( markers ) => {
- // Markers must be unique
- const unique = Cypress._.uniq( markers );
- expect(
- unique,
- 'all markers are unique'
- ).to.have.length( markers.length );
-
- // All markers must be UUIDs
- expect( markers[ 0 ] ).to.match( markerRegex );
- expect( markers[ 1 ] ).to.match( markerRegex );
- } );
- } );
- } );
-
- it( `makes existing duplicate segment markers unique`, () => {
- cy.createPost( {
- title: `I see existing duplicate markers are replaced with unique markers`,
- } );
-
- // cy.closeWelcomeToBlockEditorTips()
- cy.openBeyondwordsEditorPanel();
-
- cy.getBlockEditorCheckbox( 'Generate audio' ).check();
-
- // Add paragraph
- cy.createBlockProgramatically( 'core/paragraph', {
- content: 'One.',
- attributes: {
- beyondwordsMarker: '[DUPLICATE MARKER]',
- },
- } );
-
- // Add paragraph
- cy.createBlockProgramatically( 'core/paragraph', {
- content: 'Two.',
- attributes: {
- beyondwordsMarker: '[DUPLICATE MARKER]',
- },
- } );
-
- // Add paragraph
- cy.createBlockProgramatically( 'core/paragraph', {
- content: 'Three.',
- attributes: {
- beyondwordsMarker: '[DUPLICATE MARKER]',
- },
- } );
-
- cy.publishWithConfirmation();
-
- // "View post"
- cy.viewPostViaSnackbar();
-
- cy.getPlayerScriptTag().should( 'exist' );
- cy.hasPlayerInstances( 1 );
-
- cy.get( '.entry-content p:not(:empty)' )
- .should( 'have.length', 3 )
- .mapInvoke( 'getAttribute', 'data-beyondwords-marker' )
- .then( ( markers ) => {
- // Markers must be unique
- const unique = Cypress._.uniq( markers );
- expect( unique, 'all markers are unique' ).to.have.length(
- markers.length
- );
-
- // All markers must be UUIDs
- expect( markers[ 0 ] ).to.match( markerRegex );
- expect( markers[ 1 ] ).to.match( markerRegex );
- expect( markers[ 2 ] ).to.match( markerRegex );
- } );
- } );
-} );
diff --git a/tests/phpunit/Component/Post/BlockAttributes/BlockAttributesTest.php b/tests/phpunit/Component/Post/BlockAttributes/BlockAttributesTest.php
index 1870959b..bdea5ced 100644
--- a/tests/phpunit/Component/Post/BlockAttributes/BlockAttributesTest.php
+++ b/tests/phpunit/Component/Post/BlockAttributes/BlockAttributesTest.php
@@ -1,15 +1,9 @@
assertEquals(10, has_action('register_block_type_args', array(BlockAttributes::class, 'registerAudioAttribute')));
$this->assertEquals(10, has_action('register_block_type_args', array(BlockAttributes::class, 'registerMarkerAttribute')));
- $this->assertEquals(10, has_action('render_block', array(BlockAttributes::class, 'renderBlock')));
}
/**
@@ -185,113 +178,4 @@ public function registerMarkerAttributeProvider($args) {
],
];
}
-
- /**
- * @test
- */
- public function renderBlockWithUiDisabled()
- {
- update_option(PlayerUI::OPTION_NAME, PlayerUI::DISABLED);
-
- $this->assertSame(
- 'Test
',
- BlockAttributes::renderBlock('Test
', [
- 'attrs' => [
- 'beyondwordsMarker' => 'foo',
- ]
- ])
- );
-
- delete_option(PlayerUI::OPTION_NAME);
- }
-
- /**
- * @test
- */
- public function renderBlockWithoutCustomFields()
- {
- $postId = self::factory()->post->create([
- 'post_title' => 'BlockAttributesTest::renderBlockWithoutCustomFields',
- 'post_type' => 'post',
- ]);
-
- $this->go_to(get_permalink($postId));
- global $post;
- setup_postdata($post);
-
- $this->assertSame(
- 'Test
',
- BlockAttributes::renderBlock('Test
', [
- 'attrs' => [
- 'beyondwordsMarker' => 'foo',
- ]
- ])
- );
-
- wp_reset_postdata();
-
- wp_delete_post($postId, true);
- }
-
- /**
- * @test
- */
- public function renderBlockWithoutMarkerAttribute()
- {
- $postId = self::factory()->post->create([
- 'post_title' => 'BlockAttributesTest::renderBlockWithoutMarkerAttribute',
- 'meta_input' => [
- 'beyondwords_project_id' => BEYONDWORDS_TESTS_PROJECT_ID,
- 'beyondwords_content_id' => BEYONDWORDS_TESTS_CONTENT_ID,
- ],
- ]);
-
- $this->go_to(get_permalink($postId));
- global $post;
- setup_postdata($post);
-
- $this->assertSame(
- 'Test
',
- BlockAttributes::renderBlock('Test
', [
- 'attrs' => [
- 'foo' => 'bar',
- ]
- ])
- );
-
- wp_reset_postdata();
-
- wp_delete_post($postId, true);
- }
-
- /**
- * @test
- */
- public function renderBlockWithMarkerAttribute()
- {
- $postId = self::factory()->post->create([
- 'post_title' => 'BlockAttributesTest::renderBlockWithMarkerAttribute',
- 'meta_input' => [
- 'beyondwords_project_id' => BEYONDWORDS_TESTS_PROJECT_ID,
- 'beyondwords_content_id' => BEYONDWORDS_TESTS_CONTENT_ID,
- ],
- ]);
-
- $this->go_to(get_permalink($postId));
- global $post;
- setup_postdata($post);
-
- $this->assertSame(
- 'Test
',
- BlockAttributes::renderBlock('Test
', [
- 'attrs' => [
- 'beyondwordsMarker' => 'baz',
- ]
- ])
- );
-
- wp_reset_postdata();
-
- wp_delete_post($postId, true);
- }
}
diff --git a/tests/phpunit/Core/Player/Renderer/AmpTest.php b/tests/phpunit/Core/Player/Renderer/AmpTest.php
index 514a1183..475a0a9d 100644
--- a/tests/phpunit/Core/Player/Renderer/AmpTest.php
+++ b/tests/phpunit/Core/Player/Renderer/AmpTest.php
@@ -5,9 +5,11 @@
use \Symfony\Component\DomCrawler\Crawler;
/**
- * Class Amp
+ * Test the Amp player renderer.
*
- * Renders the AMP-compatible BeyondWords player.
+ * Note that we are are not testing Amp::check() here due to limitations
+ * with mocking the amp_is_request() function in the current test environment.
+ * The Amp::check() method is covered by integration tests when the AMP plugin is active.
*/
class AmpTest extends TestCase
{
@@ -29,47 +31,6 @@ public function tearDown(): void
parent::tearDown();
}
- /**
- * @test
- */
- public function check()
- {
- $this->markTestSkipped(
- 'This test requires mocking amp_is_request() in a separate process, ' .
- 'which conflicts with the current Xdebug configuration in the test environment. ' .
- 'The Amp::check() method is covered by integration tests when the AMP plugin is active.'
- );
-
- // Note: Original test code is preserved below but not executed:
- //
- // Load stub to define amp_is_request() function
- // require_once __DIR__ . '/../../../Stubs/amp_is_request_true.php';
- //
- // $this->assertTrue(\amp_is_request());
- //
- // // Test 1: Post without BeyondWords meta should return false
- // $post = self::factory()->post->create_and_get([
- // 'post_title' => 'Amp::check::1',
- // ]);
- //
- // $this->assertFalse(Amp::check($post));
- //
- // wp_delete_post($post->ID, true);
- //
- // // Test 2: Post with BeyondWords content should return true
- // $post = self::factory()->post->create_and_get([
- // 'post_title' => 'Amp::check::2',
- // 'meta_input' => [
- // 'beyondwords_project_id' => BEYONDWORDS_TESTS_PROJECT_ID,
- // 'beyondwords_podcast_id' => BEYONDWORDS_TESTS_CONTENT_ID,
- // ],
- // ]);
- //
- // $this->assertTrue(Amp::check($post));
- //
- // wp_delete_post($post->ID, true);
- }
-
/**
* @test
*/
diff --git a/tests/phpunit/Core/PostContentUtilsTest.php b/tests/phpunit/Core/PostContentUtilsTest.php
index 98d8939c..9f0a4f6d 100644
--- a/tests/phpunit/Core/PostContentUtilsTest.php
+++ b/tests/phpunit/Core/PostContentUtilsTest.php
@@ -140,14 +140,14 @@ public function getContentWithoutExcludedBlocksProvider()
'Previous two paragraphs were empty.
';
$withBlocksExpect = 'No marker.
' .
- 'Has marker.
' .
+ 'Has marker.
' .
+ '' .
'' .
- '' .
'Previous two paragraphs were empty.
';
- $withoutBlocks = "One
\n\n\n\nThree
\n\n";
+ $withoutBlocks = "One
\n\n\n\nThree
\n\n";
- $withoutBlocksExpect = "One
\n\n\n\nThree
";
+ $withoutBlocksExpect = "One
\n\n\n\nThree
";
return [
'Content with blocks' => [ $withBlocks, $withBlocksExpect ],
@@ -614,95 +614,4 @@ public function getAuthorName()
wp_delete_post($post->ID, true);
}
-
- /**
- * @test
- * @dataProvider addMarkerAttributeWithHTMLTagProcessorProvider
- */
- public function addMarkerAttributeWithHTMLTagProcessor($html, $marker, $expect) {
- $result = PostContentUtils::addMarkerAttributeWithHTMLTagProcessor($html, $marker);
-
- $this->assertSame($expect, trim($result));
- }
-
- public function addMarkerAttributeWithHTMLTagProcessorProvider($args) {
- return [
- 'No HTML' => [
- 'html' => '',
- 'marker' => 'foo',
- 'expect' => '',
- ],
- 'No marker' => [
- 'html' => 'Text
',
- 'marker' => '',
- 'expect' => 'Text
',
- ],
- 'Paragraph' => [
- 'html' => 'Text
',
- 'marker' => 'foo',
- 'expect' => 'Text
',
- ],
- 'Empty paragraph' => [
- 'html' => '',
- 'marker' => 'foo',
- 'expect' => '',
- ],
- 'Existing attributes' => [
- 'html' => 'Text
',
- 'marker' => 'foo',
- 'expect' => 'Text
',
- ],
- 'Multiple root elements' => [
- 'html' => "One
\nTwo
",
- 'marker' => 'foo',
- 'expect' => "One
\nTwo
",
- ],
- ];
- }
-
- /**
- * @test
- * @dataProvider addMarkerAttributeWithDOMDocumentProvider
- */
- public function addMarkerAttributeWithDOMDocument($html, $marker, $expect)
- {
- $result = PostContentUtils::addMarkerAttributeWithDOMDocument($html, $marker);
-
- $this->assertSame($expect, trim($result));
- }
-
- public function addMarkerAttributeWithDOMDocumentProvider($args) {
- return [
- 'No HTML' => [
- 'html' => '',
- 'marker' => 'foo',
- 'expect' => '',
- ],
- 'No marker' => [
- 'html' => 'Text
',
- 'marker' => '',
- 'expect' => 'Text
',
- ],
- 'Paragraph' => [
- 'html' => 'Text
',
- 'marker' => 'foo',
- 'expect' => 'Text
',
- ],
- 'Empty paragraph' => [
- 'html' => '',
- 'marker' => 'foo',
- 'expect' => '',
- ],
- 'Existing attributes' => [
- 'html' => 'Text
',
- 'marker' => 'foo',
- 'expect' => 'Text
',
- ],
- 'Multiple root elements' => [
- 'html' => "One
\nTwo
",
- 'marker' => 'foo',
- 'expect' => "One
\nTwo
",
- ],
- ];
- }
}