_x( 'Tracks', 'Post type general name', 'wp-fedistream' ), 'singular_name' => _x( 'Track', 'Post type singular name', 'wp-fedistream' ), 'menu_name' => _x( 'Tracks', 'Admin Menu text', 'wp-fedistream' ), 'name_admin_bar' => _x( 'Track', 'Add New on Toolbar', 'wp-fedistream' ), 'add_new' => __( 'Add New', 'wp-fedistream' ), 'add_new_item' => __( 'Add New Track', 'wp-fedistream' ), 'new_item' => __( 'New Track', 'wp-fedistream' ), 'edit_item' => __( 'Edit Track', 'wp-fedistream' ), 'view_item' => __( 'View Track', 'wp-fedistream' ), 'all_items' => __( 'All Tracks', 'wp-fedistream' ), 'search_items' => __( 'Search Tracks', 'wp-fedistream' ), 'parent_item_colon' => __( 'Parent Tracks:', 'wp-fedistream' ), 'not_found' => __( 'No tracks found.', 'wp-fedistream' ), 'not_found_in_trash' => __( 'No tracks found in Trash.', 'wp-fedistream' ), 'featured_image' => _x( 'Track Artwork', 'Overrides the "Featured Image" phrase', 'wp-fedistream' ), 'set_featured_image' => _x( 'Set track artwork', 'Overrides the "Set featured image" phrase', 'wp-fedistream' ), 'remove_featured_image' => _x( 'Remove track artwork', 'Overrides the "Remove featured image" phrase', 'wp-fedistream' ), 'use_featured_image' => _x( 'Use as track artwork', 'Overrides the "Use as featured image" phrase', 'wp-fedistream' ), 'archives' => _x( 'Track archives', 'The post type archive label', 'wp-fedistream' ), 'insert_into_item' => _x( 'Insert into track', 'Overrides the "Insert into post" phrase', 'wp-fedistream' ), 'uploaded_to_this_item' => _x( 'Uploaded to this track', 'Overrides the "Uploaded to this post" phrase', 'wp-fedistream' ), 'filter_items_list' => _x( 'Filter tracks list', 'Screen reader text', 'wp-fedistream' ), 'items_list_navigation' => _x( 'Tracks list navigation', 'Screen reader text', 'wp-fedistream' ), 'items_list' => _x( 'Tracks list', 'Screen reader text', 'wp-fedistream' ), ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => false, // Will be added to custom menu. 'query_var' => true, 'rewrite' => array( 'slug' => 'tracks' ), 'capability_type' => array( 'fedistream_track', 'fedistream_tracks' ), 'map_meta_cap' => true, 'has_archive' => true, 'hierarchical' => false, 'menu_position' => null, 'menu_icon' => 'dashicons-format-audio', 'supports' => array( 'title', 'editor', 'thumbnail', 'revisions' ), 'show_in_rest' => true, 'rest_base' => 'tracks', ); register_post_type( $this->post_type, $args ); } /** * Add meta boxes. * * @return void */ public function add_meta_boxes(): void { add_meta_box( 'fedistream_track_audio', __( 'Audio File', 'wp-fedistream' ), array( $this, 'render_audio_meta_box' ), $this->post_type, 'normal', 'high' ); add_meta_box( 'fedistream_track_info', __( 'Track Information', 'wp-fedistream' ), array( $this, 'render_info_meta_box' ), $this->post_type, 'normal', 'high' ); add_meta_box( 'fedistream_track_album', __( 'Album', 'wp-fedistream' ), array( $this, 'render_album_meta_box' ), $this->post_type, 'side', 'high' ); add_meta_box( 'fedistream_track_artists', __( 'Artists', 'wp-fedistream' ), array( $this, 'render_artists_meta_box' ), $this->post_type, 'side', 'default' ); add_meta_box( 'fedistream_track_codes', __( 'Track Codes', 'wp-fedistream' ), array( $this, 'render_codes_meta_box' ), $this->post_type, 'side', 'default' ); } /** * Render audio file meta box. * * @param \WP_Post $post Post object. * @return void */ public function render_audio_meta_box( \WP_Post $post ): void { wp_nonce_field( 'fedistream_track_save', 'fedistream_track_nonce' ); $audio_file = get_post_meta( $post->ID, self::META_PREFIX . 'audio_file', true ); $audio_format = get_post_meta( $post->ID, self::META_PREFIX . 'audio_format', true ); $duration = get_post_meta( $post->ID, self::META_PREFIX . 'duration', true ); wp_enqueue_media(); ?>

