array(
'name' => __( 'Sermons', 'pulpitkit' ),
'singular_name' => __( 'Sermon', 'pulpitkit' ),
'add_new_item' => __( 'Add New Sermon', 'pulpitkit' ),
'edit_item' => __( 'Edit Sermon', 'pulpitkit' ),
'new_item' => __( 'New Sermon', 'pulpitkit' ),
'view_item' => __( 'View Sermon', 'pulpitkit' ),
'search_items' => __( 'Search Sermons', 'pulpitkit' ),
'not_found' => __( 'No sermons found', 'pulpitkit' ),
'not_found_in_trash' => __( 'No sermons found in Trash', 'pulpitkit' ),
),
'public' => true,
'show_in_rest' => true,
'has_archive' => true,
'rewrite' => array( 'slug' => 'sermons' ),
'menu_icon' => 'dashicons-book-alt',
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'author' ),
)
);
register_post_type(
'pulpitkit_event',
array(
'labels' => array(
'name' => __( 'Events', 'pulpitkit' ),
'singular_name' => __( 'Event', 'pulpitkit' ),
'add_new_item' => __( 'Add New Event', 'pulpitkit' ),
'edit_item' => __( 'Edit Event', 'pulpitkit' ),
'new_item' => __( 'New Event', 'pulpitkit' ),
'view_item' => __( 'View Event', 'pulpitkit' ),
'search_items' => __( 'Search Events', 'pulpitkit' ),
'not_found' => __( 'No events found', 'pulpitkit' ),
'not_found_in_trash' => __( 'No events found in Trash', 'pulpitkit' ),
),
'public' => true,
'show_in_rest' => true,
'has_archive' => true,
'rewrite' => array( 'slug' => 'events' ),
'menu_icon' => 'dashicons-calendar-alt',
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail' ),
)
);
}
/**
* Register sermon taxonomies.
*/
public static function register_taxonomies() {
register_taxonomy(
'pulpitkit_sermon_series',
array( 'pulpitkit_sermon' ),
array(
'labels' => array(
'name' => __( 'Sermon Series', 'pulpitkit' ),
'singular_name' => __( 'Series', 'pulpitkit' ),
'search_items' => __( 'Search Series', 'pulpitkit' ),
'all_items' => __( 'All Series', 'pulpitkit' ),
'edit_item' => __( 'Edit Series', 'pulpitkit' ),
'add_new_item' => __( 'Add New Series', 'pulpitkit' ),
),
'hierarchical' => true,
'public' => true,
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'sermon-series' ),
)
);
register_taxonomy(
'pulpitkit_sermon_speaker',
array( 'pulpitkit_sermon' ),
array(
'labels' => array(
'name' => __( 'Speakers', 'pulpitkit' ),
'singular_name' => __( 'Speaker', 'pulpitkit' ),
'search_items' => __( 'Search Speakers', 'pulpitkit' ),
'all_items' => __( 'All Speakers', 'pulpitkit' ),
'edit_item' => __( 'Edit Speaker', 'pulpitkit' ),
'add_new_item' => __( 'Add New Speaker', 'pulpitkit' ),
),
'hierarchical' => false,
'public' => true,
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'speaker' ),
)
);
register_taxonomy(
'pulpitkit_sermon_topic',
array( 'pulpitkit_sermon' ),
array(
'labels' => array(
'name' => __( 'Topics', 'pulpitkit' ),
'singular_name' => __( 'Topic', 'pulpitkit' ),
'search_items' => __( 'Search Topics', 'pulpitkit' ),
'all_items' => __( 'All Topics', 'pulpitkit' ),
'edit_item' => __( 'Edit Topic', 'pulpitkit' ),
'add_new_item' => __( 'Add New Topic', 'pulpitkit' ),
),
'hierarchical' => false,
'public' => true,
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'sermon-topic' ),
)
);
}
/**
* Constructor: meta boxes + save handlers.
*/
public function __construct() {
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
add_action( 'save_post_pulpitkit_sermon', array( $this, 'save_sermon_meta' ), 10, 2 );
add_action( 'save_post_pulpitkit_event', array( $this, 'save_event_meta' ), 10, 2 );
}
/**
* Add meta boxes.
*/
public function add_meta_boxes() {
add_meta_box(
'pulpitkit_sermon_details',
__( 'Sermon Details', 'pulpitkit' ),
array( $this, 'render_sermon_meta_box' ),
'pulpitkit_sermon',
'normal',
'high'
);
add_meta_box(
'pulpitkit_event_details',
__( 'Event Details', 'pulpitkit' ),
array( $this, 'render_event_meta_box' ),
'pulpitkit_event',
'normal',
'high'
);
}
/**
* Render the sermon meta box.
*
* @param WP_Post $post Current post.
*/
public function render_sermon_meta_box( $post ) {
wp_nonce_field( 'pulpitkit_save_sermon_meta', 'pulpitkit_sermon_meta_nonce' );
$scripture = get_post_meta( $post->ID, '_pulpitkit_scripture', true );
$date = get_post_meta( $post->ID, '_pulpitkit_date_preached', true );
$audio_url = get_post_meta( $post->ID, '_pulpitkit_audio_url', true );
$audio_id = (int) get_post_meta( $post->ID, '_pulpitkit_audio_id', true );
$video_url = get_post_meta( $post->ID, '_pulpitkit_video_url', true );
$notes_url = get_post_meta( $post->ID, '_pulpitkit_notes_url', true );
$notes_id = (int) get_post_meta( $post->ID, '_pulpitkit_notes_id', true );
if ( '' === $date ) {
$date = get_the_date( 'Y-m-d', $post );
}
?>
can_save( $post_id, 'pulpitkit_sermon_meta_nonce', 'pulpitkit_save_sermon_meta' ) ) {
return;
}
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce + capability verified in can_save() above; the sniff cannot follow the helper.
if ( isset( $_POST['pulpitkit_scripture'] ) ) {
update_post_meta( $post_id, '_pulpitkit_scripture', sanitize_text_field( wp_unslash( $_POST['pulpitkit_scripture'] ) ) );
}
if ( isset( $_POST['pulpitkit_date_preached'] ) ) {
$date = sanitize_text_field( wp_unslash( $_POST['pulpitkit_date_preached'] ) );
update_post_meta( $post_id, '_pulpitkit_date_preached', preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ? $date : '' );
}
if ( isset( $_POST['pulpitkit_audio_url'] ) ) {
update_post_meta( $post_id, '_pulpitkit_audio_url', esc_url_raw( wp_unslash( $_POST['pulpitkit_audio_url'] ) ) );
}
if ( isset( $_POST['pulpitkit_audio_id'] ) ) {
update_post_meta( $post_id, '_pulpitkit_audio_id', absint( wp_unslash( $_POST['pulpitkit_audio_id'] ) ) );
}
if ( isset( $_POST['pulpitkit_video_url'] ) ) {
update_post_meta( $post_id, '_pulpitkit_video_url', esc_url_raw( wp_unslash( $_POST['pulpitkit_video_url'] ) ) );
}
if ( isset( $_POST['pulpitkit_notes_url'] ) ) {
update_post_meta( $post_id, '_pulpitkit_notes_url', esc_url_raw( wp_unslash( $_POST['pulpitkit_notes_url'] ) ) );
}
if ( isset( $_POST['pulpitkit_notes_id'] ) ) {
update_post_meta( $post_id, '_pulpitkit_notes_id', absint( wp_unslash( $_POST['pulpitkit_notes_id'] ) ) );
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Render the event meta box.
*
* @param WP_Post $post Current post.
*/
public function render_event_meta_box( $post ) {
wp_nonce_field( 'pulpitkit_save_event_meta', 'pulpitkit_event_meta_nonce' );
$start = get_post_meta( $post->ID, '_pulpitkit_event_start', true );
$end = get_post_meta( $post->ID, '_pulpitkit_event_end', true );
$location = get_post_meta( $post->ID, '_pulpitkit_location', true );
$recurrence = get_post_meta( $post->ID, '_pulpitkit_recurrence', true );
$recur_end = get_post_meta( $post->ID, '_pulpitkit_recurrence_end', true );
$start_input = $start ? str_replace( ' ', 'T', substr( (string) $start, 0, 16 ) ) : '';
$end_input = $end ? str_replace( ' ', 'T', substr( (string) $end, 0, 16 ) ) : '';
?>
can_save( $post_id, 'pulpitkit_event_meta_nonce', 'pulpitkit_save_event_meta' ) ) {
return;
}
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce + capability verified in can_save() above; the sniff cannot follow the helper.
if ( isset( $_POST['pulpitkit_event_start'] ) ) {
update_post_meta( $post_id, '_pulpitkit_event_start', $this->sanitize_datetime( wp_unslash( $_POST['pulpitkit_event_start'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized inside sanitize_datetime().
}
if ( isset( $_POST['pulpitkit_event_end'] ) ) {
update_post_meta( $post_id, '_pulpitkit_event_end', $this->sanitize_datetime( wp_unslash( $_POST['pulpitkit_event_end'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized inside sanitize_datetime().
}
if ( isset( $_POST['pulpitkit_location'] ) ) {
update_post_meta( $post_id, '_pulpitkit_location', sanitize_text_field( wp_unslash( $_POST['pulpitkit_location'] ) ) );
}
if ( isset( $_POST['pulpitkit_recurrence'] ) ) {
$recurrence = sanitize_key( wp_unslash( $_POST['pulpitkit_recurrence'] ) );
if ( ! array_key_exists( $recurrence, PulpitKit_Events::recurrence_options() ) ) {
$recurrence = 'none';
}
update_post_meta( $post_id, '_pulpitkit_recurrence', $recurrence );
}
if ( isset( $_POST['pulpitkit_recurrence_end'] ) ) {
$end = sanitize_text_field( wp_unslash( $_POST['pulpitkit_recurrence_end'] ) );
update_post_meta( $post_id, '_pulpitkit_recurrence_end', preg_match( '/^\d{4}-\d{2}-\d{2}$/', $end ) ? $end : '' );
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Nonce + capability + autosave guard shared by save handlers.
*
* @param int $post_id Post being saved.
* @param string $nonce_field POST field name.
* @param string $nonce_action Nonce action.
* @return bool
*/
private function can_save( $post_id, $nonce_field, $nonce_action ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return false;
}
if ( ! isset( $_POST[ $nonce_field ] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST[ $nonce_field ] ) ), $nonce_action ) ) {
return false;
}
return current_user_can( 'edit_post', $post_id );
}
/**
* Sanitize a datetime-local input ("2026-10-13T10:30") to "Y-m-d H:i".
*
* @param string $raw Raw input.
* @return string Sanitized datetime or empty string.
*/
private function sanitize_datetime( $raw ) {
$raw = trim( sanitize_text_field( (string) $raw ) );
if ( '' === $raw ) {
return '';
}
$raw = str_replace( 'T', ' ', $raw );
$dt = date_create( $raw, wp_timezone() );
if ( false === $dt ) {
return '';
}
return $dt->format( 'Y-m-d H:i' );
}
}