Blog

Modifying WordPress Post/Page Quick Links (subsubsub menu)

If you’ve ever done any permission management that alters what posts, pages or custom post types users see then you’ve probably run into an issue where the quick links at the top of the admin page are inaccurate. You may also find that you want to edit, alter or extend these links (which was the case with Project Panorama.) There is surprisingly little documentation on how to filter these links, so after some head banging against the wall I figured out a solution.

Screen Shot 2015-10-01 at 9.54.06 AM

The Filter

You can alter the quick links by running a filter on ‘views_edit-post’. The filter can be customized for the post type by switching -post for -page or -custom-post-type.

For example:

Posts
add_filter('views_edit-post','your_function_name');

Pages
add_filter('views_edit-page','your_function_name');

Custom post type (movies in this case)
add_filter('views_edit-movies','your_function_name');

Like any filter, the second argument is your callback function which has one parameter containing an array with the quick links markup. So if you were modifying the quicklinks for your “movies” custom post type you’d have something like this:

add_filter('views_edit-movies','wp37_update_movies_quicklinks');

function wp37_update_movies_quicklinks($views) {

     ...

     return $views;

}

The $views Array

The $views is a four item array containing the markup that will be output for the quick links. The items are:

$views['publish']

$views['draft']

$views['trash']

$views['pending']

Removing Submenu Links

Links can be removed by using unset, for example removing the link to the trash


function wp37_update_movies_quicklinks($views) {

     unset($views['trash']);

     return $views;

}

Updating Post Counts

You can also alter the views by updating an individual item which was necessary for Project Panorama where some users could only see and access posts assigned to them. For example, if you were limiting the custom post type of “movies” to post authors you might do something like this:


function wp37_limit_posts_to_author($query) {
	global $pagenow;

	if( 'edit.php' != $pagenow || !$query->is_admin )
	    return $query;

	if( ( !current_user_can( 'edit_others_posts' ) ) && ( $_GET['post_type'] == 'movies' ) ) {
		global $user_ID;
		$query->set('author', $user_ID );
	}
	return $query;
}
add_filter('pre_get_posts', 'wp37_limit_posts_to_author');

This works great except the counts on the sub menu are not accurate.

So you’d want to add a second filter. Rather than rewrite a rather lengthy script, I found one that works great over on wpcustoms.


add_filter('views_edit-movies','wp37_update_movies_quicklinks',1);	
function wp37_update_movies_quicklinks($views) { 

    global $current_user, $wp_query;  
    unset($views['mine']);  
    $types = array(  
        array( 'status' =>  NULL ),  
        array( 'status' => 'publish' ),  
        array( 'status' => 'draft' ),  
        array( 'status' => 'pending' ),  
        array( 'status' => 'trash' )  
    );  
    foreach( $types as $type ) {  
        $query = array(  
            'author'      => $current_user->ID,  
            'post_type'   => 'movies',  
            'post_status' => $type['status']  
        );  
        $result = new WP_Query($query);  
        if( $type['status'] == NULL ):  
            $class = ($wp_query->query_vars['post_status'] == NULL) ? ' class="current"' : '';  
            $views['all'] = sprintf(__('<a href="%s" '.="" $class="" .'="">All (%d)', 'all'),  
                admin_url('edit.php?post_type=post'),  
                $result->found_posts);  
        elseif( $type['status'] == 'publish' ):  
            $class = ($wp_query->query_vars['post_status'] == 'publish') ? ' class="current"' : '';  
            $views['publish'] = sprintf(__('<a href="%s" '.="" $class="" .'="">Published (%d)', 'publish'),  
                admin_url('edit.php?post_status=publish&post_type=post'),  
                $result->found_posts);  
        elseif( $type['status'] == 'draft' ):  
            $class = ($wp_query->query_vars['post_status'] == 'draft') ? ' class="current"' : '';  
            $views['draft'] = sprintf(__('<a href="%s" '.="" $class="" .'="">Draft'. ((sizeof($result->posts) > 1) ? "s" : "") .' (%d)', 'draft'),  
                admin_url('edit.php?post_status=draft&post_type=post'),  
                $result->found_posts);  
        elseif( $type['status'] == 'pending' ):  
            $class = ($wp_query->query_vars['post_status'] == 'pending') ? ' class="current"' : '';  
            $views['pending'] = sprintf(__('<a href="%s" '.="" $class="" .'="">Pending (%d)', 'pending'),  
                admin_url('edit.php?post_status=pending&post_type=post'),  
                $result->found_posts);  
        elseif( $type['status'] == 'trash' ):  
            $class = ($wp_query->query_vars['post_status'] == 'trash') ? ' class="current"' : '';  
            $views['trash'] = sprintf(__('<a href="%s" '.="" $class="" .'="">Trash (%d)', 'trash'),  
                admin_url('edit.php?post_status=trash&post_type=post'),  
                $result->found_posts);  
        endif;  
    }  
    return $views;  
}  

This loops through each post status (draft, published, trash, pending, etc…) and updates the count based on the author limited query.

Adding Links to the Sub Menu

You can also add links to the submenu, maybe you want a click link to display a specific category of movies.


add_filter('views_edit-post', 'wp37_add_movies_filter');
function wp37_add_movies_filter($views) {

    if( ( is_admin() ) && ( $_GET['post_type'] == 'movies' ) ) {
         
         global $wp_query;
         unset($views['mine']);
         $my_cat = 23 // Replace with your category ID

         $query = array(
             'author'      => $current_user->ID,
             'post_type'   => 'post',
             'post_status' => 'publish',
             'cat'         => $my_cat
         );

         $cat_object = get_category($my_cat);

         $result = new WP_Query($query);
         $class = ($wp_query->query_vars['cat'] == $cat_object->slug) ? ' class="current"' : '';
         $views['publish_f'] = sprintf(__('<a href="%s"'. $class .'>'. $cat_object->name .' (%d)', $cat_object->name ), admin_url('edit.php?post_status=publish&post_type=post&cat='.$my_cat), $result->found_posts);

         return $views;

     }

}

That’s a Wrap

Little details like ensuring an accurate and useful sub menu in the editor is what makes WordPress stand apart from other cumbersome content management systems. Even though these details can take time they are worth implementing as it’s part of your craft. If you care about how nicely your code is formatted why wouldn’t you put that same attention to detail into the admin interface?

Submit your website link and get a detailed report on how you can improve page performance, SEO optimization, mobile usability, and more.