ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

WordPress5.3 SQL, メタ・キーの比較演算子の拡張。大体のクエリ実行が可能に。

wordpress image
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

WordPressには、カスタム・フィールド値(メタ・キー)をSQLの条件にしてクエリが実行できるんですが、WordPress5.3から、そのメタ・キーSQLクエリの比較演算子が増えました。LIKE演算子以外にも多くをサポートします。

これで普通のSQLと変わらないくらいのクエリが実行できます。

開発者向けの話です。テーマ・プラグインを作っている人は要チェック。

WP5.3が対応する比較演算子

WP5.1からWP_Query, WP_Meta_Queryでメタ・キーの比較にLIKEが使えるようになりました。

(デフォルトはイコール(=))

メタ・キーはカスタムフィールド名のことで、管理画面の編集ページのカスタマイズをしている人にはおなじみのやつです。

WP5.3ではその比較演算子が大幅に増えました。メタ・キーのクエリはコンプリートしています。

演算子WP5.2までWP5.3以降
=
(デフォルト)
!=
IN
NOT IN
LIKE
NOT LIKE
RLIKE
REGEXP
NOT REGEXP
EXISTS
NOT EXISTS

メタ情報は、コメント、ユーザー、カテゴリ・タグなどのターム、サイト情報にもありますが、公式ガイドでは、投稿・固定ページ(カスタムも)のWP_Queryと、その中で使うメタクエリ(WP_Meta_Query)しか触れてません。

大元のWP_Meta_Queryに変更があるので使えるのでしょう。『そのへんは応用で分かるでしょ?』ってことなのかもしれません。

投稿情報は基本的な情報しかありません。

(タイトル、コンテンツ、日時など。)

それ以外の情報はカスタムフィールドに設定してメタ情報として保存します。

(ほかのコメント情報なども同じ。)

WP_Meta_QueryはSQLを作成するクラスで実行まではしません。

WP_Queryなどメタ情報をもつもののクエリに、メタ検索のSQLを追加するヘルパーです。

メタ・キーのクエリ

WP_Queryを使ってメタ・キーのクエリを実行してみましょう。

指定するパラメータはシングル指定と複数指定のふたつあります。

シングル複数
meta_compare_keycompare_key既存
meta_type_keytype_keyWP5.3で追加
$args = [
'meta_key' => 'test',
'meta_compare_key => 'test',
'meta_type_key => 'BINARY',
];
$args = [
'meta_query' => [
[
'key' => 'test',
'compare_key => 'test',
'type_key => 'BINARY',
],
],
];

まずは元々あったcompare_keyで実行します。

function test_query( $args ) {
    $query = new WP_Query( $args );
    echo '<p>-----------------------------------------------</p>';
    echo 'sql: ' . $query->request . PHP_EOL;
    echo '<br><br>';
    echo 'count: ' . $query->found_posts . PHP_EOL;
    echo '<br><br>';
}

$args = [
    'post_type' => 'post',
];
test_query( $args );

$args = [
    'post_type' => 'post',
    'meta_query' => [
        [
            'key' => 'views',            // カスタムフィールド名
            'compare_key' => 'EXISTS',   // 比較演算子
        ],
    ],
];
test_query( $args );
-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts
WHERE 1=1
    AND wp_posts.post_type = 'post'
    AND (wp_posts.post_status = 'publish'
         OR wp_posts.post_status = 'future'
         OR wp_posts.post_status = 'draft'
         OR wp_posts.post_status = 'pending'
         OR wp_posts.post_status = 'private'
    )
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 404

-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts INNER JOIN wp_postmeta
       ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE 1=1
    AND ( wp_postmeta.meta_key = 'views' )
    AND wp_posts.post_type = 'post'
    AND (wp_posts.post_status = 'publish'
         OR wp_posts.post_status = 'future'
         OR wp_posts.post_status = 'draft'
         OR wp_posts.post_status = 'pending'
         OR wp_posts.post_status = 'private'
    )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 293

(SQLはあとで整形)

検索SQLにメタテーブルが加わっているのが分かります。検索結果の件数もちがいますね?

