I’ll build this as a strong WordPress custom post type module for your RX theme: medical articles, taxonomies, meta boxes, admin columns, REST support, schema-ready fields, shortcodes, and helper functions.
Below is an advanced inc/post-types/medical-library.php file for your RX Theme. It creates a powerful Medical Library custom post type with many useful features: CPT, taxonomies, meta fields, REST API support, admin columns, schema helper, reading time, shortcode, archive query customization, breadcrumbs helper, and secure saving with nonce/capability checks.
WordPress officially recommends registering taxonomies with the custom post type, using show_in_rest for block editor/REST support, registering meta fields with sanitization, and checking user capability before saving post data.
Create this file:
<?php
/**
* RX Theme - Medical Library Custom Post Type
*
* File: inc/post-types/medical-library.php
*
* Features:
* - Medical Library custom post type
* - Disease categories
* - Body systems
* - Medical specialties
* - Symptoms taxonomy
* - Diagnostic test taxonomy
* - Treatment taxonomy
* - SEO-friendly rewrite slug
* - REST API support
* - Gutenberg support
* - Meta boxes
* - Registered post meta
* - Secure save handler
* - Admin columns
* - Frontend helper functions
* - Schema.org MedicalWebPage helper
* - Shortcode for latest medical articles
* - Archive query customization
*
* @package RX_Theme
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'RX_Medical_Library_Post_Type' ) ) :
final class RX_Medical_Library_Post_Type {
/**
* Post type slug.
*/
const POST_TYPE = 'rx_medical';
/**
* Nonce action.
*/
const NONCE_ACTION = 'rx_medical_library_save_meta';
/**
* Nonce name.
*/
const NONCE_NAME = 'rx_medical_library_nonce';
/**
* Meta prefix.
*/
const META_PREFIX = '_rx_medical_';
/**
* Boot class.
*/
public static function init() {
add_action( 'init', array( __CLASS__, 'register_post_type' ), 5 );
add_action( 'init', array( __CLASS__, 'register_taxonomies' ), 6 );
add_action( 'init', array( __CLASS__, 'register_meta_fields' ), 7 );
add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
add_action( 'save_post_' . self::POST_TYPE, array( __CLASS__, 'save_meta_boxes' ), 10, 2 );
add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( __CLASS__, 'admin_columns' ) );
add_action( 'manage_' . self::POST_TYPE . '_posts_custom_column', array( __CLASS__, 'admin_column_content' ), 10, 2 );
add_filter( 'manage_edit-' . self::POST_TYPE . '_sortable_columns', array( __CLASS__, 'sortable_columns' ) );
add_action( 'pre_get_posts', array( __CLASS__, 'admin_orderby_columns' ) );
add_filter( 'post_updated_messages', array( __CLASS__, 'updated_messages' ) );
add_filter( 'enter_title_here', array( __CLASS__, 'title_placeholder' ), 10, 2 );
add_action( 'pre_get_posts', array( __CLASS__, 'custom_archive_query' ) );
add_shortcode( 'rx_medical_library', array( __CLASS__, 'latest_shortcode' ) );
}
/**
* Register Medical Library custom post type.
*/
public static function register_post_type() {
$labels = array(
'name' => _x( 'Medical Library', 'Post type general name', 'rx-theme' ),
'singular_name' => _x( 'Medical Article', 'Post type singular name', 'rx-theme' ),
'menu_name' => __( 'Medical Library', 'rx-theme' ),
'name_admin_bar' => __( 'Medical Article', 'rx-theme' ),
'add_new' => __( 'Add New', 'rx-theme' ),
'add_new_item' => __( 'Add New Medical Article', 'rx-theme' ),
'new_item' => __( 'New Medical Article', 'rx-theme' ),
'edit_item' => __( 'Edit Medical Article', 'rx-theme' ),
'view_item' => __( 'View Medical Article', 'rx-theme' ),
'all_items' => __( 'All Medical Articles', 'rx-theme' ),
'search_items' => __( 'Search Medical Articles', 'rx-theme' ),
'parent_item_colon' => __( 'Parent Medical Articles:', 'rx-theme' ),
'not_found' => __( 'No medical articles found.', 'rx-theme' ),
'not_found_in_trash' => __( 'No medical articles found in Trash.', 'rx-theme' ),
'featured_image' => __( 'Medical Article Image', 'rx-theme' ),
'set_featured_image' => __( 'Set medical image', 'rx-theme' ),
'remove_featured_image' => __( 'Remove medical image', 'rx-theme' ),
'use_featured_image' => __( 'Use as medical image', 'rx-theme' ),
'archives' => __( 'Medical Library Archives', 'rx-theme' ),
'insert_into_item' => __( 'Insert into medical article', 'rx-theme' ),
'uploaded_to_this_item' => __( 'Uploaded to this medical article', 'rx-theme' ),
'filter_items_list' => __( 'Filter medical articles list', 'rx-theme' ),
'items_list_navigation' => __( 'Medical articles list navigation', 'rx-theme' ),
'items_list' => __( 'Medical articles list', 'rx-theme' ),
);
$args = array(
'labels' => $labels,
'description' => __( 'Evidence-based medical articles, diseases, symptoms, diagnostics, and treatments.', 'rx-theme' ),
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => true,
'show_in_rest' => true,
'rest_base' => 'medical-library',
'rest_controller_class' => 'WP_REST_Posts_Controller',
'menu_position' => 5,
'menu_icon' => 'dashicons-heart',
'capability_type' => 'post',
'map_meta_cap' => true,
'hierarchical' => false,
'has_archive' => 'medical-library',
'rewrite' => array(
'slug' => 'medical-library',
'with_front' => false,
'feeds' => true,
'pages' => true,
),
'query_var' => true,
'can_export' => true,
'delete_with_user' => false,
'taxonomies' => array(
'rx_disease_category',
'rx_body_system',
'rx_medical_specialty',
'rx_symptom',
'rx_diagnostic_test',
'rx_treatment_type',
),
'supports' => array(
'title',
'editor',
'excerpt',
'author',
'thumbnail',
'comments',
'revisions',
'custom-fields',
'page-attributes',
),
'template' => array(
array(
'core/heading',
array(
'level' => 2,
'content' => 'Definition',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Write a simple, evidence-based definition...',
),
),
array(
'core/heading',
array(
'level' => 2,
'content' => 'Causes',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Explain common and serious causes...',
),
),
array(
'core/heading',
array(
'level' => 2,
'content' => 'Symptoms',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Describe symptoms in simple English...',
),
),
array(
'core/heading',
array(
'level' => 2,
'content' => 'Diagnosis',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Explain diagnostic tests...',
),
),
array(
'core/heading',
array(
'level' => 2,
'content' => 'Treatment',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Explain treatment options...',
),
),
array(
'core/heading',
array(
'level' => 2,
'content' => 'When to See a Doctor',
),
),
array(
'core/paragraph',
array(
'placeholder' => 'Explain warning signs...',
),
),
),
);
register_post_type( self::POST_TYPE, $args );
}
/**
* Register taxonomies.
*/
public static function register_taxonomies() {
self::register_hierarchical_taxonomy(
'rx_disease_category',
'Disease Categories',
'Disease Category',
'disease-category'
);
self::register_hierarchical_taxonomy(
'rx_body_system',
'Body Systems',
'Body System',
'body-system'
);
self::register_hierarchical_taxonomy(
'rx_medical_specialty',
'Medical Specialties',
'Medical Specialty',
'medical-specialty'
);
self::register_flat_taxonomy(
'rx_symptom',
'Symptoms',
'Symptom',
'symptom'
);
self::register_flat_taxonomy(
'rx_diagnostic_test',
'Diagnostic Tests',
'Diagnostic Test',
'diagnostic-test'
);
self::register_flat_taxonomy(
'rx_treatment_type',
'Treatment Types',
'Treatment Type',
'treatment-type'
);
}
/**
* Register hierarchical taxonomy.
*/
private static function register_hierarchical_taxonomy( $taxonomy, $plural, $singular, $slug ) {
$labels = array(
'name' => __( $plural, 'rx-theme' ),
'singular_name' => __( $singular, 'rx-theme' ),
'search_items' => sprintf( __( 'Search %s', 'rx-theme' ), $plural ),
'all_items' => sprintf( __( 'All %s', 'rx-theme' ), $plural ),
'parent_item' => sprintf( __( 'Parent %s', 'rx-theme' ), $singular ),
'parent_item_colon' => sprintf( __( 'Parent %s:', 'rx-theme' ), $singular ),
'edit_item' => sprintf( __( 'Edit %s', 'rx-theme' ), $singular ),
'update_item' => sprintf( __( 'Update %s', 'rx-theme' ), $singular ),
'add_new_item' => sprintf( __( 'Add New %s', 'rx-theme' ), $singular ),
'new_item_name' => sprintf( __( 'New %s Name', 'rx-theme' ), $singular ),
'menu_name' => __( $plural, 'rx-theme' ),
);
register_taxonomy(
$taxonomy,
array( self::POST_TYPE ),
array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'show_in_rest' => true,
'query_var' => true,
'rewrite' => array(
'slug' => $slug,
'with_front' => false,
),
)
);
}
/**
* Register flat taxonomy.
*/
private static function register_flat_taxonomy( $taxonomy, $plural, $singular, $slug ) {
$labels = array(
'name' => __( $plural, 'rx-theme' ),
'singular_name' => __( $singular, 'rx-theme' ),
'search_items' => sprintf( __( 'Search %s', 'rx-theme' ), $plural ),
'popular_items' => sprintf( __( 'Popular %s', 'rx-theme' ), $plural ),
'all_items' => sprintf( __( 'All %s', 'rx-theme' ), $plural ),
'edit_item' => sprintf( __( 'Edit %s', 'rx-theme' ), $singular ),
'update_item' => sprintf( __( 'Update %s', 'rx-theme' ), $singular ),
'add_new_item' => sprintf( __( 'Add New %s', 'rx-theme' ), $singular ),
'new_item_name' => sprintf( __( 'New %s Name', 'rx-theme' ), $singular ),
'separate_items_with_commas' => sprintf( __( 'Separate %s with commas', 'rx-theme' ), strtolower( $plural ) ),
'add_or_remove_items' => sprintf( __( 'Add or remove %s', 'rx-theme' ), strtolower( $plural ) ),
'choose_from_most_used' => sprintf( __( 'Choose from most used %s', 'rx-theme' ), strtolower( $plural ) ),
'menu_name' => __( $plural, 'rx-theme' ),
);
register_taxonomy(
$taxonomy,
array( self::POST_TYPE ),
array(
'hierarchical' => false,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'show_in_rest' => true,
'query_var' => true,
'update_count_callback' => '_update_post_term_count',
'rewrite' => array(
'slug' => $slug,
'with_front' => false,
),
)
);
}
/**
* Register post meta fields.
*/
public static function register_meta_fields() {
$fields = self::get_meta_fields();
foreach ( $fields as $key => $field ) {
register_post_meta(
self::POST_TYPE,
self::META_PREFIX . $key,
array(
'type' => $field['type'],
'description' => $field['label'],
'single' => true,
'sanitize_callback' => $field['sanitize'],
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
'show_in_rest' => true,
)
);
}
}
/**
* Meta field list.
*/
public static function get_meta_fields() {
return array(
'medical_reviewed_by' => array(
'label' => 'Medically Reviewed By',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'reviewer_credentials' => array(
'label' => 'Reviewer Credentials',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'last_medical_review' => array(
'label' => 'Last Medical Review Date',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'evidence_level' => array(
'label' => 'Evidence Level',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'reading_level' => array(
'label' => 'Reading Level',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'icd_10_code' => array(
'label' => 'ICD-10 Code',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'snomed_code' => array(
'label' => 'SNOMED CT Code',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'mesh_term' => array(
'label' => 'MeSH Term',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'primary_keyword' => array(
'label' => 'Primary SEO Keyword',
'type' => 'string',
'sanitize' => 'sanitize_text_field',
),
'secondary_keywords' => array(
'label' => 'Secondary SEO Keywords',
'type' => 'string',
'sanitize' => 'sanitize_textarea_field',
),
'clinical_summary' => array(
'label' => 'Clinical Summary',
'type' => 'string',
'sanitize' => 'sanitize_textarea_field',
),
'warning_signs' => array(
'label' => 'Emergency Warning Signs',
'type' => 'string',
'sanitize' => 'sanitize_textarea_field',
),
'patient_friendly_summary' => array(
'label' => 'Patient Friendly Summary',
'type' => 'string',
'sanitize' => 'sanitize_textarea_field',
),
'references' => array(
'label' => 'Medical References',
'type' => 'string',
'sanitize' => 'wp_kses_post',
),
'disclaimer' => array(
'label' => 'Medical Disclaimer',
'type' => 'string',
'sanitize' => 'sanitize_textarea_field',
),
);
}
/**
* Add meta boxes.
*/
public static function add_meta_boxes() {
add_meta_box(
'rx_medical_article_details',
__( 'Medical Article Details', 'rx-theme' ),
array( __CLASS__, 'render_details_meta_box' ),
self::POST_TYPE,
'normal',
'high'
);
add_meta_box(
'rx_medical_seo_details',
__( 'Medical SEO / Search Details', 'rx-theme' ),
array( __CLASS__, 'render_seo_meta_box' ),
self::POST_TYPE,
'normal',
'default'
);
add_meta_box(
'rx_medical_references',
__( 'Medical References & Disclaimer', 'rx-theme' ),
array( __CLASS__, 'render_references_meta_box' ),
self::POST_TYPE,
'normal',
'default'
);
add_meta_box(
'rx_medical_schema_preview',
__( 'Schema / Helper Information', 'rx-theme' ),
array( __CLASS__, 'render_schema_meta_box' ),
self::POST_TYPE,
'side',
'default'
);
}
/**
* Render details meta box.
*/
public static function render_details_meta_box( $post ) {
wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME );
self::text_field( $post->ID, 'medical_reviewed_by', 'Medically Reviewed By', 'Example: Dr. John Doe' );
self::text_field( $post->ID, 'reviewer_credentials', 'Reviewer Credentials', 'Example: MBBS, MD, PhD' );
self::date_field( $post->ID, 'last_medical_review', 'Last Medical Review Date' );
self::select_field(
$post->ID,
'evidence_level',
'Evidence Level',
array(
'' => 'Select evidence level',
'clinical-guide' => 'Clinical guideline',
'systematic-review'=> 'Systematic review',
'meta-analysis' => 'Meta-analysis',
'rct' => 'Randomized controlled trial',
'observational' => 'Observational study',
'expert-review' => 'Expert review',
'educational' => 'Educational summary',
)
);
self::select_field(
$post->ID,
'reading_level',
'Reading Level',
array(
'' => 'Select reading level',
'very-simple' => 'Very simple English',
'simple' => 'Simple English',
'intermediate' => 'Intermediate',
'professional' => 'Professional',
)
);
self::textarea_field( $post->ID, 'clinical_summary', 'Clinical Summary', 'Short clinical summary for doctors and health readers.' );
self::textarea_field( $post->ID, 'patient_friendly_summary', 'Patient Friendly Summary', 'Very simple explanation for general readers.' );
self::textarea_field( $post->ID, 'warning_signs', 'Emergency Warning Signs', 'Mention red flags and when urgent care is needed.' );
}
/**
* Render SEO meta box.
*/
public static function render_seo_meta_box( $post ) {
self::text_field( $post->ID, 'primary_keyword', 'Primary SEO Keyword', 'Example: high eosinophils' );
self::textarea_field( $post->ID, 'secondary_keywords', 'Secondary SEO Keywords', 'Separate keywords with commas.' );
self::text_field( $post->ID, 'icd_10_code', 'ICD-10 Code', 'Example: D72.1' );
self::text_field( $post->ID, 'snomed_code', 'SNOMED CT Code', 'Example: SNOMED concept ID' );
self::text_field( $post->ID, 'mesh_term', 'MeSH Term', 'Example: Eosinophilia' );
}
/**
* Render references meta box.
*/
public static function render_references_meta_box( $post ) {
self::textarea_field( $post->ID, 'references', 'Medical References', 'Add PubMed, FDA, WHO, CDC, NIH, guideline, or textbook references. Basic HTML allowed.' );
self::textarea_field( $post->ID, 'disclaimer', 'Medical Disclaimer', 'Example: This article is for education only and does not replace medical advice.' );
}
/**
* Render schema info meta box.
*/
public static function render_schema_meta_box( $post ) {
$reading_time = self::get_reading_time( $post->ID );
$word_count = self::get_word_count( $post->ID );
echo '<p><strong>' . esc_html__( 'Word Count:', 'rx-theme' ) . '</strong> ' . esc_html( $word_count ) . '</p>';
echo '<p><strong>' . esc_html__( 'Reading Time:', 'rx-theme' ) . '</strong> ' . esc_html( $reading_time ) . ' min</p>';
echo '<p><strong>' . esc_html__( 'Schema Type:', 'rx-theme' ) . '</strong> MedicalWebPage</p>';
echo '<p>' . esc_html__( 'You can print schema using rx_medical_library_schema_json_ld() in single template.', 'rx-theme' ) . '</p>';
}
/**
* Save meta boxes.
*/
public static function save_meta_boxes( $post_id, $post ) {
if ( ! isset( $_POST[ self::NONCE_NAME ] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
$fields = self::get_meta_fields();
foreach ( $fields as $key => $field ) {
$meta_key = self::META_PREFIX . $key;
if ( isset( $_POST[ $meta_key ] ) ) {
$value = wp_unslash( $_POST[ $meta_key ] );
if ( 'wp_kses_post' === $field['sanitize'] ) {
$value = wp_kses_post( $value );
} elseif ( 'sanitize_textarea_field' === $field['sanitize'] ) {
$value = sanitize_textarea_field( $value );
} else {
$value = sanitize_text_field( $value );
}
update_post_meta( $post_id, $meta_key, $value );
}
}
}
/**
* Text field.
*/
private static function text_field( $post_id, $key, $label, $placeholder = '' ) {
$meta_key = self::META_PREFIX . $key;
$value = get_post_meta( $post_id, $meta_key, true );
echo '<p>';
echo '<label for="' . esc_attr( $meta_key ) . '"><strong>' . esc_html( $label ) . '</strong></label>';
echo '<input type="text" id="' . esc_attr( $meta_key ) . '" name="' . esc_attr( $meta_key ) . '" value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $placeholder ) . '" class="widefat" />';
echo '</p>';
}
/**
* Date field.
*/
private static function date_field( $post_id, $key, $label ) {
$meta_key = self::META_PREFIX . $key;
$value = get_post_meta( $post_id, $meta_key, true );
echo '<p>';
echo '<label for="' . esc_attr( $meta_key ) . '"><strong>' . esc_html( $label ) . '</strong></label>';
echo '<input type="date" id="' . esc_attr( $meta_key ) . '" name="' . esc_attr( $meta_key ) . '" value="' . esc_attr( $value ) . '" class="widefat" />';
echo '</p>';
}
/**
* Textarea field.
*/
private static function textarea_field( $post_id, $key, $label, $description = '' ) {
$meta_key = self::META_PREFIX . $key;
$value = get_post_meta( $post_id, $meta_key, true );
echo '<p>';
echo '<label for="' . esc_attr( $meta_key ) . '"><strong>' . esc_html( $label ) . '</strong></label>';
echo '<textarea id="' . esc_attr( $meta_key ) . '" name="' . esc_attr( $meta_key ) . '" rows="5" class="widefat">' . esc_textarea( $value ) . '</textarea>';
if ( $description ) {
echo '<span class="description">' . esc_html( $description ) . '</span>';
}
echo '</p>';
}
/**
* Select field.
*/
private static function select_field( $post_id, $key, $label, $options ) {
$meta_key = self::META_PREFIX . $key;
$value = get_post_meta( $post_id, $meta_key, true );
echo '<p>';
echo '<label for="' . esc_attr( $meta_key ) . '"><strong>' . esc_html( $label ) . '</strong></label>';
echo '<select id="' . esc_attr( $meta_key ) . '" name="' . esc_attr( $meta_key ) . '" class="widefat">';
foreach ( $options as $option_value => $option_label ) {
echo '<option value="' . esc_attr( $option_value ) . '" ' . selected( $value, $option_value, false ) . '>' . esc_html( $option_label ) . '</option>';
}
echo '</select>';
echo '</p>';
}
/**
* Admin columns.
*/
public static function admin_columns( $columns ) {
$new_columns = array();
$new_columns['cb'] = $columns['cb'];
$new_columns['title'] = __( 'Medical Article', 'rx-theme' );
$new_columns['rx_disease_category'] = __( 'Disease Category', 'rx-theme' );
$new_columns['rx_body_system'] = __( 'Body System', 'rx-theme' );
$new_columns['reviewed_by'] = __( 'Reviewed By', 'rx-theme' );
$new_columns['last_review'] = __( 'Last Review', 'rx-theme' );
$new_columns['evidence_level'] = __( 'Evidence', 'rx-theme' );
$new_columns['reading_time'] = __( 'Reading Time', 'rx-theme' );
$new_columns['date'] = $columns['date'];
return $new_columns;
}
/**
* Admin column content.
*/
public static function admin_column_content( $column, $post_id ) {
switch ( $column ) {
case 'rx_disease_category':
self::term_column( $post_id, 'rx_disease_category' );
break;
case 'rx_body_system':
self::term_column( $post_id, 'rx_body_system' );
break;
case 'reviewed_by':
echo esc_html( get_post_meta( $post_id, self::META_PREFIX . 'medical_reviewed_by', true ) );
break;
case 'last_review':
echo esc_html( get_post_meta( $post_id, self::META_PREFIX . 'last_medical_review', true ) );
break;
case 'evidence_level':
echo esc_html( get_post_meta( $post_id, self::META_PREFIX . 'evidence_level', true ) );
break;
case 'reading_time':
echo esc_html( self::get_reading_time( $post_id ) . ' min' );
break;
}
}
/**
* Display terms in admin column.
*/
private static function term_column( $post_id, $taxonomy ) {
$terms = get_the_terms( $post_id, $taxonomy );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
echo '—';
return;
}
$term_links = array();
foreach ( $terms as $term ) {
$term_links[] = sprintf(
'<a href="%s">%s</a>',
esc_url( add_query_arg( array( 'post_type' => self::POST_TYPE, $taxonomy => $term->slug ), admin_url( 'edit.php' ) ) ),
esc_html( $term->name )
);
}
echo wp_kses_post( implode( ', ', $term_links ) );
}
/**
* Sortable admin columns.
*/
public static function sortable_columns( $columns ) {
$columns['last_review'] = 'last_review';
$columns['evidence_level'] = 'evidence_level';
return $columns;
}
/**
* Admin orderby columns.
*/
public static function admin_orderby_columns( $query ) {
if ( ! is_admin() || ! $query->is_main_query() ) {
return;
}
if ( self::POST_TYPE !== $query->get( 'post_type' ) ) {
return;
}
$orderby = $query->get( 'orderby' );
if ( 'last_review' === $orderby ) {
$query->set( 'meta_key', self::META_PREFIX . 'last_medical_review' );
$query->set( 'orderby', 'meta_value' );
}
if ( 'evidence_level' === $orderby ) {
$query->set( 'meta_key', self::META_PREFIX . 'evidence_level' );
$query->set( 'orderby', 'meta_value' );
}
}
/**
* Updated messages.
*/
public static function updated_messages( $messages ) {
$messages[ self::POST_TYPE ] = array(
0 => '',
1 => __( 'Medical article updated.', 'rx-theme' ),
2 => __( 'Custom field updated.', 'rx-theme' ),
3 => __( 'Custom field deleted.', 'rx-theme' ),
4 => __( 'Medical article updated.', 'rx-theme' ),
5 => __( 'Medical article restored from revision.', 'rx-theme' ),
6 => __( 'Medical article published.', 'rx-theme' ),
7 => __( 'Medical article saved.', 'rx-theme' ),
8 => __( 'Medical article submitted.', 'rx-theme' ),
9 => __( 'Medical article scheduled.', 'rx-theme' ),
10 => __( 'Medical article draft updated.', 'rx-theme' ),
);
return $messages;
}
/**
* Title placeholder.
*/
public static function title_placeholder( $title, $post ) {
if ( self::POST_TYPE === $post->post_type ) {
return __( 'Enter medical condition, symptom, diagnostic test, or treatment title', 'rx-theme' );
}
return $title;
}
/**
* Customize frontend archive query.
*/
public static function custom_archive_query( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( is_post_type_archive( self::POST_TYPE ) ) {
$query->set( 'posts_per_page', 12 );
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
}
/**
* Latest shortcode.
*
* Usage:
* [rx_medical_library posts="6" category="diabetes"]
*/
public static function latest_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'posts' => 6,
'category' => '',
'system' => '',
'columns' => 3,
),
$atts,
'rx_medical_library'
);
$args = array(
'post_type' => self::POST_TYPE,
'post_status' => 'publish',
'posts_per_page' => absint( $atts['posts'] ),
'ignore_sticky_posts' => true,
);
$tax_query = array();
if ( ! empty( $atts['category'] ) ) {
$tax_query[] = array(
'taxonomy' => 'rx_disease_category',
'field' => 'slug',
'terms' => sanitize_title( $atts['category'] ),
);
}
if ( ! empty( $atts['system'] ) ) {
$tax_query[] = array(
'taxonomy' => 'rx_body_system',
'field' => 'slug',
'terms' => sanitize_title( $atts['system'] ),
);
}
if ( ! empty( $tax_query ) ) {
$args['tax_query'] = $tax_query;
}
$query = new WP_Query( $args );
if ( ! $query->have_posts() ) {
return '<p>' . esc_html__( 'No medical articles found.', 'rx-theme' ) . '</p>';
}
$columns = max( 1, min( 4, absint( $atts['columns'] ) ) );
ob_start();
echo '<div class="rx-medical-library-grid rx-medical-columns-' . esc_attr( $columns ) . '">';
while ( $query->have_posts() ) {
$query->the_post();
echo '<article class="rx-medical-card">';
if ( has_post_thumbnail() ) {
echo '<a class="rx-medical-card__image" href="' . esc_url( get_permalink() ) . '">';
the_post_thumbnail( 'medium_large' );
echo '</a>';
}
echo '<h3 class="rx-medical-card__title"><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h3>';
echo '<div class="rx-medical-card__meta">';
echo esc_html( self::get_reading_time( get_the_ID() ) . ' min read' );
echo '</div>';
echo '<p class="rx-medical-card__excerpt">' . esc_html( wp_trim_words( get_the_excerpt(), 24 ) ) . '</p>';
echo '<a class="rx-medical-card__readmore" href="' . esc_url( get_permalink() ) . '">' . esc_html__( 'Read More', 'rx-theme' ) . '</a>';
echo '</article>';
}
echo '</div>';
wp_reset_postdata();
return ob_get_clean();
}
/**
* Get word count.
*/
public static function get_word_count( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
return 0;
}
$content = wp_strip_all_tags( strip_shortcodes( $post->post_content ) );
$words = str_word_count( $content );
return absint( $words );
}
/**
* Get reading time.
*/
public static function get_reading_time( $post_id ) {
$word_count = self::get_word_count( $post_id );
$minutes = ceil( $word_count / 200 );
return max( 1, absint( $minutes ) );
}
/**
* Get meta value.
*/
public static function get_meta( $post_id, $key, $default = '' ) {
$value = get_post_meta( $post_id, self::META_PREFIX . $key, true );
return '' !== $value ? $value : $default;
}
/**
* Build schema array.
*/
public static function get_schema( $post_id = null ) {
$post_id = $post_id ? absint( $post_id ) : get_the_ID();
if ( ! $post_id || self::POST_TYPE !== get_post_type( $post_id ) ) {
return array();
}
$reviewed_by = self::get_meta( $post_id, 'medical_reviewed_by' );
$credentials = self::get_meta( $post_id, 'reviewer_credentials' );
$summary = self::get_meta( $post_id, 'clinical_summary' );
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'MedicalWebPage',
'headline' => get_the_title( $post_id ),
'name' => get_the_title( $post_id ),
'description' => $summary ? $summary : get_the_excerpt( $post_id ),
'url' => get_permalink( $post_id ),
'datePublished' => get_the_date( DATE_W3C, $post_id ),
'dateModified' => get_the_modified_date( DATE_W3C, $post_id ),
'inLanguage' => get_bloginfo( 'language' ),
'isAccessibleForFree' => true,
'publisher' => array(
'@type' => 'Organization',
'name' => get_bloginfo( 'name' ),
'url' => home_url( '/' ),
),
'mainEntityOfPage' => array(
'@type' => 'WebPage',
'@id' => get_permalink( $post_id ),
),
);
if ( has_post_thumbnail( $post_id ) ) {
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'full' );
if ( ! empty( $image[0] ) ) {
$schema['image'] = esc_url_raw( $image[0] );
}
}
if ( $reviewed_by ) {
$schema['reviewedBy'] = array(
'@type' => 'Person',
'name' => $reviewed_by,
);
if ( $credentials ) {
$schema['reviewedBy']['honorificSuffix'] = $credentials;
}
}
return apply_filters( 'rx_medical_library_schema', $schema, $post_id );
}
/**
* Print schema JSON-LD.
*/
public static function print_schema( $post_id = null ) {
$schema = self::get_schema( $post_id );
if ( empty( $schema ) ) {
return;
}
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>' . "\n";
}
}
RX_Medical_Library_Post_Type::init();
endif;
/**
* Public helper: get medical meta.
*/
if ( ! function_exists( 'rx_medical_library_get_meta' ) ) {
function rx_medical_library_get_meta( $post_id, $key, $default = '' ) {
return RX_Medical_Library_Post_Type::get_meta( $post_id, $key, $default );
}
}
/**
* Public helper: get medical reading time.
*/
if ( ! function_exists( 'rx_medical_library_reading_time' ) ) {
function rx_medical_library_reading_time( $post_id = null ) {
$post_id = $post_id ? absint( $post_id ) : get_the_ID();
return RX_Medical_Library_Post_Type::get_reading_time( $post_id );
}
}
/**
* Public helper: print schema.
*
* Use inside single-rx_medical.php:
* rx_medical_library_schema_json_ld();
*/
if ( ! function_exists( 'rx_medical_library_schema_json_ld' ) ) {
function rx_medical_library_schema_json_ld( $post_id = null ) {
RX_Medical_Library_Post_Type::print_schema( $post_id );
}
}
Then add this line in your theme functions.php:
require_once get_template_directory() . '/inc/post-types/medical-library.php';
After adding it, go to WordPress Dashboard → Settings → Permalinks → Save Changes once. This refreshes the rewrite rules so /medical-library/ works correctly.