I’ll build this as a reusable inc/helpers/schema.php module for your RX WordPress theme, with JSON-LD output, medical article support, breadcrumbs, organization, website, author, FAQ, HowTo, and safety checks.
Yes my friend. Below is an advanced schema.php file for your rx-theme/inc/helpers/schema.php.
It includes many possible schema features for RX theme:
- Website schema
- Organization schema
- Medical organization schema
- WebPage schema
- Article / BlogPosting / MedicalWebPage schema
- Breadcrumb schema
- Person / Author schema
- Publisher schema
- ImageObject schema
- FAQ schema from post meta
- HowTo schema from post meta
- MedicalCondition schema
- MedicalSignOrSymptom schema
- MedicalTest schema
- Speakable schema
- SearchAction schema
- Logo schema
- Social profile support
- Archive / Category / Tag schema
- Single post schema
- Page schema
- Homepage schema
- Attachment image schema
- Safe JSON-LD output
- Developer filters for future extension
inc/helpers/schema.php
<?php
/**
* RX Theme Advanced Schema Markup
*
* File: inc/helpers/schema.php
*
* Adds advanced JSON-LD schema markup for:
* - Website
* - Organization
* - MedicalOrganization
* - WebPage
* - BlogPosting
* - Article
* - MedicalWebPage
* - MedicalCondition
* - BreadcrumbList
* - Person / Author
* - FAQPage
* - HowTo
* - MedicalTest
* - MedicalSignOrSymptom
* - ImageObject
* - SearchAction
* - SpeakableSpecification
*
* @package RX_Theme
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Do not redeclare.
*/
if ( ! class_exists( 'RX_Advanced_Schema' ) ) :
final class RX_Advanced_Schema {
/**
* Schema context.
*
* @var string
*/
private static $context = 'https://schema.org';
/**
* Init hooks.
*/
public static function init() {
add_action( 'wp_head', array( __CLASS__, 'output_schema' ), 20 );
}
/**
* Main schema output.
*/
public static function output_schema() {
if ( is_admin() || is_feed() || is_robots() || is_trackback() ) {
return;
}
$schemas = array();
$schemas[] = self::website_schema();
$schemas[] = self::organization_schema();
if ( self::is_medical_site_enabled() ) {
$schemas[] = self::medical_organization_schema();
}
$schemas[] = self::webpage_schema();
$schemas[] = self::breadcrumb_schema();
if ( is_front_page() || is_home() ) {
$schemas[] = self::homepage_schema();
}
if ( is_singular( 'post' ) ) {
$schemas[] = self::article_schema();
if ( self::is_medical_article() ) {
$schemas[] = self::medical_webpage_schema();
$schemas[] = self::medical_condition_schema();
$schemas[] = self::medical_symptom_schema();
$schemas[] = self::medical_test_schema();
}
$schemas[] = self::faq_schema();
$schemas[] = self::howto_schema();
}
if ( is_page() && ! is_front_page() ) {
$schemas[] = self::page_schema();
$schemas[] = self::faq_schema();
$schemas[] = self::howto_schema();
}
if ( is_author() ) {
$schemas[] = self::author_archive_schema();
}
if ( is_category() || is_tag() || is_tax() ) {
$schemas[] = self::collection_page_schema();
}
if ( is_attachment() ) {
$schemas[] = self::attachment_schema();
}
$schemas = array_filter( $schemas );
/**
* Allow child theme or plugin to modify all schema pieces.
*
* Example:
* add_filter( 'rx_schema_graph', function( $schemas ) {
* $schemas[] = array(
* '@type' => 'Thing',
* 'name' => 'Custom Schema',
* );
* return $schemas;
* });
*/
$schemas = apply_filters( 'rx_schema_graph', $schemas );
if ( empty( $schemas ) ) {
return;
}
$output = array(
'@context' => self::$context,
'@graph' => array_values( $schemas ),
);
echo "\n" . '<script type="application/ld+json" class="rx-schema-jsonld">' . "\n";
echo wp_json_encode(
$output,
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
);
echo "\n" . '</script>' . "\n";
}
/**
* Website schema.
*/
private static function website_schema() {
$site_name = get_bloginfo( 'name' );
$site_url = home_url( '/' );
$schema = array(
'@type' => 'WebSite',
'@id' => trailingslashit( $site_url ) . '#website',
'url' => $site_url,
'name' => $site_name,
'description' => get_bloginfo( 'description' ),
'publisher' => array(
'@id' => trailingslashit( $site_url ) . '#organization',
),
'potentialAction' => array(
'@type' => 'SearchAction',
'target' => add_query_arg( 's', '{search_term_string}', home_url( '/' ) ),
'query-input' => 'required name=search_term_string',
),
'inLanguage' => self::language(),
);
return apply_filters( 'rx_schema_website', $schema );
}
/**
* Organization schema.
*/
private static function organization_schema() {
$site_url = home_url( '/' );
$site_name = get_bloginfo( 'name' );
$logo = self::site_logo_url();
$schema = array(
'@type' => 'Organization',
'@id' => trailingslashit( $site_url ) . '#organization',
'name' => $site_name,
'url' => $site_url,
'description' => get_bloginfo( 'description' ),
'logo' => $logo ? array(
'@type' => 'ImageObject',
'url' => $logo,
) : null,
'image' => $logo ? $logo : null,
'sameAs' => self::social_profiles(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_organization', $schema );
}
/**
* Medical organization schema.
*/
private static function medical_organization_schema() {
$site_url = home_url( '/' );
$site_name = get_bloginfo( 'name' );
$logo = self::site_logo_url();
$schema = array(
'@type' => 'MedicalOrganization',
'@id' => trailingslashit( $site_url ) . '#medical-organization',
'name' => $site_name,
'url' => $site_url,
'description' => get_bloginfo( 'description' ),
'logo' => $logo ? array(
'@type' => 'ImageObject',
'url' => $logo,
) : null,
'image' => $logo ? $logo : null,
'medicalSpecialty' => self::medical_specialties(),
'sameAs' => self::social_profiles(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_medical_organization', $schema );
}
/**
* HomePage schema.
*/
private static function homepage_schema() {
$schema = array(
'@type' => 'WebPage',
'@id' => home_url( '/' ) . '#homepage',
'url' => home_url( '/' ),
'name' => get_bloginfo( 'name' ),
'description' => get_bloginfo( 'description' ),
'isPartOf' => array(
'@id' => home_url( '/' ) . '#website',
),
'about' => array(
'@id' => home_url( '/' ) . '#organization',
),
'inLanguage' => self::language(),
);
return apply_filters( 'rx_schema_homepage', $schema );
}
/**
* Generic WebPage schema.
*/
private static function webpage_schema() {
$url = self::current_url();
$title = self::current_title();
$schema = array(
'@type' => self::webpage_type(),
'@id' => trailingslashit( $url ) . '#webpage',
'url' => $url,
'name' => $title,
'isPartOf' => array(
'@id' => home_url( '/' ) . '#website',
),
'about' => array(
'@id' => home_url( '/' ) . '#organization',
),
'inLanguage' => self::language(),
);
if ( is_singular() ) {
$post_id = get_queried_object_id();
$schema['datePublished'] = get_the_date( DATE_W3C, $post_id );
$schema['dateModified'] = get_the_modified_date( DATE_W3C, $post_id );
$excerpt = self::post_excerpt( $post_id );
if ( $excerpt ) {
$schema['description'] = $excerpt;
}
$image = self::featured_image_schema( $post_id );
if ( $image ) {
$schema['primaryImageOfPage'] = $image;
}
$schema['breadcrumb'] = array(
'@id' => trailingslashit( $url ) . '#breadcrumb',
);
$schema['speakable'] = self::speakable_schema();
}
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_webpage', $schema );
}
/**
* Detect webpage type.
*/
private static function webpage_type() {
if ( is_front_page() ) {
return 'WebPage';
}
if ( is_search() ) {
return 'SearchResultsPage';
}
if ( is_category() || is_tag() || is_tax() || is_archive() ) {
return 'CollectionPage';
}
if ( is_singular( 'post' ) && self::is_medical_article() ) {
return 'MedicalWebPage';
}
if ( is_singular() ) {
return 'WebPage';
}
return 'WebPage';
}
/**
* Article schema.
*/
private static function article_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$url = get_permalink( $post_id );
$title = get_the_title( $post_id );
$excerpt = self::post_excerpt( $post_id );
$image = self::featured_image_schema( $post_id );
$word_count = self::word_count( $post_id );
$schema = array(
'@type' => self::article_type(),
'@id' => trailingslashit( $url ) . '#article',
'mainEntityOfPage' => array(
'@id' => trailingslashit( $url ) . '#webpage',
),
'headline' => wp_strip_all_tags( $title ),
'description' => $excerpt,
'image' => $image,
'datePublished' => get_the_date( DATE_W3C, $post_id ),
'dateModified' => get_the_modified_date( DATE_W3C, $post_id ),
'author' => self::author_schema( (int) get_post_field( 'post_author', $post_id ) ),
'publisher' => array(
'@id' => home_url( '/' ) . '#organization',
),
'articleSection' => self::post_categories( $post_id ),
'keywords' => self::post_keywords( $post_id ),
'wordCount' => $word_count,
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_article', $schema, $post_id );
}
/**
* Article type.
*/
private static function article_type() {
if ( self::is_medical_article() ) {
return 'MedicalScholarlyArticle';
}
return 'BlogPosting';
}
/**
* Medical WebPage schema.
*/
private static function medical_webpage_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$url = get_permalink( $post_id );
$schema = array(
'@type' => 'MedicalWebPage',
'@id' => trailingslashit( $url ) . '#medical-webpage',
'url' => $url,
'name' => get_the_title( $post_id ),
'description' => self::post_excerpt( $post_id ),
'isPartOf' => array(
'@id' => home_url( '/' ) . '#website',
),
'publisher' => array(
'@id' => home_url( '/' ) . '#medical-organization',
),
'author' => self::author_schema( (int) get_post_field( 'post_author', $post_id ) ),
'reviewedBy' => self::reviewed_by_schema( $post_id ),
'lastReviewed' => self::post_meta( $post_id, '_rx_last_reviewed' ),
'medicalAudience' => array(
'@type' => 'MedicalAudience',
'audienceType' => 'Patient',
),
'specialty' => self::medical_specialties(),
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_medical_webpage', $schema, $post_id );
}
/**
* Medical condition schema.
*
* Recommended post meta fields:
* _rx_medical_condition_name
* _rx_medical_condition_description
* _rx_medical_condition_causes
* _rx_medical_condition_symptoms
* _rx_medical_condition_tests
* _rx_medical_condition_treatments
*/
private static function medical_condition_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id || ! self::is_medical_article() ) {
return null;
}
$name = self::post_meta( $post_id, '_rx_medical_condition_name' );
if ( ! $name ) {
$name = get_the_title( $post_id );
}
$description = self::post_meta( $post_id, '_rx_medical_condition_description' );
if ( ! $description ) {
$description = self::post_excerpt( $post_id );
}
$schema = array(
'@type' => 'MedicalCondition',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#medical-condition',
'name' => wp_strip_all_tags( $name ),
'description' => wp_strip_all_tags( $description ),
'url' => get_permalink( $post_id ),
'possibleTreatment' => self::medical_treatments_from_meta( $post_id ),
'signOrSymptom' => self::medical_symptoms_from_meta( $post_id ),
'cause' => self::medical_causes_from_meta( $post_id ),
'diagnosis' => self::medical_tests_from_meta( $post_id ),
'associatedAnatomy' => self::medical_anatomy_from_meta( $post_id ),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_medical_condition', $schema, $post_id );
}
/**
* Medical symptom schema.
*/
private static function medical_symptom_schema() {
$post_id = get_queried_object_id();
$symptoms = self::array_meta( $post_id, '_rx_medical_condition_symptoms' );
if ( empty( $symptoms ) ) {
return null;
}
$items = array();
foreach ( $symptoms as $symptom ) {
$items[] = array(
'@type' => 'MedicalSignOrSymptom',
'name' => wp_strip_all_tags( $symptom ),
);
}
$schema = array(
'@type' => 'ItemList',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#medical-symptoms',
'name' => 'Signs and symptoms of ' . get_the_title( $post_id ),
'itemListElement' => self::item_list_elements( $items ),
);
return apply_filters( 'rx_schema_medical_symptoms', $schema, $post_id );
}
/**
* Medical test schema.
*/
private static function medical_test_schema() {
$post_id = get_queried_object_id();
$tests = self::array_meta( $post_id, '_rx_medical_condition_tests' );
if ( empty( $tests ) ) {
return null;
}
$items = array();
foreach ( $tests as $test ) {
$items[] = array(
'@type' => 'MedicalTest',
'name' => wp_strip_all_tags( $test ),
);
}
$schema = array(
'@type' => 'ItemList',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#medical-tests',
'name' => 'Diagnostic tests for ' . get_the_title( $post_id ),
'itemListElement' => self::item_list_elements( $items ),
);
return apply_filters( 'rx_schema_medical_tests', $schema, $post_id );
}
/**
* Page schema.
*/
private static function page_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$schema = array(
'@type' => 'WebPage',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#page',
'url' => get_permalink( $post_id ),
'name' => get_the_title( $post_id ),
'description' => self::post_excerpt( $post_id ),
'datePublished' => get_the_date( DATE_W3C, $post_id ),
'dateModified' => get_the_modified_date( DATE_W3C, $post_id ),
'isPartOf' => array(
'@id' => home_url( '/' ) . '#website',
),
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_page', $schema, $post_id );
}
/**
* Breadcrumb schema.
*/
private static function breadcrumb_schema() {
if ( is_front_page() ) {
return null;
}
$items = array();
$pos = 1;
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => __( 'Home', 'rx-theme' ),
'item' => home_url( '/' ),
);
if ( is_singular() ) {
$post_id = get_queried_object_id();
if ( is_singular( 'post' ) ) {
$categories = get_the_category( $post_id );
if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
$cat = $categories[0];
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => $cat->name,
'item' => get_category_link( $cat->term_id ),
);
}
}
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => get_the_title( $post_id ),
'item' => get_permalink( $post_id ),
);
} elseif ( is_category() || is_tag() || is_tax() ) {
$term = get_queried_object();
if ( $term && ! is_wp_error( $term ) ) {
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => single_term_title( '', false ),
'item' => get_term_link( $term ),
);
}
} elseif ( is_search() ) {
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => sprintf(
/* translators: %s search query */
__( 'Search results for %s', 'rx-theme' ),
get_search_query()
),
'item' => self::current_url(),
);
} elseif ( is_author() ) {
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => get_the_author_meta( 'display_name', get_queried_object_id() ),
'item' => self::current_url(),
);
} elseif ( is_archive() ) {
$items[] = array(
'@type' => 'ListItem',
'position' => $pos++,
'name' => get_the_archive_title(),
'item' => self::current_url(),
);
}
$schema = array(
'@type' => 'BreadcrumbList',
'@id' => trailingslashit( self::current_url() ) . '#breadcrumb',
'itemListElement' => $items,
);
return apply_filters( 'rx_schema_breadcrumb', $schema );
}
/**
* Author schema.
*/
private static function author_schema( $author_id ) {
if ( ! $author_id ) {
return null;
}
$name = get_the_author_meta( 'display_name', $author_id );
$description = get_the_author_meta( 'description', $author_id );
$url = get_author_posts_url( $author_id );
$avatar = get_avatar_url( $author_id, array( 'size' => 256 ) );
$schema = array(
'@type' => 'Person',
'@id' => trailingslashit( $url ) . '#author',
'name' => $name,
'url' => $url,
'description' => $description,
'image' => $avatar ? array(
'@type' => 'ImageObject',
'url' => $avatar,
) : null,
'worksFor' => array(
'@id' => home_url( '/' ) . '#organization',
),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_author', $schema, $author_id );
}
/**
* Reviewed by schema.
*
* Optional post meta:
* _rx_reviewed_by_name
* _rx_reviewed_by_url
*/
private static function reviewed_by_schema( $post_id ) {
$name = self::post_meta( $post_id, '_rx_reviewed_by_name' );
$url = self::post_meta( $post_id, '_rx_reviewed_by_url' );
if ( ! $name ) {
return null;
}
$schema = array(
'@type' => 'Person',
'name' => wp_strip_all_tags( $name ),
'url' => esc_url_raw( $url ),
);
return self::remove_empty_items( $schema );
}
/**
* Author archive schema.
*/
private static function author_archive_schema() {
$author_id = get_queried_object_id();
if ( ! $author_id ) {
return null;
}
$schema = array(
'@type' => 'ProfilePage',
'@id' => trailingslashit( get_author_posts_url( $author_id ) ) . '#profile',
'url' => get_author_posts_url( $author_id ),
'name' => get_the_author_meta( 'display_name', $author_id ),
'description' => get_the_author_meta( 'description', $author_id ),
'mainEntity' => self::author_schema( $author_id ),
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_author_archive', $schema, $author_id );
}
/**
* Collection page schema.
*/
private static function collection_page_schema() {
$title = wp_strip_all_tags( get_the_archive_title() );
$desc = wp_strip_all_tags( get_the_archive_description() );
$schema = array(
'@type' => 'CollectionPage',
'@id' => trailingslashit( self::current_url() ) . '#collection',
'url' => self::current_url(),
'name' => $title,
'description' => $desc,
'isPartOf' => array(
'@id' => home_url( '/' ) . '#website',
),
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_collection_page', $schema );
}
/**
* Attachment schema.
*/
private static function attachment_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$mime = get_post_mime_type( $post_id );
if ( ! $mime || false === strpos( $mime, 'image' ) ) {
return null;
}
$image = wp_get_attachment_image_src( $post_id, 'full' );
if ( ! $image ) {
return null;
}
$schema = array(
'@type' => 'ImageObject',
'@id' => trailingslashit( get_attachment_link( $post_id ) ) . '#image',
'url' => wp_get_attachment_url( $post_id ),
'contentUrl' => wp_get_attachment_url( $post_id ),
'name' => get_the_title( $post_id ),
'description' => wp_get_attachment_caption( $post_id ),
'width' => isset( $image[1] ) ? absint( $image[1] ) : null,
'height' => isset( $image[2] ) ? absint( $image[2] ) : null,
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_attachment', $schema, $post_id );
}
/**
* FAQ schema.
*
* Supported post meta format:
* _rx_faqs = array(
* array(
* 'question' => 'What is anemia?',
* 'answer' => 'Anemia is...'
* )
* )
*
* Also supports JSON string.
*/
private static function faq_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$faqs = get_post_meta( $post_id, '_rx_faqs', true );
$faqs = self::normalize_repeater_meta( $faqs );
if ( empty( $faqs ) ) {
return null;
}
$main_entity = array();
foreach ( $faqs as $faq ) {
if ( empty( $faq['question'] ) || empty( $faq['answer'] ) ) {
continue;
}
$main_entity[] = array(
'@type' => 'Question',
'name' => wp_strip_all_tags( $faq['question'] ),
'acceptedAnswer' => array(
'@type' => 'Answer',
'text' => wp_kses_post( $faq['answer'] ),
),
);
}
if ( empty( $main_entity ) ) {
return null;
}
$schema = array(
'@type' => 'FAQPage',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#faq',
'mainEntity' => $main_entity,
);
return apply_filters( 'rx_schema_faq', $schema, $post_id );
}
/**
* HowTo schema.
*
* Supported post meta:
* _rx_howto_name
* _rx_howto_description
* _rx_howto_steps = array(
* array(
* 'name' => 'Step title',
* 'text' => 'Step description'
* )
* )
*/
private static function howto_schema() {
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return null;
}
$name = self::post_meta( $post_id, '_rx_howto_name' );
$description = self::post_meta( $post_id, '_rx_howto_description' );
$steps = get_post_meta( $post_id, '_rx_howto_steps', true );
$steps = self::normalize_repeater_meta( $steps );
if ( empty( $name ) || empty( $steps ) ) {
return null;
}
$step_items = array();
$position = 1;
foreach ( $steps as $step ) {
if ( empty( $step['text'] ) ) {
continue;
}
$step_items[] = array(
'@type' => 'HowToStep',
'position' => $position++,
'name' => ! empty( $step['name'] ) ? wp_strip_all_tags( $step['name'] ) : '',
'text' => wp_strip_all_tags( $step['text'] ),
);
}
if ( empty( $step_items ) ) {
return null;
}
$schema = array(
'@type' => 'HowTo',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#howto',
'name' => wp_strip_all_tags( $name ),
'description' => wp_strip_all_tags( $description ),
'step' => $step_items,
'inLanguage' => self::language(),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_howto', $schema, $post_id );
}
/**
* Speakable schema.
*/
private static function speakable_schema() {
if ( ! is_singular() ) {
return null;
}
$schema = array(
'@type' => 'SpeakableSpecification',
'cssSelector' => array(
'h1',
'.entry-title',
'.entry-content p:first-of-type',
),
);
return apply_filters( 'rx_schema_speakable', $schema );
}
/**
* Featured image schema.
*/
private static function featured_image_schema( $post_id ) {
if ( ! has_post_thumbnail( $post_id ) ) {
return null;
}
$image_id = get_post_thumbnail_id( $post_id );
$image = wp_get_attachment_image_src( $image_id, 'full' );
if ( ! $image ) {
return null;
}
$schema = array(
'@type' => 'ImageObject',
'@id' => trailingslashit( get_permalink( $post_id ) ) . '#primaryimage',
'url' => esc_url_raw( $image[0] ),
'width' => isset( $image[1] ) ? absint( $image[1] ) : null,
'height' => isset( $image[2] ) ? absint( $image[2] ) : null,
'caption' => wp_get_attachment_caption( $image_id ),
);
$schema = self::remove_empty_items( $schema );
return apply_filters( 'rx_schema_featured_image', $schema, $post_id );
}
/**
* Medical treatments from meta.
*/
private static function medical_treatments_from_meta( $post_id ) {
$treatments = self::array_meta( $post_id, '_rx_medical_condition_treatments' );
if ( empty( $treatments ) ) {
return null;
}
$output = array();
foreach ( $treatments as $treatment ) {
$output[] = array(
'@type' => 'MedicalTherapy',
'name' => wp_strip_all_tags( $treatment ),
);
}
return $output;
}
/**
* Medical symptoms from meta.
*/
private static function medical_symptoms_from_meta( $post_id ) {
$symptoms = self::array_meta( $post_id, '_rx_medical_condition_symptoms' );
if ( empty( $symptoms ) ) {
return null;
}
$output = array();
foreach ( $symptoms as $symptom ) {
$output[] = array(
'@type' => 'MedicalSignOrSymptom',
'name' => wp_strip_all_tags( $symptom ),
);
}
return $output;
}
/**
* Medical causes from meta.
*/
private static function medical_causes_from_meta( $post_id ) {
$causes = self::array_meta( $post_id, '_rx_medical_condition_causes' );
if ( empty( $causes ) ) {
return null;
}
$output = array();
foreach ( $causes as $cause ) {
$output[] = array(
'@type' => 'MedicalCause',
'name' => wp_strip_all_tags( $cause ),
);
}
return $output;
}
/**
* Medical tests from meta.
*/
private static function medical_tests_from_meta( $post_id ) {
$tests = self::array_meta( $post_id, '_rx_medical_condition_tests' );
if ( empty( $tests ) ) {
return null;
}
$output = array();
foreach ( $tests as $test ) {
$output[] = array(
'@type' => 'MedicalTest',
'name' => wp_strip_all_tags( $test ),
);
}
return $output;
}
/**
* Medical anatomy from meta.
*/
private static function medical_anatomy_from_meta( $post_id ) {
$items = self::array_meta( $post_id, '_rx_medical_anatomy' );
if ( empty( $items ) ) {
return null;
}
$output = array();
foreach ( $items as $item ) {
$output[] = array(
'@type' => 'AnatomicalStructure',
'name' => wp_strip_all_tags( $item ),
);
}
return $output;
}
/**
* ItemList helper.
*/
private static function item_list_elements( $items ) {
$output = array();
$position = 1;
foreach ( $items as $item ) {
$output[] = array(
'@type' => 'ListItem',
'position' => $position++,
'item' => $item,
);
}
return $output;
}
/**
* Check if medical schema is globally enabled.
*/
private static function is_medical_site_enabled() {
/**
* Default true for RX theme because your site is medical focused.
*/
return (bool) apply_filters( 'rx_schema_enable_medical_site', true );
}
/**
* Detect medical article.
*/
private static function is_medical_article() {
if ( ! is_singular( 'post' ) ) {
return false;
}
$post_id = get_queried_object_id();
$enabled = get_post_meta( $post_id, '_rx_is_medical_article', true );
if ( 'no' === $enabled ) {
return false;
}
if ( 'yes' === $enabled ) {
return true;
}
$categories = wp_get_post_categories( $post_id, array( 'fields' => 'names' ) );
$tags = wp_get_post_tags( $post_id, array( 'fields' => 'names' ) );
$all_terms = array_merge( (array) $categories, (array) $tags );
$keywords = array(
'medical',
'health',
'disease',
'condition',
'symptom',
'diagnosis',
'treatment',
'medicine',
'doctor',
'anatomy',
'pathology',
'therapy',
'surgery',
'drug',
'clinical',
);
foreach ( $all_terms as $term ) {
foreach ( $keywords as $keyword ) {
if ( false !== stripos( $term, $keyword ) ) {
return true;
}
}
}
return (bool) apply_filters( 'rx_schema_is_medical_article', true, $post_id );
}
/**
* Medical specialties.
*/
private static function medical_specialties() {
$specialties = array(
'PrimaryCare',
'InternalMedicine',
'Cardiovascular',
'Dermatologic',
'Endocrine',
'Gastroenterologic',
'Genetic',
'Geriatric',
'Gynecologic',
'Hematologic',
'Infectious',
'Neurologic',
'Oncologic',
'Ophthalmologic',
'Orthopedic',
'Otolaryngologic',
'Pediatric',
'Psychiatric',
'Pulmonary',
'Renal',
'Rheumatologic',
);
return apply_filters( 'rx_schema_medical_specialties', $specialties );
}
/**
* Social profiles.
*
* You may edit these links manually.
*/
private static function social_profiles() {
$profiles = array(
// 'https://www.facebook.com/your-page',
// 'https://twitter.com/your-handle',
// 'https://www.linkedin.com/company/your-company',
// 'https://www.youtube.com/@yourchannel',
// 'https://www.pinterest.com/yourprofile',
);
return apply_filters( 'rx_schema_social_profiles', array_filter( $profiles ) );
}
/**
* Site logo URL.
*/
private static function site_logo_url() {
$custom_logo_id = get_theme_mod( 'custom_logo' );
if ( $custom_logo_id ) {
$logo = wp_get_attachment_image_src( $custom_logo_id, 'full' );
if ( ! empty( $logo[0] ) ) {
return esc_url_raw( $logo[0] );
}
}
$site_icon = get_site_icon_url( 512 );
if ( $site_icon ) {
return esc_url_raw( $site_icon );
}
return null;
}
/**
* Current URL.
*/
private static function current_url() {
global $wp;
if ( is_singular() ) {
return get_permalink();
}
if ( is_home() && ! is_front_page() ) {
$page_for_posts = get_option( 'page_for_posts' );
if ( $page_for_posts ) {
return get_permalink( $page_for_posts );
}
}
if ( is_category() || is_tag() || is_tax() ) {
$term = get_queried_object();
if ( $term && ! is_wp_error( $term ) ) {
return get_term_link( $term );
}
}
return home_url( add_query_arg( array(), $wp->request ) );
}
/**
* Current title.
*/
private static function current_title() {
if ( is_singular() ) {
return get_the_title();
}
if ( is_search() ) {
return sprintf(
/* translators: %s search query */
__( 'Search results for %s', 'rx-theme' ),
get_search_query()
);
}
if ( is_archive() ) {
return wp_strip_all_tags( get_the_archive_title() );
}
return get_bloginfo( 'name' );
}
/**
* Post excerpt.
*/
private static function post_excerpt( $post_id ) {
$excerpt = get_the_excerpt( $post_id );
if ( ! $excerpt ) {
$content = get_post_field( 'post_content', $post_id );
$excerpt = wp_trim_words( wp_strip_all_tags( strip_shortcodes( $content ) ), 35 );
}
return wp_strip_all_tags( $excerpt );
}
/**
* Post categories.
*/
private static function post_categories( $post_id ) {
$categories = get_the_category( $post_id );
if ( empty( $categories ) || is_wp_error( $categories ) ) {
return null;
}
return wp_list_pluck( $categories, 'name' );
}
/**
* Post keywords from tags.
*/
private static function post_keywords( $post_id ) {
$tags = get_the_tags( $post_id );
if ( empty( $tags ) || is_wp_error( $tags ) ) {
return null;
}
return implode( ', ', wp_list_pluck( $tags, 'name' ) );
}
/**
* Word count.
*/
private static function word_count( $post_id ) {
$content = get_post_field( 'post_content', $post_id );
$content = wp_strip_all_tags( strip_shortcodes( $content ) );
return str_word_count( $content );
}
/**
* Language.
*/
private static function language() {
return str_replace( '_', '-', get_locale() );
}
/**
* Safe post meta.
*/
private static function post_meta( $post_id, $key ) {
$value = get_post_meta( $post_id, $key, true );
if ( is_array( $value ) || is_object( $value ) ) {
return null;
}
return $value ? wp_strip_all_tags( $value ) : null;
}
/**
* Array meta helper.
*
* Supports:
* - Serialized array
* - JSON array
* - Comma-separated string
* - New-line-separated string
*/
private static function array_meta( $post_id, $key ) {
$value = get_post_meta( $post_id, $key, true );
if ( empty( $value ) ) {
return array();
}
if ( is_array( $value ) ) {
return array_filter( array_map( 'sanitize_text_field', $value ) );
}
if ( is_string( $value ) ) {
$decoded = json_decode( $value, true );
if ( json_last_error() === JSON_ERROR_NONE && is_array( $decoded ) ) {
return array_filter( array_map( 'sanitize_text_field', $decoded ) );
}
if ( false !== strpos( $value, "\n" ) ) {
return array_filter( array_map( 'sanitize_text_field', preg_split( '/\r\n|\r|\n/', $value ) ) );
}
if ( false !== strpos( $value, ',' ) ) {
return array_filter( array_map( 'sanitize_text_field', explode( ',', $value ) ) );
}
return array( sanitize_text_field( $value ) );
}
return array();
}
/**
* Normalize repeater meta.
*/
private static function normalize_repeater_meta( $value ) {
if ( empty( $value ) ) {
return array();
}
if ( is_string( $value ) ) {
$decoded = json_decode( $value, true );
if ( json_last_error() === JSON_ERROR_NONE && is_array( $decoded ) ) {
$value = $decoded;
}
}
if ( ! is_array( $value ) ) {
return array();
}
$clean = array();
foreach ( $value as $row ) {
if ( ! is_array( $row ) ) {
continue;
}
$clean_row = array();
foreach ( $row as $key => $item ) {
if ( is_scalar( $item ) ) {
$clean_row[ sanitize_key( $key ) ] = wp_kses_post( $item );
}
}
if ( ! empty( $clean_row ) ) {
$clean[] = $clean_row;
}
}
return $clean;
}
/**
* Remove empty values recursively.
*/
private static function remove_empty_items( $data ) {
if ( ! is_array( $data ) ) {
return $data;
}
foreach ( $data as $key => $value ) {
if ( is_array( $value ) ) {
$value = self::remove_empty_items( $value );
}
if (
null === $value ||
'' === $value ||
array() === $value
) {
unset( $data[ $key ] );
} else {
$data[ $key ] = $value;
}
}
return $data;
}
}
endif;
RX_Advanced_Schema::init();
Add this line in your main functions.php
require_once get_template_directory() . '/inc/helpers/schema.php';
Optional post meta fields this file supports
You can later add these custom fields by ACF, Meta Box plugin, or your own admin panel:
_rx_is_medical_article
_rx_last_reviewed
_rx_reviewed_by_name
_rx_reviewed_by_url
_rx_medical_condition_name
_rx_medical_condition_description
_rx_medical_condition_causes
_rx_medical_condition_symptoms
_rx_medical_condition_tests
_rx_medical_condition_treatments
_rx_medical_anatomy
_rx_faqs
_rx_howto_name
_rx_howto_description
_rx_howto_steps
For example, _rx_medical_condition_symptoms can be:
Pain
Fever
Swelling
Fatigue
Headache
Or JSON:
["Pain", "Fever", "Swelling", "Fatigue", "Headache"]
This file is safe for your RX medical theme and gives you a strong SEO schema foundation.