unitoneをテキスト管理ツールにしてみた【WordPressブロックテーマ】

この記事は「Snow Monkey / unitone Advent Calendar 2022」16日目の記事です。


Snow Monkey Advent Calendar 2021から1年がたちました。
4年連続16日目を担当させていただきます( ・`ω・´)

2021年のアドベントカレンダーではSnow MonkeyでBuddyPressプラグインを導入してSNSのようなものを作成したことを書きました。

2021年より今年2022年の方がWordPressを触る時間は増えてきたように思います。

ブロックエディターも使いやすくなってきていい感じーと思ってた矢先、また新しいものがやってきました。

フルサイト編集 (FSE(Full Site Editing)))ブロックテーマ

簡単に表すと、いままで投稿や固定ページで使えるブロックをサイトのレイアウトにも使っていきましょかみたいな流れとのことです。

そんな2022年の6月に我らがキタジマの兄貴がこんなツイートをしていました。

フルサイト編集対応のテーマとか気になりすぎたので光の速さでポチりました。

何に使うか決めてなかったけど。

そんなunitoneを使って社内テキスト共有用WordPressを作ってみました。

ブロックテーマ的な機能あんまり使っていないのは秘密にしておいてくださいね!

「unitone」それはそれはシンプルで美しいWordPressテーマでした。

作りたいもの

社内でテキストのテンプレートを共有するのにいろいろなツールを使ってきました。

メモ帳に始まり、テキストファイルでの共有やWordファイル、Evernote、Googleドキュメント、Notionなどなど。

メモ帳やWordなどのファイルベースだと都度転送するのが面倒すぎました。

Webサービスだと共有は簡単にできるのですが、元のテキストを変更してしまってぐちゃぐちゃになってしまうということが頻発しました。

いい感じに共有できて元のテキストを編集しても上書きされず、簡単に管理するテキストを複製できるテキスト管理ツールを作ってしまおう!と

WordPressで作ることが最適解じゃないかもしれません。

でもとりあえず作ってみてダメだったらまた違うツールで作り直せばいいかという気持ちでプロトタイプを作ってみました。

できたものがこちら

よくあるメールテンプレートだと思います。

お客様のお名前を入力して様付けて改行するのって結構面倒くさい手間だと感じることはないでしょうか?
サービス名が複数ある場合、都度手打ちで打ち直したりしていませんでしょうか?

そんな作業を少しだけ簡単にしてくれます。

用意したもの

テーマ

unitone

WordPressをカスタマイズしたいときに悩むところが子テーマにするかプラグインにするかだと思うのですが、ブロックテーマを使うのが初めてだったのでどちらが適切かわからずSnow Monkeyにならって自前のプラグインでカスタマイズすることにしました。

あとせっかくブロックテーマ使うのだからこそファイルからのカスタマイズはなるべくしないようにしたいので、できる限り管理画面から実装できるようにしました。

昨年と同じくなるべく管理画面で実装したいという形です。

(管理画面でPHP書くとセキュリティ的によくないよという教えはもう古いのでしょうか……?
プラグインで管理画面でPHP書けるようなものもありますし、独自のショートコード作りたいだけなんです。
「別にもう気にしなくていいんじゃね?」とか「やめておいた方が無難」みたいなことあったら教えてください。)

プラグイン

社内用なので高速化プラグインやSEO的なプラグインは不要です。

Advanced Custom Fields

テキストを入力するカスタムフィールドを作る為に入れています。

My unitone

おれおれプラグインです。

上のAdvanced Custom Fieldsプラグインで作成したカスタムフィールドをショートコードにする為だけのプラグインです。

中身は後述します。

Reusable Blocks Extended

管理画面のサイドバーに再利用ブロックのリンクができるのでその為だけに導入しました。

再利用ブロックをショートコード化できたりPHPで呼び出すこともできるお気に入りのプラグインです。

プラグインや子テーマ側で再利用ブロックのリンクをサイドバーに実装したいときはこんな感じに書けばいいかもしれません_(┐「ε:)_

/**
 * 再利用ブロックへのリンクを追加 管理者のみ
 **/
function _admin_menu() {
	if ( is_admin() ) {
		add_menu_page(
			__('再利用ブロック'),
			__('再利用ブロック'),
			'manage_options',
			'edit.php?post_type=wp_block',
			'',
			'dashicons-controls-repeat',
			'81' // 「設定」 の下
		);
	}
}
add_action('admin_menu', '_admin_menu');

Simple Custom CSS and JS

今回はJavaScriptを書くことが必須だったので管理画面でJavaScriptを書けるプラグインを導入しました。

一般公開するようなWebサイトの場合はプラグインに.jsを置いて読み込みたいページだけ読み込ませるような実装をした方がいいと思います。

Pro版だと読み込みページをわけたり編集履歴の管理ができるようになるみたいです。

WP Multibyte Patch

WordPress内検索でテキスト検索をする時に全角スペースを区切り文字として認識してもらう為に導入。

日本語を扱うWordPressの場合、とりあえず入れておいていいと思います。

どんなことをしてくれるプラグインなのかわからないという方は以下リンクをご参照ください。

XO Security

サイト全体にBASIC認証かけてWeb上に公開してどこからでもアクセスできるようにはしたいので導入。

主にはログインページのURL変更の為。あと#ひらがな画像認証選手権にエントリーの為。

Yoast Duplicate Post

テキスト単位(?)で投稿にするので投稿を複製する機能は必須です。

プラグイン一覧

  • Advanced Custom Fields
  • All-in-One WP Migration
  • My unitone
  • Reusable Blocks Extended
  • Simple Custom CSS and JS
  • WP Multibyte Patch
  • XO Security
  • Yoast Duplicate Post

表示側

表示側のレイアウトはテキストinputを2つとテキストエリアが1つあるだけです。

デフォルトでサービス名のところにカテゴリ名が入るようになっています。
お客様名とサービス名を変更するとテキストエリア内のテキストがリアルタイムに変更されます。

テキストエリアをクリックするとテキストエリア内のテキストが自動的にクリップボードにコピーされてテキスト全体が選択された状態になります。

テキストエリア内のテキストはその場で変更が可能です。
変更した後は全体を選択してコピーするもよし、一度テキストエリアからフォーカスを外して再度フォーカスをあてて自動でコピーさせるもよしです。

管理画面側

投稿画面

カスタムHTMLブロックを2つ置いただけです。

ACFで本文(bodytext)というカスタムフィールドをテキストエリアで作成しています。

運用の為にグループブロックで囲んで再利用ブロック化しています。

カスタムHTMLブロックの中身はこんな感じで適当に

12月16日の記事公開後にキタジマさんからunitoneに合わせたレイアウトを教えていただきました!

神!!

<form method="post" action="">
  <div data-unitone-layout="stack -gap:1">
    <div data-unitone-layout="stack -gap:2">
      <label for="input_user_name">お客様名:</label>
      <input type="text" id="input_user_name" name="input_user_name" value="">
    </div>
    <div data-unitone-layout="stack -gap:2">
      <label for="input_service_name">サービス名:</label>
      <input type="text" id="input_service_name" name="input_service_name" value=[getthecategoryname]>
    </div>
  </div>
</form>

data属性とか意図して使ったこと無かったしちゃんとマニュアル読まないと(; ・`ω・´)

