You've already forked wp-fedistream
feat: Initial release v0.1.0
WP FediStream - Stream music over ActivityPub Features: - Custom post types: Artist, Album, Track, Playlist - Custom taxonomies: Genre, Mood, License - User roles: Artist, Label - Admin dashboard with statistics - Frontend templates and shortcodes - Audio player with queue management - ActivityPub integration with actor support - WooCommerce product types for albums/tracks - User library with favorites and history - Notification system (in-app and email) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
172
includes/Frontend/Ajax.php
Normal file
172
includes/Frontend/Ajax.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* AJAX handlers for frontend functionality.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles AJAX requests for the frontend.
|
||||
*/
|
||||
class Ajax {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Track data endpoint (public).
|
||||
add_action( 'wp_ajax_fedistream_get_track', array( $this, 'get_track' ) );
|
||||
add_action( 'wp_ajax_nopriv_fedistream_get_track', array( $this, 'get_track' ) );
|
||||
|
||||
// Record play endpoint (public).
|
||||
add_action( 'wp_ajax_fedistream_record_play', array( $this, 'record_play' ) );
|
||||
add_action( 'wp_ajax_nopriv_fedistream_record_play', array( $this, 'record_play' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get track data via AJAX.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function get_track(): void {
|
||||
// Verify nonce.
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'wp-fedistream-nonce' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
$track_id = isset( $_POST['track_id'] ) ? absint( $_POST['track_id'] ) : 0;
|
||||
|
||||
if ( ! $track_id ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid track ID.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
$track = get_post( $track_id );
|
||||
|
||||
if ( ! $track || 'fedistream_track' !== $track->post_type ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Track not found.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
// Check if track is published.
|
||||
if ( 'publish' !== $track->post_status ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Track not available.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
// Get audio file.
|
||||
$audio_id = get_post_meta( $track_id, '_fedistream_audio_file', true );
|
||||
$audio_url = $audio_id ? wp_get_attachment_url( $audio_id ) : '';
|
||||
|
||||
if ( ! $audio_url ) {
|
||||
wp_send_json_error( array( 'message' => __( 'No audio file available.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
// Get track metadata.
|
||||
$thumbnail_id = get_post_thumbnail_id( $track_id );
|
||||
$thumbnail = $thumbnail_id ? wp_get_attachment_image_url( $thumbnail_id, 'medium' ) : '';
|
||||
|
||||
// Get album info.
|
||||
$album_id = get_post_meta( $track_id, '_fedistream_album_id', true );
|
||||
$album = $album_id ? get_post( $album_id ) : null;
|
||||
|
||||
// Get artists.
|
||||
$artist_ids = get_post_meta( $track_id, '_fedistream_artist_ids', true );
|
||||
$artists = array();
|
||||
|
||||
if ( is_array( $artist_ids ) && ! empty( $artist_ids ) ) {
|
||||
foreach ( $artist_ids as $artist_id ) {
|
||||
$artist = get_post( $artist_id );
|
||||
if ( $artist && 'fedistream_artist' === $artist->post_type ) {
|
||||
$artists[] = array(
|
||||
'id' => $artist->ID,
|
||||
'name' => $artist->post_title,
|
||||
'link' => get_permalink( $artist->ID ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get duration.
|
||||
$duration = get_post_meta( $track_id, '_fedistream_duration', true );
|
||||
$duration_formatted = '';
|
||||
if ( $duration ) {
|
||||
$mins = floor( $duration / 60 );
|
||||
$secs = $duration % 60;
|
||||
$duration_formatted = $mins . ':' . str_pad( $secs, 2, '0', STR_PAD_LEFT );
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'id' => $track->ID,
|
||||
'title' => $track->post_title,
|
||||
'permalink' => get_permalink( $track->ID ),
|
||||
'audio_url' => $audio_url,
|
||||
'thumbnail' => $thumbnail,
|
||||
'artists' => $artists,
|
||||
'artist' => ! empty( $artists ) ? $artists[0]['name'] : '',
|
||||
'album' => $album ? $album->post_title : '',
|
||||
'album_id' => $album ? $album->ID : 0,
|
||||
'album_link' => $album ? get_permalink( $album->ID ) : '',
|
||||
'duration' => $duration,
|
||||
'duration_formatted' => $duration_formatted,
|
||||
'explicit' => (bool) get_post_meta( $track_id, '_fedistream_explicit', true ),
|
||||
);
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a track play via AJAX.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function record_play(): void {
|
||||
// Verify nonce.
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'wp-fedistream-nonce' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid nonce.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
$track_id = isset( $_POST['track_id'] ) ? absint( $_POST['track_id'] ) : 0;
|
||||
|
||||
if ( ! $track_id ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid track ID.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
$track = get_post( $track_id );
|
||||
|
||||
if ( ! $track || 'fedistream_track' !== $track->post_type ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Track not found.', 'wp-fedistream' ) ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
// Insert play record.
|
||||
$table = $wpdb->prefix . 'fedistream_plays';
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$wpdb->insert(
|
||||
$table,
|
||||
array(
|
||||
'track_id' => $track_id,
|
||||
'user_id' => get_current_user_id() ?: null,
|
||||
'played_at' => current_time( 'mysql' ),
|
||||
),
|
||||
array( '%d', '%d', '%s' )
|
||||
);
|
||||
|
||||
// Update play count in post meta.
|
||||
$play_count = (int) get_post_meta( $track_id, '_fedistream_play_count', true );
|
||||
update_post_meta( $track_id, '_fedistream_play_count', $play_count + 1 );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'message' => __( 'Play recorded.', 'wp-fedistream' ),
|
||||
'play_count' => $play_count + 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
513
includes/Frontend/Shortcodes.php
Normal file
513
includes/Frontend/Shortcodes.php
Normal file
@@ -0,0 +1,513 @@
|
||||
<?php
|
||||
/**
|
||||
* Shortcodes handler.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend;
|
||||
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers and handles all plugin shortcodes.
|
||||
*/
|
||||
class Shortcodes {
|
||||
|
||||
/**
|
||||
* Plugin instance.
|
||||
*
|
||||
* @var Plugin
|
||||
*/
|
||||
private Plugin $plugin;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->plugin = Plugin::get_instance();
|
||||
$this->register_shortcodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all shortcodes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function register_shortcodes(): void {
|
||||
add_shortcode( 'fedistream_artist', array( $this, 'render_artist' ) );
|
||||
add_shortcode( 'fedistream_album', array( $this, 'render_album' ) );
|
||||
add_shortcode( 'fedistream_track', array( $this, 'render_track' ) );
|
||||
add_shortcode( 'fedistream_playlist', array( $this, 'render_playlist' ) );
|
||||
add_shortcode( 'fedistream_latest_releases', array( $this, 'render_latest_releases' ) );
|
||||
add_shortcode( 'fedistream_popular_tracks', array( $this, 'render_popular_tracks' ) );
|
||||
add_shortcode( 'fedistream_artists', array( $this, 'render_artists_grid' ) );
|
||||
add_shortcode( 'fedistream_player', array( $this, 'render_player' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render single artist shortcode.
|
||||
*
|
||||
* [fedistream_artist id="123" show_albums="true" show_tracks="true"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_artist( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'slug' => '',
|
||||
'show_albums' => 'true',
|
||||
'show_tracks' => 'true',
|
||||
'layout' => 'full', // full, card, compact
|
||||
),
|
||||
$atts,
|
||||
'fedistream_artist'
|
||||
);
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_artist' );
|
||||
if ( ! $post ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'post' => TemplateLoader::get_artist_data( $post ),
|
||||
'show_albums' => filter_var( $atts['show_albums'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'show_tracks' => filter_var( $atts['show_tracks'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'layout' => sanitize_key( $atts['layout'] ),
|
||||
);
|
||||
|
||||
$template = 'card' === $atts['layout'] ? 'partials/card-artist' : 'shortcodes/artist';
|
||||
|
||||
return $this->render_template( $template, $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render single album shortcode.
|
||||
*
|
||||
* [fedistream_album id="123" show_tracks="true"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_album( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'slug' => '',
|
||||
'show_tracks' => 'true',
|
||||
'layout' => 'full', // full, card, compact
|
||||
),
|
||||
$atts,
|
||||
'fedistream_album'
|
||||
);
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_album' );
|
||||
if ( ! $post ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'post' => TemplateLoader::get_album_data( $post ),
|
||||
'show_tracks' => filter_var( $atts['show_tracks'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'layout' => sanitize_key( $atts['layout'] ),
|
||||
);
|
||||
|
||||
$template = 'card' === $atts['layout'] ? 'partials/card-album' : 'shortcodes/album';
|
||||
|
||||
return $this->render_template( $template, $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render single track shortcode.
|
||||
*
|
||||
* [fedistream_track id="123" show_player="true"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_track( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'slug' => '',
|
||||
'show_player' => 'true',
|
||||
'layout' => 'full', // full, card, compact
|
||||
),
|
||||
$atts,
|
||||
'fedistream_track'
|
||||
);
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_track' );
|
||||
if ( ! $post ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'post' => TemplateLoader::get_track_data( $post ),
|
||||
'show_player' => filter_var( $atts['show_player'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'layout' => sanitize_key( $atts['layout'] ),
|
||||
);
|
||||
|
||||
$template = 'card' === $atts['layout'] ? 'partials/card-track' : 'shortcodes/track';
|
||||
|
||||
return $this->render_template( $template, $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render playlist shortcode.
|
||||
*
|
||||
* [fedistream_playlist id="123" show_tracks="true"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_playlist( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'slug' => '',
|
||||
'show_tracks' => 'true',
|
||||
'layout' => 'full', // full, card, compact
|
||||
),
|
||||
$atts,
|
||||
'fedistream_playlist'
|
||||
);
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_playlist' );
|
||||
if ( ! $post ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'post' => TemplateLoader::get_playlist_data( $post ),
|
||||
'show_tracks' => filter_var( $atts['show_tracks'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'layout' => sanitize_key( $atts['layout'] ),
|
||||
);
|
||||
|
||||
$template = 'card' === $atts['layout'] ? 'partials/card-playlist' : 'shortcodes/playlist';
|
||||
|
||||
return $this->render_template( $template, $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render latest releases shortcode.
|
||||
*
|
||||
* [fedistream_latest_releases count="6" type="album" columns="3"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_latest_releases( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 6,
|
||||
'type' => '', // album, ep, single, compilation or empty for all
|
||||
'columns' => 3,
|
||||
'artist' => 0, // Filter by artist ID
|
||||
),
|
||||
$atts,
|
||||
'fedistream_latest_releases'
|
||||
);
|
||||
|
||||
$query_args = array(
|
||||
'post_type' => 'fedistream_album',
|
||||
'posts_per_page' => absint( $atts['count'] ),
|
||||
'orderby' => 'meta_value',
|
||||
'meta_key' => '_fedistream_release_date',
|
||||
'order' => 'DESC',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
// Filter by album type.
|
||||
if ( ! empty( $atts['type'] ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_fedistream_album_type',
|
||||
'value' => sanitize_key( $atts['type'] ),
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by artist.
|
||||
if ( ! empty( $atts['artist'] ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_fedistream_artist_id',
|
||||
'value' => absint( $atts['artist'] ),
|
||||
);
|
||||
}
|
||||
|
||||
$query = new \WP_Query( $query_args );
|
||||
$posts = array();
|
||||
|
||||
if ( $query->have_posts() ) {
|
||||
while ( $query->have_posts() ) {
|
||||
$query->the_post();
|
||||
$posts[] = TemplateLoader::get_album_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'posts' => $posts,
|
||||
'columns' => absint( $atts['columns'] ),
|
||||
'title' => __( 'Latest Releases', 'wp-fedistream' ),
|
||||
);
|
||||
|
||||
return $this->render_template( 'shortcodes/releases-grid', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render popular tracks shortcode.
|
||||
*
|
||||
* [fedistream_popular_tracks count="10" columns="1"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_popular_tracks( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 10,
|
||||
'columns' => 1,
|
||||
'artist' => 0, // Filter by artist ID
|
||||
'genre' => '', // Filter by genre slug
|
||||
),
|
||||
$atts,
|
||||
'fedistream_popular_tracks'
|
||||
);
|
||||
|
||||
$query_args = array(
|
||||
'post_type' => 'fedistream_track',
|
||||
'posts_per_page' => absint( $atts['count'] ),
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_key' => '_fedistream_play_count',
|
||||
'order' => 'DESC',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
// Filter by artist.
|
||||
if ( ! empty( $atts['artist'] ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_fedistream_artist_ids',
|
||||
'value' => absint( $atts['artist'] ),
|
||||
'compare' => 'LIKE',
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by genre.
|
||||
if ( ! empty( $atts['genre'] ) ) {
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'fedistream_genre',
|
||||
'field' => 'slug',
|
||||
'terms' => sanitize_title( $atts['genre'] ),
|
||||
);
|
||||
}
|
||||
|
||||
$query = new \WP_Query( $query_args );
|
||||
$posts = array();
|
||||
|
||||
if ( $query->have_posts() ) {
|
||||
while ( $query->have_posts() ) {
|
||||
$query->the_post();
|
||||
$posts[] = TemplateLoader::get_track_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'posts' => $posts,
|
||||
'columns' => absint( $atts['columns'] ),
|
||||
'title' => __( 'Popular Tracks', 'wp-fedistream' ),
|
||||
);
|
||||
|
||||
return $this->render_template( 'shortcodes/tracks-list', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render artists grid shortcode.
|
||||
*
|
||||
* [fedistream_artists count="12" columns="4" type="band"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_artists_grid( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 12,
|
||||
'columns' => 4,
|
||||
'type' => '', // solo, band, duo, collective, or empty for all
|
||||
'genre' => '', // Filter by genre slug
|
||||
'orderby' => 'title',
|
||||
'order' => 'ASC',
|
||||
),
|
||||
$atts,
|
||||
'fedistream_artists'
|
||||
);
|
||||
|
||||
$query_args = array(
|
||||
'post_type' => 'fedistream_artist',
|
||||
'posts_per_page' => absint( $atts['count'] ),
|
||||
'orderby' => sanitize_key( $atts['orderby'] ),
|
||||
'order' => 'DESC' === strtoupper( $atts['order'] ) ? 'DESC' : 'ASC',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
// Filter by artist type.
|
||||
if ( ! empty( $atts['type'] ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_fedistream_artist_type',
|
||||
'value' => sanitize_key( $atts['type'] ),
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by genre.
|
||||
if ( ! empty( $atts['genre'] ) ) {
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'fedistream_genre',
|
||||
'field' => 'slug',
|
||||
'terms' => sanitize_title( $atts['genre'] ),
|
||||
);
|
||||
}
|
||||
|
||||
$query = new \WP_Query( $query_args );
|
||||
$posts = array();
|
||||
|
||||
if ( $query->have_posts() ) {
|
||||
while ( $query->have_posts() ) {
|
||||
$query->the_post();
|
||||
$posts[] = TemplateLoader::get_artist_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'posts' => $posts,
|
||||
'columns' => absint( $atts['columns'] ),
|
||||
'title' => __( 'Artists', 'wp-fedistream' ),
|
||||
);
|
||||
|
||||
return $this->render_template( 'shortcodes/artists-grid', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render audio player shortcode.
|
||||
*
|
||||
* [fedistream_player track="123" autoplay="false"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function render_player( array $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'track' => 0,
|
||||
'playlist' => 0,
|
||||
'album' => 0,
|
||||
'autoplay' => 'false',
|
||||
'style' => 'default', // default, compact, mini
|
||||
),
|
||||
$atts,
|
||||
'fedistream_player'
|
||||
);
|
||||
|
||||
$tracks = array();
|
||||
|
||||
// Get tracks based on source.
|
||||
if ( ! empty( $atts['track'] ) ) {
|
||||
$post = get_post( absint( $atts['track'] ) );
|
||||
if ( $post && 'fedistream_track' === $post->post_type ) {
|
||||
$tracks[] = TemplateLoader::get_track_data( $post );
|
||||
}
|
||||
} elseif ( ! empty( $atts['album'] ) ) {
|
||||
$album_id = absint( $atts['album'] );
|
||||
$track_ids = get_post_meta( $album_id, '_fedistream_track_ids', true );
|
||||
if ( is_array( $track_ids ) ) {
|
||||
foreach ( $track_ids as $track_id ) {
|
||||
$post = get_post( $track_id );
|
||||
if ( $post && 'fedistream_track' === $post->post_type ) {
|
||||
$tracks[] = TemplateLoader::get_track_data( $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ( ! empty( $atts['playlist'] ) ) {
|
||||
$playlist_id = absint( $atts['playlist'] );
|
||||
$track_ids = get_post_meta( $playlist_id, '_fedistream_track_ids', true );
|
||||
if ( is_array( $track_ids ) ) {
|
||||
foreach ( $track_ids as $track_id ) {
|
||||
$post = get_post( $track_id );
|
||||
if ( $post && 'fedistream_track' === $post->post_type ) {
|
||||
$tracks[] = TemplateLoader::get_track_data( $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $tracks ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'tracks' => $tracks,
|
||||
'autoplay' => filter_var( $atts['autoplay'], FILTER_VALIDATE_BOOLEAN ),
|
||||
'style' => sanitize_key( $atts['style'] ),
|
||||
);
|
||||
|
||||
return $this->render_template( 'shortcodes/player', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post by ID or slug.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $post_type Post type.
|
||||
* @return \WP_Post|null
|
||||
*/
|
||||
private function get_post( array $atts, string $post_type ): ?\WP_Post {
|
||||
if ( ! empty( $atts['id'] ) ) {
|
||||
$post = get_post( absint( $atts['id'] ) );
|
||||
if ( $post && $post->post_type === $post_type ) {
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['slug'] ) ) {
|
||||
$posts = get_posts(
|
||||
array(
|
||||
'name' => sanitize_title( $atts['slug'] ),
|
||||
'post_type' => $post_type,
|
||||
'posts_per_page' => 1,
|
||||
'post_status' => 'publish',
|
||||
)
|
||||
);
|
||||
if ( ! empty( $posts ) ) {
|
||||
return $posts[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Twig template.
|
||||
*
|
||||
* @param string $template Template name.
|
||||
* @param array $context Template context.
|
||||
* @return string
|
||||
*/
|
||||
private function render_template( string $template, array $context ): string {
|
||||
try {
|
||||
return $this->plugin->render( $template, $context );
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
return '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
528
includes/Frontend/TemplateLoader.php
Normal file
528
includes/Frontend/TemplateLoader.php
Normal file
@@ -0,0 +1,528 @@
|
||||
<?php
|
||||
/**
|
||||
* Template loader for frontend display.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend;
|
||||
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* TemplateLoader class.
|
||||
*
|
||||
* Handles loading custom templates for FediStream post types.
|
||||
*/
|
||||
class TemplateLoader {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'template_include', array( $this, 'template_include' ) );
|
||||
add_filter( 'body_class', array( $this, 'body_class' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Include custom templates for FediStream post types.
|
||||
*
|
||||
* @param string $template Template path.
|
||||
* @return string Modified template path.
|
||||
*/
|
||||
public function template_include( string $template ): string {
|
||||
// Check if we're on a FediStream page.
|
||||
if ( is_singular( 'fedistream_artist' ) ) {
|
||||
return $this->get_template( 'single-artist' );
|
||||
}
|
||||
|
||||
if ( is_singular( 'fedistream_album' ) ) {
|
||||
return $this->get_template( 'single-album' );
|
||||
}
|
||||
|
||||
if ( is_singular( 'fedistream_track' ) ) {
|
||||
return $this->get_template( 'single-track' );
|
||||
}
|
||||
|
||||
if ( is_singular( 'fedistream_playlist' ) ) {
|
||||
return $this->get_template( 'single-playlist' );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive( 'fedistream_artist' ) ) {
|
||||
return $this->get_template( 'archive-artist' );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive( 'fedistream_album' ) ) {
|
||||
return $this->get_template( 'archive-album' );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive( 'fedistream_track' ) ) {
|
||||
return $this->get_template( 'archive-track' );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive( 'fedistream_playlist' ) ) {
|
||||
return $this->get_template( 'archive-playlist' );
|
||||
}
|
||||
|
||||
if ( is_tax( 'fedistream_genre' ) ) {
|
||||
return $this->get_template( 'taxonomy-genre' );
|
||||
}
|
||||
|
||||
if ( is_tax( 'fedistream_mood' ) ) {
|
||||
return $this->get_template( 'taxonomy-mood' );
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template file path.
|
||||
*
|
||||
* First checks theme for override, then uses plugin template.
|
||||
*
|
||||
* @param string $template_name Template name without extension.
|
||||
* @return string Template path.
|
||||
*/
|
||||
private function get_template( string $template_name ): string {
|
||||
// Check theme for override.
|
||||
$theme_template = locate_template(
|
||||
array(
|
||||
"fedistream/{$template_name}.php",
|
||||
"fedistream/{$template_name}.twig",
|
||||
)
|
||||
);
|
||||
|
||||
if ( $theme_template ) {
|
||||
return $theme_template;
|
||||
}
|
||||
|
||||
// Use plugin template wrapper.
|
||||
return WP_FEDISTREAM_PATH . 'includes/Frontend/template-wrapper.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add FediStream classes to body.
|
||||
*
|
||||
* @param array $classes Body classes.
|
||||
* @return array Modified classes.
|
||||
*/
|
||||
public function body_class( array $classes ): array {
|
||||
if ( $this->is_fedistream_page() ) {
|
||||
$classes[] = 'fedistream';
|
||||
|
||||
if ( is_singular( 'fedistream_artist' ) ) {
|
||||
$classes[] = 'fedistream-artist';
|
||||
$classes[] = 'fedistream-single';
|
||||
} elseif ( is_singular( 'fedistream_album' ) ) {
|
||||
$classes[] = 'fedistream-album';
|
||||
$classes[] = 'fedistream-single';
|
||||
} elseif ( is_singular( 'fedistream_track' ) ) {
|
||||
$classes[] = 'fedistream-track';
|
||||
$classes[] = 'fedistream-single';
|
||||
} elseif ( is_singular( 'fedistream_playlist' ) ) {
|
||||
$classes[] = 'fedistream-playlist';
|
||||
$classes[] = 'fedistream-single';
|
||||
} elseif ( is_post_type_archive( 'fedistream_artist' ) ) {
|
||||
$classes[] = 'fedistream-archive';
|
||||
$classes[] = 'fedistream-artists';
|
||||
} elseif ( is_post_type_archive( 'fedistream_album' ) ) {
|
||||
$classes[] = 'fedistream-archive';
|
||||
$classes[] = 'fedistream-albums';
|
||||
} elseif ( is_post_type_archive( 'fedistream_track' ) ) {
|
||||
$classes[] = 'fedistream-archive';
|
||||
$classes[] = 'fedistream-tracks';
|
||||
} elseif ( is_post_type_archive( 'fedistream_playlist' ) ) {
|
||||
$classes[] = 'fedistream-archive';
|
||||
$classes[] = 'fedistream-playlists';
|
||||
} elseif ( is_tax( 'fedistream_genre' ) || is_tax( 'fedistream_mood' ) ) {
|
||||
$classes[] = 'fedistream-archive';
|
||||
$classes[] = 'fedistream-taxonomy';
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current page is a FediStream page.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_fedistream_page(): bool {
|
||||
return is_singular( array( 'fedistream_artist', 'fedistream_album', 'fedistream_track', 'fedistream_playlist' ) )
|
||||
|| is_post_type_archive( array( 'fedistream_artist', 'fedistream_album', 'fedistream_track', 'fedistream_playlist' ) )
|
||||
|| is_tax( array( 'fedistream_genre', 'fedistream_mood', 'fedistream_license' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template context for current page.
|
||||
*
|
||||
* @return array Template context.
|
||||
*/
|
||||
public static function get_context(): array {
|
||||
$context = array(
|
||||
'site_name' => get_bloginfo( 'name' ),
|
||||
'site_url' => home_url(),
|
||||
'is_singular' => is_singular(),
|
||||
'is_archive' => is_archive(),
|
||||
'current_url' => get_permalink(),
|
||||
);
|
||||
|
||||
if ( is_singular() ) {
|
||||
global $post;
|
||||
$context['post'] = self::get_post_data( $post );
|
||||
}
|
||||
|
||||
if ( is_post_type_archive() || is_tax() ) {
|
||||
$context['posts'] = self::get_archive_posts();
|
||||
$context['pagination'] = self::get_pagination();
|
||||
$context['archive_title'] = self::get_archive_title();
|
||||
$context['archive_description'] = self::get_archive_description();
|
||||
}
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post data for template.
|
||||
*
|
||||
* @param \WP_Post $post Post object.
|
||||
* @return array Post data.
|
||||
*/
|
||||
public static function get_post_data( \WP_Post $post ): array {
|
||||
$data = array(
|
||||
'id' => $post->ID,
|
||||
'title' => get_the_title( $post ),
|
||||
'content' => apply_filters( 'the_content', $post->post_content ),
|
||||
'excerpt' => get_the_excerpt( $post ),
|
||||
'permalink' => get_permalink( $post ),
|
||||
'thumbnail' => get_the_post_thumbnail_url( $post->ID, 'large' ),
|
||||
'date' => get_the_date( '', $post ),
|
||||
'author' => get_the_author_meta( 'display_name', $post->post_author ),
|
||||
);
|
||||
|
||||
// Add post type specific data.
|
||||
switch ( $post->post_type ) {
|
||||
case 'fedistream_artist':
|
||||
$data = array_merge( $data, self::get_artist_data( $post->ID ) );
|
||||
break;
|
||||
case 'fedistream_album':
|
||||
$data = array_merge( $data, self::get_album_data( $post->ID ) );
|
||||
break;
|
||||
case 'fedistream_track':
|
||||
$data = array_merge( $data, self::get_track_data( $post->ID ) );
|
||||
break;
|
||||
case 'fedistream_playlist':
|
||||
$data = array_merge( $data, self::get_playlist_data( $post->ID ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Add taxonomies.
|
||||
$data['genres'] = self::get_terms( $post->ID, 'fedistream_genre' );
|
||||
$data['moods'] = self::get_terms( $post->ID, 'fedistream_mood' );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get artist-specific data.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array Artist data.
|
||||
*/
|
||||
private static function get_artist_data( int $post_id ): array {
|
||||
$type = get_post_meta( $post_id, '_fedistream_artist_type', true ) ?: 'solo';
|
||||
$types = array(
|
||||
'solo' => __( 'Solo Artist', 'wp-fedistream' ),
|
||||
'band' => __( 'Band', 'wp-fedistream' ),
|
||||
'duo' => __( 'Duo', 'wp-fedistream' ),
|
||||
'collective' => __( 'Collective', 'wp-fedistream' ),
|
||||
);
|
||||
|
||||
$albums = get_posts(
|
||||
array(
|
||||
'post_type' => 'fedistream_album',
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'meta_key' => '_fedistream_album_artist',
|
||||
'meta_value' => $post_id,
|
||||
'orderby' => 'meta_value',
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => '_fedistream_album_release_date',
|
||||
'compare' => 'EXISTS',
|
||||
),
|
||||
),
|
||||
'order' => 'DESC',
|
||||
)
|
||||
);
|
||||
|
||||
return array(
|
||||
'artist_type' => $type,
|
||||
'artist_type_label' => $types[ $type ] ?? $types['solo'],
|
||||
'formed_date' => get_post_meta( $post_id, '_fedistream_artist_formed_date', true ),
|
||||
'location' => get_post_meta( $post_id, '_fedistream_artist_location', true ),
|
||||
'website' => get_post_meta( $post_id, '_fedistream_artist_website', true ),
|
||||
'social_links' => get_post_meta( $post_id, '_fedistream_artist_social_links', true ) ?: array(),
|
||||
'members' => get_post_meta( $post_id, '_fedistream_artist_members', true ) ?: array(),
|
||||
'albums' => array_map( array( __CLASS__, 'get_post_data' ), $albums ),
|
||||
'album_count' => count( $albums ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get album-specific data.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array Album data.
|
||||
*/
|
||||
private static function get_album_data( int $post_id ): array {
|
||||
$type = get_post_meta( $post_id, '_fedistream_album_type', true ) ?: 'album';
|
||||
$types = array(
|
||||
'album' => __( 'Album', 'wp-fedistream' ),
|
||||
'ep' => __( 'EP', 'wp-fedistream' ),
|
||||
'single' => __( 'Single', 'wp-fedistream' ),
|
||||
'compilation' => __( 'Compilation', 'wp-fedistream' ),
|
||||
'live' => __( 'Live Album', 'wp-fedistream' ),
|
||||
'remix' => __( 'Remix Album', 'wp-fedistream' ),
|
||||
);
|
||||
$artist_id = get_post_meta( $post_id, '_fedistream_album_artist', true );
|
||||
|
||||
$tracks = get_posts(
|
||||
array(
|
||||
'post_type' => 'fedistream_track',
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'meta_key' => '_fedistream_track_album',
|
||||
'meta_value' => $post_id,
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_query' => array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'key' => '_fedistream_track_number',
|
||||
'compare' => 'EXISTS',
|
||||
),
|
||||
),
|
||||
'order' => 'ASC',
|
||||
)
|
||||
);
|
||||
|
||||
return array(
|
||||
'album_type' => $type,
|
||||
'album_type_label' => $types[ $type ] ?? $types['album'],
|
||||
'release_date' => get_post_meta( $post_id, '_fedistream_album_release_date', true ),
|
||||
'release_year' => date( 'Y', strtotime( get_post_meta( $post_id, '_fedistream_album_release_date', true ) ?: 'now' ) ),
|
||||
'artist_id' => $artist_id,
|
||||
'artist_name' => $artist_id ? get_the_title( $artist_id ) : '',
|
||||
'artist_url' => $artist_id ? get_permalink( $artist_id ) : '',
|
||||
'upc' => get_post_meta( $post_id, '_fedistream_album_upc', true ),
|
||||
'catalog_number' => get_post_meta( $post_id, '_fedistream_album_catalog_number', true ),
|
||||
'total_tracks' => count( $tracks ),
|
||||
'total_duration' => (int) get_post_meta( $post_id, '_fedistream_album_total_duration', true ),
|
||||
'tracks' => array_map( array( __CLASS__, 'get_post_data' ), $tracks ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get track-specific data.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array Track data.
|
||||
*/
|
||||
private static function get_track_data( int $post_id ): array {
|
||||
$album_id = get_post_meta( $post_id, '_fedistream_track_album', true );
|
||||
$audio_file = get_post_meta( $post_id, '_fedistream_track_audio_file', true );
|
||||
$artists = get_post_meta( $post_id, '_fedistream_track_artists', true ) ?: array();
|
||||
$duration = (int) get_post_meta( $post_id, '_fedistream_track_duration', true );
|
||||
|
||||
$artist_data = array();
|
||||
foreach ( $artists as $artist_id ) {
|
||||
$artist = get_post( $artist_id );
|
||||
if ( $artist ) {
|
||||
$artist_data[] = array(
|
||||
'id' => $artist_id,
|
||||
'name' => $artist->post_title,
|
||||
'url' => get_permalink( $artist_id ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'track_number' => (int) get_post_meta( $post_id, '_fedistream_track_number', true ),
|
||||
'disc_number' => (int) get_post_meta( $post_id, '_fedistream_track_disc_number', true ) ?: 1,
|
||||
'duration' => $duration,
|
||||
'duration_formatted' => $duration ? sprintf( '%d:%02d', floor( $duration / 60 ), $duration % 60 ) : '',
|
||||
'audio_url' => $audio_file ? wp_get_attachment_url( $audio_file ) : '',
|
||||
'audio_format' => get_post_meta( $post_id, '_fedistream_track_audio_format', true ),
|
||||
'bpm' => (int) get_post_meta( $post_id, '_fedistream_track_bpm', true ),
|
||||
'key' => get_post_meta( $post_id, '_fedistream_track_key', true ),
|
||||
'explicit' => (bool) get_post_meta( $post_id, '_fedistream_track_explicit', true ),
|
||||
'isrc' => get_post_meta( $post_id, '_fedistream_track_isrc', true ),
|
||||
'album_id' => $album_id,
|
||||
'album_title' => $album_id ? get_the_title( $album_id ) : '',
|
||||
'album_url' => $album_id ? get_permalink( $album_id ) : '',
|
||||
'album_artwork' => $album_id ? get_the_post_thumbnail_url( $album_id, 'medium' ) : '',
|
||||
'artists' => $artist_data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get playlist-specific data.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array Playlist data.
|
||||
*/
|
||||
private static function get_playlist_data( int $post_id ): array {
|
||||
global $wpdb;
|
||||
|
||||
$table = $wpdb->prefix . 'fedistream_playlist_tracks';
|
||||
$duration = (int) get_post_meta( $post_id, '_fedistream_playlist_total_duration', true );
|
||||
|
||||
// Get tracks.
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
$track_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT track_id FROM $table WHERE playlist_id = %d ORDER BY position ASC",
|
||||
$post_id
|
||||
)
|
||||
);
|
||||
|
||||
$tracks = array();
|
||||
foreach ( $track_ids as $track_id ) {
|
||||
$track = get_post( $track_id );
|
||||
if ( $track && 'publish' === $track->post_status ) {
|
||||
$tracks[] = self::get_post_data( $track );
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'visibility' => get_post_meta( $post_id, '_fedistream_playlist_visibility', true ) ?: 'public',
|
||||
'collaborative' => (bool) get_post_meta( $post_id, '_fedistream_playlist_collaborative', true ),
|
||||
'federated' => (bool) get_post_meta( $post_id, '_fedistream_playlist_federated', true ),
|
||||
'track_count' => count( $tracks ),
|
||||
'total_duration' => $duration,
|
||||
'duration_formatted' => $duration >= 3600
|
||||
? sprintf( '%d:%02d:%02d', floor( $duration / 3600 ), floor( ( $duration % 3600 ) / 60 ), $duration % 60 )
|
||||
: sprintf( '%d:%02d', floor( $duration / 60 ), $duration % 60 ),
|
||||
'tracks' => $tracks,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get taxonomy terms for post.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $taxonomy Taxonomy name.
|
||||
* @return array Terms with name and URL.
|
||||
*/
|
||||
private static function get_terms( int $post_id, string $taxonomy ): array {
|
||||
$terms = get_the_terms( $post_id, $taxonomy );
|
||||
|
||||
if ( ! $terms || is_wp_error( $terms ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function ( $term ) {
|
||||
return array(
|
||||
'id' => $term->term_id,
|
||||
'name' => $term->name,
|
||||
'slug' => $term->slug,
|
||||
'url' => get_term_link( $term ),
|
||||
);
|
||||
},
|
||||
$terms
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get archive posts.
|
||||
*
|
||||
* @return array Posts for archive.
|
||||
*/
|
||||
private static function get_archive_posts(): array {
|
||||
global $wp_query;
|
||||
|
||||
$posts = array();
|
||||
if ( $wp_query->have_posts() ) {
|
||||
while ( $wp_query->have_posts() ) {
|
||||
$wp_query->the_post();
|
||||
$posts[] = self::get_post_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pagination data.
|
||||
*
|
||||
* @return array Pagination data.
|
||||
*/
|
||||
private static function get_pagination(): array {
|
||||
global $wp_query;
|
||||
|
||||
$total_pages = $wp_query->max_num_pages;
|
||||
$current = max( 1, get_query_var( 'paged' ) );
|
||||
|
||||
return array(
|
||||
'total_pages' => $total_pages,
|
||||
'current_page' => $current,
|
||||
'has_prev' => $current > 1,
|
||||
'has_next' => $current < $total_pages,
|
||||
'prev_url' => $current > 1 ? get_pagenum_link( $current - 1 ) : '',
|
||||
'next_url' => $current < $total_pages ? get_pagenum_link( $current + 1 ) : '',
|
||||
'links' => paginate_links(
|
||||
array(
|
||||
'total' => $total_pages,
|
||||
'current' => $current,
|
||||
'type' => 'array',
|
||||
'prev_text' => __( '« Previous', 'wp-fedistream' ),
|
||||
'next_text' => __( 'Next »', 'wp-fedistream' ),
|
||||
)
|
||||
) ?: array(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get archive title.
|
||||
*
|
||||
* @return string Archive title.
|
||||
*/
|
||||
private static function get_archive_title(): string {
|
||||
if ( is_post_type_archive( 'fedistream_artist' ) ) {
|
||||
return __( 'Artists', 'wp-fedistream' );
|
||||
}
|
||||
if ( is_post_type_archive( 'fedistream_album' ) ) {
|
||||
return __( 'Albums', 'wp-fedistream' );
|
||||
}
|
||||
if ( is_post_type_archive( 'fedistream_track' ) ) {
|
||||
return __( 'Tracks', 'wp-fedistream' );
|
||||
}
|
||||
if ( is_post_type_archive( 'fedistream_playlist' ) ) {
|
||||
return __( 'Playlists', 'wp-fedistream' );
|
||||
}
|
||||
if ( is_tax() ) {
|
||||
return single_term_title( '', false );
|
||||
}
|
||||
return get_the_archive_title();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get archive description.
|
||||
*
|
||||
* @return string Archive description.
|
||||
*/
|
||||
private static function get_archive_description(): string {
|
||||
if ( is_tax() ) {
|
||||
return term_description();
|
||||
}
|
||||
return get_the_archive_description();
|
||||
}
|
||||
}
|
||||
38
includes/Frontend/Widgets.php
Normal file
38
includes/Frontend/Widgets.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* Widgets handler.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers and manages all plugin widgets.
|
||||
*/
|
||||
class Widgets {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'widgets_init', array( $this, 'register_widgets' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all widgets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_widgets(): void {
|
||||
register_widget( Widgets\RecentReleasesWidget::class );
|
||||
register_widget( Widgets\PopularTracksWidget::class );
|
||||
register_widget( Widgets\FeaturedArtistWidget::class );
|
||||
register_widget( Widgets\NowPlayingWidget::class );
|
||||
}
|
||||
}
|
||||
162
includes/Frontend/Widgets/FeaturedArtistWidget.php
Normal file
162
includes/Frontend/Widgets/FeaturedArtistWidget.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
* Featured Artist Widget.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend\Widgets;
|
||||
|
||||
use WP_FediStream\Frontend\TemplateLoader;
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a featured artist.
|
||||
*/
|
||||
class FeaturedArtistWidget extends \WP_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'fedistream_featured_artist',
|
||||
__( 'FediStream: Featured Artist', 'wp-fedistream' ),
|
||||
array(
|
||||
'description' => __( 'Display a featured artist.', 'wp-fedistream' ),
|
||||
'classname' => 'fedistream-widget fedistream-widget--featured-artist',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front-end display.
|
||||
*
|
||||
* @param array $args Widget arguments.
|
||||
* @param array $instance Saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Featured Artist', 'wp-fedistream' );
|
||||
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
||||
$artist_id = ! empty( $instance['artist_id'] ) ? absint( $instance['artist_id'] ) : 0;
|
||||
$random = ! empty( $instance['random'] ) && $instance['random'];
|
||||
|
||||
$post = null;
|
||||
|
||||
if ( $random ) {
|
||||
// Get a random artist.
|
||||
$posts = get_posts(
|
||||
array(
|
||||
'post_type' => 'fedistream_artist',
|
||||
'posts_per_page' => 1,
|
||||
'orderby' => 'rand',
|
||||
'post_status' => 'publish',
|
||||
)
|
||||
);
|
||||
if ( ! empty( $posts ) ) {
|
||||
$post = $posts[0];
|
||||
}
|
||||
} elseif ( $artist_id ) {
|
||||
$post = get_post( $artist_id );
|
||||
if ( $post && 'fedistream_artist' !== $post->post_type ) {
|
||||
$post = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $post ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$artist_data = TemplateLoader::get_artist_data( $post );
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
if ( $title ) {
|
||||
echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
try {
|
||||
$plugin = Plugin::get_instance();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $plugin->render(
|
||||
'widgets/featured-artist',
|
||||
array(
|
||||
'post' => $artist_data,
|
||||
)
|
||||
);
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
echo '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Back-end widget form.
|
||||
*
|
||||
* @param array $instance Previously saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Featured Artist', 'wp-fedistream' );
|
||||
$artist_id = ! empty( $instance['artist_id'] ) ? absint( $instance['artist_id'] ) : 0;
|
||||
$random = ! empty( $instance['random'] ) && $instance['random'];
|
||||
|
||||
// Get all artists for dropdown.
|
||||
$artists = get_posts(
|
||||
array(
|
||||
'post_type' => 'fedistream_artist',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'title',
|
||||
'order' => 'ASC',
|
||||
'post_status' => 'publish',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'wp-fedistream' ); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'random' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'random' ) ); ?>" value="1" <?php checked( $random ); ?>>
|
||||
<?php esc_html_e( 'Show random artist', 'wp-fedistream' ); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'artist_id' ) ); ?>"><?php esc_html_e( 'Or select specific artist:', 'wp-fedistream' ); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'artist_id' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'artist_id' ) ); ?>">
|
||||
<option value=""><?php esc_html_e( '-- Select Artist --', 'wp-fedistream' ); ?></option>
|
||||
<?php foreach ( $artists as $artist ) : ?>
|
||||
<option value="<?php echo esc_attr( $artist->ID ); ?>" <?php selected( $artist_id, $artist->ID ); ?>>
|
||||
<?php echo esc_html( $artist->post_title ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize widget form values as they are saved.
|
||||
*
|
||||
* @param array $new_instance Values just sent to be saved.
|
||||
* @param array $old_instance Previously saved values from database.
|
||||
* @return array Updated safe values to be saved.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ): array {
|
||||
$instance = array();
|
||||
$instance['title'] = ! empty( $new_instance['title'] ) ? sanitize_text_field( $new_instance['title'] ) : '';
|
||||
$instance['artist_id'] = ! empty( $new_instance['artist_id'] ) ? absint( $new_instance['artist_id'] ) : 0;
|
||||
$instance['random'] = ! empty( $new_instance['random'] );
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
111
includes/Frontend/Widgets/NowPlayingWidget.php
Normal file
111
includes/Frontend/Widgets/NowPlayingWidget.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Now Playing Widget.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend\Widgets;
|
||||
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the currently playing track (updates via JavaScript).
|
||||
*/
|
||||
class NowPlayingWidget extends \WP_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'fedistream_now_playing',
|
||||
__( 'FediStream: Now Playing', 'wp-fedistream' ),
|
||||
array(
|
||||
'description' => __( 'Display the currently playing track.', 'wp-fedistream' ),
|
||||
'classname' => 'fedistream-widget fedistream-widget--now-playing',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front-end display.
|
||||
*
|
||||
* @param array $args Widget arguments.
|
||||
* @param array $instance Saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Now Playing', 'wp-fedistream' );
|
||||
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
||||
$show_player = ! empty( $instance['show_player'] );
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
if ( $title ) {
|
||||
echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
try {
|
||||
$plugin = Plugin::get_instance();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $plugin->render(
|
||||
'widgets/now-playing',
|
||||
array(
|
||||
'show_player' => $show_player,
|
||||
)
|
||||
);
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
echo '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Back-end widget form.
|
||||
*
|
||||
* @param array $instance Previously saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Now Playing', 'wp-fedistream' );
|
||||
$show_player = ! empty( $instance['show_player'] );
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'wp-fedistream' ); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'show_player' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'show_player' ) ); ?>" value="1" <?php checked( $show_player ); ?>>
|
||||
<?php esc_html_e( 'Show player controls', 'wp-fedistream' ); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'This widget shows information about the currently playing track and updates automatically via JavaScript.', 'wp-fedistream' ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize widget form values as they are saved.
|
||||
*
|
||||
* @param array $new_instance Values just sent to be saved.
|
||||
* @param array $old_instance Previously saved values from database.
|
||||
* @return array Updated safe values to be saved.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ): array {
|
||||
$instance = array();
|
||||
$instance['title'] = ! empty( $new_instance['title'] ) ? sanitize_text_field( $new_instance['title'] ) : '';
|
||||
$instance['show_player'] = ! empty( $new_instance['show_player'] );
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
127
includes/Frontend/Widgets/PopularTracksWidget.php
Normal file
127
includes/Frontend/Widgets/PopularTracksWidget.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* Popular Tracks Widget.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend\Widgets;
|
||||
|
||||
use WP_FediStream\Frontend\TemplateLoader;
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays popular tracks based on play count.
|
||||
*/
|
||||
class PopularTracksWidget extends \WP_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'fedistream_popular_tracks',
|
||||
__( 'FediStream: Popular Tracks', 'wp-fedistream' ),
|
||||
array(
|
||||
'description' => __( 'Display popular tracks by play count.', 'wp-fedistream' ),
|
||||
'classname' => 'fedistream-widget fedistream-widget--popular-tracks',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front-end display.
|
||||
*
|
||||
* @param array $args Widget arguments.
|
||||
* @param array $instance Saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Popular Tracks', 'wp-fedistream' );
|
||||
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
||||
$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;
|
||||
|
||||
$query_args = array(
|
||||
'post_type' => 'fedistream_track',
|
||||
'posts_per_page' => $count,
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_key' => '_fedistream_play_count',
|
||||
'order' => 'DESC',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
$query = new \WP_Query( $query_args );
|
||||
$posts = array();
|
||||
|
||||
if ( $query->have_posts() ) {
|
||||
while ( $query->have_posts() ) {
|
||||
$query->the_post();
|
||||
$posts[] = TemplateLoader::get_track_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
if ( $title ) {
|
||||
echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
try {
|
||||
$plugin = Plugin::get_instance();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $plugin->render(
|
||||
'widgets/popular-tracks',
|
||||
array(
|
||||
'posts' => $posts,
|
||||
)
|
||||
);
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
echo '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Back-end widget form.
|
||||
*
|
||||
* @param array $instance Previously saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Popular Tracks', 'wp-fedistream' );
|
||||
$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'wp-fedistream' ); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Number of tracks:', 'wp-fedistream' ); ?></label>
|
||||
<input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" min="1" max="20" value="<?php echo esc_attr( $count ); ?>">
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize widget form values as they are saved.
|
||||
*
|
||||
* @param array $new_instance Values just sent to be saved.
|
||||
* @param array $old_instance Previously saved values from database.
|
||||
* @return array Updated safe values to be saved.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ): array {
|
||||
$instance = array();
|
||||
$instance['title'] = ! empty( $new_instance['title'] ) ? sanitize_text_field( $new_instance['title'] ) : '';
|
||||
$instance['count'] = ! empty( $new_instance['count'] ) ? absint( $new_instance['count'] ) : 5;
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
147
includes/Frontend/Widgets/RecentReleasesWidget.php
Normal file
147
includes/Frontend/Widgets/RecentReleasesWidget.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* Recent Releases Widget.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
namespace WP_FediStream\Frontend\Widgets;
|
||||
|
||||
use WP_FediStream\Frontend\TemplateLoader;
|
||||
use WP_FediStream\Plugin;
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays recent album releases.
|
||||
*/
|
||||
class RecentReleasesWidget extends \WP_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'fedistream_recent_releases',
|
||||
__( 'FediStream: Recent Releases', 'wp-fedistream' ),
|
||||
array(
|
||||
'description' => __( 'Display recent album releases.', 'wp-fedistream' ),
|
||||
'classname' => 'fedistream-widget fedistream-widget--recent-releases',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front-end display.
|
||||
*
|
||||
* @param array $args Widget arguments.
|
||||
* @param array $instance Saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Recent Releases', 'wp-fedistream' );
|
||||
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
|
||||
$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;
|
||||
$type = ! empty( $instance['type'] ) ? $instance['type'] : '';
|
||||
|
||||
$query_args = array(
|
||||
'post_type' => 'fedistream_album',
|
||||
'posts_per_page' => $count,
|
||||
'orderby' => 'meta_value',
|
||||
'meta_key' => '_fedistream_release_date',
|
||||
'order' => 'DESC',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
if ( ! empty( $type ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_fedistream_album_type',
|
||||
'value' => $type,
|
||||
);
|
||||
}
|
||||
|
||||
$query = new \WP_Query( $query_args );
|
||||
$posts = array();
|
||||
|
||||
if ( $query->have_posts() ) {
|
||||
while ( $query->have_posts() ) {
|
||||
$query->the_post();
|
||||
$posts[] = TemplateLoader::get_album_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
if ( $title ) {
|
||||
echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
try {
|
||||
$plugin = Plugin::get_instance();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $plugin->render(
|
||||
'widgets/recent-releases',
|
||||
array(
|
||||
'posts' => $posts,
|
||||
)
|
||||
);
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
echo '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Back-end widget form.
|
||||
*
|
||||
* @param array $instance Previously saved values from database.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ): void {
|
||||
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Recent Releases', 'wp-fedistream' );
|
||||
$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;
|
||||
$type = ! empty( $instance['type'] ) ? $instance['type'] : '';
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'wp-fedistream' ); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Number of releases:', 'wp-fedistream' ); ?></label>
|
||||
<input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" min="1" max="20" value="<?php echo esc_attr( $count ); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'type' ) ); ?>"><?php esc_html_e( 'Release type:', 'wp-fedistream' ); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'type' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'type' ) ); ?>">
|
||||
<option value="" <?php selected( $type, '' ); ?>><?php esc_html_e( 'All types', 'wp-fedistream' ); ?></option>
|
||||
<option value="album" <?php selected( $type, 'album' ); ?>><?php esc_html_e( 'Album', 'wp-fedistream' ); ?></option>
|
||||
<option value="ep" <?php selected( $type, 'ep' ); ?>><?php esc_html_e( 'EP', 'wp-fedistream' ); ?></option>
|
||||
<option value="single" <?php selected( $type, 'single' ); ?>><?php esc_html_e( 'Single', 'wp-fedistream' ); ?></option>
|
||||
<option value="compilation" <?php selected( $type, 'compilation' ); ?>><?php esc_html_e( 'Compilation', 'wp-fedistream' ); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize widget form values as they are saved.
|
||||
*
|
||||
* @param array $new_instance Values just sent to be saved.
|
||||
* @param array $old_instance Previously saved values from database.
|
||||
* @return array Updated safe values to be saved.
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ): array {
|
||||
$instance = array();
|
||||
$instance['title'] = ! empty( $new_instance['title'] ) ? sanitize_text_field( $new_instance['title'] ) : '';
|
||||
$instance['count'] = ! empty( $new_instance['count'] ) ? absint( $new_instance['count'] ) : 5;
|
||||
$instance['type'] = ! empty( $new_instance['type'] ) ? sanitize_key( $new_instance['type'] ) : '';
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
78
includes/Frontend/template-wrapper.php
Normal file
78
includes/Frontend/template-wrapper.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* Template wrapper for FediStream Twig templates.
|
||||
*
|
||||
* @package WP_FediStream
|
||||
*/
|
||||
|
||||
// Prevent direct file access.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use WP_FediStream\Plugin;
|
||||
use WP_FediStream\Frontend\TemplateLoader;
|
||||
|
||||
// Get template context.
|
||||
$context = TemplateLoader::get_context();
|
||||
|
||||
// Determine template name.
|
||||
$template_name = '';
|
||||
|
||||
if ( is_singular( 'fedistream_artist' ) ) {
|
||||
$template_name = 'single/artist';
|
||||
} elseif ( is_singular( 'fedistream_album' ) ) {
|
||||
$template_name = 'single/album';
|
||||
} elseif ( is_singular( 'fedistream_track' ) ) {
|
||||
$template_name = 'single/track';
|
||||
} elseif ( is_singular( 'fedistream_playlist' ) ) {
|
||||
$template_name = 'single/playlist';
|
||||
} elseif ( is_post_type_archive( 'fedistream_artist' ) ) {
|
||||
$template_name = 'archive/artist';
|
||||
} elseif ( is_post_type_archive( 'fedistream_album' ) ) {
|
||||
$template_name = 'archive/album';
|
||||
} elseif ( is_post_type_archive( 'fedistream_track' ) ) {
|
||||
$template_name = 'archive/track';
|
||||
} elseif ( is_post_type_archive( 'fedistream_playlist' ) ) {
|
||||
$template_name = 'archive/playlist';
|
||||
} elseif ( is_tax( 'fedistream_genre' ) ) {
|
||||
$template_name = 'archive/taxonomy';
|
||||
$context['taxonomy_name'] = __( 'Genre', 'wp-fedistream' );
|
||||
} elseif ( is_tax( 'fedistream_mood' ) ) {
|
||||
$template_name = 'archive/taxonomy';
|
||||
$context['taxonomy_name'] = __( 'Mood', 'wp-fedistream' );
|
||||
}
|
||||
|
||||
// Get the plugin instance.
|
||||
$plugin = Plugin::get_instance();
|
||||
|
||||
get_header();
|
||||
?>
|
||||
|
||||
<main id="fedistream-content" class="fedistream-main">
|
||||
<?php
|
||||
if ( $template_name ) {
|
||||
try {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $plugin->render( $template_name, $context );
|
||||
} catch ( \Exception $e ) {
|
||||
if ( WP_DEBUG ) {
|
||||
echo '<div class="fedistream-error">';
|
||||
echo '<p>' . esc_html__( 'Template Error:', 'wp-fedistream' ) . ' ' . esc_html( $e->getMessage() ) . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to default content.
|
||||
if ( have_posts() ) {
|
||||
while ( have_posts() ) {
|
||||
the_post();
|
||||
the_content();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</main>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
Reference in New Issue
Block a user