正規表現の条件指定

正規表現を使うときはcompare_keyだけではできません。

正規表現の
比較演算子
REGEXP
(RLIKE)
NOT REGEXP

これらの演算子は、MySQL / MariaDBの仕様で大文字と小文字を区別できないからです。

MySQL / MariaDBでは、BINARYに変換(キャスト)すれば大文字・小文字も比較できます。そのためのパラメータがtype_keyです。

type_keyは比較文字列の型を指定します。

サンプルを実行してみましょう。

function test_query( $args ) {
    $query = new WP_Query( $args );
    echo '<p>-----------------------------------------------</p>';
    echo 'sql: ' . $query->request . PHP_EOL;
    echo '<br><br>';
    echo 'count: ' . $query->found_posts . PHP_EOL;
    echo '<br><br>';
}

/**
 * 大文字・小文字の区別なし
 */
$args = [
    'post_type' => 'post',
    'meta_query' => [
        [
            'key' => 'views',            // カスタムフィールド名
            'compare_key' => 'REGEXP',   // 比較演算子
        ],
    ],
];
test_query( $args );

$args = [
    'post_type' => 'post',
    'meta_query' => [
        [
            'key' => 'Views',
            'compare_key' => 'REGEXP',
        ],
    ],
];
test_query( $args );

/**
 * 大文字・小文字の区別あり
 */
