I’ll build this as a full WordPress theme template part for template-parts/post/post-meta.php, with safe escaping, schema-friendly meta, icons, author/date/category/tags/comments/reading time/edit link, and filter hooks so you can extend it later.
Below is a large, advanced, safe, extendable template-parts/post/post-meta.php file for your RX Theme.
Place it here:
rx-theme/template-parts/post/post-meta.php
<?php
/**
* Template part: Post Meta
*
* File: template-parts/post/post-meta.php
*
* Displays post metadata:
* - Author
* - Published date
* - Modified date
* - Categories
* - Tags
* - Comments
* - Reading time
* - Views count support
* - Post format
* - Sticky label
* - Edit link
* - Schema.org microdata
* - Accessibility-friendly labels
* - Theme customizer toggles
* - Developer filter hooks
*
* @package RX_Theme
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$post_id = get_the_ID();
if ( ! $post_id ) {
return;
}
/**
* ------------------------------------------------------------
* Helper: Boolean theme mod with default
* ------------------------------------------------------------
*/
$rx_meta_show_author = (bool) get_theme_mod( 'rx_show_post_meta_author', true );
$rx_meta_show_date = (bool) get_theme_mod( 'rx_show_post_meta_date', true );
$rx_meta_show_modified = (bool) get_theme_mod( 'rx_show_post_meta_modified_date', true );
$rx_meta_show_categories = (bool) get_theme_mod( 'rx_show_post_meta_categories', true );
$rx_meta_show_tags = (bool) get_theme_mod( 'rx_show_post_meta_tags', true );
$rx_meta_show_comments = (bool) get_theme_mod( 'rx_show_post_meta_comments', true );
$rx_meta_show_reading_time = (bool) get_theme_mod( 'rx_show_post_meta_reading_time', true );
$rx_meta_show_post_format = (bool) get_theme_mod( 'rx_show_post_meta_post_format', true );
$rx_meta_show_sticky = (bool) get_theme_mod( 'rx_show_post_meta_sticky', true );
$rx_meta_show_edit_link = (bool) get_theme_mod( 'rx_show_post_meta_edit_link', true );
$rx_meta_show_views = (bool) get_theme_mod( 'rx_show_post_meta_views', false );
$rx_meta_show_word_count = (bool) get_theme_mod( 'rx_show_post_meta_word_count', false );
$rx_meta_show_reading_level = (bool) get_theme_mod( 'rx_show_post_meta_reading_level', false );
$rx_meta_layout = get_theme_mod( 'rx_post_meta_layout', 'inline' );
$rx_meta_layout = in_array( $rx_meta_layout, array( 'inline', 'stacked', 'compact' ), true ) ? $rx_meta_layout : 'inline';
$rx_meta_icon_style = get_theme_mod( 'rx_post_meta_icon_style', 'emoji' );
$rx_meta_icon_style = in_array( $rx_meta_icon_style, array( 'emoji', 'dashicons', 'none' ), true ) ? $rx_meta_icon_style : 'emoji';
/**
* Allow developers to control all visibility from one filter.
*/
$rx_meta_settings = apply_filters(
'rx_theme_post_meta_settings',
array(
'show_author' => $rx_meta_show_author,
'show_date' => $rx_meta_show_date,
'show_modified' => $rx_meta_show_modified,
'show_categories' => $rx_meta_show_categories,
'show_tags' => $rx_meta_show_tags,
'show_comments' => $rx_meta_show_comments,
'show_reading_time' => $rx_meta_show_reading_time,
'show_post_format' => $rx_meta_show_post_format,
'show_sticky' => $rx_meta_show_sticky,
'show_edit_link' => $rx_meta_show_edit_link,
'show_views' => $rx_meta_show_views,
'show_word_count' => $rx_meta_show_word_count,
'show_reading_level' => $rx_meta_show_reading_level,
'layout' => $rx_meta_layout,
'icon_style' => $rx_meta_icon_style,
),
$post_id
);
/**
* ------------------------------------------------------------
* Helper: Icon output
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_theme_post_meta_icon' ) ) {
function rx_theme_post_meta_icon( $name = '', $style = 'emoji' ) {
if ( 'none' === $style ) {
return '';
}
$emoji_icons = array(
'author' => '👤',
'date' => '📅',
'modified' => '🔄',
'category' => '📂',
'tag' => '🏷️',
'comment' => '💬',
'time' => '⏱️',
'format' => '🧩',
'sticky' => '📌',
'edit' => '✏️',
'views' => '👁️',
'words' => '🔤',
'level' => '📘',
);
$dashicons = array(
'author' => 'dashicons-admin-users',
'date' => 'dashicons-calendar-alt',
'modified' => 'dashicons-update',
'category' => 'dashicons-category',
'tag' => 'dashicons-tag',
'comment' => 'dashicons-admin-comments',
'time' => 'dashicons-clock',
'format' => 'dashicons-format-aside',
'sticky' => 'dashicons-sticky',
'edit' => 'dashicons-edit',
'views' => 'dashicons-visibility',
'words' => 'dashicons-editor-textcolor',
'level' => 'dashicons-welcome-learn-more',
);
if ( 'dashicons' === $style && isset( $dashicons[ $name ] ) ) {
return '<span class="rx-meta-icon dashicons ' . esc_attr( $dashicons[ $name ] ) . '" aria-hidden="true"></span>';
}
if ( isset( $emoji_icons[ $name ] ) ) {
return '<span class="rx-meta-icon rx-meta-icon-emoji" aria-hidden="true">' . esc_html( $emoji_icons[ $name ] ) . '</span>';
}
return '';
}
}
/**
* ------------------------------------------------------------
* Helper: Calculate reading time
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_theme_get_reading_time' ) ) {
function rx_theme_get_reading_time( $post_id = 0 ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
return 0;
}
$content = get_post_field( 'post_content', $post_id );
$content = wp_strip_all_tags( strip_shortcodes( $content ) );
$word_count = str_word_count( $content );
$words_per_minute = absint( apply_filters( 'rx_theme_words_per_minute', 200, $post_id ) );
if ( $words_per_minute < 1 ) {
$words_per_minute = 200;
}
$reading_time = ceil( $word_count / $words_per_minute );
return max( 1, absint( $reading_time ) );
}
}
/**
* ------------------------------------------------------------
* Helper: Word count
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_theme_get_word_count' ) ) {
function rx_theme_get_word_count( $post_id = 0 ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
return 0;
}
$content = get_post_field( 'post_content', $post_id );
$content = wp_strip_all_tags( strip_shortcodes( $content ) );
return absint( str_word_count( $content ) );
}
}
/**
* ------------------------------------------------------------
* Helper: Simple reading level
* Basic estimation only.
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_theme_get_simple_reading_level' ) ) {
function rx_theme_get_simple_reading_level( $post_id = 0 ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
return '';
}
$content = get_post_field( 'post_content', $post_id );
$content = wp_strip_all_tags( strip_shortcodes( $content ) );
$word_count = str_word_count( $content );
$sentence_count = preg_match_all( '/[.!?]+/', $content );
if ( $word_count < 1 || $sentence_count < 1 ) {
return esc_html__( 'Easy read', 'rx-theme' );
}
$average_sentence_length = $word_count / $sentence_count;
if ( $average_sentence_length <= 12 ) {
return esc_html__( 'Easy read', 'rx-theme' );
}
if ( $average_sentence_length <= 20 ) {
return esc_html__( 'Standard read', 'rx-theme' );
}
return esc_html__( 'Advanced read', 'rx-theme' );
}
}
/**
* ------------------------------------------------------------
* Helper: Views count
* Works if another plugin/theme function stores post views.
* Supports common meta keys.
* ------------------------------------------------------------
*/
if ( ! function_exists( 'rx_theme_get_post_views_count' ) ) {
function rx_theme_get_post_views_count( $post_id = 0 ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
return 0;
}
$possible_keys = apply_filters(
'rx_theme_post_views_meta_keys',
array(
'rx_post_views',
'post_views_count',
'views',
'_post_views',
'pvc_views',
),
$post_id
);
foreach ( $possible_keys as $key ) {
$value = get_post_meta( $post_id, $key, true );
if ( '' !== $value && is_numeric( $value ) ) {
return absint( $value );
}
}
return 0;
}
}
/**
* ------------------------------------------------------------
* Helper: Separator
* ------------------------------------------------------------
*/
$rx_meta_separator = apply_filters(
'rx_theme_post_meta_separator',
'<span class="rx-post-meta-separator" aria-hidden="true">•</span>',
$post_id
);
/**
* ------------------------------------------------------------
* Build meta items
* ------------------------------------------------------------
*/
$rx_meta_items = array();
/**
* Sticky label
*/
if ( ! empty( $rx_meta_settings['show_sticky'] ) && is_sticky( $post_id ) ) {
$rx_meta_items['sticky'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-sticky">%1$s<span class="rx-post-meta-text">%2$s</span></span>',
rx_theme_post_meta_icon( 'sticky', $rx_meta_settings['icon_style'] ),
esc_html__( 'Featured', 'rx-theme' )
);
}
/**
* Author
*/
if ( ! empty( $rx_meta_settings['show_author'] ) ) {
$author_id = absint( get_post_field( 'post_author', $post_id ) );
$author_name = get_the_author_meta( 'display_name', $author_id );
$author_url = get_author_posts_url( $author_id );
if ( $author_name ) {
$rx_meta_items['author'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-author" itemprop="author" itemscope itemtype="https://schema.org/Person">%1$s<span class="rx-screen-reader-text">%2$s </span><a class="rx-post-meta-link rx-author-link" href="%3$s" rel="author" itemprop="url"><span itemprop="name">%4$s</span></a></span>',
rx_theme_post_meta_icon( 'author', $rx_meta_settings['icon_style'] ),
esc_html__( 'Written by', 'rx-theme' ),
esc_url( $author_url ),
esc_html( $author_name )
);
}
}
/**
* Published date
*/
if ( ! empty( $rx_meta_settings['show_date'] ) ) {
$published_time_iso = get_the_date( DATE_W3C, $post_id );
$published_time = get_the_date( '', $post_id );
$rx_meta_items['date'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-date">%1$s<span class="rx-screen-reader-text">%2$s </span><a class="rx-post-meta-link rx-date-link" href="%3$s" rel="bookmark"><time datetime="%4$s" itemprop="datePublished">%5$s</time></a></span>',
rx_theme_post_meta_icon( 'date', $rx_meta_settings['icon_style'] ),
esc_html__( 'Published on', 'rx-theme' ),
esc_url( get_permalink( $post_id ) ),
esc_attr( $published_time_iso ),
esc_html( $published_time )
);
}
/**
* Modified date
*/
if ( ! empty( $rx_meta_settings['show_modified'] ) ) {
$published_timestamp = get_the_time( 'U', $post_id );
$modified_timestamp = get_the_modified_time( 'U', $post_id );
if ( $modified_timestamp && $modified_timestamp > $published_timestamp ) {
$modified_time_iso = get_the_modified_date( DATE_W3C, $post_id );
$modified_time = get_the_modified_date( '', $post_id );
$rx_meta_items['modified'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-modified">%1$s<span class="rx-screen-reader-text">%2$s </span><time datetime="%3$s" itemprop="dateModified">%4$s</time></span>',
rx_theme_post_meta_icon( 'modified', $rx_meta_settings['icon_style'] ),
esc_html__( 'Updated on', 'rx-theme' ),
esc_attr( $modified_time_iso ),
esc_html( $modified_time )
);
}
}
/**
* Categories
*/
if ( ! empty( $rx_meta_settings['show_categories'] ) ) {
$categories_list = get_the_category_list(
esc_html_x( ', ', 'category separator', 'rx-theme' ),
'',
$post_id
);
if ( $categories_list ) {
$rx_meta_items['categories'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-categories">%1$s<span class="rx-screen-reader-text">%2$s </span><span class="rx-post-meta-tax-links">%3$s</span></span>',
rx_theme_post_meta_icon( 'category', $rx_meta_settings['icon_style'] ),
esc_html__( 'Categories:', 'rx-theme' ),
wp_kses_post( $categories_list )
);
}
}
/**
* Tags
*/
if ( ! empty( $rx_meta_settings['show_tags'] ) ) {
$tags_list = get_the_tag_list(
'',
esc_html_x( ', ', 'tag separator', 'rx-theme' ),
'',
$post_id
);
if ( $tags_list ) {
$rx_meta_items['tags'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-tags">%1$s<span class="rx-screen-reader-text">%2$s </span><span class="rx-post-meta-tax-links">%3$s</span></span>',
rx_theme_post_meta_icon( 'tag', $rx_meta_settings['icon_style'] ),
esc_html__( 'Tags:', 'rx-theme' ),
wp_kses_post( $tags_list )
);
}
}
/**
* Comments
*/
if ( ! empty( $rx_meta_settings['show_comments'] ) && ! post_password_required( $post_id ) && comments_open( $post_id ) || get_comments_number( $post_id ) ) {
$comments_number = get_comments_number( $post_id );
if ( 0 === absint( $comments_number ) ) {
$comments_text = esc_html__( 'No comments', 'rx-theme' );
} elseif ( 1 === absint( $comments_number ) ) {
$comments_text = esc_html__( '1 comment', 'rx-theme' );
} else {
$comments_text = sprintf(
/* translators: %s: number of comments */
esc_html__( '%s comments', 'rx-theme' ),
number_format_i18n( $comments_number )
);
}
$rx_meta_items['comments'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-comments">%1$s<a class="rx-post-meta-link rx-comments-link" href="%2$s">%3$s</a></span>',
rx_theme_post_meta_icon( 'comment', $rx_meta_settings['icon_style'] ),
esc_url( get_comments_link( $post_id ) ),
esc_html( $comments_text )
);
}
/**
* Reading time
*/
if ( ! empty( $rx_meta_settings['show_reading_time'] ) ) {
$reading_time = rx_theme_get_reading_time( $post_id );
$rx_meta_items['reading_time'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-reading-time">%1$s<span class="rx-post-meta-text">%2$s</span></span>',
rx_theme_post_meta_icon( 'time', $rx_meta_settings['icon_style'] ),
sprintf(
/* translators: %s: reading time in minutes */
esc_html( _n( '%s min read', '%s mins read', $reading_time, 'rx-theme' ) ),
number_format_i18n( $reading_time )
)
);
}
/**
* Word count
*/
if ( ! empty( $rx_meta_settings['show_word_count'] ) ) {
$word_count = rx_theme_get_word_count( $post_id );
if ( $word_count > 0 ) {
$rx_meta_items['word_count'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-word-count">%1$s<span class="rx-post-meta-text">%2$s</span></span>',
rx_theme_post_meta_icon( 'words', $rx_meta_settings['icon_style'] ),
sprintf(
/* translators: %s: word count */
esc_html__( '%s words', 'rx-theme' ),
number_format_i18n( $word_count )
)
);
}
}
/**
* Simple reading level
*/
if ( ! empty( $rx_meta_settings['show_reading_level'] ) ) {
$reading_level = rx_theme_get_simple_reading_level( $post_id );
if ( $reading_level ) {
$rx_meta_items['reading_level'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-reading-level">%1$s<span class="rx-post-meta-text">%2$s</span></span>',
rx_theme_post_meta_icon( 'level', $rx_meta_settings['icon_style'] ),
esc_html( $reading_level )
);
}
}
/**
* Post views
*/
if ( ! empty( $rx_meta_settings['show_views'] ) ) {
$views_count = rx_theme_get_post_views_count( $post_id );
if ( $views_count > 0 ) {
$rx_meta_items['views'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-views">%1$s<span class="rx-post-meta-text">%2$s</span></span>',
rx_theme_post_meta_icon( 'views', $rx_meta_settings['icon_style'] ),
sprintf(
/* translators: %s: views count */
esc_html__( '%s views', 'rx-theme' ),
number_format_i18n( $views_count )
)
);
}
}
/**
* Post format
*/
if ( ! empty( $rx_meta_settings['show_post_format'] ) && current_theme_supports( 'post-formats' ) ) {
$post_format = get_post_format( $post_id );
if ( $post_format ) {
$post_format_object = get_post_format_object( $post_format );
if ( $post_format_object && ! empty( $post_format_object->labels->singular_name ) ) {
$rx_meta_items['post_format'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-format">%1$s<span class="rx-screen-reader-text">%2$s </span><span class="rx-post-meta-text">%3$s</span></span>',
rx_theme_post_meta_icon( 'format', $rx_meta_settings['icon_style'] ),
esc_html__( 'Post format:', 'rx-theme' ),
esc_html( $post_format_object->labels->singular_name )
);
}
}
}
/**
* Edit link
*/
if ( ! empty( $rx_meta_settings['show_edit_link'] ) && current_user_can( 'edit_post', $post_id ) ) {
$edit_url = get_edit_post_link( $post_id );
if ( $edit_url ) {
$rx_meta_items['edit'] = sprintf(
'<span class="rx-post-meta-item rx-post-meta-edit">%1$s<a class="rx-post-meta-link rx-edit-link" href="%2$s">%3$s</a></span>',
rx_theme_post_meta_icon( 'edit', $rx_meta_settings['icon_style'] ),
esc_url( $edit_url ),
esc_html__( 'Edit', 'rx-theme' )
);
}
}
/**
* Allow developers to modify meta items.
*/
$rx_meta_items = apply_filters( 'rx_theme_post_meta_items', $rx_meta_items, $post_id, $rx_meta_settings );
/**
* Stop if nothing to show.
*/
if ( empty( $rx_meta_items ) || ! is_array( $rx_meta_items ) ) {
return;
}
$rx_meta_classes = array(
'rx-post-meta',
'rx-post-meta-layout-' . sanitize_html_class( $rx_meta_settings['layout'] ),
'rx-post-meta-icons-' . sanitize_html_class( $rx_meta_settings['icon_style'] ),
);
$rx_meta_classes = apply_filters( 'rx_theme_post_meta_classes', $rx_meta_classes, $post_id, $rx_meta_settings );
?>
<div
class="<?php echo esc_attr( implode( ' ', array_map( 'sanitize_html_class', $rx_meta_classes ) ) ); ?>"
aria-label="<?php echo esc_attr__( 'Post information', 'rx-theme' ); ?>"
>
<?php
/**
* Before post meta hook.
*/
do_action( 'rx_theme_before_post_meta', $post_id, $rx_meta_settings );
$rx_meta_output = array();
foreach ( $rx_meta_items as $rx_meta_key => $rx_meta_html ) {
if ( empty( $rx_meta_html ) ) {
continue;
}
$rx_meta_output[] = apply_filters(
'rx_theme_post_meta_item_html',
$rx_meta_html,
$rx_meta_key,
$post_id,
$rx_meta_settings
);
}
echo wp_kses_post( implode( $rx_meta_separator, $rx_meta_output ) );
/**
* After post meta hook.
*/
do_action( 'rx_theme_after_post_meta', $post_id, $rx_meta_settings );
?>
</div>
Important small fix
In the comments condition, replace this line:
if ( ! empty( $rx_meta_settings['show_comments'] ) && ! post_password_required( $post_id ) && comments_open( $post_id ) || get_comments_number( $post_id ) ) {
with this safer version:
if ( ! empty( $rx_meta_settings['show_comments'] ) && ! post_password_required( $post_id ) && ( comments_open( $post_id ) || get_comments_number( $post_id ) ) ) {
So the final comments block begins like this:
if ( ! empty( $rx_meta_settings['show_comments'] ) && ! post_password_required( $post_id ) && ( comments_open( $post_id ) || get_comments_number( $post_id ) ) ) {
How to call it in your post template
Use this inside your post template file, such as:
get_template_part( 'template-parts/post/post-meta' );
Example inside:
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
<?php get_template_part( 'template-parts/post/post-meta' ); ?>
</header>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
Optional CSS
Add this to your theme CSS:
.rx-post-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
font-size: 14px;
line-height: 1.6;
color: #666;
margin-top: 10px;
margin-bottom: 15px;
}
.rx-post-meta-layout-stacked {
display: block;
}
.rx-post-meta-layout-stacked .rx-post-meta-item {
display: block;
margin-bottom: 6px;
}
.rx-post-meta-layout-compact {
font-size: 13px;
gap: 4px;
}
.rx-post-meta-item {
display: inline-flex;
align-items: center;
gap: 4px;
}
.rx-post-meta a {
text-decoration: none;
color: inherit;
}
.rx-post-meta a:hover,
.rx-post-meta a:focus {
text-decoration: underline;
}
.rx-post-meta-separator {
opacity: 0.5;
margin-left: 4px;
margin-right: 4px;
}
.rx-meta-icon {
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 1;
}
.rx-meta-icon-emoji {
font-size: 14px;
}
.rx-post-meta-sticky {
font-weight: 700;
}
.rx-post-meta-edit a {
font-weight: 600;
}
.rx-screen-reader-text {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
This file is safe, expandable, and will not break if some functions or data are missing.