medical-library.php

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 '&mdash;';
			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.

Leave a Reply

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