記事内のカスタムフィールドラベルからナビゲーションを作成するWordPressプラグインを作った話

## どんなプラグインなのか

記事内のカスタムフィールドラベルからアンカーリンクナビゲーションを作成するプラグインで、クリックするとクリックしたラベルの位置までスクロールします。また、ラベル位置まで達するとラベルがハイライトアニメーションします。
基本的には投稿タイプ毎にナビゲーションの表示・非表示を設定できる。また、ID指定で記事毎にナビゲーションを非表示にすることもできます。
WordPress4.5.X〜に対応しており、Gutenbergエディタ、Classic Editorプラグイン使用時でも動作し、日本語、英語に対応しています。

[Custom Fields List Generator](https://ja.wordpress.org/plugins/custom-fields-list-generator/)


### 動作環境
* PHP5.6以降
* WordPress4.5.X〜

### 主な使用技術
* jQuery
* React

### UI

UIが異なるのは各エディタでのJSの効き方、エディタの仕様に違いがあったためです。
Gutenbergエディタではサイドバーにプラグインを追加する仕組みがあったため、それを使用して実装しました。
クラシックエディタでは画面右下部にナビゲーションを配置し、クリックで開けるようになっています。
いずれもナビゲーションは固定で表示されます。

* Gutenberg（5系）
![screenshot-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371733/4b0fb78f-6a42-0132-6d1a-21bb0bdc7d26.png)

* Classic Editor（5系未満、またはClassic Editorプラグイン使用時）
![screenshot-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371733/bcf162b7-cd70-d4b7-b735-e1719325084d.png)

* 設定画面
![screenshot-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371733/debb7076-7308-1c64-c158-ea0beb27c101.png)


## なぜ作ったのか

WordPressで構築したWebサイトではカスタムフィールドを使うことが多く、Webサイトを運用していくにつれてカスタムフィールドの数が増え、投稿画面が煩雑になり、編集項目を探すのに時間がかかると感じたことがきっかけです。
投稿画面上のカスタムフィールドを一覧でき、アンカーリンクでその位置まで飛べるようなプラグインがあってもいいのでは？と思い、作成しました。


## どのように作ったのか

WordPressプラグインではありますが、機能自体はJS実装がメインです。
先にも述べましたが、各エディタでのJSの効き方、エディタの仕様に違いがあったので条件分岐をして読み込むJSを分けました。
下記コードのようにGutenbergエディタが使われている５系以下またはClassic Editorプラグインが使用されているかで読み込むJSを分岐しています。

### cflg.php（抜粋）

```
if ( version_compare( $wp_version, '5', '<=' ) || cflg_plugin_active_check('classic-editor.php') ) {
	// WordPress５系以下、またはClassic Editorプラグインを使用時
} else {
	// WordPress５系以上でGutenbergエディタを使用時
}
```

GutenbergエディタではReactでサイドバーにプラグインを追加する仕組みがあったため、その仕組みを使用しました。
また、DOM操作を行なうために@wordpress/dom-readyを読み込みました。ソースコードは下記のようになりました。

* [@wordpress/dom-ready](https://developer.wordpress.org/block-editor/packages/packages-dom-ready/)
* [@wordpress/plugins](https://developer.wordpress.org/block-editor/packages/packages-plugins/)

### index.js

```
import domReady from '@wordpress/dom-ready';

const { Fragment } = wp.element;
const registerPlugin = wp.plugins.registerPlugin;
const { PluginSidebar, PluginSidebarMoreMenuItem } = wp.editPost;
const { __ } = wp.i18n;

let texts = [];

// Judge lang attribute
const lang = $('html').attr('lang');
const langsEn = lang.match(/^en/gi);
let topOfPageText = '';

if (lang === 'ja') {
	topOfPageText = 'ページの先頭に戻る';
} else if ((lang === 'en') || ((langsEn !== null) && (langsEn.indexOf('en') >= 0))) {
	topOfPageText = 'Back to Top';
} else {
	topOfPageText = 'Back to Top';
}

domReady( function() {
	$('.editor-post-title').attr('id', 'editor-post-title');
	$('.hndle').each(function(i) {
		if ($(this).css('display') == 'none') {
			$(this).next('.inside').find('label').attr('id', 'cflg' + i);
			let text = $(this).next('.inside').find('label').text();
			texts.push(text);
		} else {
			if ($(this).parents('.postbox').css('display') == 'none') {
				texts.push('');
			} else {
				$(this).attr('id', 'cflg' + i);
				let text = $(this).text();
				texts.push(text);
			}
		}
	});

	registerPlugin( 'my-plugin', {
		render: () => {
			return (
				<Fragment>
					<PluginSidebarMoreMenuItem
						target='cflg'
						icon='editor-ul'
					>
						{ __( 'Custom Fields List Generator' ) }
					</PluginSidebarMoreMenuItem>
					<PluginSidebar
						name='cflg'
						icon='editor-ul'
						title='Custom Fields List Generator'
					>
						<div id="cflg">
							<ul>
								<li id="cflg-top"><a href="#editor-post-title" className="cflg-top-anchor"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>{topOfPageText}</a></li>
								{texts.map((text, index) => {
									if (text !== '') {
										return (
											<li>
												- <a href={'#cflg' + index}>{text}</a>
											</li>
										)
									}
								})}
							</ul>
						</div>
					</PluginSidebar>
				</Fragment>
			);
		},
	});
	$(document).on('click', '#cflg ul li:not(#cflg-top) a', function() {
		$($(this).attr('href')).not('#editor-post-title').addClass('cflg-highlight');
		setTimeout(function() {
			$($(this).attr('href')).removeClass('cflg-highlight');
		}.bind($(this)), 2400);
		if ($($(this).attr('href')).prev('button').attr('aria-expanded') === 'false') {
			$($(this).attr('href')).prev('button').attr('aria-expanded', true);
			$($(this).attr('href')).parents('.postbox').removeClass('closed');
		}
	});
});

```

# まとめ

特に難しいことはしていないのですが、制作の過程でGutenbergエディタ内でJSがうまく効かなかったことに苦しんだり、サイドバーにプラグインを追加する仕組みを理解するのに時間がかかりました。
今回、初めてのWordPressのプラグインを作成するにあたり、作り方や申請方法、更新方法などを知ることができてとても良かったです。

是非とも使ってください。


[Custom Fields List Generator](https://ja.wordpress.org/plugins/custom-fields-list-generator/)