template-functions.php

I will build this as a large, practical inc/helpers/template-functions.php for your RX theme: safe helpers, template tags, breadcrumbs, reading time, post meta, images, pagination, related posts, schema hooks, SEO-friendly utilities, and compatibility functions.

Below is an advanced template-functions.php file for your RX theme.

Place it here:

rx-theme/inc/helpers/template-functions.php

Then load it from functions.php:

require_once get_template_directory() . '/inc/helpers/template-functions.php';
<?php
/**
 * RX Theme Template Functions
 *
 * Advanced helper and template functions for RX Theme.
 *
 * File path:
 * inc/helpers/template-functions.php
 *
 * @package RX_Theme
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * ------------------------------------------------------------
 * 01. BASIC THEME HELPERS
 * ------------------------------------------------------------
 */

/**
 * Get theme version safely.
 */
if ( ! function_exists( 'rx_theme_version' ) ) {
	function rx_theme_version() {
		$theme = wp_get_theme();
		return $theme ? $theme->get( 'Version' ) : '1.0.0';
	}
}

/**
 * Get theme name safely.
 */
if ( ! function_exists( 'rx_theme_name' ) ) {
	function rx_theme_name() {
		$theme = wp_get_theme();
		return $theme ? $theme->get( 'Name' ) : 'RX Theme';
	}
}

/**
 * Get theme URI.
 */
if ( ! function_exists( 'rx_theme_uri' ) ) {
	function rx_theme_uri( $path = '' ) {
		$uri = get_template_directory_uri();

		if ( ! empty( $path ) ) {
			$uri .= '/' . ltrim( $path, '/' );
		}

		return esc_url( $uri );
	}
}

/**
 * Get theme path.
 */
if ( ! function_exists( 'rx_theme_path' ) ) {
	function rx_theme_path( $path = '' ) {
		$dir = get_template_directory();

		if ( ! empty( $path ) ) {
			$dir .= '/' . ltrim( $path, '/' );
		}

		return $dir;
	}
}

/**
 * Check if WooCommerce is active.
 */
if ( ! function_exists( 'rx_is_woocommerce_active' ) ) {
	function rx_is_woocommerce_active() {
		return class_exists( 'WooCommerce' );
	}
}

/**
 * Check if current page is WooCommerce page.
 */
if ( ! function_exists( 'rx_is_woocommerce_page' ) ) {
	function rx_is_woocommerce_page() {
		if ( ! rx_is_woocommerce_active() ) {
			return false;
		}

		return is_woocommerce() || is_cart() || is_checkout() || is_account_page();
	}
}

/**
 * Safe echo SVG icon.
 */
if ( ! function_exists( 'rx_icon' ) ) {
	function rx_icon( $name = '', $class = 'rx-icon' ) {
		$name  = sanitize_key( $name );
		$class = esc_attr( $class );

		$icons = array(
			'search' => '<svg class="' . $class . '" width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"><path d="M21 20l-5.2-5.2a7 7 0 10-1.4 1.4L20 21zM5 10a5 5 0 1110 0A5 5 0 015 10z" fill="currentColor"/></svg>',
			'menu'   => '<svg class="' . $class . '" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h18v2H3V6zm0 5h18v2H3v-2zm0 5h18v2H3v-2z" fill="currentColor"/></svg>',
			'close'  => '<svg class="' . $class . '" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true"><path d="M18.3 5.7L12 12l6.3 6.3-1.4 1.4L10.6 13.4 4.3 19.7 2.9 18.3 9.2 12 2.9 5.7 4.3 4.3l6.3 6.3 6.3-6.3z" fill="currentColor"/></svg>',
			'user'   => '<svg class="' . $class . '" width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 12a5 5 0 100-10 5 5 0 000 10zm0 2c-4.4 0-8 2.2-8 5v1h16v-1c0-2.8-3.6-5-8-5z" fill="currentColor"/></svg>',
			'date'   => '<svg class="' . $class . '" width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 2h2v2h6V2h2v2h3v18H4V4h3V2zm13 8H6v10h14V10z" fill="currentColor"/></svg>',
		);

		if ( isset( $icons[ $name ] ) ) {
			echo wp_kses(
				$icons[ $name ],
				array(
					'svg'  => array(
						'class'       => true,
						'width'       => true,
						'height'      => true,
						'viewBox'     => true,
						'aria-hidden' => true,
					),
					'path' => array(
						'd'    => true,
						'fill' => true,
					),
				)
			);
		}
	}
}

/**
 * ------------------------------------------------------------
 * 02. BODY, POST, AND LAYOUT CLASSES
 * ------------------------------------------------------------
 */

/**
 * Add advanced body classes.
 */
if ( ! function_exists( 'rx_body_classes' ) ) {
	function rx_body_classes( $classes ) {
		$classes[] = 'rx-theme';
		$classes[] = 'rx-version-' . sanitize_html_class( str_replace( '.', '-', rx_theme_version() ) );

		if ( is_front_page() ) {
			$classes[] = 'rx-front-page';
		}

		if ( is_home() ) {
			$classes[] = 'rx-blog-page';
		}

		if ( is_singular() ) {
			$classes[] = 'rx-singular';
		}

		if ( is_single() ) {
			$classes[] = 'rx-single-post';
		}

		if ( is_page() ) {
			$classes[] = 'rx-page';
		}

		if ( is_archive() ) {
			$classes[] = 'rx-archive';
		}

		if ( is_search() ) {
			$classes[] = 'rx-search-page';
		}

		if ( is_404() ) {
			$classes[] = 'rx-404-page';
		}

		if ( is_user_logged_in() ) {
			$classes[] = 'rx-user-logged-in';
		} else {
			$classes[] = 'rx-user-logged-out';
		}

		if ( has_nav_menu( 'primary' ) ) {
			$classes[] = 'rx-has-primary-menu';
		}

		if ( is_active_sidebar( 'sidebar-1' ) ) {
			$classes[] = 'rx-has-sidebar';
		} else {
			$classes[] = 'rx-no-sidebar';
		}

		if ( rx_is_woocommerce_page() ) {
			$classes[] = 'rx-woocommerce-page';
		}

		return $classes;
	}
}
add_filter( 'body_class', 'rx_body_classes' );

/**
 * Add custom post classes.
 */
if ( ! function_exists( 'rx_post_classes' ) ) {
	function rx_post_classes( $classes ) {
		if ( is_sticky() ) {
			$classes[] = 'rx-sticky-post';
		}

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

		$post_format = get_post_format();

		if ( $post_format ) {
			$classes[] = 'rx-format-' . sanitize_html_class( $post_format );
		}

		return $classes;
	}
}
add_filter( 'post_class', 'rx_post_classes' );

/**
 * ------------------------------------------------------------
 * 03. ACCESSIBILITY HELPERS
 * ------------------------------------------------------------
 */

/**
 * Skip link for accessibility.
 */
if ( ! function_exists( 'rx_skip_link' ) ) {
	function rx_skip_link() {
		echo '<a class="skip-link screen-reader-text" href="#primary">' . esc_html__( 'Skip to content', 'rx-theme' ) . '</a>';
	}
}
add_action( 'wp_body_open', 'rx_skip_link', 5 );

/**
 * Screen reader text.
 */
