こういうウェブおばさんになりたいです

「クエリループ」は、WordPress5.8から追加された、コンテンツ(投稿など)の繰り返しを表示するブロックです。
新着投稿ブロックとの大きな違いは、繰り返し内に投稿の「なに」を表示するかもブロックエディタで編集できる点です。

リリース時は機能が少なかったですが、この記事を書いている段階では投稿タイプの指定や繰り返し内の細かいデザイン調整、ページネーションの表示有無まで指定できるようになっていて、個人的には「これを待ってた!」な注目の機能です。

実は、デザインの指定がないシンプルな案件で既に使っています。試したのはテーマ「Lightning」を使用したサイトでしたが、基本的な情報をトップページや任意の固定ページに表示する程度なら充分に機能します。

ですが、普段よく受注する案件では、まだ採用が難しい状況です。
バージョン6.0.2の時点では、カスタムフィールドを表示できないからです。

ショートコードブロックを使えば…?

できればカスタムフィールドは、WordPressのコアのカスタムフィールドではなく、データベース構造が異なるAdvanced Custom Fields(以下ACF)の情報を出したいところです。
日本語での情報はほとんどないので海外のフォーラムなどを調べたところ「クエリループのテンプレート内で『カスタムフィールドの内容を呼び出すショートコードブロック』を使用するのはどうだろうか?」という投稿がいくつかありました。

早速、WordPressのコアのカスタムフィールド、ACFのフィールドを両方作って試してみました。ショートコードを作るのは特に難しいことではありません。とりあえず子テーマを作成して、functions.phpにカスタムフィールドの定義と「acf」と「wscf」というショートコードを作るコードを書きます。

<?php

add_shortcode( 'acf', 'WS_shortcode_acf' );
add_shortcode( 'wscf', 'WS_shortcode_wscf' );

function WS_shortcode_init() {

    function WS_shortcode_acf() {
        global $post;
        return get_field( 'text01', $post->ID );
    }

    function WS_shortcode_wscf() {
        global $post;
        return esc_html( get_post_meta( $post->ID, 'text02', true ) );
    }

}
add_action('init', 'WS_shortcode_init');

そして、できたショートコードをクエリループ内に差し込みます…
が、何も表示されません。
表示されないのは、いくつか原因があります。

ショートコードブロックで表示できない原因

ループ内の投稿情報は $post じゃない

CMSの構築の経験が長い人ならすぐ気づいたと思いますが、そもそも、さっきのコードでは「クエリループを埋め込んでいるページの投稿情報」を参照してしまいます。
たとえば、以下のように $post->ID だけを表示させてみると、ループ内のすべての投稿が、「クエリループを埋め込んでいるページの投稿ID」になってしまいます。これではだめです。

function WS_shortcode_wscf() {
    global $post;
    ob_start();
    var_dump($post->ID);
    return ob_get_clean();
}

ショートコードブロックではループ内の投稿情報を利用できない

では既存のクエリループ用ブロックと同じように、ループ内の投稿IDを引数として渡せばよいのではと調べてみます。クエリループ用の「テーマ > 投稿タイトル」ブロックはWordPressコアの、以下の場所にあります。

/wp-includes/blocks/post-title.php

これを見るとループ内の記事情報は $block->context で取得していることがわかりますが、この $block は「メンバ変数」と呼ばれるものです。WordPressの $post はテーマ内のどこでも使用することができますが、メンバ変数となっている場合は、ベースとなるプログラム(クラス)から継承しないと使用できません。そもそも $block が定義されていない、ショートコードブロックではループ内の投稿情報は利用できないのです。

get_post_meta(), get_field() が使用できない

また、カスタムフィールドの内容を取得する関数、コアの get_post_meta() 、ACFの get_field() はいずれもnullが返ってきます。そもそもクエリループ内では実行できないようです。

つまり現時点では、よほどWordPressを知り尽くしている人が、自作ブロックを追加するプラグインでも作らない限りは無理なようですし、そのような人だとしても公式のAPIの公開を待って、手を出さないほうがよいです。

FSEが見えてきた

というわけで、予想はしていましたが徒労に終わりました。

考えてみれば当然のことで、ショートコードブロックで誰でも簡単に情報を取得できたら、セキュリティホールだらけの危険なサイトになってしまいます。非公開にしていた投稿が表示されたら大変です。WordPress側でも Full Site Editing を目指した機能追加を予定していると思いますが、カスタムブロック以上に、PHPとJavaScriptの知識がない製作者が簡単には実装できないようにするだろうと思います。

投稿情報をテーマを介さずにコントロールする機能は、他のCMSでもいろいろな手法で実装されています。個人的にはa-blog cmsのモジュールIDまわりの機能が好きですが(崩れにくくて高度な知識を必要としない)、やはりここまでブラウザで見たまま編集ができるとなるとワクワクしてしまいます。

少しずつですが、Full Site Editing に近づいてきた気がします。サイトのすべてをブラウザから編集可能にする意義はあるのかセキュリティやパフォーマンスがますます下がるのではないかという根本の問題はとりあえずさておき、今後の更新を正座して待ちたいと思います。

この記事を書いた人

うぇびん

愛知県豊橋市に住んでいる、荒ぶるウェブおばさん。WordPressをはじめとした各種CMSを研究するのが好き。札幌のIT企業のビットスター株式会社に所属しています。