ID, self::META_PREFIX . 'number', true ); $disc_number = get_post_meta( $post->ID, self::META_PREFIX . 'disc_number', true ); $bpm = get_post_meta( $post->ID, self::META_PREFIX . 'bpm', true ); $key = get_post_meta( $post->ID, self::META_PREFIX . 'key', true ); $explicit = get_post_meta( $post->ID, self::META_PREFIX . 'explicit', true ); $preview_start = get_post_meta( $post->ID, self::META_PREFIX . 'preview_start', true ); $preview_duration = get_post_meta( $post->ID, self::META_PREFIX . 'preview_duration', true ); $musical_keys = array( '' => __( '— Select Key —', 'wp-fedistream' ), 'C' => 'C Major', 'Cm' => 'C Minor', 'C#' => 'C# Major', 'C#m' => 'C# Minor', 'D' => 'D Major', 'Dm' => 'D Minor', 'D#' => 'D# Major', 'D#m' => 'D# Minor', 'E' => 'E Major', 'Em' => 'E Minor', 'F' => 'F Major', 'Fm' => 'F Minor', 'F#' => 'F# Major', 'F#m' => 'F# Minor', 'G' => 'G Major', 'Gm' => 'G Minor', 'G#' => 'G# Major', 'G#m' => 'G# Minor', 'A' => 'A Major', 'Am' => 'A Minor', 'A#' => 'A# Major', 'A#m' => 'A# Minor', 'B' => 'B Major', 'Bm' => 'B Minor', ); ?>


ID, self::META_PREFIX . 'album', true ); $albums = get_posts( array( 'post_type' => 'fedistream_album', 'posts_per_page' => -1, 'post_status' => array( 'publish', 'draft' ), 'orderby' => 'title', 'order' => 'ASC', ) ); ?>