if ( ! function_exists( 'rx_screen_reader_text' ) ) {
	function rx_screen_reader_text( $text = '' ) {
		if ( empty( $text ) ) {
			return;
		}

		echo '<span class="screen-reader-text">' . esc_html( $text ) . '</span>';
	}
}

/**
 * ------------------------------------------------------------
 * 04. POST META FUNCTIONS
 * ------------------------------------------------------------
 */

/**
 * Posted on date.
 */
if ( ! function_exists( 'rx_posted_on' ) ) {
	function rx_posted_on() {
		$time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';

		if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
			$time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
		}

		$time_string = sprintf(
			$time_string,
			esc_attr( get_the_date( DATE_W3C ) ),
			esc_html( get_the_date() ),
			esc_attr( get_the_modified_date( DATE_W3C ) ),
			esc_html( get_the_modified_date() )
		);

		echo '<span class="posted-on">';
		rx_icon( 'date', 'rx-meta-icon' );
		echo '<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . wp_kses_post( $time_string ) . '</a>';
		echo '</span>';
	}
}

/**
 * Posted by author.
 */
if ( ! function_exists( 'rx_posted_by' ) ) {
	function rx_posted_by() {
		echo '<span class="byline">';
		rx_icon( 'user', 'rx-meta-icon' );
		echo '<span class="author vcard">';
		echo '<a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">';
		echo esc_html( get_the_author() );
		echo '</a>';
		echo '</span>';
		echo '</span>';
	}
}

/**
 * Display post categories.
 */
if ( ! function_exists( 'rx_post_categories' ) ) {
	function rx_post_categories( $before = '', $after = '' ) {
		if ( 'post' !== get_post_type() ) {
			return;
		}

		$categories = get_the_category_list( esc_html__( ', ', 'rx-theme' ) );

		if ( $categories ) {
			echo wp_kses_post( $before );
			echo '<span class="cat-links">';
			echo wp_kses_post( $categories );
			echo '</span>';
			echo wp_kses_post( $after );
		}
	}
}

/**
 * Display post tags.
 */
if ( ! function_exists( 'rx_post_tags' ) ) {
	function rx_post_tags( $before = '', $after = '' ) {
		if ( 'post' !== get_post_type() ) {
			return;
		}

		$tags = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'rx-theme' ) );

		if ( $tags ) {
			echo wp_kses_post( $before );
			echo '<span class="tags-links">';
			echo wp_kses_post( $tags );
			echo '</span>';
			echo wp_kses_post( $after );
		}
	}
}

/**
 * Comments link.
 */
if ( ! function_exists( 'rx_comments_link' ) ) {
	function rx_comments_link() {
		if ( ! post_password_required() && ( comments_open() || get_comments_number() ) ) {
			echo '<span class="comments-link">';
			comments_popup_link(
				esc_html__( 'Leave a comment', 'rx-theme' ),
				esc_html__( '1 Comment', 'rx-theme' ),
				esc_html__( '% Comments', 'rx-theme' )
			);
			echo '</span>';
		}
	}
}

/**
 * Full post meta.
 */
if ( ! function_exists( 'rx_entry_meta' ) ) {
	function rx_entry_meta() {
		echo '<div class="entry-meta rx-entry-meta">';
		rx_posted_on();
		rx_posted_by();
		rx_comments_link();
		echo '</div>';
	}
}

/**
 * Entry footer.
 */
if ( ! function_exists( 'rx_entry_footer' ) ) {
	function rx_entry_footer() {
		echo '<footer class="entry-footer rx-entry-footer">';

		rx_post_categories(
			'<div class="rx-post-categories"><span class="rx-meta-label">' . esc_html__( 'Categories:', 'rx-theme' ) . '</span> ',
			'</div>'
		);

		rx_post_tags(
			'<div class="rx-post-tags"><span class="rx-meta-label">' . esc_html__( 'Tags:', 'rx-theme' ) . '</span> ',
			'</div>'
		);

		edit_post_link(
			sprintf(
				wp_kses(
					__( 'Edit <span class="screen-reader-text">%s</span>', 'rx-theme' ),
					array(
						'span' => array(
							'class' => array(),
						),
					)
				),
				wp_kses_post( get_the_title() )
			),
			'<span class="edit-link">',
			'</span>'
		);

		echo '</footer>';
	}
}

/**
 * ------------------------------------------------------------
 * 05. EXCERPT HELPERS
 * ------------------------------------------------------------
 */

/**
 * Custom excerpt length.
 */
if ( ! function_exists( 'rx_excerpt_length' ) ) {
	function rx_excerpt_length( $length ) {
		return 28;
	}
}
add_filter( 'excerpt_length', 'rx_excerpt_length', 20 );

/**
 * Custom excerpt more.
 */
if ( ! function_exists( 'rx_excerpt_more' ) ) {
	function rx_excerpt_more( $more ) {
		return '&hellip;';
	}
}
add_filter( 'excerpt_more', 'rx_excerpt_more' );

/**
 * Get trimmed excerpt.
 */
if ( ! function_exists( 'rx_get_excerpt' ) ) {
	function rx_get_excerpt( $post_id = null, $length = 30 ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( ! $post_id ) {
			return '';
		}

		$post = get_post( $post_id );

		if ( ! $post ) {
			return '';
		}

		if ( has_excerpt( $post_id ) ) {
			$text = get_the_excerpt( $post_id );
		} else {
			$text = wp_strip_all_tags( strip_shortcodes( $post->post_content ) );
		}

		return wp_trim_words( $text, absint( $length ), '&hellip;' );
	}
}

/**
 * Print excerpt.
 */
if ( ! function_exists( 'rx_the_excerpt' ) ) {
	function rx_the_excerpt( $length = 30 ) {
		echo esc_html( rx_get_excerpt( get_the_ID(), $length ) );
	}
}

/**
 * Read more button.
 */
if ( ! function_exists( 'rx_read_more_button' ) ) {
	function rx_read_more_button( $text = '' ) {
		if ( empty( $text ) ) {
			$text = esc_html__( 'Read More', 'rx-theme' );
		}

		echo '<a class="rx-read-more button" href="' . esc_url( get_permalink() ) . '" aria-label="' . esc_attr( sprintf( __( 'Read more about %s', 'rx-theme' ), get_the_title() ) ) . '">';
		echo esc_html( $text );
		echo '</a>';
	}
}

/**
 * ------------------------------------------------------------
 * 06. READING TIME AND WORD COUNT
 * ------------------------------------------------------------
 */

/**
 * Get word count.
 */
if ( ! function_exists( 'rx_get_word_count' ) ) {
	function rx_get_word_count( $post_id = null ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( ! $post_id ) {
			return 0;
		}

		$content = get_post_field( 'post_content', $post_id );
		$content = wp_strip_all_tags( strip_shortcodes( $content ) );

		return str_word_count( $content );
	}
}

/**
 * Get reading time.
 */
if ( ! function_exists( 'rx_get_reading_time' ) ) {
	function rx_get_reading_time( $post_id = null, $words_per_minute = 200 ) {
		$word_count = rx_get_word_count( $post_id );
		$minutes    = ceil( $word_count / absint( $words_per_minute ) );

		return max( 1, $minutes );
	}
}

/**
 * Print reading time.
 */