元々のフォームはこちら
<form method="post" action="">
<div class="">
  <label for="input_user_name">お客様名:</label>
</div>
<div class="">
  <input type="text" id="input_user_name" name="input_user_name" value="">
</div>
<div class="">
  <label for="input_service_name">サービス名:</label>
</div>
<div class="">
  <input type="text" id="input_service_name" name="input_service_name" value=[getthecategoryname]>
</div>
</form>

<div class="copycode">
<textarea id="input_text_area" name="input_text_area" cols="50" rows="10">[getbodytext]</textarea>
<span>コピーしました!</span>
</div>

サービス名のvalueにはカテゴリー名を取得してくる為の[getthecategoryname]というショートコードを置いています。

カスタムフィールドの本文の中身は[getbodytext]というショートコードで呼び出してきています。

カスタムフィールド本文の中身のカテゴリー名を入れたいところは{{category}}としてプラグインでカテゴリ名に置換しています。
(ここのテキストもどこかで一元管理できるようにしたいなぁ。。)

プラグイン My unitone の中身

<?php
/**
 * Plugin name: My unitone
 * Description: このプラグインに、あなたの unitone 用カスタマイズコードを書いてください。
 * Version: 0.1.0
 *
 * @package my-unitone
 * @author tbshiki
 * @license GPL-2.0+
 */

