Sort Menu for Blog and Archive Pages
Adds a "Sort by" menu above the blog and archive lists so visitors can switch between newest, oldest, A to Z and most discussed posts.
Opens WPIDE on
Code
// Sort choices offered to visitors: key => array( label, orderby, order ).
$wpide_archive_sorts = array(
'newest' => array( 'Newest first', 'date', 'DESC' ),
'oldest' => array( 'Oldest first', 'date', 'ASC' ),
'title' => array( 'Title (A–Z)', 'title', 'ASC' ),
'discussed' => array( 'Most discussed', 'comment_count', 'DESC' ),
);
$wpide_archive_sort_key = function () use ( $wpide_archive_sorts ) {
$key = isset( $_GET['sort'] ) ? sanitize_key( wp_unslash( $_GET['sort'] ) ) : '';
return isset( $wpide_archive_sorts[ $key ] ) ? $key : '';
};
add_action( 'pre_get_posts', function ( $query ) use ( $wpide_archive_sorts, $wpide_archive_sort_key ) {
$key = $wpide_archive_sort_key();
if ( '' === $key || is_admin() || ! $query->is_main_query() || ! ( $query->is_home() || $query->is_archive() ) ) {
return;
}
$query->set( 'orderby', $wpide_archive_sorts[ $key ][1] );
$query->set( 'order', $wpide_archive_sorts[ $key ][2] );
$query->set( 'ignore_sticky_posts', true );
} );
// Sorted copies of a list are not separate pages for search engines.
add_filter( 'wp_robots', function ( $robots ) use ( $wpide_archive_sort_key ) {
if ( '' !== $wpide_archive_sort_key() ) {
$robots['noindex'] = true;
$robots['follow'] = true;
}
return $robots;
} );
$wpide_archive_sort_form = function () use ( $wpide_archive_sorts, $wpide_archive_sort_key ) {
$current = $wpide_archive_sort_key();
$id = wp_unique_id( 'wpide-sort-' );
$action = remove_query_arg( array( 'sort', 'paged' ), get_pagenum_link( 1, false ) );
$html = '<form class="wpide-archive-sort" method="get" action="' . esc_url( $action ) . '" style="display:flex;flex-wrap:wrap;gap:.5em;align-items:center;justify-content:flex-end;margin:0 0 1.5em;">';
$html .= '<label for="' . esc_attr( $id ) . '">Sort by</label><select id="' . esc_attr( $id ) . '" name="sort">';
foreach ( $wpide_archive_sorts as $key => $sort ) {
$html .= '<option value="' . esc_attr( $key ) . '"' . selected( $current ? $current : 'newest', $key, false ) . '>' . esc_html( $sort[0] ) . '</option>';
}
$html .= '</select>';
// A GET form drops the query string of its action, so keep those values (plain permalinks: ?cat=3 and so on).
parse_str( (string) wp_parse_url( $action, PHP_URL_QUERY ), $args );
foreach ( $args as $name => $value ) {
if ( is_string( $value ) ) {
$html .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" />';
}
}
return $html . '<button type="submit" class="wp-element-button button">Sort</button></form>';
};
// Classic themes: above the first post.
add_action( 'loop_start', function ( $query ) use ( $wpide_archive_sort_form ) {
static $done = false;
if ( $done || wp_is_block_theme() || ! $query->is_main_query() || ! ( is_home() || is_archive() ) || ! $query->have_posts() ) {
return;
}
$done = true;
echo $wpide_archive_sort_form(); // phpcs:ignore WordPress.Security.EscapeOutput -- escaped when built.
} );
// Block themes: above Query Loops that show the page's own posts.
add_filter( 'render_block_core/query', function ( $content, $block ) use ( $wpide_archive_sort_form ) {
static $done = false;
if ( $done || empty( $block['attrs']['query']['inherit'] ) || ! ( is_home() || is_archive() ) ) {
return $content;
}
$done = true;
return $wpide_archive_sort_form() . $content;
}, 10, 2 );
Notes
Sorted pages are marked noindex so search engines keep the default order; edit the list to offer other sorts.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.