if ( ! function_exists( 'rx_reading_time' ) ) {
	function rx_reading_time( $post_id = null ) {
		$minutes = rx_get_reading_time( $post_id );

		echo '<span class="rx-reading-time">';
		echo esc_html(
			sprintf(
				_n( '%s minute read', '%s minutes read', $minutes, 'rx-theme' ),
				number_format_i18n( $minutes )
			)
		);
		echo '</span>';
	}
}

/**
 * Print word count.
 */
if ( ! function_exists( 'rx_word_count' ) ) {
	function rx_word_count( $post_id = null ) {
		$count = rx_get_word_count( $post_id );

		echo '<span class="rx-word-count">';
		echo esc_html(
			sprintf(
				_n( '%s word', '%s words', $count, 'rx-theme' ),
				number_format_i18n( $count )
			)
		);
		echo '</span>';
	}
}

/**
 * ------------------------------------------------------------
 * 07. FEATURED IMAGE HELPERS
 * ------------------------------------------------------------
 */

/**
 * Get fallback image URL.
 */
if ( ! function_exists( 'rx_get_fallback_image_url' ) ) {
	function rx_get_fallback_image_url() {
		$fallback = rx_theme_uri( 'assets/images/fallback.jpg' );

		return apply_filters( 'rx_fallback_image_url', $fallback );
	}
}

/**
 * Get post thumbnail URL with fallback.
 */
if ( ! function_exists( 'rx_get_thumbnail_url' ) ) {
	function rx_get_thumbnail_url( $post_id = null, $size = 'large' ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( has_post_thumbnail( $post_id ) ) {
			return get_the_post_thumbnail_url( $post_id, $size );
		}

		return rx_get_fallback_image_url();
	}
}

/**
 * Display post thumbnail with lazy loading.
 */
if ( ! function_exists( 'rx_post_thumbnail' ) ) {
	function rx_post_thumbnail( $size = 'large', $class = 'rx-post-thumbnail' ) {
		if ( post_password_required() || is_attachment() ) {
			return;
		}

		$class = esc_attr( $class );

		echo '<div class="' . $class . '">';

		if ( is_singular() ) {
			if ( has_post_thumbnail() ) {
				the_post_thumbnail(
					$size,
					array(
						'class'    => 'rx-featured-image',
						'loading'  => 'eager',
						'decoding' => 'async',
					)
				);
			}
		} else {
			echo '<a href="' . esc_url( get_permalink() ) . '" aria-hidden="true" tabindex="-1">';

			if ( has_post_thumbnail() ) {
				the_post_thumbnail(
					$size,
					array(
						'class'    => 'rx-featured-image',
						'loading'  => 'lazy',
						'decoding' => 'async',
					)
				);
			} else {
				echo '<img class="rx-featured-image rx-fallback-image" src="' . esc_url( rx_get_fallback_image_url() ) . '" alt="' . esc_attr( get_the_title() ) . '" loading="lazy" decoding="async">';
			}

			echo '</a>';
		}

		echo '</div>';
	}
}

/**
 * ------------------------------------------------------------
 * 08. TITLE HELPERS
 * ------------------------------------------------------------
 */

/**
 * Archive title cleanup.
 */
if ( ! function_exists( 'rx_archive_title' ) ) {
	function rx_archive_title( $title ) {
		if ( is_category() ) {
			$title = single_cat_title( '', false );
		} elseif ( is_tag() ) {
			$title = single_tag_title( '', false );
		} elseif ( is_author() ) {
			$title = get_the_author();
		} elseif ( is_post_type_archive() ) {
			$title = post_type_archive_title( '', false );
		} elseif ( is_tax() ) {
			$title = single_term_title( '', false );
		}

		return $title;
	}
}
add_filter( 'get_the_archive_title', 'rx_archive_title' );

/**
 * Page header title.
 */
if ( ! function_exists( 'rx_page_title' ) ) {
	function rx_page_title() {
		if ( is_home() && ! is_front_page() ) {
			echo esc_html( single_post_title( '', false ) );
		} elseif ( is_front_page() ) {
			echo esc_html( get_bloginfo( 'name' ) );
		} elseif ( is_archive() ) {
			the_archive_title();
		} elseif ( is_search() ) {
			printf(
				esc_html__( 'Search Results for: %s', 'rx-theme' ),
				'<span>' . esc_html( get_search_query() ) . '</span>'
			);
		} elseif ( is_404() ) {
			esc_html_e( 'Page Not Found', 'rx-theme' );
		} else {
			the_title();
		}
	}
}

/**
 * ------------------------------------------------------------
 * 09. BREADCRUMBS
 * ------------------------------------------------------------
 */

/**
 * Display breadcrumbs.
 */
if ( ! function_exists( 'rx_breadcrumbs' ) ) {
	function rx_breadcrumbs() {
		if ( is_front_page() ) {
			return;
		}

		echo '<nav class="rx-breadcrumbs" aria-label="' . esc_attr__( 'Breadcrumb', 'rx-theme' ) . '">';
		echo '<ol class="rx-breadcrumb-list">';

		echo '<li class="rx-breadcrumb-item">';
		echo '<a href="' . esc_url( home_url( '/' ) ) . '">' . esc_html__( 'Home', 'rx-theme' ) . '</a>';
		echo '</li>';

		if ( is_home() ) {
			echo '<li class="rx-breadcrumb-item current">' . esc_html__( 'Blog', 'rx-theme' ) . '</li>';
		} elseif ( is_category() || is_tag() || is_tax() ) {
			$term = get_queried_object();

			if ( $term && ! is_wp_error( $term ) ) {
				if ( ! empty( $term->parent ) ) {
					$parents = get_ancestors( $term->term_id, $term->taxonomy );

					if ( ! empty( $parents ) ) {
						$parents = array_reverse( $parents );

						foreach ( $parents as $parent_id ) {
							$parent = get_term( $parent_id, $term->taxonomy );

							if ( $parent && ! is_wp_error( $parent ) ) {
								echo '<li class="rx-breadcrumb-item">';
								echo '<a href="' . esc_url( get_term_link( $parent ) ) . '">' . esc_html( $parent->name ) . '</a>';
								echo '</li>';
							}
						}
					}
				}

				echo '<li class="rx-breadcrumb-item current">' . esc_html( $term->name ) . '</li>';
			}
		} elseif ( is_single() ) {
			$categories = get_the_category();

			if ( ! empty( $categories ) ) {
				$category = $categories[0];

				echo '<li class="rx-breadcrumb-item">';
				echo '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '">' . esc_html( $category->name ) . '</a>';
				echo '</li>';
			}

			echo '<li class="rx-breadcrumb-item current">' . esc_html( get_the_title() ) . '</li>';
		} elseif ( is_page() ) {
			$post = get_post();

			if ( $post && $post->post_parent ) {
				$parents = array_reverse( get_post_ancestors( $post->ID ) );

				foreach ( $parents as $parent_id ) {
					echo '<li class="rx-breadcrumb-item">';
					echo '<a href="' . esc_url( get_permalink( $parent_id ) ) . '">' . esc_html( get_the_title( $parent_id ) ) . '</a>';
					echo '</li>';
				}
			}

			echo '<li class="rx-breadcrumb-item current">' . esc_html( get_the_title() ) . '</li>';
		} elseif ( is_search() ) {
			echo '<li class="rx-breadcrumb-item current">' . esc_html__( 'Search', 'rx-theme' ) . '</li>';
		} elseif ( is_404() ) {
			echo '<li class="rx-breadcrumb-item current">' . esc_html__( '404', 'rx-theme' ) . '</li>';
		} elseif ( is_author() ) {
			echo '<li class="rx-breadcrumb-item current">' . esc_html( get_the_author() ) . '</li>';
		} elseif ( is_date() ) {
			echo '<li class="rx-breadcrumb-item current">' . esc_html( get_the_date() ) . '</li>';
		}

		echo '</ol>';
		echo '</nav>';
	}
}

