Я думаю, что нашел способ обойти это с помощью wp.hooks.addFilter на RichText
Вот мое решение
блок. js
import {registerBlockType} from '@wordpress/blocks';
import apiFetch from '@wordpress/api-fetch';
import ServerSideRender from '@wordpress/server-side-render';
import {Disabled} from '@wordpress/components';
import {PanelBody, ToggleControl} from '@wordpress/components';
import {InspectorControls, PlainText, RichText} from '@wordpress/block-editor';
import {withState} from '@wordpress/compose';
import {addFilter} from '@wordpress/hooks';
registerBlockType('acmarche-block/bottin', {
title: 'Bottin',
description: 'Insérer une fiche ou une rubrique du bottin',
placeholder: 'Indiquer id',
icon: 'store',
category: 'widgets',
supports: {
align: true,
html: false,
},
example: {
attributes: {
id: '12345',
},
},
edit: function ({className, setAttributes, attributes}) {
const bottinCompleter = {
name: 'acbottin',
triggerPrefix: '::',
options(search) {
if (search) {
return apiFetch({
path: 'acmarche/bottin/' + search
});
}
return [];
},
isDebounced: true,
getOptionLabel(fiche) {
return <span>{fiche.slug} <small>{fiche.id}</small></span>;
},
// Declares that options should be matched by their name
getOptionKeywords: fiche => [fiche.slug, fiche.id],
// completions should be removed, but then spawn setPost
getOptionCompletion(fiche) {
return {
action: 'replace',
value: updateAttributesId(fiche.id),
};
},
};
// Our filter function
function appendBottinCompleter(completers, blockName) {
return blockName === 'acmarche-block/bottin' ?
[...completers, bottinCompleter] :
completers;
}
addFilter(
'editor.Autocomplete.completers',
'acbottin/autocompleters-bottin',
appendBottinCompleter
);
const {ShowFull} = attributes;
const updateAttributesId = (newContent) => {
const blockSelected = wp.data.select('core/block-editor').getSelectedBlock();
console.log(blockSelected);
// blockSelected.attributes.id = newContent.toString(); //not refresh block
setAttributes({id: newContent.toString()});//refresh block, bug with several times the same block
};
let blockContent = 'Indiquez le nom de la fiche';
console.log('ici');
if (parseInt(attributes.id) > 0) {
blockContent = <ServerSideRender
block="acmarche-block/bottin"
attributes={attributes}
/>;
}
const FullFicheToggleControl = withState({
isFullDisplay: ShowFull,
})(({isFullDisplay, setState}) => (
<ToggleControl
label="Afficher la fiche complète"
help={isFullDisplay ? 'Has fixed background.' : 'No fixed background.'}
checked={isFullDisplay}
onChange={value => {
console.log(value);
setAttributes({showFull: value});
setState({isFullDisplay: value});
}}
/>
));
return (<>
<InspectorControls>
<PanelBody title={'Paramètres de la fiche'}>
<FullFicheToggleControl/>
</PanelBody>
</InspectorControls>
<RichText
tagName="p"
placeholder="Modifier"
withoutInteractiveFormatting
onChange={(value) => {
}}
aria-autocomplete="list"
/>
<Disabled>
{blockContent}
</Disabled>
</>
)
},
});
Для автоматического завершения я должен был добавить API отдыха
myplugin. php
<?php
function register_block_bottin() {
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/block.asset.php' );
// Register block styles for both frontend + backend.
wp_register_style(
'bottin-block-style-css', // Handle.
plugins_url( 'bottin/src/blocks.style.build.css', dirname( __FILE__ ) ), // Block style CSS.
array( 'wp-editor' ), // Dependency to include the CSS after it.
filemtime( plugin_dir_path( __DIR__ ) . 'bottin/src/blocks.style.build.css' ) // Version: File modification time.
);
// Register block editor script for backend.
wp_register_script(
'bottin-autocompleter',
// Handle.
plugins_url( 'bottin/build/block.js', dirname( __FILE__ ) ),
// Block.build.js: We register the block here. Built with Webpack.
$asset_file['dependencies'],
$asset_file['version'],
true // Enqueue the script in the footer.
);
wp_enqueue_style( 'bottin-block-style-css' );
wp_enqueue_script( 'bottin-autocompleter' );
register_block_type( 'acmarche-block/bottin',
[
'attributes' => [
'showFull' => [
'type' => 'boolean',
'default' => false,
],
'id' => [
'type' => 'string',
],
],
'render_callback' => 'bottin_render_callback'
]
);
}
function bottin_render_callback( $attributes ) {
$id = (int) $attributes['id'];
$showFull = (bool) $attributes['showFull'];
if ( ! $id ) {
return '';
}
$render = new BottinRender();
$block_content = $render->renderFiche( $id, $showFull );//return html
return $block_content;
}
add_action( 'init', 'register_block_bottin' );
/**
* This is our callback function that embeds our phrase in a WP_REST_Response
*
* @param WP_REST_Request $request
*
* @return mixed|WP_REST_Response
*/
function rest_response_bottin( $request ) {
$search = null;
if ( isset( $request['search'] ) ) {
$search = $request['search'];
}
$elastic = new BottinElastic( 'marchebe' );
$result = $elastic->search( $search );
$hits = $result['hits'];
$total = $hits['total'];
$data = [];
$i = 0;
foreach ( $hits['hits'] as $hit ) {
$post = $hit['_source'];
$data[ $i ]['slug'] = $post['name'];
//$data[ $i ]['localite'] = $post['localite'];
$data[ $i ]['id'] = $post['id'];
$i ++;
}
return rest_ensure_response( $data );
}
/**
* This function is where we register our routes for our example endpoint.
*/
function register_rest_route_bottin() {
// register_rest_route() handles more arguments but we are going to stick to the basics for now.
register_rest_route( 'acmarche/',
'/bottin/(?P<search>.*+)',
array(
'methods' => WP_REST_Server::READABLE,
'args' => array(
'search' => array(
'validate_callback' => function ( $param, $request, $key ) {
return is_string( $param );
}
),
),
// Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
'callback' => 'rest_response_bottin',
) );
}
add_action( 'rest_api_init', 'register_rest_route_bottin' );
?>
У меня все еще есть ошибка, если в моей статье только мой блок, refre sh хорошо работает с setAttributes, но если у меня есть мой блок несколько раз, я должен выбрать текущий блок и обновить его атрибут, кроме как через setAttributes, потому что он обновляет первый найденный блок, а не тот, который записывается
blockSelected.attributes.id = newContent.toString(); //not refresh block
setAttributes({id: newContent.toString()});//refresh block but not the current block