WordPressで特定の投稿を上位表示させたい時、例えば広告費貰ってる店舗情報とか。
カスタムフィールドにチェックが入っている投稿データを優先表示したい時ってあると思います。
ただ、カスタムフィールドにチェックが入っている投稿だけ抽出したループを作って、それをメインループの上に表示したりすると、1ページ目だけ表示件数が多くなってしまったりして、美しくありません。
1ページに表示される件数は均一にしつつ、カスタムフィールドにチェックが入っている投稿を優先表示させたい時、とりあえす以下の方法で実現はできます。
<?php
if ( ! class_exists( 'RecommendPost' ) ) {
class RecommendPost {
static function init(){
add_action( 'admin_menu', array( __CLASS__, 'add_meta_box') );
add_action('save_post', array( __CLASS__, 'save_meta_data') );
add_action('pre_get_posts', array( __CLASS__, 'change_order') );
}
/*-------------------------------------------*/
/* Recommend設定用のメタボックスを追加
/*-------------------------------------------*/
// add meta_box
public static function add_meta_box() {
$post_type = 'post';
add_meta_box(
'recommend meta box',
'優先表示',
array( __CLASS__, 'pad_content_meta_fields' ),
$post_type,
'side'
);
}
/*-------------------------------------------*/
/* 入力フィールドの生成
/*-------------------------------------------*/
public static function pad_content_meta_fields(){
//CSRF対策の設定(フォームにhiddenフィールドとして追加するためのnonceを「'noncename__recommend」として設定)
wp_nonce_field( wp_create_nonce(__FILE__), 'noncename__recommend' );
global $post;
$checked = ( get_post_meta( $post->ID,'recommend_post',true ) == 1) ? ' checked':'';
$label = '優先表示する';
echo '<ul>';
echo '<li><label>'.'<input type="checkbox" id="recommend_post" name="recommend_post" value="1"'.$checked.'> '.$label.'</label></li>';
echo '</ul>';
}
/*-------------------------------------------*/
/* 入力された値の保存
/*-------------------------------------------*/
public static function save_meta_data($post_id){
global $post;
//設定したnonce を取得(CSRF対策)
$noncename__recommend = isset($_POST['noncename__recommend']) ? $_POST['noncename__recommend'] : null;
//nonce を確認し、値が書き換えられていれば、何もしない(CSRF対策)
if(!wp_verify_nonce($noncename__recommend, wp_create_nonce(__FILE__))) {
return $post_id;
}
//自動保存ルーチンかどうかチェック。そうだった場合は何もしない(記事の自動保存処理として呼び出された場合の対策)
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return $post_id; }
$field = 'recommend_post';
$field_value = ( isset( $_POST[$field] ) ) ? $_POST[$field] : '0';
// データが空だったら入れる
if( get_post_meta($post_id, $field ) == ""){
add_post_meta($post_id, $field , $field_value, true);
// 今入ってる値と違ってたらアップデートする
} elseif( $field_value != get_post_meta( $post_id, $field , true)){
update_post_meta($post_id, $field , $field_value);
// 入力がなかったら消す
// } elseif( $field_value == "" ){
// delete_post_meta($post_id, $field , get_post_meta( $post_id, $field , true ));
}
}
/*-------------------------------------------*/
/* レコメンドにチェックされている記事を優先表示する
/*-------------------------------------------*/
public static function change_order($query){
if ( is_admin() ) return;
if( is_archive() && ( $query->query_vars['post_type'] == 'post' ) ) {
$query->set('meta_key', 'recommend_post');
$query->set('orderby', array('recommend_post' => 'DESC', 'date' => 'DESC') );
}
return $query;
}
} // class RecommendPost {
$RecommendPost = new RecommendPost();
$RecommendPost::init();
}
チェックが入ってたらカスタムフィールド recommend_post に 1 を保存
チェックが入っていなかったら 0 を保存。
それで、WordPress 4.0 くらいから 複数の優先順位でのソートが使えるようになっているので、
とりあえず recommend_post の値が大きい順に並べられるので、後は日付順にでもしておけば一応実現は出来る。
が...
recommend_post の数字の大きさで並び替えてるけど、チェックの無い場合にわざわざ 0 を登録してくのが無駄なデータの蓄積で美しくないと思うのですが、そもそも 値の入ってるやつだけ先に表示とかする方法あるんですかね?
その他ツッコミどころ沢山あると思うので詳しい人指摘してください!