/**
 * ------------------------------------------------------------
 * 10. PAGINATION
 * ------------------------------------------------------------
 */

/**
 * Numeric pagination.
 */
if ( ! function_exists( 'rx_pagination' ) ) {
	function rx_pagination( $query = null ) {
		global $wp_query;

		$query = $query ? $query : $wp_query;

		if ( ! $query || $query->max_num_pages <= 1 ) {
			return;
		}

		$big = 999999999;

		$links = paginate_links(
			array(
				'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
				'format'    => '?paged=%#%',
				'current'   => max( 1, get_query_var( 'paged' ) ),
				'total'     => $query->max_num_pages,
				'type'      => 'list',
				'prev_text' => esc_html__( 'Previous', 'rx-theme' ),
				'next_text' => esc_html__( 'Next', 'rx-theme' ),
			)
		);

		if ( $links ) {
			echo '<nav class="rx-pagination" aria-label="' . esc_attr__( 'Posts pagination', 'rx-theme' ) . '">';
			echo wp_kses_post( $links );
			echo '</nav>';
		}
	}
}

/**
 * Previous and next post navigation.
 */
if ( ! function_exists( 'rx_post_navigation' ) ) {
	function rx_post_navigation() {
		if ( ! is_single() ) {
			return;
		}

		the_post_navigation(
			array(
				'prev_text' => '<span class="nav-subtitle">' . esc_html__( 'Previous:', 'rx-theme' ) . '</span> <span class="nav-title">%title</span>',
				'next_text' => '<span class="nav-subtitle">' . esc_html__( 'Next:', 'rx-theme' ) . '</span> <span class="nav-title">%title</span>',
			)
		);
	}
}

/**
 * ------------------------------------------------------------
 * 11. RELATED POSTS
 * ------------------------------------------------------------
 */

/**
 * Get related posts.
 */
if ( ! function_exists( 'rx_get_related_posts' ) ) {
	function rx_get_related_posts( $post_id = null, $limit = 3 ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( ! $post_id ) {
			return false;
		}

		$categories = wp_get_post_categories( $post_id );

		if ( empty( $categories ) ) {
			return false;
		}

		$args = array(
			'post_type'           => 'post',
			'post_status'         => 'publish',
			'posts_per_page'      => absint( $limit ),
			'post__not_in'        => array( $post_id ),
			'ignore_sticky_posts' => true,
			'category__in'        => $categories,
			'no_found_rows'       => true,
		);

		return new WP_Query( $args );
	}
}

/**
 * Display related posts.
 */
if ( ! function_exists( 'rx_related_posts' ) ) {
	function rx_related_posts( $post_id = null, $limit = 3 ) {
		$related = rx_get_related_posts( $post_id, $limit );

		if ( ! $related || ! $related->have_posts() ) {
			return;
		}

		echo '<section class="rx-related-posts">';
		echo '<h2 class="rx-related-title">' . esc_html__( 'Related Posts', 'rx-theme' ) . '</h2>';
		echo '<div class="rx-related-grid">';

		while ( $related->have_posts() ) {
			$related->the_post();

			echo '<article class="rx-related-card">';
			echo '<a href="' . esc_url( get_permalink() ) . '" class="rx-related-link">';

			if ( has_post_thumbnail() ) {
				the_post_thumbnail(
					'medium',
					array(
						'class'    => 'rx-related-image',
						'loading'  => 'lazy',
						'decoding' => 'async',
					)
				);
			}

			echo '<h3 class="rx-related-post-title">' . esc_html( get_the_title() ) . '</h3>';
			echo '</a>';
			echo '</article>';
		}

		echo '</div>';
		echo '</section>';

		wp_reset_postdata();
	}
}

/**
 * ------------------------------------------------------------
 * 12. AUTHOR BOX
 * ------------------------------------------------------------
 */

/**
 * Display author box.
 */
if ( ! function_exists( 'rx_author_box' ) ) {
	function rx_author_box() {
		if ( ! is_single() ) {
			return;
		}

		$author_id   = get_the_author_meta( 'ID' );
		$description = get_the_author_meta( 'description', $author_id );

		echo '<section class="rx-author-box">';
		echo '<div class="rx-author-avatar">';
		echo get_avatar( $author_id, 96 );
		echo '</div>';

		echo '<div class="rx-author-content">';
		echo '<h2 class="rx-author-title">';
		echo esc_html__( 'About ', 'rx-theme' ) . esc_html( get_the_author_meta( 'display_name', $author_id ) );
		echo '</h2>';

		if ( $description ) {
			echo '<p class="rx-author-description">' . esc_html( $description ) . '</p>';
		}

		echo '<a class="rx-author-posts-link" href="' . esc_url( get_author_posts_url( $author_id ) ) . '">';
		echo esc_html__( 'View all posts', 'rx-theme' );
		echo '</a>';

		echo '</div>';
		echo '</section>';
	}
}

/**
 * ------------------------------------------------------------
 * 13. SEARCH FORM
 * ------------------------------------------------------------
 */

/**
 * Custom search form.
 */
if ( ! function_exists( 'rx_search_form' ) ) {
	function rx_search_form( $form ) {
		$form = '
		<form role="search" method="get" class="rx-search-form search-form" action="' . esc_url( home_url( '/' ) ) . '">
			<label class="screen-reader-text" for="rx-search-field">' . esc_html__( 'Search for:', 'rx-theme' ) . '</label>
			<input type="search" id="rx-search-field" class="rx-search-field search-field" placeholder="' . esc_attr__( 'Search...', 'rx-theme' ) . '" value="' . esc_attr( get_search_query() ) . '" name="s">
			<button type="submit" class="rx-search-submit search-submit">
				<span class="screen-reader-text">' . esc_html__( 'Search', 'rx-theme' ) . '</span>
				<svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true"><path d="M21 20l-5.2-5.2a7 7 0 10-1.4 1.4L20 21zM5 10a5 5 0 1110 0A5 5 0 015 10z" fill="currentColor"/></svg>
			</button>
		</form>';

		return $form;
	}
}
add_filter( 'get_search_form', 'rx_search_form' );

/**
 * ------------------------------------------------------------
 * 14. COMMENT HELPERS
 * ------------------------------------------------------------
 */

/**
 * Custom comment callback.
 */
