At my job, I work a on a membership-based site where staff has access to the WordPress admin, but users of the site only have access to the front end of the site. I have two shortcode functions I wrote for a staff-facing “Changelog” page of recent edits and a user-facing “Recent Updates” page.
However, there are some pages that are accessible for users that we don’t want to advertise. Even though we don’t give the link out to a page and it’s not in any menus, I was inadvertently about to create an area where users could discover these pages. Not to mention that users could also find the pages with a quick search on the site.
My solution to both of these issues was to create a layer between “Published” and “Private” – by using a tag I named “Unlisted.” With this sweet little function, your pages, posts, and custom post types with a particular tag (change “1” to the correct ID) will be excluded from the front-end search. The second part of the conditional, !is_admin() is what stops you from going crazy when searching for pages on the admin side. 🙂
/**
* Exclude "Unlisted" tag from search.
*/
function rose_exclude_unlisted($query) {
if ( ($query->is_search) && (!is_admin()) ) {
$query->set('tag__not_in', 1); // Change 1 to the ID of your "Unlisted" tag.
}
return $query;
}
add_filter('pre_get_posts', 'rose_exclude_unlisted');
Similarly, in my [public-updates] shortcode function, I added the argument tag__not_in with the Unlisted tag’s ID.
function rose_public_updates() {
// Get the 20 most recent edited public posts/pages/custom post type.
$recent_updates = '';
$args = array(
'post_type' => 'any',
'post_status' => array(
'publish'
),
'tag__not_in' => 1, // Change 1 to the ID of your "Unlisted" tag.
'orderby' => 'modified',
'posts_per_page' => 20,
'ignore_sticky_posts' => '1'
);
$recent_loop = new WP_Query( $args );
if ( $recent_loop->have_posts() ) {
$recent_updates = '<table><tr><th width="42%">Last 20 Updates</th><th width="30%">Last Modified</th></tr>';
while( $recent_loop->have_posts() ) : $recent_loop->the_post();
$recent_updates .= '<tr><td><a href="' . get_permalink( $recent_loop->post->ID ) . '">' . get_the_title( $recent_loop->post->ID ) . '</a></td><td>'. get_the_modified_date( 'D, M d, Y \a\t g:iA' ) .'</td></tr>';
endwhile;
$recent_updates .= '</table>';
}
wp_reset_postdata();
return $recent_updates;
}
add_shortcode('public-updates', 'rose_public_updates');
Add that bad boy to your functions file (if it’s your own theme or child theme), or throw it in a plugin and fire it up!