content-page.php

I’ll build this as a full-featured WordPress theme template part for template-parts/content/content-page.php, focused on safe theme functions, accessibility, SEO markup, pagination, edit links, comments support, featured image, breadcrumbs hook compatibility, schema-friendly structure, and extension hooks.

Yes friend — for rx-theme/template-parts/content/content-page.php, you can make it very powerful. This file should mainly display page content, not register theme features. So I added many safe frontend functions: accessibility, schema markup, featured image, page meta, breadcrumbs hook, reading time hook compatibility, share hooks, table of contents hook area, child-page section hook, comments support, edit link, multipage pagination, password-protected handling, and many custom action/filter hooks.

WordPress template parts are designed for reusable theme sections, and functions like the_content(), wp_link_pages(), post_class(), the_post_thumbnail(), and edit_post_link() are standard theme-template tools.

Create this file:

rx-theme/template-parts/content/content-page.php

Then paste this full code:

<?php
/**
 * Template part for displaying single Page content.
 *
 * File: template-parts/content/content-page.php
 *
 * This file is intentionally advanced but safe:
 * - Semantic HTML5 article structure
 * - Accessibility-ready skip anchors and ARIA labels
 * - Schema.org WebPage / Article-like microdata
 * - Featured image support
 * - Breadcrumb hook support
 * - Reading-time hook support
 * - Page meta support
 * - Multipage pagination
 * - Password protected page handling
 * - Comments support
 * - Edit link
 * - Child page / related content hook areas
 * - Social share hook area
 * - Table of contents hook area
 * - Multiple WordPress filters/actions for future expansion
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

$post_id = get_the_ID();

if ( ! $post_id ) {
	return;
}

/**
 * Basic page data.
 */
$page_title       = get_the_title( $post_id );
$page_permalink   = get_permalink( $post_id );
$page_excerpt     = has_excerpt( $post_id ) ? get_the_excerpt( $post_id ) : '';
$page_author_id   = (int) get_post_field( 'post_author', $post_id );
$page_author_name = $page_author_id ? get_the_author_meta( 'display_name', $page_author_id ) : '';
$page_modified    = get_the_modified_time( DATE_W3C, $post_id );
$page_published   = get_the_date( DATE_W3C, $post_id );

/**
 * Template display options.
 * You can control these later from functions.php by using filters.
 */
$rx_show_title = apply_filters( 'rx_theme_content_page_show_title', true, $post_id );
$rx_show_featured_image = apply_filters(
	'rx_theme_content_page_show_featured_image',
	has_post_thumbnail( $post_id ),
	$post_id
);
$rx_show_excerpt = apply_filters(
	'rx_theme_content_page_show_excerpt',
	! empty( $page_excerpt ),
	$post_id
);
$rx_show_meta = apply_filters( 'rx_theme_content_page_show_meta', true, $post_id );
$rx_show_author = apply_filters( 'rx_theme_content_page_show_author', true, $post_id );
$rx_show_dates = apply_filters( 'rx_theme_content_page_show_dates', true, $post_id );
$rx_show_breadcrumbs = apply_filters( 'rx_theme_content_page_show_breadcrumbs', true, $post_id );
$rx_show_toc = apply_filters( 'rx_theme_content_page_show_toc', true, $post_id );
$rx_show_share = apply_filters( 'rx_theme_content_page_show_share', true, $post_id );
$rx_show_child_pages = apply_filters( 'rx_theme_content_page_show_child_pages', true, $post_id );
$rx_show_comments = apply_filters( 'rx_theme_content_page_show_comments', true, $post_id );
$rx_show_edit_link = apply_filters( 'rx_theme_content_page_show_edit_link', true, $post_id );

/**
 * CSS class control.
 */
$rx_article_classes = array(
	'rx-page',
	'rx-page-content',
	'rx-entry',
	'rx-content-page',
);

if ( is_page_template() ) {
	$rx_article_classes[] = 'rx-page-has-template';
}

if ( has_post_thumbnail( $post_id ) ) {
	$rx_article_classes[] = 'rx-page-has-thumbnail';
} else {
	$rx_article_classes[] = 'rx-page-no-thumbnail';
}

if ( post_password_required( $post_id ) ) {
	$rx_article_classes[] = 'rx-page-password-required';
}

$rx_article_classes = apply_filters( 'rx_theme_content_page_article_classes', $rx_article_classes, $post_id );

/**
 * Image size.
 */
$rx_featured_image_size = apply_filters( 'rx_theme_content_page_featured_image_size', 'large', $post_id );

/**
 * Schema type.
 */
$rx_schema_type = apply_filters( 'rx_theme_content_page_schema_type', 'WebPage', $post_id );

?>

<article
	id="post-<?php the_ID(); ?>"
	<?php post_class( $rx_article_classes ); ?>
	itemscope
	itemtype="https://schema.org/<?php echo esc_attr( $rx_schema_type ); ?>"
>

	<?php
	/**
	 * Before page article.
	 *
	 * Useful for ads, notices, custom hero sections, SEO blocks, etc.
	 */
	do_action( 'rx_theme_before_content_page_article', $post_id );
	?>

	<meta itemprop="mainEntityOfPage" content="<?php echo esc_url( $page_permalink ); ?>">
	<meta itemprop="url" content="<?php echo esc_url( $page_permalink ); ?>">
	<meta itemprop="datePublished" content="<?php echo esc_attr( $page_published ); ?>">
	<meta itemprop="dateModified" content="<?php echo esc_attr( $page_modified ); ?>">

	<?php if ( $page_author_name ) : ?>
		<meta itemprop="author" content="<?php echo esc_attr( $page_author_name ); ?>">
	<?php endif; ?>

	<?php if ( $rx_show_breadcrumbs ) : ?>
		<nav class="rx-page-breadcrumbs" aria-label="<?php echo esc_attr_x( 'Breadcrumb', 'breadcrumb aria label', 'rx-theme' ); ?>">
			<?php
			/**
			 * Breadcrumb compatibility.
			 *
			 * You can connect your own breadcrumb function in functions.php:
			 *
			 * add_action( 'rx_theme_content_page_breadcrumbs', 'rx_theme_breadcrumbs' );
			 */
			do_action( 'rx_theme_content_page_breadcrumbs', $post_id );
			?>
		</nav>
	<?php endif; ?>

	<header class="rx-page-header entry-header">

		<?php
		/**
		 * Before page header content.
		 */
		do_action( 'rx_theme_before_content_page_header', $post_id );
		?>

		<?php if ( $rx_show_title ) : ?>
			<?php
			the_title(
				'<h1 class="rx-page-title entry-title" itemprop="headline">',
				'</h1>'
			);
			?>
		<?php endif; ?>

		<?php if ( $rx_show_excerpt && ! post_password_required( $post_id ) ) : ?>
			<div class="rx-page-excerpt entry-summary" itemprop="description">
				<?php echo wp_kses_post( wpautop( $page_excerpt ) ); ?>
			</div>
		<?php endif; ?>

		<?php if ( $rx_show_meta ) : ?>
			<div class="rx-page-meta rx-entry-meta" aria-label="<?php echo esc_attr_x( 'Page information', 'page meta aria label', 'rx-theme' ); ?>">

				<?php if ( $rx_show_author && $page_author_name ) : ?>
					<span class="rx-page-meta-item rx-page-author vcard">
						<span class="rx-page-meta-label">
							<?php echo esc_html_x( 'By', 'page author label', 'rx-theme' ); ?>
						</span>
						<span class="rx-page-meta-value fn" itemprop="author">
							<?php echo esc_html( $page_author_name ); ?>
						</span>
					</span>
				<?php endif; ?>

				<?php if ( $rx_show_dates ) : ?>
					<span class="rx-page-meta-item rx-page-published">
						<span class="rx-page-meta-label">
							<?php echo esc_html_x( 'Published', 'published date label', 'rx-theme' ); ?>
						</span>
						<time datetime="<?php echo esc_attr( $page_published ); ?>" itemprop="datePublished">
							<?php echo esc_html( get_the_date( '', $post_id ) ); ?>
						</time>
					</span>

					<?php if ( get_the_modified_time( 'U', $post_id ) !== get_the_time( 'U', $post_id ) ) : ?>
						<span class="rx-page-meta-item rx-page-updated">
							<span class="rx-page-meta-label">
								<?php echo esc_html_x( 'Updated', 'updated date label', 'rx-theme' ); ?>
							</span>
							<time datetime="<?php echo esc_attr( $page_modified ); ?>" itemprop="dateModified">
								<?php echo esc_html( get_the_modified_date( '', $post_id ) ); ?>
							</time>
						</span>
					<?php endif; ?>
				<?php endif; ?>

				<?php
				/**
				 * Reading time or custom meta.
				 *
				 * Example:
				 * add_action( 'rx_theme_content_page_meta', 'rx_theme_reading_time' );
				 */
				do_action( 'rx_theme_content_page_meta', $post_id );
				?>

			</div>
		<?php endif; ?>

		<?php
		/**
		 * After page header content.
		 */
		do_action( 'rx_theme_after_content_page_header', $post_id );
		?>

	</header>

	<?php if ( $rx_show_featured_image && has_post_thumbnail( $post_id ) && ! post_password_required( $post_id ) ) : ?>
		<figure class="rx-page-featured-image post-thumbnail" itemprop="image" itemscope itemtype="https://schema.org/ImageObject">
			<?php
			echo get_the_post_thumbnail(
				$post_id,
				$rx_featured_image_size,
				array(
					'class'    => 'rx-page-thumbnail-img',
					'loading'  => apply_filters( 'rx_theme_content_page_featured_image_loading', 'eager', $post_id ),
					'decoding' => 'async',
					'alt'      => esc_attr( get_post_meta( get_post_thumbnail_id( $post_id ), '_wp_attachment_image_alt', true ) ?: $page_title ),
				)
			);

			$rx_thumbnail_id  = get_post_thumbnail_id( $post_id );
			$rx_thumbnail_url = $rx_thumbnail_id ? wp_get_attachment_image_url( $rx_thumbnail_id, 'full' ) : '';

			if ( $rx_thumbnail_url ) :
				?>
				<meta itemprop="url" content="<?php echo esc_url( $rx_thumbnail_url ); ?>">
			<?php endif; ?>

			<?php
			$rx_caption = get_the_post_thumbnail_caption( $post_id );

			if ( $rx_caption ) :
				?>
				<figcaption class="rx-page-featured-caption wp-caption-text">
					<?php echo wp_kses_post( $rx_caption ); ?>
				</figcaption>
			<?php endif; ?>
		</figure>
	<?php endif; ?>

	<?php
	/**
	 * Before page body.
	 */
	do_action( 'rx_theme_before_content_page_body', $post_id );
	?>

	<?php if ( $rx_show_toc && ! post_password_required( $post_id ) ) : ?>
		<aside class="rx-page-toc" aria-label="<?php echo esc_attr_x( 'Table of contents', 'toc aria label', 'rx-theme' ); ?>">
			<?php
			/**
			 * Table of contents hook.
			 *
			 * Add your TOC function from functions.php or plugin.
			 */
			do_action( 'rx_theme_content_page_toc', $post_id );
			?>
		</aside>
	<?php endif; ?>

	<div class="rx-page-body entry-content" itemprop="text">

		<?php
		/**
		 * Before the_content().
		 */
		do_action( 'rx_theme_before_content_page_content', $post_id );

		if ( post_password_required( $post_id ) ) :
			?>
			<div class="rx-page-password-form">
				<?php echo get_the_password_form( $post_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
			</div>
			<?php
		else :
			the_content(
				sprintf(
					wp_kses(
						/* translators: %s: Page title. */
						__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'rx-theme' ),
						array(
							'span' => array(
								'class' => array(),
							),
						)
					),
					esc_html( $page_title )
				)
			);

			wp_link_pages(
				array(
					'before'           => '<nav class="rx-page-links page-links" aria-label="' . esc_attr__( 'Page navigation', 'rx-theme' ) . '"><span class="rx-page-links-title">' . esc_html__( 'Pages:', 'rx-theme' ) . '</span>',
					'after'            => '</nav>',
					'link_before'      => '<span class="rx-page-link-number">',
					'link_after'       => '</span>',
					'next_or_number'   => 'number',
					'separator'        => '<span class="rx-page-links-separator"> </span>',
					'pagelink'         => '<span class="screen-reader-text">' . esc_html__( 'Page', 'rx-theme' ) . ' </span>%',
					'echo'             => 1,
				)
			);
		endif;

		/**
		 * After the_content().
		 */
		do_action( 'rx_theme_after_content_page_content', $post_id );
		?>

	</div>

	<?php if ( ! post_password_required( $post_id ) ) : ?>

		<?php if ( $rx_show_share ) : ?>
			<section class="rx-page-share" aria-label="<?php echo esc_attr_x( 'Share this page', 'share section aria label', 'rx-theme' ); ?>">
				<?php
				/**
				 * Social share hook.
				 *
				 * You can add custom social share buttons here.
				 */
				do_action( 'rx_theme_content_page_share', $post_id );
				?>
			</section>
		<?php endif; ?>

		<?php if ( $rx_show_child_pages ) : ?>
			<section class="rx-page-child-pages" aria-label="<?php echo esc_attr_x( 'Related child pages', 'child pages aria label', 'rx-theme' ); ?>">
				<?php
				/**
				 * Child pages hook.
				 *
				 * You can connect a function that lists child pages.
				 */
				do_action( 'rx_theme_content_page_child_pages', $post_id );
				?>
			</section>
		<?php endif; ?>

	<?php endif; ?>

	<footer class="rx-page-footer entry-footer">

		<?php
		/**
		 * Before footer area.
		 */
		do_action( 'rx_theme_before_content_page_footer', $post_id );
		?>

		<?php if ( $rx_show_edit_link ) : ?>
			<?php
			edit_post_link(
				sprintf(
					wp_kses(
						/* translators: %s: Page title. */
						__( 'Edit <span class="screen-reader-text">%s</span>', 'rx-theme' ),
						array(
							'span' => array(
								'class' => array(),
							),
						)
					),
					esc_html( $page_title )
				),
				'<span class="rx-edit-link edit-link">',
				'</span>'
			);
			?>
		<?php endif; ?>

		<?php
		/**
		 * After footer area.
		 */
		do_action( 'rx_theme_after_content_page_footer', $post_id );
		?>

	</footer>

	<?php
	/**
	 * After page article.
	 */
	do_action( 'rx_theme_after_content_page_article', $post_id );
	?>

