私はWordPressサイトで閲覧されている現在のカテゴリの寄稿者を表示するためのカスタムウィジェットを作成しようとしています。次のPHPコードがあります。
<?php
if (is_category()) {
?>
// Grab posts from the current category
<?php
$current_category = single_cat_title(“”, false);
$author_array = array();
$args = array(
‘numberposts’ => -1,
‘category_name’ => $current_category,
‘orderby’ => ‘author’,
‘order’ => ‘ASC’
);
// Get the posts in the array and create an array of the authors
$cat_posts = get_posts($args);
foreach ($cat_posts as $cat_post):
if (!in_array($cat_post->post_author, $author_array)) {
$author_array[] = $cat_post->post_author;
}
endforeach;
// Get the author information and build the output
foreach ($author_array as $author):
$auth = get_userdata($author)->display_name;
$auth_link = get_userdata($author)->user_login;
echo "<a href='/author/'" . $auth_link . "'>" . $auth . "</a>" . '<br \/>';
endforeach;
// Testing to make sure the current category is being pulled correctly
echo $current_category;
?>
<?php
}
?>
サイトの作者を表示していますが、カテゴリごとに変わるわけではありません - 各セクションに同じ3人が表示されます。コードブロックの末尾にあるテストステートメントは期待通りに動作しています - ウィジェット内に表示されているカテゴリはURIカテゴリと一致しています。
作者配列を作成する際にどこで問題が発生したのですか?
これは非常に高価な操作になる可能性があり、ページの読み込み時間に深刻な影響を与える可能性があります。この段階では、あなたのコードはかなり高価です。この問題に取り組むためのより良い方法を見てみましょう。
私たちがする必要があるのはdbで費やす時間を最小にすることです、そしてこれをするために、私たちは必要な情報だけを得るでしょう、それはpostオブジェクトのpost_author
プロパティです。今のところ、post_author
を使用してdbからWP_Query
プロパティを取得するだけのネイティブな方法はありません。完全なオブジェクトまたは単にID
を取得することしかできません。振る舞い(と生成されたSQL)を変更するには、posts_fields
フィールドを返すようにSQLクエリに命令することができるpost_author
フィルタを利用します。必要なものだけが取得されるので、時間内にデータベースに費やすことになります。
次に、パフォーマンスを向上させるために、投稿データや用語や投稿メタデータをキャッシュしないようにWP_Query
に指示します。メタデータやポストタームデータは必要ないので、WP_Query
にこれらのクエリを行わず、後で使用するためにキャッシュするように依頼するだけで済みます。これにより、このデータをデータベースに追加する時間を大幅に節約できます。キャッシュし、私たちはまたdbクエリを節約します。
これをすべてコードに入れてみましょう。(注:すべてのコードはテストされていないのでPHPが必要です。 5.4 +)
posts_fields
FILTERadd_filter( 'posts_fields', function ( $fields, \WP_Query $q ) use ( &$wpdb )
{
remove_filter( current_filter(), __FUNCTION__ );
// Only target a query where the new wpse_post_author parameter is set to true
if ( true === $q->get( 'wpse_post_author' ) ) {
// Only get the post_author column
$fields = "
$wpdb->posts.post_author
";
}
return $fields;
}, 10, 2);
wpse_post_author
というカスタムトリガーがあります。そのカスタムトリガーにtrue
の値を渡すたびに、フィルターが起動します。
get_posts()
QUERYデフォルトでは、get_posts()
にフィルタが作用しないように、get_posts()
はsuppress_filters=true
をWP_Query
に渡します。したがって、フィルタを機能させるには、これをtrueに戻す必要があります。
もう1つ注意してください。現在のカテゴリを確実に取得するには、カテゴリIDに$GLOBALS['wp_the_query']->get_queried_object()
と$GLOBALS['wp_the_query']->get_queried_object_id()
を使用します。
if ( is_category() ) {
$current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );
$args = [
'wpse_post_author' => true, // To trigger our filter
'posts_per_page' => -1,
'orderby' => 'author',
'order' => 'ASC',
'suppress_filters' => false, // Allow filters to alter query
'cache_results' => false, // Do not cache posts
'update_post_meta_cache' => false, // Do not cache custom field data
'update_post_term_cache' => false, // Do not cache post terms
'tax_query' => [
[
'taxonomy' => $current_category->taxonomy,
'terms' => $current_category->term_id,
'include_children' => true
]
]
];
$posts_array = get_posts( $args );
if ( $posts_array ) {
// Get all the post authors from the posts
$post_author_ids = wp_list_pluck( $posts_array, 'post_author' );
// Get a unique array of ids
$post_author_ids = array_unique( $post_author_ids );
// NOW WE CAN DO SOMETHING WITH THE ID'S, SEE BELOW TO INCLUDE HERE
}
}
ご覧のとおり、私はtax_query
を使用しましたが、これはその柔軟性のために個人的な好みであり、また、変更する必要なしに任意の用語ページでコードを再利用できます。この場合、is_category()
条件を変更するだけで済みます。
私のtax_query
ではinclude_children
をtrue
に設定しました。これはWP_Query
が現在のカテゴリからの投稿と、表示されているカテゴリの子カテゴリに属する投稿を取得することを意味します。これはすべての階層用語ページのデフォルトの動作です。表示されているカテゴリの著者が本当に必要なだけの場合は、include_children
をfalse
に設定します。
あなたがvar_dump( $post_author_ids )
をするならば、あなたはあなたがポスト作者のIDの配列を持っているのを見るでしょう。さて、すべてのIDをループするのではなく、このIDの配列を WP_User_Query
に渡して、そのクエリの結果をループするだけです。
$user_args = [
'include' => $post_author_ids
];
$user_query = new \WP_User_Query( $user_args );
var_dump( $user_query->results ); // For debugging purposes
if ( $user_query->results ) {
foreach ( $user_query->results as $user ) {
echo $user->display_name;
}
}
これをさらに進めて、すべてを一時的に保存することができます。その結果、=/ - 0.002秒で2 dbクエリしかできなくなります。
一意の一時的な名前を設定するには、オブジェクトという用語を使用して一意の名前を作成します。
if ( is_category() ) {
$current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );
$transient_name = 'wpse231557_' . md5( json_encode( $current_category ) );
// Check if transient is set
if ( false === ( $user_query = get_transient( $transient_name ) ) ) {
// Our code above
// Set the transient for 3 days, adjust as needed
set_transient( $transient_name, $user_query, 72 * HOUR_IN_SECONDS );
}
// Run your foreach loop to display users
}
トランジェントを流す
新しい投稿が公開されたとき、または投稿が編集、削除、削除されていないときなどにトランジェントをフラッシュすることができます。これにはtransition_post_status
フックを使用できます。新しい投稿が公開されたときだけのように、特定のことが起きたときにのみ起動するように調整することもできます。とにかく、これはポストに何かが起こったときに起動するフックです。
add_action( 'transition_post_status', function () use ( &$wpdb )
{
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_wpse231557_%')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_wpse231557_%')" );
});
関数型ファイル内
add_filter( 'posts_fields', function ( $fields, \WP_Query $q ) use ( &$wpdb )
{
remove_filter( current_filter(), __FUNCTION__ );
// Only target a query where the new wpse_post_author parameter is set to true
if ( true === $q->get( 'wpse_post_author' ) ) {
// Only get the post_author column
$fields = "
$wpdb->posts.post_author
";
}
return $fields;
}, 10, 2);
add_action( 'transition_post_status', function () use ( &$wpdb )
{
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_wpse231557_%')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_wpse231557_%')" );
});
あなたのウィジェットで
if ( is_category() ) {
$current_category = get_term( $GLOBALS['wp_the_query']->get_queried_object() );
$transient_name = 'wpse231557_' . md5( json_encode( $current_category ) );
// Check if transient is set
if ( false === ( $user_query = get_transient( $transient_name ) ) ) {
$args = [
'wpse_post_author' => true, // To trigger our filter
'posts_per_page' => -1,
'orderby' => 'author',
'order' => 'ASC',
'suppress_filters' => false, // Allow filters to alter query
'cache_results' => false, // Do not cache posts
'update_post_meta_cache' => false, // Do not cache custom field data
'update_post_term_cache' => false, // Do not cache post terms
'tax_query' => [
[
'taxonomy' => $current_category->taxonomy,
'terms' => $current_category->term_id,
'include_children' => true
]
]
];
$posts_array = get_posts( $args );
$user_query = false;
if ( $posts_array ) {
// Get all the post authors from the posts
$post_author_ids = wp_list_pluck( $posts_array, 'post_author' );
// Get a unique array of ids
$post_author_ids = array_unique( $post_author_ids );
$user_args = [
'include' => $post_author_ids
];
$user_query = new \WP_User_Query( $user_args );
}
// Set the transient for 3 days, adjust as needed
set_transient( $transient_name, $user_query, 72 * HOUR_IN_SECONDS );
}
if ( false !== $user_query
&& $user_query->results
) {
foreach ( $user_query->results as $user ) {
echo $user->display_name;
}
}
}
すべてのコードはテスト済みであり、期待通りに動作する
<?php
if( is_category() ) {
global $wp_query;
$term_obj = $wp_query->get_queried_object();
$author_array = array();
$args = array(
'posts_per_page' => -1,
'category' => $term_obj->term_id,
'orderby' => 'author',
'order' => 'ASC'
);
// Get the posts in the array and create an array of the authors
$cat_posts = get_posts( $args );
foreach ( $cat_posts as $cat_post ):
if ( ! in_array( $cat_post->post_author, $author_array ) ) {
$author_array[] = $cat_post->post_author;
}
endforeach;
// Get the author information and build the output
foreach ( $author_array as $author ):
$auth = get_userdata($author)->display_name;
$auth_link = get_userdata($author)->user_login;
printf( '<a href="/author/%s">%s</a><br />', $auth_link, $auth );
endforeach;
}
?>
ここでコードを説明する: