WordPressでトップページ以外のサイトタイトルブロックのタグを<div>に変更する

WordPressでは、サイトのタイトルブロック(core/site-title)を挿入すると設定ページで保存したサイト名を取得し表示できるため、一括管理に役立ちます。しかし、このブロックは全ページで<h1>タグでレンダリングしてしまうため、トップページ以外では<div>でレンダリングするカスタムブロックを作成しました。その手順を紹介します。

ブロックの雛形を用意

Localやwp-envなどでローカルにWordPressを構築します。次に、/wp-content/plugins/に移動し、コマンドプロンプトを起動します。下記のコマンドを実行します。

npx @wordpress/create-block my-dynamic-block --variant dynamic --namespace my-plugin

コマンドの意味それぞれ次の意味があります。

  • npx:Node.jsのコマンドで、一時的にパッケージをインストールしてすぐ実行できるようにする
  • @wordpress/create-block:npxでインストールする対象。WordPress ブロックプラグインのひな型を生成する
  • my-dynamic-block:ブロック名になる
  • –variant dynamic:動的ブロックの雛形を生成する
  • –namespace my-plugin:名前空間を指定する

インストールが完了したら、プラグインのルートディレクトリ名を「my-plugin」へ変更する。

// Windows コマンドプロンプト
move my-dynamic-block my-plugin

プラグインディレクトリに移動する

cd my-dynamic-block

npmを起動する

npm start

プラグインのディレクトリ構成を調整する

今回のブロックには不要となるファイルを削除すると、構成は下記になります。

  • my-dynamic-block
    • build
      • my-dynamic-block
        • block.json
        • index.asset.php
        • index.js
        • index.js.map
        • render.php
      • blocks-manifest.php
    • src
      • my-dynamic-block
        • block.json
        • edit.js
        • index.js
        • render.php
    • my-dynamic-block.php
    • node_modules
    • package-lock.json
    • package.json
    • .editorconfig
    • .gitignore
    • readme.txt

src/edit.js

edit.jsを編集し、編集画面を作成します。ポイントはサイト情報はWordPressのデータストアから取得する点です。

useSelect にstoreにアクセスするためのselect関数を渡して、その関数の中でselectを使ってcoreストアにアクセスし、’root’ の ‘site’ エンティティを取得します。

import { useBlockProps } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';

export default function Edit() {
	const blockPlops = useBlockProps();
	const siteInfo = useSelect( ( select ) =>
		select( 'core' ).getEntityRecord( 'root', 'site' )
	);
	if ( ! siteInfo ) {
		return <div>読み込み中</div>;
	}

	return (
		<h1 {...blockPlops}>
			<a
				href="#site-title-dammy-link"
				role="textbox"
				aria-multiline="false"
				aria-label="サイトタイトルのテキスト"
				contentEditable={false} // ← contenteditable="false"
				style={{ whiteSpace: "pre-wrap", minWidth: "1px" }}
				className="site-title-link"
			>
				{siteInfo.title}
			</a>
		</h1>
	);
}

// useSelectは以下の意味
useSelect(function(select) {
  return select('core').getEntityRecord('root', 'site');
});
  • useSelect:WordPressのストアから データを取得するフック
  • select( ‘core’ ): ‘core’は投稿、ページ、メディア、ユーザー、サイト設定などの情報が格納されたストア名
  • getEntityRecord( ‘root’, ‘site’ ):
    • getEntityRecord :エンティティ(投稿・ユーザー・サイトなど)を取得するメソッド
    • ‘root’:取得先のエンティティの種類。トップレベルのエンティティを指定する
    • ‘site’:取得したいデータの名前。サイト自体を指定する

edit.jsではテンプレートの識別ができないため、<h1>でレンダリングします。

src/render.php

フロントエンドの表示を組み立てていきます。ここで<h1>を<div>に変換する処理を書きます。出力されるHTMLコードは<h1>以外、既存から変更されないように属性やリンクを設定します。

$wrapper_attributes = get_block_wrapper_attributes();

$site_title = get_bloginfo('name');
$home_url = esc_url(home_url());

// フロントページなら <h1>、それ以外は <div>
if (is_front_page()) {
	$link = sprintf(
		'<a href="%s" target="_self" rel="home" aria-current="page">%s</a>',
		$home_url,
		esc_html($site_title)
	);

	echo sprintf(
		'<h1 %s>%s</h1>',
		$wrapper_attributes,
		$link
	);
} else {
	$link = sprintf(
		'<a href="%s" target="_self" rel="home">%s</a>',
		$home_url,
		esc_html($site_title)
	);

	echo sprintf(
		'<div %s>%s</div>',
		$wrapper_attributes,
		$link
	);
}