/**
 * unitone 以外のテーマを利用している場合は有効化してもカスタマイズが反映されないようにする
 */
$theme = wp_get_theme();
if ( 'unitone' !== $theme->template ) {
	return;
}

/*  おまじない  */
if ( ! defined( 'ABSPATH' ) ) exit;


/**
 * ショートコード : 1つ目のカテゴリ名を呼び出し [getthecategoryname]
 **/
function shortchord_getthecategoryname() {
	$cat = get_the_category();
	if($cat) {
		return $cat[0]->cat_name;
	}
}
add_shortcode('getthecategoryname', 'shortchord_getthecategoryname');


/**
 * ショートコード : ACFで作成したbodytext(本文)というカスタムフィールドを呼び出し [getbodytext]
 **/
function shortchord_bodytext() {
	$bodytext = get_post_meta(get_the_ID(), 'bodytext', true);
	if($bodytext) {
		$cat = get_the_category();
		$bodytext = str_replace('{{category}}', $cat[0]->cat_name, $bodytext); // カテゴリ名に置換
			
		return ($bodytext);
	}
}
add_shortcode('getbodytext', 'shortchord_bodytext');

投稿に設定しているカテゴリーを呼び出すショートコードと、ACFで作成した本文(bodytext)を呼び出して{{category}}をカテゴリ名に置換するショートコードを作成しています。これだけです。

カスタム CSS & JS の中身

Simple Custom CSS and JS プラグインでJavaScriptとCSSのコードを追加します。

いままででWebフロント的なJavaScriptって書いたことがなかったんです。

恥ずかしながらこのテキスト管理ツールで初めてちゃんとJavaScriptを書きましたw

声を大にして言いたい。

JavaScriptめっちゃ便利やんww

その時に参考にさせていただいた記事がこちらです。感謝🙏

window.addEventListener('DOMContentLoaded', function(){

	var inputCustomerName = document.getElementById("input_user_name");
 	var inputServiceName = document.getElementById("input_service_name");
	var inputTextArea = document.getElementById("input_text_area");

	var textInputTextArea = inputTextArea.value //textContent
	
	var customerName = inputCustomerName.value;

	var serviceName = inputServiceName.value;
	var beforeServiceName = inputServiceName.value
	var frontTextServiceName = textInputTextArea.slice(0, textInputTextArea.indexOf(serviceName));
	var backTextServiceName = textInputTextArea.slice(textInputTextArea.indexOf(serviceName) + serviceName.length);

	// サービス名を入力に合わせて変更
	inputServiceName.addEventListener("input", function(){
		
		console.log(serviceName);
		textInputTextArea = inputTextArea.value // overwriting
		serviceName = inputServiceName.value // overwriting
		customerName = inputCustomerName.value // overwriting
		
		textInputTextArea = textInputTextArea.replace( frontTextServiceName + beforeServiceName, frontTextServiceName + serviceName );

		reflectionServiceName(inputServiceName);
		
		beforeServiceName = inputServiceName.value  // overwriting
		
	});

	async function reflectionServiceName(target){
		try {
			inputTextArea.value = textInputTextArea
		} catch (error) {
			alert((error && error.message) + "\n上書き失敗")
			}
	};


	// お客様名を入力に合わせて変更
	inputCustomerName.addEventListener("input", function(){
		
		console.log("1:" + textInputTextArea);
		
		// Once initialized
		textInputTextArea = inputTextArea.value // overwriting
		textInputTextArea = textInputTextArea.replace( new RegExp("^" + customerName), "" );
		textInputTextArea = textInputTextArea.replace(/^様/, "");
		textInputTextArea = textInputTextArea.trim();
		
		customerName = inputCustomerName.value // overwriting

		if (customerName != ""){ // When all customer names are deleted
			textInputTextArea = customerName + "様\n\n" + textInputTextArea
		}
		
		reflectionCustomerName(inputCustomerName);
	});

	async function reflectionCustomerName(target){
		try {
			inputTextArea.value = textInputTextArea
		} catch (error) {
			alert((error && error.message) + "\n上書き失敗")
			}
	};
	

	// テキストエリアをクリックしてコピー
	inputTextArea.addEventListener("click", function(){
		textInputTextArea = inputTextArea.value;
 		copyClipboarad(textInputTextArea);
		inputTextArea.select(); 
	});

	async function copyClipboarad(target){
		try {
			await navigator.clipboard.writeText(target)
		} catch (error) {
			alert((error && error.message) + "\nコピー失敗")
		}
	};

});

