author-box.php

I’ll build this as a complete advanced template-parts/post/author-box.php file for your RX Theme, with safe escaping, schema, social links, avatar fallback, author stats, and hooks so you can extend it later.

Below is a very advanced, feature-rich template-parts/post/author-box.php file for your RX Theme.

Create this file:

rx-theme/template-parts/post/author-box.php

Then paste this full code:

<?php
/**
 * Template Part: Author Box
 *
 * File: template-parts/post/author-box.php
 *
 * Advanced author box for RX Theme.
 *
 * Features:
 * - Safe WordPress escaping
 * - Author avatar
 * - Author name
 * - Author bio
 * - Author role/title
 * - Author website
 * - Author email button optional
 * - Social profile links
 * - Author post count
 * - Author archive link
 * - Latest posts by same author
 * - Schema.org Person markup
 * - Hooks and filters for future extension
 * - Accessibility friendly markup
 * - Works inside single post templates
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

/**
 * Do not show author box in places where it is not useful.
 */
if ( ! is_singular( 'post' ) ) {
	return;
}

/**
 * Get current post author.
 */
$rx_post_id   = get_the_ID();
$rx_author_id = (int) get_post_field( 'post_author', $rx_post_id );

if ( ! $rx_author_id ) {
	return;
}

/**
 * Basic author data.
 */
$rx_author_name        = get_the_author_meta( 'display_name', $rx_author_id );
$rx_author_first_name  = get_the_author_meta( 'first_name', $rx_author_id );
$rx_author_last_name   = get_the_author_meta( 'last_name', $rx_author_id );
$rx_author_nickname    = get_the_author_meta( 'nickname', $rx_author_id );
$rx_author_description = get_the_author_meta( 'description', $rx_author_id );
$rx_author_url         = get_the_author_meta( 'user_url', $rx_author_id );
$rx_author_email       = get_the_author_meta( 'user_email', $rx_author_id );
$rx_author_archive_url = get_author_posts_url( $rx_author_id );
$rx_author_posts_count = count_user_posts( $rx_author_id, 'post', true );

/**
 * Custom user meta support.
 * You can later create user profile fields for these.
 */
$rx_author_job_title       = get_the_author_meta( 'rx_author_job_title', $rx_author_id );
$rx_author_company         = get_the_author_meta( 'rx_author_company', $rx_author_id );
$rx_author_location        = get_the_author_meta( 'rx_author_location', $rx_author_id );
$rx_author_specialty       = get_the_author_meta( 'rx_author_specialty', $rx_author_id );
$rx_author_credentials     = get_the_author_meta( 'rx_author_credentials', $rx_author_id );
$rx_author_verified        = get_the_author_meta( 'rx_author_verified', $rx_author_id );
$rx_author_verified_text   = get_the_author_meta( 'rx_author_verified_text', $rx_author_id );
$rx_author_reviewed_by     = get_the_author_meta( 'rx_author_reviewed_by', $rx_author_id );
$rx_author_updated_profile = get_the_author_meta( 'rx_author_updated_profile', $rx_author_id );

/**
 * Social profile fields.
 * These can be added later through user profile fields.
 */
$rx_social_profiles = array(
	'facebook'  => array(
		'label' => __( 'Facebook', 'rx-theme' ),
		'url'   => get_the_author_meta( 'facebook', $rx_author_id ),
	),
	'twitter'   => array(
		'label' => __( 'X / Twitter', 'rx-theme' ),
		'url'   => get_the_author_meta( 'twitter', $rx_author_id ),
	),
	'linkedin'  => array(
		'label' => __( 'LinkedIn', 'rx-theme' ),
		'url'   => get_the_author_meta( 'linkedin', $rx_author_id ),
	),
	'instagram' => array(
		'label' => __( 'Instagram', 'rx-theme' ),
		'url'   => get_the_author_meta( 'instagram', $rx_author_id ),
	),
	'youtube'   => array(
		'label' => __( 'YouTube', 'rx-theme' ),
		'url'   => get_the_author_meta( 'youtube', $rx_author_id ),
	),
	'github'    => array(
		'label' => __( 'GitHub', 'rx-theme' ),
		'url'   => get_the_author_meta( 'github', $rx_author_id ),
	),
	'website'   => array(
		'label' => __( 'Website', 'rx-theme' ),
		'url'   => $rx_author_url,
	),
);

