Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion includes/Services/Seopress_Seo_Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,59 @@ private function merge_block_faq_into_schema( array $json ): ?array {
return null;
}

$existing_questions = $this->normalize_main_entity( $json['mainEntity'] ?? [] );
$merged_questions = array_merge( $existing_questions, $questions );

$json['@type'] = 'FAQPage';
$json['mainEntity'] = $questions;
$json['mainEntity'] = $this->renumber_question_positions( $merged_questions );
$json['@context'] = $json['@context'] ?? 'https://schema.org';
$json['inLanguage'] = $json['inLanguage'] ?? get_bloginfo( 'language' );

return $json;
}

/**
* Normalize FAQPage mainEntity to a list of Question entries.
*
* @param mixed $main_entity FAQPage mainEntity value.
*
* @return array<int, array<string, mixed>>
*/
private function normalize_main_entity( $main_entity ): array {
if ( empty( $main_entity ) || ! is_array( $main_entity ) ) {
return [];
}

if ( isset( $main_entity['@type'] ) ) {
return [ $main_entity ];
}

return array_values(
array_filter(
$main_entity,
static fn( $question ) => is_array( $question ) && ! empty( $question )
)
);
}

/**
* Ensure sequential position values on merged FAQ questions.
*
* @param array<int, array<string, mixed>> $questions Question entries.
*
* @return array<int, array<string, mixed>>
*/
private function renumber_question_positions( array $questions ): array {
$position = 1;

foreach ( $questions as $index => $question ) {
$questions[ $index ]['position'] = $position;
++$position;
}

return $questions;
}

/**
* Create a schema generator from the current singular post.
*
Expand Down
100 changes: 74 additions & 26 deletions src/faq/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
useBlockProps,
useInnerBlocksProps,
InspectorControls,
useBlockEditContext,
store as blockEditorStore,
} from '@wordpress/block-editor';
import {
Expand All @@ -30,7 +29,7 @@ import {
import { useDispatch, useSelect } from '@wordpress/data';
import { createBlock } from '@wordpress/blocks';
import { __, sprintf } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { useEffect, useLayoutEffect } from '@wordpress/element';

const QUESTION_BLOCK = 'blockparty/faq-question';
const HEADING_LEVELS = [ 2, 3, 4, 5, 6 ];
Expand All @@ -53,9 +52,27 @@ function collectQuestionBlocks( blocks ) {
} );
}

function useSyncQuestionHeadingLevels( headingLevel, isAccordion ) {
const { clientId } = useBlockEditContext();
const { updateBlockAttributes } = useDispatch( blockEditorStore );
function syncQuestionHeadingLevels(
clientId,
headingLevel,
isAccordion,
{ getBlocksByClientId, updateBlockAttributes }
) {
if ( ! isAccordion ) {
return;
}

const [ faqBlock ] = getBlocksByClientId( clientId );
const questionBlocks = collectQuestionBlocks( faqBlock?.innerBlocks || [] );

questionBlocks.forEach( ( block ) => {
if ( block.attributes.headingLevel !== headingLevel ) {
updateBlockAttributes( block.clientId, { headingLevel } );
}
} );
}

function useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion ) {
const questionBlocks = useSelect(
( select ) => {
const { getBlocksByClientId } = select( blockEditorStore );
Expand All @@ -65,18 +82,25 @@ function useSyncQuestionHeadingLevels( headingLevel, isAccordion ) {
},
[ clientId ]
);
const { getBlocksByClientId } = useSelect(
( select ) => select( blockEditorStore ),
[]
);
const { updateBlockAttributes } = useDispatch( blockEditorStore );

useEffect( () => {
if ( ! isAccordion ) {
return;
}

questionBlocks.forEach( ( block ) => {
if ( block.attributes.headingLevel !== headingLevel ) {
updateBlockAttributes( block.clientId, { headingLevel } );
}
useLayoutEffect( () => {
syncQuestionHeadingLevels( clientId, headingLevel, isAccordion, {
getBlocksByClientId,
updateBlockAttributes,
Comment thread
firestar300 marked this conversation as resolved.
} );
}, [ headingLevel, isAccordion, questionBlocks, updateBlockAttributes ] );
}, [
clientId,
headingLevel,
isAccordion,
questionBlocks,
getBlocksByClientId,
updateBlockAttributes,
] );
Comment thread
firestar300 marked this conversation as resolved.
}

export default function Edit( { clientId, attributes, setAttributes } ) {
Expand All @@ -89,13 +113,14 @@ export default function Edit( { clientId, attributes, setAttributes } ) {
} );

const { insertBlock, updateBlockAttributes } =
useDispatch( 'core/block-editor' );
const { getBlocks } = useSelect(
( select ) => select( 'core/block-editor' ),
useDispatch( blockEditorStore );
const blockEditor = useSelect(
( select ) => select( blockEditorStore ),
[]
);
const { getBlocks, getBlocksByClientId } = blockEditor;

useSyncQuestionHeadingLevels( headingLevel, isAccordion );
useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion );

// Synchronize isAccordion attribute to all child blocks
useEffect( () => {
Expand Down Expand Up @@ -149,9 +174,21 @@ export default function Edit( { clientId, attributes, setAttributes } ) {
'blockparty-faq'
) }
checked={ isAccordion }
onChange={ ( value ) =>
setAttributes( { isAccordion: value } )
}
onChange={ ( value ) => {
setAttributes( { isAccordion: value } );

if ( value ) {
syncQuestionHeadingLevels(
clientId,
headingLevel,
true,
{
getBlocksByClientId,
updateBlockAttributes,
}
);
}
} }
__nextHasNoMarginBottom
/>
{ isAccordion && (
Expand All @@ -167,11 +204,22 @@ export default function Edit( { clientId, attributes, setAttributes } ) {
value={ headingLevel }
isBlock
__next40pxDefaultSize
onChange={ ( value ) =>
onChange={ ( value ) => {
const newHeadingLevel = Number( value );

setAttributes( {
headingLevel: Number( value ),
} )
}
headingLevel: newHeadingLevel,
} );
syncQuestionHeadingLevels(
clientId,
newHeadingLevel,
isAccordion,
{
getBlocksByClientId,
updateBlockAttributes,
}
);
} }
>
{ HEADING_LEVELS.map( ( level ) => (
<ToggleGroupControlOptionIcon
Expand Down
Loading