From acb54b7c4e2d54aba87726c93e88f2175e7ce31a Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 21:28:44 +0300 Subject: [PATCH 1/7] feat: register FAQ block --- assets/js/faq.js | 73 +++++++++++++++++++++++++++++++++++++++ assets/js/minified/faq.js | 1 + 2 files changed, 74 insertions(+) create mode 100644 assets/js/faq.js create mode 100644 assets/js/minified/faq.js diff --git a/assets/js/faq.js b/assets/js/faq.js new file mode 100644 index 0000000..028ca5f --- /dev/null +++ b/assets/js/faq.js @@ -0,0 +1,73 @@ +( function ( wp, lodash ) { + 'use strict'; + + // Check if the wp object exists. + if ( ! wp ) { + return; + } + + const { times, noop } = lodash; + const { createElement: el } = wp.element; + const { registerBlockType } = wp.blocks; + const { ButtonBlockAppender, useBlockProps, useInnerBlocksProps } = wp.blockEditor; + const { useSelect } = wp.data; + const { __ } = wp.i18n; + + registerBlockType( 'seo-ready/faq', { + apiVersion: 2, + title: __( 'FAQ', 'seo-ready' ), + description: __( 'This block displays a list of frequently asked questions.', 'seo-ready' ), + keywords: [ 'faq', 'question', 'answer' ], + icon: 'editor-help', + attributes: {}, + category: 'design', + supports: { + align: [ 'full', 'wide' ], + multiple: false, + html: false, + layout: { + allowSwitching: false, + allowInheriting: false, + allowEditing: false, + default: { + type: 'flex', + flexWrap: 'nowrap', + flexDirection: 'row', + }, + }, + }, + edit: ( { clientId } ) => { + const isSelectedBlockInRoot = useSelect( + ( select ) => { + const { isBlockSelected, hasSelectedInnerBlock } = select( 'core/block-editor' ); + + return isBlockSelected( clientId ) || hasSelectedInnerBlock( clientId, true ); + }, + [ clientId ] + ); + const blockProps = useBlockProps( { className: 'is-layout-constrained' } ); + const { children } = useInnerBlocksProps( + {}, + { + allowedBlocks: [ 'core/details' ], + renderAppender: noop, + template: times( 2, () => [ 'core/details', {} ] ), + templateInsertUpdatesSelection: true, + } + ); + + return el( + 'div', + blockProps, + children, + isSelectedBlockInRoot && el( ButtonBlockAppender, { rootClientId: clientId } ) + ); + }, + save: () => { + const blockProps = useBlockProps.save( { id: 'faq', className: 'is-layout-constrained' } ); + const { children } = useInnerBlocksProps.save(); + + return el( 'div', blockProps, children ); + }, + } ); +} )( window.wp, window.lodash ); diff --git a/assets/js/minified/faq.js b/assets/js/minified/faq.js new file mode 100644 index 0000000..4012c2e --- /dev/null +++ b/assets/js/minified/faq.js @@ -0,0 +1 @@ +"use strict";(function(wp,lodash){"use strict";if(!wp){return}var times=lodash.times,noop=lodash.noop;var el=wp.element.createElement;var registerBlockType=wp.blocks.registerBlockType;var _wp$blockEditor=wp.blockEditor,ButtonBlockAppender=_wp$blockEditor.ButtonBlockAppender,useBlockProps=_wp$blockEditor.useBlockProps,useInnerBlocksProps=_wp$blockEditor.useInnerBlocksProps;var useSelect=wp.data.useSelect;var __=wp.i18n.__;registerBlockType("seo-ready/faq",{apiVersion:2,title:__("FAQ","seo-ready"),description:__("This block displays a list of frequently asked questions.","seo-ready"),keywords:["faq","question","answer"],icon:"editor-help",attributes:{},category:"design",supports:{align:["full","wide"],multiple:false,html:false,layout:{allowSwitching:false,allowInheriting:false,allowEditing:false,"default":{type:"flex",flexWrap:"nowrap",flexDirection:"row"}}},edit:function edit(_ref){var clientId=_ref.clientId;var isSelectedBlockInRoot=useSelect(function(select){var _select=select("core/block-editor"),isBlockSelected=_select.isBlockSelected,hasSelectedInnerBlock=_select.hasSelectedInnerBlock;return isBlockSelected(clientId)||hasSelectedInnerBlock(clientId,true)},[clientId]);var blockProps=useBlockProps({className:"is-layout-constrained"});var _useInnerBlocksProps=useInnerBlocksProps({},{allowedBlocks:["core/details"],renderAppender:noop,template:times(2,function(){return["core/details",{}]}),templateInsertUpdatesSelection:true}),children=_useInnerBlocksProps.children;return el("div",blockProps,children,isSelectedBlockInRoot&&el(ButtonBlockAppender,{rootClientId:clientId}))},save:function save(){var blockProps=useBlockProps.save({id:"faq",className:"is-layout-constrained"});var _useInnerBlocksProps$=useInnerBlocksProps.save(),children=_useInnerBlocksProps$.children;return el("div",blockProps,children)}})})(window.wp,window.lodash); \ No newline at end of file From 261cb41f279da00e649026efa3b7dcc2b857bc06 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 21:28:52 +0300 Subject: [PATCH 2/7] Generate --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index a1adb18..35cffb6 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/mahdiyazdani/wp-breadcrumbs.git", - "reference": "743dd87a87ccddc02733e28d2e18378b492d1ee8" + "reference": "5a9f7b753dbca334a1308b9b880b6b818a8b4c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mahdiyazdani/wp-breadcrumbs/zipball/743dd87a87ccddc02733e28d2e18378b492d1ee8", - "reference": "743dd87a87ccddc02733e28d2e18378b492d1ee8", + "url": "https://api.github.com/repos/mahdiyazdani/wp-breadcrumbs/zipball/5a9f7b753dbca334a1308b9b880b6b818a8b4c90", + "reference": "5a9f7b753dbca334a1308b9b880b6b818a8b4c90", "shasum": "" }, "require": { @@ -63,7 +63,7 @@ "issues": "https://github.com/mahdiyazdani/wp-breadcrumbs/issues", "source": "https://github.com/mahdiyazdani/wp-breadcrumbs/tree/1.0.0" }, - "time": "2024-08-22T18:25:16+00:00" + "time": "2024-08-26T16:58:28+00:00" } ], "packages-dev": [ From 9216c7acde87a4d3d88625851328c5e6cfb2ea31 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 21:29:03 +0300 Subject: [PATCH 3/7] fix: remove CSS minify script --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 41c7b62..28c923f 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "lint:wpcs": "composer lint:wpcs", "lint:wpcs:fix": "composer lint:wpcbf", "makepot": "composer make-pot", - "minify": "cross-env BABEL_ENV=default NODE_ENV=production npm run minify:css && npm run minify:js && npm run minify:css:path", + "minify": "cross-env BABEL_ENV=default NODE_ENV=production npm run minify:js", "minify:css:path": "replace-in-files --string='../' --replacement='../../' assets/css/minified", - "minify:css": "rimraf assets/css/minified && cleancss --batch --batch-suffix '' assets/css/*.css --output assets/css/minified", + "minify:css": "rimraf assets/css/minified && cleancss --batch --batch-suffix '' assets/css/*.css --output assets/css/minified && npm run minify:css:path", "minify:js": "rimraf assets/js/minified && npm run format && babel assets/js/*.js --out-dir assets/js/minified --no-comments --minified --presets=@babel/preset-env" }, "devDependencies": { From 6b3ba0ff4f5e1042b5d2cbf34798bbde521d08a2 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 21:29:33 +0300 Subject: [PATCH 4/7] Add new changelog --- readme.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index a2a0db6..b9d6e73 100644 --- a/readme.txt +++ b/readme.txt @@ -5,7 +5,7 @@ Donate link: https://www.buymeacoffee.com/mahdiyazdani Requires at least: 5.5 Tested up to: 6.6 Requires PHP: 7.4 -Stable tag: 2.3.1 +Stable tag: 2.4.0 License: GPLv3 or later License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -91,6 +91,12 @@ Yes, our dedicated support team is ready to assist you with any questions or iss 3. Customize how your content appears on Facebook and Twitter/X with the SEO Ready plugin's social media settings. == Changelog === += 2.4.0 = +* Add "FAQ" editor block. + += 2.3.2 = +* Fix fatal error when endpoint function is not available. + = 2.3.1 = * Fix blog breadcrumb trails not displaying in the single post view. From 72c4ca7b4cdcba89f231323bb8f76eb7fd52a8a8 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 21:30:18 +0300 Subject: [PATCH 5/7] feat: generate faq schema feat: register faq script --- seo-ready.php | 141 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 29 deletions(-) diff --git a/seo-ready.php b/seo-ready.php index d205f9d..37a2fcb 100644 --- a/seo-ready.php +++ b/seo-ready.php @@ -26,7 +26,7 @@ * Plugin Name: SEO Ready * Plugin URI: https://mypreview.one * Description: A lightweight SEO plugin to generate most commonly used meta tags. Designed for privacy, speed, and accessibility. - * Version: 2.3.1 + * Version: 2.4.0 * Author: MyPreview * Author URI: https://mypreview.one * Requires at least: 5.9 @@ -45,7 +45,7 @@ exit; } -define( 'SEO_READY_VERSION', '2.3.0' ); +define( 'SEO_READY_VERSION', '2.4.0' ); /** * Loads the PSR-4 autoloader implementation. @@ -331,7 +331,15 @@ function seo_ready_enqueue_editor() { wp_enqueue_script( 'seo-ready-breadcrumbs', untrailingslashit( plugin_dir_url( __FILE__ ) ) . "/assets/js/{$min}breadcrumbs.js", - array( 'lodash', 'react', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives' ), + array( 'lodash', 'react', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-html-entities' ), + SEO_READY_VERSION, + true + ); + + wp_enqueue_script( + 'seo-ready-faq', + untrailingslashit( plugin_dir_url( __FILE__ ) ) . "/assets/js/{$min}faq.js", + array( 'lodash', 'react', 'wp-components', 'wp-element', 'wp-i18n' ), SEO_READY_VERSION, true ); @@ -400,6 +408,29 @@ function seo_ready_render_breadcrumbs_block( $block_content, $block ) { } add_filter( 'render_block', 'seo_ready_render_breadcrumbs_block', 10, 2 ); +/** + * Renders the FAQ block. + * + * @since 2.4.0 + * + * @param string $block_content The block content. + * @param array $block The block. + * + * @return string + */ +function seo_ready_render_faq_block( $block_content, $block ) { + + // Return early if in admin or the block is not 'seo-ready/breadcrumbs'. + if ( is_admin() || 'seo-ready/faq' !== $block['blockName'] ) { + return $block_content; + } + + seo_ready_generate_faq_page_item( $block['innerBlocks'] ); + + return $block_content; +} +add_filter( 'render_block', 'seo_ready_render_faq_block', 10, 2 ); + /** * Enqueue scripts and styles for the frontend. * @@ -412,87 +443,101 @@ function seo_ready_render_breadcrumbs_block( $block_content, $block ) { */ function seo_ready_get_schema_json_ld( $schema_types = array( 'WebPage' ), $has_person_graph = false ) { - $person = array(); $current_url = get_permalink(); + $blog_url = get_bloginfo( 'url' ); + $blog_name = get_bloginfo( 'name' ); + $language = get_bloginfo( 'language' ); + // WebPage or other schema types. $webpage_itempage = array( '@type' => array_unique( $schema_types ), '@id' => $current_url, 'url' => $current_url, - 'name' => get_the_title() . ' - ' . get_bloginfo( 'name' ), - 'isPartOf' => array( - '@id' => path_join( get_bloginfo( 'url' ), '#website' ), - ), + 'name' => get_the_title() . ' - ' . $blog_name, + 'isPartOf' => array( '@id' => path_join( $blog_url, '#website' ) ), 'datePublished' => get_the_time( 'c' ), 'dateModified' => get_the_modified_time( 'c' ), - 'breadcrumb' => array( - '@id' => path_join( $current_url, '#breadcrumb' ), - ), - 'inLanguage' => get_bloginfo( 'language' ), + 'breadcrumb' => array( '@id' => path_join( $current_url, '#breadcrumb' ) ), + 'inLanguage' => $language, 'potentialAction' => array( array( '@type' => 'ReadAction', - 'target' => array( - $current_url, - ), + 'target' => array( $current_url ), ), ), ); + // FAQPage schema type. + $faq_main_entity = seo_ready_generate_faq_page_item(); + $faq_list = ! empty( $faq_main_entity ) ? array( + '@type' => 'FAQPage', + '@id' => path_join( $current_url, '#faq' ), + 'url' => $current_url, + 'mainEntity' => $faq_main_entity, + 'inLanguage' => $language, + 'isPartOf' => array( '@id' => path_join( $blog_url, '#website' ) ), + 'breadcrumb' => array( '@id' => path_join( $current_url, '#breadcrumb' ) ), + ) : null; + + // BreadcrumbList schema type. $breadcrumb_list = array( '@type' => 'BreadcrumbList', '@id' => path_join( $current_url, '#breadcrumb' ), 'itemListElement' => seo_ready_generate_breadcrumb_list_item(), ); + // WebSite schema type. $website = array( '@type' => 'WebSite', - '@id' => path_join( get_bloginfo( 'url' ), '#website' ), - 'url' => get_bloginfo( 'url' ), - 'name' => get_bloginfo( 'name' ), + '@id' => path_join( $blog_url, '#website' ), + 'url' => $blog_url, + 'name' => $blog_name, 'description' => get_bloginfo( 'description' ), 'potentialAction' => array( array( '@type' => 'SearchAction', 'target' => array( '@type' => 'EntryPoint', - 'urlTemplate' => path_join( get_bloginfo( 'url' ), '?s={search_term_string}' ), + 'urlTemplate' => path_join( $blog_url, '?s={search_term_string}' ), ), 'query-input' => 'required name=search_term_string', ), ), - 'inLanguage' => get_bloginfo( 'language' ), + 'inLanguage' => $language, ); - // Person graph. + // Person schema type if applicable. + $person = array(); if ( $has_person_graph ) { + $author_id = get_the_author_meta( 'ID' ); $author_name = get_the_author(); - $author_url = get_author_posts_url( get_the_author_meta( 'ID' ) ); + $author_url = get_author_posts_url( $author_id ); $author_gravatar = get_avatar_url( get_the_author_meta( 'user_email' ), array( 'size' => 96 ) ); - $person = array( + + $person = array( '@type' => 'Person', - '@id' => path_join( path_join( get_bloginfo( 'url' ), '#/schema/person' ), seo_ready_get_current_user_hash( get_the_author_meta( 'ID' ) ) ), + '@id' => path_join( path_join( $blog_url, '#/schema/person' ), seo_ready_get_current_user_hash( $author_id ) ), 'name' => $author_name, 'image' => array( '@type' => 'ImageObject', - 'inLanguage' => get_bloginfo( 'language' ), + 'inLanguage' => $language, '@id' => path_join( $author_url, '#/schema/person/image' ), 'url' => $author_gravatar, 'contentUrl' => $author_gravatar, 'caption' => $author_name, ), - 'sameAs' => array( - $author_url, - ), + 'sameAs' => array( $author_url ), 'url' => $author_url, ); } + // Final schema graph. $graph = array( '@context' => 'https://schema.org', '@graph' => array_filter( array( $webpage_itempage, + $faq_list, $breadcrumb_list, $website, $person, @@ -503,6 +548,44 @@ function seo_ready_get_schema_json_ld( $schema_types = array( 'WebPage' ), $has_ return wp_json_encode( $graph, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ); } +/** + * Generates FAQPage item. + * + * @since 2.4.0 + * + * @param array $faqs FAQ items. + * + * @return array + */ +function seo_ready_generate_faq_page_item( $faqs = array() ) { + + static $faq_page_item = array(); + + if ( empty( $faqs ) ) { + return $faq_page_item; + } + + foreach ( $faqs as $position => $details_block ) { + + $answer = ''; + $question = $details_block['innerHTML']; + $answer = $details_block['innerBlocks'][0]['innerHTML']; + + $faq_page_item[] = array( + '@type' => 'Question', + 'position' => $position + 1, + 'answerCount' => 1, + 'name' => wp_strip_all_tags( $question ), + 'acceptedAnswer' => array( + '@type' => 'Answer', + 'text' => wp_strip_all_tags( $answer ), + ), + ); + } + + return $faq_page_item; +} + /** * Generates breadcrumb list item. * @@ -745,7 +828,7 @@ function seo_ready_generate_breadcrumbs_trails( $post_id = null, $attributes = a $trails = $breadcrumbs->generate(); // Leave early if no trails are found. - if ( empty( $trails ) || count( $trails ) < 2 ) { + if ( count( $trails ) <= 1 ) { return array(); } From 6ed0065f88731490be81b4a39a3385b9f7ac26f5 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Wed, 28 Aug 2024 23:19:21 +0300 Subject: [PATCH 6/7] feat: add heading support --- assets/js/faq.js | 82 +++++++++++++++++++++++++++++++++++---- assets/js/minified/faq.js | 2 +- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/assets/js/faq.js b/assets/js/faq.js index 028ca5f..7bd777e 100644 --- a/assets/js/faq.js +++ b/assets/js/faq.js @@ -9,8 +9,9 @@ const { times, noop } = lodash; const { createElement: el } = wp.element; const { registerBlockType } = wp.blocks; - const { ButtonBlockAppender, useBlockProps, useInnerBlocksProps } = wp.blockEditor; + const { ButtonBlockAppender, InspectorControls, RichText, useBlockProps, useInnerBlocksProps } = wp.blockEditor; const { useSelect } = wp.data; + const { SelectControl } = wp.components; const { __ } = wp.i18n; registerBlockType( 'seo-ready/faq', { @@ -19,12 +20,27 @@ description: __( 'This block displays a list of frequently asked questions.', 'seo-ready' ), keywords: [ 'faq', 'question', 'answer' ], icon: 'editor-help', - attributes: {}, + attributes: { + tagName: { + type: 'string', + default: 'h2', + selector: 'summary', + }, + heading: { + type: 'string', + selector: 'heading', + }, + }, category: 'design', supports: { align: [ 'full', 'wide' ], multiple: false, html: false, + color: { + background: true, + text: true, + link: false, + }, layout: { allowSwitching: false, allowInheriting: false, @@ -35,8 +51,13 @@ flexDirection: 'row', }, }, + spacing: { + margin: [ 'top', 'bottom' ], + padding: true, + }, }, - edit: ( { clientId } ) => { + edit: ( { attributes, clientId, setAttributes } ) => { + const { heading, tagName } = attributes; const isSelectedBlockInRoot = useSelect( ( select ) => { const { isBlockSelected, hasSelectedInnerBlock } = select( 'core/block-editor' ); @@ -45,7 +66,7 @@ }, [ clientId ] ); - const blockProps = useBlockProps( { className: 'is-layout-constrained' } ); + const blockProps = useBlockProps( { className: 'is-layout-flow' } ); const { children } = useInnerBlocksProps( {}, { @@ -53,21 +74,66 @@ renderAppender: noop, template: times( 2, () => [ 'core/details', {} ] ), templateInsertUpdatesSelection: true, + __experimentalCaptureToolbars: true, } ); return el( 'div', blockProps, + ( isSelectedBlockInRoot || heading ) && + el( + 'div', + { className: 'wp-block-seo-ready-faq__heading' }, + el( RichText, { + identifier: 'heading', + 'aria-label': __( 'Write heading', 'seo-ready' ), + placeholder: __( 'Write heading…', 'seo-ready' ), + allowedFormats: [], + withoutInteractiveFormatting: true, + tagName, + value: heading, + onChange: ( newHeading ) => setAttributes( { heading: newHeading } ), + } ) + ), children, - isSelectedBlockInRoot && el( ButtonBlockAppender, { rootClientId: clientId } ) + isSelectedBlockInRoot && el( ButtonBlockAppender, { rootClientId: clientId } ), + el( + InspectorControls, + { group: 'advanced' }, + el( SelectControl, { + __nextHasNoMarginBottom: true, + __next40pxDefaultSize: true, + label: __( 'Heading tag', 'seo-ready' ), + help: __( 'Select the heading tag for the FAQ block.', 'seo-ready' ), + options: [ + { label: 'p', value: 'p' }, + { label: 'H2', value: 'h2' }, + { label: 'H3', value: 'h3' }, + { label: 'H4', value: 'h4' }, + ], + value: tagName, + onChange: ( newTagName ) => setAttributes( { tagName: newTagName } ), + } ) + ) ); }, - save: () => { - const blockProps = useBlockProps.save( { id: 'faq', className: 'is-layout-constrained' } ); + save: ( { attributes } ) => { + const { heading, tagName } = attributes; + const blockProps = useBlockProps.save( { id: 'faq', className: 'is-layout-flow' } ); const { children } = useInnerBlocksProps.save(); - return el( 'div', blockProps, children ); + return el( + 'div', + blockProps, + heading && + el( + 'div', + { className: 'wp-block-seo-ready-faq__heading' }, + el( RichText.Content, { tagName, value: heading } ) + ), + children + ); }, } ); } )( window.wp, window.lodash ); diff --git a/assets/js/minified/faq.js b/assets/js/minified/faq.js index 4012c2e..4c2e610 100644 --- a/assets/js/minified/faq.js +++ b/assets/js/minified/faq.js @@ -1 +1 @@ -"use strict";(function(wp,lodash){"use strict";if(!wp){return}var times=lodash.times,noop=lodash.noop;var el=wp.element.createElement;var registerBlockType=wp.blocks.registerBlockType;var _wp$blockEditor=wp.blockEditor,ButtonBlockAppender=_wp$blockEditor.ButtonBlockAppender,useBlockProps=_wp$blockEditor.useBlockProps,useInnerBlocksProps=_wp$blockEditor.useInnerBlocksProps;var useSelect=wp.data.useSelect;var __=wp.i18n.__;registerBlockType("seo-ready/faq",{apiVersion:2,title:__("FAQ","seo-ready"),description:__("This block displays a list of frequently asked questions.","seo-ready"),keywords:["faq","question","answer"],icon:"editor-help",attributes:{},category:"design",supports:{align:["full","wide"],multiple:false,html:false,layout:{allowSwitching:false,allowInheriting:false,allowEditing:false,"default":{type:"flex",flexWrap:"nowrap",flexDirection:"row"}}},edit:function edit(_ref){var clientId=_ref.clientId;var isSelectedBlockInRoot=useSelect(function(select){var _select=select("core/block-editor"),isBlockSelected=_select.isBlockSelected,hasSelectedInnerBlock=_select.hasSelectedInnerBlock;return isBlockSelected(clientId)||hasSelectedInnerBlock(clientId,true)},[clientId]);var blockProps=useBlockProps({className:"is-layout-constrained"});var _useInnerBlocksProps=useInnerBlocksProps({},{allowedBlocks:["core/details"],renderAppender:noop,template:times(2,function(){return["core/details",{}]}),templateInsertUpdatesSelection:true}),children=_useInnerBlocksProps.children;return el("div",blockProps,children,isSelectedBlockInRoot&&el(ButtonBlockAppender,{rootClientId:clientId}))},save:function save(){var blockProps=useBlockProps.save({id:"faq",className:"is-layout-constrained"});var _useInnerBlocksProps$=useInnerBlocksProps.save(),children=_useInnerBlocksProps$.children;return el("div",blockProps,children)}})})(window.wp,window.lodash); \ No newline at end of file +"use strict";(function(wp,lodash){"use strict";if(!wp){return}var times=lodash.times,noop=lodash.noop;var el=wp.element.createElement;var registerBlockType=wp.blocks.registerBlockType;var _wp$blockEditor=wp.blockEditor,ButtonBlockAppender=_wp$blockEditor.ButtonBlockAppender,InspectorControls=_wp$blockEditor.InspectorControls,RichText=_wp$blockEditor.RichText,useBlockProps=_wp$blockEditor.useBlockProps,useInnerBlocksProps=_wp$blockEditor.useInnerBlocksProps;var useSelect=wp.data.useSelect;var SelectControl=wp.components.SelectControl;var __=wp.i18n.__;registerBlockType("seo-ready/faq",{apiVersion:2,title:__("FAQ","seo-ready"),description:__("This block displays a list of frequently asked questions.","seo-ready"),keywords:["faq","question","answer"],icon:"editor-help",attributes:{tagName:{type:"string","default":"h2",selector:"summary"},heading:{type:"string",selector:"heading"}},category:"design",supports:{align:["full","wide"],multiple:false,html:false,color:{background:true,text:true,link:false},layout:{allowSwitching:false,allowInheriting:false,allowEditing:false,"default":{type:"flex",flexWrap:"nowrap",flexDirection:"row"}},spacing:{margin:["top","bottom"],padding:true}},edit:function edit(_ref){var attributes=_ref.attributes,clientId=_ref.clientId,setAttributes=_ref.setAttributes;var heading=attributes.heading,tagName=attributes.tagName;var isSelectedBlockInRoot=useSelect(function(select){var _select=select("core/block-editor"),isBlockSelected=_select.isBlockSelected,hasSelectedInnerBlock=_select.hasSelectedInnerBlock;return isBlockSelected(clientId)||hasSelectedInnerBlock(clientId,true)},[clientId]);var blockProps=useBlockProps({className:"is-layout-flow"});var _useInnerBlocksProps=useInnerBlocksProps({},{allowedBlocks:["core/details"],renderAppender:noop,template:times(2,function(){return["core/details",{}]}),templateInsertUpdatesSelection:true,__experimentalCaptureToolbars:true}),children=_useInnerBlocksProps.children;return el("div",blockProps,(isSelectedBlockInRoot||heading)&&el("div",{className:"wp-block-seo-ready-faq__heading"},el(RichText,{identifier:"heading","aria-label":__("Write heading","seo-ready"),placeholder:__("Write heading\u2026","seo-ready"),allowedFormats:[],withoutInteractiveFormatting:true,tagName:tagName,value:heading,onChange:function onChange(newHeading){return setAttributes({heading:newHeading})}})),children,isSelectedBlockInRoot&&el(ButtonBlockAppender,{rootClientId:clientId}),el(InspectorControls,{group:"advanced"},el(SelectControl,{__nextHasNoMarginBottom:true,__next40pxDefaultSize:true,label:__("Heading tag","seo-ready"),help:__("Select the heading tag for the FAQ block.","seo-ready"),options:[{label:"p",value:"p"},{label:"H2",value:"h2"},{label:"H3",value:"h3"},{label:"H4",value:"h4"}],value:tagName,onChange:function onChange(newTagName){return setAttributes({tagName:newTagName})}})))},save:function save(_ref2){var attributes=_ref2.attributes;var heading=attributes.heading,tagName=attributes.tagName;var blockProps=useBlockProps.save({id:"faq",className:"is-layout-flow"});var _useInnerBlocksProps$=useInnerBlocksProps.save(),children=_useInnerBlocksProps$.children;return el("div",blockProps,heading&&el("div",{className:"wp-block-seo-ready-faq__heading"},el(RichText.Content,{tagName:tagName,value:heading})),children)}})})(window.wp,window.lodash); \ No newline at end of file From 9718d81db6a10fca19d2511fc21e58f7eb7d2380 Mon Sep 17 00:00:00 2001 From: Mahdi Yazdani Date: Thu, 29 Aug 2024 17:15:02 +0300 Subject: [PATCH 7/7] fix: reset graph key indexes --- seo-ready.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/seo-ready.php b/seo-ready.php index 37a2fcb..0fa9e5d 100644 --- a/seo-ready.php +++ b/seo-ready.php @@ -477,7 +477,7 @@ function seo_ready_get_schema_json_ld( $schema_types = array( 'WebPage' ), $has_ 'inLanguage' => $language, 'isPartOf' => array( '@id' => path_join( $blog_url, '#website' ) ), 'breadcrumb' => array( '@id' => path_join( $current_url, '#breadcrumb' ) ), - ) : null; + ) : array(); // BreadcrumbList schema type. $breadcrumb_list = array( @@ -534,13 +534,15 @@ function seo_ready_get_schema_json_ld( $schema_types = array( 'WebPage' ), $has_ // Final schema graph. $graph = array( '@context' => 'https://schema.org', - '@graph' => array_filter( - array( - $webpage_itempage, - $faq_list, - $breadcrumb_list, - $website, - $person, + '@graph' => array_values( // Make sure the array is indexed. + array_filter( // Remove empty values. + array( + $webpage_itempage, + $faq_list, + $breadcrumb_list, + $website, + $person, + ) ) ), );