if ( ! function_exists( 'rx_comment_callback' ) ) {
	function rx_comment_callback( $comment, $args, $depth ) {
		$GLOBALS['comment'] = $comment;
		?>
		<li <?php comment_class( 'rx-comment' ); ?> id="comment-<?php comment_ID(); ?>">
			<article id="div-comment-<?php comment_ID(); ?>" class="comment-body rx-comment-body">
				<footer class="comment-meta rx-comment-meta">
					<div class="comment-author vcard rx-comment-author">
						<?php echo get_avatar( $comment, 60 ); ?>
						<?php
						printf(
							'<b class="fn">%s</b>',
							get_comment_author_link()
						);
						?>
					</div>

					<div class="comment-metadata rx-comment-date">
						<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
							<time datetime="<?php comment_time( 'c' ); ?>">
								<?php
								printf(
									esc_html__( '%1$s at %2$s', 'rx-theme' ),
									esc_html( get_comment_date() ),
									esc_html( get_comment_time() )
								);
								?>
							</time>
						</a>
					</div>
				</footer>

				<div class="comment-content rx-comment-content">
					<?php comment_text(); ?>
				</div>

				<div class="reply rx-comment-reply">
					<?php
					comment_reply_link(
						array_merge(
							$args,
							array(
								'add_below' => 'div-comment',
								'depth'     => $depth,
								'max_depth' => $args['max_depth'],
							)
						)
					);
					?>
				</div>
			</article>
		</li>
		<?php
	}
}

/**
 * ------------------------------------------------------------
 * 15. SCHEMA HELPERS
 * ------------------------------------------------------------
 */

/**
 * Get basic organization schema.
 */
if ( ! function_exists( 'rx_get_organization_schema' ) ) {
	function rx_get_organization_schema() {
		$schema = array(
			'@context' => 'https://schema.org',
			'@type'    => 'Organization',
			'name'     => get_bloginfo( 'name' ),
			'url'      => home_url( '/' ),
		);

		$custom_logo_id = get_theme_mod( 'custom_logo' );

		if ( $custom_logo_id ) {
			$logo = wp_get_attachment_image_url( $custom_logo_id, 'full' );

			if ( $logo ) {
				$schema['logo'] = esc_url_raw( $logo );
			}
		}

		return apply_filters( 'rx_organization_schema', $schema );
	}
}

/**
 * Get article schema.
 */
if ( ! function_exists( 'rx_get_article_schema' ) ) {
	function rx_get_article_schema( $post_id = null ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( ! $post_id ) {
			return array();
		}

		$schema = array(
			'@context'         => 'https://schema.org',
			'@type'            => 'Article',
			'headline'         => get_the_title( $post_id ),
			'description'      => rx_get_excerpt( $post_id, 30 ),
			'datePublished'    => get_the_date( DATE_W3C, $post_id ),
			'dateModified'     => get_the_modified_date( DATE_W3C, $post_id ),
			'mainEntityOfPage' => get_permalink( $post_id ),
			'author'           => array(
				'@type' => 'Person',
				'name'  => get_the_author_meta( 'display_name', get_post_field( 'post_author', $post_id ) ),
			),
			'publisher'        => rx_get_organization_schema(),
		);

		if ( has_post_thumbnail( $post_id ) ) {
			$image = get_the_post_thumbnail_url( $post_id, 'full' );

			if ( $image ) {
				$schema['image'] = array( esc_url_raw( $image ) );
			}
		}

		return apply_filters( 'rx_article_schema', $schema, $post_id );
	}
}

/**
 * Print JSON-LD schema.
 */
if ( ! function_exists( 'rx_print_schema' ) ) {
	function rx_print_schema() {
		if ( is_single() ) {
			$schema = rx_get_article_schema();
		} else {
			$schema = rx_get_organization_schema();
		}

		if ( empty( $schema ) ) {
			return;
		}

		echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>' . "\n";
	}
}
add_action( 'wp_head', 'rx_print_schema', 30 );

/**
 * ------------------------------------------------------------
 * 16. SEO META FALLBACK HELPERS
 * ------------------------------------------------------------
 */

/**
 * Meta description fallback.
 */
if ( ! function_exists( 'rx_meta_description' ) ) {
	function rx_meta_description() {
		if ( is_singular() ) {
			$description = rx_get_excerpt( get_the_ID(), 30 );
		} elseif ( is_category() || is_tag() || is_tax() ) {
			$description = term_description();
			$description = wp_strip_all_tags( $description );
		} elseif ( is_search() ) {
			$description = sprintf(
				esc_html__( 'Search results for %s', 'rx-theme' ),
				get_search_query()
			);
		} else {
			$description = get_bloginfo( 'description' );
		}

		$description = wp_strip_all_tags( $description );
		$description = trim( $description );

		if ( empty( $description ) ) {
			return;
		}

		echo '<meta name="description" content="' . esc_attr( wp_trim_words( $description, 30, '' ) ) . '">' . "\n";
	}
}

/**
 * Only add fallback meta description when common SEO plugins are not active.
 */
if ( ! function_exists( 'rx_maybe_add_meta_description' ) ) {
	function rx_maybe_add_meta_description() {
		if (
			defined( 'WPSEO_VERSION' ) ||
			defined( 'RANK_MATH_VERSION' ) ||
			defined( 'AIOSEO_VERSION' )
		) {
			return;
		}

		rx_meta_description();
	}
}
add_action( 'wp_head', 'rx_maybe_add_meta_description', 5 );

/**
 * Canonical URL fallback.
 */
if ( ! function_exists( 'rx_canonical_url' ) ) {
	function rx_canonical_url() {
		if (
			defined( 'WPSEO_VERSION' ) ||
			defined( 'RANK_MATH_VERSION' ) ||
			defined( 'AIOSEO_VERSION' )
		) {
			return;
		}

		if ( is_singular() ) {
			$url = get_permalink();
		} elseif ( is_home() || is_front_page() ) {
			$url = home_url( '/' );
		} elseif ( is_archive() || is_search() ) {
			$url = get_pagenum_link();
		} else {
			return;
		}

		echo '<link rel="canonical" href="' . esc_url( $url ) . '">' . "\n";
	}
}
add_action( 'wp_head', 'rx_canonical_url', 6 );

/**
 * ------------------------------------------------------------
 * 17. OPEN GRAPH FALLBACK
 * ------------------------------------------------------------
 */

/**
 * Basic Open Graph tags.
 */
if ( ! function_exists( 'rx_open_graph_tags' ) ) {
	function rx_open_graph_tags() {
		if (
			defined( 'WPSEO_VERSION' ) ||
			defined( 'RANK_MATH_VERSION' ) ||
			defined( 'AIOSEO_VERSION' )
		) {
			return;
		}

		$title       = wp_get_document_title();
		$url         = is_singular() ? get_permalink() : home_url( add_query_arg( null, null ) );
		$description = is_singular() ? rx_get_excerpt( get_the_ID(), 30 ) : get_bloginfo( 'description' );
		$image       = is_singular() ? rx_get_thumbnail_url( get_the_ID(), 'large' ) : rx_get_fallback_image_url();
		$type        = is_singular() ? 'article' : 'website';

		echo '<meta property="og:title" content="' . esc_attr( $title ) . '">' . "\n";
		echo '<meta property="og:description" content="' . esc_attr( $description ) . '">' . "\n";
		echo '<meta property="og:url" content="' . esc_url( $url ) . '">' . "\n";
		echo '<meta property="og:image" content="' . esc_url( $image ) . '">' . "\n";
		echo '<meta property="og:type" content="' . esc_attr( $type ) . '">' . "\n";
		echo '<meta property="og:site_name" content="' . esc_attr( get_bloginfo( 'name' ) ) . '">' . "\n";
		echo '<meta name="twitter:card" content="summary_large_image">' . "\n";
	}
}
add_action( 'wp_head', 'rx_open_graph_tags', 7 );