こちらの記事からはCSSもお借りしました🙇‍♂️ありがとうございます🙏

.copycode {
  position: relative;
  display: inline-block;
}

.copycode span {
  opacity: 0;
  position: absolute;
  top: 0px;
  right: -5px;
  color: #fff;
  background: rgba(0,0,0,0.5);
  padding: 2px 5px;
  transform: translate(100%);
}

.copycode textarea:focus + span {
  animation: fade-out 2s ease-in;
}

@keyframes fade-out {
  0% {visibility: visible; opacity: 1;}
  100% {visibility: hidden; opacity: 0;}
}

今後の機能追加

この後は運用しながら出てきた要望に合わせて改修を行っていきたい予定です。

よく使うお客様名やサービス名に変更・挿入できるボタンを追加したり、ぐちゃぐちゃになってしまった時の初期化ボタンを実装していきたいと考えています。

カテゴリ内検索機能も追加していけると使い勝手が上がりそうだなと思っています。

JavaScriptが使えるようになると実装できる幅がめちゃくちゃ広がりますね!

フルサイト編集対応ブロックテーマ unitone

unitoneみたいにシンプルできれいなレイアウトにするのは難しいですがここまでは大体のWordPressテーマでも実装できる内容だったかと思います。

ここからunitoneの醍醐味であるフルサイト編集の機能を使ってみようと思います。

ただ私自身まだまだ使いこなせているわけではないので、こうやって使っていくのがいいかも?という検証途中になっていますがご了承ください(; ・`ω・´)

テキスト管理用のWordPressはまだ投稿数が少ないのでわかりやすくする為にこのブログつぶ式をテスト環境にコピーしてテーマをunitoneにして確認してみようと思います。

外観→エディター

このページから編集していくことになります。

ページを開くと表示設定で 最新の投稿 を選択している場合は ホーム のテンプレート、固定ページを選択している場合は 固定ページ のテンプレートが選択されている状態でフルサイト編集のエディターが開きます。

テンプレートの編集

フルサイト編集エディター画面
フルサイト編集エディター画面リスト表示アイコン

画像1枚目の状態が最新の投稿を選択したホームのテンプレートを開いた初期状態です。

画像2枚目で示したいまにもこけそうなハンバーガーメニューアイコンみたいなリスト表示アイコンをクリックしてみてください。

するとレイアウトに使われているブロックの構造を表示することができます。

このリストを確認しながらブロックパターンや個別のブロックを配置できるとうまくレイアウトが作れるようになるかもしれません。

フルサイト編集エディター画面リスト階層表示

リストを展開してみるとこのような構造になっています。

テンプレート→カバー(ブロック)→カバーコンテンツ(ブロック)まではお決まりな感じでしょうか。
カバーコンテンツの中にヘッダー(ブロック)・ホーム:コンテンツ(ブロック)・フッター(ブロック)でセクションのレイアウトを作る形のようです。

テンプレート
 └ カバー
  ├ カバーコンテンツ

  │ └ ヘッダー
  │   └
  ├ カバーコンテンツ
  │ └ ホーム : コンテンツ
  │   └ 
  └ カバーコンテンツ
    └ フッター
      └ 

ひとつのブロックを差し替えたり追加・削除するのはツリー構造で既存ブロックを選択して実装すると楽に変更できそうです!

一からレイアウトを作っていくには各カバーコンテンツに設置したセクションのレイアウト用ブロックの中にコンテナー(ブロック)やデコレーター(ブロック)を置いて…………

ちょっと複雑すぎるので、そんなときはキタジマさんが用意してくれているブロックパターンを使いましょうヽ(´ー`)ノ

置きたいセクション周辺あたりを適当にクリックして左上の+アイコンをクリックするとデフォルトでブロックパターンが選択できるようになっています、親切w

フルサイト編集ブロックパターン選択

パターンを選択されている状態でセクションを選びましょう。

あとはお好みのブロックパターンをクリックするだけでセクション用のブロックパターンが挿入されます。