$args = [
    'post_type' => 'post',
    'meta_query' => [
        [
            'key' => 'views',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( $args );

$args = [
    'post_type' => 'post',
    'meta_query' => [
        [
            'key' => 'Views',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( $args );
-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts INNER JOIN wp_postmeta
       ON ( wp_posts.ID = wp_postmeta.post_id ) 
WHERE 1=1
      AND ( wp_postmeta.meta_key REGEXP 'views' )
      AND wp_posts.post_type = 'post'
      AND (wp_posts.post_status = 'publish'
           OR wp_posts.post_status = 'future'
           OR wp_posts.post_status = 'draft'
           OR wp_posts.post_status = 'pending'
           OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 293

-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts INNER JOIN wp_postmeta
       ON ( wp_posts.ID = wp_postmeta.post_id ) 
WHERE 1=1
      AND ( wp_postmeta.meta_key REGEXP 'Views' )
      AND wp_posts.post_type = 'post'
      AND (wp_posts.post_status = 'publish'
           OR wp_posts.post_status = 'future'
           OR wp_posts.post_status = 'draft'
           OR wp_posts.post_status = 'pending'
           OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 293

-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts INNER JOIN wp_postmeta
       ON ( wp_posts.ID = wp_postmeta.post_id ) 
WHERE 1=1
      AND ( wp_postmeta.meta_key REGEXP BINARY 'views' )
      AND wp_posts.post_type = 'post'
      AND (wp_posts.post_status = 'publish'
           OR wp_posts.post_status = 'future'
           OR wp_posts.post_status = 'draft'
           OR wp_posts.post_status = 'pending'
           OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 293

-----------------------------------------------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts INNER JOIN wp_postmeta
       ON ( wp_posts.ID = wp_postmeta.post_id ) 
WHERE 1=1
      AND ( wp_postmeta.meta_key REGEXP BINARY 'Views' )
      AND wp_posts.post_type = 'post'
      AND (wp_posts.post_status = 'publish'
           OR wp_posts.post_status = 'future'
           OR wp_posts.post_status = 'draft'
           OR wp_posts.post_status = 'pending'
           OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

count: 0

(SQLはあとで整形)

最後のクエリは大文字が入って、BINARYを使っているので0件になりました。

今回はテスト用なので正規表現は完全一致を使いました。正規表現にはいろいろなやり方があります。

ちょっと豆知識

比較演算子のEXIST, NOT EXISTは内部で演算子を変換します。

変換前変換後
EXIST=
NOT EXIST!=

その他のメタクエリ

公式ガイドでは、WP_QueryとWP_Meta_Queryしか触れてません。

WP_Meta_Queryが対応しているので、その他のメタクエリはどうなのか実験してみました。

シングル
指定
複数
指定
タクソノミー
(カテゴリ、タグなど)
WP_Term_Query
コメント
WP_Comment_Query
ユーザー
WP_User_Query
サイト
WP_Site_Query

やっぱり使えるようですね?

実験のソースコードです。まず、この関数を作りました。

function test_query( $type, $args ) {
    $query = null;

    if ( 'term' === $type ) {
        $query = new WP_Term_Query( $args );

    } else if ( 'comment' === $type ) {
        $query = new WP_Comment_Query( $args );

    } else if ( 'user' === $type ) {
        $query = new WP_User_Query( $args );

    } else if ( 'site' === $type ) {
        $query = new WP_Site_Query( $args );

    }

    echo 'sql: ' . $query->request;
    echo '<br><br>';
}

メタテーブルが使われているかが分かればいいので、結果にSQLを出力します。

検索結果が0件になっても気にしません。必須パラメータは適当なのでヒットしないはずだから。

(そもそも実験用のデモ環境なのでデータ自体適当。)

これからどんどんサンプルを実行していきます。結果のSQLはあとで整形しました。

タクソノミー(カテゴリ、タグなど)

echo '<p>--------- タクソノミー - シングル指定 ----------</p>';
$args = [
    'taxonomy' => 'category',
    'meta_key' => 'test-key',
    'meta_compare_key' => 'REGEXP',
    'meta_type_key' => 'BINARY',
];
test_query( 'term', $args );

echo '<p>--------- タクソノミー - 複数指定 ----------</p>';
$args = [
    'taxonomy' => 'category',
    'meta_query' => [
        [
            'key' => 'test-key',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( 'term', $args );
--------- タクソノミー - シングル指定 ----------

sql:
SELECT DISTINCT t.*, tt.*
FROM wp_terms AS t
     INNER JOIN wp_termmeta
       ON ( t.term_id = wp_termmeta.term_id )
     INNER JOIN wp_term_taxonomy AS tt
       ON t.term_id = tt.term_id
WHERE tt.taxonomy IN ('category')
      AND ( wp_termmeta.meta_key REGEXP BINARY 'test-key' )
ORDER BY t.term_order ASC

--------- タクソノミー - 複数指定 ----------

sql:
SELECT DISTINCT t.*, tt.*
FROM wp_terms AS t
     INNER JOIN wp_termmeta
       ON ( t.term_id = wp_termmeta.term_id )
     INNER JOIN wp_term_taxonomy AS tt
       ON t.term_id = tt.term_id
WHERE tt.taxonomy IN ('category')
      AND ( wp_termmeta.meta_key REGEXP BINARY 'test-key' )
ORDER BY t.term_order ASC

wp_termmetaテーブルが使われてます。(wp_は環境により異なる。)

コメント

echo '<p>--------- コメント - シングル指定 ----------</p>';
$args = [
    'meta_key' => 'test-key',
    'meta_compare_key' => 'REGEXP',
    'meta_type_key' => 'BINARY',
];
test_query( 'comment', $args );

echo '<p>--------- コメント - 複数指定 ----------</p>';
$args = [
    'meta_query' => [
        [
            'key' => 'test-key',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( 'comment', $args );
--------- コメント - シングル指定 ----------

sql:
SELECT wp_comments.comment_ID
FROM wp_comments INNER JOIN wp_commentmeta
       ON ( wp_comments.comment_ID = wp_commentmeta.comment_id )
WHERE ( ( comment_approved = '0' OR comment_approved = '1' ) )
      AND ( wp_commentmeta.meta_key REGEXP BINARY 'test-key' )
GROUP BY wp_comments.comment_ID
ORDER BY wp_comments.comment_date_gmt DESC

--------- コメント - 複数指定 ----------

sql:
SELECT wp_comments.comment_ID
FROM wp_comments INNER JOIN wp_commentmeta
       ON ( wp_comments.comment_ID = wp_commentmeta.comment_id )
WHERE ( ( comment_approved = '0' OR comment_approved = '1' ) )
      AND ( wp_commentmeta.meta_key REGEXP BINARY 'test-key' )
GROUP BY wp_comments.comment_ID
ORDER BY wp_comments.comment_date_gmt DESC

wp_commentmetaテーブルが使われてます。

ユーザー

echo '<p>--------- ユーザー - シングル指定 ----------</p>';
$args = [
    'meta_key' => 'test-key',
    'meta_compare_key' => 'REGEXP',
    'meta_type_key' => 'BINARY',
];
test_query( 'user', $args );

echo '<p>--------- ユーザー - 複数指定 ----------</p>';
$args = [
    'meta_query' => [
        [
            'key' => 'test-key',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( 'user', $args );
--------- ユーザー - シングル指定 ----------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_users.*
FROM wp_users INNER JOIN wp_usermeta
       ON ( wp_users.ID = wp_usermeta.user_id )
     INNER JOIN wp_usermeta AS mt1
       ON ( wp_users.ID = mt1.user_id )
WHERE 1=1
      AND ( ( ( wp_usermeta.meta_key REGEXP BINARY 'test-key' )
      AND ( mt1.meta_key = 'wp_capabilities' ) ) )
ORDER BY user_login ASC

--------- ユーザー - 複数指定 ----------

sql:
SELECT SQL_CALC_FOUND_ROWS wp_users.*
FROM wp_users INNER JOIN wp_usermeta
       ON ( wp_users.ID = wp_usermeta.user_id )
     INNER JOIN wp_usermeta AS mt1
       ON ( wp_users.ID = mt1.user_id )
WHERE 1=1
      AND ( ( ( wp_usermeta.meta_key REGEXP BINARY 'test-key' )
      AND ( mt1.meta_key = 'wp_capabilities' ) ) )
ORDER BY user_login ASC

wp_usermetaテーブルが使われてます。

サイト

echo '<p>--------- サイト - シングル指定 ----------</p>';
$args = [
    'ID' => 1,
    'meta_key' => 'test-key',
    'meta_compare_key' => 'REGEXP',
    'meta_type_key' => 'BINARY',
];
test_query( 'site', $args );

echo '<p>--------- サイト - 複数指定 ----------</p>';
$args = [
    'ID' => 1,
    'meta_query' => [
        [
            'key' => 'test-key',
            'compare_key' => 'REGEXP',
            'type_key' => 'BINARY',
        ],
    ],
];
test_query( 'site', $args );
--------- サイト - シングル指定 ----------

sql:
SELECT wp_blogs.blog_id
FROM wp_blogs INNER JOIN wp_blogmeta
       ON ( wp_blogs.blog_id = wp_blogmeta.blog_id )
WHERE wp_blogs.blog_id = 1
      AND ( wp_blogmeta.meta_key REGEXP BINARY 'test-key' )
GROUP BY wp_blogs.blog_id
ORDER BY wp_blogs.blog_id ASC
LIMIT 100

--------- サイト - 複数指定 ----------

sql:
SELECT wp_blogs.blog_id
FROM wp_blogs INNER JOIN wp_blogmeta
       ON ( wp_blogs.blog_id = wp_blogmeta.blog_id )
WHERE wp_blogs.blog_id = 1
      AND ( wp_blogmeta.meta_key REGEXP BINARY 'test-key' )
GROUP BY wp_blogs.blog_id
ORDER BY wp_blogs.blog_id ASC
LIMIT 100

wp_blogmetaテーブルが使われてます。


前の投稿
WordPress5.3, wp_die(), HTML出力の変更
WordPress5.3, Backbone.jsのバージョンアップ
次の投稿

WordPressの本

post-cta-image

たくさんあるなかで、WordPressの基本が学べる、目的別に学べる本を選びました。

  • WordPressの基本。
  • Webサイト作成から運用まで全体的に学ぶ。
  • かんたんなカスタマイズを学ぶ。
  • 何も分からないところから学ぶ。
  • WordPressからPHPプログラミングを学ぶ。

の5冊です。どうしてもネット上で調べて勉強するのが苦手という人におすすめです。

この内容をモノにすればほかの本は必要ありません。あとは自分の力で、書籍を使わずにインターネット上にある情報だけで学んでいけます。

コメントを残す

*