/**
 * ------------------------------------------------------------
 * 18. PERFORMANCE HELPERS
 * ------------------------------------------------------------
 */

/**
 * Add decoding async to post thumbnails.
 */
if ( ! function_exists( 'rx_image_attributes' ) ) {
	function rx_image_attributes( $attr ) {
		if ( empty( $attr['loading'] ) ) {
			$attr['loading'] = 'lazy';
		}

		if ( empty( $attr['decoding'] ) ) {
			$attr['decoding'] = 'async';
		}

		return $attr;
	}
}
add_filter( 'wp_get_attachment_image_attributes', 'rx_image_attributes' );

/**
 * Preload featured image on single post/page.
 */
if ( ! function_exists( 'rx_preload_featured_image' ) ) {
	function rx_preload_featured_image() {
		if ( ! is_singular() || ! has_post_thumbnail() ) {
			return;
		}

		$image = get_the_post_thumbnail_url( get_the_ID(), 'large' );

		if ( ! $image ) {
			return;
		}

		echo '<link rel="preload" as="image" href="' . esc_url( $image ) . '">' . "\n";
	}
}
add_action( 'wp_head', 'rx_preload_featured_image', 1 );

/**
 * Add resource hints.
 */
if ( ! function_exists( 'rx_resource_hints' ) ) {
	function rx_resource_hints( $urls, $relation_type ) {
		if ( 'preconnect' === $relation_type ) {
			$urls[] = array(
				'href'        => 'https://fonts.gstatic.com',
				'crossorigin' => 'anonymous',
			);
		}

		if ( 'dns-prefetch' === $relation_type ) {
			$urls[] = '//fonts.googleapis.com';
			$urls[] = '//fonts.gstatic.com';
			$urls[] = '//www.google-analytics.com';
			$urls[] = '//www.googletagmanager.com';
		}

		return $urls;
	}
}
add_filter( 'wp_resource_hints', 'rx_resource_hints', 10, 2 );

/**
 * ------------------------------------------------------------
 * 19. SOCIAL SHARE
 * ------------------------------------------------------------
 */

/**
 * Social share links.
 */
if ( ! function_exists( 'rx_social_share' ) ) {
	function rx_social_share( $post_id = null ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();

		if ( ! $post_id ) {
			return;
		}

		$url   = rawurlencode( get_permalink( $post_id ) );
		$title = rawurlencode( get_the_title( $post_id ) );

		$links = array(
			'facebook' => 'https://www.facebook.com/sharer/sharer.php?u=' . $url,
			'twitter'  => 'https://twitter.com/intent/tweet?url=' . $url . '&text=' . $title,
			'linkedin' => 'https://www.linkedin.com/shareArticle?mini=true&url=' . $url . '&title=' . $title,
			'whatsapp' => 'https://api.whatsapp.com/send?text=' . $title . '%20' . $url,
			'telegram' => 'https://t.me/share/url?url=' . $url . '&text=' . $title,
		);

		echo '<div class="rx-social-share">';
		echo '<span class="rx-social-share-title">' . esc_html__( 'Share:', 'rx-theme' ) . '</span>';

		foreach ( $links as $network => $link ) {
			echo '<a class="rx-share-link rx-share-' . esc_attr( $network ) . '" href="' . esc_url( $link ) . '" target="_blank" rel="noopener noreferrer">';
			echo esc_html( ucfirst( $network ) );
			echo '</a>';
		}

		echo '</div>';
	}
}

/**
 * ------------------------------------------------------------
 * 20. TABLE OF CONTENTS
 * ------------------------------------------------------------
 */

/**
 * Generate simple table of contents from H2/H3 headings.
 */
if ( ! function_exists( 'rx_generate_toc' ) ) {
	function rx_generate_toc( $content ) {
		if ( ! is_singular() || empty( $content ) ) {
			return $content;
		}

		if ( false === strpos( $content, '<h2' ) && false === strpos( $content, '<h3' ) ) {
			return $content;
		}

		preg_match_all( '/<h([2-3])([^>]*)>(.*?)<\/h[2-3]>/i', $content, $matches, PREG_SET_ORDER );

		if ( empty( $matches ) || count( $matches ) < 2 ) {
			return $content;
		}

		$toc = '<nav class="rx-table-of-contents" aria-label="' . esc_attr__( 'Table of contents', 'rx-theme' ) . '">';
		$toc .= '<h2 class="rx-toc-title">' . esc_html__( 'Table of Contents', 'rx-theme' ) . '</h2>';
		$toc .= '<ol class="rx-toc-list">';

		foreach ( $matches as $match ) {
			$level = absint( $match[1] );
			$text  = wp_strip_all_tags( $match[3] );
			$id    = sanitize_title( $text );

			if ( empty( $id ) ) {
				continue;
			}

			$heading_old = $match[0];

			if ( false === strpos( $heading_old, 'id=' ) ) {
				$heading_new = '<h' . $level . $match[2] . ' id="' . esc_attr( $id ) . '">' . $match[3] . '</h' . $level . '>';
				$content     = str_replace( $heading_old, $heading_new, $content );
			}

			$toc .= '<li class="rx-toc-item rx-toc-level-' . esc_attr( $level ) . '">';
			$toc .= '<a href="#' . esc_attr( $id ) . '">' . esc_html( $text ) . '</a>';
			$toc .= '</li>';
		}

		$toc .= '</ol>';
		$toc .= '</nav>';

		$first_paragraph = strpos( $content, '</p>' );

		if ( false !== $first_paragraph ) {
			$content = substr_replace( $content, '</p>' . $toc, $first_paragraph, 4 );
		} else {
			$content = $toc . $content;
		}

		return $content;
	}
}

/**
 * Enable TOC only when post meta is not disabled.
 */
if ( ! function_exists( 'rx_maybe_add_toc' ) ) {
	function rx_maybe_add_toc( $content ) {
		if ( is_admin() || ! is_main_query() || ! in_the_loop() ) {
			return $content;
		}

		$disable = get_post_meta( get_the_ID(), '_rx_disable_toc', true );

		if ( 'yes' === $disable ) {
			return $content;
		}

		return rx_generate_toc( $content );
	}
}
add_filter( 'the_content', 'rx_maybe_add_toc', 20 );

/**
 * ------------------------------------------------------------
 * 21. CONTENT HELPERS
 * ------------------------------------------------------------
 */

/**
 * Add responsive wrapper around embeds.
 */
if ( ! function_exists( 'rx_responsive_embeds' ) ) {
	function rx_responsive_embeds( $html ) {
		if ( false !== strpos( $html, '<iframe' ) ) {
			$html = '<div class="rx-responsive-embed">' . $html . '</div>';
		}

		return $html;
	}
}
add_filter( 'embed_oembed_html', 'rx_responsive_embeds' );
add_filter( 'video_embed_html', 'rx_responsive_embeds' );

/**
 * Add nofollow to external links in content.
 */
