Block Bindings APIもうすこし遊んでみた

前回、カスタムフィールドと紐づけして表示してみたBlock Bindings APIですが、ヒントをもらったのでもう少し遊んでみました。

なるほど!!!と思ってシェアボタン作ってみました。

https://github.com/chiilog/sns-share-block

今回は既存のボタンブロックをカスタマイズしてボタンブロックを作るので、phpのみで完結。

まずは、ボタンブロックにbindingを入れていきます。

<!-- wp:buttons {"style":{"spacing":{"blockGap":"var:preset|spacing|30"}}} -->
<div class="wp-block-buttons"><!-- wp:button {"metadata":{"bindings":{"url":{"source":"chiilog/share-button","args":{"key":"x"}}}}} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">X</a></div>
<!-- /wp:button -->

<!-- wp:button {"metadata":{"bindings":{"url":{"source":"chiilog/share-button","args":{"key":"facebook"}}}}} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Facebook</a></div>
<!-- /wp:button -->

<!-- wp:button {"metadata":{"bindings":{"url":{"source":"chiilog/share-button","args":{"key":"line"}}}}} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">LINE</a></div>
<!-- /wp:button -->

<!-- wp:button {"metadata":{"bindings":{"url":{"source":"chiilog/share-button","args":{"key":"hatena"}}}}} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">はてな</a></div>
<!-- /wp:button -->

<!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="#">ただのボタン</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons -->

metadata.bindings は固定です。

<!-- wp:button {"bindings":{"url":{"source":"chiilog/share-button","args":{"key":"facebook"}}}} -->

とか書いても動かないので気をつけましょう。(やった)

ちなみに↑の書き方、JSONのエラーですとか返してくれるわけでもなく、背景とかつけたりすると値が消えます。

これだけでブロック側は準備OK。では、PHPを書いていきます。

add_action( 'init', 'chiilog_register_block_bindings' );

function chiilog_register_block_bindings() {
	register_block_bindings_source( 'chiilog/share-button', array(
		'label'              => __( 'SNS', 'chiilog-share-button' ),
		'get_value_callback' => 'chiilog_sns_data_bindings',
		'uses_context'       => [ 'postId' ]
	) );
}

まずは、register_block_bindings_sourceを使ってソースを登録します。

これで、前回使ったカスタムフィールドのようにソースとして扱うことができます。

今回は投稿IDを元にページURLをとりたいので、 uses_contextpostIdを指定しています。

次はコールバック関数を用意します。実際にシェア用のURLをバインディングするやつです。

/**
 * SNSのシェアリンクを返す
 *
 * @param array $source_args
 * @param WP_Block $block_instance
 *
 * @return string|null
 */
function chiilog_sns_data_bindings( $source_args, WP_Block $block_instance ) {
	$current_post_id = $block_instance->context['postId'];

	// キーがない場合はなにもしない
	if ( ! isset( $source_args['key'] ) ) {
		return null;
	}

	switch ( $source_args['key'] ) {
		case 'x':
			return 'https://twitter.com/intent/tweet?url=' . esc_url( get_permalink( $current_post_id ) ) . '&text=' . esc_attr( get_the_title( $current_post_id ) );
		case 'facebook':
			return 'https://www.facebook.com/sharer/sharer.php?u=' . esc_url( get_permalink( $current_post_id ) );
		case 'line':
			return 'https://social-plugins.line.me/lineit/share?url=' . esc_url( get_permalink( $current_post_id ) ) . '&text=' . esc_attr( get_the_title( $current_post_id ) );
		default:
			return null;
	}
}

なんということでしょう。swich文で記述するだけで、ボタンタグ自身のhrefに挿入されることが確認できたと思います。

bindingsを使っていないブロックはリンク先が入力できますが、bindings.url を設定したボタンはリンク先が入力できなくなっています。

リンク先の入力欄がない

さて、リンク先の入力欄がないということはリンクターゲットの設定ができません。同じくbindingsでやってみようかと思いましたが、urlとlinkTargetなど2つ地使うことはできないのか、うまくいきませんでした。私の書き方がまずかったとか色々説はあると思いますが、できるのなら私も見たいのでぜひ書き方教えてほしいです。

追記

浜野さんに書き方教えてもらいました!!!!

<!-- wp:buttons {"style":{"spacing":{"blockGap":"var:preset|spacing|30"}}} -->
<div class="wp-block-buttons"><!-- wp:button {"metadata":{"bindings":{"url":{"source":"chiilog/share-button-link","args":{"key":"x"}},"linkTarget":{"source":"chiilog/share-button-target"}}}} -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">X</a></div>
<!-- /wp:button -->
...
</div>
<!-- /wp:buttons -->

urlに対してはchiilog/share-button-linkを割り当て、linkTargetに対してはchiilog/share-button-targetを割り当てるという感じです。

ひとつの属性に対してひとつのsourceを使う、って覚え方でよさそうかな。

あとはPHPを変更。

add_action( 'init', 'chiilog_register_block_bindings' );

function chiilog_register_block_bindings() {
	register_block_bindings_source( 'chiilog/share-button-link', array(
		'label'              => __( 'SNS URL', 'chiilog/share-button' ),
		'get_value_callback' => 'chiilog_sns_data_bindings',
		'uses_context'       => [ 'postId' ]
	) );

	register_block_bindings_source( 'chiilog/share-button-target', array(
		'label'              => __( 'Link Target', 'chiilog/share-button' ),
		'get_value_callback' => function () {
			return '_blank';
		}
	) );
}

今回は絶対_blankなのでこうなりましたが、argsで変えたいときはget_value_callbackに関数名を指定すればOK。

この方がWP_HTML_Tag_Processor使うよりもスッキリ簡潔に書けますね!!!!

一応下にWP_HTML_Tag_Processor版残しておきますが、書くならregister_block_bindings_sourceを使って書くと思います。


シェアボタンに関しては常にリンクターゲットは_blankにしたいので、ここはWP_HTML_Tag_Processorの出番です。

/**
 * シェアボタンの場合、ボタンのlinkTargetを_blankに変換する
 *
 * @param string $block_content
 * @param WP_Block $block
 *
 * @return string
 */
add_filter( 'render_block_core/button', 'add_link_target_for_binding_button', 10, 2 );

function add_link_target_for_binding_button( $block_content, $block ) {
	$processor = new WP_HTML_Tag_Processor( $block_content );

	if ( isset( $block['attrs']['metadata']['bindings']['url']['source'] ) ) {
		$binding_source = $block['attrs']['metadata']['bindings']['url']['source'];
		if ( $binding_source === 'chiilog/share-button' ) {
			$processor->next_tag( array( 'class_name' => 'wp-block-button__link' ) );
			$processor->set_attribute( 'target', '_blank' );
		}
	}

	return $processor->get_updated_html();
}

Block Bindings APIを使ってるものに限りリンクターゲットを追加しています。

この分岐を入れておけば、bindingsを使っていないボタンは管理画面上でリンクターゲットの設定が可能というわけです。

まとめ

外部ソースってどう使うんだろうな、とピンときてなかったのが、これを作ってみてより身近に感じれるようになりました。シェアボタンがこんな簡単にできるのはえらいこっちゃです。

とはいえ、metadata.bindingsが複雑になるとコードエディターで書きづらそうだなあというのは感じました。改行とか入れても一回ビジュアルエディターにすると1行でギュッとされてしまうので、あとから追記を試すときにちょっと大変でした。

コードエディターで入力する前に一旦見やすいのをローカルに置いといたほうがいいかもしれません。