The scenario is, you have a page http://example.com/popular/, and you want to add custom query variables for the page which can be retrieved using the get_query_var() function to modify the template or filter a query. So a request to http://example.com/popular/music/2014/usa will make new query variables – (popular_category = music, popular_year = 2014, popular_location = usa) available for you.
A solution can be achieved using the add_rewrite_rule() & add_rewrite_tag() functions, but there is an easier way which only uses one function to make the custom query variables available for the specific page, and won’t affect any other pages or anything else.
The Code
function popular_page_parse_request( $wp ) {
// custom variables will only be available on popular page.
$pageslug = 'popular';
// get the actual request and parse it down
if ( isset( $wp->request ) && strpos( $wp->request, '/' ) ) {
$requests = explode( '/', $wp->request );
// array_shift takes out the first path which is the page slug/name.
// and make sure it's the popular page.
if ( $pageslug == array_shift( $requests ) ) {
// set pagename to make sure we have found a page with the name.
$wp->set_query_var( 'pagename', $pageslug );
// wordpress automatically tries to check if it's an attachment when a parameter is present
// after pageslug, so we set it false as we do the parsing ourselves.
$wp->set_query_var( 'attachment', false );
// we understand this is a valid page, and let WordPress understand there's no error.
$wp->set_query_var( 'error', false );
$count = count( $requests );
if ( $count > 0 ) {
// stop the canonical redirection, if a url request isn't the same as get_permalink( ) or
// the_permalink( ), then wordpress redirects it to the actual page
// and removes all parameters after the slug name.
remove_action( 'template_redirect', 'redirect_canonical' );
// the first parameter will definitely be the category.
$wp->set_query_var( 'popular_category', $requests[0] );
// for the second one, we check if it could be a year, or it could be the country name.
if ( isset( $requests['1'] ) ) {
// pretty basic checks.
if ( 4 == strlen( $requests['1'] ) && is_numeric( $requests['1'] ) ) {
$wp->set_query_var( 'popular_year', $requests[1] );
} else {
$wp->set_query_var( 'popular_location', $requests[1] );
}
}
// if location wasn't found yet, and we have a third parameter variable.
if ( isset( $requests['2'] ) && !isset( $wp->query_vars['popular_location'] ) ) {
if ( ! is_numeric( $requests['2'] ) ) {
$wp->set_query_var( 'popular_location', $requests[2] );
}
}
}
// the final step to set some defaults if no value was available.
if ( ! isset( $wp->query_vars['popular_category'] ) ) {
$wp->set_query_var( 'popular_category', 'any' );
}
if ( !isset( $wp->query_vars['popular_year'] ) ) {
$wp->set_query_var( 'popular_year', 'any' );
}
if ( !isset( $wp->query_vars['popular_location'] ) ) {
$wp->set_query_var( 'popular_location', 'any' );
}
}
}
}
add_action( 'parse_request', 'popular_page_parse_request' );
The function above has been commented for better understanding. Now we can use get_query_var( 'popular_category' ), get_query_var( 'popular_year' ) or get_query_var( 'popular_location' ) to retrieve the specific url custom query variable.
Example
We will create a list of posts based on our custom query variables. First we will create a shortcode which generates content using the custom query variables, and then place the shortcode on the Popular page.
function popular_posts_shortcode( $attrs ) {
$html = '';
$query_args = array(
'order' => 'DESC',
'orderby' => 'comment_count',
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => array()
);
if ( 'any' != get_query_var( 'popular_category' ) ) {
$query_args['category_name'] = get_query_var( 'popular_category' );
}
if ( 'any' != get_query_var( 'popular_year' ) ) {
$query_args['year'] = get_query_var( 'popular_year' );
}
// i use a post custom field to add one or multiple location names with a post
// if you don't have any similar thing, don't use it. Otherwise you will always see an empty result.
if ( 'any' != get_query_var( 'popular_location' ) ) {
$query_args['meta_query'][] = array(
'key' => 'location',
'value' => array( get_query_var( 'popular_location' ) ),
'compare' => 'IN'
);
}
$query = new WP_Query( $query_args );
if ( $query->have_posts() ) {
$html .= '<ul>';
while( $query->have_posts() ) : $query->the_post();
$html .= sprintf(
'<li><a href="%1$s">%2$s</a> - <span title="posted %3$s ago">posted %3$s ago</span></li>',
get_permalink(),
get_the_title(),
human_time_diff( strtotime( get_post()->post_date ), current_time( 'timestamp' ) )
);
endwhile;
$html .= '</ul>';
}
wp_reset_postdata();
return $html;
}
add_shortcode( 'popular_posts', 'popular_posts_shortcode' );
Ok, now if you use the shortcode [popular_posts] on your Page (Popular), you should see a list. Try manually entering urls appending to the popular page and check the results. You can also add some links to your nav menu using direct urls of the popular page for quick access by you or your users.
For ordering/sorting posts, we have used comment_count.
