私はget_next_post
とget_previous_post
(同じカテゴリーから)を使って私の単一のテンプレートでサムネイルとそれぞれの投稿へのリンクを表示していますが、それは私のサーバーに大変な困難を与えている非常に大きなdbの中です。
このサイトには49、984の投稿があり、公開された投稿、下書き、添付ファイルの間にあります。
mysql> select post_status, count(1) from wp_posts group by post_status;
+-------------+----------+
| post_status | count(1) |
+-------------+----------+
| auto-draft | 1 |
| draft | 269 |
| inherit | 38656 |
| private | 5 |
| publish | 11053 |
+-------------+----------+
5 rows in set (0,07 sec)
get_previous_post
が実行するのにそんなに多くのリソースを必要とする理由を理解できます。結局のところ、それはすべての一致する投稿を日付ごとに比較して次または前を決定する必要があります。
$wdbp->queries
から、前の投稿を取得するためだけに、
クエリ:
SELECT p.id
FROM wp_posts AS p
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id
INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
AND tt.taxonomy = 'category' AND tt.term_id IN (5,7,14474)
WHERE
p.post_date < '2013-04-11 12:15:30' AND p.post_type = 'post' AND
p.post_status = 'publish' AND tt.taxonomy = 'category'
ORDER BY p.post_date DESC LIMIT 1
から:
require('wp-blog-header.php'),
require_once('wp-includes/template-loader.php'),
include('/themes/extra/single.php'),
get_previous_post, get_adjacent_post
撮影:
111.7ms
私はそれが通常難しい仕事ではないことを知っていますが、私の場合はそうです。
前と次の投稿を取得する他の方法はありますか?
編集:
s_ha_dum が指摘するように、$in_same_cat
という条件を含めて、wp_term_relationships
とwp_term_taxonomy
との2つの非常に重い結合を行うことで問題の原因となっています。解決策は、同じカテゴリの投稿を検索しないことです。残念ながら、この条件を使用する必要があります。
これは、 toschoの解決策 に加えて、マイナーな修正と2つの新しい関数、投稿オブジェクトを取得するためのget_fast_previous_post
とget_fast_next_post
を追加したものです。
クエリを高速化する方法はわかりませんが、結果をキャッシュすることができます。
残念ながら、next_post_link()
とprevious_post_link()
を迂回するためのフックはないので、それらの関数をカスタム関数に置き換える必要があります。
次のサンプルコードでは、 postメタフィールド を使用して結果を格納しています。副作用があるかもしれません - 私はほとんどの場合をカバーしようとしましたが、何かを逃したかもしれません。
<?php # -*- coding: utf-8 -*-
namespace WPSE;
/* Plugin Name: Fast Next/Prev Post Links
* Plugin URI: https://wordpress.stackexchange.com/q/101435/
*/
add_action(
'fast_prev_post_link',
__NAMESPACE__ . '\fast_prev_post_link',
10,
4
);
add_action(
'fast_next_post_link',
__NAMESPACE__ . '\fast_next_post_link',
10,
4
);
add_action(
'transition_post_status',
__NAMESPACE__ . '\delete_fast_adjacent_meta',
10,
3
);
/**
* Print previous post link.
*
* @param unknown_type $format
* @param unknown_type $link
* @param unknown_type $in_same_cat
* @param unknown_type $excluded_categories
*/
function fast_prev_post_link(
$format = '« %link',
$link = '%title',
$in_same_cat = FALSE,
$excluded_categories = ''
)
{
empty ( $format ) && $format = '%link »';
fast_adjacent_post_link(
$format,
$link,
$in_same_cat,
$excluded_categories,
TRUE
);
}
/**
* Print next post link.
*
* @param string $format
* @param string $link
* @param bool $in_same_cat
* @param array|string $excluded_categories
* @return void
*/
function fast_next_post_link(
$format = '%link »',
$link = '%title',
$in_same_cat = FALSE,
$excluded_categories = ''
)
{
empty ( $format ) && $format = '%link »';
fast_adjacent_post_link(
$format,
$link,
$in_same_cat,
$excluded_categories,
FALSE
);
}
/**
* Display adjacent post link.
*
* Slightly changed copy of adjacent_post_link().
* Unfortunately, WP mixes retrieving data and display. :(
*
* Can be either next post link or previous.
*
* @param string $format Link anchor format.
* @param string $link Link permalink format.
* @param bool $in_same_cat Whether link should be in a same
* category.
* @param array|string $excluded_categories Array or comma-separated list of
* excluded category IDs.
* @param bool $previous Default is true. Whether to display
* link to previous or next post.
* @return void
*/
function fast_adjacent_post_link(
$format,
$link,
$in_same_cat = FALSE,
$excluded_categories = '',
$previous = TRUE
)
{
if ( $previous && is_attachment() )
$post = get_post( get_post()->post_parent );
else // the only real change
$post = get_fast_adjacent_post(
$in_same_cat,
$excluded_categories,
$previous
);
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 );
}
/**
* Get next or previous post from post meta.
*
* @param bool $in_same_cat
* @param string|array $excluded_categories
* @param bool $previous
* @param object $post
* @return object|NULL Either the found post object or NULL
*/
function get_fast_adjacent_post(
$in_same_cat = FALSE,
$excluded_categories = array(),
$previous = TRUE,
$post = NULL
)
{
if ( ! $post = get_post( $post ) )
return;
$excluded_categories = prepare_excluded_categories( $excluded_categories );
$type = $previous ? 'prev' : 'next';
$cat_hash = empty ( $excluded_categories ) ? 0 : join( '-', $excluded_categories );
$hash = (int) $in_same_cat . "-$cat_hash";
$meta = (array) get_post_meta( $post->ID, "_fast_{$type}_post", TRUE );
if ( isset ( $meta[ $hash ] ) )
return get_post( $meta[ $hash ] );
$ad_post = get_adjacent_post( $in_same_cat, $excluded_categories, $previous );
if ( ! $ad_post )
return;
$meta[ $hash ] = $ad_post->ID;
update_post_meta( $post->ID, "_fast_{$type}_post", $meta );
return $ad_post;
}
/**
* Prepare categories sent as string.
*
* @param string|array $cats
* @return array
*/
function prepare_excluded_categories( $cats )
{
if ( empty ( $cats ) or is_array( $cats ) )
return array();
$cats = explode( ',', $cats );
$cats = array_map( 'trim', $excluded_categories );
$cats = array_map( 'intval', $excluded_categories );
return $cats;
}
/**
* Deletes post meta values for the current post and all posts referencing it.
*
* @wp-hook transition_post_status
* @param string $new_status
* @param string $old_status
* @param object $post
* @return void
*/
function delete_fast_adjacent_meta( $new_status, $old_status, $post )
{
$prev = (array) get_post_meta( $post->ID, '_fast_prev_post', TRUE );
if ( ! empty ( $prev ) )
{
foreach ( $prev as $post_id )
delete_post_meta( $post_id, '_fast_next_post' );
}
$next = (array) get_post_meta( $post->ID, '_fast_next_post', TRUE );
if ( ! empty ( $next ) )
{
foreach ( $next as $post_id )
delete_post_meta( $post_id, '_fast_prev_post' );
}
delete_post_meta( $post->ID, '_fast_prev_post' );
delete_post_meta( $post->ID, '_fast_next_post' );
}
これらの機能を使用するには、これをテーマに追加します。
do_action( 'fast_prev_post_link' );
do_action( 'fast_next_post_link' );