ID, self::META_PREFIX . 'artists', true ); if ( ! is_array( $selected_artists ) ) { $selected_artists = array(); } $artists = get_posts( array( 'post_type' => 'fedistream_artist', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title', 'order' => 'ASC', ) ); ?>

' . esc_html__( 'Add an artist first.', 'wp-fedistream' ) . '' ); ?>

ID, self::META_PREFIX . 'isrc', true ); ?>

can_save( $post_id, 'fedistream_track_save', 'fedistream_track_nonce' ) ) { return; } // Save audio fields. $this->save_int_meta( $post_id, self::META_PREFIX . 'audio_file', 'fedistream_track_audio_file' ); $this->save_int_meta( $post_id, self::META_PREFIX . 'duration', 'fedistream_track_duration' ); // Save audio format. if ( isset( $_POST['fedistream_track_audio_format'] ) ) { $allowed_formats = array( '', 'mp3', 'wav', 'flac', 'ogg' ); $format = sanitize_text_field( wp_unslash( $_POST['fedistream_track_audio_format'] ) ); if ( in_array( $format, $allowed_formats, true ) ) { update_post_meta( $post_id, self::META_PREFIX . 'audio_format', $format ); } } // Save track info. $this->save_int_meta( $post_id, self::META_PREFIX . 'number', 'fedistream_track_number' ); $this->save_int_meta( $post_id, self::META_PREFIX . 'disc_number', 'fedistream_track_disc_number' ); $this->save_int_meta( $post_id, self::META_PREFIX . 'bpm', 'fedistream_track_bpm' ); $this->save_text_meta( $post_id, self::META_PREFIX . 'key', 'fedistream_track_key' ); $this->save_bool_meta( $post_id, self::META_PREFIX . 'explicit', 'fedistream_track_explicit' ); $this->save_int_meta( $post_id, self::META_PREFIX . 'preview_start', 'fedistream_track_preview_start' ); $this->save_int_meta( $post_id, self::META_PREFIX . 'preview_duration', 'fedistream_track_preview_duration' ); // Save album. $this->save_int_meta( $post_id, self::META_PREFIX . 'album', 'fedistream_track_album' ); // Save artists. if ( isset( $_POST['fedistream_track_artists'] ) && is_array( $_POST['fedistream_track_artists'] ) ) { $artists = array_map( 'absint', $_POST['fedistream_track_artists'] ); update_post_meta( $post_id, self::META_PREFIX . 'artists', $artists ); } else { delete_post_meta( $post_id, self::META_PREFIX . 'artists' ); } // Save ISRC. $this->save_text_meta( $post_id, self::META_PREFIX . 'isrc', 'fedistream_track_isrc' ); } /** * Update album stats when track is saved. * * @param int $post_id Post ID. * @param \WP_Post $post Post object. * @return void */ public function update_album_on_save( int $post_id, \WP_Post $post ): void { $album_id = get_post_meta( $post_id, self::META_PREFIX . 'album', true ); if ( $album_id ) { Album::update_album_stats( (int) $album_id ); } } /** * Get track by ID with meta. * * @param int $post_id Post ID. * @return array|null Track data or null. */ public static function get_track( int $post_id ): ?array { $post = get_post( $post_id ); if ( ! $post || 'fedistream_track' !== $post->post_type ) { return null; } $album_id = get_post_meta( $post_id, self::META_PREFIX . 'album', true ); $audio_file = get_post_meta( $post_id, self::META_PREFIX . 'audio_file', true ); $artists = get_post_meta( $post_id, self::META_PREFIX . 'artists', true ) ?: array(); // Get artist names. $artist_names = array(); foreach ( $artists as $artist_id ) { $artist_names[] = get_the_title( $artist_id ); } return array( 'id' => $post->ID, 'title' => $post->post_title, 'slug' => $post->post_name, 'lyrics' => $post->post_content, 'album_id' => $album_id ? (int) $album_id : null, 'album_title' => $album_id ? get_the_title( $album_id ) : null, 'artists' => $artists, 'artist_names' => $artist_names, 'track_number' => (int) get_post_meta( $post_id, self::META_PREFIX . 'number', true ), 'disc_number' => (int) get_post_meta( $post_id, self::META_PREFIX . 'disc_number', true ) ?: 1, 'duration' => (int) get_post_meta( $post_id, self::META_PREFIX . 'duration', true ), 'audio_file' => $audio_file ? (int) $audio_file : null, 'audio_url' => $audio_file ? wp_get_attachment_url( $audio_file ) : null, 'audio_format' => get_post_meta( $post_id, self::META_PREFIX . 'audio_format', true ), 'bpm' => (int) get_post_meta( $post_id, self::META_PREFIX . 'bpm', true ), 'key' => get_post_meta( $post_id, self::META_PREFIX . 'key', true ), 'explicit' => (bool) get_post_meta( $post_id, self::META_PREFIX . 'explicit', true ), 'isrc' => get_post_meta( $post_id, self::META_PREFIX . 'isrc', true ), 'preview_start' => (int) get_post_meta( $post_id, self::META_PREFIX . 'preview_start', true ), 'preview_duration' => (int) get_post_meta( $post_id, self::META_PREFIX . 'preview_duration', true ) ?: 30, 'artwork' => get_the_post_thumbnail_url( $post_id, 'large' ), 'url' => get_permalink( $post_id ), ); } }