</article>

<?php
/**
 * Comments area.
 *
 * Page comments are shown only when comments are open or when the page already has comments.
 */
if (
	$rx_show_comments
	&& ! post_password_required( $post_id )
	&& ( comments_open( $post_id ) || get_comments_number( $post_id ) )
) :
	?>
	<section class="rx-page-comments-area" id="comments-area" aria-label="<?php echo esc_attr_x( 'Page comments', 'comments area aria label', 'rx-theme' ); ?>">
		<?php comments_template(); ?>
	</section>
	<?php
endif;

Add this optional CSS to style.css:

/* RX Page Content Template */
.rx-page {
	width: 100%;
	max-width: var(--rx-content-width, 920px);
	margin-inline: auto;
	padding-inline: var(--rx-content-padding, 1rem);
}

.rx-page-header {
	margin-bottom: 2rem;
}

.rx-page-title {
	margin: 0 0 1rem;
	line-height: 1.15;
}

.rx-page-excerpt {
	font-size: 1.125rem;
	line-height: 1.7;
	opacity: 0.85;
	margin-bottom: 1rem;
}

.rx-page-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem 1.25rem;
	font-size: 0.9375rem;
	opacity: 0.8;
	margin-bottom: 1.5rem;
}

.rx-page-meta-label {
	font-weight: 600;
	margin-right: 0.25rem;
}

