rank-math.php

I’ll build this as a practical Rank Math integration file for your RX theme: SEO breadcrumbs, schema support, Open Graph/Twitter cleanup, sitemap helpers, robots/meta controls, canonical safety, performance-friendly output, and safe fallbacks when Rank Math is not active.

Below is a strong inc/integrations/rank-math.php file for your RX theme. It adds many safe Rank Math integrations: theme support, breadcrumbs helper, schema cleanup, medical/website schema helpers, Open Graph/Twitter fallback image, canonical fixes, robots rules, sitemap exclusions, author/archive controls, WooCommerce support, and admin notices.

Rank Math officially recommends adding theme-level Rank Math filters in a theme rank-math.php style integration file, and it documents filters for meta robots, Open Graph, breadcrumbs, schema, sitemap, and frontend data control.

Create this file:

<?php
/**
 * RX Theme - Rank Math SEO Integration
 *
 * File: inc/integrations/rank-math.php
 *
 * Purpose:
 * - Add deep compatibility between RX Theme and Rank Math SEO.
 * - Improve breadcrumbs, canonical URLs, robots meta, Open Graph, Twitter Card,
 *   Schema.org structured data, sitemap behavior, WooCommerce SEO support,
 *   medical content schema helpers, and safe fallback behavior.
 *
 * Important:
 * - This file does not replace Rank Math settings.
 * - It enhances Rank Math output when the plugin is active.
 * - Keep only one SEO plugin active at a time.
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'RX_Theme_Rank_Math_Integration' ) ) :

	final class RX_Theme_Rank_Math_Integration {

		/**
		 * Instance.
		 *
		 * @var RX_Theme_Rank_Math_Integration|null
		 */
		private static $instance = null;

		/**
		 * Theme option prefix.
		 *
		 * @var string
		 */
		private $prefix = 'rx_theme_';

		/**
		 * Get instance.
		 *
		 * @return RX_Theme_Rank_Math_Integration
		 */
		public static function instance() {
			if ( null === self::$instance ) {
				self::$instance = new self();
			}

			return self::$instance;
		}

		/**
		 * Constructor.
		 */
		private function __construct() {
			add_action( 'after_setup_theme', array( $this, 'theme_support' ) );
			add_action( 'init', array( $this, 'init_hooks' ), 20 );
			add_action( 'wp', array( $this, 'frontend_hooks' ) );
			add_action( 'admin_notices', array( $this, 'admin_notice_if_rank_math_missing' ) );
		}

		/**
		 * Add theme support.
		 *
		 * @return void
		 */
		public function theme_support() {
			add_theme_support( 'rank-math-breadcrumbs' );
			add_theme_support( 'title-tag' );
			add_theme_support( 'post-thumbnails' );
			add_theme_support( 'html5', array(
				'search-form',
				'comment-form',
				'comment-list',
				'gallery',
				'caption',
				'style',
				'script',
			) );
		}

		/**
		 * Check whether Rank Math is active.
		 *
		 * @return bool
		 */
		public function is_rank_math_active() {
			return defined( 'RANK_MATH_VERSION' ) || class_exists( 'RankMath' );
		}

		/**
		 * Register Rank Math hooks.
		 *
		 * @return void
		 */
		public function init_hooks() {
			if ( ! $this->is_rank_math_active() ) {
				return;
			}

			/**
			 * Frontend meta filters.
			 */
			add_filter( 'rank_math/frontend/title', array( $this, 'filter_frontend_title' ), 20 );
			add_filter( 'rank_math/frontend/description', array( $this, 'filter_frontend_description' ), 20 );
			add_filter( 'rank_math/frontend/canonical', array( $this, 'filter_canonical_url' ), 20 );
			add_filter( 'rank_math/frontend/robots', array( $this, 'filter_robots_meta' ), 20 );

			/**
			 * Open Graph and Twitter.
			 */
			add_filter( 'rank_math/opengraph/type', array( $this, 'filter_og_type' ), 20 );
			add_filter( 'rank_math/opengraph/facebook/image', array( $this, 'filter_social_image' ), 20 );
			add_filter( 'rank_math/opengraph/twitter/image', array( $this, 'filter_social_image' ), 20 );
			add_filter( 'rank_math/opengraph/twitter/card_type', array( $this, 'filter_twitter_card_type' ), 20 );

			/**
			 * Breadcrumbs.
			 */
			add_filter( 'rank_math/frontend/breadcrumb/settings', array( $this, 'filter_breadcrumb_settings' ), 20 );
			add_filter( 'rank_math/frontend/breadcrumb/items', array( $this, 'filter_breadcrumb_items' ), 20 );
			add_filter( 'rank_math/frontend/breadcrumb/html', array( $this, 'filter_breadcrumb_html' ), 20, 3 );

			/**
			 * Schema.
			 */
			add_filter( 'rank_math/json_ld', array( $this, 'filter_json_ld_schema' ), 30, 2 );
			add_filter( 'rank_math/snippet/rich_snippet_article_entity', array( $this, 'filter_article_schema' ), 30 );
			add_filter( 'rank_math/snippet/rich_snippet_product_entity', array( $this, 'filter_product_schema' ), 30 );

			/**
			 * Sitemaps.
			 */
			add_filter( 'rank_math/sitemap/entry', array( $this, 'filter_sitemap_entry' ), 20, 3 );
			add_filter( 'rank_math/sitemap/exclude_post_type', array( $this, 'exclude_post_type_from_sitemap' ), 20, 2 );
			add_filter( 'rank_math/sitemap/exclude_taxonomy', array( $this, 'exclude_taxonomy_from_sitemap' ), 20, 2 );

			/**
			 * Analysis/content compatibility.
			 */
			add_filter( 'rank_math/researches/content', array( $this, 'add_builder_content_to_rank_math_analysis' ), 20, 2 );

			/**
			 * Admin.
			 */
			add_filter( 'rank_math/settings/general', array( $this, 'register_rank_math_theme_settings' ), 20 );
		}

		/**
		 * Frontend-only hooks.
		 *
		 * @return void
		 */
		public function frontend_hooks() {
			if ( ! $this->is_rank_math_active() || is_admin() ) {
				return;
			}

			add_action( 'wp_head', array( $this, 'print_rx_extra_meta' ), 1 );
		}

		/**
		 * Admin notice if Rank Math is missing.
		 *
		 * @return void
		 */
		public function admin_notice_if_rank_math_missing() {
			if ( ! current_user_can( 'activate_plugins' ) ) {
				return;
			}

			if ( $this->is_rank_math_active() ) {
				return;
			}

			$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;

			if ( ! $screen || false === strpos( $screen->id, 'themes' ) ) {
				return;
			}

			echo '<div class="notice notice-info is-dismissible">';
			echo '<p><strong>RX Theme SEO Notice:</strong> For advanced SEO, schema, breadcrumbs, Open Graph, and sitemap features, install and activate Rank Math SEO.</p>';
			echo '</div>';
		}

		/**
		 * Better title fallback.
		 *
		 * @param string $title Rank Math title.
		 * @return string
		 */
		public function filter_frontend_title( $title ) {
			if ( ! empty( $title ) ) {
				return $title;
			}

			if ( is_singular() ) {
				$title = single_post_title( '', false );
			} elseif ( is_archive() ) {
				$title = get_the_archive_title();
			} elseif ( is_search() ) {
				$title = sprintf(
					/* translators: %s search query */
					__( 'Search results for: %s', 'rx-theme' ),
					get_search_query()
				);
			} elseif ( is_404() ) {
				$title = __( 'Page Not Found', 'rx-theme' );
			} else {
				$title = get_bloginfo( 'name' );
			}

			$site_name = get_bloginfo( 'name' );

			if ( $site_name && false === stripos( $title, $site_name ) ) {
				$title .= ' - ' . $site_name;
			}

			return wp_strip_all_tags( $title );
		}

		/**
		 * Better description fallback.
		 *
		 * @param string $description Rank Math description.
		 * @return string
		 */
		public function filter_frontend_description( $description ) {
			if ( ! empty( $description ) ) {
				return $this->limit_text( $description, 160 );
			}

			if ( is_singular() ) {
				$post = get_post();

				if ( $post ) {
					$custom = get_post_meta( $post->ID, '_rx_meta_description', true );

					if ( $custom ) {
						return $this->limit_text( $custom, 160 );
					}

					if ( has_excerpt( $post ) ) {
						return $this->limit_text( get_the_excerpt( $post ), 160 );
					}

					return $this->limit_text( wp_strip_all_tags( strip_shortcodes( $post->post_content ) ), 160 );
				}
			}

			if ( is_category() || is_tag() || is_tax() ) {
				$term = get_queried_object();

				if ( $term && ! empty( $term->description ) ) {
					return $this->limit_text( $term->description, 160 );
				}
			}

			$tagline = get_bloginfo( 'description' );

			return $tagline ? $this->limit_text( $tagline, 160 ) : '';
		}

		/**
		 * Canonical URL cleanup.
		 *
		 * @param string $canonical Canonical URL.
		 * @return string
		 */
		public function filter_canonical_url( $canonical ) {
			if ( is_404() || is_search() ) {
				return false;
			}

			if ( is_paged() ) {
				return $canonical;
			}

			if ( is_singular() ) {
				$canonical = get_permalink();
			}

			if ( is_home() || is_front_page() ) {
				$canonical = home_url( '/' );
			}

			if ( is_category() || is_tag() || is_tax() ) {
				$term = get_queried_object();

				if ( $term && ! is_wp_error( $term ) ) {
					$url = get_term_link( $term );

					if ( ! is_wp_error( $url ) ) {
						$canonical = $url;
					}
				}
			}

			return $canonical ? esc_url_raw( $canonical ) : $canonical;
		}

		/**
		 * Robots meta rules.
		 *
		 * @param array $robots Robots directives.
		 * @return array
		 */
		public function filter_robots_meta( $robots ) {
			if ( ! is_array( $robots ) ) {
				$robots = array();
			}

			/**
			 * Noindex weak pages.
			 */
			if (
				is_search() ||
				is_404() ||
				is_date() ||
				is_author() ||
				$this->is_thin_paged_archive()
			) {
				$robots['index']  = 'noindex';
				$robots['follow'] = 'follow';
			}

			/**
			 * Noindex private-like utility pages by slug.
			 */
			if ( is_page() ) {
				$slug = get_post_field( 'post_name', get_queried_object_id() );

				$noindex_slugs = array(
					'thank-you',
					'privacy-confirmation',
					'login',
					'register',
					'account',
					'checkout',
					'cart',
					'wishlist',
				);

				if ( in_array( $slug, $noindex_slugs, true ) ) {
					$robots['index']  = 'noindex';
					$robots['follow'] = 'follow';
				}
			}

			/**
			 * Keep media attachment pages out of Google index.
			 */
			if ( is_attachment() ) {
				$robots['index']  = 'noindex';
				$robots['follow'] = 'follow';
			}

			/**
			 * Good defaults.
			 */
			if ( ! isset( $robots['max-snippet'] ) ) {
				$robots['max-snippet'] = 'max-snippet:-1';
			}

			if ( ! isset( $robots['max-video-preview'] ) ) {
				$robots['max-video-preview'] = 'max-video-preview:-1';
			}

			if ( ! isset( $robots['max-image-preview'] ) ) {
				$robots['max-image-preview'] = 'max-image-preview:large';
			}

			return $robots;
		}

		/**
		 * Open Graph type.
		 *
		 * @param string $type OG type.
		 * @return string
		 */
		public function filter_og_type( $type ) {
			if ( is_front_page() || is_home() ) {
				return 'website';
			}

			if ( is_singular( 'post' ) ) {
				return 'article';
			}

			if ( function_exists( 'is_product' ) && is_product() ) {
				return 'product';
			}

			if ( is_singular() ) {
				return 'article';
			}

			return $type;
		}

		/**
		 * Social fallback image.
		 *
		 * @param string|array $image Image URL or image data.
		 * @return string|array
		 */
		public function filter_social_image( $image ) {
			if ( ! empty( $image ) ) {
				return $image;
			}

			if ( is_singular() && has_post_thumbnail() ) {
				$thumb = wp_get_attachment_image_url( get_post_thumbnail_id(), 'full' );

				if ( $thumb ) {
					return $thumb;
				}
			}

			$custom_logo_id = get_theme_mod( 'custom_logo' );

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

				if ( $logo ) {
					return $logo;
				}
			}

			$fallback = get_theme_file_uri( 'assets/images/social-share.jpg' );

			return esc_url_raw( $fallback );
		}

		/**
		 * Twitter card type.
		 *
		 * @param string $type Card type.
		 * @return string
		 */
		public function filter_twitter_card_type( $type ) {
			if ( is_singular() && has_post_thumbnail() ) {
				return 'summary_large_image';
			}

			return $type ? $type : 'summary_large_image';
		}

		/**
		 * Breadcrumb settings.
		 *
		 * @param array $settings Breadcrumb settings.
		 * @return array
		 */
		public function filter_breadcrumb_settings( $settings ) {
			if ( ! is_array( $settings ) ) {
				$settings = array();
			}

			$settings['separator']      = '<span class="rx-breadcrumb-separator" aria-hidden="true">›</span>';
			$settings['wrap_before']    = '<nav class="rx-breadcrumbs rank-math-breadcrumb" aria-label="' . esc_attr__( 'Breadcrumb', 'rx-theme' ) . '"><p>';
			$settings['wrap_after']     = '</p></nav>';
			$settings['before']         = '';
			$settings['after']          = '';
			$settings['home']           = esc_html__( 'Home', 'rx-theme' );
			$settings['show_home']      = true;
			$settings['show_title']     = true;
			$settings['hide_tax_name']  = false;
			$settings['hide_post_title'] = false;

			return $settings;
		}

		/**
		 * Breadcrumb items cleanup.
		 *
		 * @param array $crumbs Breadcrumb items.
		 * @return array
		 */
		public function filter_breadcrumb_items( $crumbs ) {
			if ( empty( $crumbs ) || ! is_array( $crumbs ) ) {
				return $crumbs;
			}

			foreach ( $crumbs as $index => $crumb ) {
				if ( isset( $crumb[0] ) ) {
					$crumbs[ $index ][0] = wp_strip_all_tags( $crumb[0] );
				}

				if ( isset( $crumb[1] ) ) {
					$crumbs[ $index ][1] = esc_url_raw( $crumb[1] );
				}
			}

			return $crumbs;
		}

		/**
		 * Breadcrumb HTML final cleanup.
		 *
		 * @param string $html Breadcrumb HTML.
		 * @param array  $crumbs Breadcrumb items.
		 * @param object $class Breadcrumb class.
		 * @return string
		 */
		public function filter_breadcrumb_html( $html, $crumbs, $class ) {
			unset( $crumbs, $class );

			$html = str_replace( '<p>', '<ol class="rx-breadcrumb-list">', $html );
			$html = str_replace( '</p>', '</ol>', $html );

			return $html;
		}

		/**
		 * Main JSON-LD schema filter.
		 *
		 * @param array $data JSON-LD data.
		 * @param object $jsonld JSON-LD class object.
		 * @return array
		 */
		public function filter_json_ld_schema( $data, $jsonld ) {
			unset( $jsonld );

			if ( ! is_array( $data ) ) {
				return $data;
			}

			$data = $this->add_website_schema_enhancements( $data );
			$data = $this->add_medical_article_schema_if_needed( $data );
			$data = $this->add_author_schema_enhancements( $data );
			$data = $this->add_image_license_schema( $data );
			$data = $this->clean_empty_schema_values( $data );

			return $data;
		}

		/**
		 * Article schema enhancements.
		 *
		 * @param array $entity Article entity.
		 * @return array
		 */
		public function filter_article_schema( $entity ) {
			if ( ! is_singular( 'post' ) ) {
				return $entity;
			}

			$post_id = get_queried_object_id();

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

			$entity['@type'] = $this->is_medical_content( $post_id ) ? 'MedicalScholarlyArticle' : 'Article';

			$entity['isAccessibleForFree'] = true;
			$entity['inLanguage']          = get_bloginfo( 'language' );
			$entity['dateModified']        = get_the_modified_date( DATE_W3C, $post_id );
			$entity['datePublished']       = get_the_date( DATE_W3C, $post_id );

			$reviewed_by = get_post_meta( $post_id, '_rx_reviewed_by', true );

			if ( $reviewed_by ) {
				$entity['reviewedBy'] = array(
					'@type' => 'Person',
					'name'  => sanitize_text_field( $reviewed_by ),
				);
			}

			$medical_specialty = get_post_meta( $post_id, '_rx_medical_specialty', true );

			if ( $medical_specialty ) {
				$entity['medicalSpecialty'] = sanitize_text_field( $medical_specialty );
			}

			return $entity;
		}

		/**
		 * Product schema enhancements for WooCommerce.
		 *
		 * @param array $entity Product entity.
		 * @return array
		 */
		public function filter_product_schema( $entity ) {
			if ( ! function_exists( 'is_product' ) || ! is_product() ) {
				return $entity;
			}

			$product_id = get_queried_object_id();

			if ( ! $product_id ) {
				return $entity;
			}

			$entity['url'] = get_permalink( $product_id );

			if ( has_post_thumbnail( $product_id ) ) {
				$image = wp_get_attachment_image_url( get_post_thumbnail_id( $product_id ), 'full' );

				if ( $image ) {
					$entity['image'] = $image;
				}
			}

			return $entity;
		}

		/**
		 * Add website schema enhancements.
		 *
		 * @param array $data Schema data.
		 * @return array
		 */
		private function add_website_schema_enhancements( $data ) {
			if ( empty( $data['WebSite'] ) || ! is_array( $data['WebSite'] ) ) {
				return $data;
			}

			$data['WebSite']['name']        = get_bloginfo( 'name' );
			$data['WebSite']['description'] = get_bloginfo( 'description' );
			$data['WebSite']['inLanguage']  = get_bloginfo( 'language' );

			$search_url = home_url( '/?s={search_term_string}' );

			$data['WebSite']['potentialAction'] = array(
				'@type'       => 'SearchAction',
				'target'      => esc_url_raw( $search_url ),
				'query-input' => 'required name=search_term_string',
			);

			return $data;
		}

		/**
		 * Add medical schema when content looks medical.
		 *
		 * @param array $data Schema data.
		 * @return array
		 */
		private function add_medical_article_schema_if_needed( $data ) {
			if ( ! is_singular( 'post' ) ) {
				return $data;
			}

			$post_id = get_queried_object_id();

			if ( ! $post_id || ! $this->is_medical_content( $post_id ) ) {
				return $data;
			}

			$condition = get_post_meta( $post_id, '_rx_medical_condition', true );
			$specialty = get_post_meta( $post_id, '_rx_medical_specialty', true );

			$medical_web_page = array(
				'@type'              => 'MedicalWebPage',
				'@id'                => trailingslashit( get_permalink( $post_id ) ) . '#medical-webpage',
				'url'                => get_permalink( $post_id ),
				'name'               => get_the_title( $post_id ),
				'description'        => $this->filter_frontend_description( '' ),
				'lastReviewed'       => get_the_modified_date( DATE_W3C, $post_id ),
				'isAccessibleForFree'=> true,
				'inLanguage'         => get_bloginfo( 'language' ),
			);

			if ( $specialty ) {
				$medical_web_page['medicalSpecialty'] = sanitize_text_field( $specialty );
			}

			if ( $condition ) {
				$medical_web_page['about'] = array(
					'@type' => 'MedicalCondition',
					'name'  => sanitize_text_field( $condition ),
				);
			}

			$data['RXMedicalWebPage'] = $medical_web_page;

			return $data;
		}

		/**
		 * Author schema enhancements.
		 *
		 * @param array $data Schema data.
		 * @return array
		 */
		private function add_author_schema_enhancements( $data ) {
			if ( ! is_singular() ) {
				return $data;
			}

			$post = get_post();

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

			$author_id = (int) $post->post_author;

			if ( ! $author_id ) {
				return $data;
			}

			$author_url = get_author_posts_url( $author_id );

			$data['RXAuthor'] = array(
				'@type' => 'Person',
				'@id'   => trailingslashit( $author_url ) . '#person',
				'name'  => get_the_author_meta( 'display_name', $author_id ),
				'url'   => $author_url,
			);

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

			if ( $description ) {
				$data['RXAuthor']['description'] = wp_strip_all_tags( $description );
			}

			$same_as = array();

			$user_url = get_the_author_meta( 'user_url', $author_id );

			if ( $user_url ) {
				$same_as[] = esc_url_raw( $user_url );
			}

			$social_fields = array(
				'facebook',
				'twitter',
				'linkedin',
				'instagram',
				'youtube',
				'github',
			);

			foreach ( $social_fields as $field ) {
				$value = get_the_author_meta( $field, $author_id );

				if ( $value ) {
					$same_as[] = esc_url_raw( $value );
				}
			}

			if ( ! empty( $same_as ) ) {
				$data['RXAuthor']['sameAs'] = array_values( array_unique( $same_as ) );
			}

			return $data;
		}

		/**
		 * Image license schema.
		 *
		 * @param array $data Schema data.
		 * @return array
		 */
		private function add_image_license_schema( $data ) {
			if ( ! is_singular() || ! has_post_thumbnail() ) {
				return $data;
			}

			$post_id = get_queried_object_id();
			$image_id = get_post_thumbnail_id( $post_id );
			$image_url = wp_get_attachment_image_url( $image_id, 'full' );

			if ( ! $image_url ) {
				return $data;
			}

			$caption = wp_get_attachment_caption( $image_id );
			$alt     = get_post_meta( $image_id, '_wp_attachment_image_alt', true );

			$data['RXPrimaryImage'] = array(
				'@type'      => 'ImageObject',
				'@id'        => trailingslashit( get_permalink( $post_id ) ) . '#primaryimage',
				'url'        => esc_url_raw( $image_url ),
				'contentUrl' => esc_url_raw( $image_url ),
				'caption'    => $caption ? wp_strip_all_tags( $caption ) : get_the_title( $post_id ),
				'name'       => $alt ? wp_strip_all_tags( $alt ) : get_the_title( $post_id ),
			);

			$license_url = get_theme_mod( 'rx_image_license_url' );

			if ( $license_url ) {
				$data['RXPrimaryImage']['license'] = esc_url_raw( $license_url );
			}

			return $data;
		}

		/**
		 * Clean empty schema values recursively.
		 *
		 * @param mixed $value Schema data.
		 * @return mixed
		 */
		private function clean_empty_schema_values( $value ) {
			if ( is_array( $value ) ) {
				foreach ( $value as $key => $item ) {
					$value[ $key ] = $this->clean_empty_schema_values( $item );

					if (
						'' === $value[ $key ] ||
						null === $value[ $key ] ||
						array() === $value[ $key ]
					) {
						unset( $value[ $key ] );
					}
				}
			}

			return $value;
		}

		/**
		 * Sitemap entry filter.
		 *
		 * @param string|false $url URL.
		 * @param string       $type Object type.
		 * @param object       $object Object.
		 * @return string|false
		 */
		public function filter_sitemap_entry( $url, $type, $object ) {
			if ( 'post' === $type && isset( $object->ID ) ) {
				$noindex = get_post_meta( $object->ID, 'rank_math_robots', true );

				if ( is_array( $noindex ) && in_array( 'noindex', $noindex, true ) ) {
					return false;
				}

				$rx_hide = get_post_meta( $object->ID, '_rx_hide_from_sitemap', true );

				if ( '1' === (string) $rx_hide ) {
					return false;
				}
			}

			return $url;
		}

		/**
		 * Exclude post types from sitemap.
		 *
		 * @param bool   $exclude Whether to exclude.
		 * @param string $post_type Post type.
		 * @return bool
		 */
		public function exclude_post_type_from_sitemap( $exclude, $post_type ) {
			$excluded = array(
				'revision',
				'nav_menu_item',
				'custom_css',
				'customize_changeset',
				'oembed_cache',
				'user_request',
				'wp_block',
				'wp_template',
				'wp_template_part',
				'wp_global_styles',
				'wp_navigation',
			);

			if ( in_array( $post_type, $excluded, true ) ) {
				return true;
			}

			return $exclude;
		}

		/**
		 * Exclude taxonomies from sitemap.
		 *
		 * @param bool   $exclude Whether to exclude.
		 * @param string $taxonomy Taxonomy name.
		 * @return bool
		 */
		public function exclude_taxonomy_from_sitemap( $exclude, $taxonomy ) {
			$excluded = array(
				'nav_menu',
				'link_category',
				'post_format',
				'wp_theme',
				'wp_template_part_area',
			);

			if ( in_array( $taxonomy, $excluded, true ) ) {
				return true;
			}

			return $exclude;
		}

		/**
		 * Add custom builder content to Rank Math content analysis.
		 *
		 * @param string $content Existing content.
		 * @param int    $post_id Post ID.
		 * @return string
		 */
		public function add_builder_content_to_rank_math_analysis( $content, $post_id ) {
			$extra_fields = array(
				'_rx_hero_title',
				'_rx_hero_subtitle',
				'_rx_summary',
				'_rx_faq_content',
				'_rx_medical_condition',
				'_rx_medical_specialty',
				'_rx_reviewed_by',
			);

			foreach ( $extra_fields as $field ) {
				$value = get_post_meta( $post_id, $field, true );

				if ( $value ) {
					$content .= "\n\n" . wp_strip_all_tags( $value );
				}
			}

			return $content;
		}

		/**
		 * Add custom settings placeholder.
		 *
		 * @param array $tabs Rank Math settings tabs.
		 * @return array
		 */
		public function register_rank_math_theme_settings( $tabs ) {
			return $tabs;
		}

		/**
		 * Print extra safe meta.
		 *
		 * @return void
		 */
		public function print_rx_extra_meta() {
			if ( is_admin() || is_feed() ) {
				return;
			}

			echo "\n" . '<!-- RX Theme Rank Math Integration Active -->' . "\n";

			if ( is_singular() ) {
				$post_id = get_queried_object_id();

				$reviewed_by = get_post_meta( $post_id, '_rx_reviewed_by', true );
				$reviewed_on = get_post_meta( $post_id, '_rx_reviewed_on', true );

				if ( $reviewed_by ) {
					echo '<meta name="rx:reviewed_by" content="' . esc_attr( $reviewed_by ) . '">' . "\n";
				}

				if ( $reviewed_on ) {
					echo '<meta name="rx:reviewed_on" content="' . esc_attr( $reviewed_on ) . '">' . "\n";
				}
			}
		}

		/**
		 * Check if paged archive is thin.
		 *
		 * @return bool
		 */
		private function is_thin_paged_archive() {
			if ( ! is_paged() ) {
				return false;
			}

			if ( is_category() || is_tag() || is_tax() || is_post_type_archive() ) {
				global $wp_query;

				if ( isset( $wp_query->post_count ) && $wp_query->post_count < 3 ) {
					return true;
				}
			}

			return false;
		}

		/**
		 * Is medical content.
		 *
		 * @param int $post_id Post ID.
		 * @return bool
		 */
		private function is_medical_content( $post_id ) {
			$medical_flag = get_post_meta( $post_id, '_rx_is_medical_content', true );

			if ( '1' === (string) $medical_flag ) {
				return true;
			}

			$condition = get_post_meta( $post_id, '_rx_medical_condition', true );

			if ( $condition ) {
				return true;
			}

			$categories = wp_get_post_terms( $post_id, 'category', array( 'fields' => 'slugs' ) );

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

			$medical_slugs = array(
				'medical',
				'health',
				'disease',
				'diseases',
				'medicine',
				'diagnosis',
				'treatment',
				'anatomy',
				'pathology',
			);

			return (bool) array_intersect( $medical_slugs, $categories );
		}

		/**
		 * Limit text safely.
		 *
		 * @param string $text Text.
		 * @param int    $limit Character limit.
		 * @return string
		 */
		private function limit_text( $text, $limit = 160 ) {
			$text = wp_strip_all_tags( strip_shortcodes( (string) $text ) );
			$text = preg_replace( '/\s+/', ' ', $text );
			$text = trim( $text );

			if ( function_exists( 'mb_strlen' ) && mb_strlen( $text ) > $limit ) {
				$text = mb_substr( $text, 0, $limit - 3 ) . '...';
			} elseif ( strlen( $text ) > $limit ) {
				$text = substr( $text, 0, $limit - 3 ) . '...';
			}

			return $text;
		}
	}

