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:
2026-01-28 23:23:05 +01:00
commit 4a5d7b9f4d
91 changed files with 22750 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
<?php
/**
* Abstract base class for custom post types.
*
* @package WP_FediStream
*/
namespace WP_FediStream\PostTypes;
// Prevent direct file access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Abstract post type class.
*
* Provides common functionality for all custom post types.
*/
abstract class AbstractPostType {
/**
* Post type key.
*
* @var string
*/
protected string $post_type;
/**
* Constructor.
*/
public function __construct() {
add_action( 'init', array( $this, 'register' ) );
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
add_action( 'save_post_' . $this->post_type, array( $this, 'save_meta' ), 10, 2 );
}
/**
* Register the post type.
*
* @return void
*/
abstract public function register(): void;
/**
* Add meta boxes.
*
* @return void
*/
abstract public function add_meta_boxes(): void;
/**
* Save post meta.
*
* @param int $post_id Post ID.
* @param \WP_Post $post Post object.
* @return void
*/
abstract public function save_meta( int $post_id, \WP_Post $post ): void;
/**
* Get the post type key.
*
* @return string
*/
public function get_post_type(): string {
return $this->post_type;
}
/**
* Verify nonce and user capabilities before saving.
*
* @param int $post_id Post ID.
* @param string $nonce_action Nonce action name.
* @param string $nonce_name Nonce field name.
* @return bool Whether save should proceed.
*/
protected function can_save( int $post_id, string $nonce_action, string $nonce_name ): bool {
// Verify nonce.
if ( ! isset( $_POST[ $nonce_name ] ) || ! wp_verify_nonce( sanitize_key( $_POST[ $nonce_name ] ), $nonce_action ) ) {
return false;
}
// Check autosave.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return false;
}
// Check permissions.
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return false;
}
return true;
}
/**
* Sanitize and save a text meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_text_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) ) {
update_post_meta( $post_id, $meta_key, sanitize_text_field( wp_unslash( $_POST[ $post_key ] ) ) );
}
}
/**
* Sanitize and save a textarea meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_textarea_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) ) {
update_post_meta( $post_id, $meta_key, sanitize_textarea_field( wp_unslash( $_POST[ $post_key ] ) ) );
}
}
/**
* Sanitize and save an integer meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_int_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) ) {
update_post_meta( $post_id, $meta_key, absint( $_POST[ $post_key ] ) );
}
}
/**
* Sanitize and save a URL meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_url_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) ) {
update_post_meta( $post_id, $meta_key, esc_url_raw( wp_unslash( $_POST[ $post_key ] ) ) );
}
}
/**
* Sanitize and save a boolean meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_bool_meta( int $post_id, string $meta_key, string $post_key ): void {
$value = isset( $_POST[ $post_key ] ) ? 1 : 0;
update_post_meta( $post_id, $meta_key, $value );
}
/**
* Sanitize and save an array meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_array_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) && is_array( $_POST[ $post_key ] ) ) {
$values = array_map( 'sanitize_text_field', wp_unslash( $_POST[ $post_key ] ) );
update_post_meta( $post_id, $meta_key, $values );
} else {
delete_post_meta( $post_id, $meta_key );
}
}
/**
* Sanitize and save a date meta field.
*
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string $post_key POST array key.
* @return void
*/
protected function save_date_meta( int $post_id, string $meta_key, string $post_key ): void {
if ( isset( $_POST[ $post_key ] ) && ! empty( $_POST[ $post_key ] ) ) {
$date = sanitize_text_field( wp_unslash( $_POST[ $post_key ] ) );
// Validate date format (YYYY-MM-DD).
if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) {
update_post_meta( $post_id, $meta_key, $date );
}
} else {
delete_post_meta( $post_id, $meta_key );
}
}
}