.rx-page-featured-image {
	margin: 0 0 2rem;
}

.rx-page-thumbnail-img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--rx-radius-lg, 16px);
}

.rx-page-featured-caption {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	opacity: 0.75;
	text-align: center;
}

.rx-page-body {
	line-height: 1.8;
}

.rx-page-body > *:first-child {
	margin-top: 0;
}

.rx-page-body img {
	max-width: 100%;
	height: auto;
}

.rx-page-body iframe,
.rx-page-body video {
	max-width: 100%;
}

.rx-page-links {
	margin-top: 2rem;
	padding-top: 1rem;
	border-top: 1px solid currentColor;
}

.rx-page-links-title {
	font-weight: 700;
	margin-right: 0.75rem;
}

.rx-page-link-number {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2rem;
	min-height: 2rem;
	padding: 0.25rem 0.5rem;
	border: 1px solid currentColor;
	border-radius: 999px;
	text-decoration: none;
}

.rx-page-share,
.rx-page-child-pages,
.rx-page-footer,
.rx-page-comments-area {
	margin-top: 2rem;
}

.rx-edit-link a {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-weight: 600;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

Example use in page.php:

<?php
/**
 * Page template.
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

get_header();

?>

<main id="primary" class="site-main rx-site-main">

	<?php
	while ( have_posts() ) :
		the_post();

		get_template_part( 'template-parts/content/content', 'page' );

	endwhile;
	?>

</main>

<?php
get_footer();

This is a strong advanced content-page.php, but keep heavy logic like sitemap, cache, preload, SEO meta registration, scripts, menus, sidebars, and image sizes inside functions.php or files inside inc/. This template part should stay focused on displaying page content cleanly.

Leave a Reply

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