Secura Vita

Category: Works > wordpress » wordpress:複数のカスタムフィールドをまとめて取得する
2016/02/06
Works

wordpress:複数のカスタムフィールドをまとめて取得する

wordpress:複数のカスタムフィールドをまとめて取得する

wordpressのカスタマイズを行う際、必ずと言っていいほどカスタムフィールドを使います。

それも複数使うことが多く、時には十数個使うことも。

通常であればget_post_meta()を複数回使ったり、get_post_custom()で一気に取得したりしますがどちらもちょっとめんどくさかったりします。

get_post_meta()

$key1 = get_post_meta( $post->ID , 'key1' , true);
$key2 = get_post_meta( $post->ID , 'key2' , true);
...
$key10 = get_post_meta( $post->ID , 'key10' , true);

こりゃめんどくさい。データベースにも負担だし。

get_post_custom()

Array
(
    [_edit_lock] => Array
        (
            [0] => 1454683503:1
        )
    [_edit_last] => Array
        (
            [0] => 1
        )
    [key1] => Array
        (
            [0] => val1
        )
    [arraykey] => Array
        (
            [0] => a:3:{i:0;s:4:"val1";i:1;s:4:"val2";i:2;s:4:"val3";}
        )
)

という感じでいらないものまで取得しちゃいます。シリアライズされたそのまんまだし。


という制作上の面倒な点を解消するべく複数の指定したカスタムフィールドを1回でまとめて取得するfunctionを作成してみました。

スポンサーリンク

コード

下記コードをfunctions.phpに加えてください。

function get_post_meta_multiple( $args , $post_id) {
     
    global $wpdb;
    
    //$post_idをエスケープ処理
    $post_id = $wpdb->prepare('%d', $post_id);
    
    //$argsをエスケープ処理
    foreach($args as $val){
        $keys[] = $wpdb->prepare('%s', $val);
    }
    $keys = implode(',', $keys);

        
    //データベースから取得
    $getmetas = $wpdb->get_results(
            "
                SELECT meta_key,meta_value
                FROM $wpdb->postmeta
                WHERE post_id = $post_id
                AND meta_key IN ($keys)
            "
    );

    //結果を整形
    $metas = array();
    if( !empty( $getmetas) ) {
        foreach( $getmetas as $meta ) {
            
            //値がシリアライズされているか
            $value = ( is_serialized( $meta->meta_value ) ) ? unserialize( $meta->meta_value ) : $meta->meta_value ;

            $metas[ $meta->meta_key ] = $value; 
        }

        //見つからなかったフィールドがあった場合、$metas[見つからなかったキー]にnullを入れる
        $none = array_diff( $args , array_keys( $metas ) );
        if( !empty( $none ) ) {
            foreach( $none as $key ) {
                $metas[ $key ] = null;    
            }
        }
    }  
    
    //データをオブジェクトで返す
    return (object)$metas;

}

説明ですが、コメントに書いてあるとおりです。

ちょっと細くしますと、$wpdb->prepareはSELECTにかける値をエスケープします。

SQL インジェクション攻撃からクエリを保護するためには、実行する前にクエリデータはすべて SQL エスケープする必要があります。

キーが1つの場合はこう書けばいいんですが、

$getmetas = $wpdb->get_results($wpdb->prepare(
    "
        SELECT meta_key,meta_value
        FROM $wpdb->postmeta
        WHERE post_id = %d
        AND meta_key = %s
    ",
    $post_id , $key
));

今回は値の複数指定であるINで指定しているのでこのやりかただとうまくいきませんでした。

その他は「結果を整形」のところにあるunserializeですが、wordpressのデータベースを見てる人はわかると思いますが、配列をデータベースに入れる際はシリアライズされたカタチで入ります。

a:3:{i:0;s:4:"val1";i:1;s:4:"val2";i:2;s:4:"val3";}

こんなやつ。

これをphpで扱える配列のカタチに戻してやるのがunserializeです。