/**
 * Allow child theme/plugin customization.
 */
$rx_social_profiles = apply_filters( 'rx_theme_author_box_social_profiles', $rx_social_profiles, $rx_author_id, $rx_post_id );

/**
 * Author avatar settings.
 */
$rx_avatar_size = apply_filters( 'rx_theme_author_box_avatar_size', 120, $rx_author_id, $rx_post_id );

$rx_avatar = get_avatar(
	$rx_author_id,
	$rx_avatar_size,
	'',
	$rx_author_name,
	array(
		'class'         => 'rx-author-box__avatar-img',
		'loading'       => 'lazy',
		'fetchpriority' => 'low',
		'decoding'      => 'async',
	)
);

/**
 * Should show sections?
 */
$rx_show_author_box = apply_filters( 'rx_theme_show_author_box', true, $rx_author_id, $rx_post_id );
$rx_show_avatar     = apply_filters( 'rx_theme_author_box_show_avatar', true, $rx_author_id, $rx_post_id );
$rx_show_bio        = apply_filters( 'rx_theme_author_box_show_bio', true, $rx_author_id, $rx_post_id );
$rx_show_social     = apply_filters( 'rx_theme_author_box_show_social', true, $rx_author_id, $rx_post_id );
$rx_show_stats      = apply_filters( 'rx_theme_author_box_show_stats', true, $rx_author_id, $rx_post_id );
$rx_show_latest     = apply_filters( 'rx_theme_author_box_show_latest_posts', true, $rx_author_id, $rx_post_id );
$rx_show_email      = apply_filters( 'rx_theme_author_box_show_email', false, $rx_author_id, $rx_post_id );

if ( ! $rx_show_author_box ) {
	return;
}

/**
 * Do not show empty author box if author has no useful data.
 */
if (
	empty( $rx_author_name )
	&& empty( $rx_author_description )
	&& empty( $rx_avatar )
) {
	return;
}

/**
 * Latest posts by same author.
 */
$rx_latest_posts_count = apply_filters( 'rx_theme_author_box_latest_posts_count', 3, $rx_author_id, $rx_post_id );

$rx_latest_posts = array();

if ( $rx_show_latest && $rx_latest_posts_count > 0 ) {
	$rx_latest_posts_query = new WP_Query(
		array(
			'post_type'           => 'post',
			'post_status'         => 'publish',
			'author'              => $rx_author_id,
			'posts_per_page'      => absint( $rx_latest_posts_count ),
			'post__not_in'        => array( $rx_post_id ),
			'ignore_sticky_posts' => true,
			'no_found_rows'       => true,
		)
	);

	if ( $rx_latest_posts_query->have_posts() ) {
		while ( $rx_latest_posts_query->have_posts() ) {
			$rx_latest_posts_query->the_post();

			$rx_latest_posts[] = array(
				'id'    => get_the_ID(),
				'title' => get_the_title(),
				'url'   => get_permalink(),
				'date'  => get_the_date(),
			);
		}

		wp_reset_postdata();
	}
}

/**
 * Build sameAs schema array.
 */
$rx_schema_same_as = array();

foreach ( $rx_social_profiles as $rx_social_key => $rx_social_data ) {
	if ( ! empty( $rx_social_data['url'] ) && filter_var( $rx_social_data['url'], FILTER_VALIDATE_URL ) ) {
		$rx_schema_same_as[] = esc_url_raw( $rx_social_data['url'] );
	}
}

/**
 * Person schema data.
 */
$rx_author_schema = array(
	'@context' => 'https://schema.org',
	'@type'    => 'Person',
	'name'     => wp_strip_all_tags( $rx_author_name ),
	'url'      => esc_url_raw( $rx_author_archive_url ),
);