if ( ! function_exists( 'rx_external_links_attributes' ) ) {
	function rx_external_links_attributes( $content ) {
		if ( is_admin() || empty( $content ) ) {
			return $content;
		}

		$home_host = wp_parse_url( home_url(), PHP_URL_HOST );

		return preg_replace_callback(
			'/<a\s+[^>]*href=["\']([^"\']+)["\'][^>]*>/i',
			function ( $matches ) use ( $home_host ) {
				$link = $matches[0];
				$url  = $matches[1];
				$host = wp_parse_url( $url, PHP_URL_HOST );

				if ( empty( $host ) || $host === $home_host ) {
					return $link;
				}

				if ( false === strpos( $link, 'rel=' ) ) {
					$link = str_replace( '<a ', '<a rel="nofollow noopener noreferrer" ', $link );
				}

				if ( false === strpos( $link, 'target=' ) ) {
					$link = str_replace( '<a ', '<a target="_blank" ', $link );
				}

				return $link;
			},
			$content
		);
	}
}
add_filter( 'the_content', 'rx_external_links_attributes', 25 );

/**
 * ------------------------------------------------------------
 * 22. MENU HELPERS
 * ------------------------------------------------------------
 */

/**
 * Fallback menu.
 */
if ( ! function_exists( 'rx_fallback_menu' ) ) {
	function rx_fallback_menu() {
		echo '<ul class="rx-fallback-menu">';
		echo '<li><a href="' . esc_url( home_url( '/' ) ) . '">' . esc_html__( 'Home', 'rx-theme' ) . '</a></li>';

		wp_list_pages(
			array(
				'title_li' => '',
				'depth'    => 1,
			)
		);

		echo '</ul>';
	}
}

/**
 * Primary menu.
 */
if ( ! function_exists( 'rx_primary_menu' ) ) {
	function rx_primary_menu() {
		wp_nav_menu(
			array(
				'theme_location' => 'primary',
				'menu_id'        => 'primary-menu',
				'menu_class'     => 'rx-primary-menu',
				'container'      => 'nav',
				'container_id'   => 'site-navigation',
				'container_class'=> 'main-navigation rx-main-navigation',
				'fallback_cb'    => 'rx_fallback_menu',
			)
		);
	}
}

/**
 * Footer menu.
 */
if ( ! function_exists( 'rx_footer_menu' ) ) {
	function rx_footer_menu() {
		if ( ! has_nav_menu( 'footer' ) ) {
			return;
		}

		wp_nav_menu(
			array(
				'theme_location' => 'footer',
				'menu_id'        => 'footer-menu',
				'menu_class'     => 'rx-footer-menu',
				'container'      => 'nav',
				'container_class'=> 'rx-footer-navigation',
				'depth'          => 1,
			)
		);
	}
}

/**
 * ------------------------------------------------------------
 * 23. HEADER AND FOOTER HELPERS
 * ------------------------------------------------------------
 */

/**
 * Site branding.
 */
if ( ! function_exists( 'rx_site_branding' ) ) {
	function rx_site_branding() {
		echo '<div class="site-branding rx-site-branding">';

		if ( has_custom_logo() ) {
			the_custom_logo();
		}

		if ( is_front_page() && is_home() ) {
			echo '<h1 class="site-title rx-site-title">';
			echo '<a href="' . esc_url( home_url( '/' ) ) . '" rel="home">' . esc_html( get_bloginfo( 'name' ) ) . '</a>';
			echo '</h1>';
		} else {
			echo '<p class="site-title rx-site-title">';
			echo '<a href="' . esc_url( home_url( '/' ) ) . '" rel="home">' . esc_html( get_bloginfo( 'name' ) ) . '</a>';
			echo '</p>';
		}

		$description = get_bloginfo( 'description', 'display' );

		if ( $description || is_customize_preview() ) {
			echo '<p class="site-description rx-site-description">' . esc_html( $description ) . '</p>';
		}

		echo '</div>';
	}
}

/**
 * Copyright text.
 */
if ( ! function_exists( 'rx_copyright' ) ) {
	function rx_copyright() {
		echo '<div class="rx-copyright">';
		echo esc_html( sprintf( __( '© %1$s %2$s. All rights reserved.', 'rx-theme' ), date_i18n( 'Y' ), get_bloginfo( 'name' ) ) );
		echo '</div>';
	}
}

/**
 * Back to top button.
 */
if ( ! function_exists( 'rx_back_to_top' ) ) {
	function rx_back_to_top() {
		echo '<button class="rx-back-to-top" type="button" aria-label="' . esc_attr__( 'Back to top', 'rx-theme' ) . '">';
		echo '&uarr;';
		echo '</button>';
	}
}
add_action( 'wp_footer', 'rx_back_to_top', 20 );

/**
 * ------------------------------------------------------------
 * 24. ARCHIVE HELPERS
 * ------------------------------------------------------------
 */

/**
 * Archive description.
 */
if ( ! function_exists( 'rx_archive_description' ) ) {
	function rx_archive_description() {
		if ( is_archive() ) {
			$description = get_the_archive_description();

			if ( $description ) {
				echo '<div class="archive-description rx-archive-description">';
				echo wp_kses_post( wpautop( $description ) );
				echo '</div>';
			}
		}
	}
}

/**
 * No results template helper.
 */
if ( ! function_exists( 'rx_no_results' ) ) {
	function rx_no_results() {
		echo '<section class="no-results not-found rx-no-results">';
		echo '<header class="page-header">';
		echo '<h1 class="page-title">' . esc_html__( 'Nothing Found', 'rx-theme' ) . '</h1>';
		echo '</header>';

		echo '<div class="page-content">';

		if ( is_home() && current_user_can( 'publish_posts' ) ) {
			printf(
				wp_kses(
					__( '<p>Ready to publish your first post? <a href="%1$s">Get started here</a>.</p>', 'rx-theme' ),
					array(
						'p' => array(),
						'a' => array(
							'href' => array(),
						),
					)
				),
				esc_url( admin_url( 'post-new.php' ) )
			);
		} elseif ( is_search() ) {
			echo '<p>' . esc_html__( 'Sorry, nothing matched your search. Please try again with different keywords.', 'rx-theme' ) . '</p>';
			get_search_form();
		} else {
			echo '<p>' . esc_html__( 'It seems we cannot find what you are looking for. Maybe search can help.', 'rx-theme' ) . '</p>';
			get_search_form();
		}

		echo '</div>';
		echo '</section>';
	}
}

/**
 * ------------------------------------------------------------
 * 25. POST VIEWS
 * ------------------------------------------------------------
 */

/**
 * Count post views.
 */
if ( ! function_exists( 'rx_track_post_views' ) ) {
	function rx_track_post_views() {
		if ( ! is_single() ) {
			return;
		}

		global $post;

		if ( empty( $post->ID ) ) {
			return;
		}

		$key   = '_rx_post_views';
		$count = get_post_meta( $post->ID, $key, true );
		$count = $count ? absint( $count ) : 0;

		update_post_meta( $post->ID, $key, $count + 1 );
	}
}
add_action( 'wp_head', 'rx_track_post_views' );

/**
 * Get post views.
 */
if ( ! function_exists( 'rx_get_post_views' ) ) {
	function rx_get_post_views( $post_id = null ) {
		$post_id = $post_id ? absint( $post_id ) : get_the_ID();
		$count   = get_post_meta( $post_id, '_rx_post_views', true );

		return $count ? absint( $count ) : 0;
	}
}

/**
 * Print post views.
 */
