File manager - Edit - /home/monara/public_html/efm_web/wp-content/plugins/radio-chart/radio-chart.php
Back
<?php /* Plugin Name: Radio Chart - Simple Voting Description: Add up to 10 songs and display a voting chart via shortcode [radio_chart]. Anonymous one-click votes. Version: 1.0 Author: (you) */ if ( ! defined( 'ABSPATH' ) ) exit; global $radio_chart_db_version; $radio_chart_db_version = '1.0'; /* Activation: create tables */ register_activation_hook( __FILE__, 'radio_chart_install' ); function radio_chart_install() { global $wpdb, $radio_chart_db_version; $songs_table = $wpdb->prefix . 'radio_chart_songs'; $votes_table = $wpdb->prefix . 'radio_chart_votes'; $charset_collate = $wpdb->get_charset_collate(); $sql = " CREATE TABLE $songs_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, title varchar(191) NOT NULL, artist varchar(191) DEFAULT '', image varchar(255) DEFAULT '', votes int(10) unsigned DEFAULT 0, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) $charset_collate; CREATE TABLE $votes_table ( id bigint(20) NOT NULL AUTO_INCREMENT, song_id mediumint(9) NOT NULL, voter_hash varchar(255) NOT NULL, ip varchar(45) DEFAULT '', created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY song_id (song_id), KEY voter_hash (voter_hash) ) $charset_collate; "; require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); add_option( 'radio_chart_db_version', $radio_chart_db_version ); } /* Admin menu */ add_action( 'admin_menu', 'radio_chart_admin_menu' ); function radio_chart_admin_menu() { add_menu_page( 'Radio Chart', 'Radio Chart', 'manage_options', 'radio-chart', 'radio_chart_admin_page', 'dashicons-chart-bar', 26 ); } /* Admin page: add/edit/delete songs (very simple UI) */ function radio_chart_admin_page() { if ( ! current_user_can( 'manage_options' ) ) return; global $wpdb; $songs_table = $wpdb->prefix . 'radio_chart_songs'; // Handle add / edit via POST if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['radio_chart_save'] ) ) { check_admin_referer( 'radio_chart_save_action', 'radio_chart_save' ); $title = sanitize_text_field( wp_unslash( $_POST['title'] ?? '' ) ); $artist = sanitize_text_field( wp_unslash( $_POST['artist'] ?? '' ) ); $image = esc_url_raw( wp_unslash( $_POST['image'] ?? '' ) ); $id = ! empty( $_POST['id'] ) ? intval( $_POST['id'] ) : 0; // Count songs currently $count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $songs_table" ); if ( $id ) { $wpdb->update( $songs_table, array( 'title' => $title, 'artist' => $artist, 'image' => $image ), array( 'id' => $id ), array( '%s', '%s', '%s' ), array( '%d' ) ); echo '<div class="notice notice-success is-dismissible"><p>Song updated.</p></div>'; } else { if ( $count >= 10 ) { echo '<div class="notice notice-error is-dismissible"><p>You already have 10 songs. Delete one to add a new song.</p></div>'; } else { $wpdb->insert( $songs_table, array( 'title' => $title, 'artist' => $artist, 'image' => $image ), array( '%s', '%s', '%s' ) ); echo '<div class="notice notice-success is-dismissible"><p>Song added.</p></div>'; } } } // Handle delete via GET + nonce if ( isset( $_GET['action'] ) && $_GET['action'] === 'delete' && ! empty( $_GET['id'] ) ) { $del_id = intval( $_GET['id'] ); if ( check_admin_referer( 'radio_chart_delete_' . $del_id ) ) { $wpdb->delete( $songs_table, array( 'id' => $del_id ), array( '%d' ) ); echo '<div class="notice notice-success is-dismissible"><p>Song deleted.</p></div>'; } } // If editing, load song data $edit_song = null; if ( isset( $_GET['edit'] ) && intval( $_GET['edit'] ) ) { $edit_song = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $songs_table WHERE id = %d", intval( $_GET['edit'] ) ) ); } // Fetch songs list $songs = $wpdb->get_results( "SELECT * FROM $songs_table ORDER BY id ASC" ); ?> <div class="wrap"> <h1>Radio Chart</h1> <h2><?php echo $edit_song ? 'Edit song' : 'Add new song'; ?></h2> <form method="post" style="max-width:640px;"> <?php wp_nonce_field( 'radio_chart_save_action', 'radio_chart_save' ); ?> <input type="hidden" name="id" value="<?php echo esc_attr( $edit_song->id ?? '' ); ?>"> <table class="form-table"> <tr> <th scope="row"><label for="title">Title</label></th> <td><input name="title" id="title" type="text" class="regular-text" required value="<?php echo esc_attr( $edit_song->title ?? '' ); ?>"></td> </tr> <tr> <th scope="row"><label for="artist">Artist</label></th> <td><input name="artist" id="artist" type="text" class="regular-text" value="<?php echo esc_attr( $edit_song->artist ?? '' ); ?>"></td> </tr> <tr> <th scope="row"><label for="image">Image URL</label></th> <td> <input name="image" id="image" type="url" class="regular-text" placeholder="Paste image URL from Media Library" value="<?php echo esc_attr( $edit_song->image ?? '' ); ?>"> <p class="description">Optional — copy URL from WP Media Library.</p> </td> </tr> </table> <?php submit_button( $edit_song ? 'Update song' : 'Add song' ); ?> </form> <hr> <h2>Current songs (<?php echo count( $songs ); ?> / 10)</h2> <table class="widefat fixed striped" style="max-width:900px;"> <thead><tr><th>ID</th><th>Image</th><th>Title</th><th>Artist</th><th>Votes</th><th>Actions</th></tr></thead> <tbody> <?php if ( $songs ) : foreach ( $songs as $s ) : ?> <tr> <td><?php echo intval( $s->id ); ?></td> <td><?php if ( $s->image ) echo '<img src="' . esc_url( $s->image ) . '" style="height:48px;width:auto;">'; ?></td> <td><?php echo esc_html( $s->title ); ?></td> <td><?php echo esc_html( $s->artist ); ?></td> <td><?php echo intval( $s->votes ); ?></td> <td> <a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=radio-chart&edit=' . $s->id ) ); ?>">Edit</a> <?php echo wp_nonce_url( admin_url( 'admin.php?page=radio-chart&action=delete&id=' . $s->id ), 'radio_chart_delete_' . $s->id ); ?> <a class="button button-secondary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=radio-chart&action=delete&id=' . $s->id ), 'radio_chart_delete_' . $s->id ) ); ?>" onclick="return confirm('Delete this song?');">Delete</a> </td> </tr> <?php endforeach; else: ?> <tr><td colspan="6">No songs yet. Add one above.</td></tr> <?php endif; ?> </tbody> </table> </div> <?php } function radio_chart_get_thumbnail($url) { // If it's a YouTube URL if (strpos($url, 'youtube.com') !== false || strpos($url, 'youtu.be') !== false) { // Extract video ID if (preg_match('/(?:v=|\/)([0-9A-Za-z_-]{11})/', $url, $matches)) { $video_id = $matches[1]; return 'https://img.youtube.com/vi/' . $video_id . '/hqdefault.jpg'; } } // Otherwise return the URL as is return $url; } /* Shortcode to show chart */ add_shortcode( 'radio_chart', 'radio_chart_shortcode' ); function radio_chart_shortcode( $atts ) { global $wpdb; $songs_table = $wpdb->prefix . 'radio_chart_songs'; // enqueue scripts & styles wp_enqueue_script( 'radio-chart-js', plugin_dir_url( __FILE__ ) . 'radio-chart.js', array( 'jquery' ), '1.0', true ); wp_enqueue_style( 'radio-chart-css', plugin_dir_url( __FILE__ ) . 'radio-chart.css', array(), '1.0' ); // localize wp_localize_script( 'radio-chart-js', 'radioChart', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'radio_chart_vote' ) ) ); $songs = $wpdb->get_results( "SELECT * FROM $songs_table ORDER BY votes DESC, id ASC LIMIT 10" ); ob_start(); ?> <div class="radio-chart-wrap"> <?php if ( $songs ) : foreach ( $songs as $s ) : ?> <div class="radio-chart-item" data-song-id="<?php echo intval( $s->id ); ?>"> <?php if ( $s->image ) : $thumb = radio_chart_get_thumbnail($s->image); ?> <div class="radio-chart-thumb"> <img src="<?php echo esc_url( $thumb ); ?>" alt="<?php echo esc_attr( $s->title ); ?>"> </div> <?php endif; ?> <div class="radio-chart-meta"> <span class="radio-chart-title"><?php echo esc_html( $s->title ); ?></span> <span class="radio-chart-artist"><?php echo esc_html( $s->artist ); ?></span> </div> <div class="radio-chart-actions"> <div class="radio-chart-count"><?php echo intval( $s->votes ); ?></div> <button class="radio-chart-vote-btn" data-song-id="<?php echo intval( $s->id ); ?>">Vote</button> </div> </div> <?php endforeach; else: ?> <p>No songs in the chart yet.</p> <?php endif; ?> </div> <?php return ob_get_clean(); } /* AJAX handler (both logged-in and not) */ add_action( 'wp_ajax_radio_chart_vote', 'radio_chart_ajax_vote' ); add_action( 'wp_ajax_nopriv_radio_chart_vote', 'radio_chart_ajax_vote' ); function radio_chart_ajax_vote() { check_ajax_referer( 'radio_chart_vote', 'nonce' ); $song_id = isset( $_POST['song_id'] ) ? intval( $_POST['song_id'] ) : 0; if ( ! $song_id ) wp_send_json_error( 'Invalid song.' ); global $wpdb; $songs_table = $wpdb->prefix . 'radio_chart_songs'; $votes_table = $wpdb->prefix . 'radio_chart_votes'; // voter identifier: hash of IP + UA (hashed) $ip = sanitize_text_field( $_SERVER['REMOTE_ADDR'] ?? '' ); $ua = sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ?? '' ); $voter_hash = wp_hash( $ip . $ua ); // check cookie first $cookie_name = 'radio_chart_voted_' . $song_id; if ( isset( $_COOKIE[ $cookie_name ] ) && $_COOKIE[ $cookie_name ] === '1' ) { wp_send_json_error( 'You already voted.' ); } // check votes table for same voter_hash and song $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $votes_table WHERE song_id = %d AND voter_hash = %s", $song_id, $voter_hash ) ); if ( $exists ) wp_send_json_error( 'You already voted.' ); // Record vote $inserted = $wpdb->insert( $votes_table, array( 'song_id' => $song_id, 'voter_hash' => $voter_hash, 'ip' => $ip ), array( '%d', '%s', '%s' ) ); if ( $inserted === false ) wp_send_json_error( 'Database error.' ); // increment counter in songs table $wpdb->query( $wpdb->prepare( "UPDATE $songs_table SET votes = votes + 1 WHERE id = %d", $song_id ) ); // set cookie for 1 year $expire = time() + YEAR_IN_SECONDS; // path & domain from WP constants setcookie( $cookie_name, '1', $expire, COOKIEPATH ?: '/', COOKIE_DOMAIN ?: '' ); // return new count $votes = (int) $wpdb->get_var( $wpdb->prepare( "SELECT votes FROM $songs_table WHERE id = %d", $song_id ) ); wp_send_json_success( array( 'votes' => $votes ) ); }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.03 |
proxy
|
phpinfo
|
Settings