By blog has a header menu that consists of different links to pages like “About Us”, “Help”, “Contact Us” and “Blog”.
The “Blog” link is actually a page with a custom template that displays all the posts from my “blog” category.
What i want to do is to display a little notification text/link near my “Blog” link in the top menu if the “blog” category has a post published in the last 24 hours.
The theme i’m using is using the wp_nav_menu
function to display the menu in header.php.
Is there any way to achieve this?
1
I would store a transient with a life-time of 24 hours when a post (in some category, I’m using category with ID 333 as an example) is published. Whenever subsequent posts are published, the transient is either updated or recreated if 24 hours has elapsed and the transient has been deleted.
Logic
Whenever a post changes from one status to publish (including updates of currently published posts) a post type transition_post_status
is fired. This action passes the old status, the new status and te post object. Hooking into this, we can check:
- new status is ‘publish’ and old status is something else (i.e. newly published)
- It’s of post type ‘post’
- It’s in category 333
If so we update a transient which lasts for 24 hours.
add_action('transition_post_status', 'wpse_maybe_update_new_post_transient',10,2);
function wpse_maybe_update_new_post_transient($new_status, $old_status,$post){
if( 'post' != get_post_type($post) || !has_term( 333, 'category', $post) ){
return;
}
if( 'publish' == $new_status && $new_status != $old_status && ){
set_transient('wpse_post_published', $post->ID, 60*60*24 );
}
}
get_transient('wpse_post_published')
should then only return something when a post has been published in the last 24 hours.
So when the menu is being generated, we can check the transient – and conditionally add the class new-post-published a menu element.
In this example, the menu element I’m adding the class to corresponds to a ‘category’ term (with ID 333). I’ve not done so here, but you can use the $arg
to check that the menu is at a particular location too.
add_filter( 'nav_menu_css_class','wpse_maybe_add_new_post_class',10,3);
function wpse_maybe_add_new_post_class($classes, $item, $arg){
if( 'taxonomy' == $item->type && 'category' == $item->object && 333 == $item->object_id ){
if( get_transient('wpse_post_published') ){
$classes[] = 'new-post-published';
}
}
return $classes;
}
Then you can style the element appropriately. The same idea, with other filters can be used to insert extra elements (e.g. walker_nav_menu_start_el
) or through a custom walker.
Caveat
The following drawbacks to this method is, that:
- If a post is published, ‘cancelling’ the publish, either by reverting to draft status or scheduling it for the future won’t be observed – i.e. the transient will still exist and the menu will still show ‘new-post-published’.
- Similarly if you publish a post in category 333, and then remove it from that category.
- If you publish a post, not in category 333 and then update it so it is – this won’t add the ‘new-post-published’.
The last point has an easy fix using the above method. The first two are bit trickier, and if these two matter then instead you should perform a query for the latest published post in category 333, in the last 24 hours. If you find it, update the transient so it expires 24 hours after the post is published.
This second method is far more robust – but a little bit more expensive.