if ( ! function_exists( 'rx_post_views' ) ) {
	function rx_post_views( $post_id = null ) {
		$count = rx_get_post_views( $post_id );

		echo '<span class="rx-post-views">';
		echo esc_html(
			sprintf(
				_n( '%s view', '%s views', $count, 'rx-theme' ),
				number_format_i18n( $count )
			)
		);
		echo '</span>';
	}
}

/**
 * ------------------------------------------------------------
 * 26. CUSTOMIZER HELPER VALUES
 * ------------------------------------------------------------
 */

/**
 * Get theme option from customizer.
 */
if ( ! function_exists( 'rx_get_option' ) ) {
	function rx_get_option( $key, $default = '' ) {
		$value = get_theme_mod( $key, $default );

		return apply_filters( 'rx_get_option', $value, $key, $default );
	}
}

/**
 * Print inline CSS variable from customizer.
 */
if ( ! function_exists( 'rx_css_variable' ) ) {
	function rx_css_variable( $name, $value ) {
		if ( empty( $name ) || empty( $value ) ) {
			return;
		}

		echo esc_html( '--' . sanitize_key( $name ) . ':' . sanitize_text_field( $value ) . ';' );
	}
}

/**
 * Output dynamic CSS variables.
 */
if ( ! function_exists( 'rx_dynamic_css_variables' ) ) {
	function rx_dynamic_css_variables() {
		$primary_color = rx_get_option( 'rx_primary_color', '#0d6efd' );
		$body_bg       = rx_get_option( 'rx_body_background', '#ffffff' );
		$text_color    = rx_get_option( 'rx_text_color', '#222222' );

		echo '<style id="rx-dynamic-css">';
		echo ':root{';
		rx_css_variable( 'rx-primary-color', $primary_color );
		rx_css_variable( 'rx-body-bg', $body_bg );
		rx_css_variable( 'rx-text-color', $text_color );
		echo '}';
		echo '</style>';
	}
}
add_action( 'wp_head', 'rx_dynamic_css_variables', 20 );

/**
 * ------------------------------------------------------------
 * 27. SECURITY AND CLEAN OUTPUT HELPERS
 * ------------------------------------------------------------
 */

/**
 * Remove WordPress version from head.
 */
remove_action( 'wp_head', 'wp_generator' );

/**
 * Remove version query from static files.
 */
if ( ! function_exists( 'rx_remove_asset_version_query' ) ) {
	function rx_remove_asset_version_query( $src ) {
		if ( is_admin() ) {
			return $src;
		}

		if ( strpos( $src, 'ver=' ) ) {
			$src = remove_query_arg( 'ver', $src );
		}

		return $src;
	}
}

/**
 * Optional: enable this only if you really want no ?ver on CSS/JS.
 */
// add_filter( 'style_loader_src', 'rx_remove_asset_version_query', 15 );
// add_filter( 'script_loader_src', 'rx_remove_asset_version_query', 15 );

/**
 * Sanitize HTML class.
 */
if ( ! function_exists( 'rx_sanitize_html_classes' ) ) {
	function rx_sanitize_html_classes( $classes ) {
		if ( is_array( $classes ) ) {
			$classes = array_map( 'sanitize_html_class', $classes );
			return implode( ' ', $classes );
		}

		return sanitize_html_class( $classes );
	}
}

/**
 * ------------------------------------------------------------
 * 28. WOOCOMMERCE HELPERS
 * ------------------------------------------------------------
 */

if ( rx_is_woocommerce_active() ) {

	/**
	 * WooCommerce wrapper start.
	 */
	if ( ! function_exists( 'rx_woocommerce_wrapper_start' ) ) {
		function rx_woocommerce_wrapper_start() {
			echo '<main id="primary" class="site-main rx-woocommerce-main">';
		}
	}

	/**
	 * WooCommerce wrapper end.
	 */
	if ( ! function_exists( 'rx_woocommerce_wrapper_end' ) ) {
		function rx_woocommerce_wrapper_end() {
			echo '</main>';
		}
	}

	remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10 );
	remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10 );

	add_action( 'woocommerce_before_main_content', 'rx_woocommerce_wrapper_start', 10 );
	add_action( 'woocommerce_after_main_content', 'rx_woocommerce_wrapper_end', 10 );
}

/**
 * ------------------------------------------------------------
 * 29. ADMIN BAR HELPER
 * ------------------------------------------------------------
 */

/**
 * Add RX quick link in admin bar.
 */
if ( ! function_exists( 'rx_admin_bar_links' ) ) {
	function rx_admin_bar_links( $wp_admin_bar ) {
		if ( ! current_user_can( 'edit_theme_options' ) ) {
			return;
		}

		$wp_admin_bar->add_node(
			array(
				'id'    => 'rx-theme-options',
				'title' => esc_html__( 'RX Theme', 'rx-theme' ),
				'href'  => esc_url( admin_url( 'customize.php' ) ),
				'meta'  => array(
					'title' => esc_html__( 'Customize RX Theme', 'rx-theme' ),
				),
			)
		);
	}
}
add_action( 'admin_bar_menu', 'rx_admin_bar_links', 100 );

/**
 * ------------------------------------------------------------
 * 30. TEMPLATE PART LOADER
 * ------------------------------------------------------------
 */

/**
 * Safe template part loader with arguments.
 */
if ( ! function_exists( 'rx_get_template_part' ) ) {
	function rx_get_template_part( $slug, $name = null, $args = array() ) {
		if ( ! empty( $args ) && is_array( $args ) ) {
			set_query_var( 'rx_template_args', $args );
		}

		get_template_part( $slug, $name );
	}
}

/**
 * Get argument inside template part.
 */
if ( ! function_exists( 'rx_template_arg' ) ) {
	function rx_template_arg( $key, $default = null ) {
		$args = get_query_var( 'rx_template_args', array() );

		if ( isset( $args[ $key ] ) ) {
			return $args[ $key ];
		}

		return $default;
	}
}

/**
 * ------------------------------------------------------------
 * 31. DEBUG HELPER
 * ------------------------------------------------------------
 */

/**
 * Safe debug print for development only.
 */
if ( ! function_exists( 'rx_debug' ) ) {
	function rx_debug( $data ) {
		if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG || ! current_user_can( 'manage_options' ) ) {
			return;
		}

		echo '<pre class="rx-debug">';
		print_r( $data ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
		echo '</pre>';
	}
}

You can now use these functions in your theme files like:

<?php rx_site_branding(); ?>
<?php rx_primary_menu(); ?>
<?php rx_breadcrumbs(); ?>
<?php rx_entry_meta(); ?>
<?php rx_post_thumbnail(); ?>
<?php rx_the_excerpt(35); ?>
<?php rx_read_more_button(); ?>
<?php rx_entry_footer(); ?>
<?php rx_author_box(); ?>
<?php rx_related_posts(); ?>
<?php rx_post_navigation(); ?>
<?php rx_pagination(); ?>
<?php rx_copyright(); ?>

Best structure:

rx-theme/
├── functions.php
├── inc/
│   ├── helpers/
│   │   ├── template-functions.php
│   │   ├── breadcrumbs.php
│   │   ├── reading-time.php
│   │   ├── related-posts.php
│   │   ├── pagination.php
│   │   └── schema.php

Since this template-functions.php already includes breadcrumbs, reading time, related posts, pagination, and schema helpers, do not duplicate the same function names in separate helper files unless you split the file later.

Leave a Reply

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