- 2012.09.13
- コードを修正しました(カスタム投稿タイプでも動作するようにpageの縛りを削除。条件式の不具合修正)。
下記の関数とクラスをfunctions.phpに貼り付けてください。「get_next_page()」で次の固定ページの投稿オブジェクト($post)が、get_previous_page()で前の固定ページが取得できます。
注意点として、グローバル変数の$postを読みますので、WordPressループ内でしか使用できないこと、標準的な固定ページの並び順ルール(menu_order、投稿名順)で取得されること、があります。
<?php
function get_next_page() {
$get_adjacent_page = new get_adjacent_page();
return $get_adjacent_page->get_next_page();
}
function get_previous_page() {
$get_adjacent_page = new get_adjacent_page();
return $get_adjacent_page->get_previous_page();
}
/**
* get_adjacent_page
* 前後の固定ページ(同階層)を取得するクラス
*/
class get_adjacent_page {
private $post = null;
private $wpdb = null;
private $op = '';
private $orderby = '';
/**
* __construct
*/
public function __construct() {
global $post;
global $wpdb;
$this->post = $post;
$this->wpdb = $wpdb;
}
/**
* get_next_page
* 後の固定ページを取得する
* @return null or $post
*/
public function get_next_page() {
$this->op = '>=';
$this->orderby = 'ASC';
return $this->get_adjacent_post( 'next' );
}
/**
* get_previous_page
* 前の固定ページを取得する
* @return null or $post
*/
public function get_previous_page() {
$this->op = '<=';
$this->orderby = 'DESC';
return $this->get_adjacent_post( 'previous' );
}
/**
* get_adjacent_post
* get_adjacent_post関数を実行
* @params next or previous
* @return null or $post
*/
private function get_adjacent_post( $adjacent ) {
if ( !in_array( $adjacent, array( 'previous', 'next' ) ) ) return;
$previous = ( $adjacent === 'previous' ) ? true : false;
add_filter( 'get_'.$adjacent.'_post_join', array( $this, 'get_page_join' ), 10, 3 );
add_filter( 'get_'.$adjacent.'_post_where', array( $this, 'get_page_where' ), 10, 3 );
add_filter( 'get_'.$adjacent.'_post_sort', array( $this, 'get_page_sort' ) );
return get_adjacent_post( false, '', $previous );
}
/**
* get_page_join
* get_{$adjacent}_post_joinにフックさせる関数
* @return null
*/
public function get_page_join( $join, $in_same_cat, $excluded_categories ) {
return;
}
/**
* get_page_where
* get_{$adjacent}_post_whereにフックさせる関数
* @return String where文
*/
public function get_page_where( $where, $in_same_cat, $excluded_categories ) {
$where = $this->wpdb->prepare( "WHERE
p.ID != %s AND
p.post_parent = %s AND
( p.menu_order $this->op %s OR ( p.menu_order = %s AND p.post_title $this->op %s ) ) AND
p.post_type = %s AND
p.post_status = 'publish'",
$this->post->ID, $this->post->post_parent, $this->post->menu_order, $this->post->menu_order, $this->post->post_title, $this->post->post_type
);
return $where;
}
/**
* get_page_sort
* get_{$adjacent}_post_sortにフックさせる関数
* @return String order by, limit文
*/
public function get_page_sort( $sort ) {
return "ORDER BY p.menu_order $this->orderby, p.post_title $this->orderby LIMIT 1";
}
}
解説など
WordPressには、get_next_post関数や、get_previous_post関数など、前後の「投稿」を取得する関数はあるのですが、固定ページを取得する関数がありません(厳密にはget_next_post関数や、get_previous_post関数でも取得できるはずですが、投稿時間順になってしまう)。
そこで、方法がないか調べたところ、フォーラムで同様の質問を発見。
ここでは、SQLを直接発行して前後の固定ページを取得する方法が挙げられていました。
function get_next_page( $post ) {
global $wpdb;
if ( $post->post_type != 'page' ) { retrun; }
$next_page = $wpdb->get_row( $wpdb->prepare( "
SELECT *
FROM $wpdb->posts
WHERE post_type = 'page'
AND post_status = 'publish'
AND ID != %s
AND post_parent = %s
AND menu_order >= %s
AND post_title >= %s
ORDER BY menu_order ASC, post_title ASC
LIMIT 1", $post->ID, $post->post_parent, $post->menu_order, $post->post_title ) );
return $next_page;
}
はじめはこのコードを利用させてもらおうかなーと思っていましたが、get_next_post関数、get_previous_post関数のコードを見てみると内部では「get_adjacent_post関数」を利用していることを発見。さらにこの関数のコードを見てみると、複数のフィルターフックが用意されており、投稿オブジェクトを取得する条件を変更することができるということがわかりました。
このフックに引っ掛けて条件を変更することで、固定ページのデータ取得を実現しました。ただ、恐らく速度的にはSQL書いたほうが速いと思います…。
