Ich versuche, ein benutzerdefiniertes Widget zu erstellen, um beitragende Autoren für die aktuelle Kategorie anzuzeigen, die auf einer WordPress-Site angezeigt wird. Ich habe den folgenden PHP Code:
<?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
}
?>
Es werden Autoren der Website angezeigt, die sich jedoch nicht von Kategorie zu Kategorie ändern. In jedem Abschnitt werden die gleichen drei angezeigt. Die Testanweisung am Ende des Codeblocks funktioniert wie erwartet - die im Widget angezeigte Kategorie entspricht der URI-Kategorie.
Irgendwelche Gedanken darüber, wo ich beim Erstellen des Autorenarrays einen Fehler gemacht habe?
Dies kann zu einer ziemlich kostspieligen Operation werden, die die Ladezeit der Seite ernsthaft beeinträchtigen kann. In diesem Stadium ist Ihr Code ziemlich teuer. Schauen wir uns einen besseren Weg an, um dieses Problem anzugehen.
Was wir tun müssen, ist, den Zeitaufwand in db zu minimieren. Um dies zu tun, erhalten wir nur die Informationen, die wir benötigen, dh die Eigenschaft post_author
des Post-Objekts. Da es derzeit keine systemeigene Möglichkeit gibt, die Eigenschaft post_author
mit WP_Query
aus der Datenbank abzurufen, haben wir nur die Möglichkeit, das vollständige Objekt oder nur die Post-Eigenschaft ID
abzurufen. Um das Verhalten ( und das generierte SQL ) zu ändern, verwenden wir den Filter posts_fields
, in dem wir der SQL-Abfrage befehlen können, nur das Feld post_author
zurückzugeben, wodurch wir eine Menge Zeit sparen die db bekommen wir da nur was wir brauchen.
Um die Leistung zu verbessern, teilen wir WP_Query
zweitens mit, dass keine Post-Daten oder Post-Term- und Post-Meta-Daten zwischengespeichert werden sollen. Da wir keine Metadaten oder Post-Term-Daten benötigen, können wir einfach WP_Query
bitten, diese nicht abzufragen und für die spätere Verwendung zwischenzuspeichern. Dies spart uns außerdem viel zusätzliche Zeit in db, Zeit zum Hinzufügen dieser Daten Cache, und wir werden auch auf DB-Abfragen speichern.
Geben Sie dies alles in den Code ein: ( HINWEIS: Der gesamte Code ist ungetestet und erfordert 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);
Sie werden feststellen, dass wir einen benutzerdefinierten Auslöser namens wpse_post_author
haben. Immer wenn wir diesem benutzerdefinierten Trigger den Wert true
übergeben, wird unser Filter ausgelöst.
get_posts()
QUERYStandardmäßig übergibt get_posts()
suppress_filters=true
an WP_Query
, um zu verhindern, dass Filter auf get_posts()
einwirken. Damit unser Filter funktioniert, müssen wir ihn auf true zurücksetzen.
Nur ein weiterer Hinweis: Um die aktuelle Kategorie zuverlässig abzurufen, verwenden Sie für die Kategorie-ID $GLOBALS['wp_the_query']->get_queried_object()
und $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
}
}
Wie Sie sehen, habe ich einen tax_query
verwendet. Dies ist aufgrund seiner Flexibilität eine persönliche Präferenz. Außerdem können Sie den Code auf jeder Termseite wiederverwenden, ohne ihn ändern zu müssen. In diesem Fall müssen Sie nur die Bedingung is_category()
ändern.
In meinem tax_query
habe ich include_children
auf true
gesetzt, was bedeutet, dass WP_Query
Beiträge aus der aktuellen Kategorie und den Beiträgen erhält, die zu den untergeordneten Kategorien der angezeigten Kategorie gehören. Dies ist das Standardverhalten für alle hierarchischen Term-Seiten. Wenn Sie wirklich nur Autoren aus der angezeigten Kategorie benötigen, setzen Sie include_children
auf false
.
Wenn Sie eine var_dump( $post_author_ids )
ausführen, werden Sie feststellen, dass Sie eine Reihe von Autoren-IDs für Posts haben. Anstatt jede einzelne ID zu durchlaufen, können Sie dieses Array von IDs einfach an WP_User_Query
übergeben und anschließend die Ergebnisse dieser Abfrage durchlaufen.
$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;
}
}
Wir können dies noch weiter gehen und alles in einem Übergang speichern, wodurch wir nur 2-dB-Abfragen in =/- 0,002s erhalten.
Um einen eindeutigen vorübergehenden Namen festzulegen, verwenden wir den Begriff Objekt, um einen eindeutigen Namen zu erstellen
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
}
FLUSHING THE TRANSIENT
Wir können den Transienten löschen, wenn ein neuer Beitrag veröffentlicht wird oder wenn ein Beitrag bearbeitet, gelöscht, nicht gelöscht usw. wird. Dazu können wir den Hook transition_post_status
verwenden. Sie können es auch so einstellen, dass es nur bei bestimmten Ereignissen ausgelöst wird, beispielsweise wenn ein neuer Beitrag veröffentlicht wird. Sowieso ist hier der Haken, der abfeuert, wenn dem Pfosten etwas passiert
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_%')" );
});
In einer Funktionstypdatei
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_%')" );
});
In Ihrem Widget
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;
}
}
}
Der gesamte Code ist jetzt getestet und funktioniert wie erwartet
<?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;
}
?>
Erklären Sie den Code hier: