Files
wp-fedistream/includes/PostTypes/Artist.php

332 lines
14 KiB
PHP
Raw Normal View History

<?php
/**
* Artist custom post type.
*
* @package WP_FediStream
*/
namespace WP_FediStream\PostTypes;
// Prevent direct file access.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Artist post type class.
*
* Handles registration and management of artist/band profiles.
*/
class Artist extends AbstractPostType {
/**
* Post type key.
*
* @var string
*/
protected string $post_type = 'fedistream_artist';
/**
* Meta key prefix.
*
* @var string
*/
private const META_PREFIX = '_fedistream_artist_';
/**
* Register the post type.
*
* @return void
*/
public function register(): void {
$labels = array(
'name' => _x( 'Artists', 'Post type general name', 'wp-fedistream' ),
'singular_name' => _x( 'Artist', 'Post type singular name', 'wp-fedistream' ),
'menu_name' => _x( 'Artists', 'Admin Menu text', 'wp-fedistream' ),
'name_admin_bar' => _x( 'Artist', 'Add New on Toolbar', 'wp-fedistream' ),
'add_new' => __( 'Add New', 'wp-fedistream' ),
'add_new_item' => __( 'Add New Artist', 'wp-fedistream' ),
'new_item' => __( 'New Artist', 'wp-fedistream' ),
'edit_item' => __( 'Edit Artist', 'wp-fedistream' ),
'view_item' => __( 'View Artist', 'wp-fedistream' ),
'all_items' => __( 'All Artists', 'wp-fedistream' ),
'search_items' => __( 'Search Artists', 'wp-fedistream' ),
'parent_item_colon' => __( 'Parent Artists:', 'wp-fedistream' ),
'not_found' => __( 'No artists found.', 'wp-fedistream' ),
'not_found_in_trash' => __( 'No artists found in Trash.', 'wp-fedistream' ),
'featured_image' => _x( 'Artist Photo', 'Overrides the "Featured Image" phrase', 'wp-fedistream' ),
'set_featured_image' => _x( 'Set artist photo', 'Overrides the "Set featured image" phrase', 'wp-fedistream' ),
'remove_featured_image' => _x( 'Remove artist photo', 'Overrides the "Remove featured image" phrase', 'wp-fedistream' ),
'use_featured_image' => _x( 'Use as artist photo', 'Overrides the "Use as featured image" phrase', 'wp-fedistream' ),
'archives' => _x( 'Artist archives', 'The post type archive label', 'wp-fedistream' ),
'insert_into_item' => _x( 'Insert into artist', 'Overrides the "Insert into post" phrase', 'wp-fedistream' ),
'uploaded_to_this_item' => _x( 'Uploaded to this artist', 'Overrides the "Uploaded to this post" phrase', 'wp-fedistream' ),
'filter_items_list' => _x( 'Filter artists list', 'Screen reader text', 'wp-fedistream' ),
'items_list_navigation' => _x( 'Artists list navigation', 'Screen reader text', 'wp-fedistream' ),
'items_list' => _x( 'Artists 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' => 'artists' ),
'capability_type' => array( 'fedistream_artist', 'fedistream_artists' ),
'map_meta_cap' => true,
'has_archive' => true,
'hierarchical' => false,
'menu_position' => null,
'menu_icon' => 'dashicons-groups',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'revisions' ),
'show_in_rest' => true,
'rest_base' => 'artists',
);
register_post_type( $this->post_type, $args );
}
/**
* Add meta boxes.
*
* @return void
*/
public function add_meta_boxes(): void {
add_meta_box(
'fedistream_artist_info',
__( 'Artist Information', 'wp-fedistream' ),
array( $this, 'render_info_meta_box' ),
$this->post_type,
'normal',
'high'
);
add_meta_box(
'fedistream_artist_social',
__( 'Social Links', 'wp-fedistream' ),
array( $this, 'render_social_meta_box' ),
$this->post_type,
'normal',
'default'
);
add_meta_box(
'fedistream_artist_members',
__( 'Band Members', 'wp-fedistream' ),
array( $this, 'render_members_meta_box' ),
$this->post_type,
'side',
'default'
);
}
/**
* Render artist info meta box.
*
* @param \WP_Post $post Post object.
* @return void
*/
public function render_info_meta_box( \WP_Post $post ): void {
wp_nonce_field( 'fedistream_artist_save', 'fedistream_artist_nonce' );
$artist_type = get_post_meta( $post->ID, self::META_PREFIX . 'type', true );
$formed_date = get_post_meta( $post->ID, self::META_PREFIX . 'formed_date', true );
$location = get_post_meta( $post->ID, self::META_PREFIX . 'location', true );
$website = get_post_meta( $post->ID, self::META_PREFIX . 'website', true );
?>
<table class="form-table">
<tr>
<th scope="row">
<label for="fedistream_artist_type"><?php esc_html_e( 'Artist Type', 'wp-fedistream' ); ?></label>
</th>
<td>
<select name="fedistream_artist_type" id="fedistream_artist_type">
<option value="solo" <?php selected( $artist_type, 'solo' ); ?>><?php esc_html_e( 'Solo Artist', 'wp-fedistream' ); ?></option>
<option value="band" <?php selected( $artist_type, 'band' ); ?>><?php esc_html_e( 'Band', 'wp-fedistream' ); ?></option>
<option value="duo" <?php selected( $artist_type, 'duo' ); ?>><?php esc_html_e( 'Duo', 'wp-fedistream' ); ?></option>
<option value="collective" <?php selected( $artist_type, 'collective' ); ?>><?php esc_html_e( 'Collective', 'wp-fedistream' ); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="fedistream_artist_formed_date"><?php esc_html_e( 'Formed Date', 'wp-fedistream' ); ?></label>
</th>
<td>
<input type="date" name="fedistream_artist_formed_date" id="fedistream_artist_formed_date" value="<?php echo esc_attr( $formed_date ); ?>" class="regular-text">
<p class="description"><?php esc_html_e( 'When the artist/band was formed or started their career.', 'wp-fedistream' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="fedistream_artist_location"><?php esc_html_e( 'Location', 'wp-fedistream' ); ?></label>
</th>
<td>
<input type="text" name="fedistream_artist_location" id="fedistream_artist_location" value="<?php echo esc_attr( $location ); ?>" class="regular-text">
<p class="description"><?php esc_html_e( 'City, Country or region where the artist is based.', 'wp-fedistream' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="fedistream_artist_website"><?php esc_html_e( 'Website', 'wp-fedistream' ); ?></label>
</th>
<td>
<input type="url" name="fedistream_artist_website" id="fedistream_artist_website" value="<?php echo esc_url( $website ); ?>" class="regular-text">
<p class="description"><?php esc_html_e( 'Official website URL.', 'wp-fedistream' ); ?></p>
</td>
</tr>
</table>
<?php
}
/**
* Render social links meta box.
*
* @param \WP_Post $post Post object.
* @return void
*/
public function render_social_meta_box( \WP_Post $post ): void {
$social_links = get_post_meta( $post->ID, self::META_PREFIX . 'social_links', true );
if ( ! is_array( $social_links ) ) {
$social_links = array();
}
$platforms = array(
'mastodon' => __( 'Mastodon', 'wp-fedistream' ),
'bandcamp' => __( 'Bandcamp', 'wp-fedistream' ),
'soundcloud' => __( 'SoundCloud', 'wp-fedistream' ),
'youtube' => __( 'YouTube', 'wp-fedistream' ),
'instagram' => __( 'Instagram', 'wp-fedistream' ),
'twitter' => __( 'Twitter/X', 'wp-fedistream' ),
'facebook' => __( 'Facebook', 'wp-fedistream' ),
'tiktok' => __( 'TikTok', 'wp-fedistream' ),
'other' => __( 'Other', 'wp-fedistream' ),
);
?>
<table class="form-table">
<?php foreach ( $platforms as $key => $label ) : ?>
<tr>
<th scope="row">
<label for="fedistream_social_<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $label ); ?></label>
</th>
<td>
<input type="url" name="fedistream_artist_social[<?php echo esc_attr( $key ); ?>]" id="fedistream_social_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_url( $social_links[ $key ] ?? '' ); ?>" class="regular-text">
</td>
</tr>
<?php endforeach; ?>
</table>
<?php
}
/**
* Render band members meta box.
*
* @param \WP_Post $post Post object.
* @return void
*/
public function render_members_meta_box( \WP_Post $post ): void {
$members = get_post_meta( $post->ID, self::META_PREFIX . 'members', true );
if ( ! is_array( $members ) ) {
$members = array();
}
$artist_type = get_post_meta( $post->ID, self::META_PREFIX . 'type', true );
?>
<div id="fedistream-members-wrapper" style="<?php echo 'solo' === $artist_type ? 'display:none;' : ''; ?>">
<p class="description"><?php esc_html_e( 'Add band/group members (comma-separated names).', 'wp-fedistream' ); ?></p>
<textarea name="fedistream_artist_members" id="fedistream_artist_members" rows="5" class="large-text"><?php echo esc_textarea( implode( "\n", $members ) ); ?></textarea>
<p class="description"><?php esc_html_e( 'One member per line.', 'wp-fedistream' ); ?></p>
</div>
<script>
jQuery(document).ready(function($) {
$('#fedistream_artist_type').on('change', function() {
if ($(this).val() === 'solo') {
$('#fedistream-members-wrapper').hide();
} else {
$('#fedistream-members-wrapper').show();
}
});
});
</script>
<?php
}
/**
* Save 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 ( ! $this->can_save( $post_id, 'fedistream_artist_save', 'fedistream_artist_nonce' ) ) {
return;
}
// Save artist type.
if ( isset( $_POST['fedistream_artist_type'] ) ) {
$allowed_types = array( 'solo', 'band', 'duo', 'collective' );
$type = sanitize_text_field( wp_unslash( $_POST['fedistream_artist_type'] ) );
if ( in_array( $type, $allowed_types, true ) ) {
update_post_meta( $post_id, self::META_PREFIX . 'type', $type );
}
}
// Save other fields.
$this->save_date_meta( $post_id, self::META_PREFIX . 'formed_date', 'fedistream_artist_formed_date' );
$this->save_text_meta( $post_id, self::META_PREFIX . 'location', 'fedistream_artist_location' );
$this->save_url_meta( $post_id, self::META_PREFIX . 'website', 'fedistream_artist_website' );
// Save social links.
if ( isset( $_POST['fedistream_artist_social'] ) && is_array( $_POST['fedistream_artist_social'] ) ) {
$social_links = array();
foreach ( $_POST['fedistream_artist_social'] as $key => $url ) {
$clean_key = sanitize_key( $key );
$clean_url = esc_url_raw( wp_unslash( $url ) );
if ( ! empty( $clean_url ) ) {
$social_links[ $clean_key ] = $clean_url;
}
}
update_post_meta( $post_id, self::META_PREFIX . 'social_links', $social_links );
}
// Save members.
if ( isset( $_POST['fedistream_artist_members'] ) ) {
$members_text = sanitize_textarea_field( wp_unslash( $_POST['fedistream_artist_members'] ) );
$members = array_filter( array_map( 'trim', explode( "\n", $members_text ) ) );
update_post_meta( $post_id, self::META_PREFIX . 'members', $members );
}
}
/**
* Get artist by ID with meta.
*
* @param int $post_id Post ID.
* @return array|null Artist data or null.
*/
public static function get_artist( int $post_id ): ?array {
$post = get_post( $post_id );
if ( ! $post || 'fedistream_artist' !== $post->post_type ) {
return null;
}
return array(
'id' => $post->ID,
'name' => $post->post_title,
'slug' => $post->post_name,
'bio' => $post->post_content,
'excerpt' => $post->post_excerpt,
'type' => get_post_meta( $post_id, self::META_PREFIX . 'type', true ) ?: 'solo',
'formed_date' => get_post_meta( $post_id, self::META_PREFIX . 'formed_date', true ),
'location' => get_post_meta( $post_id, self::META_PREFIX . 'location', true ),
'website' => get_post_meta( $post_id, self::META_PREFIX . 'website', true ),
'social_links' => get_post_meta( $post_id, self::META_PREFIX . 'social_links', true ) ?: array(),
'members' => get_post_meta( $post_id, self::META_PREFIX . 'members', true ) ?: array(),
'photo' => get_the_post_thumbnail_url( $post_id, 'large' ),
'url' => get_permalink( $post_id ),
);
}
}