block.json

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "my-plugin/my-dynamic-block",
	"version": "0.1.0",
	"title": "My Dynamic Block",
	"category": "theme",
	"icon": "admin-site",
	"description": "Example block scaffolded with Create Block tool.",
	"keywords": [ "サイト", "タイトル", "Site Title" ],
	"example": {},
	"supports": {
		"color": {
			"background": true,
			"text": true,
			"link": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true
		},
		"align": true,
		"anchor": true,
		"multiple": false
	},
	"textdomain": "my-dynamic-block",
	"editorScript": "file:./index.js",
	"render": "file:./render.php"
}

index.js

import { registerBlockType } from '@wordpress/blocks';

import Edit from './edit';
import metadata from './block.json';

registerBlockType( metadata.name, {
	edit: Edit,
} );

フロントエンドのHTML

トップページの場合

<h1 class="has-link-color wp-block-site-title has-x-large-font-size">
    <a href="http://myblob.com" target="_self" rel="home" aria-current="page">MyBlog</a>
</h1>

それ以外の場合

<h1 class="has-link-color wp-block-site-title has-x-large-font-size">
    <a href="http://convert.com" target="_self" rel="home">MyBlog</a>
</h1>

ブロックが完成しました。

サイトタイトルタグと互換性をもたせる

サイトタイトルのタグと互換性を持たせるため、追加設定を行います。

index.jsonに「transforms」を追記します。

import { registerBlockType } from '@wordpress/blocks';

import Edit from './edit';
import metadata from './block.json';
import transformers from './transforms';

registerBlockType( metadata.name, {
	edit: Edit,
	transforms: transformers,
} );

src/transforms.jsを作成します。

import { createBlock } from '@wordpress/blocks';

const transformers = {
	to: [
		{
			type: 'block',
			blocks: [ 'core/site-title' ],
			transform: () => {
				return createBlock( 'core/site-title' );
			},
		},
	],
	from: [
		{
			type: 'block',
			blocks: [ 'core/site-title' ],
			transform: () => {
				return createBlock( 'my-plugin/my-dynamic-block' );
			},
		},
	],
};
export default transformers;

ブロックツールバーのボタンにより、作成したブロックとサイトタイトルのタグが相互五感を持つようになりました。

サイトロゴブロックをトップページでは<h1>でレンダリングする

変更前

<p class="wp-block-site-title">
    <a
        href="http://bdev.com"
        target="_self"
        rel="home"
        aria-current="page">
        bdev
    </a>
</p>

変更後はh1タグがpタグになります。

<h1 class="wp-block-site-title">
    <a
        href="http://bdev.com"
        target="_self"
        rel="home"
        aria-current="page">
        bdev
    </a>
</h1>

php編集


/****************************
Topページのサイトタイトルのタグを<h1>に変更する
 *****************************/
function my_change_h1_coresitetitle($block_content, $block) {
    // トップページ以外ではそのまま返す
    if (! is_front_page()) {
        return $block_content;
    }

    // 対象ブロックが "core/site-title" である場合のみ処理
    if ('core/site-title' !== $block['blockName']) {
        return $block_content;
    }

    // <p>タグを削除し、<h1>で囲んで返す
    $tag_to_remove = ['<p class="wp-block-site-title">', '</p>'];
    $content_without_p = str_replace($tag_to_remove, '', $block_content);

    return sprintf(
        '<h1 class="wp-block-site-title">%s</h1>',
        $content_without_p
    );
}
add_filter('render_block_core/site-title', 'my_change_h1_coresitetitle', 10, 2);

1.サイトタイトルブロックのみ$block_contentに入る

$block_contentをvar_dumpすると次のコードを取得できる。

// ヘッダーのサイトタイトル
<p class="wp-block-site-title">
    <a href="http://bdev.com" target="_self" rel="home" aria-current="page">bdev</a>
</p>
// フッターのサイトタイトル
<h2 class="wp-block-site-title">
    <a href="http://bdev.com" target="_self" rel="home" aria-current="page">bdev</a>
</h2>

2. pタグの削除

$content_without_p = str_replace($tag_to_remove, '', $block_content);

$block_contentで渡ってきたHTMLコードの中から、<p class=”wp-block-site-title”>を探し削除します。続けて、$block_contentで渡ってきたHTMLコードの中から、</p>を探し削除します。

その結果、$content_without_pには<a>~</a>が残ります。

3.h1タグの挿入

return sprintf(
'<h1 class="wp-block-site-title">%s</h1>',
    $content_without_p
);

サイトタイトルのタグにしたいh1をsprintfの第一引数に渡し、%sに$content_without_pを当てはめます。その結果、<h1>タグで囲うことができました。

<h1 class="wp-block-site-title">
    <a href="http://bdev.com" target="_self" rel="home" aria-current="page">bdev</a>
</h1>