Once I wrote the back-end code to show admin alerts on posts, I decided to add in some front end magic.

Since the original code was written to be called by hooking into the admin_notices action, the obvious solution was to hook into something on the front end. But where?


I’m a fan of the Genesis themes. There’s a handy hook for placement called genesis_before_content_sidebar_wrap() and the call (based on last week’s code) is this:

add_action( 'genesis_before_content_sidebar_wrap', 'MYSITE_admin_notices' );

And immediately that outputs this below the menu:

Output message above title

Obviously there’s no CSS going on there, but that’s okay.

Not Genesis

That’s lovely but what if I don’t use Genesis?

While a filter like add_filter( 'the_title', 'MYSITE_admin_notices', 10, 2 ); would work, it also calls it for every output of the title on a page. If you happen to be using a sidebar that links to your 5 most recent posts, it can get pretty messy.

And the problem here is that WordPress doesn’t have standard template hooks like that. You can use get_header() but that puts it at the top of every page. There just isn’t a way to say “I want this above the title” and have it work universally on all themes. Bummer.

That said, you can totally make the get_header() call work with a little CSS magic and a little extra if-checks.

The CSS Code

Remember our goal in life is to load as little as possible on pages, so the best thing is to check if this is even the right post type:

add_action( 'wp_enqueue_scripts', 'MYSITE_wp_enqueue_scripts' );
public function MYSITE_wp_enqueue_scripts( ) {
	wp_register_style( 'cpt-shows-styles', plugins_url('shows.css', __FILE__ ) );

	if( is_single() && get_post_type() == 'post_type_shows' ){
		wp_enqueue_style( 'cpt-shows-styles' );

The actual CSS is up to you, but mine looks like this and is cribbed from WordPress core:

.wrap .notice {
	background: #fff;
	border-left: 4px solid #fff;
	-webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .1);
	box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .1);
	margin: 5px;
	padding: 1px 12px;

.wrap .notice p {
	margin: .5em 0;
	padding: 2px;

.wrap .notice p:before {
	margin-right: 6px;
	vertical-align: bottom;

.wrap .notice-error {
	border-left-color: #dc3232;

.wrap .notice-info {
	border-left-color: #00a0d2;

.wrap .notice-warning {
	border-left-color: #ffb900;

.wrap .notice-updated,
.wrap .notice-success {
	border-left-color: #46b450;

This basically reproduces the same CSS as you’d see on the Admin Dashboard.

The PHP Code

While we covered the brunt of the PHP code before, we need to make a few alterations to make sure that the output only shows on the right pages and to the right people.

The first changes will be in this section:

if ( $message ) {
	printf( '<div class="notice %1$s"><p><span class="dashicons dashicons-%2$s"></span> %3$s</p></div>', esc_attr( $type ), esc_attr( $dashicon ), esc_html( $message ) );

While it’s possible to use is_admin() to check if a visitor is on the dashboard or not, this is going to show on both front and backend. That means a better choice is is_user_logged_in() so our code will look like if ( $message && is_user_logged_in() ) and now it only shows if you’re logged in.

But. The code shows on every page. That meant the code showed up on the static front page because it had no code and just widgets. In order to make it only show up on the right pages, I put in a check for what was called when.

Since I have multiple CPTs, I keep the code that is post type specific in a file that matches the name, and I have an extra file called all-cpts.php that calls common code that they all use. This helps me keep my code dry (Don’t Repeat Yourself). That makes it easy for me to use a switch based the post type and output the right code on the right pages:

function MYSITE_CPT_admin_notices() {

	if ( !get_post() ) return;

	$message    = '';
	$type       = 'updated';
	$post       = get_post();

	$content    = get_post_field( 'post_content', $post->ID );
	$word_count = str_word_count( strip_tags( $content ) );

	switch ( $post->post_type ) {
		case 'post_type_shows':
			$worthit = get_post_meta( $post->ID, 'shows_worthit_details', true );

			if ( $worthit < '1' ) {
				$type     = 'notice-info';
				$message  = 'Is this show worth watching? We don\'t know. Halp!';
				$dashicon = 'heart';

				if ( $word_count < '100' ) {
					$type     = 'notice-error';
					$message  = 'We clearly know nothing about this show. Help!';
					$dashicon = 'warning';
				} elseif ( $word_count < '200' ) {
					$type     = 'notice-warning';
					$message  = 'This post is a stub. Please edit it and make it more awesome.';
					$dashicon = 'info';

	if ( $message && is_user_logged_in() && ( is_single() || is_admin() ) ) {
		printf( '<div class="wrap"><div class="notice %1$s"><p><span class="dashicons dashicons-%2$s"></span> %3$s</p></div></div>', esc_attr( $type ), esc_attr( $dashicon ), esc_html( $message ) );


Now the message shows up for logged in users only, and only on the intended pages.

Reader Interactions

%d bloggers like this: