‘Featured Dance Chart’, ‘subtitle’ => ‘Add your own links in settings later’, ‘url’ => ‘https://open.spotify.com/’, ‘service’ => ‘Spotify’, ], [ ‘title’ => ‘YouTube Dance Picks’, ‘subtitle’ => ‘Perfect for socials & practice’, ‘url’ => ‘https://www.youtube.com/’, ‘service’ => ‘YouTube’, ], ]; add_option(‘w2d_featured_charts’, $default); } $this->register_cpt_and_tax(); flush_rewrite_rules(); } public function register_cpt_and_tax() { // Custom Post Type: Playlists register_post_type(self::CPT, [ ‘labels’ => [ ‘name’ => ‘Playlists’, ‘singular_name’ => ‘Playlist’, ], ‘public’ => true, ‘has_archive’ => false, ‘show_in_rest’ => true, ‘menu_icon’ => ‘dashicons-playlist-audio’, ‘supports’ => [‘title’, ‘editor’, ‘author’], ‘rewrite’ => [‘slug’ => ‘playlists’], ]); // Taxonomy: Dance Style register_taxonomy(‘w2d_dance_style’, [self::CPT], [ ‘labels’ => [‘name’ => ‘Dance Styles’], ‘public’ => true, ‘show_in_rest’ => true, ‘hierarchical’ => false, ‘rewrite’ => [‘slug’ => ‘dance-style’], ]); // Taxonomy: Service register_taxonomy(‘w2d_playlist_service’, [self::CPT], [ ‘labels’ => [‘name’ => ‘Services’], ‘public’ => true, ‘show_in_rest’ => true, ‘hierarchical’ => false, ‘rewrite’ => [‘slug’ => ‘playlist-service’], ]); } public function enqueue_assets() { // Only load when shortcode exists on the page if (!is_singular() && !is_page()) return; global $post; if (!$post || stripos($post->post_content ?? ”, ‘[w2d_dance_charts’) === false) return; wp_register_style(‘w2d-dance-css’, false, [], ‘1.0.0’); wp_enqueue_style(‘w2d-dance-css’); $css = ” .w2d-dance-wrap{max-width:1100px;margin:0 auto;padding:18px} .w2d-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:14px} .w2d-card{ grid-column:span 12; background:rgba(20,20,24,.72); border:1px solid rgba(255,255,255,.08); border-radius:18px; box-shadow:0 12px 30px rgba(0,0,0,.35); padding:16px; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); } @media(min-width:820px){ .w2d-card.half{grid-column:span 6} .w2d-card.third{grid-column:span 4} } .w2d-h1{font-size:28px;line-height:1.2;margin:0 0 6px 0} .w2d-sub{opacity:.85;margin:0 0 10px 0} .w2d-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center} .w2d-pill{display:inline-flex;gap:8px;align-items:center;border:1px solid rgba(255,255,255,.10);padding:8px 12px;border-radius:999px;background:rgba(255,255,255,.04)} .w2d-btn{ border:none;cursor:pointer;border-radius:999px; padding:10px 14px; background:rgba(70,130,255,.95); color:#fff;font-weight:600; box-shadow:0 10px 20px rgba(0,0,0,.25); } .w2d-btn.secondary{background:rgba(255,255,255,.10);color:#fff;border:1px solid rgba(255,255,255,.10)} .w2d-btn:disabled{opacity:.55;cursor:not-allowed} .w2d-input,.w2d-select,.w2d-textarea{ width:100%; background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.10); border-radius:14px; padding:12px 12px; color:#fff; outline:none; } .w2d-textarea{min-height:96px;resize:vertical} .w2d-label{display:block;margin:10px 0 6px 0;opacity:.9;font-weight:600} .w2d-muted{opacity:.75;font-size:13px} .w2d-embed iframe{width:100%;min-height:152px;border:0;border-radius:14px;overflow:hidden} .w2d-topbar{display:flex;gap:10px;flex-wrap:wrap;justify-content:space-between;align-items:center} .w2d-search{flex:1;min-width:220px} .w2d-like{display:inline-flex;gap:8px;align-items:center} .w2d-like-count{opacity:.85} .w2d-hr{height:1px;background:rgba(255,255,255,.08);margin:12px 0} .w2d-note{padding:10px 12px;border-radius:14px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.08)} “; wp_add_inline_style(‘w2d-dance-css’, $css); wp_register_script(‘w2d-dance-js’, false, [‘jquery’], ‘1.0.0’, true); wp_enqueue_script(‘w2d-dance-js’); $data = [ ‘ajaxurl’ => admin_url(‘admin-ajax.php’), ‘nonce’ => wp_create_nonce(self::NONCE_ACTION), ‘loggedIn’ => is_user_logged_in(), ]; wp_add_inline_script(‘w2d-dance-js’, ‘window.W2D_DANCE=’ . wp_json_encode($data) . ‘;’); $js = <<‘+msg+’
‘); } // Client-side filter $(document).on(‘input’, ‘#w2dPlaylistSearch’, function(){ var q = ($(this).val() || ”).toLowerCase().trim(); $(‘.w2d-playlist-card’).each(function(){ var t = ($(this).data(‘search’) || ”).toLowerCase(); $(this).toggle(!q || t.indexOf(q) !== -1); }); }); // Submit playlist $(document).on(‘submit’, ‘#w2dPlaylistForm’, function(e){ e.preventDefault(); var $form = $(this); var $msg = $(‘#w2dFormMsg’); var payload = $form.serializeArray(); payload.push({name:’action’, value:’w2d_submit_playlist’}); payload.push({name:’nonce’, value: (window.W2D_DANCE ? W2D_DANCE.nonce : ”) }); $form.find(‘button[type=”submit”]’).prop(‘disabled’, true); $.post((window.W2D_DANCE ? W2D_DANCE.ajaxurl : ”), payload) .done(function(res){ if(res && res.success){ showMsg($msg, res.data.message, true); $form[0].reset(); }else{ showMsg($msg, (res && res.data && res.data.message) ? res.data.message : ‘Something went wrong.’, false); } }) .fail(function(){ showMsg($msg, ‘Request failed. Please try again.’, false); }) .always(function(){ $form.find(‘button[type=”submit”]’).prop(‘disabled’, false); }); }); // Like playlist $(document).on(‘click’, ‘.w2dLikeBtn’, function(){ var $btn = $(this); var postId = $btn.data(‘id’); if(!postId) return; $btn.prop(‘disabled’, true); $.post((window.W2D_DANCE ? W2D_DANCE.ajaxurl : ”), { action: ‘w2d_like_playlist’, nonce: (window.W2D_DANCE ? W2D_DANCE.nonce : ”), post_id: postId }).done(function(res){ if(res && res.success){ $btn.closest(‘.w2d-like’).find(‘.w2d-like-count’).text(res.data.likes); } }).always(function(){ $btn.prop(‘disabled’, false); }); }); })(jQuery); JS; wp_add_inline_script(‘w2d-dance-js’, $js); } private function get_featured_charts() { $charts = get_option(‘w2d_featured_charts’, []); return is_array($charts) ? $charts : []; } private function get_like_count($post_id) { return (int) get_post_meta($post_id, ‘_w2d_likes’, true); } private function render_embed($url) { $url = esc_url($url); if (!$url) return ”; // Try WordPress oEmbed first $embed = wp_oembed_get($url); if ($embed) { return ‘
‘ . $embed . ‘
‘; } // Fallback: link only return ‘

Open playlist

‘; } public function shortcode() { ob_start(); $charts = $this->get_featured_charts(); ?>
Dance

Explore featured dance charts, then share the playlists that get your community moving.

🎧 Charts 🕺 Community Playlists ❤️ Like & discover
‘Please log in to submit a playlist.’]); } $nonce = sanitize_text_field($_POST[‘nonce’] ?? ”); if (!wp_verify_nonce($nonce, self::NONCE_ACTION)) { wp_send_json_error([‘message’ => ‘Security check failed. Please refresh and try again.’]); } $title = sanitize_text_field($_POST[‘title’] ?? ”); $url = esc_url_raw($_POST[‘url’] ?? ”); $service = sanitize_text_field($_POST[‘service’] ?? ‘Other’); $styles_raw = sanitize_text_field($_POST[‘styles’] ?? ”); $bpm = sanitize_text_field($_POST[‘bpm’] ?? ”); $notes = wp_kses_post($_POST[‘notes’] ?? ”); if (!$title || !$url) { wp_send_json_error([‘message’ => ‘Title and playlist link are required.’]); } // Decide status: publish if user can publish posts, else pending. $status = current_user_can(‘publish_posts’) ? ‘publish’ : ‘pending’; $post_id = wp_insert_post([ ‘post_type’ => self::CPT, ‘post_title’ => $title, ‘post_content’ => $notes, ‘post_status’ => $status, ‘post_author’ => get_current_user_id(), ], true); if (is_wp_error($post_id)) { wp_send_json_error([‘message’ => ‘Could not save playlist.’]); } update_post_meta($post_id, ‘_w2d_url’, $url); if ($bpm !== ”) { $bpm_i = (int)$bpm; if ($bpm_i > 0 && $bpm_i < 500) { update_post_meta($post_id, '_w2d_bpm', $bpm_i); } } // Set service taxonomy if ($service) { wp_set_post_terms($post_id, [$service], 'w2d_playlist_service', false); } // Styles to taxonomy (comma-separated) if ($styles_raw) { $parts = array_filter(array_map('trim', explode(',', $styles_raw))); if (!empty($parts)) { wp_set_post_terms($post_id, $parts, 'w2d_dance_style', false); } } $msg = ($status === 'publish') ? 'Playlist published — thank you for sharing!' : 'Playlist submitted for approval — thank you for sharing!'; wp_send_json_success(['message' => $msg]); } public function ajax_like_playlist() { $nonce = sanitize_text_field($_POST[‘nonce’] ?? ”); if (!wp_verify_nonce($nonce, self::NONCE_ACTION)) { wp_send_json_error([‘message’ => ‘Security check failed.’]); } $post_id = (int)($_POST[‘post_id’] ?? 0); if (!$post_id || get_post_type($post_id) !== self::CPT) { wp_send_json_error([‘message’ => ‘Invalid playlist.’]); } // Prevent rapid repeat likes using a short cookie $cookie_key = ‘w2d_like_’ . $post_id; if (!empty($_COOKIE[$cookie_key])) { wp_send_json_success([‘likes’ => $this->get_like_count($post_id)]); } $likes = $this->get_like_count($post_id); $likes++; update_post_meta($post_id, ‘_w2d_likes’, $likes); setcookie($cookie_key, ‘1’, time() + 3600, COOKIEPATH ?: ‘/’, COOKIE_DOMAIN ?: ”); wp_send_json_success([‘likes’ => $likes]); } } new W2D_Dance_Charts_Playlists();