endif;

/**
 * Boot integration.
 */
RX_Theme_Rank_Math_Integration::instance();

/**
 * RX breadcrumb helper.
 *
 * Use in theme template:
 *
 * rx_theme_breadcrumbs();
 *
 * @return void
 */
if ( ! function_exists( 'rx_theme_breadcrumbs' ) ) :
	function rx_theme_breadcrumbs() {
		if ( function_exists( 'rank_math_the_breadcrumbs' ) ) {
			rank_math_the_breadcrumbs();
			return;
		}

		if ( is_front_page() ) {
			return;
		}

		echo '<nav class="rx-breadcrumbs rx-breadcrumbs-fallback" aria-label="' . esc_attr__( 'Breadcrumb', 'rx-theme' ) . '">';
		echo '<ol class="rx-breadcrumb-list">';
		echo '<li><a href="' . esc_url( home_url( '/' ) ) . '">' . esc_html__( 'Home', 'rx-theme' ) . '</a></li>';

		if ( is_singular() ) {
			echo '<li aria-current="page">' . esc_html( get_the_title() ) . '</li>';
		} elseif ( is_archive() ) {
			echo '<li aria-current="page">' . esc_html( wp_strip_all_tags( get_the_archive_title() ) ) . '</li>';
		} elseif ( is_search() ) {
			echo '<li aria-current="page">' . esc_html__( 'Search', 'rx-theme' ) . '</li>';
		} elseif ( is_404() ) {
			echo '<li aria-current="page">' . esc_html__( '404', 'rx-theme' ) . '</li>';
		}

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

/**
 * RX schema meta helper.
 *
 * Example:
 * rx_theme_set_medical_schema_meta( get_the_ID(), 'Diabetes Mellitus', 'Endocrinology', 'Dr. RX Harun' );
 *
 * @param int    $post_id Post ID.
 * @param string $condition Medical condition.
 * @param string $specialty Medical specialty.
 * @param string $reviewed_by Reviewer name.
 * @return void
 */
if ( ! function_exists( 'rx_theme_set_medical_schema_meta' ) ) :
	function rx_theme_set_medical_schema_meta( $post_id, $condition = '', $specialty = '', $reviewed_by = '' ) {
		$post_id = absint( $post_id );

		if ( ! $post_id ) {
			return;
		}

		update_post_meta( $post_id, '_rx_is_medical_content', '1' );

		if ( $condition ) {
			update_post_meta( $post_id, '_rx_medical_condition', sanitize_text_field( $condition ) );
		}

		if ( $specialty ) {
			update_post_meta( $post_id, '_rx_medical_specialty', sanitize_text_field( $specialty ) );
		}

		if ( $reviewed_by ) {
			update_post_meta( $post_id, '_rx_reviewed_by', sanitize_text_field( $reviewed_by ) );
			update_post_meta( $post_id, '_rx_reviewed_on', current_time( 'Y-m-d' ) );
		}
	}
endif;

Then load it from your theme functions.php:

/**
 * RX Theme Rank Math Integration.
 */
$rx_rank_math_file = get_template_directory() . '/inc/integrations/rank-math.php';

if ( file_exists( $rx_rank_math_file ) ) {
	require_once $rx_rank_math_file;
}

Optional breadcrumb use in template, for example in single.php, page.php, or archive.php:

<?php
if ( function_exists( 'rx_theme_breadcrumbs' ) ) {
	rx_theme_breadcrumbs();
}
?>

Optional CSS:

.rx-breadcrumbs {
	margin: 0 0 20px;
	font-size: 14px;
	line-height: 1.6;
}

.rx-breadcrumb-list {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.rx-breadcrumb-list a {
	text-decoration: none;
}

.rx-breadcrumb-separator {
	opacity: 0.65;
}

Important note: keep your actual SEO title, meta description, schema type, sitemap settings, and social image defaults configured inside Rank Math SEO settings first. This file is an advanced theme-side enhancement, not a replacement for Rank Math’s dashboard settings.

Leave a Reply

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