__( 'Display Name', 'peptide-repo-core' ), 'aliases' => __( 'Aliases (JSON array)', 'peptide-repo-core' ), 'molecular_formula' => __( 'Molecular Formula', 'peptide-repo-core' ), 'molecular_weight' => __( 'Molecular Weight (Da)', 'peptide-repo-core' ), 'cas_number' => __( 'CAS Number', 'peptide-repo-core' ), 'drugbank_id' => __( 'DrugBank ID', 'peptide-repo-core' ), 'chembl_id' => __( 'ChEMBL ID', 'peptide-repo-core' ), ); echo '
' . esc_html__( 'Save the peptide first, then add dosing data.', 'peptide-repo-core' ) . '
'; return; } $repo = new PR_Core_Dosing_Repository(); $rows = $repo->find_by_peptide( $post->ID ); if ( empty( $rows ) ) { echo '' . esc_html__( 'No dosing rows yet.', 'peptide-repo-core' ) . '
'; } else { echo '| ' . esc_html__( 'Route', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Dose Range', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Population', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Evidence', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Source', 'peptide-repo-core' ) . ' | '; echo '
|---|---|---|---|---|
| %s | %s | %s | %s | %s |
%s
', esc_html__( 'Dosing rows are managed via the REST API or AI Candidate Queue. Direct admin editing coming in v0.2.', 'peptide-repo-core' ) ); } /** * Render the Legal Status meta box (read-only summary). * * @param \WP_Post $post Current post. * @return void */ public function render_legal_box( \WP_Post $post ): void { if ( 'auto-draft' === $post->post_status ) { echo '' . esc_html__( 'Save the peptide first, then add legal data.', 'peptide-repo-core' ) . '
'; return; } $repo = new PR_Core_Legal_Repository(); $cells = $repo->find_by_peptide( $post->ID ); if ( empty( $cells ) ) { echo '' . esc_html__( 'No legal status data yet.', 'peptide-repo-core' ) . '
'; } else { echo '| ' . esc_html__( 'Country', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Status', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Framework', 'peptide-repo-core' ) . ' | '; echo '' . esc_html__( 'Verified', 'peptide-repo-core' ) . ' | '; echo '
|---|---|---|---|
| %s | %s | %s | %s |
%s
', esc_html__( 'Legal cells are managed via the REST API. Direct admin editing coming in v0.2.', 'peptide-repo-core' ) ); } /** * Save peptide meta fields on post save. * * Side effects: updates post meta. * * @param int $post_id Post ID. * @param \WP_Post $post Post object. * @return void */ public function save_meta( int $post_id, \WP_Post $post ): void { if ( ! isset( $_POST['pr_core_meta_nonce'] ) ) { return; } if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pr_core_meta_nonce'] ) ), 'pr_core_save_meta' ) ) { return; } if ( ! current_user_can( PR_Core_Peptide_CPT::CAPABILITY ) ) { return; } if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } $meta_fields = PR_Core_Peptide_CPT::get_meta_fields(); foreach ( $meta_fields as $key => $config ) { $input_key = 'pr_core_' . $key; if ( ! isset( $_POST[ $input_key ] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- existence check only; unslash+sanitize below continue; } $raw = wp_unslash( $_POST[ $input_key ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized via config['sanitize'] callback on next line $clean = is_callable( $config['sanitize'] ) ? call_user_func( $config['sanitize'], $raw ) : sanitize_text_field( (string) $raw ); update_post_meta( $post_id, $key, $clean ); } // Set last_editorial_review_at when status changes to published. $new_review_status = sanitize_text_field( wp_unslash( $_POST['pr_core_editorial_review_status'] ?? '' ) ); if ( 'published' === $new_review_status ) { $old_status = get_post_meta( $post_id, 'editorial_review_status', true ); if ( 'published' !== $old_status ) { update_post_meta( $post_id, 'last_editorial_review_at', current_time( 'mysql' ) ); update_post_meta( $post_id, 'medical_editor_id', get_current_user_id() ); } } do_action( 'pr_core_after_peptide_publish', $post_id, $post ); } }