wordpress next_post_link (カスタムタクソノミーの同一カテゴリー)

2013年5月23日

next_post_link, previous_post_link をカスタムタクソノミーの個別ページで使用する際、同一カテゴリー限定のパラメータ(in_same_cat)を「true」に指定すると機能しないというか表示されなくなる。

調べてみると、この関数の元の関数でタクソノミーを「’category’」とハードコーディングしている。

PHPXref 0.7: WordPress」で「next_post_link」を検索すると、

/wp-includes/link-template.php -> line 1351 とあったので、そこを調べてみると、以下のことがわかる。

  • next_post_link は adjacent_post_link を呼び出している。
  • adjacent_post_link は get_adjacent_post を呼び出している。
  • get_adjacent_post では次のように ‘category’ とハードコーディングされている。
...
 $cat_array = wp_get_object_terms($post->ID, 'category', array('fields' => 'ids'));
...

以下は、next_post_link に代わる関数を作成し、カスタムタクソノミーの個別ページで、同一カテゴリー限定を指定できるようにする際のメモ。但し、限定的な知識を元に行っているのでまったく動作への保障はなし。

また、WordPress のアップグレードなどにより機能しなくなる可能性は十分考えられる。(現時点のバージョンWordPress 3.5.1 では一応動く)

  • next_post_link, previous_post_link, adjacent_post_link, get_adjacent_post を functions.php にコピーして名前を変更。
  • くれぐれもオリジナルのコードは変更しない(さわらない)ように注意する。
  • 名前はそれぞれ以下のように変更。
  • next_post_link → next_tax_post_link
  • previous_post_link → previous_tax_post_link
  • adjacent_post_link → adjacent_tax_post_link
  • get_adjacent_post → get_adjacent_tax_post
  • それぞれの関数にカテゴリーのパラメータを追加( $cat = ‘category’)
  • フィルター名やクエリをそれに従って変更
//previous_post_link,next_post_linkでカスタムタクソノミーの同類カテゴリーが機能しないので、代わりの関数
//wp-include/link-template.php previous_post_link から
function previous_tax_post_link($format='« %link', $link='%title', $in_same_cat = false, $excluded_categories = '',  $cat = 'category') {
  //オリジナル adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, true);
  adjacent_tax_post_link($format, $link, $in_same_cat, $excluded_categories, true, $cat);
}