if ( ! empty( $rx_author_description ) ) {
	$rx_author_schema['description'] = wp_strip_all_tags( $rx_author_description );
}

if ( ! empty( $rx_author_job_title ) ) {
	$rx_author_schema['jobTitle'] = wp_strip_all_tags( $rx_author_job_title );
}

if ( ! empty( $rx_author_company ) ) {
	$rx_author_schema['worksFor'] = array(
		'@type' => 'Organization',
		'name'  => wp_strip_all_tags( $rx_author_company ),
	);
}

if ( ! empty( $rx_schema_same_as ) ) {
	$rx_author_schema['sameAs'] = $rx_schema_same_as;
}

$rx_author_schema = apply_filters( 'rx_theme_author_box_schema', $rx_author_schema, $rx_author_id, $rx_post_id );

/**
 * CSS classes.
 */
$rx_author_box_classes = array(
	'rx-author-box',
	'rx-author-box--post',
	'rx-author-box--author-' . $rx_author_id,
);

if ( ! empty( $rx_author_verified ) ) {
	$rx_author_box_classes[] = 'rx-author-box--verified';
}

if ( ! empty( $rx_author_description ) ) {
	$rx_author_box_classes[] = 'rx-author-box--has-bio';
}

if ( ! empty( $rx_latest_posts ) ) {
	$rx_author_box_classes[] = 'rx-author-box--has-latest-posts';
}

$rx_author_box_classes = apply_filters( 'rx_theme_author_box_classes', $rx_author_box_classes, $rx_author_id, $rx_post_id );

?>

<?php do_action( 'rx_theme_before_author_box', $rx_author_id, $rx_post_id ); ?>

<section
	class="<?php echo esc_attr( implode( ' ', array_map( 'sanitize_html_class', $rx_author_box_classes ) ) ); ?>"
	aria-labelledby="rx-author-box-title-<?php echo esc_attr( $rx_author_id ); ?>"
	itemscope
	itemtype="https://schema.org/Person"
>
	<div class="rx-author-box__inner">

		<?php if ( $rx_show_avatar && ! empty( $rx_avatar ) ) : ?>
			<div class="rx-author-box__avatar">
				<a
					class="rx-author-box__avatar-link"
					href="<?php echo esc_url( $rx_author_archive_url ); ?>"
					aria-label="<?php echo esc_attr( sprintf( __( 'View all posts by %s', 'rx-theme' ), $rx_author_name ) ); ?>"
					itemprop="url"
				>
					<?php echo wp_kses_post( $rx_avatar ); ?>
				</a>
			</div>
		<?php endif; ?>

		<div class="rx-author-box__content">

			<header class="rx-author-box__header">

				<p class="rx-author-box__label">
					<?php esc_html_e( 'Written by', 'rx-theme' ); ?>
				</p>

				<h2
					id="rx-author-box-title-<?php echo esc_attr( $rx_author_id ); ?>"
					class="rx-author-box__title"
					itemprop="name"
				>
					<a
						class="rx-author-box__name-link"
						href="<?php echo esc_url( $rx_author_archive_url ); ?>"
						rel="author"
					>
						<?php echo esc_html( $rx_author_name ); ?>
					</a>

					<?php if ( ! empty( $rx_author_verified ) ) : ?>
						<span class="rx-author-box__verified" title="<?php echo esc_attr__( 'Verified author', 'rx-theme' ); ?>">
							<span aria-hidden="true"></span>
							<span class="screen-reader-text">
								<?php esc_html_e( 'Verified author', 'rx-theme' ); ?>
							</span>
						</span>
					<?php endif; ?>
				</h2>

				<?php if ( ! empty( $rx_author_credentials ) || ! empty( $rx_author_job_title ) || ! empty( $rx_author_specialty ) ) : ?>
					<div class="rx-author-box__meta">
						<?php if ( ! empty( $rx_author_credentials ) ) : ?>
							<span class="rx-author-box__credential">
								<?php echo esc_html( $rx_author_credentials ); ?>
							</span>
						<?php endif; ?>

						<?php if ( ! empty( $rx_author_job_title ) ) : ?>
							<span class="rx-author-box__job-title" itemprop="jobTitle">
								<?php echo esc_html( $rx_author_job_title ); ?>
							</span>
						<?php endif; ?>

						<?php if ( ! empty( $rx_author_specialty ) ) : ?>
							<span class="rx-author-box__specialty">
								<?php echo esc_html( $rx_author_specialty ); ?>
							</span>
						<?php endif; ?>
					</div>
				<?php endif; ?>

				<?php if ( ! empty( $rx_author_company ) || ! empty( $rx_author_location ) ) : ?>
					<div class="rx-author-box__details">
						<?php if ( ! empty( $rx_author_company ) ) : ?>
							<span class="rx-author-box__company">
								<?php esc_html_e( 'Works at', 'rx-theme' ); ?>
								<strong><?php echo esc_html( $rx_author_company ); ?></strong>
							</span>
						<?php endif; ?>

						<?php if ( ! empty( $rx_author_location ) ) : ?>
							<span class="rx-author-box__location">
								<?php echo esc_html( $rx_author_location ); ?>
							</span>
						<?php endif; ?>
					</div>
				<?php endif; ?>

			</header>

			<?php if ( $rx_show_bio && ! empty( $rx_author_description ) ) : ?>
				<div class="rx-author-box__bio" itemprop="description">
					<?php
					echo wp_kses_post(
						wpautop(
							wp_trim_words(
								$rx_author_description,
								apply_filters( 'rx_theme_author_box_bio_words', 80, $rx_author_id, $rx_post_id ),
								'...'
							)
						)
					);
					?>
				</div>
			<?php else : ?>
				<div class="rx-author-box__bio rx-author-box__bio--empty">
					<p>
						<?php
						printf(
							esc_html__( '%s writes helpful, evidence-based, and reader-friendly articles for this website.', 'rx-theme' ),
							esc_html( $rx_author_name )
						);
						?>
					</p>
				</div>
			<?php endif; ?>

			<?php if ( ! empty( $rx_author_verified_text ) ) : ?>
				<div class="rx-author-box__verification-note">
					<?php echo wp_kses_post( wpautop( $rx_author_verified_text ) ); ?>
				</div>
			<?php endif; ?>

			<?php if ( $rx_show_stats ) : ?>
				<div class="rx-author-box__stats" aria-label="<?php echo esc_attr__( 'Author statistics', 'rx-theme' ); ?>">
					<span class="rx-author-box__stat rx-author-box__stat--posts">
						<strong><?php echo esc_html( number_format_i18n( $rx_author_posts_count ) ); ?></strong>
						<?php echo esc_html( _n( 'Published article', 'Published articles', $rx_author_posts_count, 'rx-theme' ) ); ?>
					</span>

					<?php if ( ! empty( $rx_author_updated_profile ) ) : ?>
						<span class="rx-author-box__stat rx-author-box__stat--updated">
							<?php esc_html_e( 'Profile updated:', 'rx-theme' ); ?>
							<strong><?php echo esc_html( $rx_author_updated_profile ); ?></strong>
						</span>
					<?php endif; ?>
				</div>
			<?php endif; ?>

			<?php if ( $rx_show_social ) : ?>
				<?php
				$rx_has_social_links = false;

				foreach ( $rx_social_profiles as $rx_social_data ) {
					if ( ! empty( $rx_social_data['url'] ) ) {
						$rx_has_social_links = true;
						break;
					}
				}
				?>

				<?php if ( $rx_has_social_links ) : ?>
					<nav class="rx-author-box__social" aria-label="<?php echo esc_attr__( 'Author social links', 'rx-theme' ); ?>">
						<ul class="rx-author-box__social-list">
							<?php foreach ( $rx_social_profiles as $rx_social_key => $rx_social_data ) : ?>
								<?php
								if ( empty( $rx_social_data['url'] ) ) {
									continue;
								}

								$rx_social_label = ! empty( $rx_social_data['label'] ) ? $rx_social_data['label'] : ucfirst( $rx_social_key );
								$rx_social_url   = $rx_social_data['url'];
								?>

								<li class="rx-author-box__social-item rx-author-box__social-item--<?php echo esc_attr( sanitize_html_class( $rx_social_key ) ); ?>">
									<a
										class="rx-author-box__social-link"
										href="<?php echo esc_url( $rx_social_url ); ?>"
										target="_blank"
										rel="nofollow noopener noreferrer me"
										itemprop="sameAs"
									>
										<span class="rx-author-box__social-text">
											<?php echo esc_html( $rx_social_label ); ?>
										</span>
									</a>
								</li>
							<?php endforeach; ?>
						</ul>
					</nav>
				<?php endif; ?>
			<?php endif; ?>

			<div class="rx-author-box__actions">

				<a
					class="rx-author-box__button rx-author-box__button--archive"
					href="<?php echo esc_url( $rx_author_archive_url ); ?>"
				>
					<?php
					printf(
						esc_html__( 'View all posts by %s', 'rx-theme' ),
						esc_html( $rx_author_name )
					);
					?>
				</a>

				<?php if ( ! empty( $rx_author_url ) ) : ?>
					<a
						class="rx-author-box__button rx-author-box__button--website"
						href="<?php echo esc_url( $rx_author_url ); ?>"
						target="_blank"
						rel="nofollow noopener noreferrer"
					>
						<?php esc_html_e( 'Visit website', 'rx-theme' ); ?>
					</a>
				<?php endif; ?>

				<?php if ( $rx_show_email && ! empty( $rx_author_email ) && is_email( $rx_author_email ) ) : ?>
					<a
						class="rx-author-box__button rx-author-box__button--email"
						href="<?php echo esc_url( 'mailto:' . antispambot( $rx_author_email ) ); ?>"
					>
						<?php esc_html_e( 'Contact author', 'rx-theme' ); ?>
					</a>
				<?php endif; ?>

			</div>

			<?php if ( ! empty( $rx_latest_posts ) ) : ?>
				<div class="rx-author-box__latest">
					<h3 class="rx-author-box__latest-title">
						<?php esc_html_e( 'More articles by this author', 'rx-theme' ); ?>
					</h3>

					<ul class="rx-author-box__latest-list">
						<?php foreach ( $rx_latest_posts as $rx_latest_post ) : ?>
							<li class="rx-author-box__latest-item">
								<a
									class="rx-author-box__latest-link"
									href="<?php echo esc_url( $rx_latest_post['url'] ); ?>"
								>
									<?php echo esc_html( $rx_latest_post['title'] ); ?>
								</a>

								<?php if ( ! empty( $rx_latest_post['date'] ) ) : ?>
									<span class="rx-author-box__latest-date">
										<?php echo esc_html( $rx_latest_post['date'] ); ?>
									</span>
								<?php endif; ?>
							</li>
						<?php endforeach; ?>
					</ul>
				</div>
			<?php endif; ?>

		</div>
	</div>

	<?php if ( ! empty( $rx_author_schema ) ) : ?>
		<script type="application/ld+json">
			<?php
			echo wp_json_encode(
				$rx_author_schema,
				JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
			);
			?>
		</script>
	<?php endif; ?>

</section>

<?php do_action( 'rx_theme_after_author_box', $rx_author_id, $rx_post_id ); ?>

To show it inside your single.php, add this where you want the author box to appear:

<?php get_template_part( 'template-parts/post/author-box' ); ?>

Best position is usually after post content and before related posts:

<?php the_content(); ?>

<?php get_template_part( 'template-parts/post/author-box' ); ?>

<?php get_template_part( 'template-parts/post/related-posts' ); ?>

You can later add custom user fields like:

rx_author_job_title
rx_author_company
rx_author_location
rx_author_specialty
rx_author_credentials
rx_author_verified
rx_author_verified_text
rx_author_updated_profile
facebook
twitter
linkedin
instagram
youtube
github

This file is already safe, expandable, SEO-friendly, and suitable for a serious medical/blog theme.

Leave a Reply

Your email address will not be published. Required fields are marked *