セクション名の右側の参照ボタンをポチッとしてやると大きく表示できるのでよりわかりやすいです。

各セクションにお好みのブロックパターンを配置した後はリスト表示に戻ってひとつずつセクションの中身を自由に差し替えたり追加したりしてレイアウトしてくと効率がいいと思います。

フルサイト編集エディターを開く
フルサイト編集エディタ画面

ここまでは1テンプレートの編集方法でしたが、WordPressではいろいろなページで別のテンプレートが使用されています。

投稿には投稿のテンプレート、固定ページには固定ページのテンプレートのようにです。

フルサイト編集ではそれぞれのページに合わせたテンプレートを管理画面から編集することが可能になっています。

テンプレートの選択

左上のアイコンをクリックしてエディターのサイドバーを展開してみましょう。
(サイトアイコンを変更していない状態ではWordPressのアイコンになっています)

フルサイト編集エディターテンプレートパーツ

このエディターのテンプレート一覧からテンプレートを選んでテンプレートを編集することが可能です。

いままではテンプレートを編集する為にPHPファイルを直接編集するということが必要でしたが、ここからテンプレートを編集することでノーコードでレイアウトを作成することが可能になっています。

これほんとに便利ですねw

いままで手を出しにくかった404ページのレイアウトやアーカイブページ、検索結果ページのレイアウトをUIで編集できるのは素敵すぎます。

テンプレートパーツの選択

各テンプレートで使えるテンプレート用のパーツもテンプレートパーツとして編集が可能になっています。

テンプレート編集部分にあった ホーム : コンテンツ のようなブロックも編集が可能です。

フルサイト編集エディターテンプレート

複数テンプレートで同じテンプレートパーツを使用している場合はこのテンプレートパーツを変更すると設置しているテンプレートパーツをまとめて変更できるので、投稿と固定ページで同じテンプレートパーツを使用していても一括で変更することが可能になっています。

右上にある新規追加ボタンから新しくテンプレートパーツを追加することも可能なので、オリジナルのテンプレートパーツを作ってみるなんてこともできるようになっています。

すごいな、フルサイト編集!

unitoneのライセンスを有効にしたときのブロックパターンの多さと美しさがすごい(語彙力)

さらに簡単にレイアウト

これまた記事公開後にキタジマさんからいただいたツイートでテンプレートの中身を簡単に置換できる方法があることを教えていただきました🙌

レイアウトを置換する動きを撮ってみました!

固定ページ用のテンプレートを選択して、ブロックを選択するとツールバーに置換というボタンが現れます。

この置換をポチッとするだけでレイアウトを簡単に差し替えすることができます🙌


難しいこと考えなくてもポチポチしていくだけで簡単にレイアウトを差し替えできるなんてwすごww

キタジマ神!!!

最後に

フルサイト編集対応のブロックテーマはまだそれほど多くないはずです。

いままでこのブログでもSnow Monkeyを使ってきましたが、unitoneにテーマ変更したくなるくらいとても美しくて柔軟性のあるテーマだと感じました。

ブログのテーマunitoneに載せ替えようかな(´-`)

いままで細かい部分を編集しようと思うとどうしてもテーマファイル(子テーマやプラグイン含)を編集する必要があったのでPHPやHTML/CSSを学ばないといけなかったのですが、フルサイト編集を使えばノーコードでページをレイアウトすることが可能になりました。

なんていうか、WordPressめちゃ楽しいですねw

そんな新しい領域を体験させてくれるテーマ開発者のキタジマさん本当にありがとうございます!

今年はこう言います!

unitone本当にオススメなので騙されたと思って使ってみてください!

ここまで読んでいただいてありがとうございました!

この記事は「Snow Monkey / unitone Advent Calendar 2022」16日目の記事です。

https://adventar.org/calendars/8154

あなたにも素敵な情報収集生活が訪れますように♪

Twitterでいろいろつぶやいています。
フォローお待ちしております。

この記事を書いた人

つぶ

情報収集が大好きです。

月曜夜のもくもく会 西中島StudyGroup
IT入門勉強会 ATTOsaka
主宰しています。

西中島StudyGroup - connpass
ATTOsaka - 公式ホームページ

オンラインリサイクルサービスをしています
スクレイピング案件ありませんか??

風呂敷 畳み人 / WordPress / SEO / Selenium

I'm computer nerd.