//wp-include/link-template.php next_post_link から
function next_tax_post_link($format='%link »', $link='%title', $in_same_cat = false, $excluded_categories = '',  $cat = 'category') {
  //オリジナル adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, false);
  adjacent_tax_post_link($format, $link, $in_same_cat, $excluded_categories, false, $cat);  
}
//wp-include/link-template.php adjacent_post_link から
function adjacent_tax_post_link( $format, $link, $in_same_cat = false, $excluded_categories = '', $previous = true,  $cat = 'category' ) {
  if ( $previous && is_attachment() )
    $post = get_post( get_post()->post_parent );
  else
    //オリジナル $post = get_adjacent_post( $in_same_cat, $excluded_categories, $previous );
    $post = get_adjacent_tax_post( $in_same_cat, $excluded_categories, $previous, $cat );
  if ( ! $post ) {
    $output = '';
  } else {
    $title = $post->post_title;
    if ( empty( $post->post_title ) )
      $title = $previous ? __( 'Previous Post' ) : __( 'Next Post' );
    $title = apply_filters( 'the_title', $title, $post->ID );
    $date = mysql2date( get_option( 'date_format' ), $post->post_date );
    $rel = $previous ? 'prev' : 'next';
    $string = '<a href="' . get_permalink( $post ) . '" rel="'.$rel.'">';
    $inlink = str_replace( '%title', $title, $link );
    $inlink = str_replace( '%date', $date, $inlink );
    $inlink = $string . $inlink . '</a>';
    $output = str_replace( '%link', $inlink, $format );
  }
  $adjacent = $previous ? 'previous' : 'next';
  //オリジナル echo apply_filters( "{$adjacent}_post_link", $output, $format, $link, $post );
  echo apply_filters( "{$adjacent}_tax_post_link", $output, $format, $link, $post );
}
//wp-include/link-template.php get_adjacent_post から
function get_adjacent_tax_post( $in_same_cat = false, $excluded_categories = '', $previous = true, $cat = 'category' ) {
  global $wpdb;
  if ( ! $post = get_post() )
    return null;
  $current_post_date = $post->post_date;
  $join = '';
  $posts_in_ex_cats_sql = '';
  if ( $in_same_cat || ! empty( $excluded_categories ) ) {
    $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
    if ( $in_same_cat ) {
      //オリジナル if ( ! is_object_in_taxonomy( $post->post_type, 'category' ) )
      if ( ! is_object_in_taxonomy( $post->post_type, $cat ) )
        return '';
      $cat_array = wp_get_object_terms($post->ID, $cat, array('fields' => 'ids'));
      if ( ! $cat_array || is_wp_error( $cat_array ) )
        return '';
      //オリジナル $join .= " AND tt.taxonomy = 'category' AND tt.term_id IN (" . implode(',', $cat_array) . ")";
      $join .= " AND tt.taxonomy = '".$cat."' AND tt.term_id IN (" . implode(',', $cat_array) . ")";
    }
    //オリジナル $posts_in_ex_cats_sql = "AND tt.taxonomy = 'category'";
    $posts_in_ex_cats_sql = "AND tt.taxonomy = '".$cat."'";
    if ( ! empty( $excluded_categories ) ) {
      if ( ! is_array( $excluded_categories ) ) {
        // back-compat, $excluded_categories used to be IDs separated by " and "
        if ( strpos( $excluded_categories, ' and ' ) !== false ) {
          _deprecated_argument( __FUNCTION__, '3.3', sprintf( __( 'Use commas instead of %s to separate excluded categories.' ), "'and'" ) );
          $excluded_categories = explode( ' and ', $excluded_categories );
        } else {
          $excluded_categories = explode( ',', $excluded_categories );
        }
      }
      $excluded_categories = array_map( 'intval', $excluded_categories );
      if ( ! empty( $cat_array ) ) {
        $excluded_categories = array_diff($excluded_categories, $cat_array);
        $posts_in_ex_cats_sql = '';
      }
      if ( !empty($excluded_categories) ) {
        //オリジナル $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')';
        $posts_in_ex_cats_sql = " AND tt.taxonomy = '".$cat."' AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')';
      }
    }
  }
  $adjacent = $previous ? 'previous' : 'next';
  $op = $previous ? '<' : '>';
  $order = $previous ? 'DESC' : 'ASC';  
  //オリジナル $join  = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_cat, $excluded_categories );
  $join  = apply_filters( "get_{$adjacent}_tax_post_join", $join, $in_same_cat, $excluded_categories );
  //オリジナル $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_cats_sql", $current_post_date, $post->post_type), $in_same_cat, $excluded_categories );
  $where = apply_filters( "get_{$adjacent}_tax_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_cats_sql", $current_post_date, $post->post_type), $in_same_cat, $excluded_categories );
  //オリジナル $sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
  $sort  = apply_filters( "get_{$adjacent}_tax_post_sort", "ORDER BY p.post_date $order LIMIT 1" );

  $query = "SELECT p.id FROM $wpdb->posts AS p $join $where $sort";
  //オリジナル $query_key = 'adjacent_post_' . md5($query);
  $query_key = 'adjacent_tax_post_' . md5($query);    
  $result = wp_cache_get($query_key, 'counts');
  if ( false !== $result ) {
    if ( $result )
      $result = get_post( $result );
    return $result;
  }
  $result = $wpdb->get_var( $query );
  if ( null === $result )
    $result = '';
  wp_cache_set($query_key, $result, 'counts');

  if ( $result )
    $result = get_post( $result );
  return $result;
}

使用する際は、カスタムタクソノミーの個別ページなどでパラメータは全て省略せず、最後にカスタムタクソノミーを指定する。

<?php next_tax_post_link('%link &raquo;', '%title', true, '', 'works_cat'); ?></p>