WordPressでHtmxを使ってみた
この記事はオンライン勉強会「htmx勉強会配信 - connpass」用に突貫で書いたので誤字脱字間違いが沢山ある気がします。すみません。ご指摘お待ちしています。
今日のゴール
WordPressでHtmxを使ったサンプルを書いて実行してみます。
教材
を有り難く使わせてもらいました。
STEP1 まずは教材をそのまま試してみよう
git clone https://gitlab.com/i922/htmx-live-search.git
cd htmx-live-search
npx @wp-now/wp-now start
プラグインが有効化されて、「HTML Live Search」というブロックが利用できるようになるので、適当なページで呼び出して実行してみます。
STEP2 教材のコードを読む
いっぱいファイルあるけどキモのコードは htmx-live-search.php
と ajax-functions.php
に全部書かれています。
htmx-live-search.php(抜粋)
<input type="search" name="search" placeholder="Search..."
hx-post="<?php echo admin_url('admin-ajax.php'); ?>?action=live_search" hx-target="#search-results"
hx-trigger="input changed delay:500ms, search" hx-indicator=".htmx-indicator">
<span class="htmx-indicator" style='display:inline;'>Searching…</span>
と
ajax-functions.php
これです。
STEP3 WordPressのAjaxの扱い方を知る
知ってたら読み飛ばしOK
公式はこちら
個人ブログでははにわまんさんの記事が良さそう
つまりadmin-ajax.php
にGETやPOSTでゴニョゴニョすることでajaxを実現できます(雑ですみません、詳細は公式読みましょう)。
hx-post="<?php echo admin_url('admin-ajax.php'); ?>?action=live_search"
ここですね、今回はlive_searchという名前をactionで渡していて、その本体は ajax-functions.php
に書かれています。
※ $search_term = $_POST['search'];
そのまま使ってるのはちょっと怖いし色々雑いので、このプラグインはあくまでお試しであることを念頭においてください(記事にもそう書いてあります)
STEP4 教材を参考にちょっとカスタムしたコードを書いてみよう
強引ですが、デフォルトの検索ブロックをオーバーライドして同じような実装できたら面白いかもしれないと思ってちょっと書いてみました。
// Htmxのcdnを読み込み
function htmx_add_htmx_js()
{
// Enqueue HTMX script
wp_enqueue_script('htmx-script', 'https://unpkg.com/htmx.org@2.0.0/dist/htmx.min.js', array(), '2.0.0', true);
}
add_action('init', 'htmx_add_htmx_js');
// CSSを読み込み
function htmx_enqueue_styles()
{
if (has_block('core/search')) {
wp_enqueue_style('search-block-style', plugin_dir_url(__FILE__) . 'style.css', array(), '1.0.0');
}
}
add_action('enqueue_block_assets', 'htmx_enqueue_styles');
// 検索ブロックにフロント側だけhtmxの属性等を追加する
function add_htmx_attributes_and_elements_to_search_input($block_content, $block)
{
// 検索ブロックかどうかを確認
if ($block['blockName'] === 'core/search') {
// DOMDocumentのインスタンスを作成
$dom = new DOMDocument();
// HTMLを読み込む
@$dom->loadHTML(mb_convert_encoding($block_content, 'HTML-ENTITIES', 'UTF-8'));
// inputタグを取得
$inputs = $dom->getElementsByTagName('input');
foreach ($inputs as $input) {
// inputタグのクラス名をチェックしてターゲットを絞り込む
if ($input->getAttribute('class') === 'wp-block-search__input') {
$ajax_url = admin_url('admin-ajax.php') . '?action=live_search';
// HTMX属性を追加
$input->setAttribute('hx-post', $ajax_url);
$input->setAttribute('hx-trigger', 'input changed delay:500ms, search');
$input->setAttribute('hx-target', '#search-results');
$input->setAttribute('hx-indicator', '.htmx-indicator');
// spanタグを作成し、inputタグの後に追加
$span = $dom->createElement('span', 'Searching…');
$span->setAttribute('class', 'htmx-indicator');
$span->setAttribute('style', 'display:inline;');
$input->parentNode->insertBefore($span, $input->nextSibling);
// divタグを作成し、spanタグの後に追加
$div = $dom->createElement('div');
$div->setAttribute('id', 'search-results');
$span->parentNode->insertBefore($div, $span->nextSibling);
}
}
// 更新されたHTMLを取得
$block_content = $dom->saveHTML($dom->documentElement);
}
// コンテンツを返す
return $block_content;
}
// 関数をフィルターフックに追加
add_filter('render_block', 'add_htmx_attributes_and_elements_to_search_input', 10, 2);
// live_search関数を読み込み
include_once (plugin_dir_path(__FILE__) . 'ajax-functions.php');
.wp-block-search .wp-block-search__inside-wrapper {
position: relative;
}
.wp-block-search .htmx-indicator,
.wp-block-search #search-results {
position: absolute;
}
.wp-block-search .htmx-indicator {
top: 2.5em;
}
.wp-block-search #search-results {
top: 3em;
}
とかで、プラグイン作ってあげたら動きました。ハラショー!
感想
動いたものの、外部からWP_Queryを500ms毎に走らせられるのはどうなん?という気持ちに。
既存のajax-functions.phpの内容を
function fetch_posts_with_cache() {
// キャッシュキーを設定
$cache_key = 'my_query_cache_key';
// キャッシュの有効期限を設定(秒単位)
$cache_duration = 30; // 例えば30秒
// キャッシュからデータを取得
$cached_posts = get_transient($cache_key);
if (false === $cached_posts) {
// キャッシュがない場合、WP_Queryを実行
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
);
$query = new WP_Query($args);
// クエリ結果をキャッシュに保存
$cached_posts = $query->posts;
set_transient($cache_key, $cached_posts, $cache_duration);
}
return $cached_posts;
}
?>
とかなんかでキャッシュ利用したりしたらマシなのかな?と思ったりしましたけれど、自己責任でどうぞ(責任持てないのでプラグイン公開しません…)
非公式なAPIありました
どうしてもHTMX使ってやりたい!みたいな気持ちになっている人は試してみても良いかも。
だけれど、さらにメンテナー2人しかいないライブラリに乗っかるよりは素直に素のJSかReactか書いたほうが良くないか、という気はします。
Block周りで書くなら Interactivity API かも
WordPressは最近、Interactivity API( https://developer.wordpress.org/block-editor/reference-guides/packages/packages-interactivity/ )を出した(WordPressは何度も外部ライブラリ利用をしては開発止まっちゃうみたいなのを経験しまくっているので最近は最初から自作しちゃう派になりつつある気がする)ので、今から書くならそっち寄りにしたほうが良いかな、という気持ちに。
とはいえSTEP4みたいな強引なことするのだったら何だって良いか、という気もします。
Interactivity API は Alpine.js ライクに使える(ように完全にインスパイアされて開発されてる)ので、最近のイケてるJS開発に慣れているなら使えるってこの公式ブログ記事にも書かれていました。
今のところの結論、WordPressでの使い処は
既存のクラシックテーマのサイトにちょいとAjaxな処理乗っけたい、みたいな時には良いと思います。
既存サイトのメンテナンスとか追加開発に導入を検討するのは全然アリだと思います。
にもその良さが書かれていて頷ける気はします。
いいとこ取りしていきたい!
WordPressのことばっかりになってhtmxのこと殆ど学べてない心地…
その他、参照URL
set_transient() – Function | Developer.WordPress.org https://developer.wordpress.org/reference/functions/set_transient/
とりあえずWordPressは置いといて、htmxの使い方知りたい場合
使いやすいシチュエーションもいっぱいあると思うので、試しておいて損はなさそう。
Discussion