is_serializedでシリアライズされてるか調べて、シリアライズされていれば元に戻すということです。

//見つからなかったフィールドがあった場合~のところは、見つからなかったキーは$metasには入りませんのでデータを使用した場合エラーが出ます。
その回避として見つからなかったキーにnullを入れて作成します。

使い方

使い方はいたって簡単。

例のデータ

  • key1 → val1
  • key2 → val2
  • key3 → val3
  • arraykey → array(val1,val2,val3)
$args = array( 'key1' , 'key2' , 'key3' , 'arraykey' );
$metas = get_post_meta_multiple( $args , $post->ID );

$argsに取得したいカスタムフィールドのキーを配列で入れてください。

1つの場合もarray( ‘key’ )として下さい。

$metasをpreするとこうなります。

stdClass Object
(
    [key1] => val1
    [key2] => val2
    [key3] => val3
    [arraykey] => Array
        (
            [0] => val1
            [1] => val2
            [2] => val3
        )

)

//見つからないキーがあった場合はこうなります。
例)key4を設定してた場合
stdClass Object
(
    [key1] => val1
    [key2] => val2
    [key3] => val3 
    [arraykey] => Array
        (
            [0] => val1
            [1] => val2
            [2] => val3
        )
    [key4] =>

)

出力は取得した変数->メタキーです。

echo $metas->key1
//結果
val1

foreach( $metas->arraykey as $val ) {
    echo $val . '<br>';
}
//結果
val1
val2
val3

注意事項

カスタムフィールドは同じキー名で複数作成することがきます。
上記のコードは1キー1値が前提なので、その可能性がある場合は下記コードを使用して下さい。

使用するデータ

  • key1 → val1
  • key1 → val2
  • key2 → val3
  • arraykey → array(val1,val2,val3)

foreachの部分を書き換えて下さい。

foreach( $getmetas as $meta ) {
    //値がシリアライズされているか
    $value = ( is_serialized( $meta->meta_value ) ) ? unserialize( $meta->meta_value ) : $meta->meta_value ;

    //同じキーが複数ある場合配列で保存
    if( isset( $metas[ $meta->meta_key ] ) ) {
        if( !is_array( $metas[ $meta->meta_key ] ) ) {
            $metas[ $meta->meta_key ] = (array)$metas[ $meta->meta_key ];
        }
        $metas[ $meta->meta_key ][] = $value;
    } else {
        $metas[ $meta->meta_key ] = $value;
    }       
}

結果

stdClass Object
(
    [key1] => Array
        (
            [0] => val1
            [1] => val2
        )

    [key2] => val3
    [arraykey] => Array
        (
            [0] => val1
            [1] => val2
            [2] => val3
        )

)

この場合、key1が1つか2つかわからないので出力するときに配列に変換してやる必要がありますね。

//これはエラーが出ます
echo $metas->key1

//こうする
foreach( (array)$metas->key1 as $val ) {
    echo $val . '<br>';
}

なら全部配列で入れときゃいいじゃん!ってことで

foreach( $getmetas as $meta ) {

    //値がシリアライズされているか
    $value = ( is_serialized( $meta->meta_value ) ) ? unserialize( $meta->meta_value ) : $meta->meta_value ;

    if( isset( $metas[ $meta->meta_key ] ) ) {
        $metas[ $meta->meta_key ][] = $value;
    } else {
        $metas[ $meta->meta_key ] = array( $value );
    }
}

出力結果

stdClass Object
(
    [key1] => Array
        (
            [0] => val1
            [1] => val3
        )

    [key2] => Array
        (
            [0] => val2
        )

    [arraykey] => Array
        (
            [0] => Array
                (
                    [0] => val1
                    [1] => val2
                    [2] => val3
                )

        )

)

いままでめんどくさいなーって思ってはいたけど改めて関数作るまでいってなかったんですよね。
わりかし使う場面あるかなーと思ったりもするので今後はこのコード使っていこうかと思います。

もしおかしいところあったら…すいません…

スポンサーリンク
おもしろかった・役に立った